@gajae-code/coding-agent 0.11.0 → 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 (418) hide show
  1. package/CHANGELOG.md +63 -1
  2. package/dist/types/async/job-manager.d.ts +46 -7
  3. package/dist/types/cli/config-cli.d.ts +11 -1
  4. package/dist/types/cli/notify-cli.d.ts +1 -0
  5. package/dist/types/cli/session-picker.d.ts +2 -1
  6. package/dist/types/cli/setup-cli.d.ts +1 -1
  7. package/dist/types/commands/mcp-serve.d.ts +33 -0
  8. package/dist/types/commands/mcp.d.ts +1 -1
  9. package/dist/types/commands/notify.d.ts +0 -2
  10. package/dist/types/commands/sdk.d.ts +1 -1
  11. package/dist/types/config/atomic-yaml-patch.d.ts +18 -0
  12. package/dist/types/config/file-lock.d.ts +14 -4
  13. package/dist/types/config/keybindings.d.ts +42 -1
  14. package/dist/types/config/model-auth.d.ts +3 -0
  15. package/dist/types/config/model-bindings-applier.d.ts +13 -0
  16. package/dist/types/config/model-discovery-manager.d.ts +49 -0
  17. package/dist/types/config/model-equivalence.d.ts +20 -0
  18. package/dist/types/config/model-registry.d.ts +16 -15
  19. package/dist/types/config/model-resolver.d.ts +28 -18
  20. package/dist/types/config/models-config-schema.d.ts +11 -0
  21. package/dist/types/config/settings-schema.d.ts +56 -1
  22. package/dist/types/config/settings.d.ts +14 -11
  23. package/dist/types/coordinator-mcp/policy.d.ts +5 -0
  24. package/dist/types/coordinator-mcp/question-gate-codec.d.ts +129 -0
  25. package/dist/types/coordinator-mcp/question-state.d.ts +356 -0
  26. package/dist/types/coordinator-mcp/server.d.ts +4 -0
  27. package/dist/types/discovery/helpers.d.ts +0 -6
  28. package/dist/types/edit/index.d.ts +3 -0
  29. package/dist/types/eval/py/env.d.ts +9 -0
  30. package/dist/types/extensibility/extensions/loader.d.ts +2 -1
  31. package/dist/types/extensibility/extensions/runner.d.ts +2 -2
  32. package/dist/types/extensibility/extensions/types.d.ts +34 -3
  33. package/dist/types/extensibility/hooks/runner.d.ts +1 -1
  34. package/dist/types/extensibility/shared-events.d.ts +2 -0
  35. package/dist/types/gjc-runtime/deep-interview-recorder.d.ts +10 -1
  36. package/dist/types/gjc-runtime/deep-interview-state.d.ts +44 -0
  37. package/dist/types/gjc-runtime/goal-mode-request.d.ts +11 -1
  38. package/dist/types/gjc-runtime/launch-worktree.d.ts +4 -2
  39. package/dist/types/gjc-runtime/linux-proc.d.ts +29 -0
  40. package/dist/types/gjc-runtime/session-resolution.d.ts +2 -2
  41. package/dist/types/gjc-runtime/state-migrations.d.ts +1 -1
  42. package/dist/types/gjc-runtime/state-writer.d.ts +2 -1
  43. package/dist/types/gjc-runtime/team-launch.d.ts +59 -0
  44. package/dist/types/gjc-runtime/team-notify.d.ts +45 -0
  45. package/dist/types/gjc-runtime/team-runtime.d.ts +29 -121
  46. package/dist/types/gjc-runtime/team-store.d.ts +160 -0
  47. package/dist/types/gjc-runtime/team-workers.d.ts +78 -0
  48. package/dist/types/gjc-runtime/tmux-owner-isolation.d.ts +8 -0
  49. package/dist/types/gjc-runtime/ultragoal-change-set.d.ts +13 -0
  50. package/dist/types/gjc-runtime/ultragoal-evidence.d.ts +38 -0
  51. package/dist/types/gjc-runtime/ultragoal-guard.d.ts +7 -0
  52. package/dist/types/gjc-runtime/ultragoal-pipeline.d.ts +23 -0
  53. package/dist/types/gjc-runtime/ultragoal-receipt-freshness.d.ts +11 -0
  54. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +55 -33
  55. package/dist/types/gjc-runtime/workflow-cli-common.d.ts +8 -0
  56. package/dist/types/gjc-runtime/workflow-manifest.d.ts +3 -0
  57. package/dist/types/goals/continuation-timeout-guard.d.ts +22 -0
  58. package/dist/types/goals/runtime.d.ts +1 -0
  59. package/dist/types/goals/state.d.ts +8 -0
  60. package/dist/types/harness-control-plane/lifecycle-reconciliation.d.ts +17 -0
  61. package/dist/types/harness-control-plane/phase-rollup.d.ts +4 -7
  62. package/dist/types/harness-control-plane/receipt-ingest.d.ts +5 -0
  63. package/dist/types/harness-control-plane/receipt-spool.d.ts +4 -0
  64. package/dist/types/hindsight/state.d.ts +11 -4
  65. package/dist/types/lsp/lspmux.d.ts +5 -3
  66. package/dist/types/lsp/path-trust.d.ts +1 -0
  67. package/dist/types/main.d.ts +3 -2
  68. package/dist/types/memories/storage.d.ts +1 -0
  69. package/dist/types/modes/action-registry.d.ts +29 -0
  70. package/dist/types/modes/components/chrome.d.ts +14 -0
  71. package/dist/types/modes/components/command-palette.d.ts +27 -0
  72. package/dist/types/modes/components/custom-provider-wizard.d.ts +1 -0
  73. package/dist/types/modes/components/index.d.ts +2 -1
  74. package/dist/types/modes/components/pet-selector.d.ts +1 -1
  75. package/dist/types/modes/components/plan-preview-overlay.d.ts +43 -0
  76. package/dist/types/modes/components/queue-mode-selector.d.ts +1 -1
  77. package/dist/types/modes/components/queue-pane.d.ts +12 -0
  78. package/dist/types/modes/components/read-tool-group.d.ts +6 -0
  79. package/dist/types/modes/components/session-observer-overlay.d.ts +3 -4
  80. package/dist/types/modes/components/sessions-dashboard.d.ts +32 -0
  81. package/dist/types/modes/components/settings-selector.d.ts +1 -1
  82. package/dist/types/modes/components/show-images-selector.d.ts +1 -1
  83. package/dist/types/modes/components/status-line/types.d.ts +1 -1
  84. package/dist/types/modes/components/status-line.d.ts +1 -94
  85. package/dist/types/modes/components/tasks-pane.d.ts +15 -0
  86. package/dist/types/modes/components/theme-selector.d.ts +1 -1
  87. package/dist/types/modes/components/tool-execution.d.ts +15 -0
  88. package/dist/types/modes/components/tool-status-header.d.ts +111 -0
  89. package/dist/types/modes/components/transcript-viewer-overlay.d.ts +42 -0
  90. package/dist/types/modes/controllers/command-controller.d.ts +2 -2
  91. package/dist/types/modes/controllers/extension-ui-controller.d.ts +1 -0
  92. package/dist/types/modes/controllers/goal-mode-controller.d.ts +62 -0
  93. package/dist/types/modes/controllers/input-controller.d.ts +8 -1
  94. package/dist/types/modes/controllers/mode-gate.d.ts +8 -0
  95. package/dist/types/modes/controllers/plan-mode-controller.d.ts +65 -0
  96. package/dist/types/modes/controllers/selector-controller.d.ts +15 -3
  97. package/dist/types/modes/controllers/stt-controller.d.ts +26 -0
  98. package/dist/types/modes/interactive-mode.d.ts +21 -19
  99. package/dist/types/modes/jobs-observer.d.ts +2 -0
  100. package/dist/types/modes/shared/agent-wire/deep-interview-gate.d.ts +4 -11
  101. package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +21 -2
  102. package/dist/types/modes/shared/agent-wire/workflow-gate-types.d.ts +31 -0
  103. package/dist/types/modes/tasks-aggregator.d.ts +39 -0
  104. package/dist/types/modes/transcript-item-registry.d.ts +60 -0
  105. package/dist/types/modes/types.d.ts +22 -15
  106. package/dist/types/modes/utils/ui-helpers.d.ts +2 -2
  107. package/dist/types/runtime-mcp/manager.d.ts +1 -1
  108. package/dist/types/sdk/broker/broker.d.ts +78 -12
  109. package/dist/types/sdk/broker/ensure.d.ts +9 -0
  110. package/dist/types/sdk/broker/lifecycle-codec.d.ts +4 -0
  111. package/dist/types/sdk/broker/lifecycle-ledger.d.ts +15 -1
  112. package/dist/types/sdk/broker/lifecycle.d.ts +6 -2
  113. package/dist/types/sdk/broker/process-incarnation.d.ts +2 -0
  114. package/dist/types/sdk/broker/session-index.d.ts +0 -1
  115. package/dist/types/sdk/broker/state-version.d.ts +2 -0
  116. package/dist/types/sdk/bus/chat-effect-journal.d.ts +1 -0
  117. package/dist/types/sdk/bus/config-commands.d.ts +1 -1
  118. package/dist/types/sdk/bus/config.d.ts +11 -0
  119. package/dist/types/sdk/bus/daemon-paths.d.ts +1 -0
  120. package/dist/types/sdk/bus/discord-daemon.d.ts +5 -0
  121. package/dist/types/sdk/bus/html-format.d.ts +3 -2
  122. package/dist/types/sdk/bus/index.d.ts +27 -0
  123. package/dist/types/sdk/bus/lifecycle-control-runtime.d.ts +4 -0
  124. package/dist/types/sdk/bus/notification-service.d.ts +20 -0
  125. package/dist/types/sdk/bus/rate-limit-pool.d.ts +13 -2
  126. package/dist/types/sdk/bus/recent-activity.d.ts +21 -12
  127. package/dist/types/sdk/bus/rich-document.d.ts +7 -0
  128. package/dist/types/sdk/bus/rich-render.d.ts +18 -41
  129. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +9 -4
  130. package/dist/types/sdk/bus/telegram-daemon.d.ts +69 -3
  131. package/dist/types/sdk/bus/threaded-inbound.d.ts +1 -1
  132. package/dist/types/sdk/bus/threaded-render.d.ts +13 -0
  133. package/dist/types/sdk/bus/topic-registry.d.ts +24 -2
  134. package/dist/types/sdk/host/control/operations.d.ts +1 -1
  135. package/dist/types/sdk/host/host.d.ts +2 -0
  136. package/dist/types/sdk/index.d.ts +1 -0
  137. package/dist/types/sdk/session-directory.d.ts +56 -0
  138. package/dist/types/session/agent-session.d.ts +82 -47
  139. package/dist/types/session/agent-storage.d.ts +7 -0
  140. package/dist/types/session/fallback-chain-controller.d.ts +10 -2
  141. package/dist/types/session/internal/managed-session-scope.d.ts +102 -0
  142. package/dist/types/session/internal/managed-session-storage.d.ts +38 -0
  143. package/dist/types/session/messages.d.ts +16 -0
  144. package/dist/types/session/session-manager-internal.d.ts +14 -0
  145. package/dist/types/session/session-manager.d.ts +82 -12
  146. package/dist/types/session/session-storage.d.ts +43 -3
  147. package/dist/types/session/volatile-context-pruning.d.ts +15 -0
  148. package/dist/types/skill-state/{deep-interview-mutation-guard.d.ts → workflow-mutation-guard.d.ts} +24 -8
  149. package/dist/types/skill-state/workflow-state-contract.d.ts +1 -3
  150. package/dist/types/slash-commands/builtin-registry.d.ts +4 -1
  151. package/dist/types/system-prompt.d.ts +2 -11
  152. package/dist/types/task/executor.d.ts +3 -1
  153. package/dist/types/thinking.d.ts +7 -0
  154. package/dist/types/tool-discovery/tool-index.d.ts +1 -50
  155. package/dist/types/tools/ask.d.ts +64 -2
  156. package/dist/types/tools/bash.d.ts +3 -0
  157. package/dist/types/tools/browser/dead-tab-recovery.d.ts +24 -0
  158. package/dist/types/tools/browser/tab-supervisor.d.ts +21 -0
  159. package/dist/types/tools/cron.d.ts +2 -0
  160. package/dist/types/tools/fetch.d.ts +1 -0
  161. package/dist/types/tools/index.d.ts +30 -15
  162. package/dist/types/tools/output-meta.d.ts +1 -0
  163. package/dist/types/tools/read.d.ts +3 -0
  164. package/dist/types/tools/search-tool-bm25.d.ts +3 -4
  165. package/dist/types/tools/subagent-render.d.ts +1 -0
  166. package/dist/types/tools/subagent.d.ts +6 -1
  167. package/dist/types/utils/event-bus.d.ts +1 -1
  168. package/dist/types/web/search/index.d.ts +3 -1
  169. package/package.json +21 -9
  170. package/scripts/build-sdk-package-smoke.ts +39 -1
  171. package/scripts/generate-hotkeys-docs.ts +74 -0
  172. package/scripts/generate-sdk-operation-inventory.ts +64 -20
  173. package/scripts/verify-gjc-sdk-canonicalization.ts +182 -2
  174. package/src/async/job-manager.ts +455 -69
  175. package/src/cli/config-cli.ts +75 -2
  176. package/src/cli/notify-cli.ts +92 -26
  177. package/src/cli/session-picker.ts +20 -3
  178. package/src/cli/setup-cli.ts +1 -1
  179. package/src/cli.ts +1 -1
  180. package/src/commands/config.ts +1 -1
  181. package/src/commands/harness.ts +34 -106
  182. package/src/commands/launch.ts +6 -4
  183. package/src/commands/mcp-serve.ts +85 -8
  184. package/src/commands/mcp.ts +2 -2
  185. package/src/commands/notify.ts +8 -4
  186. package/src/commands/sdk.ts +61 -40
  187. package/src/commands/ultragoal.ts +4 -1
  188. package/src/config/atomic-yaml-patch.ts +80 -13
  189. package/src/config/file-lock.ts +105 -43
  190. package/src/config/keybindings.ts +64 -20
  191. package/src/config/model-auth.ts +9 -0
  192. package/src/config/model-bindings-applier.ts +139 -0
  193. package/src/config/model-discovery-manager.ts +224 -0
  194. package/src/config/model-equivalence.ts +66 -0
  195. package/src/config/model-registry.ts +169 -302
  196. package/src/config/model-resolver.ts +361 -369
  197. package/src/config/models-config-schema.ts +5 -4
  198. package/src/config/settings-schema.ts +159 -2
  199. package/src/config/settings.ts +458 -482
  200. package/src/coordinator-mcp/policy.ts +76 -11
  201. package/src/coordinator-mcp/question-gate-codec.ts +274 -0
  202. package/src/coordinator-mcp/question-state.ts +778 -0
  203. package/src/coordinator-mcp/server.ts +1702 -238
  204. package/src/debug/index.ts +1 -1
  205. package/src/defaults/gjc/skills/deep-interview/SKILL.md +13 -1
  206. package/src/defaults/gjc/skills/team/SKILL.md +16 -0
  207. package/src/discovery/helpers.ts +1 -50
  208. package/src/edit/index.ts +64 -0
  209. package/src/eval/py/env.ts +26 -0
  210. package/src/eval/py/kernel.ts +5 -3
  211. package/src/extensibility/extensions/loader.ts +9 -1
  212. package/src/extensibility/extensions/runner.ts +12 -3
  213. package/src/extensibility/extensions/types.ts +39 -1
  214. package/src/extensibility/gjc-plugins/installer.ts +16 -16
  215. package/src/extensibility/hooks/runner.ts +2 -2
  216. package/src/extensibility/runtime-skill-discovery.ts +33 -13
  217. package/src/extensibility/shared-events.ts +2 -0
  218. package/src/gjc-runtime/deep-interview-recorder.ts +63 -3
  219. package/src/gjc-runtime/deep-interview-runtime.ts +76 -27
  220. package/src/gjc-runtime/deep-interview-state.ts +317 -5
  221. package/src/gjc-runtime/goal-mode-request.ts +55 -8
  222. package/src/gjc-runtime/launch-tmux.ts +2 -5
  223. package/src/gjc-runtime/launch-worktree.ts +5 -5
  224. package/src/gjc-runtime/linux-proc.ts +71 -0
  225. package/src/gjc-runtime/ralplan-runtime.ts +74 -90
  226. package/src/gjc-runtime/session-resolution.ts +18 -3
  227. package/src/gjc-runtime/session-state-sidecar.ts +6 -107
  228. package/src/gjc-runtime/state-migrations.ts +1 -1
  229. package/src/gjc-runtime/state-runtime.ts +320 -249
  230. package/src/gjc-runtime/state-writer.ts +36 -40
  231. package/src/gjc-runtime/team-launch.ts +319 -0
  232. package/src/gjc-runtime/team-notify.ts +326 -0
  233. package/src/gjc-runtime/team-runtime.ts +1099 -1482
  234. package/src/gjc-runtime/team-store.ts +828 -0
  235. package/src/gjc-runtime/team-workers.ts +962 -0
  236. package/src/gjc-runtime/tmux-owner-isolation-cli.ts +2 -11
  237. package/src/gjc-runtime/tmux-owner-isolation.ts +14 -9
  238. package/src/gjc-runtime/tmux-sessions.ts +4 -21
  239. package/src/gjc-runtime/ultragoal-change-set.ts +172 -0
  240. package/src/gjc-runtime/ultragoal-evidence.ts +874 -0
  241. package/src/gjc-runtime/ultragoal-guard.ts +83 -12
  242. package/src/gjc-runtime/ultragoal-pipeline.ts +306 -0
  243. package/src/gjc-runtime/ultragoal-receipt-freshness.ts +102 -1
  244. package/src/gjc-runtime/ultragoal-runtime.ts +156 -1319
  245. package/src/gjc-runtime/workflow-cli-common.ts +30 -0
  246. package/src/gjc-runtime/workflow-manifest.generated.json +58 -0
  247. package/src/gjc-runtime/workflow-manifest.ts +18 -0
  248. package/src/goals/continuation-timeout-guard.ts +79 -0
  249. package/src/goals/runtime.ts +7 -5
  250. package/src/goals/state.ts +18 -0
  251. package/src/harness-control-plane/lifecycle-reconciliation.ts +64 -0
  252. package/src/harness-control-plane/phase-rollup.ts +4 -7
  253. package/src/harness-control-plane/receipt-ingest.ts +5 -0
  254. package/src/harness-control-plane/receipt-spool.ts +51 -7
  255. package/src/harness-control-plane/session-lease.ts +12 -130
  256. package/src/hindsight/backend.ts +26 -27
  257. package/src/hindsight/state.ts +101 -32
  258. package/src/hooks/skill-state.ts +17 -11
  259. package/src/internal-urls/docs-index.generated.ts +21 -18
  260. package/src/lsp/client.ts +1 -1
  261. package/src/lsp/config.ts +145 -26
  262. package/src/lsp/index.ts +1 -1
  263. package/src/lsp/lspmux.ts +39 -10
  264. package/src/lsp/path-trust.ts +81 -0
  265. package/src/main.ts +28 -8
  266. package/src/memories/index.ts +1 -0
  267. package/src/memories/storage.ts +6 -2
  268. package/src/modes/action-registry.ts +165 -0
  269. package/src/modes/components/chrome.ts +40 -0
  270. package/src/modes/components/command-palette.ts +168 -0
  271. package/src/modes/components/custom-editor.ts +1 -1
  272. package/src/modes/components/custom-provider-wizard.ts +51 -14
  273. package/src/modes/components/index.ts +2 -1
  274. package/src/modes/components/pet-selector.ts +11 -17
  275. package/src/modes/components/plan-preview-overlay.ts +295 -0
  276. package/src/modes/components/queue-mode-selector.ts +10 -27
  277. package/src/modes/components/queue-pane.ts +79 -0
  278. package/src/modes/components/read-tool-group.ts +13 -0
  279. package/src/modes/components/session-observer-overlay.ts +207 -772
  280. package/src/modes/components/sessions-dashboard.ts +181 -0
  281. package/src/modes/components/settings-selector.ts +1 -1
  282. package/src/modes/components/show-images-selector.ts +10 -24
  283. package/src/modes/components/status-line/types.ts +1 -1
  284. package/src/modes/components/status-line.ts +1 -969
  285. package/src/modes/components/tasks-pane.ts +73 -0
  286. package/src/modes/components/theme-selector.ts +11 -31
  287. package/src/modes/components/tool-execution.ts +22 -0
  288. package/src/modes/components/tool-status-header.ts +1056 -0
  289. package/src/modes/components/transcript-viewer-overlay.ts +384 -0
  290. package/src/modes/controllers/btw-controller.ts +1 -0
  291. package/src/modes/controllers/command-controller.ts +9 -15
  292. package/src/modes/controllers/event-controller.ts +3 -2
  293. package/src/modes/controllers/extension-ui-controller.ts +72 -25
  294. package/src/modes/controllers/goal-mode-controller.ts +474 -0
  295. package/src/modes/controllers/input-controller.ts +764 -229
  296. package/src/modes/controllers/mode-gate.ts +24 -0
  297. package/src/modes/controllers/plan-mode-controller.ts +517 -0
  298. package/src/modes/controllers/selector-controller.ts +225 -10
  299. package/src/modes/controllers/stt-controller.ts +125 -0
  300. package/src/modes/interactive-mode.ts +302 -1151
  301. package/src/modes/jobs-observer.ts +3 -0
  302. package/src/modes/runtime-init.ts +8 -0
  303. package/src/modes/shared/agent-wire/deep-interview-gate.ts +31 -106
  304. package/src/modes/shared/agent-wire/workflow-gate-broker.ts +78 -19
  305. package/src/modes/shared/agent-wire/workflow-gate-types.ts +177 -0
  306. package/src/modes/tasks-aggregator.ts +199 -0
  307. package/src/modes/transcript-item-registry.ts +229 -0
  308. package/src/modes/types.ts +47 -20
  309. package/src/modes/utils/ui-helpers.ts +17 -9
  310. package/src/prompts/agent-fragments/ralplan-persistence.md +6 -0
  311. package/src/prompts/agent-fragments/restricted-bash.md +1 -0
  312. package/src/prompts/agents/architect.md +2 -8
  313. package/src/prompts/agents/critic.md +2 -8
  314. package/src/prompts/agents/executor.md +3 -0
  315. package/src/prompts/agents/planner.md +4 -12
  316. package/src/prompts/system/custom-system-prompt.md +1 -23
  317. package/src/prompts/system/plan-mode-approved.md +8 -0
  318. package/src/prompts/system/system-prompt.md +17 -96
  319. package/src/prompts/tools/bash.md +4 -4
  320. package/src/prompts/tools/browser.md +15 -52
  321. package/src/prompts/tools/find.md +2 -2
  322. package/src/prompts/tools/hashline.md +13 -55
  323. package/src/prompts/tools/read.md +3 -6
  324. package/src/prompts/tools/search-tool-bm25.md +0 -2
  325. package/src/prompts/tools/search.md +2 -4
  326. package/src/prompts/tools/skill-discovery.md +1 -2
  327. package/src/prompts/tools/task.md +1 -1
  328. package/src/runtime-mcp/manager.ts +1 -1
  329. package/src/sdk/broker/broker.ts +206 -78
  330. package/src/sdk/broker/discovery.ts +21 -2
  331. package/src/sdk/broker/ensure.ts +85 -25
  332. package/src/sdk/broker/lifecycle-codec.ts +11 -0
  333. package/src/sdk/broker/lifecycle-ledger.ts +371 -74
  334. package/src/sdk/broker/lifecycle.ts +1399 -142
  335. package/src/sdk/broker/process-incarnation.ts +5 -13
  336. package/src/sdk/broker/session-index.ts +145 -56
  337. package/src/sdk/broker/state-version.ts +21 -0
  338. package/src/sdk/broker/transport.ts +1 -1
  339. package/src/sdk/bus/chat-daemon-cli.ts +2 -0
  340. package/src/sdk/bus/chat-daemon-control.ts +8 -28
  341. package/src/sdk/bus/chat-effect-journal.ts +14 -4
  342. package/src/sdk/bus/config-commands.ts +5 -4
  343. package/src/sdk/bus/config.ts +98 -0
  344. package/src/sdk/bus/conversation-store.ts +5 -29
  345. package/src/sdk/bus/daemon-paths.ts +2 -0
  346. package/src/sdk/bus/discord-daemon.ts +25 -8
  347. package/src/sdk/bus/html-format.ts +20 -3
  348. package/src/sdk/bus/index.ts +834 -113
  349. package/src/sdk/bus/lifecycle-control-runtime.ts +91 -33
  350. package/src/sdk/bus/native-runtime-compatibility.ts +1 -1
  351. package/src/sdk/bus/natives-augment.d.ts +26 -1
  352. package/src/sdk/bus/notification-service.ts +168 -20
  353. package/src/sdk/bus/rate-limit-pool.ts +58 -14
  354. package/src/sdk/bus/recent-activity.ts +188 -74
  355. package/src/sdk/bus/rich-document.ts +258 -0
  356. package/src/sdk/bus/rich-render.ts +62 -70
  357. package/src/sdk/bus/telegram-daemon-cli.ts +15 -59
  358. package/src/sdk/bus/telegram-daemon-contract.ts +9 -4
  359. package/src/sdk/bus/telegram-daemon.ts +1491 -247
  360. package/src/sdk/bus/threaded-inbound.ts +8 -3
  361. package/src/sdk/bus/threaded-render.ts +57 -1
  362. package/src/sdk/bus/topic-registry.ts +120 -13
  363. package/src/sdk/host/control/dispatch.ts +14 -2
  364. package/src/sdk/host/control/operations.ts +6 -1
  365. package/src/sdk/host/host.ts +31 -1
  366. package/src/sdk/host/query/handlers.ts +20 -22
  367. package/src/sdk/host/query/revision-store.ts +80 -57
  368. package/src/sdk/index.ts +1 -0
  369. package/src/sdk/protocol/operation-inventory.generated.json +943 -1907
  370. package/src/sdk/session-directory.ts +141 -0
  371. package/src/sdk/session.ts +458 -479
  372. package/src/session/agent-session.ts +1901 -637
  373. package/src/session/agent-storage.ts +18 -0
  374. package/src/session/cache-economics.ts +25 -8
  375. package/src/session/fallback-chain-controller.ts +53 -3
  376. package/src/session/internal/managed-session-scope.ts +2226 -0
  377. package/src/session/internal/managed-session-storage.ts +453 -0
  378. package/src/session/messages.ts +91 -2
  379. package/src/session/session-manager-internal.ts +33 -0
  380. package/src/session/session-manager.ts +1112 -333
  381. package/src/session/session-storage.ts +444 -39
  382. package/src/session/volatile-context-pruning.ts +78 -0
  383. package/src/setup/credential-auto-import.ts +2 -1
  384. package/src/setup/hermes/templates/operator-instructions.v1.md +1 -1
  385. package/src/setup/provider-onboarding.ts +36 -61
  386. package/src/setup/provider-presets.json +5 -0
  387. package/src/skill-state/active-state.ts +3 -13
  388. package/src/skill-state/{deep-interview-mutation-guard.ts → workflow-mutation-guard.ts} +47 -29
  389. package/src/skill-state/workflow-state-contract.ts +6 -41
  390. package/src/slash-commands/builtin-registry.ts +46 -11
  391. package/src/system-prompt.ts +37 -44
  392. package/src/task/agents.ts +19 -1
  393. package/src/task/executor.ts +90 -6
  394. package/src/task/index.ts +62 -37
  395. package/src/thinking.ts +21 -6
  396. package/src/tool-discovery/tool-index.ts +2 -134
  397. package/src/tools/ask.ts +157 -21
  398. package/src/tools/ast-edit.ts +1 -1
  399. package/src/tools/bash.ts +38 -0
  400. package/src/tools/browser/dead-tab-recovery.ts +78 -0
  401. package/src/tools/browser/tab-supervisor.ts +282 -36
  402. package/src/tools/computer.ts +10 -3
  403. package/src/tools/cron.ts +30 -16
  404. package/src/tools/eval.ts +1 -2
  405. package/src/tools/fetch.ts +11 -4
  406. package/src/tools/index.ts +76 -24
  407. package/src/tools/output-meta.ts +13 -5
  408. package/src/tools/read.ts +37 -1
  409. package/src/tools/resource-gc.ts +2 -2
  410. package/src/tools/search-tool-bm25.ts +11 -74
  411. package/src/tools/subagent-render.ts +19 -8
  412. package/src/tools/subagent.ts +84 -32
  413. package/src/utils/event-bus.ts +9 -4
  414. package/src/web/search/index.ts +3 -3
  415. package/dist/types/discovery/plugin-dir-roots.d.ts +0 -15
  416. package/dist/types/runtime-mcp/discoverable-tool-metadata.d.ts +0 -7
  417. package/src/discovery/plugin-dir-roots.ts +0 -28
  418. package/src/runtime-mcp/discoverable-tool-metadata.ts +0 -25
