sidecar self-registration: sidecars connect to API server instead of vice versa

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>
This commit is contained in:
2026-03-06 08:48:19 +00:00
co-authored by Claude Opus 4.6
parent 6cfa40bad1
commit a0d9ea63f9
17 changed files with 878 additions and 712 deletions
+7 -2
View File
@@ -9,7 +9,7 @@ import {
updateEmailAccountStatus,
} from 'officerdb';
import { validateImapConnection } from './imap-validate';
import * as sidecar from '../../sidecar-client';
import * as sidecar from '../../sidecar-registry';
type CreateAccountBody = {
provider: string;
@@ -137,7 +137,12 @@ accountsRouter.post('/:id/sync', async (ctx) => {
if (account.status === 'syncing') throw BAD_REQUEST('Account is already syncing');
// Resolve auth before enqueueing
const authResult = await resolveAuth(user.id, account.authType, account.email, account.credentials as Record<string, unknown>);
const authResult = await resolveAuth(
user.id,
account.authType,
account.email,
account.credentials as Record<string, unknown>,
);
if (!authResult.ok) throw BAD_REQUEST(authResult.error);
// Set status immediately so the UI reflects the queued state