process sidecar: independent process manager for long-running work

Introduces a separate Bun process (port 5100) that owns all spawned
processes and long-running work, so the API server can restart freely
without disrupting active sessions.

The sidecar owns:
- Anthropic proxy (port 5051) with persisted secret across restarts
- Claude Code process spawning and session tracking (--resume support)
- Pi agent spawning and RPC lifecycle (prompt/abort/thinking)
- Job queue engine (lane processing, retries, notifications)

The API server becomes a thin client that forwards commands over a
single WebSocket connection with auto-reconnect. send-claude-code.ts
goes from 550 lines of spawn logic to 73 lines of sidecar delegation.

State persisted to data/sidecar/state.json every 30s and on shutdown.
Lockfile prevents duplicate instances. See SIDECAR.md for full docs
and manual testing procedures.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-05 07:36:47 +00:00
co-authored by Claude Opus 4.6
parent 726c77e346
commit 86c2d6333a
21 changed files with 2415 additions and 610 deletions
+2 -4
View File
@@ -8,7 +8,7 @@ import { syncSeedExtensions } from './sync-extensions';
import { syncSeedResources } from './sync-resources';
import { migrateSettingsToResources } from './migrate-resources';
import { generateResourceSkill } from './api/pi/pi-bridge';
import { initQueue } from './queue';
// Queue is now owned by the sidecar process
import { startDiscordBotIfConfigured } from './channels/discord/bot';
import { startTelegramBotIfConfigured } from './channels/telegram/bot';
import { startWhatsAppBotIfConfigured } from './channels/whatsapp/bot';
@@ -78,9 +78,7 @@ async function installPi(): Promise<boolean> {
await migrateSettingsToResources();
generateResourceSkill(DATA_PATH);
await initQueue().catch((err) => {
console.error('[bootstrap] Failed to initialize queue:', err);
});
// Queue is initialized by the sidecar process
await startDiscordBotIfConfigured().catch((err) => {
console.error('[channels] Failed to start Discord bot:', err);