@gajae-code/coding-agent 0.2.5 → 0.3.1

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 (234) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/types/async/job-manager.d.ts +91 -2
  3. package/dist/types/cli/args.d.ts +1 -1
  4. package/dist/types/commands/deep-interview.d.ts +3 -0
  5. package/dist/types/commands/harness.d.ts +37 -0
  6. package/dist/types/config/keybindings.d.ts +5 -0
  7. package/dist/types/config/settings-schema.d.ts +10 -4
  8. package/dist/types/config/settings.d.ts +2 -0
  9. package/dist/types/debug/crash-diagnostics.d.ts +45 -0
  10. package/dist/types/debug/runtime-gauges.d.ts +6 -0
  11. package/dist/types/deep-interview/render-middleware.d.ts +6 -0
  12. package/dist/types/eval/py/executor.d.ts +2 -0
  13. package/dist/types/eval/py/kernel.d.ts +2 -0
  14. package/dist/types/exec/bash-executor.d.ts +10 -0
  15. package/dist/types/extensibility/custom-tools/types.d.ts +1 -0
  16. package/dist/types/extensibility/extensions/types.d.ts +6 -0
  17. package/dist/types/extensibility/shared-events.d.ts +1 -0
  18. package/dist/types/gjc-runtime/cli-write-receipt.d.ts +24 -0
  19. package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +1 -0
  20. package/dist/types/gjc-runtime/state-graph.d.ts +4 -0
  21. package/dist/types/gjc-runtime/state-migrations.d.ts +33 -0
  22. package/dist/types/gjc-runtime/state-renderer.d.ts +65 -0
  23. package/dist/types/gjc-runtime/state-runtime.d.ts +2 -0
  24. package/dist/types/gjc-runtime/state-schema.d.ts +317 -0
  25. package/dist/types/gjc-runtime/state-validation.d.ts +6 -0
  26. package/dist/types/gjc-runtime/state-writer.d.ts +147 -0
  27. package/dist/types/gjc-runtime/team-runtime.d.ts +81 -7
  28. package/dist/types/gjc-runtime/workflow-command-ref.d.ts +43 -0
  29. package/dist/types/gjc-runtime/workflow-manifest.d.ts +54 -0
  30. package/dist/types/harness-control-plane/classifier.d.ts +13 -0
  31. package/dist/types/harness-control-plane/control-endpoint.d.ts +31 -0
  32. package/dist/types/harness-control-plane/finalize.d.ts +47 -0
  33. package/dist/types/harness-control-plane/frame-mapper.d.ts +29 -0
  34. package/dist/types/harness-control-plane/operate.d.ts +35 -0
  35. package/dist/types/harness-control-plane/owner.d.ts +46 -0
  36. package/dist/types/harness-control-plane/preserve.d.ts +19 -0
  37. package/dist/types/harness-control-plane/receipts.d.ts +88 -0
  38. package/dist/types/harness-control-plane/rpc-adapter.d.ts +66 -0
  39. package/dist/types/harness-control-plane/seams.d.ts +21 -0
  40. package/dist/types/harness-control-plane/session-lease.d.ts +65 -0
  41. package/dist/types/harness-control-plane/state-machine.d.ts +19 -0
  42. package/dist/types/harness-control-plane/storage.d.ts +53 -0
  43. package/dist/types/harness-control-plane/types.d.ts +162 -0
  44. package/dist/types/hooks/skill-keywords.d.ts +2 -1
  45. package/dist/types/hooks/skill-state.d.ts +23 -29
  46. package/dist/types/internal-urls/agent-protocol.d.ts +2 -2
  47. package/dist/types/internal-urls/artifact-protocol.d.ts +2 -2
  48. package/dist/types/internal-urls/registry-helpers.d.ts +8 -7
  49. package/dist/types/internal-urls/types.d.ts +4 -0
  50. package/dist/types/lsp/index.d.ts +10 -10
  51. package/dist/types/modes/bridge/auth.d.ts +12 -0
  52. package/dist/types/modes/bridge/bridge-client-bridge.d.ts +9 -0
  53. package/dist/types/modes/bridge/bridge-mode.d.ts +44 -0
  54. package/dist/types/modes/bridge/bridge-ui-context.d.ts +88 -0
  55. package/dist/types/modes/bridge/event-stream.d.ts +8 -0
  56. package/dist/types/modes/components/custom-editor.d.ts +6 -0
  57. package/dist/types/modes/components/hook-selector.d.ts +1 -0
  58. package/dist/types/modes/components/jobs-overlay-model.d.ts +31 -0
  59. package/dist/types/modes/components/jobs-overlay.d.ts +30 -0
  60. package/dist/types/modes/components/status-line/types.d.ts +2 -0
  61. package/dist/types/modes/components/status-line.d.ts +2 -0
  62. package/dist/types/modes/controllers/input-controller.d.ts +1 -0
  63. package/dist/types/modes/controllers/selector-controller.d.ts +8 -0
  64. package/dist/types/modes/index.d.ts +1 -0
  65. package/dist/types/modes/interactive-mode.d.ts +2 -0
  66. package/dist/types/modes/jobs-observer.d.ts +57 -0
  67. package/dist/types/modes/rpc/host-tools.d.ts +1 -16
  68. package/dist/types/modes/rpc/host-uris.d.ts +1 -38
  69. package/dist/types/modes/shared/agent-wire/command-dispatch.d.ts +20 -0
  70. package/dist/types/modes/shared/agent-wire/command-validation.d.ts +2 -0
  71. package/dist/types/modes/shared/agent-wire/event-envelope.d.ts +24 -0
  72. package/dist/types/modes/shared/agent-wire/handshake.d.ts +46 -0
  73. package/dist/types/modes/shared/agent-wire/host-tool-bridge.d.ts +16 -0
  74. package/dist/types/modes/shared/agent-wire/host-uri-bridge.d.ts +17 -0
  75. package/dist/types/modes/shared/agent-wire/protocol.d.ts +44 -0
  76. package/dist/types/modes/shared/agent-wire/responses.d.ts +4 -0
  77. package/dist/types/modes/shared/agent-wire/scopes.d.ts +18 -0
  78. package/dist/types/modes/shared/agent-wire/ui-request-broker.d.ts +42 -0
  79. package/dist/types/modes/shared/agent-wire/ui-result.d.ts +27 -0
  80. package/dist/types/modes/types.d.ts +2 -0
  81. package/dist/types/sdk.d.ts +4 -0
  82. package/dist/types/session/agent-session.d.ts +19 -1
  83. package/dist/types/skill-state/active-state.d.ts +2 -0
  84. package/dist/types/skill-state/deep-interview-mutation-guard.d.ts +1 -1
  85. package/dist/types/skill-state/workflow-state-contract.d.ts +25 -2
  86. package/dist/types/skill-state/workflow-state-version.d.ts +3 -0
  87. package/dist/types/task/executor.d.ts +3 -0
  88. package/dist/types/task/id.d.ts +7 -0
  89. package/dist/types/task/index.d.ts +5 -0
  90. package/dist/types/task/receipt.d.ts +85 -0
  91. package/dist/types/task/spawn-gate.d.ts +38 -0
  92. package/dist/types/task/types.d.ts +198 -14
  93. package/dist/types/tools/cron.d.ts +6 -0
  94. package/dist/types/tools/index.d.ts +2 -0
  95. package/dist/types/tools/path-utils.d.ts +1 -0
  96. package/dist/types/tools/subagent.d.ts +26 -1
  97. package/package.json +7 -7
  98. package/scripts/build-binary.ts +7 -0
  99. package/src/async/job-manager.ts +334 -6
  100. package/src/cli/args.ts +9 -2
  101. package/src/cli/auth-broker-cli.ts +1 -0
  102. package/src/cli/config-cli.ts +10 -2
  103. package/src/cli.ts +2 -0
  104. package/src/commands/deep-interview.ts +1 -0
  105. package/src/commands/harness.ts +862 -0
  106. package/src/commands/launch.ts +2 -2
  107. package/src/commands/state.ts +2 -1
  108. package/src/commands/team.ts +54 -39
  109. package/src/config/keybindings.ts +6 -0
  110. package/src/config/settings-schema.ts +13 -3
  111. package/src/config/settings.ts +5 -0
  112. package/src/dap/client.ts +17 -3
  113. package/src/debug/crash-diagnostics.ts +223 -0
  114. package/src/debug/runtime-gauges.ts +20 -0
  115. package/src/deep-interview/render-middleware.ts +372 -0
  116. package/src/defaults/gjc/skills/deep-interview/SKILL.md +1 -1
  117. package/src/defaults/gjc/skills/ralplan/SKILL.md +31 -2
  118. package/src/defaults/gjc/skills/team/SKILL.md +47 -21
  119. package/src/defaults/gjc/skills/ultragoal/SKILL.md +106 -13
  120. package/src/eval/py/executor.ts +21 -1
  121. package/src/eval/py/kernel.ts +15 -0
  122. package/src/exec/bash-executor.ts +41 -0
  123. package/src/extensibility/custom-tools/types.ts +1 -0
  124. package/src/extensibility/extensions/types.ts +6 -0
  125. package/src/extensibility/shared-events.ts +1 -0
  126. package/src/gjc-runtime/cli-write-receipt.ts +31 -0
  127. package/src/gjc-runtime/deep-interview-runtime.ts +98 -42
  128. package/src/gjc-runtime/goal-mode-request.ts +11 -3
  129. package/src/gjc-runtime/ralplan-runtime.ts +235 -43
  130. package/src/gjc-runtime/state-graph.ts +86 -0
  131. package/src/gjc-runtime/state-migrations.ts +179 -0
  132. package/src/gjc-runtime/state-renderer.ts +345 -0
  133. package/src/gjc-runtime/state-runtime.ts +1155 -46
  134. package/src/gjc-runtime/state-schema.ts +192 -0
  135. package/src/gjc-runtime/state-validation.ts +49 -0
  136. package/src/gjc-runtime/state-writer.ts +749 -0
  137. package/src/gjc-runtime/team-runtime.ts +1255 -189
  138. package/src/gjc-runtime/ultragoal-runtime.ts +460 -43
  139. package/src/gjc-runtime/workflow-command-ref.ts +239 -0
  140. package/src/gjc-runtime/workflow-manifest.generated.json +1601 -0
  141. package/src/gjc-runtime/workflow-manifest.ts +427 -0
  142. package/src/harness-control-plane/classifier.ts +128 -0
  143. package/src/harness-control-plane/control-endpoint.ts +148 -0
  144. package/src/harness-control-plane/finalize.ts +222 -0
  145. package/src/harness-control-plane/frame-mapper.ts +286 -0
  146. package/src/harness-control-plane/operate.ts +225 -0
  147. package/src/harness-control-plane/owner.ts +600 -0
  148. package/src/harness-control-plane/preserve.ts +102 -0
  149. package/src/harness-control-plane/receipts.ts +216 -0
  150. package/src/harness-control-plane/rpc-adapter.ts +276 -0
  151. package/src/harness-control-plane/seams.ts +39 -0
  152. package/src/harness-control-plane/session-lease.ts +388 -0
  153. package/src/harness-control-plane/state-machine.ts +98 -0
  154. package/src/harness-control-plane/storage.ts +257 -0
  155. package/src/harness-control-plane/types.ts +214 -0
  156. package/src/hooks/skill-keywords.ts +4 -2
  157. package/src/hooks/skill-state.ts +197 -64
  158. package/src/internal-urls/agent-protocol.ts +68 -21
  159. package/src/internal-urls/artifact-protocol.ts +12 -17
  160. package/src/internal-urls/docs-index.generated.ts +3 -2
  161. package/src/internal-urls/registry-helpers.ts +19 -16
  162. package/src/internal-urls/types.ts +4 -0
  163. package/src/lsp/client.ts +18 -2
  164. package/src/main.ts +21 -5
  165. package/src/modes/bridge/auth.ts +41 -0
  166. package/src/modes/bridge/bridge-client-bridge.ts +47 -0
  167. package/src/modes/bridge/bridge-mode.ts +520 -0
  168. package/src/modes/bridge/bridge-ui-context.ts +200 -0
  169. package/src/modes/bridge/event-stream.ts +70 -0
  170. package/src/modes/components/assistant-message.ts +5 -1
  171. package/src/modes/components/custom-editor.ts +101 -0
  172. package/src/modes/components/hook-selector.ts +133 -20
  173. package/src/modes/components/jobs-overlay-model.ts +109 -0
  174. package/src/modes/components/jobs-overlay.ts +172 -0
  175. package/src/modes/components/status-line/presets.ts +7 -5
  176. package/src/modes/components/status-line/segments.ts +25 -0
  177. package/src/modes/components/status-line/types.ts +2 -0
  178. package/src/modes/components/status-line.ts +9 -1
  179. package/src/modes/controllers/event-controller.ts +71 -6
  180. package/src/modes/controllers/extension-ui-controller.ts +43 -1
  181. package/src/modes/controllers/input-controller.ts +105 -9
  182. package/src/modes/controllers/selector-controller.ts +31 -1
  183. package/src/modes/index.ts +1 -0
  184. package/src/modes/interactive-mode.ts +28 -0
  185. package/src/modes/jobs-observer.ts +204 -0
  186. package/src/modes/rpc/host-tools.ts +1 -186
  187. package/src/modes/rpc/host-uris.ts +1 -235
  188. package/src/modes/rpc/rpc-client.ts +25 -10
  189. package/src/modes/rpc/rpc-mode.ts +12 -381
  190. package/src/modes/shared/agent-wire/command-dispatch.ts +341 -0
  191. package/src/modes/shared/agent-wire/command-validation.ts +131 -0
  192. package/src/modes/shared/agent-wire/event-envelope.ts +108 -0
  193. package/src/modes/shared/agent-wire/handshake.ts +117 -0
  194. package/src/modes/shared/agent-wire/host-tool-bridge.ts +194 -0
  195. package/src/modes/shared/agent-wire/host-uri-bridge.ts +236 -0
  196. package/src/modes/shared/agent-wire/protocol.ts +96 -0
  197. package/src/modes/shared/agent-wire/responses.ts +17 -0
  198. package/src/modes/shared/agent-wire/scopes.ts +89 -0
  199. package/src/modes/shared/agent-wire/ui-request-broker.ts +150 -0
  200. package/src/modes/shared/agent-wire/ui-result.ts +48 -0
  201. package/src/modes/types.ts +2 -0
  202. package/src/prompts/agents/executor.md +13 -0
  203. package/src/prompts/tools/subagent.md +39 -4
  204. package/src/prompts/tools/task-summary.md +3 -9
  205. package/src/prompts/tools/task.md +5 -1
  206. package/src/sdk.ts +8 -0
  207. package/src/session/agent-session.ts +445 -71
  208. package/src/session/session-manager.ts +13 -1
  209. package/src/skill-state/active-state.ts +58 -65
  210. package/src/skill-state/deep-interview-mutation-guard.ts +114 -17
  211. package/src/skill-state/initial-phase.ts +2 -0
  212. package/src/skill-state/workflow-state-contract.ts +33 -4
  213. package/src/skill-state/workflow-state-version.ts +3 -0
  214. package/src/slash-commands/builtin-registry.ts +8 -0
  215. package/src/task/executor.ts +79 -13
  216. package/src/task/id.ts +33 -0
  217. package/src/task/index.ts +376 -74
  218. package/src/task/output-manager.ts +5 -4
  219. package/src/task/receipt.ts +297 -0
  220. package/src/task/render.ts +54 -134
  221. package/src/task/spawn-gate.ts +132 -0
  222. package/src/task/types.ts +104 -10
  223. package/src/tools/ask.ts +88 -27
  224. package/src/tools/ast-edit.ts +1 -0
  225. package/src/tools/ast-grep.ts +1 -0
  226. package/src/tools/bash.ts +1 -1
  227. package/src/tools/cron.ts +48 -0
  228. package/src/tools/find.ts +4 -1
  229. package/src/tools/index.ts +2 -0
  230. package/src/tools/path-utils.ts +3 -2
  231. package/src/tools/read.ts +1 -0
  232. package/src/tools/search.ts +1 -0
  233. package/src/tools/skill.ts +6 -1
  234. package/src/tools/subagent.ts +423 -79