@@ -0,0 +1,78 @@
1
+ import type { CustomMessageEntry, SessionEntry } from "./session-manager";
2
+
3
+ const SUPERSEDED_VOLATILE_CONTEXT_NOTICE = "[superseded volatile context pruned]";
4
+
5
+ /**
6
+ * Custom messages whose producer maintains one current singleton state:
7
+ * - todo-write-error-reminder: a later todo-write failure replaces the prior warning.
8
+ * - resolve-reminder: only the currently pending resolve preview can be applied.
9
+ * - eager-todo-prelude: the newest todo prelude reflects the current task state.
10
+ */
11
+ const SUPERSEDED_SINGLETON_REMINDER_TYPES = new Set([
12
+ "todo-write-error-reminder",
13
+ "resolve-reminder",
14
+ "eager-todo-prelude",
15
+ ]);
16
+
17
+ /**
18
+ * Volatile context is refreshed for every prompt. Only its newest copy is useful;
19
+ * replacing older copies at a maintenance boundary preserves the audit trail
20
+ * without repeatedly charging the model for stale workspace snapshots.
21
+ */
22
+ export function pruneSupersededVolatileProjectContext(entries: readonly SessionEntry[]): {
23
+ changed: CustomMessageEntry[];
24
+ bytesSaved: number;
25
+ } {
26
+ let latest = -1;
27
+ entries.forEach((entry, index) => {
28
+ if (entry.type === "custom_message" && entry.customType === "volatile-project-context") latest = index;
29
+ });
30
+ if (latest < 0) return { changed: [], bytesSaved: 0 };
31
+
32
+ const changed: CustomMessageEntry[] = [];
33
+ let bytesSaved = 0;
34
+ entries.forEach((entry, index) => {
35
+ if (index >= latest || entry.type !== "custom_message" || entry.customType !== "volatile-project-context") return;
36
+ const content =
37
+ typeof entry.content === "string"
38
+ ? entry.content
39
+ : entry.content.map(block => (block.type === "text" ? block.text : "")).join("\n");
40
+ if (!content) return;
41
+ entry.content = SUPERSEDED_VOLATILE_CONTEXT_NOTICE;
42
+ bytesSaved += Buffer.byteLength(content, "utf-8");
43
+ changed.push(entry as CustomMessageEntry);
44
+ });
45
+ return { changed, bytesSaved };
46
+ }
47
+
48
+ /** Retire superseded known singleton maintenance reminders without touching ordinary user context. */
49
+ export function pruneSupersededMaintenanceReminders(entries: readonly SessionEntry[]): {
50
+ changed: CustomMessageEntry[];
51
+ bytesSaved: number;
52
+ } {
53
+ const latest = new Map<string, number>();
54
+ entries.forEach((entry, index) => {
55
+ if (entry.type === "custom_message" && SUPERSEDED_SINGLETON_REMINDER_TYPES.has(entry.customType)) {
56
+ latest.set(entry.customType, index);
57
+ }
58
+ });
59
+ const changed: CustomMessageEntry[] = [];
60
+ let bytesSaved = 0;
61
+ entries.forEach((entry, index) => {
62
+ if (
63
+ entry.type !== "custom_message" ||
64
+ latest.get(entry.customType) === undefined ||
65
+ latest.get(entry.customType) === index
66
+ )
67
+ return;
68
+ const text =
69
+ typeof entry.content === "string"
70
+ ? entry.content
71
+ : entry.content.map(block => (block.type === "text" ? block.text : "")).join("\n");
72
+ if (!text) return;
73
+ entry.content = SUPERSEDED_VOLATILE_CONTEXT_NOTICE;
74
+ bytesSaved += Buffer.byteLength(text, "utf-8");
75
+ changed.push(entry);
76
+ });
77
+ return { changed, bytesSaved };
78
+ }
@@ -211,7 +211,8 @@ export function isCredentialAutoImportStateResolvedForVersion(
211
211
  version: string,
212
212
  ): boolean {
213
213
  return (
214
- state.initialImportResolution !== undefined ||
214
+ state.initialImportResolution === "declined" ||
215
+ (state.initialImportResolution === "accepted" && state.lastImportVersion === undefined) ||
215
216
  (state.lastImportVersion !== undefined && state.lastImportVersion === version)
216
217
  );
217
218
  }
