@mariozechner/pi-coding-agent 0.18.0 → 0.18.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +13 -2
  3. package/dist/core/agent-session.d.ts +43 -3
  4. package/dist/core/agent-session.d.ts.map +1 -1
  5. package/dist/core/agent-session.js +175 -7
  6. package/dist/core/agent-session.js.map +1 -1
  7. package/dist/core/export-html.d.ts.map +1 -1
  8. package/dist/core/export-html.js +10 -1
  9. package/dist/core/export-html.js.map +1 -1
  10. package/dist/core/hooks/types.d.ts +4 -4
  11. package/dist/core/hooks/types.d.ts.map +1 -1
  12. package/dist/core/hooks/types.js.map +1 -1
  13. package/dist/core/model-resolver.d.ts.map +1 -1
  14. package/dist/core/model-resolver.js +1 -0
  15. package/dist/core/model-resolver.js.map +1 -1
  16. package/dist/core/session-manager.d.ts +4 -2
  17. package/dist/core/session-manager.d.ts.map +1 -1
  18. package/dist/core/session-manager.js +23 -7
  19. package/dist/core/session-manager.js.map +1 -1
  20. package/dist/core/settings-manager.d.ts +13 -0
  21. package/dist/core/settings-manager.d.ts.map +1 -1
  22. package/dist/core/settings-manager.js +17 -0
  23. package/dist/core/settings-manager.js.map +1 -1
  24. package/dist/main.d.ts.map +1 -1
  25. package/dist/main.js +7 -3
  26. package/dist/main.js.map +1 -1
  27. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  28. package/dist/modes/interactive/components/footer.js +27 -4
  29. package/dist/modes/interactive/components/footer.js.map +1 -1
  30. package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
  31. package/dist/modes/interactive/components/user-message-selector.js +2 -2
  32. package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
  33. package/dist/modes/interactive/interactive-mode.d.ts +2 -0
  34. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  35. package/dist/modes/interactive/interactive-mode.js +39 -3
  36. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  37. package/dist/modes/interactive/theme/theme.d.ts +2 -2
  38. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  39. package/dist/modes/interactive/theme/theme.js +8 -4
  40. package/dist/modes/interactive/theme/theme.js.map +1 -1
  41. package/dist/modes/rpc/rpc-client.d.ts +8 -0
  42. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  43. package/dist/modes/rpc/rpc-client.js +12 -0
  44. package/dist/modes/rpc/rpc-client.js.map +1 -1
  45. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  46. package/dist/modes/rpc/rpc-mode.js +11 -0
  47. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  48. package/dist/modes/rpc/rpc-types.d.ts +18 -1
  49. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  50. package/dist/modes/rpc/rpc-types.js.map +1 -1
  51. package/docs/gemini.md +255 -0
  52. package/docs/hooks.md +10 -2
  53. package/docs/rpc.md +62 -0
  54. package/package.json +4 -4
