@gajae-code/coding-agent 0.13.2 → 0.14.0

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 (610) hide show
  1. package/CHANGELOG.md +215 -8
  2. package/README.md +2 -0
  3. package/bin/gajaessi.js +4 -0
  4. package/dist/types/async/job-manager.d.ts +55 -2
  5. package/dist/types/async/support.d.ts +14 -0
  6. package/dist/types/capability/mcp.d.ts +6 -0
  7. package/dist/types/capability/types.d.ts +6 -0
  8. package/dist/types/cli/accounts-cli.d.ts +19 -0
  9. package/dist/types/cli/args.d.ts +3 -0
  10. package/dist/types/cli/config-cli.d.ts +6 -0
  11. package/dist/types/cli/crash-cli.d.ts +10 -0
  12. package/dist/types/cli/customize-doctor.d.ts +145 -0
  13. package/dist/types/cli/daemon-cli.d.ts +3 -1
  14. package/dist/types/cli/mcp-cli.d.ts +11 -0
  15. package/dist/types/cli/notify-cli.d.ts +1 -1
  16. package/dist/types/cli/root-flags.d.ts +12 -0
  17. package/dist/types/cli/setup-cli.d.ts +3 -1
  18. package/dist/types/cli/skills-cli.d.ts +2 -1
  19. package/dist/types/cli/update-cli.d.ts +19 -1
  20. package/dist/types/cli.d.ts +6 -0
  21. package/dist/types/commands/accounts.d.ts +40 -0
  22. package/dist/types/commands/crash.d.ts +24 -0
  23. package/dist/types/commands/customize.d.ts +22 -0
  24. package/dist/types/commands/daemon.d.ts +1 -1
  25. package/dist/types/commands/launch.d.ts +6 -0
  26. package/dist/types/commands/setup.d.ts +6 -0
  27. package/dist/types/commands/skills.d.ts +6 -1
  28. package/dist/types/commands/update.d.ts +7 -0
  29. package/dist/types/config/atomic-yaml-patch-worker.d.ts +25 -0
  30. package/dist/types/config/atomic-yaml-patch.d.ts +62 -2
  31. package/dist/types/config/config-schema-version.d.ts +10 -0
  32. package/dist/types/config/file-lock.d.ts +18 -0
  33. package/dist/types/config/model-profile-activation.d.ts +3 -1
  34. package/dist/types/config/model-registry.d.ts +10 -1
  35. package/dist/types/config/models-config-schema.d.ts +2 -0
  36. package/dist/types/config/settings-schema.d.ts +73 -9
  37. package/dist/types/config/settings.d.ts +63 -0
  38. package/dist/types/config/skill-settings-defaults.d.ts +26 -0
  39. package/dist/types/config/task-delegation.d.ts +39 -0
  40. package/dist/types/config/update-channel.d.ts +10 -0
  41. package/dist/types/coordinator-mcp/server.d.ts +5 -1
  42. package/dist/types/crash/index-store.d.ts +87 -0
  43. package/dist/types/crash/nudge.d.ts +50 -0
  44. package/dist/types/crash/record-loader.d.ts +17 -0
  45. package/dist/types/crash/report.d.ts +134 -0
  46. package/dist/types/crash/sanitize.d.ts +25 -0
  47. package/dist/types/cursor.d.ts +13 -2
  48. package/dist/types/customization/import.d.ts +37 -0
  49. package/dist/types/customization/index.d.ts +4 -0
  50. package/dist/types/customization/inventory.d.ts +25 -0
  51. package/dist/types/customization/mutations.d.ts +32 -0
  52. package/dist/types/customization/types.d.ts +115 -0
  53. package/dist/types/daemon/control-types.d.ts +8 -1
  54. package/dist/types/daemon/operator-contract.d.ts +4 -4
  55. package/dist/types/discovery/claude.d.ts +39 -1
  56. package/dist/types/discovery/codex.d.ts +39 -1
  57. package/dist/types/discovery/index.d.ts +2 -0
  58. package/dist/types/discovery/mcp-compat.d.ts +30 -0
  59. package/dist/types/edit/renderer.d.ts +23 -0
  60. package/dist/types/extensibility/extensions/runner.d.ts +3 -0
  61. package/dist/types/extensibility/extensions/types.d.ts +21 -4
  62. package/dist/types/extensibility/gjc-plugins/observability.d.ts +6 -1
  63. package/dist/types/extensibility/gjc-plugins/registry.d.ts +8 -1
  64. package/dist/types/extensibility/hooks/loader.d.ts +19 -5
  65. package/dist/types/extensibility/runtime-skill-discovery.d.ts +22 -1
  66. package/dist/types/extensibility/skill-management.d.ts +107 -0
  67. package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +3 -1
  68. package/dist/types/gjc-runtime/launch-worktree.d.ts +8 -0
  69. package/dist/types/gjc-runtime/linux-proc.d.ts +3 -0
  70. package/dist/types/gjc-runtime/ralplan-runtime.d.ts +10 -6
  71. package/dist/types/gjc-runtime/session-state-lock.d.ts +104 -0
  72. package/dist/types/gjc-runtime/session-state-sidecar.d.ts +120 -2
  73. package/dist/types/gjc-runtime/state-writer.d.ts +10 -1
  74. package/dist/types/gjc-runtime/ultragoal-guard.d.ts +4 -2
  75. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +8 -6
  76. package/dist/types/gjc-runtime/workflow-settings.d.ts +109 -0
  77. package/dist/types/hooks/events.d.ts +60 -0
  78. package/dist/types/hooks/normalize.d.ts +83 -0
  79. package/dist/types/hooks/skill-state.d.ts +9 -2
  80. package/dist/types/main.d.ts +2 -1
  81. package/dist/types/modes/acp/abort-scope.d.ts +13 -0
  82. package/dist/types/modes/acp/acp-agent.d.ts +7 -4
  83. package/dist/types/modes/components/customization/customization-dashboard.d.ts +44 -0
  84. package/dist/types/modes/components/customization/import-wizard.d.ts +21 -0
  85. package/dist/types/modes/components/customization/index.d.ts +1 -0
  86. package/dist/types/modes/components/dynamic-theme-text.d.ts +9 -0
  87. package/dist/types/modes/components/gajae-pet-widget.d.ts +6 -28
  88. package/dist/types/modes/components/irc-sidebar.d.ts +1 -0
  89. package/dist/types/modes/components/iterm-pet-transport.d.ts +122 -0
  90. package/dist/types/modes/components/oauth-selector.d.ts +10 -4
  91. package/dist/types/modes/components/pet-capability.d.ts +7 -21
  92. package/dist/types/modes/components/settings-selector.d.ts +5 -0
  93. package/dist/types/modes/components/status-line/gh.d.ts +6 -2
  94. package/dist/types/modes/controllers/extension-ui-controller.d.ts +1 -1
  95. package/dist/types/modes/controllers/selector-controller.d.ts +7 -8
  96. package/dist/types/modes/controllers/stt-controller.d.ts +1 -1
  97. package/dist/types/modes/interactive-mode.d.ts +1 -0
  98. package/dist/types/modes/theme/defaults/index.d.ts +118 -0
  99. package/dist/types/modes/types.d.ts +1 -0
  100. package/dist/types/modes/utils/injected-user-submission.d.ts +10 -0
  101. package/dist/types/runtime-mcp/config.d.ts +9 -0
  102. package/dist/types/runtime-mcp/manager.d.ts +26 -1
  103. package/dist/types/runtime-mcp/oauth-discovery.d.ts +4 -0
  104. package/dist/types/runtime-mcp/oauth-flow.d.ts +24 -1
  105. package/dist/types/runtime-mcp/pool-key.d.ts +2 -0
  106. package/dist/types/runtime-mcp/protocol.d.ts +278 -0
  107. package/dist/types/runtime-mcp/scope-config.d.ts +29 -0
  108. package/dist/types/runtime-mcp/tool-bridge.d.ts +15 -13
  109. package/dist/types/runtime-mcp/transports/http.d.ts +9 -0
  110. package/dist/types/runtime-mcp/types.d.ts +102 -10
  111. package/dist/types/sdk/acp/adapter.d.ts +26 -5
  112. package/dist/types/sdk/broker/broker.d.ts +3 -55
  113. package/dist/types/sdk/broker/lifecycle.d.ts +18 -12
  114. package/dist/types/sdk/broker/session-index.d.ts +14 -5
  115. package/dist/types/sdk/broker/startup-failure.d.ts +16 -1
  116. package/dist/types/sdk/bus/chat-daemon-control.d.ts +51 -1
  117. package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +4 -41
  118. package/dist/types/sdk/bus/config.d.ts +11 -0
  119. package/dist/types/sdk/bus/conversation-store.d.ts +0 -1
  120. package/dist/types/sdk/bus/daemon-paths.d.ts +6 -0
  121. package/dist/types/sdk/bus/discord-conversation.d.ts +2 -0
  122. package/dist/types/sdk/bus/discord-daemon.d.ts +17 -12
  123. package/dist/types/sdk/bus/existing-thread-readiness.d.ts +4 -34
  124. package/dist/types/sdk/bus/inbound-reaction-ordering.d.ts +61 -0
  125. package/dist/types/sdk/bus/index.d.ts +85 -99
  126. package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +29 -7
  127. package/dist/types/sdk/bus/managed-daemon.d.ts +2 -32
  128. package/dist/types/sdk/bus/notification-service.d.ts +52 -0
  129. package/dist/types/sdk/bus/operator-runtime.d.ts +1 -1
  130. package/dist/types/sdk/bus/prompt-reconciliation.d.ts +16 -5
  131. package/dist/types/sdk/bus/reconciliation-store.d.ts +113 -5
  132. package/dist/types/sdk/bus/session-control.d.ts +25 -1
  133. package/dist/types/sdk/bus/slack-conversation.d.ts +4 -0
  134. package/dist/types/sdk/bus/slack-daemon.d.ts +9 -17
  135. package/dist/types/sdk/bus/slack-live-provider.d.ts +3 -1
  136. package/dist/types/sdk/bus/slack-provider.d.ts +4 -0
  137. package/dist/types/sdk/bus/slack-thread-binding.d.ts +6 -40
  138. package/dist/types/sdk/bus/telegram-adoption-intent.d.ts +30 -104
  139. package/dist/types/sdk/bus/telegram-daemon-cli.d.ts +10 -0
  140. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +262 -19
  141. package/dist/types/sdk/bus/telegram-daemon-orphan-reap.d.ts +125 -0
  142. package/dist/types/sdk/bus/telegram-daemon-owner-registry.d.ts +22 -0
  143. package/dist/types/sdk/bus/telegram-daemon.d.ts +119 -310
  144. package/dist/types/sdk/bus/telegram-reference.d.ts +1 -47
  145. package/dist/types/sdk/bus/threaded-render.d.ts +1 -0
  146. package/dist/types/sdk/bus/topic-registry.d.ts +33 -17
  147. package/dist/types/sdk/cli/rows.d.ts +2 -11
  148. package/dist/types/sdk/cli/session-cli.d.ts +15 -25
  149. package/dist/types/sdk/client/client.d.ts +97 -1
  150. package/dist/types/sdk/host/control/dispatch.d.ts +0 -7
  151. package/dist/types/sdk/host/control/index.d.ts +1 -1
  152. package/dist/types/sdk/host/control/operations.d.ts +18 -5
  153. package/dist/types/sdk/host/control/runtime-gate.d.ts +19 -0
  154. package/dist/types/sdk/host/host.d.ts +15 -1
  155. package/dist/types/sdk/host/query/handlers.d.ts +5 -0
  156. package/dist/types/sdk/host/reverse-leases.d.ts +1 -1
  157. package/dist/types/sdk/host/session-runtime.d.ts +127 -7
  158. package/dist/types/sdk/host/types.d.ts +1 -1
  159. package/dist/types/sdk/host/websocket-transport.d.ts +1 -1
  160. package/dist/types/sdk/index.d.ts +2 -1
  161. package/dist/types/sdk/lifecycle/broker-client.d.ts +8 -0
  162. package/dist/types/sdk/lifecycle/client.d.ts +59 -0
  163. package/dist/types/sdk/lifecycle/index.d.ts +3 -0
  164. package/dist/types/sdk/lifecycle/service.d.ts +232 -0
  165. package/dist/types/sdk/mcp/server.d.ts +9 -6
  166. package/dist/types/sdk/prompt-deadline-lease.d.ts +43 -0
  167. package/dist/types/sdk/prompt-deadline-manager.d.ts +28 -0
  168. package/dist/types/sdk/prompt-status.d.ts +10 -3
  169. package/dist/types/sdk/protocol/operation-registry.d.ts +5 -0
  170. package/dist/types/sdk/receipt-state.d.ts +17 -0
  171. package/dist/types/sdk/reconciliation-extensions.d.ts +2 -0
  172. package/dist/types/sdk/router/index.d.ts +1 -0
  173. package/dist/types/sdk/router/session-router.d.ts +152 -0
  174. package/dist/types/sdk/session-list.d.ts +22 -0
  175. package/dist/types/sdk/session-reconnect.d.ts +43 -1
  176. package/dist/types/sdk/session.d.ts +34 -1
  177. package/dist/types/sdk/transport/serve-cli.d.ts +1 -4
  178. package/dist/types/session/account-inventory.d.ts +86 -0
  179. package/dist/types/session/agent-session.d.ts +145 -6
  180. package/dist/types/session/agent-storage.d.ts +10 -0
  181. package/dist/types/session/coordinator-tool-label.d.ts +28 -0
  182. package/dist/types/session/internal/managed-session-storage.d.ts +23 -4
  183. package/dist/types/session/messages.d.ts +1 -1
  184. package/dist/types/session/secure-token-file.d.ts +3 -0
  185. package/dist/types/session/session-manager.d.ts +47 -1
  186. package/dist/types/session/startup-auth-config.d.ts +44 -0
  187. package/dist/types/session/terminal-abort.d.ts +378 -0
  188. package/dist/types/session/yield-queue.d.ts +7 -0
  189. package/dist/types/session-import/claude.d.ts +26 -0
  190. package/dist/types/session-import/codex.d.ts +88 -0
  191. package/dist/types/session-import/command.d.ts +35 -0
  192. package/dist/types/session-import/detect.d.ts +22 -0
  193. package/dist/types/session-import/index.d.ts +7 -0
  194. package/dist/types/session-import/provider-codex.d.ts +22 -0
  195. package/dist/types/session-import/provider-service.d.ts +38 -0
  196. package/dist/types/session-import/redact.d.ts +23 -0
  197. package/dist/types/session-import/service.d.ts +47 -0
  198. package/dist/types/session-import/types.d.ts +120 -0
  199. package/dist/types/setup/paseo/check.d.ts +16 -0
  200. package/dist/types/setup/paseo/install-saga.d.ts +115 -0
  201. package/dist/types/setup/paseo/json-publisher.d.ts +76 -0
  202. package/dist/types/setup/paseo/orchestration-preferences.d.ts +24 -0
  203. package/dist/types/setup/paseo/paseo-ownership.d.ts +87 -0
  204. package/dist/types/setup/paseo/paseo-setup.d.ts +29 -0
  205. package/dist/types/setup/paseo/provider-config.d.ts +35 -0
  206. package/dist/types/setup/paseo/remove.d.ts +14 -0
  207. package/dist/types/setup/paseo/result-types.d.ts +59 -0
  208. package/dist/types/setup/paseo/setup-deps.d.ts +73 -0
  209. package/dist/types/setup/paseo/skills-bridge.d.ts +44 -0
  210. package/dist/types/skill-state/active-state.d.ts +5 -1
  211. package/dist/types/slash-commands/acp-builtins.d.ts +5 -1
  212. package/dist/types/slash-commands/builtin-registry.d.ts +2 -0
  213. package/dist/types/slash-commands/helpers/credential-switch.d.ts +12 -0
  214. package/dist/types/slash-commands/helpers/usage-report.d.ts +5 -6
  215. package/dist/types/slash-commands/types.d.ts +7 -1
  216. package/dist/types/task/executor.d.ts +10 -0
  217. package/dist/types/task/index.d.ts +3 -1
  218. package/dist/types/tools/ask-answer-registry.d.ts +6 -3
  219. package/dist/types/tools/bash-sleep-advisory.d.ts +14 -0
  220. package/dist/types/tools/bash.d.ts +2 -6
  221. package/dist/types/tools/browser/attach.d.ts +11 -0
  222. package/dist/types/tools/browser/launch.d.ts +20 -0
  223. package/dist/types/tools/browser/profile-discovery.d.ts +6 -0
  224. package/dist/types/tools/browser/render.d.ts +1 -0
  225. package/dist/types/tools/browser.d.ts +3 -1
  226. package/dist/types/tools/image-gen.d.ts +10 -2
  227. package/dist/types/tools/index.d.ts +8 -0
  228. package/dist/types/tools/monitor.d.ts +1 -1
  229. package/dist/types/tools/skill-discovery.d.ts +8 -1
  230. package/dist/types/tools/subagent.d.ts +2 -0
  231. package/dist/types/tools/ultragoal-ask-guard.d.ts +2 -2
  232. package/dist/types/utils/herdr-pane.d.ts +76 -0
  233. package/package.json +19 -9
  234. package/scripts/build-binary.ts +2 -1
  235. package/scripts/build-sdk-package-smoke.ts +2 -13
  236. package/scripts/capture-sticky-viewport-showcase.ts +0 -1
  237. package/scripts/compile-args.ts +2 -0
  238. package/scripts/generate-sdk-adapter-parity-manifest.ts +31 -16
  239. package/scripts/generate-sdk-operation-inventory.ts +28 -0
  240. package/scripts/generate-telegram-baseline-manifest.ts +1 -0
  241. package/scripts/generate-tool-catalog.ts +6 -4
  242. package/scripts/verify-gjc-sdk-canonicalization.ts +5 -39
  243. package/src/async/job-manager.ts +352 -17
  244. package/src/async/support.ts +25 -0
  245. package/src/autoresearch/dashboard.ts +28 -13
  246. package/src/capability/index.ts +3 -1
  247. package/src/capability/mcp.ts +6 -0
  248. package/src/capability/types.ts +6 -0
  249. package/src/cli/accounts-cli.ts +395 -0
  250. package/src/cli/args.ts +23 -0
  251. package/src/cli/auth-broker-cli.ts +136 -66
  252. package/src/cli/auth-gateway-cli.ts +94 -70
  253. package/src/cli/config-cli.ts +27 -2
  254. package/src/cli/crash-cli.ts +78 -0
  255. package/src/cli/customize-doctor.ts +1605 -0
  256. package/src/cli/daemon-cli.ts +12 -3
  257. package/src/cli/fast-help.ts +1 -0
  258. package/src/cli/mcp-cli.ts +128 -60
  259. package/src/cli/notify-cli.ts +8 -14
  260. package/src/cli/root-flags.ts +8 -0
  261. package/src/cli/setup-cli.ts +145 -0
  262. package/src/cli/skills-cli.ts +38 -2
  263. package/src/cli/update-cli.ts +167 -12
  264. package/src/cli.ts +4 -0
  265. package/src/commands/accounts.ts +71 -0
  266. package/src/commands/crash.ts +35 -0
  267. package/src/commands/customize.ts +84 -0
  268. package/src/commands/daemon.ts +2 -2
  269. package/src/commands/deep-interview.ts +2 -0
  270. package/src/commands/launch.ts +1 -0
  271. package/src/commands/mcp.ts +12 -7
  272. package/src/commands/ralplan.ts +2 -0
  273. package/src/commands/sdk.ts +65 -32
  274. package/src/commands/setup.ts +5 -0
  275. package/src/commands/skills.ts +14 -4
  276. package/src/commands/ultragoal.ts +10 -1
  277. package/src/commands/update.ts +26 -15
  278. package/src/config/atomic-yaml-patch-worker.ts +57 -0
  279. package/src/config/atomic-yaml-patch.ts +769 -29
  280. package/src/config/config-schema-version.ts +10 -0
  281. package/src/config/file-lock.ts +70 -1
  282. package/src/config/mcp-schema.json +52 -14
  283. package/src/config/model-profile-activation.ts +23 -2
  284. package/src/config/model-profiles.ts +88 -21
  285. package/src/config/model-registry.ts +147 -21
  286. package/src/config/models-config-schema.ts +1 -1
  287. package/src/config/settings-schema.ts +77 -7
  288. package/src/config/settings.ts +4038 -199
  289. package/src/config/skill-settings-defaults.ts +41 -3
  290. package/src/config/task-delegation.ts +87 -0
  291. package/src/config/update-channel.ts +23 -0
  292. package/src/coordinator-mcp/server.ts +377 -308
  293. package/src/crash/index-store.ts +723 -0
  294. package/src/crash/nudge.ts +89 -0
  295. package/src/crash/record-loader.ts +149 -0
  296. package/src/crash/report.ts +551 -0
  297. package/src/crash/sanitize.ts +129 -0
  298. package/src/cursor.ts +36 -10
  299. package/src/customization/import.ts +946 -0
  300. package/src/customization/index.ts +4 -0
  301. package/src/customization/inventory.ts +335 -0
  302. package/src/customization/mutations.ts +141 -0
  303. package/src/customization/types.ts +223 -0
  304. package/src/daemon/control-types.ts +8 -1
  305. package/src/daemon/operator-contract.ts +6 -6
  306. package/src/defaults/gjc/extensions/grok-cli-vendor/src/models/catalog.ts +31 -6
  307. package/src/defaults/gjc/skills/deep-interview/SKILL.md +11 -22
  308. package/src/defaults/gjc/skills/ralplan/SKILL.md +36 -23
  309. package/src/defaults/gjc/skills/ultragoal/SKILL.md +16 -0
  310. package/src/discovery/claude-hooks.ts +38 -0
  311. package/src/discovery/claude.ts +142 -209
  312. package/src/discovery/codex-hooks.ts +38 -0
  313. package/src/discovery/codex.ts +132 -198
  314. package/src/discovery/helpers.ts +8 -1
  315. package/src/discovery/index.ts +2 -0
  316. package/src/discovery/mcp-compat.ts +234 -0
  317. package/src/discovery/mcp-json.ts +6 -0
  318. package/src/edit/renderer.ts +40 -0
  319. package/src/edit/streaming.ts +4 -2
  320. package/src/exec/bash-executor.ts +24 -20
  321. package/src/export/html/index.ts +51 -2
  322. package/src/extensibility/extensions/loader.ts +9 -1
  323. package/src/extensibility/extensions/runner.ts +17 -4
  324. package/src/extensibility/extensions/types.ts +31 -6
  325. package/src/extensibility/gjc-plugins/constrained-hooks.ts +33 -0
  326. package/src/extensibility/gjc-plugins/installer.ts +9 -5
  327. package/src/extensibility/gjc-plugins/observability.ts +8 -2
  328. package/src/extensibility/gjc-plugins/registry.ts +13 -2
  329. package/src/extensibility/gjc-plugins/runtime-adapters.ts +3 -1
  330. package/src/extensibility/gjc-plugins/schema.ts +222 -39
  331. package/src/extensibility/hooks/loader.ts +154 -10
  332. package/src/extensibility/runtime-skill-discovery.ts +257 -60
  333. package/src/extensibility/skill-management.ts +368 -0
  334. package/src/extensibility/skills.ts +52 -16
  335. package/src/gjc-runtime/deep-interview-runtime.ts +45 -61
  336. package/src/gjc-runtime/launch-worktree.ts +56 -2
  337. package/src/gjc-runtime/linux-proc.ts +7 -1
  338. package/src/gjc-runtime/ralplan-runtime.ts +100 -164
  339. package/src/gjc-runtime/session-state-lock.ts +992 -0
  340. package/src/gjc-runtime/session-state-sidecar.ts +644 -142
  341. package/src/gjc-runtime/state-writer.ts +39 -14
  342. package/src/gjc-runtime/tmux-owner-isolation.ts +5 -4
  343. package/src/gjc-runtime/ultragoal-guard.ts +11 -4
  344. package/src/gjc-runtime/ultragoal-runtime.ts +44 -41
  345. package/src/gjc-runtime/workflow-settings.ts +596 -0
  346. package/src/goals/tools/goal-tool.ts +6 -1
  347. package/src/hooks/events.ts +291 -0
  348. package/src/hooks/native-skill-hook.ts +4 -0
  349. package/src/hooks/normalize.ts +369 -0
  350. package/src/hooks/skill-state.ts +165 -46
  351. package/src/internal-urls/docs-index.generated.ts +41 -32
  352. package/src/main.ts +36 -5
  353. package/src/migrate/mcp-mapper.ts +25 -2
  354. package/src/modes/acp/abort-scope.ts +29 -0
  355. package/src/modes/acp/acp-agent.ts +423 -98
  356. package/src/modes/components/assistant-message.ts +6 -1
  357. package/src/modes/components/chrome.ts +4 -3
  358. package/src/modes/components/customization/customization-dashboard.ts +443 -0
  359. package/src/modes/components/customization/import-wizard.ts +372 -0
  360. package/src/modes/components/customization/index.ts +1 -0
  361. package/src/modes/components/dynamic-theme-text.ts +22 -0
  362. package/src/modes/components/gajae-pet-widget.ts +607 -193
  363. package/src/modes/components/irc-sidebar.ts +11 -0
  364. package/src/modes/components/iterm-pet-transport.ts +585 -0
  365. package/src/modes/components/model-selector.ts +1 -6
  366. package/src/modes/components/oauth-selector.ts +277 -86
  367. package/src/modes/components/pet-capability.ts +35 -31
  368. package/src/modes/components/settings-selector.ts +29 -5
  369. package/src/modes/components/status-line/gh.ts +45 -1
  370. package/src/modes/components/status-line/segments.ts +19 -4
  371. package/src/modes/components/tool-status-header.ts +13 -3
  372. package/src/modes/controllers/command-controller.ts +20 -8
  373. package/src/modes/controllers/extension-ui-controller.ts +56 -257
  374. package/src/modes/controllers/input-controller.ts +10 -0
  375. package/src/modes/controllers/runtime-mcp-command-controller.ts +16 -3
  376. package/src/modes/controllers/selector-controller.ts +238 -77
  377. package/src/modes/controllers/stt-controller.ts +3 -3
  378. package/src/modes/interactive-mode.ts +88 -16
  379. package/src/modes/print-mode.ts +35 -6
  380. package/src/modes/runtime-init.ts +21 -68
  381. package/src/modes/theme/defaults/index.ts +2 -0
  382. package/src/modes/theme/defaults/ouroboros.json +118 -0
  383. package/src/modes/types.ts +1 -0
  384. package/src/modes/utils/injected-user-submission.ts +25 -0
  385. package/src/modes/utils/terminal-bell.ts +15 -1
  386. package/src/prompts/agent-fragments/ralplan-persistence.md +1 -1
  387. package/src/prompts/agent-fragments/restricted-bash.md +1 -1
  388. package/src/prompts/agents/critic.md +1 -1
  389. package/src/prompts/system/rlm-research.md +1 -1
  390. package/src/prompts/system/system-prompt.md +0 -2
  391. package/src/prompts/tools/bash.md +7 -1
  392. package/src/prompts/tools/browser.md +1 -1
  393. package/src/prompts/tools/cron.md +6 -6
  394. package/src/prompts/tools/read.md +0 -2
  395. package/src/prompts/tools/skill-discovery.md +4 -2
  396. package/src/runtime-mcp/client.ts +427 -23
  397. package/src/runtime-mcp/config.ts +37 -5
  398. package/src/runtime-mcp/manager-pool.test.ts +56 -0
  399. package/src/runtime-mcp/manager.ts +52 -2
  400. package/src/runtime-mcp/oauth-discovery.ts +13 -0
  401. package/src/runtime-mcp/oauth-flow.ts +46 -1
  402. package/src/runtime-mcp/pool-key.ts +5 -1
  403. package/src/runtime-mcp/pool.test.ts +9 -0
  404. package/src/runtime-mcp/protocol.test.ts +353 -0
  405. package/src/runtime-mcp/protocol.ts +624 -0
  406. package/src/runtime-mcp/scope-config.ts +78 -0
  407. package/src/runtime-mcp/tool-bridge.ts +44 -10
  408. package/src/runtime-mcp/transports/http.ts +84 -13
  409. package/src/runtime-mcp/types.ts +123 -12
  410. package/src/sdk/acp/adapter.ts +328 -97
  411. package/src/sdk/broker/broker.ts +160 -741
  412. package/src/sdk/broker/ensure.ts +9 -1
  413. package/src/sdk/broker/lifecycle.ts +510 -116
  414. package/src/sdk/broker/operation-receipt-ledger.ts +11 -2
  415. package/src/sdk/broker/process-incarnation.ts +19 -0
  416. package/src/sdk/broker/session-index.ts +516 -117
  417. package/src/sdk/broker/startup-failure.ts +28 -5
  418. package/src/sdk/broker/transport.ts +1 -13
  419. package/src/sdk/bus/chat-daemon-cli.ts +4 -2
  420. package/src/sdk/bus/chat-daemon-control.ts +67 -6
  421. package/src/sdk/bus/chat-daemon-runtime.ts +183 -859
  422. package/src/sdk/bus/config.ts +13 -0
  423. package/src/sdk/bus/conversation-store.ts +59 -171
  424. package/src/sdk/bus/daemon-paths.ts +20 -0
  425. package/src/sdk/bus/discord-conversation.ts +2 -0
  426. package/src/sdk/bus/discord-daemon.ts +524 -126
  427. package/src/sdk/bus/discord-live-provider.ts +206 -79
  428. package/src/sdk/bus/existing-thread-readiness.ts +4 -97
  429. package/src/sdk/bus/inbound-reaction-ordering.ts +122 -0
  430. package/src/sdk/bus/index.ts +2480 -456
  431. package/src/sdk/bus/kind-aware-reconciliation.ts +204 -34
  432. package/src/sdk/bus/lifecycle-commands.ts +2 -2
  433. package/src/sdk/bus/managed-daemon.ts +2 -145
  434. package/src/sdk/bus/notification-service.ts +196 -0
  435. package/src/sdk/bus/operator-runtime.ts +1 -1
  436. package/src/sdk/bus/prompt-reconciliation.ts +24 -15
  437. package/src/sdk/bus/reconciliation-store.ts +553 -24
  438. package/src/sdk/bus/session-control.ts +49 -3
  439. package/src/sdk/bus/slack-conversation.ts +4 -0
  440. package/src/sdk/bus/slack-daemon.ts +733 -134
  441. package/src/sdk/bus/slack-live-provider.ts +65 -15
  442. package/src/sdk/bus/slack-provider.ts +4 -0
  443. package/src/sdk/bus/slack-thread-binding.ts +9 -104
  444. package/src/sdk/bus/telegram-adoption-intent.ts +299 -209
  445. package/src/sdk/bus/telegram-daemon-cli.ts +194 -7
  446. package/src/sdk/bus/telegram-daemon-contract.ts +265 -19
  447. package/src/sdk/bus/telegram-daemon-control.ts +3 -13
  448. package/src/sdk/bus/telegram-daemon-orphan-reap.ts +498 -0
  449. package/src/sdk/bus/telegram-daemon-owner-registry.ts +176 -0
  450. package/src/sdk/bus/telegram-daemon.ts +2552 -2280
  451. package/src/sdk/bus/telegram-reference.ts +1 -226
  452. package/src/sdk/bus/telegram-setup.ts +2 -2
  453. package/src/sdk/bus/threaded-render.ts +1 -0
  454. package/src/sdk/bus/topic-registry.ts +279 -146
  455. package/src/sdk/cli/rows.ts +2 -35
  456. package/src/sdk/cli/session-cli.ts +776 -700
  457. package/src/sdk/client/client.ts +892 -1
  458. package/src/sdk/host/control/dispatch.ts +93 -58
  459. package/src/sdk/host/control/index.ts +1 -1
  460. package/src/sdk/host/control/operations.ts +18 -10
  461. package/src/sdk/host/control/runtime-gate.ts +40 -0
  462. package/src/sdk/host/host.ts +63 -12
  463. package/src/sdk/host/query/handlers.ts +66 -7
  464. package/src/sdk/host/reverse-leases.ts +2 -2
  465. package/src/sdk/host/sdk-surface-parity.test.ts +1 -1
  466. package/src/sdk/host/session-runtime.test.ts +2787 -34
  467. package/src/sdk/host/session-runtime.ts +1489 -101
  468. package/src/sdk/host/surface-policy.ts +12 -8
  469. package/src/sdk/host/types.ts +1 -1
  470. package/src/sdk/host/websocket-transport.lifecycle.test.ts +31 -59
  471. package/src/sdk/host/websocket-transport.ts +85 -50
  472. package/src/sdk/index.ts +2 -1
  473. package/src/sdk/lifecycle/broker-client.ts +53 -0
  474. package/src/sdk/lifecycle/client.ts +234 -0
  475. package/src/sdk/lifecycle/index.ts +3 -0
  476. package/src/sdk/{bus/recent-activity.ts → lifecycle/recent-sessions.ts} +5 -2
  477. package/src/sdk/lifecycle/service.ts +720 -0
  478. package/src/sdk/mcp/server.ts +226 -188
  479. package/src/sdk/prompt-deadline-lease.ts +55 -0
  480. package/src/sdk/prompt-deadline-manager.ts +148 -0
  481. package/src/sdk/prompt-status.ts +11 -3
  482. package/src/sdk/protocol/operation-inventory.generated.json +272 -129
  483. package/src/sdk/protocol/operation-registry.ts +71 -8
  484. package/src/sdk/receipt-state.ts +43 -0
  485. package/src/sdk/reconciliation-extensions.ts +14 -0
  486. package/src/sdk/router/index.ts +1 -0
  487. package/src/sdk/router/session-router.ts +1658 -0
  488. package/src/sdk/session-list.ts +93 -0
  489. package/src/sdk/session-reconnect.ts +45 -1
  490. package/src/sdk/session.ts +716 -120
  491. package/src/sdk/transport/serve-cli.ts +18 -34
  492. package/src/session/account-inventory.ts +603 -0
  493. package/src/session/agent-session.ts +2873 -559
  494. package/src/session/agent-storage.ts +35 -0
  495. package/src/session/blob-store.ts +32 -1
  496. package/src/session/coordinator-tool-label.ts +40 -0
  497. package/src/session/internal/managed-session-scope.ts +4 -0
  498. package/src/session/internal/managed-session-storage.ts +199 -31
  499. package/src/session/messages.ts +1 -1
  500. package/src/session/secure-token-file.ts +80 -0
  501. package/src/session/session-manager.ts +757 -57
  502. package/src/session/session-storage.ts +25 -16
  503. package/src/session/startup-auth-config.ts +297 -0
  504. package/src/session/terminal-abort.ts +1253 -0
  505. package/src/session/yield-queue.ts +57 -15
  506. package/src/session-import/claude.ts +334 -0
  507. package/src/session-import/codex.ts +1033 -0
  508. package/src/session-import/command.ts +77 -0
  509. package/src/session-import/detect.ts +133 -0
  510. package/src/session-import/index.ts +7 -0
  511. package/src/session-import/provider-codex.ts +327 -0
  512. package/src/session-import/provider-service.ts +457 -0
  513. package/src/session-import/redact.ts +128 -0
  514. package/src/session-import/service.ts +1264 -0
  515. package/src/session-import/types.ts +148 -0
  516. package/src/setup/paseo/check.ts +213 -0
  517. package/src/setup/paseo/install-saga.ts +293 -0
  518. package/src/setup/paseo/json-publisher.ts +263 -0
  519. package/src/setup/paseo/orchestration-preferences.ts +86 -0
  520. package/src/setup/paseo/paseo-ownership.ts +224 -0
  521. package/src/setup/paseo/paseo-setup.ts +253 -0
  522. package/src/setup/paseo/provider-config.ts +139 -0
  523. package/src/setup/paseo/remove.ts +183 -0
  524. package/src/setup/paseo/result-types.ts +79 -0
  525. package/src/setup/paseo/setup-deps.ts +175 -0
  526. package/src/setup/paseo/skills-bridge.ts +260 -0
  527. package/src/skill-state/active-state.ts +21 -11
  528. package/src/slash-commands/acp-builtins.ts +9 -1
  529. package/src/slash-commands/builtin-registry.ts +117 -19
  530. package/src/slash-commands/helpers/credential-switch.ts +143 -0
  531. package/src/slash-commands/helpers/mcp.ts +9 -3
  532. package/src/slash-commands/helpers/usage-report.ts +61 -56
  533. package/src/slash-commands/types.ts +7 -2
  534. package/src/task/executor.ts +30 -11
  535. package/src/task/index.ts +66 -7
  536. package/src/task/render.ts +23 -9
  537. package/src/tools/ask-answer-registry.ts +23 -7
  538. package/src/tools/ask.ts +8 -4
  539. package/src/tools/bash-sleep-advisory.ts +115 -0
  540. package/src/tools/bash.ts +98 -18
  541. package/src/tools/browser/attach.ts +71 -3
  542. package/src/tools/browser/launch.ts +86 -13
  543. package/src/tools/browser/profile-discovery.ts +57 -7
  544. package/src/tools/browser/render.ts +8 -1
  545. package/src/tools/browser.ts +130 -21
  546. package/src/tools/computer.enforcement.test.ts +1 -1
  547. package/src/tools/computer.ts +3 -2
  548. package/src/tools/cron.ts +12 -1
  549. package/src/tools/image-gen.ts +349 -142
  550. package/src/tools/index.ts +8 -0
  551. package/src/tools/job.ts +33 -6
  552. package/src/tools/monitor.ts +41 -2
  553. package/src/tools/skill-discovery.ts +21 -29
  554. package/src/tools/subagent.ts +142 -24
  555. package/src/tools/todo-contract.ts +55 -3
  556. package/src/tools/todo-write.ts +4 -3
  557. package/src/tools/tool-catalog.generated.ts +6 -6
  558. package/src/tools/ultragoal-ask-guard.ts +10 -3
  559. package/src/utils/herdr-pane.ts +345 -0
  560. package/src/utils/title-generator.ts +2 -0
  561. package/src/web/scrapers/index.ts +6 -4
  562. package/dist/types/cli/malloc-env-guard.test.d.ts +0 -1
  563. package/dist/types/defaults/gjc-defaults.test.d.ts +0 -1
  564. package/dist/types/memory-backend/lazy-loading.test.d.ts +0 -1
  565. package/dist/types/runtime/boot-ordering.test.d.ts +0 -1
  566. package/dist/types/runtime/lazy-service.test.d.ts +0 -1
  567. package/dist/types/runtime/network-prewarm-service.test.d.ts +0 -1
  568. package/dist/types/runtime/workspace-tree-service.test.d.ts +0 -1
  569. package/dist/types/runtime-mcp/config.test.d.ts +0 -1
  570. package/dist/types/runtime-mcp/http.test.d.ts +0 -1
  571. package/dist/types/runtime-mcp/manager-pool.test.d.ts +0 -1
  572. package/dist/types/runtime-mcp/pool-key.test.d.ts +0 -1
  573. package/dist/types/runtime-mcp/pool.test.d.ts +0 -1
  574. package/dist/types/sdk/bus/lifecycle-control-runtime.d.ts +0 -117
  575. package/dist/types/sdk/bus/lifecycle-orchestrator.d.ts +0 -141
  576. package/dist/types/sdk/bus/telegram-cli.d.ts +0 -31
  577. package/dist/types/sdk/elevation/allowlist.d.ts +0 -20
  578. package/dist/types/sdk/elevation/audit.d.ts +0 -93
  579. package/dist/types/sdk/elevation/capability.d.ts +0 -3
  580. package/dist/types/sdk/elevation/digest.d.ts +0 -72
  581. package/dist/types/sdk/elevation/dispatch-receipt.d.ts +0 -85
  582. package/dist/types/sdk/elevation/grant-ledger.d.ts +0 -163
  583. package/dist/types/sdk/elevation/owner.d.ts +0 -48
  584. package/dist/types/sdk/host/import-graph.test.d.ts +0 -1
  585. package/dist/types/sdk/host/sdk-surface-parity.test.d.ts +0 -1
  586. package/dist/types/sdk/host/session-runtime.test.d.ts +0 -1
  587. package/dist/types/sdk/host/websocket-transport.lifecycle.test.d.ts +0 -1
  588. package/dist/types/session/auth-broker-config.d.ts +0 -13
  589. package/dist/types/session/heap-eviction-artifacts.test.d.ts +0 -1
  590. package/dist/types/skills/skills.test.d.ts +0 -1
  591. package/dist/types/slash-commands/notify-command.test.d.ts +0 -1
  592. package/dist/types/task/token-log.test.d.ts +0 -1
  593. package/dist/types/tools/computer.enforcement.test.d.ts +0 -1
  594. package/dist/types/tools/descriptors.test.d.ts +0 -1
  595. package/scripts/g005-daemon-smoke.ts +0 -180
  596. package/scripts/g011-daemon-path-smoke.ts +0 -153
  597. package/src/sdk/bus/lifecycle-control-runtime.ts +0 -1733
  598. package/src/sdk/bus/lifecycle-orchestrator.ts +0 -489
  599. package/src/sdk/bus/telegram-cli.ts +0 -212
  600. package/src/sdk/elevation/allowlist.ts +0 -54
  601. package/src/sdk/elevation/audit.ts +0 -208
  602. package/src/sdk/elevation/capability.ts +0 -41
  603. package/src/sdk/elevation/digest.ts +0 -129
  604. package/src/sdk/elevation/dispatch-receipt.ts +0 -184
  605. package/src/sdk/elevation/grant-ledger.ts +0 -1142
  606. package/src/sdk/elevation/owner.ts +0 -109
  607. package/src/session/auth-broker-config.ts +0 -109
  608. /package/dist/types/{ai-core-import-gate.test.d.ts → discovery/claude-hooks.d.ts} +0 -0
  609. /package/dist/types/{cli/fixture-report.test.d.ts → discovery/codex-hooks.d.ts} +0 -0
  610. /package/dist/types/sdk/{bus/recent-activity.d.ts → lifecycle/recent-sessions.d.ts} +0 -0