@@ -11,7 +11,7 @@ These instructions teach a Hermes-style coordinator how to operate GJC through t
11
11
  3. Store the returned `turn_id`.
12
12
  4. Prefer `{{TOOL_PREFIX}}_watch_events` with the stored `latest_seq` for event-driven progress; fall back to `{{TOOL_PREFIX}}_read_turn` or `{{TOOL_PREFIX}}_await_turn` for a specific `turn_id` until terminal.
13
13
  If a second task is needed while one turn is active, pass `queue: true`; the next queued turn is promoted after the active turn is reported terminal.
14
- 5. If GJC asks a structured question, use `{{TOOL_PREFIX}}_list_questions` and answer with `{{TOOL_PREFIX}}_submit_question_answer`.
14
+ 5. If GJC asks structured questions, call `{{TOOL_PREFIX}}_list_questions` with `session_id`. It reconciles pending `workflow.gates.list` rows and returns bounded public questions, diagnostics, and reconciliation; `pending` is the current filter and `open` is a compatibility alias. Handle every pending row. Submit its `session_id`, `turn_id`, `question_id`, and `answer_binding` to `{{TOOL_PREFIX}}_submit_question_answer` with the advertised `answer`, a unique `idempotency_key`, and `allow_mutation: true`. That tool resolves through `workflow.gate_answer`, never generic `ask.answer`; re-list after restart, incomplete reconciliation is `terminal_uncertain`, stale/terminal rows are not answerable, identical replay is safe, and conflicting idempotency-key reuse fails. Never expect private gate payloads or raw values. This coordinator loop is separate from #2549/#2551 and unattended plain-CLI behavior.
15
15
  6. Use `{{TOOL_PREFIX}}_report_status` for coordinator-visible status and final reports.
