Flips the connection model so sidecars register themselves with the API server via WebSocket at /api/sidecar/register, enabling dynamic discovery, location independence, and automatic reconnection from either side. - Add registration protocol types and PTY command/event types - Create sidecar-registry.ts (replaces sidecar-client.ts) as passive registry - Create sidecar connector (connect.ts) with exponential backoff reconnect - Convert process sidecar from WS server to WS client - Convert PTY sidecar from WS server to multiplexed WS client - Simplify terminal bridge to thin adapter using registry - Add PTY sidecar as PM2-managed process - Update all consumer imports Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
144 lines
4.3 KiB
TypeScript
144 lines
4.3 KiB
TypeScript
import type { MessageCost, PiEvent } from '../api/pi/types';
|
|
import type { Job, EnqueueParams, JobProgress } from '../queue/types';
|
|
|
|
// ── Envelope ──
|
|
|
|
export type SidecarMessage = SidecarCommand | SidecarEvent;
|
|
|
|
// ── Commands (API server → sidecar) ──
|
|
|
|
export type SidecarCommand =
|
|
| { type: 'ping'; id: string }
|
|
| { type: 'state:sync'; id: string }
|
|
// Proxy
|
|
| { type: 'proxy:secret'; id: string }
|
|
// Claude Code
|
|
| { type: 'claude:spawn'; id: string; params: ClaudeSpawnParams }
|
|
| { type: 'claude:spawn-streaming'; id: string; params: ClaudeSpawnStreamingParams }
|
|
| { type: 'claude:kill'; id: string; sessionKey: string }
|
|
| { type: 'claude:clear-session'; id: string; sessionKey: string }
|
|
// Pi
|
|
| { type: 'pi:spawn'; id: string; params: PiSpawnParams }
|
|
| { type: 'pi:prompt'; id: string; sessionId: string; prompt: string; requestId: string }
|
|
| { type: 'pi:abort'; id: string; sessionId: string; requestId: string }
|
|
| { type: 'pi:kill'; id: string; sessionId: string }
|
|
| { type: 'pi:set-thinking'; id: string; sessionId: string; level: string }
|
|
// Queue
|
|
| { type: 'queue:enqueue'; id: string; params: EnqueueParams }
|
|
| { type: 'queue:cancel'; id: string; jobId: string }
|
|
| { type: 'queue:list'; id: string }
|
|
| { type: 'queue:get'; id: string; jobId: string };
|
|
|
|
// ── Responses/Events (sidecar → API server) ──
|
|
|
|
export type SidecarEvent =
|
|
| { type: 'pong'; id: string }
|
|
| { type: 'state:sync'; id: string; state: SidecarState }
|
|
| { type: 'proxy:secret'; id: string; secret: string }
|
|
// Claude Code
|
|
| { type: 'claude:spawned'; id: string; sessionKey: string }
|
|
| { type: 'claude:event'; sessionKey: string; event: PiEvent }
|
|
| { type: 'claude:result'; id: string; result: ClaudeCodeResult }
|
|
| { type: 'claude:error'; id: string; error: string }
|
|
| { type: 'claude:killed'; id: string }
|
|
| { type: 'claude:session-cleared'; id: string }
|
|
// Pi
|
|
| { type: 'pi:spawned'; id: string; sessionId: string }
|
|
| { type: 'pi:event'; sessionId: string; event: PiEvent }
|
|
| { type: 'pi:error'; id: string; error: string }
|
|
| { type: 'pi:killed'; id: string }
|
|
// Queue
|
|
| { type: 'queue:enqueued'; id: string; job: Job }
|
|
| { type: 'queue:cancelled'; id: string; job: Job | null }
|
|
| { type: 'queue:list'; id: string; jobs: Job[] }
|
|
| { type: 'queue:get'; id: string; job: Job | null }
|
|
| { type: 'queue:error'; id: string; error: string }
|
|
// Generic
|
|
| { type: 'error'; id?: string; error: string };
|
|
|
|
// ── Shared state snapshot ──
|
|
|
|
export type SidecarState = {
|
|
proxySecret: string;
|
|
claudeSessions: Record<string, string>; // sessionKey → Claude Code session_id
|
|
piSessions: PiSessionInfo[];
|
|
uptime: number;
|
|
};
|
|
|
|
export type PiSessionInfo = {
|
|
sessionId: string;
|
|
email: string;
|
|
userId: number;
|
|
model: string;
|
|
cwd: string;
|
|
pid: number;
|
|
alive: boolean;
|
|
};
|
|
|
|
// ── Param types ──
|
|
|
|
export type ClaudeSpawnParams = {
|
|
userId: number;
|
|
email: string;
|
|
username: string;
|
|
prompt: string;
|
|
sessionKey: string;
|
|
model?: string;
|
|
};
|
|
|
|
export type ClaudeSpawnStreamingParams = {
|
|
userId: number;
|
|
email: string;
|
|
username: string;
|
|
prompt: string;
|
|
sessionKey: string;
|
|
cwd?: string;
|
|
model?: string;
|
|
};
|
|
|
|
export type ClaudeCodeResult = {
|
|
text: string;
|
|
sessionId: string;
|
|
model: string;
|
|
cost: MessageCost;
|
|
};
|
|
|
|
export type PiSpawnParams = {
|
|
sessionId: string;
|
|
email: string;
|
|
userId: number;
|
|
username: string;
|
|
role: string;
|
|
cwd: string;
|
|
model: string;
|
|
sessionFile?: string;
|
|
};
|
|
|
|
// ── PTY types ──
|
|
|
|
export type PtyInitConfig = {
|
|
sessionId: string;
|
|
shell?: { command: string; args?: string[] };
|
|
cwd?: string;
|
|
homeDir?: string;
|
|
userLabel?: string;
|
|
username?: string;
|
|
host?: boolean;
|
|
cols?: number;
|
|
rows?: number;
|
|
env?: Record<string, string>;
|
|
};
|
|
|
|
// PTY commands (API → PTY sidecar)
|
|
export type PtyCommand =
|
|
| { type: 'pty:init'; id: string; sessionId: string; config: PtyInitConfig }
|
|
| { type: 'pty:input'; id: string; sessionId: string; data: string }
|
|
| { type: 'pty:resize'; id: string; sessionId: string; cols: number; rows: number }
|
|
| { type: 'pty:close'; id: string; sessionId: string };
|
|
|
|
// PTY events (PTY sidecar → API)
|
|
export type PtyEvent =
|
|
| { type: 'pty:ready'; id: string; sessionId: string }
|
|
| { type: 'pty:output'; sessionId: string; data: string }
|
|
| { type: 'pty:exit'; sessionId: string; exitCode: number; signal?: number };
|