fix(remote-control): resync clients on session switch

This commit is contained in:
Yejun Su 2026-03-20 18:12:20 +08:00
parent f16a5fed83
commit 33403bd030
No known key found for this signature in database
GPG Key ID: AD03A563F321CA44
3 changed files with 35 additions and 13 deletions

View File

@ -74,6 +74,11 @@ export default function remoteControl(pi: ExtensionAPI) {
updateStatus(ctx);
});
pi.on("session_switch", async (_event, ctx) => {
server?.sync(ctx);
updateStatus(ctx);
});
pi.on("session_shutdown", async () => {
if (server) {
await server.stop();

View File

@ -79,3 +79,25 @@ export function getBranchMessages(ctx: ExtensionContext): RenderMsg[] {
}
return out;
}
export function buildSyncMessage(ctx: ExtensionContext): {
type: "sync";
messages: RenderMsg[];
state: {
isStreaming: boolean;
model: string | undefined;
cwd: string;
sessionName: string | undefined;
};
} {
return {
type: "sync",
messages: getBranchMessages(ctx),
state: {
isStreaming: !ctx.isIdle(),
model: ctx.model?.id,
cwd: ctx.cwd,
sessionName: ctx.sessionManager.getSessionName(),
},
};
}

View File

@ -16,7 +16,7 @@ import {
generateSessionId,
parseCookies,
} from "./auth.js";
import { getBranchMessages } from "./messages.js";
import { buildSyncMessage } from "./messages.js";
import { buildHTML } from "./html.js";
// Load ws (bundled with pi) without needing @types/ws installed locally
@ -29,6 +29,7 @@ const { WebSocketServer, OPEN } = wsModule;
export interface RemoteServer {
broadcast: (msg: object) => void;
sync: (ctx: ExtensionContext) => void;
stop: () => Promise<void>;
clientCount: () => number;
onClientChange: (cb: () => void) => void;
@ -79,6 +80,10 @@ export function startServer(pi: ExtensionAPI, ctx: ExtensionContext): Promise<Re
}
}
function sync(currentCtx: ExtensionContext): void {
broadcast(buildSyncMessage(currentCtx));
}
const httpServer = createServer((req, res) => {
const url = new URL(req.url ?? "/", "http://localhost");
const pathname = url.pathname;
@ -160,18 +165,7 @@ export function startServer(pi: ExtensionAPI, ctx: ExtensionContext): Promise<Re
// Send full state snapshot to the new client
try {
ws.send(
JSON.stringify({
type: "sync",
messages: getBranchMessages(ctx),
state: {
isStreaming: !ctx.isIdle(),
model: ctx.model?.id,
cwd: ctx.cwd,
sessionName: ctx.sessionManager.getSessionName(),
},
}),
);
ws.send(JSON.stringify(buildSyncMessage(ctx)));
} catch {
/* client disconnected before first send */
}
@ -225,6 +219,7 @@ export function startServer(pi: ExtensionAPI, ctx: ExtensionContext): Promise<Re
httpServer.listen(0, "127.0.0.1", () => {
resolve({
broadcast,
sync,
stop: () =>
new Promise<void>((res) => {
// Forcefully kill all WebSocket clients — terminate() sends no