16
16
  7. Use `{{TOOL_PREFIX}}_read_tail` only to inspect the latest assistant response through the SDK when structured turn state is insufficient; it never reads terminal output.
17
17
 
@@ -1,8 +1,11 @@
1
+ import { randomUUID } from "node:crypto";
1
2
  import * as fs from "node:fs/promises";
2
3
  import * as path from "node:path";
3
- import { getAgentDir } from "@gajae-code/utils";
4
+ import { getAgentDbPath, getAgentDir } from "@gajae-code/utils";
4
5
  import { YAML } from "bun";
5
6
  import { type ModelsConfig, ModelsConfigSchema } from "../config/models-config-schema";
7
+ import { AuthStorage } from "../session/auth-storage";
8
+ import providerPresets from "./provider-presets.json";
6
9
 
7
10
  export type ProviderCompatibility = "openai" | "anthropic";
8
11
  export type ProviderSetupApi = "openai-responses" | "openai-completions" | "anthropic-messages";
@@ -52,63 +55,7 @@ interface ProviderPreset {
52
55
  const PROVIDER_ID_PATTERN = /^[a-z0-9][a-z0-9._-]*$/;
53
56
  const REDACT_PREFIX = 4;
54
57
  const REDACT_SUFFIX = 4;
55
- // Preset compat values are onboarding snapshots for generated models.yml entries.
56
- // Keep them aligned with provider descriptor behavior without importing descriptor internals into setup UX.
57
- const MINIMAX_OPENAI_COMPAT: ProviderCompatConfig = {
58
- supportsStore: false,
59
- supportsDeveloperRole: false,
60
- supportsReasoningEffort: false,
61
- reasoningContentField: "reasoning_content",
62
- };
63
-
64
- const GLM_OPENAI_COMPAT: ProviderCompatConfig = {
65
- supportsDeveloperRole: false,
66
- supportsReasoningEffort: false,
67
- thinkingFormat: "zai",
68
- reasoningContentField: "reasoning_content",
69
- };
70
-
71
- export const PROVIDER_PRESETS: readonly ProviderPreset[] = [
72
- {
73
- id: "minimax",
74
- aliases: ["minimax-code"],
75
- name: "MiniMax Coding Plan",
76
- description: "OpenAI-compatible MiniMax Coding Plan endpoint",
77
- compatibility: "openai",
78
- api: "openai-completions",
79
- providerId: "minimax-code",
80
- baseUrl: "https://api.minimax.io/v1",
81
- apiKeyEnv: "MINIMAX_CODE_API_KEY",
82
- models: ["minimax-m3"],
83
- compat: MINIMAX_OPENAI_COMPAT,
84
- },
85
- {
86
- id: "minimax-cn",
87
- aliases: ["minimax-code-cn", "minimaxi"],
88
- name: "MiniMax Coding Plan (China)",
89
- description: "OpenAI-compatible MiniMax China endpoint",
90
- compatibility: "openai",
91
- api: "openai-completions",
92
- providerId: "minimax-code-cn",
93
- baseUrl: "https://api.minimaxi.com/v1",
94
- apiKeyEnv: "MINIMAX_CODE_CN_API_KEY",
95
- models: ["minimax-m3"],
96
- compat: MINIMAX_OPENAI_COMPAT,
97
- },
98
- {
99
- id: "glm",
100
- aliases: ["zai", "z-ai", "bigmodel"],
101
- name: "GLM / zAI",
102
- description: "OpenAI-compatible GLM endpoint from zAI/BigModel",
103
- compatibility: "openai",
104
- api: "openai-completions",
105
- providerId: "glm-proxy",
106
- baseUrl: "https://api.z.ai/api/paas/v4",
107
- apiKeyEnv: "ZAI_API_KEY",
108
- models: ["glm-4.6"],
109
- compat: GLM_OPENAI_COMPAT,
110
- },
111
- ];
58
+ export const PROVIDER_PRESETS: readonly ProviderPreset[] = providerPresets as ProviderPreset[];
112
59
 
113
60
  export function getDefaultModelsPath(): string {
114
61
  return path.join(getAgentDir(), "models.yml");
@@ -290,8 +237,31 @@ async function writeModelsConfig(modelsPath: string, config: ModelsConfig): Prom
290
237
  const where = first?.path.length ? `/${first.path.map(String).join("/")}` : "root";
291
238
  throw new Error(`Generated models config is invalid at ${where}: ${first?.message ?? "unknown schema error"}`);
292
239
  }
293
- await fs.mkdir(path.dirname(modelsPath), { recursive: true });
294
- await Bun.write(modelsPath, YAML.stringify(checked.data, null, 2));
240
+ const directory = path.dirname(modelsPath);
241
+ await fs.mkdir(directory, { recursive: true });
242
+ const tempPath = path.join(directory, `.${path.basename(modelsPath)}.${process.pid}.${randomUUID()}.tmp`);
243
+ try {
244
+ const tempHandle = await fs.open(tempPath, "wx", 0o600);
245
+ try {
246
+ await tempHandle.writeFile(YAML.stringify(checked.data, null, 2), "utf8");
247
+ await tempHandle.sync();
248
+ } finally {
249
+ await tempHandle.close();
250
+ }
251
+ await fs.rename(tempPath, modelsPath);
252
+ try {
253
+ const directoryHandle = await fs.open(directory, "r");
254
+ try {
255
+ await directoryHandle.sync();
256
+ } finally {
257
+ await directoryHandle.close();
258
+ }
259
+ } catch {
260
+ // Directory fsync is unavailable on some filesystems; the replacement succeeded.
261
+ }
262
+ } finally {
263
+ await fs.rm(tempPath, { force: true }).catch(() => undefined);
264
+ }
295
265
  }
