remove seed directory, clean up provisioning and sync modules

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-08 00:07:50 +00:00
co-authored by Claude Opus 4.6
parent 9578110e8b
commit 56f8da8907
86 changed files with 182 additions and 12061 deletions
+5 -43
View File
@@ -1,7 +1,6 @@
import type { SidecarCommand, SidecarEvent } from '../protocol';
import { loadState, flushAndSave, acquireLock, releaseLock, getState } from './state';
import { startAnthropicProxy, getProxySecret, ensureProxySecret } from './proxy';
import * as claudeManager from './claude-manager';
import { createSidecarConnector } from '../connect';
const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '5000'}`;
@@ -9,7 +8,7 @@ const API_URL = process.env.API_URL ?? `ws://127.0.0.1:${process.env.PORT ?? '50
// ── Startup ──
if (!acquireLock()) {
console.error('[claude] another instance is already running (lock file exists with live PID)');
console.error('[proxy] another instance is already running (lock file exists with live PID)');
process.exit(1);
}
@@ -20,7 +19,7 @@ ensureProxySecret();
try {
startAnthropicProxy();
} catch (err) {
console.error('[claude] failed to start Anthropic proxy:', err instanceof Error ? err.message : err);
console.error('[proxy] failed to start Anthropic proxy:', err instanceof Error ? err.message : err);
}
// ── Command handlers ──
@@ -48,43 +47,6 @@ async function handleCommand(cmd: SidecarCommand, reply: ReplyFn) {
reply({ type: 'proxy:secret', id: cmd.id, secret: getProxySecret() });
break;
case 'claude:spawn': {
try {
const result = await claudeManager.spawnClaude(cmd.params);
reply({ type: 'claude:result', id: cmd.id, result });
} catch (err) {
reply({ type: 'claude:error', id: cmd.id, error: err instanceof Error ? err.message : String(err) });
}
break;
}
case 'claude:spawn-streaming': {
reply({ type: 'claude:spawned', id: cmd.id, sessionKey: cmd.params.sessionKey });
const onEvent = (event: import('../../api/pi/types').PiEvent) => {
connection.send({ type: 'claude:event', sessionKey: cmd.params.sessionKey, event });
};
claudeManager.spawnClaudeStreaming(cmd.params, onEvent).catch((err) => {
connection.send({
type: 'claude:event',
sessionKey: cmd.params.sessionKey,
event: { type: 'error', message: err instanceof Error ? err.message : String(err) },
});
});
break;
}
case 'claude:kill':
claudeManager.killClaudeSession(cmd.sessionKey);
reply({ type: 'claude:killed', id: cmd.id });
break;
case 'claude:clear-session':
claudeManager.clearSession(cmd.sessionKey);
reply({ type: 'claude:session-cleared', id: cmd.id });
break;
default:
reply({
type: 'error',
@@ -98,8 +60,8 @@ async function handleCommand(cmd: SidecarCommand, reply: ReplyFn) {
const connection = createSidecarConnector({
apiUrl: `${API_URL}/api/sidecar/register`,
name: 'claude',
capabilities: ['claude', 'proxy'],
name: 'proxy',
capabilities: ['proxy'],
onCommand(cmd, reply) {
handleCommand(cmd as SidecarCommand, reply as ReplyFn);
},
@@ -108,7 +70,7 @@ const connection = createSidecarConnector({
// ── Graceful shutdown ──
async function shutdown(signal: string) {
console.log(`[claude] ${signal} received, saving state...`);
console.log(`[proxy] ${signal} received, saving state...`);
connection.destroy();
await flushAndSave();
releaseLock();
+30 -14
View File
@@ -1,10 +1,7 @@
import { join } from 'node:path';
import { mkdirSync, existsSync } from 'node:fs';
import { mkdirSync, existsSync, readFileSync, writeFileSync, unlinkSync } from 'node:fs';
const DATA_PATH = process.env.DATA_PATH ?? join(process.cwd(), 'data');
const STATE_DIR = join(DATA_PATH, 'sidecar');
const STATE_FILE = join(STATE_DIR, 'claude-state.json');
const LOCK_FILE = join(STATE_DIR, 'claude.lock');
export type PersistedState = {
proxySecret: string;
@@ -16,23 +13,42 @@ const DEFAULT_STATE: PersistedState = {
claudeSessions: {},
};
let stateDir: string;
let stateFile: string;
let lockFile: string;
let currentState: PersistedState = { ...DEFAULT_STATE };
let saveTimer: Timer | null = null;
/** Call once at startup to configure paths. For proxy: no email. For per-user: pass email. */
export function initPaths(email?: string): void {
if (email) {
stateDir = join(DATA_PATH, email, 'sidecar');
stateFile = join(stateDir, 'claude-state.json');
lockFile = join(stateDir, 'claude.lock');
} else {
stateDir = join(DATA_PATH, 'sidecar');
stateFile = join(stateDir, 'claude-state.json');
lockFile = join(stateDir, 'claude.lock');
}
}
// Default to proxy paths
initPaths();
function ensureDir() {
if (!existsSync(STATE_DIR)) {
mkdirSync(STATE_DIR, { recursive: true });
if (!existsSync(stateDir)) {
mkdirSync(stateDir, { recursive: true });
}
}
export function loadState(): PersistedState {
ensureDir();
try {
if (!existsSync(STATE_FILE)) {
if (!existsSync(stateFile)) {
currentState = { ...DEFAULT_STATE };
return currentState;
}
const text = require('node:fs').readFileSync(STATE_FILE, 'utf-8');
const text = readFileSync(stateFile, 'utf-8');
currentState = { ...DEFAULT_STATE, ...JSON.parse(text) };
return currentState;
} catch {
@@ -43,7 +59,7 @@ export function loadState(): PersistedState {
export async function saveState(): Promise<void> {
ensureDir();
await Bun.write(STATE_FILE, JSON.stringify(currentState, null, 2));
await Bun.write(stateFile, JSON.stringify(currentState, null, 2));
}
export function getState(): PersistedState {
@@ -90,14 +106,14 @@ export async function flushAndSave(): Promise<void> {
export function acquireLock(): boolean {
ensureDir();
try {
if (existsSync(LOCK_FILE)) {
const pidStr = require('node:fs').readFileSync(LOCK_FILE, 'utf-8').trim();
if (existsSync(lockFile)) {
const pidStr = readFileSync(lockFile, 'utf-8').trim();
const pid = Number(pidStr);
if (pid && isProcessAlive(pid)) {
return false;
}
}
require('node:fs').writeFileSync(LOCK_FILE, String(process.pid));
writeFileSync(lockFile, String(process.pid));
return true;
} catch {
return false;
@@ -106,8 +122,8 @@ export function acquireLock(): boolean {
export function releaseLock(): void {
try {
if (existsSync(LOCK_FILE)) {
require('node:fs').unlinkSync(LOCK_FILE);
if (existsSync(lockFile)) {
unlinkSync(lockFile);
}
} catch {
// best effort