@@ -10,7 +10,6 @@
10
10
  * - Events: AgentSessionEvent objects streamed as they occur
11
11
  * - Extension UI: Extension UI requests are emitted, client responds with extension_ui_response
12
12
  */
13
- import { getOAuthProviders } from "@gajae-code/ai/utils/oauth";
14
13
  import { $env, readJsonl, Snowflake } from "@gajae-code/utils";
15
14
  import type {
16
15
  ExtensionUIContext,
@@ -20,6 +19,8 @@ import type {
20
19
  import { type Theme, theme } from "../../modes/theme/theme";
21
20
  import type { AgentSession } from "../../session/agent-session";
22
21
  import { initializeExtensions } from "../runtime-init";
22
+ import { dispatchRpcCommand } from "../shared/agent-wire/command-dispatch";
23
+ import { rpcError as error } from "../shared/agent-wire/responses";
23
24
  import { isRpcHostToolResult, isRpcHostToolUpdate, RpcHostToolBridge } from "./host-tools";
24
25
  import { isRpcHostUriResult, RpcHostUriBridge } from "./host-uris";
25
26
  import type {
@@ -28,11 +29,9 @@ import type {
28
29
  RpcExtensionUIResponse,
29
30
  RpcHostToolCallRequest,
30
31
  RpcHostToolCancelRequest,
31
- RpcHostToolDefinition,
32
32
  RpcHostUriCancelRequest,
33
33
  RpcHostUriRequest,
34
34
  RpcResponse,
35
- RpcSessionState,
36
35
  } from "./rpc-types";
37
36
 
38
37
  // Re-export types for consumers
@@ -54,30 +53,6 @@ type RpcOutput = (
54
53
  | object,
55
54
  ) => void;
56
55
 
57
- function normalizeHostToolDefinitions(tools: RpcHostToolDefinition[]): RpcHostToolDefinition[] {
58
- return tools.map((tool, index) => {
59
- const name = typeof tool.name === "string" ? tool.name.trim() : "";
60
- if (!name) {
61
- throw new Error(`Host tool at index ${index} must provide a non-empty name`);
62
- }
63
- const description = typeof tool.description === "string" ? tool.description.trim() : "";
64
- if (!description) {
65
- throw new Error(`Host tool "${name}" must provide a non-empty description`);
66
- }
67
- if (!tool.parameters || typeof tool.parameters !== "object" || Array.isArray(tool.parameters)) {
68
- throw new Error(`Host tool "${name}" must provide a JSON Schema object`);
69
- }
70
- const label = typeof tool.label === "string" && tool.label.trim() ? tool.label.trim() : name;
71
- return {
72
- name,
73
- label,
74
- description,
75
- parameters: tool.parameters,
76
- hidden: tool.hidden === true,
77
- };
78
- });
79
- }
80
-
81
56
  function parseValueDialogResponse(
82
57
  response: RpcExtensionUIResponse,
83
58
  dialogOptions: ExtensionUIDialogOptions | undefined,
@@ -181,21 +156,6 @@ export async function runRpcMode(
181
156
  };
182
157
  const emitRpcTitles = shouldEmitRpcTitles();
183
158
 
184
- const success = <T extends RpcCommand["type"]>(
185
- id: string | undefined,
186
- command: T,
187
- data?: object | null,
188
- ): RpcResponse => {
189
- if (data === undefined) {
190
- return { id, type: "response", command, success: true } as RpcResponse;
191
- }
192
- return { id, type: "response", command, success: true, data } as RpcResponse;
193
- };
194
-
195
- const error = (id: string | undefined, command: string, message: string): RpcResponse => {
196
- return { id, type: "response", command, success: false, error: message };
197
- };
198
-
199
159
  const pendingExtensionRequests = new Map<string, PendingExtensionRequest>();
200
160
  const hostToolBridge = new RpcHostToolBridge(output);
201
161
  const hostUriBridge = new RpcHostUriBridge(output);
@@ -450,345 +410,16 @@ export async function runRpcMode(
450
410
  output(event);
451
411
  });
452
412
 
453
- // Handle a single command
454
- const handleCommand = async (command: RpcCommand): Promise<RpcResponse> => {
455
- const id = command.id;
456
-
457
- switch (command.type) {
458
- // =================================================================
459
- // Prompting
460
- // =================================================================
461
-
462
- case "prompt": {
463
- // Don't await - events will stream
464
- // Extension commands are executed immediately, file prompt templates are expanded
465
- // If streaming and streamingBehavior specified, queues via steer/followUp
466
- session
467
- .prompt(command.message, {
468
- images: command.images,
469
- streamingBehavior: command.streamingBehavior,
470
- })
471
- .catch(e => output(error(id, "prompt", e.message)));
472
- return success(id, "prompt");
473
- }
474
-
475
- case "steer": {
476
- await session.steer(command.message, command.images);
477
- return success(id, "steer");
478
- }
479
-
480
- case "follow_up": {
481
- await session.followUp(command.message, command.images);
482
- return success(id, "follow_up");
483
- }
484
-
485
- case "abort": {
486
- await session.abort();
487
- return success(id, "abort");
488
- }
489
-
490
- case "abort_and_prompt": {
491
- await session.abort();
492
- session
493
- .prompt(command.message, { images: command.images })
494
- .catch(e => output(error(id, "abort_and_prompt", e.message)));
495
- return success(id, "abort_and_prompt");
496
- }
497
-
498
- case "new_session": {
499
- const options = command.parentSession ? { parentSession: command.parentSession } : undefined;
500
- const cancelled = !(await session.newSession(options));
501
- return success(id, "new_session", { cancelled });
502
- }
503
-
504
- // =================================================================
505
- // State
506
- // =================================================================
507
-
508
- case "get_state": {
509
- const state: RpcSessionState = {
510
- model: session.model,
511
- thinkingLevel: session.thinkingLevel,
512
- isStreaming: session.isStreaming,
513
- isCompacting: session.isCompacting,
514
- steeringMode: session.steeringMode,
515
- followUpMode: session.followUpMode,
516
- interruptMode: session.interruptMode,
517
- sessionFile: session.sessionFile,
518
- sessionId: session.sessionId,
519
- sessionName: session.sessionName,
520
- autoCompactionEnabled: session.autoCompactionEnabled,
521
- messageCount: session.messages.length,
522
- queuedMessageCount: session.queuedMessageCount,
523
- todoPhases: session.getTodoPhases(),
524
- systemPrompt: session.systemPrompt,
525
- dumpTools: session.agent.state.tools.map(tool => ({
526
- name: tool.name,
527
- description: tool.description,
528
- parameters: tool.parameters,
529
- })),
530
- contextUsage: session.getContextUsage(),
531
- };
532
- return success(id, "get_state", state);
533
- }
534
-
535
- case "set_todos": {
536
- session.setTodoPhases(command.phases);
537
- return success(id, "set_todos", { todoPhases: session.getTodoPhases() });
538
- }
539
-
540
- case "set_host_tools": {
541
- const tools = normalizeHostToolDefinitions(command.tools);
542
- const rpcTools = hostToolBridge.setTools(tools);
543
- await session.refreshRpcHostTools(rpcTools);
544
- return success(id, "set_host_tools", { toolNames: tools.map(tool => tool.name) });
545
- }
546
-
547
- case "set_host_uri_schemes": {
548
- try {
549
- const schemes = hostUriBridge.setSchemes(command.schemes);
550
- return success(id, "set_host_uri_schemes", { schemes });
551
- } catch (err) {
552
- return error(id, "set_host_uri_schemes", err instanceof Error ? err.message : String(err));
553
- }
554
- }
555
-
556
- // =================================================================
557
- // Model
558
- // =================================================================
559
-
560
- case "set_model": {
561
- const models = session.getAvailableModels();
562
- const model = models.find(m => m.provider === command.provider && m.id === command.modelId);
563
- if (!model) {
564
- return error(id, "set_model", `Model not found: ${command.provider}/${command.modelId}`);
565
- }
566
- await session.setModel(model);
567
- return success(id, "set_model", model);
568
- }
569
-
570
- case "cycle_model": {
571
- const result = await session.cycleModel();
572
- if (!result) {
573
- return success(id, "cycle_model", null);
574
- }
575
- return success(id, "cycle_model", result);
576
- }
577
-
578
- case "get_available_models": {
579
- const models = session.getAvailableModels();
580
- return success(id, "get_available_models", { models });
581
- }
582
-
583
- // =================================================================
584
- // Thinking
585
- // =================================================================
586
-
587
- case "set_thinking_level": {
588
- session.setThinkingLevel(command.level);
589
- return success(id, "set_thinking_level");
590
- }
591
-
592
- case "cycle_thinking_level": {
593
- const level = session.cycleThinkingLevel();
594
- if (!level) {
595
- return success(id, "cycle_thinking_level", null);
596
- }
597
- return success(id, "cycle_thinking_level", { level });
598
- }
599
-
600
- // =================================================================
601
- // Queue Modes
602
- // =================================================================
603
-
604
- case "set_steering_mode": {
605
- session.setSteeringMode(command.mode);
606
- return success(id, "set_steering_mode");
607
- }
608
-
609
- case "set_follow_up_mode": {
610
- session.setFollowUpMode(command.mode);
611
- return success(id, "set_follow_up_mode");
612
- }
613
-
614
- case "set_interrupt_mode": {
615
- session.setInterruptMode(command.mode);
616
- return success(id, "set_interrupt_mode");
617
- }
618
-
619
- // =================================================================
620
- // Compaction
621
- // =================================================================
622
-
623
- case "compact": {
624
- const result = await session.compact(command.customInstructions);
625
- return success(id, "compact", result);
626
- }
627
-
628
- case "set_auto_compaction": {
629
- session.setAutoCompactionEnabled(command.enabled);
630
- return success(id, "set_auto_compaction");
631
- }
632
-
633
- // =================================================================
634
- // Retry
635
- // =================================================================
636
-
637
- case "set_auto_retry": {
638
- session.setAutoRetryEnabled(command.enabled);
639
- return success(id, "set_auto_retry");
640
- }
641
-
642
- case "abort_retry": {
643
- session.abortRetry();
644
- return success(id, "abort_retry");
645
- }
646
-
647
- // =================================================================
648
- // Bash
649
- // =================================================================
650
-
651
- case "bash": {
652
- const result = await session.executeBash(command.command);
653
- return success(id, "bash", result);
654
- }
655
-
656
- case "abort_bash": {
657
- session.abortBash();
658
- return success(id, "abort_bash");
659
- }
660
-
661
- // =================================================================
662
- // Session
663
- // =================================================================
664
-
665
- case "get_session_stats": {
666
- const stats = session.getSessionStats();
667
- return success(id, "get_session_stats", stats);
668
- }
669
-
670
- case "export_html": {
671
- const path = await session.exportToHtml(command.outputPath);
672
- return success(id, "export_html", { path });
673
- }
674
-
675
- case "switch_session": {
676
- const cancelled = !(await session.switchSession(command.sessionPath));
677
- return success(id, "switch_session", { cancelled });
678
- }
679
-
680
- case "branch": {
681
- const result = await session.branch(command.entryId);
682
- return success(id, "branch", { text: result.selectedText, cancelled: result.cancelled });
683
- }
684
-
685
- case "get_branch_messages": {
686
- const messages = session.getUserMessagesForBranching();
687
- return success(id, "get_branch_messages", { messages });
688
- }
689
-
690
- case "get_last_assistant_text": {
691
- const text = session.getLastAssistantText();
692
- return success(id, "get_last_assistant_text", { text });
693
- }
694
-
695
- case "set_session_name": {
696
- const name = command.name.trim();
697
- if (!name) {
698
- return error(id, "set_session_name", "Session name cannot be empty");
699
- }
700
- const applied = await session.setSessionName(name, "user");
701
- if (!applied) {
702
- return error(id, "set_session_name", "Session name cannot be empty");
703
- }
704
- return success(id, "set_session_name");
705
- }
706
-
707
- case "handoff": {
708
- const result = await session.handoff(command.customInstructions);
709
- return success(id, "handoff", result ? { savedPath: result.savedPath } : null);
710
- }
711
-
712
- // =================================================================
713
- // Messages
714
- // =================================================================
715
-
716
- case "get_messages": {
717
- return success(id, "get_messages", { messages: session.messages });
718
- }
719
-
720
- // =================================================================
721
- // Login
722
- // =================================================================
723
-
724
- case "get_login_providers": {
725
- const providers = getOAuthProviders().map(provider => ({
726
- id: provider.id,
727
- name: provider.name,
728
- available: provider.available,
729
- authenticated: session.modelRegistry.authStorage.hasAuth(provider.id),
730
- }));
731
- return success(id, "get_login_providers", { providers });
732
- }
733
-
734
- case "login": {
735
- const knownProvider = getOAuthProviders().find(p => p.id === command.providerId);
736
- if (!knownProvider) {
737
- return error(id, "login", `Unknown OAuth provider: ${command.providerId}`);
738
- }
739
- const uiCtx = new RpcExtensionUIContext(pendingExtensionRequests, output);
740
- // Track whether onAuth has fired. Providers that use OAuthCallbackFlow
741
- // always call onAuth first (emit browser URL), then onManualCodeInput as
742
- // a fallback. Providers that require interactive input (API-key paste,
743
- // GitHub Enterprise URL, device-code entry) call onPrompt before onAuth.
744
- // We use this ordering to self-classify at runtime — no static allowlist.
745
- let authEmitted = false;
746
- try {
747
- await session.modelRegistry.authStorage.login(command.providerId, {
748
- onAuth: info => {
749
- authEmitted = true;
750
- output({
751
- type: "extension_ui_request",
752
- id: Snowflake.next() as string,
753
- method: "open_url",
754
- url: info.url,
755
- instructions: info.instructions,
756
- } as RpcExtensionUIRequest);
757
- },
758
- onProgress: message => {
759
- uiCtx.notify(message, "info");
760
- },
761
- onPrompt: () => {
762
- if (!authEmitted) {
763
- // onPrompt called before any auth URL — provider requires
764
- // interactive input that cannot be satisfied headlessly.
765
- return Promise.reject(
766
- new Error(
767
- `Provider '${command.providerId}' requires interactive prompts ` +
768
- "which are not supported in RPC mode. Use the terminal UI to log in.",
769
- ),
770
- );
771
- }
772
- // onAuth has already fired — we are inside OAuthCallbackFlow's
773
- // manual-redirect fallback race. Returning a never-settling promise
774
- // lets the race block until the callback server wins; a rejection
775
- // would be caught as null and spin the while(true) loop.
776
- return new Promise<string>(() => {});
777
- },
778
- });
779
- await session.modelRegistry.refresh();
780
- return success(id, "login", { providerId: command.providerId });
781
- } catch (err: unknown) {
782
- return error(id, "login", err instanceof Error ? err.message : String(err));
783
- }
784
- }
785
-
786
- default: {
787
- const unknownCommand = command as { type: string };
788
- return error(undefined, unknownCommand.type, `Unknown command: ${unknownCommand.type}`);
789
- }
790
- }
791
- };
413
+ // Handle a single command through the shared agent-wire dispatcher so RPC
414
+ // and bridge mode use one command surface.
415
+ const handleCommand = (command: RpcCommand): Promise<RpcResponse> =>
416
+ dispatchRpcCommand(command, {
417
+ session,
418
+ output,
419
+ hostToolRegistry: hostToolBridge,
420
+ hostUriRegistry: hostUriBridge,
421
+ createUiContext: () => new RpcExtensionUIContext(pendingExtensionRequests, output),
422
+ });
792
423
 
793
424
  /**
794
425
  * Check if shutdown was requested and perform shutdown if so.