@gajae-code/coding-agent 0.11.1 → 0.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (404) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/dist/types/cli/config-cli.d.ts +11 -1
  3. package/dist/types/cli/notify-cli.d.ts +1 -0
  4. package/dist/types/cli/session-picker.d.ts +2 -1
  5. package/dist/types/cli/setup-cli.d.ts +1 -1
  6. package/dist/types/commands/mcp-serve.d.ts +33 -0
  7. package/dist/types/commands/mcp.d.ts +1 -1
  8. package/dist/types/commands/notify.d.ts +0 -2
  9. package/dist/types/commands/sdk.d.ts +1 -1
  10. package/dist/types/config/atomic-yaml-patch.d.ts +18 -0
  11. package/dist/types/config/file-lock.d.ts +14 -4
  12. package/dist/types/config/keybindings.d.ts +42 -1
  13. package/dist/types/config/model-auth.d.ts +3 -0
  14. package/dist/types/config/model-bindings-applier.d.ts +13 -0
  15. package/dist/types/config/model-discovery-manager.d.ts +49 -0
  16. package/dist/types/config/model-equivalence.d.ts +20 -0
  17. package/dist/types/config/model-registry.d.ts +16 -15
  18. package/dist/types/config/model-resolver.d.ts +28 -18
  19. package/dist/types/config/models-config-schema.d.ts +11 -0
  20. package/dist/types/config/settings-schema.d.ts +56 -1
  21. package/dist/types/config/settings.d.ts +14 -11
  22. package/dist/types/coordinator-mcp/policy.d.ts +5 -0
  23. package/dist/types/coordinator-mcp/question-gate-codec.d.ts +129 -0
  24. package/dist/types/coordinator-mcp/question-state.d.ts +356 -0
  25. package/dist/types/coordinator-mcp/server.d.ts +4 -0
  26. package/dist/types/discovery/helpers.d.ts +0 -6
  27. package/dist/types/edit/index.d.ts +3 -0
  28. package/dist/types/eval/py/env.d.ts +9 -0
  29. package/dist/types/extensibility/extensions/loader.d.ts +2 -1
  30. package/dist/types/extensibility/extensions/runner.d.ts +2 -2
  31. package/dist/types/extensibility/extensions/types.d.ts +34 -3
  32. package/dist/types/extensibility/hooks/runner.d.ts +1 -1
  33. package/dist/types/extensibility/shared-events.d.ts +2 -0
  34. package/dist/types/gjc-runtime/deep-interview-recorder.d.ts +10 -1
  35. package/dist/types/gjc-runtime/deep-interview-state.d.ts +44 -0
  36. package/dist/types/gjc-runtime/goal-mode-request.d.ts +11 -1
  37. package/dist/types/gjc-runtime/launch-worktree.d.ts +4 -2
  38. package/dist/types/gjc-runtime/linux-proc.d.ts +29 -0
  39. package/dist/types/gjc-runtime/session-resolution.d.ts +2 -2
  40. package/dist/types/gjc-runtime/state-migrations.d.ts +1 -1
  41. package/dist/types/gjc-runtime/state-writer.d.ts +2 -1
  42. package/dist/types/gjc-runtime/team-launch.d.ts +59 -0
  43. package/dist/types/gjc-runtime/team-notify.d.ts +45 -0
  44. package/dist/types/gjc-runtime/team-runtime.d.ts +29 -121
  45. package/dist/types/gjc-runtime/team-store.d.ts +160 -0
  46. package/dist/types/gjc-runtime/team-workers.d.ts +78 -0
  47. package/dist/types/gjc-runtime/tmux-owner-isolation.d.ts +8 -0
  48. package/dist/types/gjc-runtime/ultragoal-change-set.d.ts +13 -0
  49. package/dist/types/gjc-runtime/ultragoal-evidence.d.ts +38 -0
  50. package/dist/types/gjc-runtime/ultragoal-guard.d.ts +7 -0
  51. package/dist/types/gjc-runtime/ultragoal-pipeline.d.ts +23 -0
  52. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +55 -33
  53. package/dist/types/gjc-runtime/workflow-cli-common.d.ts +8 -0
  54. package/dist/types/gjc-runtime/workflow-manifest.d.ts +3 -0
  55. package/dist/types/goals/continuation-timeout-guard.d.ts +22 -0
  56. package/dist/types/goals/runtime.d.ts +1 -0
  57. package/dist/types/goals/state.d.ts +8 -0
  58. package/dist/types/harness-control-plane/lifecycle-reconciliation.d.ts +17 -0
  59. package/dist/types/harness-control-plane/phase-rollup.d.ts +4 -7
  60. package/dist/types/harness-control-plane/receipt-ingest.d.ts +5 -0
  61. package/dist/types/harness-control-plane/receipt-spool.d.ts +4 -0
  62. package/dist/types/hindsight/state.d.ts +11 -4
  63. package/dist/types/lsp/lspmux.d.ts +5 -3
  64. package/dist/types/lsp/path-trust.d.ts +1 -0
  65. package/dist/types/main.d.ts +3 -2
  66. package/dist/types/memories/storage.d.ts +1 -0
  67. package/dist/types/modes/action-registry.d.ts +29 -0
  68. package/dist/types/modes/components/chrome.d.ts +14 -0
  69. package/dist/types/modes/components/command-palette.d.ts +27 -0
  70. package/dist/types/modes/components/custom-provider-wizard.d.ts +1 -0
  71. package/dist/types/modes/components/index.d.ts +2 -1
  72. package/dist/types/modes/components/pet-selector.d.ts +1 -1
  73. package/dist/types/modes/components/plan-preview-overlay.d.ts +43 -0
  74. package/dist/types/modes/components/queue-mode-selector.d.ts +1 -1
  75. package/dist/types/modes/components/queue-pane.d.ts +12 -0
  76. package/dist/types/modes/components/read-tool-group.d.ts +6 -0
  77. package/dist/types/modes/components/session-observer-overlay.d.ts +3 -4
  78. package/dist/types/modes/components/sessions-dashboard.d.ts +32 -0
  79. package/dist/types/modes/components/settings-selector.d.ts +1 -1
  80. package/dist/types/modes/components/show-images-selector.d.ts +1 -1
  81. package/dist/types/modes/components/status-line/types.d.ts +1 -1
  82. package/dist/types/modes/components/status-line.d.ts +1 -94
  83. package/dist/types/modes/components/tasks-pane.d.ts +15 -0
  84. package/dist/types/modes/components/theme-selector.d.ts +1 -1
  85. package/dist/types/modes/components/tool-execution.d.ts +15 -0
  86. package/dist/types/modes/components/tool-status-header.d.ts +111 -0
  87. package/dist/types/modes/components/transcript-viewer-overlay.d.ts +42 -0
  88. package/dist/types/modes/controllers/goal-mode-controller.d.ts +62 -0
  89. package/dist/types/modes/controllers/input-controller.d.ts +8 -1
  90. package/dist/types/modes/controllers/mode-gate.d.ts +8 -0
  91. package/dist/types/modes/controllers/plan-mode-controller.d.ts +65 -0
  92. package/dist/types/modes/controllers/selector-controller.d.ts +15 -3
  93. package/dist/types/modes/controllers/stt-controller.d.ts +26 -0
  94. package/dist/types/modes/interactive-mode.d.ts +19 -17
  95. package/dist/types/modes/jobs-observer.d.ts +2 -0
  96. package/dist/types/modes/shared/agent-wire/deep-interview-gate.d.ts +4 -11
  97. package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +20 -2
  98. package/dist/types/modes/shared/agent-wire/workflow-gate-types.d.ts +31 -0
  99. package/dist/types/modes/tasks-aggregator.d.ts +39 -0
  100. package/dist/types/modes/transcript-item-registry.d.ts +60 -0
  101. package/dist/types/modes/types.d.ts +20 -13
  102. package/dist/types/modes/utils/ui-helpers.d.ts +2 -2
  103. package/dist/types/runtime-mcp/manager.d.ts +1 -1
  104. package/dist/types/sdk/broker/broker.d.ts +78 -12
  105. package/dist/types/sdk/broker/lifecycle-codec.d.ts +4 -0
  106. package/dist/types/sdk/broker/lifecycle-ledger.d.ts +15 -1
  107. package/dist/types/sdk/broker/lifecycle.d.ts +6 -2
  108. package/dist/types/sdk/broker/process-incarnation.d.ts +2 -0
  109. package/dist/types/sdk/broker/session-index.d.ts +0 -1
  110. package/dist/types/sdk/broker/state-version.d.ts +2 -0
  111. package/dist/types/sdk/bus/chat-effect-journal.d.ts +1 -0
  112. package/dist/types/sdk/bus/config-commands.d.ts +1 -1
  113. package/dist/types/sdk/bus/config.d.ts +11 -0
  114. package/dist/types/sdk/bus/daemon-paths.d.ts +1 -0
  115. package/dist/types/sdk/bus/html-format.d.ts +3 -2
  116. package/dist/types/sdk/bus/index.d.ts +27 -0
  117. package/dist/types/sdk/bus/lifecycle-control-runtime.d.ts +4 -0
  118. package/dist/types/sdk/bus/notification-service.d.ts +20 -0
  119. package/dist/types/sdk/bus/rate-limit-pool.d.ts +13 -2
  120. package/dist/types/sdk/bus/recent-activity.d.ts +21 -12
  121. package/dist/types/sdk/bus/rich-document.d.ts +7 -0
  122. package/dist/types/sdk/bus/rich-render.d.ts +18 -41
  123. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +9 -4
  124. package/dist/types/sdk/bus/telegram-daemon.d.ts +46 -3
  125. package/dist/types/sdk/bus/threaded-inbound.d.ts +1 -1
  126. package/dist/types/sdk/bus/threaded-render.d.ts +13 -0
  127. package/dist/types/sdk/bus/topic-registry.d.ts +24 -2
  128. package/dist/types/sdk/host/control/operations.d.ts +1 -1
  129. package/dist/types/sdk/host/host.d.ts +2 -0
  130. package/dist/types/sdk/index.d.ts +1 -0
  131. package/dist/types/sdk/session-directory.d.ts +56 -0
  132. package/dist/types/session/agent-session.d.ts +82 -47
  133. package/dist/types/session/agent-storage.d.ts +7 -0
  134. package/dist/types/session/fallback-chain-controller.d.ts +10 -2
  135. package/dist/types/session/internal/managed-session-scope.d.ts +102 -0
  136. package/dist/types/session/internal/managed-session-storage.d.ts +38 -0
  137. package/dist/types/session/messages.d.ts +16 -0
  138. package/dist/types/session/session-manager-internal.d.ts +14 -0
  139. package/dist/types/session/session-manager.d.ts +82 -12
  140. package/dist/types/session/session-storage.d.ts +43 -3
  141. package/dist/types/session/volatile-context-pruning.d.ts +15 -0
  142. package/dist/types/skill-state/{deep-interview-mutation-guard.d.ts → workflow-mutation-guard.d.ts} +24 -8
  143. package/dist/types/skill-state/workflow-state-contract.d.ts +1 -3
  144. package/dist/types/slash-commands/builtin-registry.d.ts +4 -1
  145. package/dist/types/system-prompt.d.ts +2 -11
  146. package/dist/types/task/executor.d.ts +3 -1
  147. package/dist/types/thinking.d.ts +7 -0
  148. package/dist/types/tool-discovery/tool-index.d.ts +1 -50
  149. package/dist/types/tools/ask.d.ts +64 -2
  150. package/dist/types/tools/bash.d.ts +3 -0
  151. package/dist/types/tools/browser/dead-tab-recovery.d.ts +24 -0
  152. package/dist/types/tools/browser/tab-supervisor.d.ts +21 -0
  153. package/dist/types/tools/cron.d.ts +2 -0
  154. package/dist/types/tools/fetch.d.ts +1 -0
  155. package/dist/types/tools/index.d.ts +30 -15
  156. package/dist/types/tools/output-meta.d.ts +1 -0
  157. package/dist/types/tools/read.d.ts +3 -0
  158. package/dist/types/tools/search-tool-bm25.d.ts +3 -4
  159. package/dist/types/utils/event-bus.d.ts +1 -1
  160. package/dist/types/web/search/index.d.ts +3 -1
  161. package/package.json +21 -9
  162. package/scripts/build-sdk-package-smoke.ts +34 -1
  163. package/scripts/generate-hotkeys-docs.ts +74 -0
  164. package/scripts/generate-sdk-operation-inventory.ts +64 -20
  165. package/scripts/verify-gjc-sdk-canonicalization.ts +182 -2
  166. package/src/async/job-manager.ts +49 -6
  167. package/src/cli/config-cli.ts +75 -2
  168. package/src/cli/notify-cli.ts +92 -26
  169. package/src/cli/session-picker.ts +20 -3
  170. package/src/cli/setup-cli.ts +1 -1
  171. package/src/cli.ts +1 -1
  172. package/src/commands/config.ts +1 -1
  173. package/src/commands/harness.ts +34 -106
  174. package/src/commands/launch.ts +6 -4
  175. package/src/commands/mcp-serve.ts +85 -8
  176. package/src/commands/mcp.ts +2 -2
  177. package/src/commands/notify.ts +8 -4
  178. package/src/commands/sdk.ts +61 -40
  179. package/src/commands/ultragoal.ts +4 -1
  180. package/src/config/atomic-yaml-patch.ts +80 -13
  181. package/src/config/file-lock.ts +105 -43
  182. package/src/config/keybindings.ts +64 -20
  183. package/src/config/model-auth.ts +9 -0
  184. package/src/config/model-bindings-applier.ts +139 -0
  185. package/src/config/model-discovery-manager.ts +224 -0
  186. package/src/config/model-equivalence.ts +66 -0
  187. package/src/config/model-registry.ts +169 -302
  188. package/src/config/model-resolver.ts +361 -369
  189. package/src/config/models-config-schema.ts +5 -4
  190. package/src/config/settings-schema.ts +159 -2
  191. package/src/config/settings.ts +458 -482
  192. package/src/coordinator-mcp/policy.ts +76 -11
  193. package/src/coordinator-mcp/question-gate-codec.ts +274 -0
  194. package/src/coordinator-mcp/question-state.ts +778 -0
  195. package/src/coordinator-mcp/server.ts +1702 -238
  196. package/src/debug/index.ts +1 -1
  197. package/src/defaults/gjc/skills/deep-interview/SKILL.md +13 -1
  198. package/src/defaults/gjc/skills/team/SKILL.md +16 -0
  199. package/src/discovery/helpers.ts +1 -50
  200. package/src/edit/index.ts +64 -0
  201. package/src/eval/py/env.ts +26 -0
  202. package/src/eval/py/kernel.ts +5 -3
  203. package/src/extensibility/extensions/loader.ts +9 -1
  204. package/src/extensibility/extensions/runner.ts +12 -3
  205. package/src/extensibility/extensions/types.ts +39 -1
  206. package/src/extensibility/gjc-plugins/installer.ts +16 -16
  207. package/src/extensibility/hooks/runner.ts +2 -2
  208. package/src/extensibility/runtime-skill-discovery.ts +33 -13
  209. package/src/extensibility/shared-events.ts +2 -0
  210. package/src/gjc-runtime/deep-interview-recorder.ts +63 -3
  211. package/src/gjc-runtime/deep-interview-runtime.ts +76 -27
  212. package/src/gjc-runtime/deep-interview-state.ts +317 -5
  213. package/src/gjc-runtime/goal-mode-request.ts +55 -8
  214. package/src/gjc-runtime/launch-tmux.ts +2 -5
  215. package/src/gjc-runtime/launch-worktree.ts +5 -5
  216. package/src/gjc-runtime/linux-proc.ts +71 -0
  217. package/src/gjc-runtime/ralplan-runtime.ts +74 -90
  218. package/src/gjc-runtime/session-resolution.ts +18 -3
  219. package/src/gjc-runtime/session-state-sidecar.ts +6 -107
  220. package/src/gjc-runtime/state-migrations.ts +1 -1
  221. package/src/gjc-runtime/state-runtime.ts +320 -249
  222. package/src/gjc-runtime/state-writer.ts +36 -40
  223. package/src/gjc-runtime/team-launch.ts +319 -0
  224. package/src/gjc-runtime/team-notify.ts +326 -0
  225. package/src/gjc-runtime/team-runtime.ts +1099 -1482
  226. package/src/gjc-runtime/team-store.ts +828 -0
  227. package/src/gjc-runtime/team-workers.ts +962 -0
  228. package/src/gjc-runtime/tmux-owner-isolation-cli.ts +2 -11
  229. package/src/gjc-runtime/tmux-owner-isolation.ts +14 -9
  230. package/src/gjc-runtime/tmux-sessions.ts +4 -21
  231. package/src/gjc-runtime/ultragoal-change-set.ts +172 -0
  232. package/src/gjc-runtime/ultragoal-evidence.ts +874 -0
  233. package/src/gjc-runtime/ultragoal-guard.ts +29 -5
  234. package/src/gjc-runtime/ultragoal-pipeline.ts +306 -0
  235. package/src/gjc-runtime/ultragoal-runtime.ts +84 -1311
  236. package/src/gjc-runtime/workflow-cli-common.ts +30 -0
  237. package/src/gjc-runtime/workflow-manifest.generated.json +58 -0
  238. package/src/gjc-runtime/workflow-manifest.ts +18 -0
  239. package/src/goals/continuation-timeout-guard.ts +79 -0
  240. package/src/goals/runtime.ts +7 -5
  241. package/src/goals/state.ts +18 -0
  242. package/src/harness-control-plane/lifecycle-reconciliation.ts +64 -0
  243. package/src/harness-control-plane/phase-rollup.ts +4 -7
  244. package/src/harness-control-plane/receipt-ingest.ts +5 -0
  245. package/src/harness-control-plane/receipt-spool.ts +51 -7
  246. package/src/harness-control-plane/session-lease.ts +12 -130
  247. package/src/hindsight/backend.ts +26 -27
  248. package/src/hindsight/state.ts +101 -32
  249. package/src/hooks/skill-state.ts +17 -11
  250. package/src/internal-urls/docs-index.generated.ts +21 -18
  251. package/src/lsp/client.ts +1 -1
  252. package/src/lsp/config.ts +145 -26
  253. package/src/lsp/index.ts +1 -1
  254. package/src/lsp/lspmux.ts +39 -10
  255. package/src/lsp/path-trust.ts +81 -0
  256. package/src/main.ts +28 -8
  257. package/src/memories/index.ts +1 -0
  258. package/src/memories/storage.ts +6 -2
  259. package/src/modes/action-registry.ts +165 -0
  260. package/src/modes/components/chrome.ts +40 -0
  261. package/src/modes/components/command-palette.ts +168 -0
  262. package/src/modes/components/custom-editor.ts +1 -1
  263. package/src/modes/components/custom-provider-wizard.ts +51 -14
  264. package/src/modes/components/index.ts +2 -1
  265. package/src/modes/components/pet-selector.ts +11 -17
  266. package/src/modes/components/plan-preview-overlay.ts +295 -0
  267. package/src/modes/components/queue-mode-selector.ts +10 -27
  268. package/src/modes/components/queue-pane.ts +79 -0
  269. package/src/modes/components/read-tool-group.ts +13 -0
  270. package/src/modes/components/session-observer-overlay.ts +207 -772
  271. package/src/modes/components/sessions-dashboard.ts +181 -0
  272. package/src/modes/components/settings-selector.ts +1 -1
  273. package/src/modes/components/show-images-selector.ts +10 -24
  274. package/src/modes/components/status-line/types.ts +1 -1
  275. package/src/modes/components/status-line.ts +1 -969
  276. package/src/modes/components/tasks-pane.ts +73 -0
  277. package/src/modes/components/theme-selector.ts +11 -31
  278. package/src/modes/components/tool-execution.ts +22 -0
  279. package/src/modes/components/tool-status-header.ts +1056 -0
  280. package/src/modes/components/transcript-viewer-overlay.ts +384 -0
  281. package/src/modes/controllers/btw-controller.ts +1 -0
  282. package/src/modes/controllers/event-controller.ts +3 -2
  283. package/src/modes/controllers/extension-ui-controller.ts +24 -1
  284. package/src/modes/controllers/goal-mode-controller.ts +474 -0
  285. package/src/modes/controllers/input-controller.ts +764 -229
  286. package/src/modes/controllers/mode-gate.ts +24 -0
  287. package/src/modes/controllers/plan-mode-controller.ts +517 -0
  288. package/src/modes/controllers/selector-controller.ts +225 -10
  289. package/src/modes/controllers/stt-controller.ts +125 -0
  290. package/src/modes/interactive-mode.ts +289 -1150
  291. package/src/modes/jobs-observer.ts +3 -0
  292. package/src/modes/runtime-init.ts +8 -0
  293. package/src/modes/shared/agent-wire/deep-interview-gate.ts +31 -106
  294. package/src/modes/shared/agent-wire/workflow-gate-broker.ts +71 -16
  295. package/src/modes/shared/agent-wire/workflow-gate-types.ts +177 -0
  296. package/src/modes/tasks-aggregator.ts +199 -0
  297. package/src/modes/transcript-item-registry.ts +229 -0
  298. package/src/modes/types.ts +45 -18
  299. package/src/modes/utils/ui-helpers.ts +17 -9
  300. package/src/prompts/agent-fragments/ralplan-persistence.md +6 -0
  301. package/src/prompts/agent-fragments/restricted-bash.md +1 -0
  302. package/src/prompts/agents/architect.md +2 -8
  303. package/src/prompts/agents/critic.md +2 -8
  304. package/src/prompts/agents/executor.md +3 -0
  305. package/src/prompts/agents/planner.md +4 -12
  306. package/src/prompts/system/custom-system-prompt.md +1 -23
  307. package/src/prompts/system/plan-mode-approved.md +8 -0
  308. package/src/prompts/system/system-prompt.md +17 -96
  309. package/src/prompts/tools/bash.md +4 -4
  310. package/src/prompts/tools/browser.md +15 -52
  311. package/src/prompts/tools/find.md +2 -2
  312. package/src/prompts/tools/hashline.md +13 -55
  313. package/src/prompts/tools/read.md +3 -6
  314. package/src/prompts/tools/search-tool-bm25.md +0 -2
  315. package/src/prompts/tools/search.md +2 -4
  316. package/src/prompts/tools/skill-discovery.md +1 -2
  317. package/src/prompts/tools/task.md +1 -1
  318. package/src/runtime-mcp/manager.ts +1 -1
  319. package/src/sdk/broker/broker.ts +206 -78
  320. package/src/sdk/broker/discovery.ts +1 -1
  321. package/src/sdk/broker/ensure.ts +3 -1
  322. package/src/sdk/broker/lifecycle-codec.ts +11 -0
  323. package/src/sdk/broker/lifecycle-ledger.ts +371 -74
  324. package/src/sdk/broker/lifecycle.ts +1399 -142
  325. package/src/sdk/broker/process-incarnation.ts +5 -13
  326. package/src/sdk/broker/session-index.ts +145 -56
  327. package/src/sdk/broker/state-version.ts +21 -0
  328. package/src/sdk/broker/transport.ts +1 -1
  329. package/src/sdk/bus/chat-daemon-cli.ts +2 -0
  330. package/src/sdk/bus/chat-daemon-control.ts +8 -28
  331. package/src/sdk/bus/chat-effect-journal.ts +10 -2
  332. package/src/sdk/bus/config-commands.ts +5 -4
  333. package/src/sdk/bus/config.ts +98 -0
  334. package/src/sdk/bus/conversation-store.ts +5 -29
  335. package/src/sdk/bus/daemon-paths.ts +2 -0
  336. package/src/sdk/bus/html-format.ts +20 -3
  337. package/src/sdk/bus/index.ts +778 -93
  338. package/src/sdk/bus/lifecycle-control-runtime.ts +91 -33
  339. package/src/sdk/bus/natives-augment.d.ts +26 -1
  340. package/src/sdk/bus/notification-service.ts +168 -20
  341. package/src/sdk/bus/rate-limit-pool.ts +58 -14
  342. package/src/sdk/bus/recent-activity.ts +188 -74
  343. package/src/sdk/bus/rich-document.ts +258 -0
  344. package/src/sdk/bus/rich-render.ts +62 -70
  345. package/src/sdk/bus/telegram-daemon-cli.ts +15 -59
  346. package/src/sdk/bus/telegram-daemon-contract.ts +9 -4
  347. package/src/sdk/bus/telegram-daemon.ts +1389 -237
  348. package/src/sdk/bus/threaded-inbound.ts +8 -3
  349. package/src/sdk/bus/threaded-render.ts +57 -1
  350. package/src/sdk/bus/topic-registry.ts +120 -13
  351. package/src/sdk/host/control/dispatch.ts +14 -2
  352. package/src/sdk/host/control/operations.ts +6 -1
  353. package/src/sdk/host/host.ts +31 -1
  354. package/src/sdk/host/query/handlers.ts +20 -22
  355. package/src/sdk/host/query/revision-store.ts +80 -57
  356. package/src/sdk/index.ts +1 -0
  357. package/src/sdk/protocol/operation-inventory.generated.json +943 -1907
  358. package/src/sdk/session-directory.ts +141 -0
  359. package/src/sdk/session.ts +458 -479
  360. package/src/session/agent-session.ts +1700 -583
  361. package/src/session/agent-storage.ts +18 -0
  362. package/src/session/cache-economics.ts +25 -8
  363. package/src/session/fallback-chain-controller.ts +53 -3
  364. package/src/session/internal/managed-session-scope.ts +2226 -0
  365. package/src/session/internal/managed-session-storage.ts +453 -0
  366. package/src/session/messages.ts +91 -2
  367. package/src/session/session-manager-internal.ts +33 -0
  368. package/src/session/session-manager.ts +1112 -333
  369. package/src/session/session-storage.ts +444 -39
  370. package/src/session/volatile-context-pruning.ts +78 -0
  371. package/src/setup/credential-auto-import.ts +2 -1
  372. package/src/setup/hermes/templates/operator-instructions.v1.md +1 -1
  373. package/src/setup/provider-onboarding.ts +36 -61
  374. package/src/setup/provider-presets.json +5 -0
  375. package/src/skill-state/active-state.ts +3 -13
  376. package/src/skill-state/{deep-interview-mutation-guard.ts → workflow-mutation-guard.ts} +47 -29
  377. package/src/skill-state/workflow-state-contract.ts +6 -41
  378. package/src/slash-commands/builtin-registry.ts +46 -11
  379. package/src/system-prompt.ts +37 -44
  380. package/src/task/agents.ts +19 -1
  381. package/src/task/executor.ts +90 -6
  382. package/src/task/index.ts +36 -21
  383. package/src/thinking.ts +21 -6
  384. package/src/tool-discovery/tool-index.ts +2 -134
  385. package/src/tools/ask.ts +157 -21
  386. package/src/tools/ast-edit.ts +1 -1
  387. package/src/tools/bash.ts +38 -0
  388. package/src/tools/browser/dead-tab-recovery.ts +78 -0
  389. package/src/tools/browser/tab-supervisor.ts +282 -36
  390. package/src/tools/computer.ts +10 -3
  391. package/src/tools/cron.ts +30 -16
  392. package/src/tools/eval.ts +1 -2
  393. package/src/tools/fetch.ts +11 -4
  394. package/src/tools/index.ts +76 -24
  395. package/src/tools/output-meta.ts +13 -5
  396. package/src/tools/read.ts +37 -1
  397. package/src/tools/resource-gc.ts +2 -2
  398. package/src/tools/search-tool-bm25.ts +11 -74
  399. package/src/utils/event-bus.ts +9 -4
  400. package/src/web/search/index.ts +3 -3
  401. package/dist/types/discovery/plugin-dir-roots.d.ts +0 -15
  402. package/dist/types/runtime-mcp/discoverable-tool-metadata.d.ts +0 -7
  403. package/src/discovery/plugin-dir-roots.ts +0 -28
  404. package/src/runtime-mcp/discoverable-tool-metadata.ts +0 -25