296
266
 
297
267
  export async function addApiCompatibleProvider(input: ProviderSetupInput): Promise<ProviderSetupResult> {
@@ -311,7 +281,12 @@ export async function addApiCompatibleProvider(input: ProviderSetupInput): Promi
311
281
  if (validated.credentialSource === "env") {
312
282
  provider.apiKeyEnv = validated.apiKey;
313
283
  } else {
314
- provider.apiKey = validated.apiKey;
284
+ const authStorage = await AuthStorage.create(getAgentDbPath());
285
+ try {
286
+ await authStorage.set(validated.providerId, { type: "api_key", key: validated.apiKey });
287
+ } finally {
288
+ authStorage.close();
289
+ }
315
290
  }
316
291
  const next: ModelsConfig = {
317
292
  ...existing,
@@ -0,0 +1,5 @@
1
+ [
2
+ {"id":"minimax","aliases":["minimax-code"],"name":"MiniMax Coding Plan","description":"OpenAI-compatible MiniMax Coding Plan endpoint","compatibility":"openai","api":"openai-completions","providerId":"minimax-code","baseUrl":"https://api.minimax.io/v1","apiKeyEnv":"MINIMAX_CODE_API_KEY","models":["minimax-m3"],"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"reasoningContentField":"reasoning_content"}},
3
+ {"id":"minimax-cn","aliases":["minimax-code-cn","minimaxi"],"name":"MiniMax Coding Plan (China)","description":"OpenAI-compatible MiniMax China endpoint","compatibility":"openai","api":"openai-completions","providerId":"minimax-code-cn","baseUrl":"https://api.minimaxi.com/v1","apiKeyEnv":"MINIMAX_CODE_CN_API_KEY","models":["minimax-m3"],"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"reasoningContentField":"reasoning_content"}},
4
+ {"id":"glm","aliases":["zai","z-ai","bigmodel"],"name":"GLM / zAI","description":"OpenAI-compatible GLM endpoint from zAI/BigModel","compatibility":"openai","api":"openai-completions","providerId":"glm-proxy","baseUrl":"https://api.z.ai/api/paas/v4","apiKeyEnv":"ZAI_API_KEY","models":["glm-4.6"],"compat":{"supportsDeveloperRole":false,"supportsReasoningEffort":false,"thinkingFormat":"zai","reasoningContentField":"reasoning_content"}}
5
+ ]
@@ -16,6 +16,7 @@ import {
16
16
  setActiveStateCacheInvalidator,
17
17
  writeActiveEntry,
18
18
  } from "../gjc-runtime/state-writer";
19
+ import { getSkillManifest } from "../gjc-runtime/workflow-manifest";
19
20
  import { CANONICAL_GJC_WORKFLOW_SKILLS, type CanonicalGjcWorkflowSkill } from "./canonical-skills";
20
21
  import type { WorkflowStateReceipt } from "./workflow-state-contract";
21
22
 
@@ -445,29 +446,18 @@ async function readModeStatePhase(
445
446
  const record = parsed as Record<string, unknown>;
446
447
  const phase = safeString(record.current_phase).trim();
447
448
  if (!phase) return undefined;
448
- if (record.active === false && !RALPLAN_CANONICAL_PHASE_OVERRIDES.has(phase)) return undefined;
449
+ if (record.active === false && !getSkillManifest("ralplan").canonicalOverrides.includes(phase)) return undefined;
449
450
  return phase;
450
451
  } catch {
451
452
  return undefined;
452
453
  }
453
454
  }
454
455
 
455
- const RALPLAN_CANONICAL_PHASE_OVERRIDES = new Set([
456
- "final",
457
- "handoff",
458
- "complete",
459
- "completed",
460
- "failed",
461
- "cancelled",
462
- "canceled",
463
- "inactive",
464
- ]);
465
-
466
456
  function withCanonicalRalplanPhase(entry: SkillActiveEntry, canonicalPhase: string | undefined): SkillActiveEntry {
467
457
  if (
468
458
  entry.skill !== "ralplan" ||
469
459
  !canonicalPhase ||
470
- !RALPLAN_CANONICAL_PHASE_OVERRIDES.has(canonicalPhase) ||
460
+ !getSkillManifest("ralplan").canonicalOverrides.includes(canonicalPhase) ||
471
461
  entry.phase === canonicalPhase
472
462
  ) {
473
463
  return entry;
@@ -7,6 +7,7 @@ import { expandApplyPatchToEntries } from "../edit/modes/apply-patch";
7
7
  import { GJC_SESSION_PREFIX, modeStatePath as sessionModeStatePath } from "../gjc-runtime/session-layout";
8
8
  import { resolveGjcSessionForRead } from "../gjc-runtime/session-resolution";
9
9
  import { ModeStateSchema } from "../gjc-runtime/state-schema";
10
+ import { getSkillManifest } from "../gjc-runtime/workflow-manifest";
10
11
  import { LocalProtocolHandler, resolveLocalUrlToPath } from "../internal-urls/local-protocol";
11
12
  import { resolveToCwd } from "../tools/path-utils";
12
13
  import { ToolError } from "../tools/tool-errors";
@@ -51,7 +52,7 @@ type ToolWithEditMode = AgentTool & {
51
52
  customWireName?: unknown;
52
53
  };
53
54
 
54
- export interface DeepInterviewMutationGuardInput {
55
+ export interface WorkflowMutationGuardInput {
55
56
  cwd: string;
56
57
  sessionId?: string;
57
58
  threadId?: string;
@@ -59,6 +60,7 @@ export interface DeepInterviewMutationGuardInput {
59
60
  args: unknown;
60
61
  forceOverride?: boolean;
61
62
  enforceWorkflowState?: boolean;
63
+ guardContext?: WorkflowGuardContext;
62
64
  }
63
65
 
64
66
  interface ExtractedTargets {
@@ -66,7 +68,7 @@ interface ExtractedTargets {
66
68
  unknown: boolean;
67
69
  }
68
70
 
69
- export interface DeepInterviewMutationDecision {
71
+ export interface WorkflowMutationDecision {
70
72
  blocked: boolean;
71
73
  message?: string;
72
74
  targets: string[];
@@ -74,6 +76,12 @@ export interface DeepInterviewMutationDecision {
74
76
  command?: string;
75
77
  }
76
78
 
79
+ export interface WorkflowGuardContext {
80
+ sessionId: string | null;
81
+ activeState: Awaited<ReturnType<typeof readVisibleSkillActiveState>>;
82
+ modeStates: ReadonlyMap<string, ModeState | null>;
83
+ }
84
+
77
85
  interface ModeState {
78
86
  active?: boolean;
79
87
  current_phase?: string;
@@ -125,8 +133,23 @@ async function readValidatedModeState(filePath: string): Promise<ModeState | nul
125
133
  }
126
134
  return state;
127
135
  }
128
- async function readVisibleModeState(cwd: string, skill: string, sessionId: string): Promise<ModeState | null> {
129
- return await readValidatedModeState(modeStatePath(cwd, skill, sessionId));
136
+
137
+ export async function readWorkflowGuardContext(
138
+ cwd: string,
139
+ options: { sessionId?: string; threadId?: string } = {},
140
+ ): Promise<WorkflowGuardContext> {
141
+ const sessionId = await resolveBoundarySessionId(cwd, options.sessionId);
142
+ if (!sessionId) return { sessionId: null, activeState: null, modeStates: new Map() };
143
+ const activeState = await readVisibleSkillActiveState(cwd, sessionId, { tier: "security" });
144
+ const skills = activeState ? [...new Set(listActiveSkills(activeState).map(entry => entry.skill))] : [];
145
+ const modeStates = new Map(
146
+ await Promise.all(
147
+ skills.map(
148
+ async skill => [skill, await readValidatedModeState(modeStatePath(cwd, skill, sessionId))] as const,
149
+ ),
150
+ ),
151
+ );
152
+ return { sessionId, activeState, modeStates };
130
153
  }
131
154
 
132
155
  /**
@@ -135,7 +158,6 @@ async function readVisibleModeState(cwd: string, skill: string, sessionId: strin
135
158
  * absent so a handoff-required planning skill (deep-interview/ralplan) keeps
136
159
  * blocking through its handoff/ask window until it is demoted or cleared.
137
160
  */
138
- const WORKFLOW_FINISHED_PHASES = new Set(["complete", "completed", "failed", "cancelled", "canceled", "inactive"]);
139
161
 
140
162
  function entryMatchesContext(entry: SkillActiveEntry, sessionId?: string, threadId?: string): boolean {
141
163
  if (sessionId && entry.session_id && entry.session_id !== sessionId) return false;
@@ -165,7 +187,7 @@ function isPlanningSkill(skill: string): skill is "deep-interview" | "ralplan" |
165
187
  function isBlockingPlanningPhase(skill: "deep-interview" | "ralplan" | "ultragoal", phase: string): boolean {
166
188
  const normalized = phase.trim().toLowerCase();
167
189
  if (skill === "ultragoal") return normalized === "goal-planning";
168
- return !WORKFLOW_FINISHED_PHASES.has(normalized);
190
+ return !getSkillManifest(skill).stopReleasingPhases.includes(normalized);
169
191
  }
170
192
 
171
193
  interface ActivePlanningSkill {
@@ -219,10 +241,13 @@ async function getActivePlanningSkill(
219
241
  cwd: string,
220
242
  sessionId?: string,
221
243
  threadId?: string,
244
+ context?: WorkflowGuardContext,
222
245
  ): Promise<ActivePlanningSkill | null> {
223
- const resolvedSessionId = await resolveBoundarySessionId(cwd, sessionId);
246
+ const guardContext = context ?? (await readWorkflowGuardContext(cwd, { sessionId, threadId }));
247
+ const resolvedSessionId = guardContext.sessionId;
224
248
  if (!resolvedSessionId) return null;
225
- const skillState = await readVisibleSkillActiveState(cwd, resolvedSessionId, { tier: "security" });
249
+ const skillState = guardContext.activeState;
250
+
226
251
  if (!skillState) return null;
227
252
  const activeEntries = listActiveSkills(skillState).filter(entry =>
228
253
  entryMatchesContext(entry, resolvedSessionId, threadId),
@@ -230,7 +255,8 @@ async function getActivePlanningSkill(
230
255
  if (activeEntries.length === 0) return null;
231
256
  const current = resolveCurrentWorkflowEntry(activeEntries, safeString(skillState.skill).trim());
232
257
  if (!isPlanningSkill(current.skill)) return null;
233
- const modeState = await readVisibleModeState(cwd, current.skill, resolvedSessionId);
258
+ const modeState = guardContext.modeStates.get(current.skill) ?? null;
259
+
234
260
  if (!modeState) return null;
235
261
  if (modeState.active !== true) return null;
236
262
  if (!modeStateMatchesContext(modeState, resolvedSessionId, threadId)) return null;
@@ -558,23 +584,25 @@ async function planningBlockedTargets(cwd: string, targets: ExtractedTargets): P
558
584
  }
559
585
  return blocked;
560
586
  }
561
- export async function assertDeepInterviewMutationRawPathsAllowed(input: {
587
+ export async function assertWorkflowMutationRawPathsAllowed(input: {
562
588
  cwd: string;
563
589
  sessionId?: string;
564
590
  threadId?: string;
565
591
  rawPaths: string[];
566
592
  forceOverride?: boolean;
593
+ guardContext?: WorkflowGuardContext;
567
594
  }): Promise<void> {
568
595
  const targets: ExtractedTargets = { paths: input.rawPaths, unknown: input.rawPaths.length === 0 };
569
- // Always-on `.gjc/**` runtime-owned block, in parity with getDeepInterviewMutationDecision
570
- // and ahead of forceOverride: a deferred ast_edit apply must not reach `.gjc/**` either.
596
+ // Always-on `.gjc/**` runtime-owned block, ahead of forceOverride.
597
+ // A deferred ast_edit apply must not reach `.gjc/**` either.
571
598
  if (hasBlockedGjcTarget(input.cwd, targets)) {
572
599
  const stateSkill = firstBlockedWorkflowStateSkill(input.cwd, targets);
573
600
  const command = stateSkill ? sanctionedWorkflowStateCommand(stateSkill) : "gjc <workflow-command>";
574
601
  throw new ToolError(`${WORKFLOW_STATE_MUTATION_BLOCK_MESSAGE}\nUse: ${command}`);
575
602
  }
576
603
  if (input.forceOverride) return;
577
- const planning = await getActivePlanningSkill(input.cwd, input.sessionId, input.threadId);
604
+ const planning = await getActivePlanningSkill(input.cwd, input.sessionId, input.threadId, input.guardContext);
605
+
578
606
  if (!planning) return;
579
607
  const message = planningPhaseBlockMessage(planning.skill);
580
608
  if (input.rawPaths.length === 0) throw new ToolError(message);
@@ -582,9 +610,9 @@ export async function assertDeepInterviewMutationRawPathsAllowed(input: {
582
610
  if (blocked.length > 0) throw new ToolError(message);
583
611
  }
584
612
 
585
- export async function getDeepInterviewMutationDecision(
586
- input: DeepInterviewMutationGuardInput,
587
- ): Promise<DeepInterviewMutationDecision> {
613
+ export async function getWorkflowMutationDecision(
614
+ input: WorkflowMutationGuardInput,
615
+ ): Promise<WorkflowMutationDecision> {
588
616
  if (!BLOCKED_TOOL_NAMES.has(input.tool.name)) return { blocked: false, targets: [] };
589
617
  const targets = extractTargets(input.tool, input.args);
590
618
  if (input.tool.name !== "bash" && input.enforceWorkflowState !== false && hasBlockedGjcTarget(input.cwd, targets)) {
@@ -598,7 +626,7 @@ export async function getDeepInterviewMutationDecision(
598
626
  command,
599
627
  };
600
628
  }
601
- const planning = await getActivePlanningSkill(input.cwd, input.sessionId, input.threadId);
629
+ const planning = await getActivePlanningSkill(input.cwd, input.sessionId, input.threadId, input.guardContext);
602
630
  if (!planning) {
603
631
  return { blocked: false, targets: [] };
604
632
  }
@@ -627,17 +655,7 @@ export async function getDeepInterviewMutationDecision(
627
655
  };
628
656
  }
629
657
 
630
- export async function assertDeepInterviewMutationAllowed(input: DeepInterviewMutationGuardInput): Promise<void> {
631
- const decision = await getDeepInterviewMutationDecision(input);
658
+ export async function assertWorkflowMutationAllowed(input: WorkflowMutationGuardInput): Promise<void> {
659
+ const decision = await getWorkflowMutationDecision(input);
632
660
  if (decision.blocked) throw new ToolError(decision.message ?? DEEP_INTERVIEW_MUTATION_BLOCK_MESSAGE);
633
661
  }
634
-
635
- /*
636
- * Generic cross-workflow names for this planning-phase mutation guard. The guard
637
- * now governs deep-interview, ralplan, and ultragoal goal-planning, so new
638
- * callers SHOULD use these names; the `*DeepInterview*` exports above remain as
639
- * compatibility aliases (and are still what the test-suite imports).
640
- */
641
- export const getWorkflowMutationDecision = getDeepInterviewMutationDecision;
642
- export const assertWorkflowMutationAllowed = assertDeepInterviewMutationAllowed;
643
- export const assertWorkflowMutationRawPathsAllowed = assertDeepInterviewMutationRawPathsAllowed;
@@ -1,4 +1,5 @@
1
1
  import * as path from "node:path";
2
+ import { activeSnapshotPath, assertNonEmptyGjcSessionId, modeStatePath } from "../gjc-runtime/session-layout";
2
3
  import { CANONICAL_GJC_WORKFLOW_SKILLS, type CanonicalGjcWorkflowSkill, SKILL_ACTIVE_STATE_FILE } from "./active-state";
3
4
  import { WORKFLOW_STATE_RECEIPT_FRESH_MS, WORKFLOW_STATE_RECEIPT_VERSION } from "./workflow-state-version";
4
5
 
@@ -51,57 +52,21 @@ export interface AuditEntry {
51
52
  paths: string[];
52
53
  }
53
54
 
54
- function safeString(value: unknown): string {
55
- return typeof value === "string" ? value : "";
56
- }
57
-
58
- function encodePathSegment(value: string): string {
59
- return encodeURIComponent(value).replaceAll(".", "%2E");
60
- }
61
-
62
55
  export function workflowModeStateFileName(skill: CanonicalGjcWorkflowSkill): string {
63
56
  return `${skill}-state.json`;
64
57
  }
65
58
 
66
- export function workflowStateStoragePath(cwd: string, skill: CanonicalGjcWorkflowSkill, sessionId?: string): string {
67
- const normalizedSessionId = safeString(sessionId).trim();
68
- if (normalizedSessionId) {
69
- return path.join(
70
- cwd,
71
- ".gjc",
72
- "state",
73
- "sessions",
74
- encodePathSegment(normalizedSessionId),
75
- workflowModeStateFileName(skill),
76
- );
77
- }
78
- return path.join(cwd, ".gjc", "state", workflowModeStateFileName(skill));
79
- }
80
-
81
- export function workflowActiveStatePath(cwd: string, sessionId?: string): string {
82
- const normalizedSessionId = safeString(sessionId).trim();
83
- if (normalizedSessionId) {
84
- return path.join(
85
- cwd,
86
- ".gjc",
87
- "state",
88
- "sessions",
89
- encodePathSegment(normalizedSessionId),
90
- SKILL_ACTIVE_STATE_FILE,
91
- );
92
- }
93
- return path.join(cwd, ".gjc", "state", SKILL_ACTIVE_STATE_FILE);
94
- }
95
-
96
59
  export function buildWorkflowStateReceipt(input: {
97
60
  cwd: string;
98
61
  skill: CanonicalGjcWorkflowSkill;
99
62
  owner: WorkflowStateMutationOwner;
100
63
  command: string;
101
- sessionId?: string;
64
+ sessionId: string;
102
65
  nowIso?: string;
103
66
  mutationId?: string;
104
67
  }): WorkflowStateReceipt {
68
+ assertNonEmptyGjcSessionId(input.sessionId, "buildWorkflowStateReceipt");
69
+ const cwd = path.resolve(input.cwd);
105
70
  const mutatedAt = input.nowIso ?? new Date().toISOString();
106
71
  const freshUntil = new Date(Date.parse(mutatedAt) + WORKFLOW_STATE_RECEIPT_FRESH_MS).toISOString();
107
72
  return {
@@ -109,8 +74,8 @@ export function buildWorkflowStateReceipt(input: {
109
74
  skill: input.skill,
110
75
  owner: input.owner,
111
76
  command: input.command,
112
- state_path: workflowActiveStatePath(input.cwd, input.sessionId),
113
- storage_path: workflowStateStoragePath(input.cwd, input.skill, input.sessionId),
77
+ state_path: activeSnapshotPath(cwd, input.sessionId),
78
+ storage_path: modeStatePath(cwd, input.sessionId, input.skill),
114
79
  mutated_at: mutatedAt,
115
80
  fresh_until: freshUntil,
116
81
  status: "fresh",
@@ -18,12 +18,17 @@ import {
18
18
  formatModelSelectorValue,
19
19
  parseModelPattern,
20
20
  parseModelString,
21
+ splitSelectorThinkingSuffix,
21
22
  } from "../config/model-resolver";
22
23
  import { clearPluginRootsAndCaches, resolveActiveProjectRegistryPath } from "../discovery/helpers.js";
23
24
  import { resolveMemoryBackend } from "../memory-backend";
24
25
  import { DynamicBorder } from "../modes/components/dynamic-border";
25
26
  import { theme } from "../modes/theme/theme";
26
- import type { InteractiveModeContext } from "../modes/types";
27
+ import {
28
+ type ComposerSubmissionOptions,
29
+ canApplyComposerSubmission,
30
+ type InteractiveModeContext,
31
+ } from "../modes/types";
27
32
  import {
28
33
  buildNotificationStatusReport,
29
34
  checkNotificationHealth,
@@ -62,7 +67,13 @@ import type {
62
67
  export type { BuiltinSlashCommand, SubcommandDef } from "./types";
63
68
 
64
69
  /** TUI-specific runtime accepted by `executeBuiltinSlashCommand`. */
65
- export type BuiltinSlashCommandRuntime = TuiSlashCommandRuntime;
70
+ export type BuiltinSlashCommandRuntime = TuiSlashCommandRuntime & {
71
+ composer?: ComposerSubmissionOptions;
72
+ };
73
+
74
+ function canClearComposer(runtime: BuiltinSlashCommandRuntime): boolean {
75
+ return canApplyComposerSubmission(runtime.composer, runtime.ctx.editor);
76
+ }
66
77
 
67
78
  const PET_COMMAND_OPTIONS: ReadonlyArray<{ name: string; mode: PetMode; description: string }> = [
68
79
  { name: "off", mode: "off", description: "Hide the pet" },
@@ -243,12 +254,9 @@ function parseModelCommandArgs(args: string): ParsedModelCommandArgs {
243
254
 
244
255
  function splitExplicitThinkingSelector(selector: string): { baseSelector: string; thinkingLevel?: ThinkingLevel } {
245
256
  const trimmed = selector.trim();
246
- const colonIndex = trimmed.lastIndexOf(":");
247
- if (colonIndex === -1) {
248
- return { baseSelector: trimmed };
249
- }
250
- const thinkingLevel = parseThinkingLevel(trimmed.slice(colonIndex + 1));
251
- return thinkingLevel ? { baseSelector: trimmed.slice(0, colonIndex), thinkingLevel } : { baseSelector: trimmed };
257
+ const { selector: baseSelector, thinkingLevel } = splitSelectorThinkingSuffix(trimmed);
258
+ // Preserve the whole selector when the trailing suffix is not a valid thinking level.
259
+ return thinkingLevel ? { baseSelector, thinkingLevel } : { baseSelector: trimmed };
252
260
  }
253
261
 
254
262
  interface ModelCommandSelection {
@@ -625,7 +633,7 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<SlashCommandSpec> = [
625
633
  // — including the first-time `/goal set <objective>` case where goal
626
634
  // mode was not yet active. A previous `wasGoalModeEnabled` guard dropped
627
635
  // that first-time case from history (up/down-arrow recall).
628
- await runtime.ctx.handleGoalModeCommand(command.args || undefined);
636
+ await runtime.ctx.goalModeController.handleCommand(command.args || undefined);
629
637
  if (command.args) {
630
638
  runtime.ctx.editor.addToHistory(command.text);
631
639
  }
@@ -1048,6 +1056,20 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<SlashCommandSpec> = [
1048
1056
  runtime.ctx.editor.setText("");
1049
1057
  },
1050
1058
  },
1059
+ {
1060
+ name: "transcript",
1061
+ description: "Browse the current session transcript",
1062
+ acpDescription: "Browse the current session transcript",
1063
+ handle: async (_command, runtime) => {
1064
+ await runtime.output("Transcript browsing is available in the interactive TUI.");
1065
+ return commandConsumed();
1066
+ },
1067
+ handleTui: (_command, runtime) => {
1068
+ if (runtime.ctx.isTranscriptViewerOpen()) return;
1069
+ runtime.ctx.showTranscriptViewer();
1070
+ runtime.ctx.editor.setText("");
1071
+ },
1072
+ },
1051
1073
  {
1052
1074
  name: "context",
1053
1075
  description: "Show active context token usage breakdown",
@@ -1446,6 +1468,15 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<SlashCommandSpec> = [
1446
1468
  runtime.ctx.editor.setText("");
1447
1469
  },
1448
1470
  },
1471
+ {
1472
+ name: "sessions",
1473
+ priority: 91,
1474
+ description: "Show all persisted sessions (read-only)",
1475
+ handleTui: (_command, runtime) => {
1476
+ runtime.ctx.showSessionsDashboard();
1477
+ runtime.ctx.editor.setText("");
1478
+ },
1479
+ },
1449
1480
  {
1450
1481
  name: "btw",
1451
1482
  description: "Ask an ephemeral side question using the current session context",
@@ -1688,7 +1719,9 @@ export async function executeBuiltinSlashCommand(
1688
1719
  const diagnostic = formatUnknownBuiltinSlashCommandDiagnostic(parsed.name);
1689
1720
  if (!diagnostic) return false;
1690
1721
  runtime.ctx.showError(diagnostic);
1691
- runtime.ctx.editor.setText("");
1722
+ if (canClearComposer(runtime)) {
1723
+ runtime.ctx.editor.setText("");
1724
+ }
1692
1725
  return true;
1693
1726
  }
1694
1727
  if (parsed.args.length > 0 && !command.allowArgs) {
@@ -1703,7 +1736,9 @@ export async function executeBuiltinSlashCommand(
1703
1736
  const ctx = runtime.ctx;
1704
1737
  const adapted = toSlashCommandRuntime(runtime);
1705
1738
  const result = await command.handle(parsed, adapted);
1706
- ctx.editor.setText("");
1739
+ if (canClearComposer(runtime)) {
1740
+ ctx.editor.setText("");
1741
+ }
1707
1742
  if (result && typeof result === "object" && "prompt" in result) return result.prompt;
1708
1743
  return true;
1709
1744
  }