@@ -1 +1 @@
1
- {"version":3,"file":"rpc-mode.d.ts","sourceRoot":"","sources":["../../../src/modes/rpc/rpc-mode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAKhE,YAAY,EAAE,UAAU,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEpH;;;GAGG;AACH,wBAAsB,UAAU,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,KAAK,CAAC,CAsVtE","sourcesContent":["/**\n * RPC mode: Headless operation with JSON stdin/stdout protocol.\n *\n * Used for embedding the agent in other applications.\n * Receives commands as JSON on stdin, outputs events and responses as JSON on stdout.\n *\n * Protocol:\n * - Commands: JSON objects with `type` field, optional `id` for correlation\n * - Responses: JSON objects with `type: \"response\"`, `command`, `success`, and optional `data`/`error`\n * - Events: AgentSessionEvent objects streamed as they occur\n * - Hook UI: Hook UI requests are emitted, client responds with hook_ui_response\n */\n\nimport * as crypto from \"node:crypto\";\nimport * as readline from \"readline\";\nimport type { AgentSession } from \"../../core/agent-session.js\";\nimport type { HookUIContext } from \"../../core/hooks/index.js\";\nimport type { RpcCommand, RpcHookUIRequest, RpcHookUIResponse, RpcResponse, RpcSessionState } from \"./rpc-types.js\";\n\n// Re-export types for consumers\nexport type { RpcCommand, RpcHookUIRequest, RpcHookUIResponse, RpcResponse, RpcSessionState } from \"./rpc-types.js\";\n\n/**\n * Run in RPC mode.\n * Listens for JSON commands on stdin, outputs events and responses on stdout.\n */\nexport async function runRpcMode(session: AgentSession): Promise<never> {\n\tconst output = (obj: RpcResponse | RpcHookUIRequest | object) => {\n\t\tconsole.log(JSON.stringify(obj));\n\t};\n\n\tconst success = <T extends RpcCommand[\"type\"]>(\n\t\tid: string | undefined,\n\t\tcommand: T,\n\t\tdata?: object | null,\n\t): RpcResponse => {\n\t\tif (data === undefined) {\n\t\t\treturn { id, type: \"response\", command, success: true } as RpcResponse;\n\t\t}\n\t\treturn { id, type: \"response\", command, success: true, data } as RpcResponse;\n\t};\n\n\tconst error = (id: string | undefined, command: string, message: string): RpcResponse => {\n\t\treturn { id, type: \"response\", command, success: false, error: message };\n\t};\n\n\t// Pending hook UI requests waiting for response\n\tconst pendingHookRequests = new Map<string, { resolve: (value: any) => void; reject: (error: Error) => void }>();\n\n\t/**\n\t * Create a hook UI context that uses the RPC protocol.\n\t */\n\tconst createHookUIContext = (): HookUIContext => ({\n\t\tasync select(title: string, options: string[]): Promise<string | null> {\n\t\t\tconst id = crypto.randomUUID();\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tpendingHookRequests.set(id, {\n\t\t\t\t\tresolve: (response: RpcHookUIResponse) => {\n\t\t\t\t\t\tif (\"cancelled\" in response && response.cancelled) {\n\t\t\t\t\t\t\tresolve(null);\n\t\t\t\t\t\t} else if (\"value\" in response) {\n\t\t\t\t\t\t\tresolve(response.value);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tresolve(null);\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\treject,\n\t\t\t\t});\n\t\t\t\toutput({ type: \"hook_ui_request\", id, method: \"select\", title, options } as RpcHookUIRequest);\n\t\t\t});\n\t\t},\n\n\t\tasync confirm(title: string, message: string): Promise<boolean> {\n\t\t\tconst id = crypto.randomUUID();\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tpendingHookRequests.set(id, {\n\t\t\t\t\tresolve: (response: RpcHookUIResponse) => {\n\t\t\t\t\t\tif (\"cancelled\" in response && response.cancelled) {\n\t\t\t\t\t\t\tresolve(false);\n\t\t\t\t\t\t} else if (\"confirmed\" in response) {\n\t\t\t\t\t\t\tresolve(response.confirmed);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tresolve(false);\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\treject,\n\t\t\t\t});\n\t\t\t\toutput({ type: \"hook_ui_request\", id, method: \"confirm\", title, message } as RpcHookUIRequest);\n\t\t\t});\n\t\t},\n\n\t\tasync input(title: string, placeholder?: string): Promise<string | null> {\n\t\t\tconst id = crypto.randomUUID();\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tpendingHookRequests.set(id, {\n\t\t\t\t\tresolve: (response: RpcHookUIResponse) => {\n\t\t\t\t\t\tif (\"cancelled\" in response && response.cancelled) {\n\t\t\t\t\t\t\tresolve(null);\n\t\t\t\t\t\t} else if (\"value\" in response) {\n\t\t\t\t\t\t\tresolve(response.value);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tresolve(null);\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\treject,\n\t\t\t\t});\n\t\t\t\toutput({ type: \"hook_ui_request\", id, method: \"input\", title, placeholder } as RpcHookUIRequest);\n\t\t\t});\n\t\t},\n\n\t\tnotify(message: string, type?: \"info\" | \"warning\" | \"error\"): void {\n\t\t\t// Fire and forget - no response needed\n\t\t\toutput({\n\t\t\t\ttype: \"hook_ui_request\",\n\t\t\t\tid: crypto.randomUUID(),\n\t\t\t\tmethod: \"notify\",\n\t\t\t\tmessage,\n\t\t\t\tnotifyType: type,\n\t\t\t} as RpcHookUIRequest);\n\t\t},\n\t});\n\n\t// Set up hooks with RPC-based UI context\n\tconst hookRunner = session.hookRunner;\n\tif (hookRunner) {\n\t\thookRunner.setUIContext(createHookUIContext(), false);\n\t\thookRunner.setSessionFile(session.sessionFile);\n\t\thookRunner.onError((err) => {\n\t\t\toutput({ type: \"hook_error\", hookPath: err.hookPath, event: err.event, error: err.error });\n\t\t});\n\t\t// Set up send handler for pi.send()\n\t\thookRunner.setSendHandler((text, attachments) => {\n\t\t\t// In RPC mode, just queue or prompt based on streaming state\n\t\t\tif (session.isStreaming) {\n\t\t\t\tsession.queueMessage(text);\n\t\t\t} else {\n\t\t\t\tsession.prompt(text, { attachments }).catch((e) => {\n\t\t\t\t\toutput(error(undefined, \"hook_send\", e.message));\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t\t// Emit session_start event\n\t\tawait hookRunner.emit({ type: \"session_start\" });\n\t}\n\n\t// Output all agent events as JSON\n\tsession.subscribe((event) => {\n\t\toutput(event);\n\t});\n\n\t// Handle a single command\n\tconst handleCommand = async (command: RpcCommand): Promise<RpcResponse> => {\n\t\tconst id = command.id;\n\n\t\tswitch (command.type) {\n\t\t\t// =================================================================\n\t\t\t// Prompting\n\t\t\t// =================================================================\n\n\t\t\tcase \"prompt\": {\n\t\t\t\t// Don't await - events will stream\n\t\t\t\tsession\n\t\t\t\t\t.prompt(command.message, {\n\t\t\t\t\t\tattachments: command.attachments,\n\t\t\t\t\t\texpandSlashCommands: false,\n\t\t\t\t\t})\n\t\t\t\t\t.catch((e) => output(error(id, \"prompt\", e.message)));\n\t\t\t\treturn success(id, \"prompt\");\n\t\t\t}\n\n\t\t\tcase \"queue_message\": {\n\t\t\t\tawait session.queueMessage(command.message);\n\t\t\t\treturn success(id, \"queue_message\");\n\t\t\t}\n\n\t\t\tcase \"abort\": {\n\t\t\t\tawait session.abort();\n\t\t\t\treturn success(id, \"abort\");\n\t\t\t}\n\n\t\t\tcase \"reset\": {\n\t\t\t\tawait session.reset();\n\t\t\t\treturn success(id, \"reset\");\n\t\t\t}\n\n\t\t\t// =================================================================\n\t\t\t// State\n\t\t\t// =================================================================\n\n\t\t\tcase \"get_state\": {\n\t\t\t\tconst state: RpcSessionState = {\n\t\t\t\t\tmodel: session.model,\n\t\t\t\t\tthinkingLevel: session.thinkingLevel,\n\t\t\t\t\tisStreaming: session.isStreaming,\n\t\t\t\t\tisCompacting: session.isCompacting,\n\t\t\t\t\tqueueMode: session.queueMode,\n\t\t\t\t\tsessionFile: session.sessionFile,\n\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\tautoCompactionEnabled: session.autoCompactionEnabled,\n\t\t\t\t\tmessageCount: session.messages.length,\n\t\t\t\t\tqueuedMessageCount: session.queuedMessageCount,\n\t\t\t\t};\n\t\t\t\treturn success(id, \"get_state\", state);\n\t\t\t}\n\n\t\t\t// =================================================================\n\t\t\t// Model\n\t\t\t// =================================================================\n\n\t\t\tcase \"set_model\": {\n\t\t\t\tconst models = await session.getAvailableModels();\n\t\t\t\tconst model = models.find((m) => m.provider === command.provider && m.id === command.modelId);\n\t\t\t\tif (!model) {\n\t\t\t\t\treturn error(id, \"set_model\", `Model not found: ${command.provider}/${command.modelId}`);\n\t\t\t\t}\n\t\t\t\tawait session.setModel(model);\n\t\t\t\treturn success(id, \"set_model\", model);\n\t\t\t}\n\n\t\t\tcase \"cycle_model\": {\n\t\t\t\tconst result = await session.cycleModel();\n\t\t\t\tif (!result) {\n\t\t\t\t\treturn success(id, \"cycle_model\", null);\n\t\t\t\t}\n\t\t\t\treturn success(id, \"cycle_model\", result);\n\t\t\t}\n\n\t\t\tcase \"get_available_models\": {\n\t\t\t\tconst models = await session.getAvailableModels();\n\t\t\t\treturn success(id, \"get_available_models\", { models });\n\t\t\t}\n\n\t\t\t// =================================================================\n\t\t\t// Thinking\n\t\t\t// =================================================================\n\n\t\t\tcase \"set_thinking_level\": {\n\t\t\t\tsession.setThinkingLevel(command.level);\n\t\t\t\treturn success(id, \"set_thinking_level\");\n\t\t\t}\n\n\t\t\tcase \"cycle_thinking_level\": {\n\t\t\t\tconst level = session.cycleThinkingLevel();\n\t\t\t\tif (!level) {\n\t\t\t\t\treturn success(id, \"cycle_thinking_level\", null);\n\t\t\t\t}\n\t\t\t\treturn success(id, \"cycle_thinking_level\", { level });\n\t\t\t}\n\n\t\t\t// =================================================================\n\t\t\t// Queue Mode\n\t\t\t// =================================================================\n\n\t\t\tcase \"set_queue_mode\": {\n\t\t\t\tsession.setQueueMode(command.mode);\n\t\t\t\treturn success(id, \"set_queue_mode\");\n\t\t\t}\n\n\t\t\t// =================================================================\n\t\t\t// Compaction\n\t\t\t// =================================================================\n\n\t\t\tcase \"compact\": {\n\t\t\t\tconst result = await session.compact(command.customInstructions);\n\t\t\t\treturn success(id, \"compact\", result);\n\t\t\t}\n\n\t\t\tcase \"set_auto_compaction\": {\n\t\t\t\tsession.setAutoCompactionEnabled(command.enabled);\n\t\t\t\treturn success(id, \"set_auto_compaction\");\n\t\t\t}\n\n\t\t\t// =================================================================\n\t\t\t// Bash\n\t\t\t// =================================================================\n\n\t\t\tcase \"bash\": {\n\t\t\t\tconst result = await session.executeBash(command.command);\n\t\t\t\treturn success(id, \"bash\", result);\n\t\t\t}\n\n\t\t\tcase \"abort_bash\": {\n\t\t\t\tsession.abortBash();\n\t\t\t\treturn success(id, \"abort_bash\");\n\t\t\t}\n\n\t\t\t// =================================================================\n\t\t\t// Session\n\t\t\t// =================================================================\n\n\t\t\tcase \"get_session_stats\": {\n\t\t\t\tconst stats = session.getSessionStats();\n\t\t\t\treturn success(id, \"get_session_stats\", stats);\n\t\t\t}\n\n\t\t\tcase \"export_html\": {\n\t\t\t\tconst path = session.exportToHtml(command.outputPath);\n\t\t\t\treturn success(id, \"export_html\", { path });\n\t\t\t}\n\n\t\t\tcase \"switch_session\": {\n\t\t\t\tawait session.switchSession(command.sessionPath);\n\t\t\t\treturn success(id, \"switch_session\");\n\t\t\t}\n\n\t\t\tcase \"branch\": {\n\t\t\t\tconst result = await session.branch(command.entryIndex);\n\t\t\t\treturn success(id, \"branch\", { text: result.selectedText, skipped: result.skipped });\n\t\t\t}\n\n\t\t\tcase \"get_branch_messages\": {\n\t\t\t\tconst messages = session.getUserMessagesForBranching();\n\t\t\t\treturn success(id, \"get_branch_messages\", { messages });\n\t\t\t}\n\n\t\t\tcase \"get_last_assistant_text\": {\n\t\t\t\tconst text = session.getLastAssistantText();\n\t\t\t\treturn success(id, \"get_last_assistant_text\", { text });\n\t\t\t}\n\n\t\t\t// =================================================================\n\t\t\t// Messages\n\t\t\t// =================================================================\n\n\t\t\tcase \"get_messages\": {\n\t\t\t\treturn success(id, \"get_messages\", { messages: session.messages });\n\t\t\t}\n\n\t\t\tdefault: {\n\t\t\t\tconst unknownCommand = command as { type: string };\n\t\t\t\treturn error(undefined, unknownCommand.type, `Unknown command: ${unknownCommand.type}`);\n\t\t\t}\n\t\t}\n\t};\n\n\t// Listen for JSON input\n\tconst rl = readline.createInterface({\n\t\tinput: process.stdin,\n\t\toutput: process.stdout,\n\t\tterminal: false,\n\t});\n\n\trl.on(\"line\", async (line: string) => {\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(line);\n\n\t\t\t// Handle hook UI responses\n\t\t\tif (parsed.type === \"hook_ui_response\") {\n\t\t\t\tconst response = parsed as RpcHookUIResponse;\n\t\t\t\tconst pending = pendingHookRequests.get(response.id);\n\t\t\t\tif (pending) {\n\t\t\t\t\tpendingHookRequests.delete(response.id);\n\t\t\t\t\tpending.resolve(response);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Handle regular commands\n\t\t\tconst command = parsed as RpcCommand;\n\t\t\tconst response = await handleCommand(command);\n\t\t\toutput(response);\n\t\t} catch (e: any) {\n\t\t\toutput(error(undefined, \"parse\", `Failed to parse command: ${e.message}`));\n\t\t}\n\t});\n\n\t// Keep process alive forever\n\treturn new Promise(() => {});\n}\n"]}
1
+ {"version":3,"file":"rpc-mode.d.ts","sourceRoot":"","sources":["../../../src/modes/rpc/rpc-mode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAKhE,YAAY,EAAE,UAAU,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEpH;;;GAGG;AACH,wBAAsB,UAAU,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,KAAK,CAAC,CAoWtE","sourcesContent":["/**\n * RPC mode: Headless operation with JSON stdin/stdout protocol.\n *\n * Used for embedding the agent in other applications.\n * Receives commands as JSON on stdin, outputs events and responses as JSON on stdout.\n *\n * Protocol:\n * - Commands: JSON objects with `type` field, optional `id` for correlation\n * - Responses: JSON objects with `type: \"response\"`, `command`, `success`, and optional `data`/`error`\n * - Events: AgentSessionEvent objects streamed as they occur\n * - Hook UI: Hook UI requests are emitted, client responds with hook_ui_response\n */\n\nimport * as crypto from \"node:crypto\";\nimport * as readline from \"readline\";\nimport type { AgentSession } from \"../../core/agent-session.js\";\nimport type { HookUIContext } from \"../../core/hooks/index.js\";\nimport type { RpcCommand, RpcHookUIRequest, RpcHookUIResponse, RpcResponse, RpcSessionState } from \"./rpc-types.js\";\n\n// Re-export types for consumers\nexport type { RpcCommand, RpcHookUIRequest, RpcHookUIResponse, RpcResponse, RpcSessionState } from \"./rpc-types.js\";\n\n/**\n * Run in RPC mode.\n * Listens for JSON commands on stdin, outputs events and responses on stdout.\n */\nexport async function runRpcMode(session: AgentSession): Promise<never> {\n\tconst output = (obj: RpcResponse | RpcHookUIRequest | object) => {\n\t\tconsole.log(JSON.stringify(obj));\n\t};\n\n\tconst success = <T extends RpcCommand[\"type\"]>(\n\t\tid: string | undefined,\n\t\tcommand: T,\n\t\tdata?: object | null,\n\t): RpcResponse => {\n\t\tif (data === undefined) {\n\t\t\treturn { id, type: \"response\", command, success: true } as RpcResponse;\n\t\t}\n\t\treturn { id, type: \"response\", command, success: true, data } as RpcResponse;\n\t};\n\n\tconst error = (id: string | undefined, command: string, message: string): RpcResponse => {\n\t\treturn { id, type: \"response\", command, success: false, error: message };\n\t};\n\n\t// Pending hook UI requests waiting for response\n\tconst pendingHookRequests = new Map<string, { resolve: (value: any) => void; reject: (error: Error) => void }>();\n\n\t/**\n\t * Create a hook UI context that uses the RPC protocol.\n\t */\n\tconst createHookUIContext = (): HookUIContext => ({\n\t\tasync select(title: string, options: string[]): Promise<string | null> {\n\t\t\tconst id = crypto.randomUUID();\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tpendingHookRequests.set(id, {\n\t\t\t\t\tresolve: (response: RpcHookUIResponse) => {\n\t\t\t\t\t\tif (\"cancelled\" in response && response.cancelled) {\n\t\t\t\t\t\t\tresolve(null);\n\t\t\t\t\t\t} else if (\"value\" in response) {\n\t\t\t\t\t\t\tresolve(response.value);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tresolve(null);\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\treject,\n\t\t\t\t});\n\t\t\t\toutput({ type: \"hook_ui_request\", id, method: \"select\", title, options } as RpcHookUIRequest);\n\t\t\t});\n\t\t},\n\n\t\tasync confirm(title: string, message: string): Promise<boolean> {\n\t\t\tconst id = crypto.randomUUID();\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tpendingHookRequests.set(id, {\n\t\t\t\t\tresolve: (response: RpcHookUIResponse) => {\n\t\t\t\t\t\tif (\"cancelled\" in response && response.cancelled) {\n\t\t\t\t\t\t\tresolve(false);\n\t\t\t\t\t\t} else if (\"confirmed\" in response) {\n\t\t\t\t\t\t\tresolve(response.confirmed);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tresolve(false);\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\treject,\n\t\t\t\t});\n\t\t\t\toutput({ type: \"hook_ui_request\", id, method: \"confirm\", title, message } as RpcHookUIRequest);\n\t\t\t});\n\t\t},\n\n\t\tasync input(title: string, placeholder?: string): Promise<string | null> {\n\t\t\tconst id = crypto.randomUUID();\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tpendingHookRequests.set(id, {\n\t\t\t\t\tresolve: (response: RpcHookUIResponse) => {\n\t\t\t\t\t\tif (\"cancelled\" in response && response.cancelled) {\n\t\t\t\t\t\t\tresolve(null);\n\t\t\t\t\t\t} else if (\"value\" in response) {\n\t\t\t\t\t\t\tresolve(response.value);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tresolve(null);\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\treject,\n\t\t\t\t});\n\t\t\t\toutput({ type: \"hook_ui_request\", id, method: \"input\", title, placeholder } as RpcHookUIRequest);\n\t\t\t});\n\t\t},\n\n\t\tnotify(message: string, type?: \"info\" | \"warning\" | \"error\"): void {\n\t\t\t// Fire and forget - no response needed\n\t\t\toutput({\n\t\t\t\ttype: \"hook_ui_request\",\n\t\t\t\tid: crypto.randomUUID(),\n\t\t\t\tmethod: \"notify\",\n\t\t\t\tmessage,\n\t\t\t\tnotifyType: type,\n\t\t\t} as RpcHookUIRequest);\n\t\t},\n\t});\n\n\t// Set up hooks with RPC-based UI context\n\tconst hookRunner = session.hookRunner;\n\tif (hookRunner) {\n\t\thookRunner.setUIContext(createHookUIContext(), false);\n\t\thookRunner.setSessionFile(session.sessionFile);\n\t\thookRunner.onError((err) => {\n\t\t\toutput({ type: \"hook_error\", hookPath: err.hookPath, event: err.event, error: err.error });\n\t\t});\n\t\t// Set up send handler for pi.send()\n\t\thookRunner.setSendHandler((text, attachments) => {\n\t\t\t// In RPC mode, just queue or prompt based on streaming state\n\t\t\tif (session.isStreaming) {\n\t\t\t\tsession.queueMessage(text);\n\t\t\t} else {\n\t\t\t\tsession.prompt(text, { attachments }).catch((e) => {\n\t\t\t\t\toutput(error(undefined, \"hook_send\", e.message));\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t\t// Emit session_start event\n\t\tawait hookRunner.emit({ type: \"session_start\" });\n\t}\n\n\t// Output all agent events as JSON\n\tsession.subscribe((event) => {\n\t\toutput(event);\n\t});\n\n\t// Handle a single command\n\tconst handleCommand = async (command: RpcCommand): Promise<RpcResponse> => {\n\t\tconst id = command.id;\n\n\t\tswitch (command.type) {\n\t\t\t// =================================================================\n\t\t\t// Prompting\n\t\t\t// =================================================================\n\n\t\t\tcase \"prompt\": {\n\t\t\t\t// Don't await - events will stream\n\t\t\t\tsession\n\t\t\t\t\t.prompt(command.message, {\n\t\t\t\t\t\tattachments: command.attachments,\n\t\t\t\t\t\texpandSlashCommands: false,\n\t\t\t\t\t})\n\t\t\t\t\t.catch((e) => output(error(id, \"prompt\", e.message)));\n\t\t\t\treturn success(id, \"prompt\");\n\t\t\t}\n\n\t\t\tcase \"queue_message\": {\n\t\t\t\tawait session.queueMessage(command.message);\n\t\t\t\treturn success(id, \"queue_message\");\n\t\t\t}\n\n\t\t\tcase \"abort\": {\n\t\t\t\tawait session.abort();\n\t\t\t\treturn success(id, \"abort\");\n\t\t\t}\n\n\t\t\tcase \"reset\": {\n\t\t\t\tawait session.reset();\n\t\t\t\treturn success(id, \"reset\");\n\t\t\t}\n\n\t\t\t// =================================================================\n\t\t\t// State\n\t\t\t// =================================================================\n\n\t\t\tcase \"get_state\": {\n\t\t\t\tconst state: RpcSessionState = {\n\t\t\t\t\tmodel: session.model,\n\t\t\t\t\tthinkingLevel: session.thinkingLevel,\n\t\t\t\t\tisStreaming: session.isStreaming,\n\t\t\t\t\tisCompacting: session.isCompacting,\n\t\t\t\t\tqueueMode: session.queueMode,\n\t\t\t\t\tsessionFile: session.sessionFile,\n\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\tautoCompactionEnabled: session.autoCompactionEnabled,\n\t\t\t\t\tmessageCount: session.messages.length,\n\t\t\t\t\tqueuedMessageCount: session.queuedMessageCount,\n\t\t\t\t};\n\t\t\t\treturn success(id, \"get_state\", state);\n\t\t\t}\n\n\t\t\t// =================================================================\n\t\t\t// Model\n\t\t\t// =================================================================\n\n\t\t\tcase \"set_model\": {\n\t\t\t\tconst models = await session.getAvailableModels();\n\t\t\t\tconst model = models.find((m) => m.provider === command.provider && m.id === command.modelId);\n\t\t\t\tif (!model) {\n\t\t\t\t\treturn error(id, \"set_model\", `Model not found: ${command.provider}/${command.modelId}`);\n\t\t\t\t}\n\t\t\t\tawait session.setModel(model);\n\t\t\t\treturn success(id, \"set_model\", model);\n\t\t\t}\n\n\t\t\tcase \"cycle_model\": {\n\t\t\t\tconst result = await session.cycleModel();\n\t\t\t\tif (!result) {\n\t\t\t\t\treturn success(id, \"cycle_model\", null);\n\t\t\t\t}\n\t\t\t\treturn success(id, \"cycle_model\", result);\n\t\t\t}\n\n\t\t\tcase \"get_available_models\": {\n\t\t\t\tconst models = await session.getAvailableModels();\n\t\t\t\treturn success(id, \"get_available_models\", { models });\n\t\t\t}\n\n\t\t\t// =================================================================\n\t\t\t// Thinking\n\t\t\t// =================================================================\n\n\t\t\tcase \"set_thinking_level\": {\n\t\t\t\tsession.setThinkingLevel(command.level);\n\t\t\t\treturn success(id, \"set_thinking_level\");\n\t\t\t}\n\n\t\t\tcase \"cycle_thinking_level\": {\n\t\t\t\tconst level = session.cycleThinkingLevel();\n\t\t\t\tif (!level) {\n\t\t\t\t\treturn success(id, \"cycle_thinking_level\", null);\n\t\t\t\t}\n\t\t\t\treturn success(id, \"cycle_thinking_level\", { level });\n\t\t\t}\n\n\t\t\t// =================================================================\n\t\t\t// Queue Mode\n\t\t\t// =================================================================\n\n\t\t\tcase \"set_queue_mode\": {\n\t\t\t\tsession.setQueueMode(command.mode);\n\t\t\t\treturn success(id, \"set_queue_mode\");\n\t\t\t}\n\n\t\t\t// =================================================================\n\t\t\t// Compaction\n\t\t\t// =================================================================\n\n\t\t\tcase \"compact\": {\n\t\t\t\tconst result = await session.compact(command.customInstructions);\n\t\t\t\treturn success(id, \"compact\", result);\n\t\t\t}\n\n\t\t\tcase \"set_auto_compaction\": {\n\t\t\t\tsession.setAutoCompactionEnabled(command.enabled);\n\t\t\t\treturn success(id, \"set_auto_compaction\");\n\t\t\t}\n\n\t\t\t// =================================================================\n\t\t\t// Retry\n\t\t\t// =================================================================\n\n\t\t\tcase \"set_auto_retry\": {\n\t\t\t\tsession.setAutoRetryEnabled(command.enabled);\n\t\t\t\treturn success(id, \"set_auto_retry\");\n\t\t\t}\n\n\t\t\tcase \"abort_retry\": {\n\t\t\t\tsession.abortRetry();\n\t\t\t\treturn success(id, \"abort_retry\");\n\t\t\t}\n\n\t\t\t// =================================================================\n\t\t\t// Bash\n\t\t\t// =================================================================\n\n\t\t\tcase \"bash\": {\n\t\t\t\tconst result = await session.executeBash(command.command);\n\t\t\t\treturn success(id, \"bash\", result);\n\t\t\t}\n\n\t\t\tcase \"abort_bash\": {\n\t\t\t\tsession.abortBash();\n\t\t\t\treturn success(id, \"abort_bash\");\n\t\t\t}\n\n\t\t\t// =================================================================\n\t\t\t// Session\n\t\t\t// =================================================================\n\n\t\t\tcase \"get_session_stats\": {\n\t\t\t\tconst stats = session.getSessionStats();\n\t\t\t\treturn success(id, \"get_session_stats\", stats);\n\t\t\t}\n\n\t\t\tcase \"export_html\": {\n\t\t\t\tconst path = session.exportToHtml(command.outputPath);\n\t\t\t\treturn success(id, \"export_html\", { path });\n\t\t\t}\n\n\t\t\tcase \"switch_session\": {\n\t\t\t\tawait session.switchSession(command.sessionPath);\n\t\t\t\treturn success(id, \"switch_session\");\n\t\t\t}\n\n\t\t\tcase \"branch\": {\n\t\t\t\tconst result = await session.branch(command.entryIndex);\n\t\t\t\treturn success(id, \"branch\", { text: result.selectedText, skipped: result.skipped });\n\t\t\t}\n\n\t\t\tcase \"get_branch_messages\": {\n\t\t\t\tconst messages = session.getUserMessagesForBranching();\n\t\t\t\treturn success(id, \"get_branch_messages\", { messages });\n\t\t\t}\n\n\t\t\tcase \"get_last_assistant_text\": {\n\t\t\t\tconst text = session.getLastAssistantText();\n\t\t\t\treturn success(id, \"get_last_assistant_text\", { text });\n\t\t\t}\n\n\t\t\t// =================================================================\n\t\t\t// Messages\n\t\t\t// =================================================================\n\n\t\t\tcase \"get_messages\": {\n\t\t\t\treturn success(id, \"get_messages\", { messages: session.messages });\n\t\t\t}\n\n\t\t\tdefault: {\n\t\t\t\tconst unknownCommand = command as { type: string };\n\t\t\t\treturn error(undefined, unknownCommand.type, `Unknown command: ${unknownCommand.type}`);\n\t\t\t}\n\t\t}\n\t};\n\n\t// Listen for JSON input\n\tconst rl = readline.createInterface({\n\t\tinput: process.stdin,\n\t\toutput: process.stdout,\n\t\tterminal: false,\n\t});\n\n\trl.on(\"line\", async (line: string) => {\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(line);\n\n\t\t\t// Handle hook UI responses\n\t\t\tif (parsed.type === \"hook_ui_response\") {\n\t\t\t\tconst response = parsed as RpcHookUIResponse;\n\t\t\t\tconst pending = pendingHookRequests.get(response.id);\n\t\t\t\tif (pending) {\n\t\t\t\t\tpendingHookRequests.delete(response.id);\n\t\t\t\t\tpending.resolve(response);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Handle regular commands\n\t\t\tconst command = parsed as RpcCommand;\n\t\t\tconst response = await handleCommand(command);\n\t\t\toutput(response);\n\t\t} catch (e: any) {\n\t\t\toutput(error(undefined, \"parse\", `Failed to parse command: ${e.message}`));\n\t\t}\n\t});\n\n\t// Keep process alive forever\n\treturn new Promise(() => {});\n}\n"]}
@@ -236,6 +236,17 @@ export async function runRpcMode(session) {
236
236
  return success(id, "set_auto_compaction");
237
237
  }
238
238
  // =================================================================
239
+ // Retry
240
+ // =================================================================
241
+ case "set_auto_retry": {
242
+ session.setAutoRetryEnabled(command.enabled);
243
+ return success(id, "set_auto_retry");
244
+ }
245
+ case "abort_retry": {
246
+ session.abortRetry();
247
+ return success(id, "abort_retry");
248
+ }
249
+ // =================================================================
239
250
  // Bash
240
251
  // =================================================================
241
252
  case "bash": {
@@ -1 +1 @@
1
- {"version":3,"file":"rpc-mode.js","sourceRoot":"","sources":["../../../src/modes/rpc/rpc-mode.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * RPC mode: Headless operation with JSON stdin/stdout protocol.\n *\n * Used for embedding the agent in other applications.\n * Receives commands as JSON on stdin, outputs events and responses as JSON on stdout.\n *\n * Protocol:\n * - Commands: JSON objects with `type` field, optional `id` for correlation\n * - Responses: JSON objects with `type: \"response\"`, `command`, `success`, and optional `data`/`error`\n * - Events: AgentSessionEvent objects streamed as they occur\n * - Hook UI: Hook UI requests are emitted, client responds with hook_ui_response\n */\n\nimport * as crypto from \"node:crypto\";\nimport * as readline from \"readline\";\nimport type { AgentSession } from \"../../core/agent-session.js\";\nimport type { HookUIContext } from \"../../core/hooks/index.js\";\nimport type { RpcCommand, RpcHookUIRequest, RpcHookUIResponse, RpcResponse, RpcSessionState } from \"./rpc-types.js\";\n\n// Re-export types for consumers\nexport type { RpcCommand, RpcHookUIRequest, RpcHookUIResponse, RpcResponse, RpcSessionState } from \"./rpc-types.js\";\n\n/**\n * Run in RPC mode.\n * Listens for JSON commands on stdin, outputs events and responses on stdout.\n */\nexport async function runRpcMode(session: AgentSession): Promise<never> {\n\tconst output = (obj: RpcResponse | RpcHookUIRequest | object) => {\n\t\tconsole.log(JSON.stringify(obj));\n\t};\n\n\tconst success = <T extends RpcCommand[\"type\"]>(\n\t\tid: string | undefined,\n\t\tcommand: T,\n\t\tdata?: object | null,\n\t): RpcResponse => {\n\t\tif (data === undefined) {\n\t\t\treturn { id, type: \"response\", command, success: true } as RpcResponse;\n\t\t}\n\t\treturn { id, type: \"response\", command, success: true, data } as RpcResponse;\n\t};\n\n\tconst error = (id: string | undefined, command: string, message: string): RpcResponse => {\n\t\treturn { id, type: \"response\", command, success: false, error: message };\n\t};\n\n\t// Pending hook UI requests waiting for response\n\tconst pendingHookRequests = new Map<string, { resolve: (value: any) => void; reject: (error: Error) => void }>();\n\n\t/**\n\t * Create a hook UI context that uses the RPC protocol.\n\t */\n\tconst createHookUIContext = (): HookUIContext => ({\n\t\tasync select(title: string, options: string[]): Promise<string | null> {\n\t\t\tconst id = crypto.randomUUID();\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tpendingHookRequests.set(id, {\n\t\t\t\t\tresolve: (response: RpcHookUIResponse) => {\n\t\t\t\t\t\tif (\"cancelled\" in response && response.cancelled) {\n\t\t\t\t\t\t\tresolve(null);\n\t\t\t\t\t\t} else if (\"value\" in response) {\n\t\t\t\t\t\t\tresolve(response.value);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tresolve(null);\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\treject,\n\t\t\t\t});\n\t\t\t\toutput({ type: \"hook_ui_request\", id, method: \"select\", title, options } as RpcHookUIRequest);\n\t\t\t});\n\t\t},\n\n\t\tasync confirm(title: string, message: string): Promise<boolean> {\n\t\t\tconst id = crypto.randomUUID();\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tpendingHookRequests.set(id, {\n\t\t\t\t\tresolve: (response: RpcHookUIResponse) => {\n\t\t\t\t\t\tif (\"cancelled\" in response && response.cancelled) {\n\t\t\t\t\t\t\tresolve(false);\n\t\t\t\t\t\t} else if (\"confirmed\" in response) {\n\t\t\t\t\t\t\tresolve(response.confirmed);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tresolve(false);\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\treject,\n\t\t\t\t});\n\t\t\t\toutput({ type: \"hook_ui_request\", id, method: \"confirm\", title, message } as RpcHookUIRequest);\n\t\t\t});\n\t\t},\n\n\t\tasync input(title: string, placeholder?: string): Promise<string | null> {\n\t\t\tconst id = crypto.randomUUID();\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tpendingHookRequests.set(id, {\n\t\t\t\t\tresolve: (response: RpcHookUIResponse) => {\n\t\t\t\t\t\tif (\"cancelled\" in response && response.cancelled) {\n\t\t\t\t\t\t\tresolve(null);\n\t\t\t\t\t\t} else if (\"value\" in response) {\n\t\t\t\t\t\t\tresolve(response.value);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tresolve(null);\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\treject,\n\t\t\t\t});\n\t\t\t\toutput({ type: \"hook_ui_request\", id, method: \"input\", title, placeholder } as RpcHookUIRequest);\n\t\t\t});\n\t\t},\n\n\t\tnotify(message: string, type?: \"info\" | \"warning\" | \"error\"): void {\n\t\t\t// Fire and forget - no response needed\n\t\t\toutput({\n\t\t\t\ttype: \"hook_ui_request\",\n\t\t\t\tid: crypto.randomUUID(),\n\t\t\t\tmethod: \"notify\",\n\t\t\t\tmessage,\n\t\t\t\tnotifyType: type,\n\t\t\t} as RpcHookUIRequest);\n\t\t},\n\t});\n\n\t// Set up hooks with RPC-based UI context\n\tconst hookRunner = session.hookRunner;\n\tif (hookRunner) {\n\t\thookRunner.setUIContext(createHookUIContext(), false);\n\t\thookRunner.setSessionFile(session.sessionFile);\n\t\thookRunner.onError((err) => {\n\t\t\toutput({ type: \"hook_error\", hookPath: err.hookPath, event: err.event, error: err.error });\n\t\t});\n\t\t// Set up send handler for pi.send()\n\t\thookRunner.setSendHandler((text, attachments) => {\n\t\t\t// In RPC mode, just queue or prompt based on streaming state\n\t\t\tif (session.isStreaming) {\n\t\t\t\tsession.queueMessage(text);\n\t\t\t} else {\n\t\t\t\tsession.prompt(text, { attachments }).catch((e) => {\n\t\t\t\t\toutput(error(undefined, \"hook_send\", e.message));\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t\t// Emit session_start event\n\t\tawait hookRunner.emit({ type: \"session_start\" });\n\t}\n\n\t// Output all agent events as JSON\n\tsession.subscribe((event) => {\n\t\toutput(event);\n\t});\n\n\t// Handle a single command\n\tconst handleCommand = async (command: RpcCommand): Promise<RpcResponse> => {\n\t\tconst id = command.id;\n\n\t\tswitch (command.type) {\n\t\t\t// =================================================================\n\t\t\t// Prompting\n\t\t\t// =================================================================\n\n\t\t\tcase \"prompt\": {\n\t\t\t\t// Don't await - events will stream\n\t\t\t\tsession\n\t\t\t\t\t.prompt(command.message, {\n\t\t\t\t\t\tattachments: command.attachments,\n\t\t\t\t\t\texpandSlashCommands: false,\n\t\t\t\t\t})\n\t\t\t\t\t.catch((e) => output(error(id, \"prompt\", e.message)));\n\t\t\t\treturn success(id, \"prompt\");\n\t\t\t}\n\n\t\t\tcase \"queue_message\": {\n\t\t\t\tawait session.queueMessage(command.message);\n\t\t\t\treturn success(id, \"queue_message\");\n\t\t\t}\n\n\t\t\tcase \"abort\": {\n\t\t\t\tawait session.abort();\n\t\t\t\treturn success(id, \"abort\");\n\t\t\t}\n\n\t\t\tcase \"reset\": {\n\t\t\t\tawait session.reset();\n\t\t\t\treturn success(id, \"reset\");\n\t\t\t}\n\n\t\t\t// =================================================================\n\t\t\t// State\n\t\t\t// =================================================================\n\n\t\t\tcase \"get_state\": {\n\t\t\t\tconst state: RpcSessionState = {\n\t\t\t\t\tmodel: session.model,\n\t\t\t\t\tthinkingLevel: session.thinkingLevel,\n\t\t\t\t\tisStreaming: session.isStreaming,\n\t\t\t\t\tisCompacting: session.isCompacting,\n\t\t\t\t\tqueueMode: session.queueMode,\n\t\t\t\t\tsessionFile: session.sessionFile,\n\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\tautoCompactionEnabled: session.autoCompactionEnabled,\n\t\t\t\t\tmessageCount: session.messages.length,\n\t\t\t\t\tqueuedMessageCount: session.queuedMessageCount,\n\t\t\t\t};\n\t\t\t\treturn success(id, \"get_state\", state);\n\t\t\t}\n\n\t\t\t// =================================================================\n\t\t\t// Model\n\t\t\t// =================================================================\n\n\t\t\tcase \"set_model\": {\n\t\t\t\tconst models = await session.getAvailableModels();\n\t\t\t\tconst model = models.find((m) => m.provider === command.provider && m.id === command.modelId);\n\t\t\t\tif (!model) {\n\t\t\t\t\treturn error(id, \"set_model\", `Model not found: ${command.provider}/${command.modelId}`);\n\t\t\t\t}\n\t\t\t\tawait session.setModel(model);\n\t\t\t\treturn success(id, \"set_model\", model);\n\t\t\t}\n\n\t\t\tcase \"cycle_model\": {\n\t\t\t\tconst result = await session.cycleModel();\n\t\t\t\tif (!result) {\n\t\t\t\t\treturn success(id, \"cycle_model\", null);\n\t\t\t\t}\n\t\t\t\treturn success(id, \"cycle_model\", result);\n\t\t\t}\n\n\t\t\tcase \"get_available_models\": {\n\t\t\t\tconst models = await session.getAvailableModels();\n\t\t\t\treturn success(id, \"get_available_models\", { models });\n\t\t\t}\n\n\t\t\t// =================================================================\n\t\t\t// Thinking\n\t\t\t// =================================================================\n\n\t\t\tcase \"set_thinking_level\": {\n\t\t\t\tsession.setThinkingLevel(command.level);\n\t\t\t\treturn success(id, \"set_thinking_level\");\n\t\t\t}\n\n\t\t\tcase \"cycle_thinking_level\": {\n\t\t\t\tconst level = session.cycleThinkingLevel();\n\t\t\t\tif (!level) {\n\t\t\t\t\treturn success(id, \"cycle_thinking_level\", null);\n\t\t\t\t}\n\t\t\t\treturn success(id, \"cycle_thinking_level\", { level });\n\t\t\t}\n\n\t\t\t// =================================================================\n\t\t\t// Queue Mode\n\t\t\t// =================================================================\n\n\t\t\tcase \"set_queue_mode\": {\n\t\t\t\tsession.setQueueMode(command.mode);\n\t\t\t\treturn success(id, \"set_queue_mode\");\n\t\t\t}\n\n\t\t\t// =================================================================\n\t\t\t// Compaction\n\t\t\t// =================================================================\n\n\t\t\tcase \"compact\": {\n\t\t\t\tconst result = await session.compact(command.customInstructions);\n\t\t\t\treturn success(id, \"compact\", result);\n\t\t\t}\n\n\t\t\tcase \"set_auto_compaction\": {\n\t\t\t\tsession.setAutoCompactionEnabled(command.enabled);\n\t\t\t\treturn success(id, \"set_auto_compaction\");\n\t\t\t}\n\n\t\t\t// =================================================================\n\t\t\t// Bash\n\t\t\t// =================================================================\n\n\t\t\tcase \"bash\": {\n\t\t\t\tconst result = await session.executeBash(command.command);\n\t\t\t\treturn success(id, \"bash\", result);\n\t\t\t}\n\n\t\t\tcase \"abort_bash\": {\n\t\t\t\tsession.abortBash();\n\t\t\t\treturn success(id, \"abort_bash\");\n\t\t\t}\n\n\t\t\t// =================================================================\n\t\t\t// Session\n\t\t\t// =================================================================\n\n\t\t\tcase \"get_session_stats\": {\n\t\t\t\tconst stats = session.getSessionStats();\n\t\t\t\treturn success(id, \"get_session_stats\", stats);\n\t\t\t}\n\n\t\t\tcase \"export_html\": {\n\t\t\t\tconst path = session.exportToHtml(command.outputPath);\n\t\t\t\treturn success(id, \"export_html\", { path });\n\t\t\t}\n\n\t\t\tcase \"switch_session\": {\n\t\t\t\tawait session.switchSession(command.sessionPath);\n\t\t\t\treturn success(id, \"switch_session\");\n\t\t\t}\n\n\t\t\tcase \"branch\": {\n\t\t\t\tconst result = await session.branch(command.entryIndex);\n\t\t\t\treturn success(id, \"branch\", { text: result.selectedText, skipped: result.skipped });\n\t\t\t}\n\n\t\t\tcase \"get_branch_messages\": {\n\t\t\t\tconst messages = session.getUserMessagesForBranching();\n\t\t\t\treturn success(id, \"get_branch_messages\", { messages });\n\t\t\t}\n\n\t\t\tcase \"get_last_assistant_text\": {\n\t\t\t\tconst text = session.getLastAssistantText();\n\t\t\t\treturn success(id, \"get_last_assistant_text\", { text });\n\t\t\t}\n\n\t\t\t// =================================================================\n\t\t\t// Messages\n\t\t\t// =================================================================\n\n\t\t\tcase \"get_messages\": {\n\t\t\t\treturn success(id, \"get_messages\", { messages: session.messages });\n\t\t\t}\n\n\t\t\tdefault: {\n\t\t\t\tconst unknownCommand = command as { type: string };\n\t\t\t\treturn error(undefined, unknownCommand.type, `Unknown command: ${unknownCommand.type}`);\n\t\t\t}\n\t\t}\n\t};\n\n\t// Listen for JSON input\n\tconst rl = readline.createInterface({\n\t\tinput: process.stdin,\n\t\toutput: process.stdout,\n\t\tterminal: false,\n\t});\n\n\trl.on(\"line\", async (line: string) => {\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(line);\n\n\t\t\t// Handle hook UI responses\n\t\t\tif (parsed.type === \"hook_ui_response\") {\n\t\t\t\tconst response = parsed as RpcHookUIResponse;\n\t\t\t\tconst pending = pendingHookRequests.get(response.id);\n\t\t\t\tif (pending) {\n\t\t\t\t\tpendingHookRequests.delete(response.id);\n\t\t\t\t\tpending.resolve(response);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Handle regular commands\n\t\t\tconst command = parsed as RpcCommand;\n\t\t\tconst response = await handleCommand(command);\n\t\t\toutput(response);\n\t\t} catch (e: any) {\n\t\t\toutput(error(undefined, \"parse\", `Failed to parse command: ${e.message}`));\n\t\t}\n\t});\n\n\t// Keep process alive forever\n\treturn new Promise(() => {});\n}\n"]}
1
+ {"version":3,"file":"rpc-mode.js","sourceRoot":"","sources":["../../../src/modes/rpc/rpc-mode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,QAAQ,MAAM,UAAU,CAAC;AAQrC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,OAAqB,EAAkB;IACvE,MAAM,MAAM,GAAG,CAAC,GAA4C,EAAE,EAAE,CAAC;QAChE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;IAAA,CACjC,CAAC;IAEF,MAAM,OAAO,GAAG,CACf,EAAsB,EACtB,OAAU,EACV,IAAoB,EACN,EAAE,CAAC;QACjB,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACxB,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAiB,CAAC;QACxE,CAAC;QACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAiB,CAAC;IAAA,CAC7E,CAAC;IAEF,MAAM,KAAK,GAAG,CAAC,EAAsB,EAAE,OAAe,EAAE,OAAe,EAAe,EAAE,CAAC;QACxF,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;IAAA,CACzE,CAAC;IAEF,gDAAgD;IAChD,MAAM,mBAAmB,GAAG,IAAI,GAAG,EAA6E,CAAC;IAEjH;;OAEG;IACH,MAAM,mBAAmB,GAAG,GAAkB,EAAE,CAAC,CAAC;QACjD,KAAK,CAAC,MAAM,CAAC,KAAa,EAAE,OAAiB,EAA0B;YACtE,MAAM,EAAE,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;YAC/B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC;gBACvC,mBAAmB,CAAC,GAAG,CAAC,EAAE,EAAE;oBAC3B,OAAO,EAAE,CAAC,QAA2B,EAAE,EAAE,CAAC;wBACzC,IAAI,WAAW,IAAI,QAAQ,IAAI,QAAQ,CAAC,SAAS,EAAE,CAAC;4BACnD,OAAO,CAAC,IAAI,CAAC,CAAC;wBACf,CAAC;6BAAM,IAAI,OAAO,IAAI,QAAQ,EAAE,CAAC;4BAChC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;wBACzB,CAAC;6BAAM,CAAC;4BACP,OAAO,CAAC,IAAI,CAAC,CAAC;wBACf,CAAC;oBAAA,CACD;oBACD,MAAM;iBACN,CAAC,CAAC;gBACH,MAAM,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAsB,CAAC,CAAC;YAAA,CAC9F,CAAC,CAAC;QAAA,CACH;QAED,KAAK,CAAC,OAAO,CAAC,KAAa,EAAE,OAAe,EAAoB;YAC/D,MAAM,EAAE,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;YAC/B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC;gBACvC,mBAAmB,CAAC,GAAG,CAAC,EAAE,EAAE;oBAC3B,OAAO,EAAE,CAAC,QAA2B,EAAE,EAAE,CAAC;wBACzC,IAAI,WAAW,IAAI,QAAQ,IAAI,QAAQ,CAAC,SAAS,EAAE,CAAC;4BACnD,OAAO,CAAC,KAAK,CAAC,CAAC;wBAChB,CAAC;6BAAM,IAAI,WAAW,IAAI,QAAQ,EAAE,CAAC;4BACpC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;wBAC7B,CAAC;6BAAM,CAAC;4BACP,OAAO,CAAC,KAAK,CAAC,CAAC;wBAChB,CAAC;oBAAA,CACD;oBACD,MAAM;iBACN,CAAC,CAAC;gBACH,MAAM,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAsB,CAAC,CAAC;YAAA,CAC/F,CAAC,CAAC;QAAA,CACH;QAED,KAAK,CAAC,KAAK,CAAC,KAAa,EAAE,WAAoB,EAA0B;YACxE,MAAM,EAAE,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;YAC/B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC;gBACvC,mBAAmB,CAAC,GAAG,CAAC,EAAE,EAAE;oBAC3B,OAAO,EAAE,CAAC,QAA2B,EAAE,EAAE,CAAC;wBACzC,IAAI,WAAW,IAAI,QAAQ,IAAI,QAAQ,CAAC,SAAS,EAAE,CAAC;4BACnD,OAAO,CAAC,IAAI,CAAC,CAAC;wBACf,CAAC;6BAAM,IAAI,OAAO,IAAI,QAAQ,EAAE,CAAC;4BAChC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;wBACzB,CAAC;6BAAM,CAAC;4BACP,OAAO,CAAC,IAAI,CAAC,CAAC;wBACf,CAAC;oBAAA,CACD;oBACD,MAAM;iBACN,CAAC,CAAC;gBACH,MAAM,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAsB,CAAC,CAAC;YAAA,CACjG,CAAC,CAAC;QAAA,CACH;QAED,MAAM,CAAC,OAAe,EAAE,IAAmC,EAAQ;YAClE,uCAAuC;YACvC,MAAM,CAAC;gBACN,IAAI,EAAE,iBAAiB;gBACvB,EAAE,EAAE,MAAM,CAAC,UAAU,EAAE;gBACvB,MAAM,EAAE,QAAQ;gBAChB,OAAO;gBACP,UAAU,EAAE,IAAI;aACI,CAAC,CAAC;QAAA,CACvB;KACD,CAAC,CAAC;IAEH,yCAAyC;IACzC,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IACtC,IAAI,UAAU,EAAE,CAAC;QAChB,UAAU,CAAC,YAAY,CAAC,mBAAmB,EAAE,EAAE,KAAK,CAAC,CAAC;QACtD,UAAU,CAAC,cAAc,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QAC/C,UAAU,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC;YAC3B,MAAM,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;QAAA,CAC3F,CAAC,CAAC;QACH,oCAAoC;QACpC,UAAU,CAAC,cAAc,CAAC,CAAC,IAAI,EAAE,WAAW,EAAE,EAAE,CAAC;YAChD,6DAA6D;YAC7D,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;gBACzB,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;YAC5B,CAAC;iBAAM,CAAC;gBACP,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;oBAClD,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;gBAAA,CACjD,CAAC,CAAC;YACJ,CAAC;QAAA,CACD,CAAC,CAAC;QACH,2BAA2B;QAC3B,MAAM,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC,CAAC;IAClD,CAAC;IAED,kCAAkC;IAClC,OAAO,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC;QAC5B,MAAM,CAAC,KAAK,CAAC,CAAC;IAAA,CACd,CAAC,CAAC;IAEH,0BAA0B;IAC1B,MAAM,aAAa,GAAG,KAAK,EAAE,OAAmB,EAAwB,EAAE,CAAC;QAC1E,MAAM,EAAE,GAAG,OAAO,CAAC,EAAE,CAAC;QAEtB,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;YACtB,oEAAoE;YACpE,YAAY;YACZ,oEAAoE;YAEpE,KAAK,QAAQ,EAAE,CAAC;gBACf,mCAAmC;gBACnC,OAAO;qBACL,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE;oBACxB,WAAW,EAAE,OAAO,CAAC,WAAW;oBAChC,mBAAmB,EAAE,KAAK;iBAC1B,CAAC;qBACD,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;gBACvD,OAAO,OAAO,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;YAC9B,CAAC;YAED,KAAK,eAAe,EAAE,CAAC;gBACtB,MAAM,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;gBAC5C,OAAO,OAAO,CAAC,EAAE,EAAE,eAAe,CAAC,CAAC;YACrC,CAAC;YAED,KAAK,OAAO,EAAE,CAAC;gBACd,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;gBACtB,OAAO,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YAC7B,CAAC;YAED,KAAK,OAAO,EAAE,CAAC;gBACd,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;gBACtB,OAAO,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YAC7B,CAAC;YAED,oEAAoE;YACpE,QAAQ;YACR,oEAAoE;YAEpE,KAAK,WAAW,EAAE,CAAC;gBAClB,MAAM,KAAK,GAAoB;oBAC9B,KAAK,EAAE,OAAO,CAAC,KAAK;oBACpB,aAAa,EAAE,OAAO,CAAC,aAAa;oBACpC,WAAW,EAAE,OAAO,CAAC,WAAW;oBAChC,YAAY,EAAE,OAAO,CAAC,YAAY;oBAClC,SAAS,EAAE,OAAO,CAAC,SAAS;oBAC5B,WAAW,EAAE,OAAO,CAAC,WAAW;oBAChC,SAAS,EAAE,OAAO,CAAC,SAAS;oBAC5B,qBAAqB,EAAE,OAAO,CAAC,qBAAqB;oBACpD,YAAY,EAAE,OAAO,CAAC,QAAQ,CAAC,MAAM;oBACrC,kBAAkB,EAAE,OAAO,CAAC,kBAAkB;iBAC9C,CAAC;gBACF,OAAO,OAAO,CAAC,EAAE,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC;YACxC,CAAC;YAED,oEAAoE;YACpE,QAAQ;YACR,oEAAoE;YAEpE,KAAK,WAAW,EAAE,CAAC;gBAClB,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,kBAAkB,EAAE,CAAC;gBAClD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,QAAQ,IAAI,CAAC,CAAC,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;gBAC9F,IAAI,CAAC,KAAK,EAAE,CAAC;oBACZ,OAAO,KAAK,CAAC,EAAE,EAAE,WAAW,EAAE,oBAAoB,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;gBAC1F,CAAC;gBACD,MAAM,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;gBAC9B,OAAO,OAAO,CAAC,EAAE,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC;YACxC,CAAC;YAED,KAAK,aAAa,EAAE,CAAC;gBACpB,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC;gBAC1C,IAAI,CAAC,MAAM,EAAE,CAAC;oBACb,OAAO,OAAO,CAAC,EAAE,EAAE,aAAa,EAAE,IAAI,CAAC,CAAC;gBACzC,CAAC;gBACD,OAAO,OAAO,CAAC,EAAE,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC;YAC3C,CAAC;YAED,KAAK,sBAAsB,EAAE,CAAC;gBAC7B,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,kBAAkB,EAAE,CAAC;gBAClD,OAAO,OAAO,CAAC,EAAE,EAAE,sBAAsB,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;YACxD,CAAC;YAED,oEAAoE;YACpE,WAAW;YACX,oEAAoE;YAEpE,KAAK,oBAAoB,EAAE,CAAC;gBAC3B,OAAO,CAAC,gBAAgB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;gBACxC,OAAO,OAAO,CAAC,EAAE,EAAE,oBAAoB,CAAC,CAAC;YAC1C,CAAC;YAED,KAAK,sBAAsB,EAAE,CAAC;gBAC7B,MAAM,KAAK,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC;gBAC3C,IAAI,CAAC,KAAK,EAAE,CAAC;oBACZ,OAAO,OAAO,CAAC,EAAE,EAAE,sBAAsB,EAAE,IAAI,CAAC,CAAC;gBAClD,CAAC;gBACD,OAAO,OAAO,CAAC,EAAE,EAAE,sBAAsB,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;YACvD,CAAC;YAED,oEAAoE;YACpE,aAAa;YACb,oEAAoE;YAEpE,KAAK,gBAAgB,EAAE,CAAC;gBACvB,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;gBACnC,OAAO,OAAO,CAAC,EAAE,EAAE,gBAAgB,CAAC,CAAC;YACtC,CAAC;YAED,oEAAoE;YACpE,aAAa;YACb,oEAAoE;YAEpE,KAAK,SAAS,EAAE,CAAC;gBAChB,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;gBACjE,OAAO,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;YACvC,CAAC;YAED,KAAK,qBAAqB,EAAE,CAAC;gBAC5B,OAAO,CAAC,wBAAwB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;gBAClD,OAAO,OAAO,CAAC,EAAE,EAAE,qBAAqB,CAAC,CAAC;YAC3C,CAAC;YAED,oEAAoE;YACpE,QAAQ;YACR,oEAAoE;YAEpE,KAAK,gBAAgB,EAAE,CAAC;gBACvB,OAAO,CAAC,mBAAmB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;gBAC7C,OAAO,OAAO,CAAC,EAAE,EAAE,gBAAgB,CAAC,CAAC;YACtC,CAAC;YAED,KAAK,aAAa,EAAE,CAAC;gBACpB,OAAO,CAAC,UAAU,EAAE,CAAC;gBACrB,OAAO,OAAO,CAAC,EAAE,EAAE,aAAa,CAAC,CAAC;YACnC,CAAC;YAED,oEAAoE;YACpE,OAAO;YACP,oEAAoE;YAEpE,KAAK,MAAM,EAAE,CAAC;gBACb,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;gBAC1D,OAAO,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;YACpC,CAAC;YAED,KAAK,YAAY,EAAE,CAAC;gBACnB,OAAO,CAAC,SAAS,EAAE,CAAC;gBACpB,OAAO,OAAO,CAAC,EAAE,EAAE,YAAY,CAAC,CAAC;YAClC,CAAC;YAED,oEAAoE;YACpE,UAAU;YACV,oEAAoE;YAEpE,KAAK,mBAAmB,EAAE,CAAC;gBAC1B,MAAM,KAAK,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;gBACxC,OAAO,OAAO,CAAC,EAAE,EAAE,mBAAmB,EAAE,KAAK,CAAC,CAAC;YAChD,CAAC;YAED,KAAK,aAAa,EAAE,CAAC;gBACpB,MAAM,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;gBACtD,OAAO,OAAO,CAAC,EAAE,EAAE,aAAa,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;YAC7C,CAAC;YAED,KAAK,gBAAgB,EAAE,CAAC;gBACvB,MAAM,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;gBACjD,OAAO,OAAO,CAAC,EAAE,EAAE,gBAAgB,CAAC,CAAC;YACtC,CAAC;YAED,KAAK,QAAQ,EAAE,CAAC;gBACf,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;gBACxD,OAAO,OAAO,CAAC,EAAE,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,YAAY,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;YACtF,CAAC;YAED,KAAK,qBAAqB,EAAE,CAAC;gBAC5B,MAAM,QAAQ,GAAG,OAAO,CAAC,2BAA2B,EAAE,CAAC;gBACvD,OAAO,OAAO,CAAC,EAAE,EAAE,qBAAqB,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;YACzD,CAAC;YAED,KAAK,yBAAyB,EAAE,CAAC;gBAChC,MAAM,IAAI,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;gBAC5C,OAAO,OAAO,CAAC,EAAE,EAAE,yBAAyB,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;YACzD,CAAC;YAED,oEAAoE;YACpE,WAAW;YACX,oEAAoE;YAEpE,KAAK,cAAc,EAAE,CAAC;gBACrB,OAAO,OAAO,CAAC,EAAE,EAAE,cAAc,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;YACpE,CAAC;YAED,SAAS,CAAC;gBACT,MAAM,cAAc,GAAG,OAA2B,CAAC;gBACnD,OAAO,KAAK,CAAC,SAAS,EAAE,cAAc,CAAC,IAAI,EAAE,oBAAoB,cAAc,CAAC,IAAI,EAAE,CAAC,CAAC;YACzF,CAAC;QACF,CAAC;IAAA,CACD,CAAC;IAEF,wBAAwB;IACxB,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC;QACnC,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,QAAQ,EAAE,KAAK;KACf,CAAC,CAAC;IAEH,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,IAAY,EAAE,EAAE,CAAC;QACrC,IAAI,CAAC;YACJ,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAEhC,2BAA2B;YAC3B,IAAI,MAAM,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;gBACxC,MAAM,QAAQ,GAAG,MAA2B,CAAC;gBAC7C,MAAM,OAAO,GAAG,mBAAmB,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;gBACrD,IAAI,OAAO,EAAE,CAAC;oBACb,mBAAmB,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;oBACxC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;gBAC3B,CAAC;gBACD,OAAO;YACR,CAAC;YAED,0BAA0B;YAC1B,MAAM,OAAO,GAAG,MAAoB,CAAC;YACrC,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,OAAO,CAAC,CAAC;YAC9C,MAAM,CAAC,QAAQ,CAAC,CAAC;QAClB,CAAC;QAAC,OAAO,CAAM,EAAE,CAAC;YACjB,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,OAAO,EAAE,4BAA4B,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAC5E,CAAC;IAAA,CACD,CAAC,CAAC;IAEH,6BAA6B;IAC7B,OAAO,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,EAAC,CAAC,CAAC,CAAC;AAAA,CAC7B","sourcesContent":["/**\n * RPC mode: Headless operation with JSON stdin/stdout protocol.\n *\n * Used for embedding the agent in other applications.\n * Receives commands as JSON on stdin, outputs events and responses as JSON on stdout.\n *\n * Protocol:\n * - Commands: JSON objects with `type` field, optional `id` for correlation\n * - Responses: JSON objects with `type: \"response\"`, `command`, `success`, and optional `data`/`error`\n * - Events: AgentSessionEvent objects streamed as they occur\n * - Hook UI: Hook UI requests are emitted, client responds with hook_ui_response\n */\n\nimport * as crypto from \"node:crypto\";\nimport * as readline from \"readline\";\nimport type { AgentSession } from \"../../core/agent-session.js\";\nimport type { HookUIContext } from \"../../core/hooks/index.js\";\nimport type { RpcCommand, RpcHookUIRequest, RpcHookUIResponse, RpcResponse, RpcSessionState } from \"./rpc-types.js\";\n\n// Re-export types for consumers\nexport type { RpcCommand, RpcHookUIRequest, RpcHookUIResponse, RpcResponse, RpcSessionState } from \"./rpc-types.js\";\n\n/**\n * Run in RPC mode.\n * Listens for JSON commands on stdin, outputs events and responses on stdout.\n */\nexport async function runRpcMode(session: AgentSession): Promise<never> {\n\tconst output = (obj: RpcResponse | RpcHookUIRequest | object) => {\n\t\tconsole.log(JSON.stringify(obj));\n\t};\n\n\tconst success = <T extends RpcCommand[\"type\"]>(\n\t\tid: string | undefined,\n\t\tcommand: T,\n\t\tdata?: object | null,\n\t): RpcResponse => {\n\t\tif (data === undefined) {\n\t\t\treturn { id, type: \"response\", command, success: true } as RpcResponse;\n\t\t}\n\t\treturn { id, type: \"response\", command, success: true, data } as RpcResponse;\n\t};\n\n\tconst error = (id: string | undefined, command: string, message: string): RpcResponse => {\n\t\treturn { id, type: \"response\", command, success: false, error: message };\n\t};\n\n\t// Pending hook UI requests waiting for response\n\tconst pendingHookRequests = new Map<string, { resolve: (value: any) => void; reject: (error: Error) => void }>();\n\n\t/**\n\t * Create a hook UI context that uses the RPC protocol.\n\t */\n\tconst createHookUIContext = (): HookUIContext => ({\n\t\tasync select(title: string, options: string[]): Promise<string | null> {\n\t\t\tconst id = crypto.randomUUID();\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tpendingHookRequests.set(id, {\n\t\t\t\t\tresolve: (response: RpcHookUIResponse) => {\n\t\t\t\t\t\tif (\"cancelled\" in response && response.cancelled) {\n\t\t\t\t\t\t\tresolve(null);\n\t\t\t\t\t\t} else if (\"value\" in response) {\n\t\t\t\t\t\t\tresolve(response.value);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tresolve(null);\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\treject,\n\t\t\t\t});\n\t\t\t\toutput({ type: \"hook_ui_request\", id, method: \"select\", title, options } as RpcHookUIRequest);\n\t\t\t});\n\t\t},\n\n\t\tasync confirm(title: string, message: string): Promise<boolean> {\n\t\t\tconst id = crypto.randomUUID();\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tpendingHookRequests.set(id, {\n\t\t\t\t\tresolve: (response: RpcHookUIResponse) => {\n\t\t\t\t\t\tif (\"cancelled\" in response && response.cancelled) {\n\t\t\t\t\t\t\tresolve(false);\n\t\t\t\t\t\t} else if (\"confirmed\" in response) {\n\t\t\t\t\t\t\tresolve(response.confirmed);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tresolve(false);\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\treject,\n\t\t\t\t});\n\t\t\t\toutput({ type: \"hook_ui_request\", id, method: \"confirm\", title, message } as RpcHookUIRequest);\n\t\t\t});\n\t\t},\n\n\t\tasync input(title: string, placeholder?: string): Promise<string | null> {\n\t\t\tconst id = crypto.randomUUID();\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tpendingHookRequests.set(id, {\n\t\t\t\t\tresolve: (response: RpcHookUIResponse) => {\n\t\t\t\t\t\tif (\"cancelled\" in response && response.cancelled) {\n\t\t\t\t\t\t\tresolve(null);\n\t\t\t\t\t\t} else if (\"value\" in response) {\n\t\t\t\t\t\t\tresolve(response.value);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tresolve(null);\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\treject,\n\t\t\t\t});\n\t\t\t\toutput({ type: \"hook_ui_request\", id, method: \"input\", title, placeholder } as RpcHookUIRequest);\n\t\t\t});\n\t\t},\n\n\t\tnotify(message: string, type?: \"info\" | \"warning\" | \"error\"): void {\n\t\t\t// Fire and forget - no response needed\n\t\t\toutput({\n\t\t\t\ttype: \"hook_ui_request\",\n\t\t\t\tid: crypto.randomUUID(),\n\t\t\t\tmethod: \"notify\",\n\t\t\t\tmessage,\n\t\t\t\tnotifyType: type,\n\t\t\t} as RpcHookUIRequest);\n\t\t},\n\t});\n\n\t// Set up hooks with RPC-based UI context\n\tconst hookRunner = session.hookRunner;\n\tif (hookRunner) {\n\t\thookRunner.setUIContext(createHookUIContext(), false);\n\t\thookRunner.setSessionFile(session.sessionFile);\n\t\thookRunner.onError((err) => {\n\t\t\toutput({ type: \"hook_error\", hookPath: err.hookPath, event: err.event, error: err.error });\n\t\t});\n\t\t// Set up send handler for pi.send()\n\t\thookRunner.setSendHandler((text, attachments) => {\n\t\t\t// In RPC mode, just queue or prompt based on streaming state\n\t\t\tif (session.isStreaming) {\n\t\t\t\tsession.queueMessage(text);\n\t\t\t} else {\n\t\t\t\tsession.prompt(text, { attachments }).catch((e) => {\n\t\t\t\t\toutput(error(undefined, \"hook_send\", e.message));\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t\t// Emit session_start event\n\t\tawait hookRunner.emit({ type: \"session_start\" });\n\t}\n\n\t// Output all agent events as JSON\n\tsession.subscribe((event) => {\n\t\toutput(event);\n\t});\n\n\t// Handle a single command\n\tconst handleCommand = async (command: RpcCommand): Promise<RpcResponse> => {\n\t\tconst id = command.id;\n\n\t\tswitch (command.type) {\n\t\t\t// =================================================================\n\t\t\t// Prompting\n\t\t\t// =================================================================\n\n\t\t\tcase \"prompt\": {\n\t\t\t\t// Don't await - events will stream\n\t\t\t\tsession\n\t\t\t\t\t.prompt(command.message, {\n\t\t\t\t\t\tattachments: command.attachments,\n\t\t\t\t\t\texpandSlashCommands: false,\n\t\t\t\t\t})\n\t\t\t\t\t.catch((e) => output(error(id, \"prompt\", e.message)));\n\t\t\t\treturn success(id, \"prompt\");\n\t\t\t}\n\n\t\t\tcase \"queue_message\": {\n\t\t\t\tawait session.queueMessage(command.message);\n\t\t\t\treturn success(id, \"queue_message\");\n\t\t\t}\n\n\t\t\tcase \"abort\": {\n\t\t\t\tawait session.abort();\n\t\t\t\treturn success(id, \"abort\");\n\t\t\t}\n\n\t\t\tcase \"reset\": {\n\t\t\t\tawait session.reset();\n\t\t\t\treturn success(id, \"reset\");\n\t\t\t}\n\n\t\t\t// =================================================================\n\t\t\t// State\n\t\t\t// =================================================================\n\n\t\t\tcase \"get_state\": {\n\t\t\t\tconst state: RpcSessionState = {\n\t\t\t\t\tmodel: session.model,\n\t\t\t\t\tthinkingLevel: session.thinkingLevel,\n\t\t\t\t\tisStreaming: session.isStreaming,\n\t\t\t\t\tisCompacting: session.isCompacting,\n\t\t\t\t\tqueueMode: session.queueMode,\n\t\t\t\t\tsessionFile: session.sessionFile,\n\t\t\t\t\tsessionId: session.sessionId,\n\t\t\t\t\tautoCompactionEnabled: session.autoCompactionEnabled,\n\t\t\t\t\tmessageCount: session.messages.length,\n\t\t\t\t\tqueuedMessageCount: session.queuedMessageCount,\n\t\t\t\t};\n\t\t\t\treturn success(id, \"get_state\", state);\n\t\t\t}\n\n\t\t\t// =================================================================\n\t\t\t// Model\n\t\t\t// =================================================================\n\n\t\t\tcase \"set_model\": {\n\t\t\t\tconst models = await session.getAvailableModels();\n\t\t\t\tconst model = models.find((m) => m.provider === command.provider && m.id === command.modelId);\n\t\t\t\tif (!model) {\n\t\t\t\t\treturn error(id, \"set_model\", `Model not found: ${command.provider}/${command.modelId}`);\n\t\t\t\t}\n\t\t\t\tawait session.setModel(model);\n\t\t\t\treturn success(id, \"set_model\", model);\n\t\t\t}\n\n\t\t\tcase \"cycle_model\": {\n\t\t\t\tconst result = await session.cycleModel();\n\t\t\t\tif (!result) {\n\t\t\t\t\treturn success(id, \"cycle_model\", null);\n\t\t\t\t}\n\t\t\t\treturn success(id, \"cycle_model\", result);\n\t\t\t}\n\n\t\t\tcase \"get_available_models\": {\n\t\t\t\tconst models = await session.getAvailableModels();\n\t\t\t\treturn success(id, \"get_available_models\", { models });\n\t\t\t}\n\n\t\t\t// =================================================================\n\t\t\t// Thinking\n\t\t\t// =================================================================\n\n\t\t\tcase \"set_thinking_level\": {\n\t\t\t\tsession.setThinkingLevel(command.level);\n\t\t\t\treturn success(id, \"set_thinking_level\");\n\t\t\t}\n\n\t\t\tcase \"cycle_thinking_level\": {\n\t\t\t\tconst level = session.cycleThinkingLevel();\n\t\t\t\tif (!level) {\n\t\t\t\t\treturn success(id, \"cycle_thinking_level\", null);\n\t\t\t\t}\n\t\t\t\treturn success(id, \"cycle_thinking_level\", { level });\n\t\t\t}\n\n\t\t\t// =================================================================\n\t\t\t// Queue Mode\n\t\t\t// =================================================================\n\n\t\t\tcase \"set_queue_mode\": {\n\t\t\t\tsession.setQueueMode(command.mode);\n\t\t\t\treturn success(id, \"set_queue_mode\");\n\t\t\t}\n\n\t\t\t// =================================================================\n\t\t\t// Compaction\n\t\t\t// =================================================================\n\n\t\t\tcase \"compact\": {\n\t\t\t\tconst result = await session.compact(command.customInstructions);\n\t\t\t\treturn success(id, \"compact\", result);\n\t\t\t}\n\n\t\t\tcase \"set_auto_compaction\": {\n\t\t\t\tsession.setAutoCompactionEnabled(command.enabled);\n\t\t\t\treturn success(id, \"set_auto_compaction\");\n\t\t\t}\n\n\t\t\t// =================================================================\n\t\t\t// Retry\n\t\t\t// =================================================================\n\n\t\t\tcase \"set_auto_retry\": {\n\t\t\t\tsession.setAutoRetryEnabled(command.enabled);\n\t\t\t\treturn success(id, \"set_auto_retry\");\n\t\t\t}\n\n\t\t\tcase \"abort_retry\": {\n\t\t\t\tsession.abortRetry();\n\t\t\t\treturn success(id, \"abort_retry\");\n\t\t\t}\n\n\t\t\t// =================================================================\n\t\t\t// Bash\n\t\t\t// =================================================================\n\n\t\t\tcase \"bash\": {\n\t\t\t\tconst result = await session.executeBash(command.command);\n\t\t\t\treturn success(id, \"bash\", result);\n\t\t\t}\n\n\t\t\tcase \"abort_bash\": {\n\t\t\t\tsession.abortBash();\n\t\t\t\treturn success(id, \"abort_bash\");\n\t\t\t}\n\n\t\t\t// =================================================================\n\t\t\t// Session\n\t\t\t// =================================================================\n\n\t\t\tcase \"get_session_stats\": {\n\t\t\t\tconst stats = session.getSessionStats();\n\t\t\t\treturn success(id, \"get_session_stats\", stats);\n\t\t\t}\n\n\t\t\tcase \"export_html\": {\n\t\t\t\tconst path = session.exportToHtml(command.outputPath);\n\t\t\t\treturn success(id, \"export_html\", { path });\n\t\t\t}\n\n\t\t\tcase \"switch_session\": {\n\t\t\t\tawait session.switchSession(command.sessionPath);\n\t\t\t\treturn success(id, \"switch_session\");\n\t\t\t}\n\n\t\t\tcase \"branch\": {\n\t\t\t\tconst result = await session.branch(command.entryIndex);\n\t\t\t\treturn success(id, \"branch\", { text: result.selectedText, skipped: result.skipped });\n\t\t\t}\n\n\t\t\tcase \"get_branch_messages\": {\n\t\t\t\tconst messages = session.getUserMessagesForBranching();\n\t\t\t\treturn success(id, \"get_branch_messages\", { messages });\n\t\t\t}\n\n\t\t\tcase \"get_last_assistant_text\": {\n\t\t\t\tconst text = session.getLastAssistantText();\n\t\t\t\treturn success(id, \"get_last_assistant_text\", { text });\n\t\t\t}\n\n\t\t\t// =================================================================\n\t\t\t// Messages\n\t\t\t// =================================================================\n\n\t\t\tcase \"get_messages\": {\n\t\t\t\treturn success(id, \"get_messages\", { messages: session.messages });\n\t\t\t}\n\n\t\t\tdefault: {\n\t\t\t\tconst unknownCommand = command as { type: string };\n\t\t\t\treturn error(undefined, unknownCommand.type, `Unknown command: ${unknownCommand.type}`);\n\t\t\t}\n\t\t}\n\t};\n\n\t// Listen for JSON input\n\tconst rl = readline.createInterface({\n\t\tinput: process.stdin,\n\t\toutput: process.stdout,\n\t\tterminal: false,\n\t});\n\n\trl.on(\"line\", async (line: string) => {\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(line);\n\n\t\t\t// Handle hook UI responses\n\t\t\tif (parsed.type === \"hook_ui_response\") {\n\t\t\t\tconst response = parsed as RpcHookUIResponse;\n\t\t\t\tconst pending = pendingHookRequests.get(response.id);\n\t\t\t\tif (pending) {\n\t\t\t\t\tpendingHookRequests.delete(response.id);\n\t\t\t\t\tpending.resolve(response);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Handle regular commands\n\t\t\tconst command = parsed as RpcCommand;\n\t\t\tconst response = await handleCommand(command);\n\t\t\toutput(response);\n\t\t} catch (e: any) {\n\t\t\toutput(error(undefined, \"parse\", `Failed to parse command: ${e.message}`));\n\t\t}\n\t});\n\n\t// Keep process alive forever\n\treturn new Promise(() => {});\n}\n"]}
@@ -56,6 +56,13 @@ export type RpcCommand = {
56
56
  id?: string;
57
57
  type: "set_auto_compaction";
58
58
  enabled: boolean;
59
+ } | {
60
+ id?: string;
61
+ type: "set_auto_retry";
62
+ enabled: boolean;
63
+ } | {
64
+ id?: string;
65
+ type: "abort_retry";
59
66
  } | {
60
67
  id?: string;
61
68
  type: "bash";
@@ -94,7 +101,7 @@ export interface RpcSessionState {
94
101
  isStreaming: boolean;
95
102
  isCompacting: boolean;
96
103
  queueMode: "all" | "one-at-a-time";
97
- sessionFile: string;
104
+ sessionFile: string | null;
98
105
  sessionId: string;
99
106
  autoCompactionEnabled: boolean;
100
107
  messageCount: number;
@@ -179,6 +186,16 @@ export type RpcResponse = {
179
186
  type: "response";
180
187
  command: "set_auto_compaction";
181
188
  success: true;
189
+ } | {
190
+ id?: string;
191
+ type: "response";
192
+ command: "set_auto_retry";
193
+ success: true;
194
+ } | {
195
+ id?: string;
196
+ type: "response";
197
+ command: "abort_retry";
198
+ success: true;
182
199
  } | {
183
200
  id?: string;
184
201
  type: "response";
@@ -1 +1 @@
1
- {"version":3,"file":"rpc-types.d.ts","sourceRoot":"","sources":["../../../src/modes/rpc/rpc-types.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * RPC protocol types for headless operation.\n *\n * Commands are sent as JSON lines on stdin.\n * Responses and events are emitted as JSON lines on stdout.\n */\n\nimport type { AppMessage, Attachment, ThinkingLevel } from \"@mariozechner/pi-agent-core\";\nimport type { Model } from \"@mariozechner/pi-ai\";\nimport type { CompactionResult, SessionStats } from \"../../core/agent-session.js\";\nimport type { BashResult } from \"../../core/bash-executor.js\";\n\n// ============================================================================\n// RPC Commands (stdin)\n// ============================================================================\n\nexport type RpcCommand =\n\t// Prompting\n\t| { id?: string; type: \"prompt\"; message: string; attachments?: Attachment[] }\n\t| { id?: string; type: \"queue_message\"; message: string }\n\t| { id?: string; type: \"abort\" }\n\t| { id?: string; type: \"reset\" }\n\n\t// State\n\t| { id?: string; type: \"get_state\" }\n\n\t// Model\n\t| { id?: string; type: \"set_model\"; provider: string; modelId: string }\n\t| { id?: string; type: \"cycle_model\" }\n\t| { id?: string; type: \"get_available_models\" }\n\n\t// Thinking\n\t| { id?: string; type: \"set_thinking_level\"; level: ThinkingLevel }\n\t| { id?: string; type: \"cycle_thinking_level\" }\n\n\t// Queue mode\n\t| { id?: string; type: \"set_queue_mode\"; mode: \"all\" | \"one-at-a-time\" }\n\n\t// Compaction\n\t| { id?: string; type: \"compact\"; customInstructions?: string }\n\t| { id?: string; type: \"set_auto_compaction\"; enabled: boolean }\n\n\t// Bash\n\t| { id?: string; type: \"bash\"; command: string }\n\t| { id?: string; type: \"abort_bash\" }\n\n\t// Session\n\t| { id?: string; type: \"get_session_stats\" }\n\t| { id?: string; type: \"export_html\"; outputPath?: string }\n\t| { id?: string; type: \"switch_session\"; sessionPath: string }\n\t| { id?: string; type: \"branch\"; entryIndex: number }\n\t| { id?: string; type: \"get_branch_messages\" }\n\t| { id?: string; type: \"get_last_assistant_text\" }\n\n\t// Messages\n\t| { id?: string; type: \"get_messages\" };\n\n// ============================================================================\n// RPC State\n// ============================================================================\n\nexport interface RpcSessionState {\n\tmodel: Model<any> | null;\n\tthinkingLevel: ThinkingLevel;\n\tisStreaming: boolean;\n\tisCompacting: boolean;\n\tqueueMode: \"all\" | \"one-at-a-time\";\n\tsessionFile: string;\n\tsessionId: string;\n\tautoCompactionEnabled: boolean;\n\tmessageCount: number;\n\tqueuedMessageCount: number;\n}\n\n// ============================================================================\n// RPC Responses (stdout)\n// ============================================================================\n\n// Success responses with data\nexport type RpcResponse =\n\t// Prompting (async - events follow)\n\t| { id?: string; type: \"response\"; command: \"prompt\"; success: true }\n\t| { id?: string; type: \"response\"; command: \"queue_message\"; success: true }\n\t| { id?: string; type: \"response\"; command: \"abort\"; success: true }\n\t| { id?: string; type: \"response\"; command: \"reset\"; success: true }\n\n\t// State\n\t| { id?: string; type: \"response\"; command: \"get_state\"; success: true; data: RpcSessionState }\n\n\t// Model\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"response\";\n\t\t\tcommand: \"set_model\";\n\t\t\tsuccess: true;\n\t\t\tdata: Model<any>;\n\t }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"response\";\n\t\t\tcommand: \"cycle_model\";\n\t\t\tsuccess: true;\n\t\t\tdata: { model: Model<any>; thinkingLevel: ThinkingLevel; isScoped: boolean } | null;\n\t }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"response\";\n\t\t\tcommand: \"get_available_models\";\n\t\t\tsuccess: true;\n\t\t\tdata: { models: Model<any>[] };\n\t }\n\n\t// Thinking\n\t| { id?: string; type: \"response\"; command: \"set_thinking_level\"; success: true }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"response\";\n\t\t\tcommand: \"cycle_thinking_level\";\n\t\t\tsuccess: true;\n\t\t\tdata: { level: ThinkingLevel } | null;\n\t }\n\n\t// Queue mode\n\t| { id?: string; type: \"response\"; command: \"set_queue_mode\"; success: true }\n\n\t// Compaction\n\t| { id?: string; type: \"response\"; command: \"compact\"; success: true; data: CompactionResult }\n\t| { id?: string; type: \"response\"; command: \"set_auto_compaction\"; success: true }\n\n\t// Bash\n\t| { id?: string; type: \"response\"; command: \"bash\"; success: true; data: BashResult }\n\t| { id?: string; type: \"response\"; command: \"abort_bash\"; success: true }\n\n\t// Session\n\t| { id?: string; type: \"response\"; command: \"get_session_stats\"; success: true; data: SessionStats }\n\t| { id?: string; type: \"response\"; command: \"export_html\"; success: true; data: { path: string } }\n\t| { id?: string; type: \"response\"; command: \"switch_session\"; success: true }\n\t| { id?: string; type: \"response\"; command: \"branch\"; success: true; data: { text: string } }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"response\";\n\t\t\tcommand: \"get_branch_messages\";\n\t\t\tsuccess: true;\n\t\t\tdata: { messages: Array<{ entryIndex: number; text: string }> };\n\t }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"response\";\n\t\t\tcommand: \"get_last_assistant_text\";\n\t\t\tsuccess: true;\n\t\t\tdata: { text: string | null };\n\t }\n\n\t// Messages\n\t| { id?: string; type: \"response\"; command: \"get_messages\"; success: true; data: { messages: AppMessage[] } }\n\n\t// Error response (any command can fail)\n\t| { id?: string; type: \"response\"; command: string; success: false; error: string };\n\n// ============================================================================\n// Hook UI Events (stdout)\n// ============================================================================\n\n/** Emitted when a hook needs user input */\nexport type RpcHookUIRequest =\n\t| { type: \"hook_ui_request\"; id: string; method: \"select\"; title: string; options: string[] }\n\t| { type: \"hook_ui_request\"; id: string; method: \"confirm\"; title: string; message: string }\n\t| { type: \"hook_ui_request\"; id: string; method: \"input\"; title: string; placeholder?: string }\n\t| {\n\t\t\ttype: \"hook_ui_request\";\n\t\t\tid: string;\n\t\t\tmethod: \"notify\";\n\t\t\tmessage: string;\n\t\t\tnotifyType?: \"info\" | \"warning\" | \"error\";\n\t };\n\n// ============================================================================\n// Hook UI Commands (stdin)\n// ============================================================================\n\n/** Response to a hook UI request */\nexport type RpcHookUIResponse =\n\t| { type: \"hook_ui_response\"; id: string; value: string }\n\t| { type: \"hook_ui_response\"; id: string; confirmed: boolean }\n\t| { type: \"hook_ui_response\"; id: string; cancelled: true };\n\n// ============================================================================\n// Helper type for extracting command types\n// ============================================================================\n\nexport type RpcCommandType = RpcCommand[\"type\"];\n"]}
1
+ {"version":3,"file":"rpc-types.d.ts","sourceRoot":"","sources":["../../../src/modes/rpc/rpc-types.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * RPC protocol types for headless operation.\n *\n * Commands are sent as JSON lines on stdin.\n * Responses and events are emitted as JSON lines on stdout.\n */\n\nimport type { AppMessage, Attachment, ThinkingLevel } from \"@mariozechner/pi-agent-core\";\nimport type { Model } from \"@mariozechner/pi-ai\";\nimport type { CompactionResult, SessionStats } from \"../../core/agent-session.js\";\nimport type { BashResult } from \"../../core/bash-executor.js\";\n\n// ============================================================================\n// RPC Commands (stdin)\n// ============================================================================\n\nexport type RpcCommand =\n\t// Prompting\n\t| { id?: string; type: \"prompt\"; message: string; attachments?: Attachment[] }\n\t| { id?: string; type: \"queue_message\"; message: string }\n\t| { id?: string; type: \"abort\" }\n\t| { id?: string; type: \"reset\" }\n\n\t// State\n\t| { id?: string; type: \"get_state\" }\n\n\t// Model\n\t| { id?: string; type: \"set_model\"; provider: string; modelId: string }\n\t| { id?: string; type: \"cycle_model\" }\n\t| { id?: string; type: \"get_available_models\" }\n\n\t// Thinking\n\t| { id?: string; type: \"set_thinking_level\"; level: ThinkingLevel }\n\t| { id?: string; type: \"cycle_thinking_level\" }\n\n\t// Queue mode\n\t| { id?: string; type: \"set_queue_mode\"; mode: \"all\" | \"one-at-a-time\" }\n\n\t// Compaction\n\t| { id?: string; type: \"compact\"; customInstructions?: string }\n\t| { id?: string; type: \"set_auto_compaction\"; enabled: boolean }\n\n\t// Retry\n\t| { id?: string; type: \"set_auto_retry\"; enabled: boolean }\n\t| { id?: string; type: \"abort_retry\" }\n\n\t// Bash\n\t| { id?: string; type: \"bash\"; command: string }\n\t| { id?: string; type: \"abort_bash\" }\n\n\t// Session\n\t| { id?: string; type: \"get_session_stats\" }\n\t| { id?: string; type: \"export_html\"; outputPath?: string }\n\t| { id?: string; type: \"switch_session\"; sessionPath: string }\n\t| { id?: string; type: \"branch\"; entryIndex: number }\n\t| { id?: string; type: \"get_branch_messages\" }\n\t| { id?: string; type: \"get_last_assistant_text\" }\n\n\t// Messages\n\t| { id?: string; type: \"get_messages\" };\n\n// ============================================================================\n// RPC State\n// ============================================================================\n\nexport interface RpcSessionState {\n\tmodel: Model<any> | null;\n\tthinkingLevel: ThinkingLevel;\n\tisStreaming: boolean;\n\tisCompacting: boolean;\n\tqueueMode: \"all\" | \"one-at-a-time\";\n\tsessionFile: string | null;\n\tsessionId: string;\n\tautoCompactionEnabled: boolean;\n\tmessageCount: number;\n\tqueuedMessageCount: number;\n}\n\n// ============================================================================\n// RPC Responses (stdout)\n// ============================================================================\n\n// Success responses with data\nexport type RpcResponse =\n\t// Prompting (async - events follow)\n\t| { id?: string; type: \"response\"; command: \"prompt\"; success: true }\n\t| { id?: string; type: \"response\"; command: \"queue_message\"; success: true }\n\t| { id?: string; type: \"response\"; command: \"abort\"; success: true }\n\t| { id?: string; type: \"response\"; command: \"reset\"; success: true }\n\n\t// State\n\t| { id?: string; type: \"response\"; command: \"get_state\"; success: true; data: RpcSessionState }\n\n\t// Model\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"response\";\n\t\t\tcommand: \"set_model\";\n\t\t\tsuccess: true;\n\t\t\tdata: Model<any>;\n\t }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"response\";\n\t\t\tcommand: \"cycle_model\";\n\t\t\tsuccess: true;\n\t\t\tdata: { model: Model<any>; thinkingLevel: ThinkingLevel; isScoped: boolean } | null;\n\t }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"response\";\n\t\t\tcommand: \"get_available_models\";\n\t\t\tsuccess: true;\n\t\t\tdata: { models: Model<any>[] };\n\t }\n\n\t// Thinking\n\t| { id?: string; type: \"response\"; command: \"set_thinking_level\"; success: true }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"response\";\n\t\t\tcommand: \"cycle_thinking_level\";\n\t\t\tsuccess: true;\n\t\t\tdata: { level: ThinkingLevel } | null;\n\t }\n\n\t// Queue mode\n\t| { id?: string; type: \"response\"; command: \"set_queue_mode\"; success: true }\n\n\t// Compaction\n\t| { id?: string; type: \"response\"; command: \"compact\"; success: true; data: CompactionResult }\n\t| { id?: string; type: \"response\"; command: \"set_auto_compaction\"; success: true }\n\n\t// Retry\n\t| { id?: string; type: \"response\"; command: \"set_auto_retry\"; success: true }\n\t| { id?: string; type: \"response\"; command: \"abort_retry\"; success: true }\n\n\t// Bash\n\t| { id?: string; type: \"response\"; command: \"bash\"; success: true; data: BashResult }\n\t| { id?: string; type: \"response\"; command: \"abort_bash\"; success: true }\n\n\t// Session\n\t| { id?: string; type: \"response\"; command: \"get_session_stats\"; success: true; data: SessionStats }\n\t| { id?: string; type: \"response\"; command: \"export_html\"; success: true; data: { path: string } }\n\t| { id?: string; type: \"response\"; command: \"switch_session\"; success: true }\n\t| { id?: string; type: \"response\"; command: \"branch\"; success: true; data: { text: string } }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"response\";\n\t\t\tcommand: \"get_branch_messages\";\n\t\t\tsuccess: true;\n\t\t\tdata: { messages: Array<{ entryIndex: number; text: string }> };\n\t }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"response\";\n\t\t\tcommand: \"get_last_assistant_text\";\n\t\t\tsuccess: true;\n\t\t\tdata: { text: string | null };\n\t }\n\n\t// Messages\n\t| { id?: string; type: \"response\"; command: \"get_messages\"; success: true; data: { messages: AppMessage[] } }\n\n\t// Error response (any command can fail)\n\t| { id?: string; type: \"response\"; command: string; success: false; error: string };\n\n// ============================================================================\n// Hook UI Events (stdout)\n// ============================================================================\n\n/** Emitted when a hook needs user input */\nexport type RpcHookUIRequest =\n\t| { type: \"hook_ui_request\"; id: string; method: \"select\"; title: string; options: string[] }\n\t| { type: \"hook_ui_request\"; id: string; method: \"confirm\"; title: string; message: string }\n\t| { type: \"hook_ui_request\"; id: string; method: \"input\"; title: string; placeholder?: string }\n\t| {\n\t\t\ttype: \"hook_ui_request\";\n\t\t\tid: string;\n\t\t\tmethod: \"notify\";\n\t\t\tmessage: string;\n\t\t\tnotifyType?: \"info\" | \"warning\" | \"error\";\n\t };\n\n// ============================================================================\n// Hook UI Commands (stdin)\n// ============================================================================\n\n/** Response to a hook UI request */\nexport type RpcHookUIResponse =\n\t| { type: \"hook_ui_response\"; id: string; value: string }\n\t| { type: \"hook_ui_response\"; id: string; confirmed: boolean }\n\t| { type: \"hook_ui_response\"; id: string; cancelled: true };\n\n// ============================================================================\n// Helper type for extracting command types\n// ============================================================================\n\nexport type RpcCommandType = RpcCommand[\"type\"];\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"rpc-types.js","sourceRoot":"","sources":["../../../src/modes/rpc/rpc-types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG","sourcesContent":["/**\n * RPC protocol types for headless operation.\n *\n * Commands are sent as JSON lines on stdin.\n * Responses and events are emitted as JSON lines on stdout.\n */\n\nimport type { AppMessage, Attachment, ThinkingLevel } from \"@mariozechner/pi-agent-core\";\nimport type { Model } from \"@mariozechner/pi-ai\";\nimport type { CompactionResult, SessionStats } from \"../../core/agent-session.js\";\nimport type { BashResult } from \"../../core/bash-executor.js\";\n\n// ============================================================================\n// RPC Commands (stdin)\n// ============================================================================\n\nexport type RpcCommand =\n\t// Prompting\n\t| { id?: string; type: \"prompt\"; message: string; attachments?: Attachment[] }\n\t| { id?: string; type: \"queue_message\"; message: string }\n\t| { id?: string; type: \"abort\" }\n\t| { id?: string; type: \"reset\" }\n\n\t// State\n\t| { id?: string; type: \"get_state\" }\n\n\t// Model\n\t| { id?: string; type: \"set_model\"; provider: string; modelId: string }\n\t| { id?: string; type: \"cycle_model\" }\n\t| { id?: string; type: \"get_available_models\" }\n\n\t// Thinking\n\t| { id?: string; type: \"set_thinking_level\"; level: ThinkingLevel }\n\t| { id?: string; type: \"cycle_thinking_level\" }\n\n\t// Queue mode\n\t| { id?: string; type: \"set_queue_mode\"; mode: \"all\" | \"one-at-a-time\" }\n\n\t// Compaction\n\t| { id?: string; type: \"compact\"; customInstructions?: string }\n\t| { id?: string; type: \"set_auto_compaction\"; enabled: boolean }\n\n\t// Bash\n\t| { id?: string; type: \"bash\"; command: string }\n\t| { id?: string; type: \"abort_bash\" }\n\n\t// Session\n\t| { id?: string; type: \"get_session_stats\" }\n\t| { id?: string; type: \"export_html\"; outputPath?: string }\n\t| { id?: string; type: \"switch_session\"; sessionPath: string }\n\t| { id?: string; type: \"branch\"; entryIndex: number }\n\t| { id?: string; type: \"get_branch_messages\" }\n\t| { id?: string; type: \"get_last_assistant_text\" }\n\n\t// Messages\n\t| { id?: string; type: \"get_messages\" };\n\n// ============================================================================\n// RPC State\n// ============================================================================\n\nexport interface RpcSessionState {\n\tmodel: Model<any> | null;\n\tthinkingLevel: ThinkingLevel;\n\tisStreaming: boolean;\n\tisCompacting: boolean;\n\tqueueMode: \"all\" | \"one-at-a-time\";\n\tsessionFile: string;\n\tsessionId: string;\n\tautoCompactionEnabled: boolean;\n\tmessageCount: number;\n\tqueuedMessageCount: number;\n}\n\n// ============================================================================\n// RPC Responses (stdout)\n// ============================================================================\n\n// Success responses with data\nexport type RpcResponse =\n\t// Prompting (async - events follow)\n\t| { id?: string; type: \"response\"; command: \"prompt\"; success: true }\n\t| { id?: string; type: \"response\"; command: \"queue_message\"; success: true }\n\t| { id?: string; type: \"response\"; command: \"abort\"; success: true }\n\t| { id?: string; type: \"response\"; command: \"reset\"; success: true }\n\n\t// State\n\t| { id?: string; type: \"response\"; command: \"get_state\"; success: true; data: RpcSessionState }\n\n\t// Model\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"response\";\n\t\t\tcommand: \"set_model\";\n\t\t\tsuccess: true;\n\t\t\tdata: Model<any>;\n\t }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"response\";\n\t\t\tcommand: \"cycle_model\";\n\t\t\tsuccess: true;\n\t\t\tdata: { model: Model<any>; thinkingLevel: ThinkingLevel; isScoped: boolean } | null;\n\t }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"response\";\n\t\t\tcommand: \"get_available_models\";\n\t\t\tsuccess: true;\n\t\t\tdata: { models: Model<any>[] };\n\t }\n\n\t// Thinking\n\t| { id?: string; type: \"response\"; command: \"set_thinking_level\"; success: true }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"response\";\n\t\t\tcommand: \"cycle_thinking_level\";\n\t\t\tsuccess: true;\n\t\t\tdata: { level: ThinkingLevel } | null;\n\t }\n\n\t// Queue mode\n\t| { id?: string; type: \"response\"; command: \"set_queue_mode\"; success: true }\n\n\t// Compaction\n\t| { id?: string; type: \"response\"; command: \"compact\"; success: true; data: CompactionResult }\n\t| { id?: string; type: \"response\"; command: \"set_auto_compaction\"; success: true }\n\n\t// Bash\n\t| { id?: string; type: \"response\"; command: \"bash\"; success: true; data: BashResult }\n\t| { id?: string; type: \"response\"; command: \"abort_bash\"; success: true }\n\n\t// Session\n\t| { id?: string; type: \"response\"; command: \"get_session_stats\"; success: true; data: SessionStats }\n\t| { id?: string; type: \"response\"; command: \"export_html\"; success: true; data: { path: string } }\n\t| { id?: string; type: \"response\"; command: \"switch_session\"; success: true }\n\t| { id?: string; type: \"response\"; command: \"branch\"; success: true; data: { text: string } }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"response\";\n\t\t\tcommand: \"get_branch_messages\";\n\t\t\tsuccess: true;\n\t\t\tdata: { messages: Array<{ entryIndex: number; text: string }> };\n\t }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"response\";\n\t\t\tcommand: \"get_last_assistant_text\";\n\t\t\tsuccess: true;\n\t\t\tdata: { text: string | null };\n\t }\n\n\t// Messages\n\t| { id?: string; type: \"response\"; command: \"get_messages\"; success: true; data: { messages: AppMessage[] } }\n\n\t// Error response (any command can fail)\n\t| { id?: string; type: \"response\"; command: string; success: false; error: string };\n\n// ============================================================================\n// Hook UI Events (stdout)\n// ============================================================================\n\n/** Emitted when a hook needs user input */\nexport type RpcHookUIRequest =\n\t| { type: \"hook_ui_request\"; id: string; method: \"select\"; title: string; options: string[] }\n\t| { type: \"hook_ui_request\"; id: string; method: \"confirm\"; title: string; message: string }\n\t| { type: \"hook_ui_request\"; id: string; method: \"input\"; title: string; placeholder?: string }\n\t| {\n\t\t\ttype: \"hook_ui_request\";\n\t\t\tid: string;\n\t\t\tmethod: \"notify\";\n\t\t\tmessage: string;\n\t\t\tnotifyType?: \"info\" | \"warning\" | \"error\";\n\t };\n\n// ============================================================================\n// Hook UI Commands (stdin)\n// ============================================================================\n\n/** Response to a hook UI request */\nexport type RpcHookUIResponse =\n\t| { type: \"hook_ui_response\"; id: string; value: string }\n\t| { type: \"hook_ui_response\"; id: string; confirmed: boolean }\n\t| { type: \"hook_ui_response\"; id: string; cancelled: true };\n\n// ============================================================================\n// Helper type for extracting command types\n// ============================================================================\n\nexport type RpcCommandType = RpcCommand[\"type\"];\n"]}
1
+ {"version":3,"file":"rpc-types.js","sourceRoot":"","sources":["../../../src/modes/rpc/rpc-types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG","sourcesContent":["/**\n * RPC protocol types for headless operation.\n *\n * Commands are sent as JSON lines on stdin.\n * Responses and events are emitted as JSON lines on stdout.\n */\n\nimport type { AppMessage, Attachment, ThinkingLevel } from \"@mariozechner/pi-agent-core\";\nimport type { Model } from \"@mariozechner/pi-ai\";\nimport type { CompactionResult, SessionStats } from \"../../core/agent-session.js\";\nimport type { BashResult } from \"../../core/bash-executor.js\";\n\n// ============================================================================\n// RPC Commands (stdin)\n// ============================================================================\n\nexport type RpcCommand =\n\t// Prompting\n\t| { id?: string; type: \"prompt\"; message: string; attachments?: Attachment[] }\n\t| { id?: string; type: \"queue_message\"; message: string }\n\t| { id?: string; type: \"abort\" }\n\t| { id?: string; type: \"reset\" }\n\n\t// State\n\t| { id?: string; type: \"get_state\" }\n\n\t// Model\n\t| { id?: string; type: \"set_model\"; provider: string; modelId: string }\n\t| { id?: string; type: \"cycle_model\" }\n\t| { id?: string; type: \"get_available_models\" }\n\n\t// Thinking\n\t| { id?: string; type: \"set_thinking_level\"; level: ThinkingLevel }\n\t| { id?: string; type: \"cycle_thinking_level\" }\n\n\t// Queue mode\n\t| { id?: string; type: \"set_queue_mode\"; mode: \"all\" | \"one-at-a-time\" }\n\n\t// Compaction\n\t| { id?: string; type: \"compact\"; customInstructions?: string }\n\t| { id?: string; type: \"set_auto_compaction\"; enabled: boolean }\n\n\t// Retry\n\t| { id?: string; type: \"set_auto_retry\"; enabled: boolean }\n\t| { id?: string; type: \"abort_retry\" }\n\n\t// Bash\n\t| { id?: string; type: \"bash\"; command: string }\n\t| { id?: string; type: \"abort_bash\" }\n\n\t// Session\n\t| { id?: string; type: \"get_session_stats\" }\n\t| { id?: string; type: \"export_html\"; outputPath?: string }\n\t| { id?: string; type: \"switch_session\"; sessionPath: string }\n\t| { id?: string; type: \"branch\"; entryIndex: number }\n\t| { id?: string; type: \"get_branch_messages\" }\n\t| { id?: string; type: \"get_last_assistant_text\" }\n\n\t// Messages\n\t| { id?: string; type: \"get_messages\" };\n\n// ============================================================================\n// RPC State\n// ============================================================================\n\nexport interface RpcSessionState {\n\tmodel: Model<any> | null;\n\tthinkingLevel: ThinkingLevel;\n\tisStreaming: boolean;\n\tisCompacting: boolean;\n\tqueueMode: \"all\" | \"one-at-a-time\";\n\tsessionFile: string | null;\n\tsessionId: string;\n\tautoCompactionEnabled: boolean;\n\tmessageCount: number;\n\tqueuedMessageCount: number;\n}\n\n// ============================================================================\n// RPC Responses (stdout)\n// ============================================================================\n\n// Success responses with data\nexport type RpcResponse =\n\t// Prompting (async - events follow)\n\t| { id?: string; type: \"response\"; command: \"prompt\"; success: true }\n\t| { id?: string; type: \"response\"; command: \"queue_message\"; success: true }\n\t| { id?: string; type: \"response\"; command: \"abort\"; success: true }\n\t| { id?: string; type: \"response\"; command: \"reset\"; success: true }\n\n\t// State\n\t| { id?: string; type: \"response\"; command: \"get_state\"; success: true; data: RpcSessionState }\n\n\t// Model\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"response\";\n\t\t\tcommand: \"set_model\";\n\t\t\tsuccess: true;\n\t\t\tdata: Model<any>;\n\t }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"response\";\n\t\t\tcommand: \"cycle_model\";\n\t\t\tsuccess: true;\n\t\t\tdata: { model: Model<any>; thinkingLevel: ThinkingLevel; isScoped: boolean } | null;\n\t }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"response\";\n\t\t\tcommand: \"get_available_models\";\n\t\t\tsuccess: true;\n\t\t\tdata: { models: Model<any>[] };\n\t }\n\n\t// Thinking\n\t| { id?: string; type: \"response\"; command: \"set_thinking_level\"; success: true }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"response\";\n\t\t\tcommand: \"cycle_thinking_level\";\n\t\t\tsuccess: true;\n\t\t\tdata: { level: ThinkingLevel } | null;\n\t }\n\n\t// Queue mode\n\t| { id?: string; type: \"response\"; command: \"set_queue_mode\"; success: true }\n\n\t// Compaction\n\t| { id?: string; type: \"response\"; command: \"compact\"; success: true; data: CompactionResult }\n\t| { id?: string; type: \"response\"; command: \"set_auto_compaction\"; success: true }\n\n\t// Retry\n\t| { id?: string; type: \"response\"; command: \"set_auto_retry\"; success: true }\n\t| { id?: string; type: \"response\"; command: \"abort_retry\"; success: true }\n\n\t// Bash\n\t| { id?: string; type: \"response\"; command: \"bash\"; success: true; data: BashResult }\n\t| { id?: string; type: \"response\"; command: \"abort_bash\"; success: true }\n\n\t// Session\n\t| { id?: string; type: \"response\"; command: \"get_session_stats\"; success: true; data: SessionStats }\n\t| { id?: string; type: \"response\"; command: \"export_html\"; success: true; data: { path: string } }\n\t| { id?: string; type: \"response\"; command: \"switch_session\"; success: true }\n\t| { id?: string; type: \"response\"; command: \"branch\"; success: true; data: { text: string } }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"response\";\n\t\t\tcommand: \"get_branch_messages\";\n\t\t\tsuccess: true;\n\t\t\tdata: { messages: Array<{ entryIndex: number; text: string }> };\n\t }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"response\";\n\t\t\tcommand: \"get_last_assistant_text\";\n\t\t\tsuccess: true;\n\t\t\tdata: { text: string | null };\n\t }\n\n\t// Messages\n\t| { id?: string; type: \"response\"; command: \"get_messages\"; success: true; data: { messages: AppMessage[] } }\n\n\t// Error response (any command can fail)\n\t| { id?: string; type: \"response\"; command: string; success: false; error: string };\n\n// ============================================================================\n// Hook UI Events (stdout)\n// ============================================================================\n\n/** Emitted when a hook needs user input */\nexport type RpcHookUIRequest =\n\t| { type: \"hook_ui_request\"; id: string; method: \"select\"; title: string; options: string[] }\n\t| { type: \"hook_ui_request\"; id: string; method: \"confirm\"; title: string; message: string }\n\t| { type: \"hook_ui_request\"; id: string; method: \"input\"; title: string; placeholder?: string }\n\t| {\n\t\t\ttype: \"hook_ui_request\";\n\t\t\tid: string;\n\t\t\tmethod: \"notify\";\n\t\t\tmessage: string;\n\t\t\tnotifyType?: \"info\" | \"warning\" | \"error\";\n\t };\n\n// ============================================================================\n// Hook UI Commands (stdin)\n// ============================================================================\n\n/** Response to a hook UI request */\nexport type RpcHookUIResponse =\n\t| { type: \"hook_ui_response\"; id: string; value: string }\n\t| { type: \"hook_ui_response\"; id: string; confirmed: boolean }\n\t| { type: \"hook_ui_response\"; id: string; cancelled: true };\n\n// ============================================================================\n// Helper type for extracting command types\n// ============================================================================\n\nexport type RpcCommandType = RpcCommand[\"type\"];\n"]}
package/docs/gemini.md ADDED
@@ -0,0 +1,255 @@
1
+ # Gemini OAuth Integration Guide
2
+
3
+ This document provides a comprehensive analysis of how OAuth authentication could be implemented for Google Gemini in the pi coding-agent, based on the existing Anthropic OAuth implementation and the Gemini CLI's approach.
4
+
5
+ ## Table of Contents
6
+
7
+ 1. [Current Anthropic OAuth Implementation](#current-anthropic-oauth-implementation)
8
+ 2. [Gemini CLI Authentication Analysis](#gemini-cli-authentication-analysis)
9
+ 3. [Gemini API Capabilities](#gemini-api-capabilities)
10
+ 4. [Gemini API Endpoints](#gemini-api-endpoints)
11
+ 5. [Implementation Plan](#implementation-plan)
12
+
13
+ ## Current Anthropic OAuth Implementation
14
+
15
+ The pi coding-agent implements OAuth for Anthropic with the following architecture:
16
+
17
+ ### Key Components
18
+
19
+ 1. **OAuth Flow** (`packages/coding-agent/src/core/oauth/anthropic.ts`):
20
+ - Uses PKCE (Proof Key for Code Exchange) flow for security
21
+ - Client ID: `9d1c250a-e61b-44d9-88ed-5944d1962f5e`
22
+ - Authorization URL: `https://claude.ai/oauth/authorize`
23
+ - Token URL: `https://console.anthropic.com/v1/oauth/token`
24
+ - Scopes: `org:create_api_key user:profile user:inference`
25
+
26
+ 2. **Token Storage** (`packages/coding-agent/src/core/oauth/storage.ts`):
27
+ - Stores credentials in `~/.pi/agent/oauth.json`
28
+ - File permissions set to 0600 (owner read/write only)
29
+ - Format: `{ provider: { type: "oauth", refresh: string, access: string, expires: number } }`
30
+
31
+ 3. **Token Management** (`packages/coding-agent/src/core/oauth/index.ts`):
32
+ - Auto-refresh tokens when expired (with 5-minute buffer)
33
+ - Supports multiple providers through `SupportedOAuthProvider` type
34
+ - Provider info includes id, name, and availability status
35
+
36
+ 4. **Model Integration** (`packages/coding-agent/src/core/model-config.ts`):
37
+ - Checks OAuth tokens first, then environment variables
38
+ - OAuth status cached to avoid repeated file reads
39
+ - Maps providers to OAuth providers via `providerToOAuthProvider`
40
+
41
+ ### Authentication Flow
42
+
43
+ 1. User initiates login with `pi auth login`
44
+ 2. Authorization URL is generated with PKCE challenge
45
+ 3. User opens URL in browser and authorizes
46
+ 4. User copies authorization code (format: `code#state`)
47
+ 5. Code is exchanged for access/refresh tokens
48
+ 6. Tokens are saved encrypted with expiry time
49
+
50
+ ## Gemini CLI Authentication Analysis
51
+
52
+ The Gemini CLI uses a more complex OAuth implementation with several key differences:
53
+
54
+ ### Authentication Methods
55
+
56
+ Gemini supports multiple authentication types:
57
+ - `LOGIN_WITH_GOOGLE` (OAuth personal account)
58
+ - `USE_GEMINI` (API key)
59
+ - `USE_VERTEX_AI` (Vertex AI)
60
+ - `COMPUTE_ADC` (Application Default Credentials)
61
+
62
+ ### OAuth Implementation Details
63
+
64
+ 1. **OAuth Configuration**:
65
+ - Client ID and Secret: See [google-gemini/gemini-cli oauth2.ts](https://github.com/google-gemini/gemini-cli/blob/main/packages/core/src/code_assist/oauth2.ts) (public for installed apps per Google's OAuth docs)
66
+ - Scopes:
67
+ - `https://www.googleapis.com/auth/cloud-platform`
68
+ - `https://www.googleapis.com/auth/userinfo.email`
69
+ - `https://www.googleapis.com/auth/userinfo.profile`
70
+
71
+ 2. **Authentication Flows**:
72
+ - **Web Flow**: Opens browser, runs local HTTP server for callback
73
+ - **User Code Flow**: For environments without browser (NO_BROWSER=true)
74
+ - Uses Google's `google-auth-library` for OAuth handling
75
+
76
+ 3. **Token Storage**:
77
+ - Supports encrypted storage via `OAuthCredentialStorage`
78
+ - Falls back to plain JSON storage
79
+ - Stores user info (email) separately
80
+
81
+ 4. **API Integration**:
82
+ - Uses `CodeAssistServer` for API calls
83
+ - Endpoint: `https://cloudcode-pa.googleapis.com`
84
+ - Includes user tier information (FREE, STANDARD, etc.)
85
+
86
+ ## Gemini API Capabilities
87
+
88
+ Based on the Gemini CLI analysis:
89
+
90
+ ### System Prompts
91
+ ✅ **Yes, Gemini supports system prompts**
92
+ - Implemented via `getCoreSystemPrompt()` in the codebase
93
+ - System instructions are part of the `GenerateContentParameters`
94
+
95
+ ### Tools/Function Calling
96
+ ✅ **Yes, Gemini supports tools and function calling**
97
+ - Uses the `Tool` type from `@google/genai`
98
+ - Extensive tool support including:
99
+ - File system operations (read, write, edit)
100
+ - Web search and fetch
101
+ - MCP (Model Context Protocol) tools
102
+ - Custom tool registration
103
+
104
+ ### Content Generation
105
+ - Supports streaming and non-streaming generation
106
+ - Token counting capabilities
107
+ - Embedding support
108
+ - Context compression for long conversations
109
+
110
+ ## Gemini API Endpoints
111
+
112
+ When using OAuth tokens, the Gemini CLI talks to:
113
+
114
+ ### Primary Endpoint
115
+ - **Base URL**: `https://cloudcode-pa.googleapis.com`
116
+ - **API Version**: `v1internal`
117
+
118
+ ### Key Methods
119
+ - `generateContent` - Non-streaming content generation
120
+ - `streamGenerateContent` - Streaming content generation
121
+ - `countTokens` - Token counting
122
+ - `embedContent` - Text embeddings
123
+ - `loadCodeAssist` - User setup and tier information
124
+ - `onboardUser` - User onboarding
125
+
126
+ ### Authentication
127
+ - OAuth tokens are passed via `AuthClient` from `google-auth-library`
128
+ - Tokens are automatically refreshed by the library
129
+ - Project ID and session ID included in requests
130
+
131
+ ## Implementation Plan
132
+
133
+ ### 1. Add Gemini OAuth Provider Support
134
+
135
+ **File**: `packages/coding-agent/src/core/oauth/gemini.ts`
136
+
137
+ ```typescript
138
+ import { OAuth2Client } from 'google-auth-library';
139
+ import { type OAuthCredentials, saveOAuthCredentials } from "./storage.js";
140
+
141
+ // OAuth credentials from google-gemini/gemini-cli:
142
+ // https://github.com/google-gemini/gemini-cli/blob/main/packages/core/src/code_assist/oauth2.ts
143
+ const SCOPES = [
144
+ "https://www.googleapis.com/auth/cloud-platform",
145
+ "https://www.googleapis.com/auth/userinfo.email",
146
+ "https://www.googleapis.com/auth/userinfo.profile"
147
+ ];
148
+
149
+ export async function loginGemini(
150
+ onAuthUrl: (url: string) => void,
151
+ onPromptCode: () => Promise<string>,
152
+ ): Promise<void> {
153
+ // Implementation similar to Anthropic but using google-auth-library
154
+ }
155
+
156
+ export async function refreshGeminiToken(refreshToken: string): Promise<OAuthCredentials> {
157
+ // Use google-auth-library for refresh
158
+ }
159
+ ```
160
+
161
+ ### 2. Update OAuth Index
162
+
163
+ **File**: `packages/coding-agent/src/core/oauth/index.ts`
164
+
165
+ ```typescript
166
+ export type SupportedOAuthProvider = "anthropic" | "github-copilot" | "gemini";
167
+
168
+ // Add Gemini to provider list
169
+ {
170
+ id: "gemini",
171
+ name: "Google Gemini (Code Assist)",
172
+ available: true,
173
+ }
174
+
175
+ // Add cases for Gemini in login/refresh functions
176
+ ```
177
+
178
+ ### 3. Create Gemini API Client
179
+
180
+ **File**: `packages/ai/src/providers/gemini-oauth.ts`
181
+
182
+ ```typescript
183
+ export class GeminiOAuthProvider implements Provider {
184
+ // Implement Provider interface
185
+ // Use CodeAssistServer approach from Gemini CLI
186
+ // Map to standard pi-ai API format
187
+ }
188
+ ```
189
+
190
+ ### 4. Update Model Configuration
191
+
192
+ **File**: `packages/coding-agent/src/core/model-config.ts`
193
+
194
+ ```typescript
195
+ // Add to providerToOAuthProvider mapping
196
+ gemini: "gemini",
197
+
198
+ // Add Gemini OAuth token check
199
+ if (model.provider === "gemini") {
200
+ const oauthToken = await getOAuthToken("gemini");
201
+ if (oauthToken) return oauthToken;
202
+ const oauthEnv = process.env.GEMINI_OAUTH_TOKEN;
203
+ if (oauthEnv) return oauthEnv;
204
+ }
205
+ ```
206
+
207
+ ### 5. Dependencies
208
+
209
+ Add to `package.json`:
210
+ ```json
211
+ {
212
+ "dependencies": {
213
+ "google-auth-library": "^9.0.0"
214
+ }
215
+ }
216
+ ```
217
+
218
+ ### 6. Environment Variables
219
+
220
+ Support these environment variables:
221
+ - `GEMINI_OAUTH_TOKEN` - Manual OAuth token
222
+ - `GOOGLE_CLOUD_PROJECT` - For project-specific features
223
+ - `NO_BROWSER` - Force user code flow
224
+
225
+ ### Key Differences from Anthropic Implementation
226
+
227
+ 1. **Authentication Library**: Use `google-auth-library` instead of manual OAuth
228
+ 2. **Multiple Auth Types**: Support OAuth, API key, and ADC
229
+ 3. **User Info**: Fetch and cache user email/profile
230
+ 4. **Project Context**: Include project ID in API calls
231
+ 5. **Tier Management**: Handle user tier (FREE/STANDARD) responses
232
+
233
+ ### Challenges and Considerations
234
+
235
+ 1. **API Access**: The Code Assist API (`cloudcode-pa.googleapis.com`) might require special access or be in preview
236
+ 2. **Model Naming**: Need to map Gemini model names to Code Assist equivalents
237
+ 3. **Rate Limits**: Handle tier-based rate limits
238
+ 4. **Error Handling**: Map Google-specific errors to pi error types
239
+ 5. **Token Scopes**: Ensure scopes are sufficient for all operations
240
+
241
+ ### Testing Plan
242
+
243
+ 1. Test OAuth flow (browser and NO_BROWSER modes)
244
+ 2. Test token refresh
245
+ 3. Test API calls with OAuth tokens
246
+ 4. Test fallback to API keys
247
+ 5. Test error scenarios (invalid tokens, network errors)
248
+ 6. Test model switching and tier limits
249
+
250
+ ### Migration Path
251
+
252
+ 1. Users with `GEMINI_API_KEY` continue working unchanged
253
+ 2. New `pi auth login gemini` command for OAuth
254
+ 3. OAuth takes precedence over API keys when available
255
+ 4. Clear messaging about benefits (higher limits, better features)