@@ -7,6 +7,7 @@ export type DiscoverableToolSource = "builtin" | "mcp" | "extension" | "custom";
7
7
  export interface DiscoverableTool {
8
8
  name: string;
9
9
  label: string;
10
+ description: string;
10
11
  /** Short BM25 corpus entry; falls back to description first 200 chars */
11
12
  summary: string;
12
13
  source: DiscoverableToolSource;
@@ -44,47 +45,6 @@ export interface DiscoverableToolSearchResult {
44
45
  score: number;
45
46
  }
46
47
 
47
- // ─── Legacy MCP-typed aliases (back-compat) ──────────────────────────────────
48
-
49
- /** @deprecated Use DiscoverableTool with source === "mcp" */
50
- export type DiscoverableMCPTool = Pick<
51
- DiscoverableTool,
52
- "name" | "label" | "schemaKeys" | "serverName" | "mcpToolName"
53
- > & { description: string };
54
-
55
- /** @deprecated Use DiscoverableToolServerSummary */
56
- export type DiscoverableMCPToolServerSummary = DiscoverableToolServerSummary;
57
-
58
- /** @deprecated Use DiscoverableToolSummary */
59
- export type DiscoverableMCPToolSummary = DiscoverableToolSummary;
60
-
61
- /** Tool object stored on legacy MCP index documents. Carries both legacy `description` and the
62
- * generic `summary`/`source` so the legacy index is structurally assignable to
63
- * DiscoverableToolSearchIndex (search functions read termFrequencies, not the tool fields). */
64
- export type DiscoverableMCPSearchTool = DiscoverableTool & { description: string };
65
-
66
- /** @deprecated Use DiscoverableToolSearchDocument */
67
- export interface DiscoverableMCPSearchDocument {
68
- tool: DiscoverableMCPSearchTool;
69
- termFrequencies: Map<string, number>;
70
- length: number;
71
- }
72
-
73
- /** @deprecated Use DiscoverableToolSearchIndex.
74
- * Documents on this index expose `tool.description` (legacy MCP shape) while still being
75
- * searchable via `searchDiscoverableTools`. */
76
- export interface DiscoverableMCPSearchIndex {
77
- documents: DiscoverableMCPSearchDocument[];
78
- averageLength: number;
79
- documentFrequencies: Map<string, number>;
80
- }
81
-
82
- /** @deprecated Use DiscoverableToolSearchResult */
83
- export interface DiscoverableMCPSearchResult {
84
- tool: DiscoverableMCPSearchTool;
85
- score: number;
86
- }
87
-
88
48
  // ─── BM25 Constants ───────────────────────────────────────────────────────────
89
49
 
90
50
  const BM25_K1 = 1.2;
@@ -194,6 +154,7 @@ export function getDiscoverableTool(
194
154
  return {
195
155
  name: tool.name,
196
156
  label: typeof toolRecord.label === "string" ? toolRecord.label : tool.name,
157
+ description: rawDescription,
197
158
  summary,
198
159
  source,
199
160
  serverName: typeof toolRecord.mcpServerName === "string" ? toolRecord.mcpServerName : undefined,
@@ -305,96 +266,3 @@ export function searchDiscoverableTools(
305
266
  .sort((left, right) => right.score - left.score || left.tool.name.localeCompare(right.tool.name))
306
267
  .slice(0, limit);
307
268
  }
308
-
309
- // ─── Legacy MCP-specific shims (back-compat wrappers) ────────────────────────
310
-
311
- /** @deprecated Use getDiscoverableTool */
312
- export function getDiscoverableMCPTool(tool: AgentTool): DiscoverableMCPTool | null {
313
- const toolRecord = tool as AgentTool & {
314
- label?: string;
315
- description?: string;
316
- mcpServerName?: string;
317
- mcpToolName?: string;
318
- parameters?: unknown;
319
- };
320
- if (!isMCPBridgeTool(toolRecord)) return null;
321
- return {
322
- name: tool.name,
323
- label: typeof toolRecord.label === "string" ? toolRecord.label : tool.name,
324
- description: typeof toolRecord.description === "string" ? toolRecord.description : "",
325
- serverName: typeof toolRecord.mcpServerName === "string" ? toolRecord.mcpServerName : undefined,
326
- mcpToolName: typeof toolRecord.mcpToolName === "string" ? toolRecord.mcpToolName : undefined,
327
- schemaKeys: getSchemaPropertyKeys(toolRecord.parameters),
328
- };
329
- }
330
-
331
- /** @deprecated Use collectDiscoverableTools with source filter */
332
- export function collectDiscoverableMCPTools(tools: Iterable<AgentTool>): DiscoverableMCPTool[] {
333
- const discoverable: DiscoverableMCPTool[] = [];
334
- for (const tool of tools) {
335
- const metadata = getDiscoverableMCPTool(tool);
336
- if (metadata) {
337
- discoverable.push(metadata);
338
- }
339
- }
340
- return discoverable;
341
- }
342
-
343
- /** @deprecated Use selectDiscoverableToolNamesByServer */
344
- export function selectDiscoverableMCPToolNamesByServer(
345
- tools: Iterable<DiscoverableMCPTool>,
346
- serverNames: ReadonlySet<string>,
347
- ): string[] {
348
- if (serverNames.size === 0) return [];
349
- return Array.from(tools)
350
- .filter(tool => tool.serverName !== undefined && serverNames.has(tool.serverName))
351
- .map(tool => tool.name);
352
- }
353
-
354
- /** @deprecated Use summarizeDiscoverableTools */
355
- export function summarizeDiscoverableMCPTools(tools: DiscoverableMCPTool[]): DiscoverableMCPToolSummary {
356
- const serverToolCounts = new Map<string, number>();
357
- for (const tool of tools) {
358
- if (!tool.serverName) continue;
359
- serverToolCounts.set(tool.serverName, (serverToolCounts.get(tool.serverName) ?? 0) + 1);
360
- }
361
- const servers = Array.from(serverToolCounts.entries())
362
- .sort(([left], [right]) => left.localeCompare(right))
363
- .map(([name, toolCount]) => ({ name, toolCount }));
364
- return {
365
- servers,
366
- toolCount: tools.length,
367
- };
368
- }
369
-
370
- /** @deprecated Use buildDiscoverableToolSearchIndex.
371
- * Builds an index whose documents preserve the legacy `description` field on each tool while
372
- * also carrying the generic `summary` (set from `description`) so the index remains usable
373
- * with `searchDiscoverableTools`. */
374
- export function buildDiscoverableMCPSearchIndex(tools: Iterable<DiscoverableMCPTool>): DiscoverableMCPSearchIndex {
375
- const adapted: DiscoverableMCPSearchTool[] = Array.from(tools).map(t => ({
376
- name: t.name,
377
- label: t.label,
378
- description: t.description,
379
- summary: t.description,
380
- source: "mcp" as DiscoverableToolSource,
381
- serverName: t.serverName,
382
- mcpToolName: t.mcpToolName,
383
- schemaKeys: t.schemaKeys,
384
- }));
385
- const generic = buildDiscoverableToolSearchIndex(adapted);
386
- // Documents reference `adapted` tools (with `description`), so the cast is sound.
387
- return generic as unknown as DiscoverableMCPSearchIndex;
388
- }
389
-
390
- /** @deprecated Use searchDiscoverableTools */
391
- export function searchDiscoverableMCPTools(
392
- index: DiscoverableMCPSearchIndex | DiscoverableToolSearchIndex,
393
- query: string,
394
- limit: number,
395
- ): DiscoverableMCPSearchResult[] {
396
- return searchDiscoverableTools(index as DiscoverableToolSearchIndex, query, limit) as DiscoverableMCPSearchResult[];
397
- }
398
-
399
- /** @deprecated Use formatDiscoverableToolServerSummary */
400
- export const formatDiscoverableMCPToolServerSummary = formatDiscoverableToolServerSummary;
package/src/tools/ask.ts CHANGED
@@ -66,29 +66,130 @@ const OptionItem = z.object({
66
66
  label: z.string().describe("display label"),
67
67
  });
68
68
 
69
+ const DeepInterviewIntentItem = z
70
+ .object({
71
+ id: z.string().regex(/^(artifact|surface|integration|constraint):[a-z0-9][a-z0-9._/-]{0,127}$/),
72
+ category: z.enum(["artifact", "surface", "integration", "constraint"]),
73
+ statement: z.string().min(1).max(1_000),
74
+ })
75
+ .strict()
76
+ .superRefine((value, context) => {
77
+ if (!value.id.startsWith(`${value.category}:`))
78
+ context.addIssue({ code: "custom", message: "intent ID must use its category prefix", path: ["id"] });
79
+ });
80
+
81
+ const DeepInterviewIntentContract = z
82
+ .object({
83
+ items: z.array(DeepInterviewIntentItem).min(1).max(64),
84
+ confirmation_options: z.array(z.string().min(1).max(200)).min(1).max(5),
85
+ })
86
+ .strict();
87
+
88
+ const DeepInterviewIntentReview = z
89
+ .object({
90
+ observed_items: z.array(DeepInterviewIntentItem).min(1).max(64),
91
+ supporting_substitutions: z
92
+ .array(
93
+ z
94
+ .object({
95
+ removed_id: z
96
+ .string()
97
+ .regex(/^(artifact|surface|integration|constraint):[a-z0-9][a-z0-9._/-]{0,127}$/),
98
+ replacement_ids: z
99
+ .array(z.string().regex(/^(artifact|surface|integration|constraint):[a-z0-9][a-z0-9._/-]{0,127}$/))
100
+ .min(1)
101
+ .max(64),
102
+ rationale: z.string().min(1).max(500),
103
+ })
104
+ .strict(),
105
+ )
106
+ .max(64),
107
+ approval_options: z.array(z.string().min(1).max(200)).min(1).max(5),
108
+ })
109
+ .strict();
110
+
69
111
  /** Optional structured deep-interview round metadata; when present the round is recorded automatically. */
70
- const DeepInterviewMeta = z.object({
71
- round_id: z.string().describe("stable optional round identity").optional(),
72
- round: z.number().int().nonnegative().describe("round number"),
73
- component: z.string().min(1).describe("targeted topology component"),
74
- dimension: z.string().min(1).describe("targeted clarity dimension"),
75
- ambiguity: z.number().min(0).max(1).describe("ambiguity at ask time (0..1)"),
76
- });
112
+ const DeepInterviewMeta = z
113
+ .object({
114
+ round_id: z.string().max(128).describe("stable optional round identity").optional(),
115
+ round: z.number().int().nonnegative().describe("round number"),
116
+ component: z.string().min(1).max(128).describe("targeted topology component"),
117
+ dimension: z.string().min(1).max(128).describe("targeted clarity dimension"),
118
+ ambiguity: z.number().min(0).max(1).describe("ambiguity at ask time (0..1)"),
119
+ intent_contract: DeepInterviewIntentContract.describe("Round-0 locked intent contract").optional(),
120
+ intent_review: DeepInterviewIntentReview.describe("Locked-intent reduction review").optional(),
121
+ })
122
+ .strict()
123
+ .superRefine((value, context) => {
124
+ if (
125
+ value.intent_contract &&
126
+ (value.round !== 0 || value.component !== "review-topology" || value.dimension !== "topology")
127
+ )
128
+ context.addIssue({
129
+ code: "custom",
130
+ message: "intent_contract requires Round 0 review-topology metadata",
131
+ path: ["intent_contract"],
132
+ });
133
+ if (value.intent_review && value.round === 0)
134
+ context.addIssue({
135
+ code: "custom",
136
+ message: "intent_review requires a post-Round-0 answer",
137
+ path: ["intent_review"],
138
+ });
139
+ if (value.intent_contract && value.intent_review)
140
+ context.addIssue({ code: "custom", message: "intent_contract and intent_review are mutually exclusive" });
141
+ });
77
142
 
78
143
  const WorkflowGateMeta = z.object({
79
144
  stage: z.enum(["deep-interview", "ralplan", "ultragoal"]).describe("workflow gate stage"),
80
145
  kind: z.enum(["question", "approval", "execution"]).describe("workflow gate kind"),
81
146
  });
82
147
 
83
- const QuestionItem = z.object({
84
- id: z.string().describe("question id"),
85
- question: z.string().describe("question text"),
86
- options: z.array(OptionItem).describe("available options"),
87
- multi: z.boolean().describe("allow multiple selections").optional(),
88
- recommended: z.number().describe("recommended option index").optional(),
89
- deepInterview: DeepInterviewMeta.describe("optional deep-interview round metadata").optional(),
90
- workflowGate: WorkflowGateMeta.describe("optional workflow gate stage/kind override").optional(),
91
- });
148
+ const QuestionItem = z
149
+ .object({
150
+ id: z.string().describe("question id"),
151
+ question: z.string().describe("question text"),
152
+ options: z.array(OptionItem).describe("available options"),
153
+ multi: z.boolean().describe("allow multiple selections").optional(),
154
+ recommended: z.number().describe("recommended option index").optional(),
155
+ deepInterview: DeepInterviewMeta.describe("optional deep-interview round metadata").optional(),
156
+ workflowGate: WorkflowGateMeta.describe("optional workflow gate stage/kind override").optional(),
157
+ })
158
+ .superRefine((value, context) => {
159
+ const labels = new Set(value.options.map(option => option.label));
160
+ if ((value.deepInterview?.intent_contract || value.deepInterview?.intent_review) && value.multi === true)
161
+ context.addIssue({ code: "custom", message: "intent gates must be single-select", path: ["multi"] });
162
+ const confirmationOptions = value.deepInterview?.intent_contract?.confirmation_options ?? [];
163
+ if (new Set(confirmationOptions).size !== confirmationOptions.length)
164
+ context.addIssue({
165
+ code: "custom",
166
+ message: "intent confirmation options must be unique",
167
+ path: ["deepInterview", "intent_contract"],
168
+ });
169
+ const approvalOptions = value.deepInterview?.intent_review?.approval_options ?? [];
170
+ if (new Set(approvalOptions).size !== approvalOptions.length)
171
+ context.addIssue({
172
+ code: "custom",
173
+ message: "intent approval options must be unique",
174
+ path: ["deepInterview", "intent_review"],
175
+ });
176
+ for (const label of value.deepInterview?.intent_contract?.confirmation_options ?? []) {
177
+ if (!labels.has(label))
178
+ context.addIssue({
179
+ code: "custom",
180
+ message: "intent confirmation option must be displayed",
181
+ path: ["deepInterview", "intent_contract"],
182
+ });
183
+ }
184
+ for (const label of value.deepInterview?.intent_review?.approval_options ?? []) {
185
+ if (!labels.has(label))
186
+ context.addIssue({
187
+ code: "custom",
188
+ message: "intent approval option must be displayed",
189
+ path: ["deepInterview", "intent_review"],
190
+ });
191
+ }
192
+ });
92
193
 
93
194
  export const askSchema = z.object({
94
195
  questions: z.array(QuestionItem).min(1).describe("questions to ask"),
@@ -133,7 +234,11 @@ function errorMessage(error: unknown): string {
133
234
  return error instanceof Error ? error.message : String(error);
134
235
  }
135
236
 
136
- async function awaitDeepInterviewRecorderPersistence(persistence: Promise<void>): Promise<void> {
237
+ async function awaitDeepInterviewRecorderPersistence(persistence: Promise<void>, required: boolean): Promise<void> {
238
+ if (required) {
239
+ await persistence;
240
+ return;
241
+ }
137
242
  let timeout: ReturnType<typeof setTimeout> | undefined;
138
243
  try {
139
244
  await Promise.race([
@@ -147,6 +252,7 @@ async function awaitDeepInterviewRecorderPersistence(persistence: Promise<void>)
147
252
  ]);
148
253
  } catch (error) {
149
254
  logger.warn(`ask: deep-interview round recording failed: ${errorMessage(error)}`);
255
+ if (required) throw error;
150
256
  } finally {
151
257
  if (timeout) clearTimeout(timeout);
152
258
  }
@@ -293,6 +399,7 @@ interface AskSingleQuestionOptions {
293
399
  scrollTitleRows?: number;
294
400
  otherOptionLabel?: string;
295
401
  clarificationOptionLabel?: string;
402
+ autoSelectOnTimeout?: boolean;
296
403
  onRemoteState?: (state: {
297
404
  interaction: "selector" | "custom_editor" | "clarification_editor";
298
405
  selectedCount: number;
@@ -334,7 +441,15 @@ async function askSingleQuestion(
334
441
  multi: boolean,
335
442
  options: AskSingleQuestionOptions = {},
336
443
  ): Promise<SelectionResult> {
337
- const { recommended, timeout, signal, initialSelection, navigation, scrollTitleRows } = options;
444
+ const {
445
+ recommended,
446
+ timeout,
447
+ signal,
448
+ initialSelection,
449
+ navigation,
450
+ scrollTitleRows,
451
+ autoSelectOnTimeout = true,
452
+ } = options;
338
453
  const doneLabel = getDoneOptionLabel();
339
454
  const otherOptionLabel = options.otherOptionLabel ?? OTHER_OPTION;
340
455
  const clarificationOptionLabel = options.clarificationOptionLabel;
@@ -632,12 +747,23 @@ async function askSingleQuestion(
632
747
  selectedOptions = [];
633
748
  }
634
749
  }
750
+ if (timedOut && !autoSelectOnTimeout) {
751
+ return {
752
+ selectedOptions: [],
753
+ customInput: undefined,
754
+ timedOut,
755
+ ...(navigation?.allowForward ? { navigation: "forward" as const } : {}),
756
+ };
757
+ }
635
758
  if (navigation?.allowForward) {
636
759
  return { selectedOptions, customInput, timedOut, navigation: "forward" };
637
760
  }
638
761
  }
639
762
 
640
- if (timedOut && selectedOptions.length === 0 && customInput === undefined) {
763
+ if (timedOut && !autoSelectOnTimeout) {
764
+ return { selectedOptions: [], customInput: undefined, timedOut };
765
+ }
766
+ if (timedOut && selectedOptions.length === 0 && customInput === undefined && autoSelectOnTimeout) {
641
767
  selectedOptions = getAutoSelectionOnTimeout(optionLabels, recommended);
642
768
  }
643
769
 
@@ -724,11 +850,14 @@ export class AskTool implements AgentTool<typeof askSchema, AskToolDetails> {
724
850
  ambiguity: meta.ambiguity,
725
851
  selectedOptions,
726
852
  customInput,
853
+ intent_contract: meta.intent_contract,
854
+ intent_review: meta.intent_review,
727
855
  },
728
856
  { sessionId },
729
857
  ).then(async () => {
730
858
  await syncDeepInterviewRecorderHud(cwd, statePath, sessionId);
731
859
  }),
860
+ meta.intent_contract !== undefined || meta.intent_review !== undefined,
732
861
  );
733
862
  }
734
863
 
@@ -1061,6 +1190,7 @@ export class AskTool implements AgentTool<typeof askSchema, AskToolDetails> {
1061
1190
  navigation: options?.navigation,
1062
1191
  scrollTitleRows: isDeepInterviewQuestion ? DEEP_INTERVIEW_SELECTOR_SCROLL_TITLE_ROWS : undefined,
1063
1192
  otherOptionLabel,
1193
+ autoSelectOnTimeout: !q.deepInterview?.intent_contract && !q.deepInterview?.intent_review,
1064
1194
  clarificationOptionLabel,
1065
1195
  onRemoteState: state => {
1066
1196
  activeRemoteRequest = {
@@ -1145,7 +1275,10 @@ export class AskTool implements AgentTool<typeof askSchema, AskToolDetails> {
1145
1275
  context?.abort();
1146
1276
  throw new ToolAbortError("Ask tool was cancelled by the user");
1147
1277
  }
1148
- if (clarificationQuestion === undefined) {
1278
+ if (
1279
+ clarificationQuestion === undefined &&
1280
+ !(timedOut && (q.deepInterview?.intent_contract || q.deepInterview?.intent_review))
1281
+ ) {
1149
1282
  await this.#recordDeepInterviewRound(q, selectedOptions, customInput);
1150
1283
  }
1151
1284
  const details: AskToolDetails = {
@@ -1223,7 +1356,10 @@ export class AskTool implements AgentTool<typeof askSchema, AskToolDetails> {
1223
1356
  clarificationQuestion,
1224
1357
  };
1225
1358
 
1226
- if (clarificationQuestion === undefined) {
1359
+ if (
1360
+ clarificationQuestion === undefined &&
1361
+ !(timedOut && (q.deepInterview?.intent_contract || q.deepInterview?.intent_review))
1362
+ ) {
1227
1363
  await this.#recordDeepInterviewRound(q, selectedOptions, customInput);
1228
1364
  }
1229
1365
 
@@ -9,7 +9,7 @@ import type { RenderResultOptions } from "../extensibility/custom-tools/types";
9
9
  import { computeLineHash, HL_BODY_SEP } from "../hashline/hash";
10
10
  import type { Theme } from "../modes/theme/theme";
11
11
  import astEditDescription from "../prompts/tools/ast-edit.md" with { type: "text" };
12
- import { assertWorkflowMutationRawPathsAllowed } from "../skill-state/deep-interview-mutation-guard";
12
+ import { assertWorkflowMutationRawPathsAllowed } from "../skill-state/workflow-mutation-guard";
13
13
  import { Ellipsis, fileHyperlink, renderStatusLine, renderTreeList, truncateToWidth } from "../tui";
14
14
  import { resolveFileDisplayMode } from "../utils/file-display-mode";
15
15
  import type { ToolSession } from ".";
package/src/tools/bash.ts CHANGED
@@ -99,6 +99,43 @@ export interface BashToolDetails {
99
99
  };
100
100
  }
101
101
 
102
+ /** Project only a bare executable name; commands and their output are never notification-safe. */
103
+ export function summarizeBashToolActivity(kind: "args" | "result", value: unknown): string | undefined {
104
+ if (!value || typeof value !== "object" || Array.isArray(value)) return undefined;
105
+ const record = value as Record<string, unknown>;
106
+ if (kind === "args") {
107
+ const command = record.command;
108
+ if (typeof command !== "string") return undefined;
109
+ const program = command.trim().match(/^([A-Za-z][A-Za-z0-9_.+-]*)\b/)?.[1];
110
+ if (
111
+ !program ||
112
+ program.length > 80 ||
113
+ /(?:api[-_ ]?key|access[-_ ]?token|bearer|secret|password|\b(?:sk|pk|rk)-)/i.test(program)
114
+ ) {
115
+ return undefined;
116
+ }
117
+ return program;
118
+ }
119
+
120
+ const output =
121
+ typeof record.output === "string"
122
+ ? record.output
123
+ : Array.isArray(record.content)
124
+ ? record.content
125
+ .filter(
126
+ (block): block is { type: unknown; text: unknown } =>
127
+ typeof block === "object" && block !== null && "type" in block && "text" in block,
128
+ )
129
+ .filter(block => block.type === "text" && typeof block.text === "string")
130
+ .map(block => block.text as string)
131
+ .join("\n")
132
+ : undefined;
133
+ if (output === undefined) return undefined;
134
+ const exitCode = typeof record.exitCode === "number" ? `exit=${record.exitCode}` : "completed";
135
+ const lines = output.length === 0 ? 0 : output.split("\n").length;
136
+ return `${exitCode}, ${lines} lines, ${Buffer.byteLength(output, "utf-8")} bytes`;
137
+ }
138
+
102
139
  export interface BashToolOptions {}
103
140
 
104
141
  type ManagedBashJobCompletion =
@@ -248,6 +285,7 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
248
285
  readonly parameters: BashToolSchema;
249
286
  readonly concurrency = "exclusive";
250
287
  readonly strict = true;
288
+ readonly safeSummary = summarizeBashToolActivity;
251
289
  readonly #asyncEnabled: boolean;
252
290
  readonly #autoBackgroundEnabled: boolean;
253
291
  readonly #autoBackgroundThresholdMs: number;
@@ -0,0 +1,78 @@
1
+ export type DeadTabRecoveryConsumeStatus = "consumed" | "expired_or_missing" | "owner_mismatch";
2
+
3
+ export interface DeadTabRecoveryConsumeResult<T> {
4
+ status: DeadTabRecoveryConsumeStatus;
5
+ descriptor?: T;
6
+ }
7
+
8
+ interface StoredDescriptor<T> {
9
+ descriptor: T;
10
+ ownerId: string | undefined;
11
+ expiresAt: number;
12
+ }
13
+
14
+ interface DeadTabRecoveryDeps {
15
+ now(): number;
16
+ onPeek(): void;
17
+ }
18
+
19
+ const DEFAULT_TTL_MS = 30_000;
20
+ const descriptors = new Map<string, StoredDescriptor<unknown>>();
21
+ let deps: DeadTabRecoveryDeps = { now: () => Date.now(), onPeek: () => {} };
22
+
23
+ /** Store a short-lived immutable recovery descriptor for a dead tab worker. */
24
+ export function registerDeadTabRecovery<T extends object>(
25
+ name: string,
26
+ ownerId: string | undefined,
27
+ descriptor: T,
28
+ ttlMs = DEFAULT_TTL_MS,
29
+ ): void {
30
+ descriptors.set(name, { descriptor: Object.freeze(descriptor), ownerId, expiresAt: deps.now() + ttlMs });
31
+ }
32
+
33
+ /**
34
+ * Check whether a recovery descriptor may be consumed by this owner. The test hook is
35
+ * intentionally synchronous: recovery must not yield between this check and consume.
36
+ */
37
+ export function peekDeadTabRecovery<T>(name: string, ownerId: string | undefined): DeadTabRecoveryConsumeResult<T> {
38
+ const stored = descriptors.get(name);
39
+ const result: DeadTabRecoveryConsumeResult<T> =
40
+ !stored || stored.expiresAt <= deps.now()
41
+ ? { status: "expired_or_missing" }
42
+ : stored.ownerId !== ownerId
43
+ ? { status: "owner_mismatch" }
44
+ : { status: "consumed", descriptor: stored.descriptor as T };
45
+ deps.onPeek();
46
+ return result;
47
+ }
48
+
49
+ /** Consume only a live descriptor belonging to the expected owner. */
50
+ export function consumeDeadTabRecovery<T>(name: string, ownerId: string | undefined): DeadTabRecoveryConsumeResult<T> {
51
+ const stored = descriptors.get(name);
52
+ if (!stored || stored.expiresAt <= deps.now()) {
53
+ if (stored) descriptors.delete(name);
54
+ return { status: "expired_or_missing" };
55
+ }
56
+ if (stored.ownerId !== ownerId) return { status: "owner_mismatch" };
57
+ descriptors.delete(name);
58
+ return { status: "consumed", descriptor: stored.descriptor as T };
59
+ }
60
+
61
+ export function discardDeadTabRecovery(name: string): void {
62
+ descriptors.delete(name);
63
+ }
64
+
65
+ /** Whether an unconsumed descriptor remains live at the supplied policy clock. */
66
+ export function isDeadTabRecoveryLive(name: string, now: number): boolean {
67
+ const stored = descriptors.get(name);
68
+ return stored !== undefined && stored.expiresAt > now;
69
+ }
70
+
71
+ export function __setDeadTabRecoveryDepsForTest(overrides: Partial<DeadTabRecoveryDeps>): void {
72
+ deps = { ...deps, ...overrides };
73
+ }
74
+
75
+ export function __resetDeadTabRecoveryForTest(): void {
76
+ descriptors.clear();
77
+ deps = { now: () => Date.now(), onPeek: () => {} };
78
+ }