@@ -3,9 +3,9 @@ import {
3
3
  DEFAULT_MODEL_SELECTION_RECOVERY_MESSAGE,
4
4
  parseDefaultModelSelectionRecovery,
5
5
  } from "../../../session/default-model-selection";
6
- import { isElevationAllowlisted } from "../../elevation/allowlist";
7
6
  import { OPERATIONS, type Operation } from "../../protocol/operation-registry";
8
7
  import type { ControlInput, ControlSurface, ControlValue } from "./operations";
8
+ import { brokerRuntimeCloseCapability, hasBrokerRuntimeCloseCapability } from "./runtime-gate";
9
9
 
10
10
  export interface ControlRequest {
11
11
  id: string;
@@ -14,8 +14,6 @@ export interface ControlRequest {
14
14
  expectedRevision?: string;
15
15
  idempotencyKey?: string;
16
16
  confirm?: boolean;
17
- /** Top-level elevation claim selector, preserved from the control frame. */
18
- elevationRequestId?: string;
19
17
  }
20
18
 
21
19
  export type ControlErrorCode = string;
@@ -69,8 +67,21 @@ const SHARED_ERROR_CODES = new Set([
69
67
  "cursor_expired",
70
68
  "event_gap",
71
69
  "unavailable",
70
+ "operation_prohibited",
72
71
  "internal",
73
72
  ]);
73
+
74
+ /** Lifecycle mutations must enter through the Broker-backed lifecycle service. */
75
+ const BROKER_LIFECYCLE_CONTROL_OPERATIONS = new Set([
76
+ "session.new",
77
+ "session.fork",
78
+ "session.resume",
79
+ "session.switch",
80
+ "session.branch",
81
+ "session.handoff",
82
+ "session.close",
83
+ "session.delete",
84
+ ]);
74
85
  const IDEMPOTENCY_TTL_MS = 15 * 60 * 1_000;
75
86
  const MAX_IDEMPOTENCY_ENTRIES = 256;
76
87
 
@@ -108,11 +119,7 @@ function failure(
108
119
  function isInput(value: unknown): value is ControlInput {
109
120
  return typeof value === "object" && value !== null && !Array.isArray(value);
110
121
  }
111
- /**
112
- * Build the typed control request from a wire frame. Every runtime transport
113
- * mapper uses this helper so the top-level elevation claim selector cannot
114
- * drift between callsites.
115
- */
122
+
116
123
  export function controlRequestFromFrame(frame: Record<string, unknown>): ControlRequest {
117
124
  return {
118
125
  id: typeof frame.id === "string" ? frame.id : "",
@@ -121,7 +128,6 @@ export function controlRequestFromFrame(frame: Record<string, unknown>): Control
121
128
  expectedRevision: typeof frame.expectedRevision === "string" ? frame.expectedRevision : undefined,
122
129
  idempotencyKey: typeof frame.idempotencyKey === "string" ? frame.idempotencyKey : undefined,
123
130
  confirm: frame.confirm === true,
124
- elevationRequestId: typeof frame.elevationRequestId === "string" ? frame.elevationRequestId : undefined,
125
131
  };
126
132
  }
127
133
 
@@ -142,47 +148,95 @@ function inputHash(input: unknown): string {
142
148
  .update(JSON.stringify(canonicalize(input)))
143
149
  .digest("hex");
144
150
  }
151
+ /**
152
+ * Normalize a WELL-FORMED terminal abort input for the idempotency hash:
153
+ * omitted scope defaults to "turn", so `{mode:"terminal"}` and
154
+ * `{mode:"terminal", scope:"turn"}` share one idempotency key (the durable
155
+ * terminal-scope replay hashes the same normalized payload). Malformed
156
+ * inputs (unknown fields, invalid mode/scope) are left raw so they are
157
+ * rejected downstream and never collide with a valid input's key.
158
+ */
159
+ function normalizeTerminalAbortInputForHash(input: unknown): unknown {
160
+ if (typeof input !== "object" || input === null) return input;
161
+ const record = input as Record<string, unknown>;
162
+ if (record.mode !== "terminal") return input;
163
+ for (const key of Object.keys(record)) if (!TERMINAL_ABORT_FIELDS.has(key)) return input;
164
+ const scope = record.scope;
165
+ if (scope !== undefined && scope !== "turn" && scope !== "owned") return input;
166
+ return { mode: "terminal", scope: scope === undefined ? "turn" : scope };
167
+ }
145
168
 
146
169
  function text(input: ControlInput, key = "text"): string {
147
170
  return input[key] as string;
148
171
  }
149
172
 
173
+ const TERMINAL_ABORT_FIELDS = new Set(["mode", "scope"]);
174
+
175
+ function invalidInput(message: string): never {
176
+ throw new TypedControlError("invalid_input", message);
177
+ }
178
+
179
+ /**
180
+ * C04 `turn.abort` dispatch.
181
+ *
182
+ * Legacy behavior (omitted mode or `mode:"turn"`) is preserved verbatim: the
183
+ * input is dropped and the ordinary argument-less `surface.abort()` runs.
184
+ *
185
+ * Terminal mode (`mode:"terminal"`) is validated strictly and side-effect-free
186
+ * before any surface call: only `mode`/`scope` fields are accepted, `scope`
187
+ * must be `"turn"` or `"owned"` (default `"turn"`), and a nonempty idempotency
188
+ * key of at most 128 UTF-8 bytes is required on the request envelope. Terminal
189
+ * semantics (see the approved plan): stop the root worker's current turn and
190
+ * block only its own continuation routes; left-running owned work keeps
191
+ * running and its completions are delivered normally so the root worker can
192
+ * resume with a fresh attempt — owned delivery is NOT suppressed.
193
+ */
194
+ function invokeAbort(surface: ControlSurface, input: ControlInput, idempotencyKey: string | undefined): ControlValue {
195
+ const mode = input.mode === undefined ? "turn" : input.mode;
196
+ if (mode === "turn") return surface.abort();
197
+ if (mode !== "terminal") invalidInput('turn.abort mode must be "turn" or "terminal".');
198
+ for (const key of Object.keys(input))
199
+ if (!TERMINAL_ABORT_FIELDS.has(key)) invalidInput(`Unknown turn.abort terminal field: ${key}`);
200
+ const scope = input.scope === undefined ? "turn" : input.scope;
201
+ if (scope !== "turn" && scope !== "owned") invalidInput('turn.abort terminal scope must be "turn" or "owned".');
202
+ if (typeof idempotencyKey !== "string" || idempotencyKey.length === 0)
203
+ invalidInput("terminal abort requires a nonempty idempotency key.");
204
+ if (new TextEncoder().encode(idempotencyKey).length > 128)
205
+ invalidInput("terminal abort idempotency key must be at most 128 UTF-8 bytes.");
206
+ if (!surface.abortTerminal) invalidInput("terminal abort is not supported by this surface.");
207
+ return surface.abortTerminal({ mode: "terminal", scope }, idempotencyKey);
208
+ }
150
209
  function invoke(
151
210
  surface: ControlSurface,
152
211
  operation: string,
153
212
  input: ControlInput,
154
213
  confirm: boolean | undefined,
155
214
  idempotencyKey: string | undefined,
156
- elevationRequestId: string | undefined,
157
215
  ): Promise<ControlValue> | ControlValue {
158
216
  switch (operation) {
159
217
  case "turn.prompt":
160
218
  return surface.prompt(text(input), input.images, input.clientRef as string | undefined);
161
219
  case "turn.steer":
162
- return surface.steer(text(input));
220
+ return surface.steer(text(input), typeof input.clientRef === "string" ? input.clientRef : undefined);
163
221
  case "turn.follow_up":
164
222
  return surface.followUp(text(input));
165
223
  case "turn.abort":
166
- return surface.abort();
224
+ return invokeAbort(surface, input, idempotencyKey);
167
225
  case "turn.abort_and_prompt":
168
226
  return surface.abortAndPrompt(text(input));
169
227
  case "ask.answer":
170
228
  return surface.answerAsk(text(input, "id"), input.answer);
171
229
  case "workflow.gate_answer":
230
+ if (idempotencyKey === undefined)
231
+ return surface.answerGate(text(input, "id"), input.response, input.expectedSessionId as string | undefined);
172
232
  return surface.answerGate(
173
233
  text(input, "id"),
174
234
  input.response,
175
235
  input.expectedSessionId as string | undefined,
176
236
  idempotencyKey,
177
- elevationRequestId,
178
237
  );
179
238
  case "workflow.plan_approve":
180
- return surface.approvePlan(
181
- text(input, "id"),
182
- input.choice,
183
- input.expectedSessionId as string | undefined,
184
- elevationRequestId,
185
- );
239
+ return surface.approvePlan(text(input, "id"), input.choice, input.expectedSessionId as string | undefined);
186
240
  case "skill.invoke":
187
241
  return surface.invokeSkill(
188
242
  text(input, "name"),
@@ -225,22 +279,10 @@ function invoke(
225
279
  return surface.executeBash(text(input, "cmd"));
226
280
  case "bash.abort":
227
281
  return surface.abortBash();
228
- case "session.new":
229
- return surface.newSession();
230
- case "session.fork":
231
- return surface.forkSession();
232
- case "session.resume":
233
- return surface.resumeSession(text(input, "id"));
234
282
  case "session.close":
235
- return surface.closeSession();
236
- case "session.switch":
237
- return surface.switchSession(text(input, "id"));
238
- case "session.branch":
239
- return surface.branchSession(text(input, "entryId"));
283
+ return surface.closeSession(brokerRuntimeCloseCapability(input));
240
284
  case "session.rename":
241
285
  return surface.renameSession(text(input, "name"));
242
- case "session.handoff":
243
- return surface.handoffSession(input.target);
244
286
  case "session.export_html":
245
287
  return surface.exportHtml();
246
288
  case "config.patch":
@@ -270,8 +312,6 @@ function invoke(
270
312
  return surface.setExtensionEnabled(text(input, "id"), input.on as boolean);
271
313
  case "context.clear":
272
314
  return surface.clearContext(confirm === true);
273
- case "session.delete":
274
- return surface.deleteSession(text(input, "id"), confirm === true);
275
315
  case "session.cwd.move":
276
316
  return surface.moveCwd(text(input, "path"));
277
317
  case "retry.last":
@@ -329,7 +369,6 @@ async function execute(surface: ControlSurface, row: Operation, request: Control
329
369
  request.input as ControlInput,
330
370
  request.confirm,
331
371
  request.idempotencyKey,
332
- request.elevationRequestId,
333
372
  ),
334
373
  };
335
374
  } catch (error) {
@@ -364,7 +403,11 @@ function idempotent(
364
403
  const now = Date.now();
365
404
  for (const [key, entry] of requests) if (entry.expiresAt <= now) requests.delete(key);
366
405
  const key = `${row.sdkId}\u0000${request.idempotencyKey}`;
367
- const hash = inputHash(request.input);
406
+ // Terminal abort normalizes the omitted scope BEFORE hashing so the
407
+ // defaulted and explicit shapes share one idempotency key (and reach the
408
+ // durable terminal-scope replay on eviction); malformed inputs stay raw.
409
+ const hashInput = row.sdkId === "turn.abort" ? normalizeTerminalAbortInputForHash(request.input) : request.input;
410
+ const hash = inputHash(hashInput);
368
411
  const existing = requests.get(key);
369
412
  if (existing) {
370
413
  requests.delete(key);
@@ -400,33 +443,25 @@ export function dispatchControl(
400
443
  return Promise.resolve(
401
444
  failure(request.id, "unknown_operation", `Unknown control operation: ${request.operation}.`),
402
445
  );
403
- if (surface.installedOperations instanceof Set && !surface.installedOperations.has(row.sdkId))
446
+ const brokerCloseAuthorized = row.sdkId === "session.close" && hasBrokerRuntimeCloseCapability(request.input);
447
+ if (BROKER_LIFECYCLE_CONTROL_OPERATIONS.has(row.sdkId) && !brokerCloseAuthorized)
448
+ return Promise.resolve(
449
+ failure(
450
+ request.id,
451
+ "operation_prohibited",
452
+ `${request.operation} is available only through the Broker lifecycle service.`,
453
+ ),
454
+ );
455
+ if (
456
+ !brokerCloseAuthorized &&
457
+ surface.installedOperations instanceof Set &&
458
+ !surface.installedOperations.has(row.sdkId)
459
+ )
404
460
  return Promise.resolve(
405
461
  failure(request.id, "operation_not_session_owned", `${request.operation} is not installed for this session.`),
406
462
  );
407
463
  if (!isInput(request.input))
408
464
  return Promise.resolve(failure(request.id, "invalid_input", "Control input must be an object."));
409
- const elevationEnabled =
410
- process.env.GJC_SDK_ELEVATION_ENABLED === "1" || process.env.GJC_SDK_ELEVATION_ENABLED === "true";
411
- const elevationAllowlisted = isElevationAllowlisted("control", row.sdkId);
412
- const elevationRequired = elevationEnabled && elevationAllowlisted;
413
- if (elevationRequired && request.elevationRequestId === undefined)
414
- return Promise.resolve(failure(request.id, "elevation_required", `${row.sdkId} requires an elevation grant.`));
415
- if (request.elevationRequestId !== undefined) {
416
- const claim = request.elevationRequestId.trim();
417
- if (!claim || claim.length > 128)
418
- return Promise.resolve(
419
- failure(request.id, "invalid_input", "elevationRequestId must be a non-empty bounded string."),
420
- );
421
- if (!elevationAllowlisted)
422
- return Promise.resolve(
423
- failure(request.id, "invalid_input", "Only allowlisted elevation operations may carry elevationRequestId."),
424
- );
425
- if (!surface.authorizeElevationClaim?.(row.sdkId, request.input, claim))
426
- return Promise.resolve(
427
- failure(request.id, "elevation_required", "The elevation claim is not broker-authorized for this control."),
428
- );
429
- }
430
465
  if ((row.sdkId === "context.clear" || row.sdkId === "session.delete") && request.confirm !== true)
431
466
  return Promise.resolve(
432
467
  failure(request.id, "invalid_input", "confirm: true is required for this destructive operation."),
@@ -8,4 +8,4 @@ export {
8
8
  dispatchControl,
9
9
  TypedControlError,
10
10
  } from "./dispatch";
11
- export type { ControlInput, ControlSurface, ControlValue } from "./operations";
11
+ export type { AbortScope, ControlInput, ControlSurface, ControlValue } from "./operations";
@@ -1,4 +1,17 @@
1
1
  export type ControlValue = unknown;
2
+ export type AbortMode = "turn" | "terminal";
3
+ export type AbortScope = "turn" | "owned";
4
+
5
+ /**
6
+ * Terminal-mode C04 `turn.abort` input. `scope` selects whether exact causal
7
+ * owned work (background Bash/task jobs, detached subagents) is also stopped
8
+ * (`"owned"`) or left running so its completion can resume the root worker
9
+ * (`"turn"`, the default).
10
+ */
11
+ export interface TerminalAbortInput {
12
+ mode: "terminal";
13
+ scope?: AbortScope;
14
+ }
2
15
  export type ControlInput = Record<string, unknown>;
3
16
 
4
17
  /**
@@ -6,11 +19,12 @@ export type ControlInput = Record<string, unknown>;
6
19
  * AgentSession and its controllers without exposing those concrete types here.
7
20
  */
8
21
  export interface ControlSurface {
9
- authorizeElevationClaim?(sdkId: string, input: ControlInput, capability: string): boolean;
10
22
  prompt(text: string, images?: ControlValue, clientRef?: string): Promise<ControlValue> | ControlValue;
11
- steer(text: string): Promise<ControlValue> | ControlValue;
23
+ steer(text: string, clientRef?: string): Promise<ControlValue> | ControlValue;
12
24
  followUp(text: string): Promise<ControlValue> | ControlValue;
13
25
  abort(): Promise<ControlValue> | ControlValue;
26
+ /** Terminal abort: stop the current root turn (and optionally exact owned work). */
27
+ abortTerminal?(input: TerminalAbortInput, idempotencyKey?: string): Promise<ControlValue> | ControlValue;
14
28
  abortAndPrompt(text: string): Promise<ControlValue> | ControlValue;
15
29
  answerAsk(id: string, answer: ControlValue): Promise<ControlValue> | ControlValue;
16
30
  answerGate(
@@ -18,14 +32,8 @@ export interface ControlSurface {
18
32
  response: ControlValue,
19
33
  expectedSessionId?: string,
20
34
  idempotencyKey?: string,
21
- elevationRequestId?: string,
22
- ): Promise<ControlValue> | ControlValue;
23
- approvePlan(
24
- id: string,
25
- choice: ControlValue,
26
- expectedSessionId?: string,
27
- elevationRequestId?: string,
28
35
  ): Promise<ControlValue> | ControlValue;
36
+ approvePlan(id: string, choice: ControlValue, expectedSessionId?: string): Promise<ControlValue> | ControlValue;
29
37
  invokeSkill(name: string, args: ControlValue, clientRef?: string): Promise<ControlValue> | ControlValue;
30
38
  setPlanMode(on: boolean): Promise<ControlValue> | ControlValue;
31
39
  operateGoal(op: string, objective?: string): Promise<ControlValue> | ControlValue;
@@ -46,7 +54,7 @@ export interface ControlSurface {
46
54
  newSession(): Promise<ControlValue> | ControlValue;
47
55
  forkSession(): Promise<ControlValue> | ControlValue;
48
56
  resumeSession(id: string): Promise<ControlValue> | ControlValue;
49
- closeSession(): Promise<ControlValue> | ControlValue;
57
+ closeSession(capability?: string): Promise<ControlValue> | ControlValue;
50
58
  switchSession(id: string): Promise<ControlValue> | ControlValue;
51
59
  branchSession(entryId: string): Promise<ControlValue> | ControlValue;
52
60
  renameSession(name: string): Promise<ControlValue> | ControlValue;
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Private field carried only on the Broker's endpoint close request.
3
+ *
4
+ * The value is the lifecycle effect marker bound to the serving process. It is
5
+ * never published in endpoint discovery or lifecycle service results; callers
6
+ * that do not hold the Broker's indexed lifecycle record cannot satisfy this
7
+ * gate.
8
+ */
9
+ export const BROKER_RUNTIME_CLOSE_CAPABILITY_FIELD = "__gjcBrokerCloseCapability";
10
+ const EXPECTED_BROKER_RUNTIME_CLOSE_CAPABILITY = process.env.GJC_LIFECYCLE_REQUEST_ID;
11
+
12
+ function record(value: unknown): Record<string, unknown> | undefined {
13
+ return value && typeof value === "object" && !Array.isArray(value) ? (value as Record<string, unknown>) : undefined;
14
+ }
15
+
16
+ export function brokerRuntimeCloseCapability(input: unknown): string | undefined {
17
+ const value = record(input)?.[BROKER_RUNTIME_CLOSE_CAPABILITY_FIELD];
18
+ return typeof value === "string" && value.length > 0 ? value : undefined;
19
+ }
20
+
21
+ /** Remove the private close capability before a request is exposed to diagnostics. */
22
+ export function redactBrokerRuntimeCloseCapability(frame: Record<string, unknown>): Record<string, unknown> {
23
+ if (frame.type !== "control_request" || frame.operation !== "session.close") return frame;
24
+ const input = record(frame.input);
25
+ if (!input || !Object.hasOwn(input, BROKER_RUNTIME_CLOSE_CAPABILITY_FIELD)) return frame;
26
+ const { [BROKER_RUNTIME_CLOSE_CAPABILITY_FIELD]: _capability, ...publicInput } = input;
27
+ return { ...frame, input: publicInput };
28
+ }
29
+
30
+ /**
31
+ * Runtime-local authority check for the Broker-only graceful close executor.
32
+ *
33
+ * A lifecycle child receives GJC_LIFECYCLE_REQUEST_ID from the Broker launch
34
+ * environment. Generic SDK requests never receive that private marker.
35
+ */
36
+ export function hasBrokerRuntimeCloseCapability(input: unknown): boolean {
37
+ const expected = EXPECTED_BROKER_RUNTIME_CLOSE_CAPABILITY;
38
+ const actual = brokerRuntimeCloseCapability(input);
39
+ return typeof expected === "string" && expected.length > 0 && actual === expected;
40
+ }
@@ -1,3 +1,5 @@
1
+ import { logger } from "@gajae-code/utils";
2
+ import { redactBrokerRuntimeCloseCapability } from "./control/runtime-gate";
1
3
  import { type EventFrame, SessionEventStream } from "./events";
2
4
  import { type ProviderLease, ReverseLeaseError, ReverseLeaseRuntime } from "./reverse-leases";
3
5
  import type { BrokerIndexWriter, HostEndpointAdapters, SdkFrame } from "./types";
@@ -43,6 +45,8 @@ export type SessionActivationGate = (input: { sessionId: string; generation: num
43
45
  export interface SessionSdkHostOptions extends HostEndpointAdapters {
44
46
  control?: (connectionId: string, frame: SdkFrame) => unknown | Promise<unknown>;
45
47
  query?: (connectionId: string, frame: SdkFrame) => unknown | Promise<unknown>;
48
+ /** Test/lifecycle seam invoked synchronously before fire-and-forget dispatch. */
49
+ onFrameAdmitted?: (connectionId: string, frame: SdkFrame) => void;
46
50
  /** Best-effort diagnostic observation of accepted control/query frames. */
47
51
  onRequest?: SdkRequestObserver;
48
52
  /** Runs before a control response is sent; identity transitions use sendTerminal. */
@@ -50,10 +54,22 @@ export interface SessionSdkHostOptions extends HostEndpointAdapters {
50
54
  connectionId: string,
51
55
  request: SdkFrame,
52
56
  response: SdkFrame,
53
- sendTerminal: () => Promise<void>,
57
+ sendTerminal: () => Promise<unknown>,
54
58
  ) => void | Promise<void>;
55
59
  /** Runs only after a successful control response has been sent to the client. */
56
60
  afterControlResponse?: (connectionId: string, request: SdkFrame, response: SdkFrame) => void | Promise<void>;
61
+ /**
62
+ * Classifies the awaited control-response write exactly once: `written`
63
+ * (sent), `rejected` (the write threw), or `dropped` (the send adapter
64
+ * deliberately skipped delivery). `afterControlResponse` runs only
65
+ * on `written`. Used to persist monotonic response-state transitions.
66
+ */
67
+ onControlResponseDelivery?: (
68
+ connectionId: string,
69
+ request: SdkFrame,
70
+ response: SdkFrame,
71
+ outcome: "written" | "rejected" | "dropped",
72
+ ) => void | Promise<void>;
57
73
  installProviderDefinitions?: (capability: string, definitions: unknown) => void;
58
74
  onProviderDefinitionsRemoved?: (capability: string) => void;
59
75
  onReverseCancel?: (requestId: string, reason: "provider_disconnected" | "lease_released") => void;
@@ -69,8 +85,11 @@ export interface SessionSdkHostOptions extends HostEndpointAdapters {
69
85
  activationGate?: SessionActivationGate;
70
86
  }
71
87
 
72
- const TOOL_ACTIVITY_CAPABILITY = "tool_activity_v2";
73
- const CAP_GATED_FRAME_KINDS = new Set(["tool_activity", "reasoning_summary"]);
88
+ /** Shared by the replay filter and transport live broadcasts: a connection
89
+ * must see the same capability-gated event kinds on both legs, or live and
90
+ * replay delivery diverge for the same subscriber. */
91
+ export const TOOL_ACTIVITY_CAPABILITY = "tool_activity_v2";
92
+ export const CAP_GATED_FRAME_KINDS: ReadonlySet<string> = new Set(["tool_activity", "reasoning_summary"]);
74
93
  const EMPTY_CAPABILITIES: ReadonlySet<string> = new Set();
75
94
 
76
95
  /** Safe, identifier-free explanations for every refused activation status. */
@@ -239,6 +258,7 @@ export class SessionSdkHost {
239
258
  generation: this.events.generation,
240
259
  });
241
260
  const disposer = this.#options.onFrame((connectionId, frame) => {
261
+ this.#options.onFrameAdmitted?.(connectionId, frame);
242
262
  void this.#onFrame(connectionId, frame);
243
263
  });
244
264
  this.#unsubscribe = typeof disposer === "function" ? disposer : undefined;
@@ -353,8 +373,8 @@ export class SessionSdkHost {
353
373
  });
354
374
  }
355
375
 
356
- async #send(connectionId: string, frame: SdkFrame): Promise<void> {
357
- await this.#options.sendFrame(connectionId, frame);
376
+ async #send(connectionId: string, frame: SdkFrame): Promise<"written" | "dropped"> {
377
+ return await this.#options.sendFrame(connectionId, frame);
358
378
  }
359
379
 
360
380
  /**
@@ -395,14 +415,45 @@ export class SessionSdkHost {
395
415
  if (result !== undefined) {
396
416
  const response = { type: "control_response", ...(result as SdkFrame) };
397
417
  let terminalSent = false;
398
- const sendTerminal = async (): Promise<void> => {
399
- if (terminalSent) return;
418
+ let sendOutcome: "written" | "rejected" | "dropped" = "dropped";
419
+ const sendTerminal = async (): Promise<"written" | "rejected" | "dropped"> => {
420
+ // Repeat calls (early hook send + fallback) return the FIRST,
421
+ // actual outcome — never a false dropped for an already
422
+ // written response (early-identity-rotation pattern).
423
+ if (terminalSent) return sendOutcome;
400
424
  terminalSent = true;
401
- await this.#send(connectionId, response);
425
+ try {
426
+ const outcome = await this.#send(connectionId, response);
427
+ sendOutcome = outcome === "written" ? "written" : "dropped";
428
+ } catch {
429
+ sendOutcome = "rejected";
430
+ }
431
+ return sendOutcome;
402
432
  };
403
- await this.#options.beforeControlResponse?.(connectionId, frame, response, sendTerminal);
404
- await sendTerminal();
405
- await this.#options.afterControlResponse?.(connectionId, frame, response);
433
+ try {
434
+ await this.#options.beforeControlResponse?.(connectionId, frame, response, sendTerminal);
435
+ // Fallback: if the before hook did not send early (identity
436
+ // rotation), the response is always sent here.
437
+ if (!terminalSent) sendOutcome = await sendTerminal();
438
+ } finally {
439
+ // Classify exactly once, immediately after the send attempt and
440
+ // BEFORE the optional post-write hook, so a rejected/dropped
441
+ // write (or an afterControlResponse throw) never mislabels it.
442
+ try {
443
+ await this.#options.onControlResponseDelivery?.(connectionId, frame, response, sendOutcome);
444
+ } catch (error) {
445
+ // Contain observer persistence failures: the response was already
446
+ // sent (or classified) and its delivery state recorded; rethrowing
447
+ // would escape into the outer #onFrame catch and send a SECOND
448
+ // control_response for the same request id (review thread P2).
449
+ logger.warn("sdk control delivery observer failed", {
450
+ error: error instanceof Error ? error.message : String(error),
451
+ });
452
+ }
453
+ }
454
+ if (sendOutcome === "written") {
455
+ await this.#options.afterControlResponse?.(connectionId, frame, response);
456
+ }
406
457
  }
407
458
  break;
408
459
  }
@@ -542,7 +593,7 @@ export class SessionSdkHost {
542
593
  }
543
594
  #observeRequest(kind: "control" | "query", connectionId: string, frame: SdkFrame): void {
544
595
  try {
545
- this.#options.onRequest?.(kind, connectionId, frame);
596
+ this.#options.onRequest?.(kind, connectionId, redactBrokerRuntimeCloseCapability(frame));
546
597
  } catch {
547
598
  // Diagnostic observers must not change request handling.
548
599
  }
@@ -1,7 +1,10 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import { PROMPT_CLIENT_REF_MAX_LENGTH } from "../../prompt-status.js";
3
+ import { TURN_RESULT_PROMPT_ALIAS, TURN_RESULT_SKILL_ALIAS } from "../../protocol/operation-registry.js";
4
+
3
5
  import type { ActiveProviderDescriptor } from "../../providers.js";
4
6
  import { ActiveProviderResolutionError } from "../../providers.js";
7
+
5
8
  import {
6
9
  assertCursorSelector,
7
10
  type CursorEnvelope,
@@ -61,6 +64,7 @@ export interface SessionSurface {
61
64
  commandId?: string;
62
65
  turnId?: string;
63
66
  }): unknown | Promise<unknown>;
67
+ getSteerStatus?(selector: { commandId?: string; turnId?: string; clientRef?: string }): unknown | Promise<unknown>;
64
68
  /** Q27 effective model-profile catalog from the live session registry. */
65
69
  getModelProfiles?(): unknown[] | Promise<unknown[]>;
66
70
  /**
@@ -175,9 +179,11 @@ const names = [
175
179
  "runtime.jobs.list",
176
180
  "turn.result",
177
181
  "models.profiles.list",
178
- "skill.invoke_status",
182
+ // Q28 was folded into Q26; retain the vacant slot so Q29/Q30 remain stable.
183
+ undefined,
179
184
  "providers.list/active",
180
185
  "session.checkpoint",
186
+ "turn.steer_status",
181
187
  ];
182
188
 
183
189
  export class QueryHandlers {
@@ -199,8 +205,9 @@ export class QueryHandlers {
199
205
  );
200
206
  return await this.#turnResult(request);
201
207
  }
202
- if (request.query === "turn.prompt_status") return await this.#promptTurnResult(request);
203
- if (request.query === "skill.invoke_status") return await this.#skillTurnResult(request);
208
+ if (request.query === TURN_RESULT_PROMPT_ALIAS) return await this.#promptTurnResult(request);
209
+
210
+ if (request.query === TURN_RESULT_SKILL_ALIAS) return await this.#skillTurnResult(request);
204
211
 
205
212
  const query = request.query.startsWith("Q")
206
213
  ? request.query
@@ -217,7 +224,7 @@ export class QueryHandlers {
217
224
  );
218
225
  return await this.#turnResult(request);
219
226
  }
220
- if (query === "Q28") return await this.#skillTurnResult(request);
227
+
221
228
  if (
222
229
  this.surface.installedQueries instanceof Set &&
223
230
  !this.surface.installedQueries.has(names[Number(query.slice(1)) - 1] ?? "")
@@ -252,6 +259,7 @@ export class QueryHandlers {
252
259
  if (query === "Q23") return await this.#resourceBody(request);
253
260
  if (query === "Q24") return await this.#artifact(request);
254
261
  if (query === "Q30") return await this.#checkpoint(request);
262
+ if (query === "Q31") return await this.#steerStatus(request);
255
263
  if (query === "Q27" && request.input && Object.keys(request.input).length > 0)
256
264
  return this.#error(request, "invalid_request", false, "models.profiles.list does not accept input fields.");
257
265
  if (query === "Q27" && typeof this.surface.getModelProfiles !== "function")
@@ -581,7 +589,8 @@ export class QueryHandlers {
581
589
  // unreachable: the bounded content cap is well under both RESPONSE_CEILING_BYTES
582
590
  // and TARGET_PAGE_BYTES, so no revision is ever created. Reject cursors
583
591
  // upfront instead of advertising a continuation path that can never fire.
584
- if (request.cursor) return this.#error(request, "invalid_cursor", false, "turn.result does not support cursors.");
592
+ if (request.cursor !== undefined)
593
+ return this.#error(request, "invalid_request", false, "turn.result does not support cursors.");
585
594
  if (typeof this.surface.getTurnResult !== "function") return this.#error(request, "unavailable");
586
595
  const result = await this.surface.getTurnResult({
587
596
  kind,
@@ -637,12 +646,12 @@ export class QueryHandlers {
637
646
  return await this.#turnResult({ ...request, input: { ...input, kind: "prompt" } });
638
647
  }
639
648
  async #skillTurnResult(request: QueryRequest): Promise<QueryResponse> {
640
- if (this.surface.installedQueries instanceof Set && !this.surface.installedQueries.has("skill.invoke_status"))
649
+ if (this.surface.installedQueries instanceof Set && !this.surface.installedQueries.has("turn.result"))
641
650
  return this.#error(
642
651
  request,
643
652
  "operation_not_session_owned",
644
653
  false,
645
- "skill.invoke_status is not installed for this session.",
654
+ "turn.result is not installed for this session.",
646
655
  );
647
656
  const input = request.input ?? {};
648
657
  if (input.kind !== undefined && input.kind !== "skill")
@@ -779,6 +788,56 @@ export class QueryHandlers {
779
788
  return { id: request.id, ok: true, page };
780
789
  }
781
790
 
791
+ async #steerStatus(request: QueryRequest): Promise<QueryResponse> {
792
+ if (request.cursor)
793
+ return this.#error(request, "invalid_request", false, "turn.steer_status does not support cursors.");
794
+ const input = request.input ?? {};
795
+ for (const key of Object.keys(input))
796
+ if (key !== "commandId" && key !== "turnId" && key !== "clientRef")
797
+ return this.#error(
798
+ request,
799
+ "invalid_request",
800
+ false,
801
+ `turn.steer_status does not accept selector field "${key}".`,
802
+ );
803
+ const commandId = typeof input.commandId === "string" && input.commandId ? input.commandId : undefined;
804
+ const turnId = typeof input.turnId === "string" && input.turnId ? input.turnId : undefined;
805
+ const rawClientRef = typeof input.clientRef === "string" ? input.clientRef : undefined;
806
+ const clientRef = rawClientRef?.trim() || undefined;
807
+ if (rawClientRef !== undefined && (!clientRef || clientRef.length > PROMPT_CLIENT_REF_MAX_LENGTH))
808
+ return this.#error(
809
+ request,
810
+ "invalid_request",
811
+ false,
812
+ "clientRef must be a non-empty string of at most 128 characters.",
813
+ );
814
+ if ((commandId === undefined) !== (turnId === undefined))
815
+ return this.#error(request, "invalid_request", false, "commandId and turnId must be provided together.");
816
+ if (commandId !== undefined && clientRef !== undefined)
817
+ return this.#error(
818
+ request,
819
+ "invalid_request",
820
+ false,
821
+ "Provide exactly one selector: a commandId/turnId pair or a clientRef.",
822
+ );
823
+ if (commandId === undefined && clientRef === undefined)
824
+ return this.#error(
825
+ request,
826
+ "invalid_request",
827
+ false,
828
+ "turn.steer_status requires a commandId/turnId pair or a clientRef.",
829
+ );
830
+ if (typeof this.surface.getSteerStatus !== "function")
831
+ return this.#error(request, "unavailable", false, "turn.steer_status is unavailable for this session.");
832
+ return {
833
+ id: request.id,
834
+ ok: true,
835
+ result: await this.surface.getSteerStatus(
836
+ clientRef !== undefined ? { clientRef } : { commandId: commandId!, turnId: turnId! },
837
+ ),
838
+ };
839
+ }
840
+
782
841
  #error(request: QueryRequest, code: string, restartQuery = false, message = code, details?: unknown): QueryResponse {
783
842
  return {
784
843
  id: request.id,
@@ -57,7 +57,7 @@ interface Outstanding {
57
57
  export interface ReverseLeaseOptions {
58
58
  now?: () => number;
59
59
  leaseTtlMs?: number;
60
- sendFrame: (connectionId: string, frame: SdkFrame) => void | Promise<void>;
60
+ sendFrame: (connectionId: string, frame: SdkFrame) => unknown;
61
61
  installDefinitions?: (capability: string, definitions: unknown) => void;
62
62
  onCancel?: (requestId: string, reason: "provider_disconnected" | "lease_released") => void;
63
63
  onDefinitionsRemoved?: (capability: string) => void;
@@ -245,7 +245,7 @@ export class ReverseLeaseRuntime {
245
245
  return;
246
246
  }
247
247
  }
248
- let delivery: void | Promise<void>;
248
+ let delivery: unknown;
249
249
  try {
250
250
  delivery = this.#sendFrame(lease.connectionId, {
251
251
  type: "reverse_request",