fail only the disconnected sidecar's in-flight requests
unregisterSidecar rejected every entry in the pending map, not just the ones belonging to the sidecar that went away. Restarting any single sidecar failed in-flight work on every other: `pm2 restart officer-music` could kill a running agent turn with `Sidecar "music" disconnected` — a message pointing at a process that had nothing to do with it. Pending entries now carry their owning sidecar id and the rejection loop skips the rest. Also deletes src/servers/api/anthropic-proxy.ts. It had no importers; PM2's officer-anthropic-proxy runs src/servers/sidecar/claude/index.ts. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -23,6 +23,8 @@ type RegisteredSidecar = {
|
||||
};
|
||||
|
||||
type PendingRequest = {
|
||||
/** Which sidecar this request was sent to, so a disconnect only fails that sidecar's own work. */
|
||||
sidecarId: string;
|
||||
resolve: (value: any) => void;
|
||||
reject: (error: Error) => void;
|
||||
timer: Timer;
|
||||
@@ -73,8 +75,12 @@ export function unregisterSidecar(id: string): void {
|
||||
sidecars.delete(id);
|
||||
console.log(`[registry] unregistered sidecar "${sc.name}" (id=${id})`);
|
||||
|
||||
// Reject all pending requests for this sidecar
|
||||
// Reject the pending requests belonging to THIS sidecar, and only those. Until the pending entries
|
||||
// carried a sidecarId this loop rejected the whole map, so restarting any one sidecar failed in-flight
|
||||
// work on every other — `pm2 restart officer-music` could kill a running agent turn with the message
|
||||
// `Sidecar "music" disconnected`, which is the sort of failure nobody traces back to its cause.
|
||||
for (const [reqId, req] of pending) {
|
||||
if (req.sidecarId !== id) continue;
|
||||
clearTimeout(req.timer);
|
||||
req.reject(new Error(`Sidecar "${sc.name}" disconnected`));
|
||||
pending.delete(reqId);
|
||||
@@ -152,7 +158,7 @@ function sendCommand(cap: string, cmd: SidecarCommand, timeoutMs = DEFAULT_TIMEO
|
||||
reject(new Error(`Sidecar command ${cmd.type} timed out`));
|
||||
}, timeoutMs);
|
||||
|
||||
pending.set((cmd as any).id, { resolve, reject, timer });
|
||||
pending.set((cmd as any).id, { sidecarId: sc.id, resolve, reject, timer });
|
||||
sc.ws.send(JSON.stringify(cmd));
|
||||
});
|
||||
}
|
||||
@@ -175,7 +181,7 @@ function sendCommandToSidecar(
|
||||
reject(new Error(`Sidecar command ${cmd.type} timed out`));
|
||||
}, timeoutMs);
|
||||
|
||||
pending.set((cmd as any).id, { resolve, reject, timer });
|
||||
pending.set((cmd as any).id, { sidecarId: sc.id, resolve, reject, timer });
|
||||
sc.ws.send(JSON.stringify(cmd));
|
||||
});
|
||||
}
|
||||
@@ -320,7 +326,6 @@ export function onOpenCodeSession(handler: (sessionKey: string, sessionId: strin
|
||||
// Nothing here any more. The pty sidecar serves its own listener; `/api/terminal/*` is a proxy and
|
||||
// `/api/terminal/ws` a byte relay, both keyed off the `pty:server` port like every other HTTP sidecar.
|
||||
|
||||
|
||||
// ── VNC ──
|
||||
|
||||
export async function startVnc(params: VncStartParams): Promise<{ port: number; display: number }> {
|
||||
|
||||
Reference in New Issue
Block a user