diff --git a/extensions/remote-control/index.ts b/extensions/remote-control/index.ts index b4e074b..a2216c9 100644 --- a/extensions/remote-control/index.ts +++ b/extensions/remote-control/index.ts @@ -93,7 +93,9 @@ export default function remoteControl(pi: ExtensionAPI) { updateStatus(ctx); }); - pi.on("session_switch", async (_event, ctx) => { + // session_switch is not in the ExtensionAPI — use session_start instead + // to sync state when a session becomes active. + pi.on("session_start", async (_event, ctx) => { scheduleSync(ctx); }); diff --git a/extensions/remote-control/pi/events.ts b/extensions/remote-control/pi/events.ts index 86b68c6..be346b8 100644 --- a/extensions/remote-control/pi/events.ts +++ b/extensions/remote-control/pi/events.ts @@ -28,72 +28,41 @@ export type StateCallback = (event: StateEvent) => void; /** * Subscribe to pi agent lifecycle events. - * Returns an unsubscribe function. + * + * Note: `pi.on()` returns void and has no unsubscribe mechanism — event + * handlers are scoped to the extension lifetime, not to individual calls. + * The returned function is a no-op kept for API compatibility. */ export function subscribeAgentEvents( pi: ExtensionAPI, onState: StateCallback, ): () => void { - const unsubs: Array<() => void> = []; - // agent_start → thinking - try { - const off = pi.on("agent_start", () => { - onState({ value: "thinking", ts: Date.now() }); - }); - if (off) unsubs.push(off); - } catch { - // event may not exist in this pi version - } + pi.on("agent_start", () => { + onState({ value: "thinking", ts: Date.now() }); + }); // agent_end → idle - try { - const off = pi.on("agent_end", () => { - onState({ value: "idle", ts: Date.now() }); - }); - if (off) unsubs.push(off); - } catch { - // event may not exist - } + pi.on("agent_end", () => { + onState({ value: "idle", ts: Date.now() }); + }); - // tool_start → tool - try { - const off = pi.on("tool_start", (data: unknown) => { - const toolName = - data && - typeof data === "object" && - "name" in data && - typeof (data as { name: unknown }).name === "string" - ? (data as { name: string }).name - : undefined; - onState({ value: "tool", tool: toolName, ts: Date.now() }); - }); - if (off) unsubs.push(off); - } catch { - // event may not exist - } + // tool_execution_start → tool (carries toolName directly on the event) + pi.on("tool_execution_start", (event) => { + onState({ value: "tool", tool: event.toolName, ts: Date.now() }); + }); - // tool_end → thinking (agent is still running after tool) - try { - const off = pi.on("tool_end", () => { - onState({ value: "thinking", ts: Date.now() }); - }); - if (off) unsubs.push(off); - } catch { - // event may not exist - } + // tool_execution_end → thinking (agent loop continues after tool completes) + pi.on("tool_execution_end", () => { + onState({ value: "thinking", ts: Date.now() }); + }); - // awaiting_input → awaiting-input - try { - const off = pi.on("awaiting_input", () => { - onState({ value: "awaiting-input", ts: Date.now() }); - }); - if (off) unsubs.push(off); - } catch { - // event may not exist - } + // input → awaiting-input (fired when pi pauses to wait for user input) + pi.on("input", () => { + onState({ value: "awaiting-input", ts: Date.now() }); + }); return () => { - for (const off of unsubs) off(); + // No-op: pi event subscriptions cannot be cancelled. }; }