@gajae-code/coding-agent 0.11.1 → 0.11.3

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 (413) hide show
  1. package/CHANGELOG.md +64 -0
  2. package/dist/types/cli/config-cli.d.ts +11 -1
  3. package/dist/types/cli/launch-disposition.d.ts +23 -0
  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 +141 -11
  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-runtime.d.ts +55 -33
  54. package/dist/types/gjc-runtime/workflow-cli-common.d.ts +8 -0
  55. package/dist/types/gjc-runtime/workflow-manifest.d.ts +3 -0
  56. package/dist/types/goals/continuation-timeout-guard.d.ts +22 -0
  57. package/dist/types/goals/runtime.d.ts +1 -0
  58. package/dist/types/goals/state.d.ts +8 -0
  59. package/dist/types/harness-control-plane/lifecycle-reconciliation.d.ts +17 -0
  60. package/dist/types/harness-control-plane/phase-rollup.d.ts +4 -7
  61. package/dist/types/harness-control-plane/receipt-ingest.d.ts +5 -0
  62. package/dist/types/harness-control-plane/receipt-spool.d.ts +4 -0
  63. package/dist/types/hindsight/state.d.ts +11 -4
  64. package/dist/types/lsp/lspmux.d.ts +5 -3
  65. package/dist/types/lsp/path-trust.d.ts +1 -0
  66. package/dist/types/main.d.ts +4 -2
  67. package/dist/types/memories/storage.d.ts +1 -0
  68. package/dist/types/modes/action-registry.d.ts +29 -0
  69. package/dist/types/modes/components/chrome.d.ts +14 -0
  70. package/dist/types/modes/components/command-palette.d.ts +27 -0
  71. package/dist/types/modes/components/custom-provider-wizard.d.ts +1 -0
  72. package/dist/types/modes/components/index.d.ts +2 -1
  73. package/dist/types/modes/components/pet-selector.d.ts +1 -1
  74. package/dist/types/modes/components/plan-preview-overlay.d.ts +43 -0
  75. package/dist/types/modes/components/queue-mode-selector.d.ts +1 -1
  76. package/dist/types/modes/components/queue-pane.d.ts +12 -0
  77. package/dist/types/modes/components/read-tool-group.d.ts +6 -0
  78. package/dist/types/modes/components/session-observer-overlay.d.ts +3 -4
  79. package/dist/types/modes/components/sessions-dashboard.d.ts +32 -0
  80. package/dist/types/modes/components/settings-selector.d.ts +1 -1
  81. package/dist/types/modes/components/show-images-selector.d.ts +1 -1
  82. package/dist/types/modes/components/status-line/types.d.ts +1 -1
  83. package/dist/types/modes/components/status-line.d.ts +1 -94
  84. package/dist/types/modes/components/tasks-pane.d.ts +15 -0
  85. package/dist/types/modes/components/theme-selector.d.ts +1 -1
  86. package/dist/types/modes/components/tool-execution.d.ts +15 -0
  87. package/dist/types/modes/components/tool-status-header.d.ts +111 -0
  88. package/dist/types/modes/components/transcript-viewer-overlay.d.ts +42 -0
  89. package/dist/types/modes/controllers/goal-mode-controller.d.ts +62 -0
  90. package/dist/types/modes/controllers/input-controller.d.ts +8 -1
  91. package/dist/types/modes/controllers/mode-gate.d.ts +8 -0
  92. package/dist/types/modes/controllers/plan-mode-controller.d.ts +65 -0
  93. package/dist/types/modes/controllers/selector-controller.d.ts +15 -3
  94. package/dist/types/modes/controllers/stt-controller.d.ts +26 -0
  95. package/dist/types/modes/interactive-mode.d.ts +19 -17
  96. package/dist/types/modes/jobs-observer.d.ts +2 -0
  97. package/dist/types/modes/prompt-action-autocomplete.d.ts +4 -0
  98. package/dist/types/modes/shared/agent-wire/deep-interview-gate.d.ts +4 -11
  99. package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +20 -2
  100. package/dist/types/modes/shared/agent-wire/workflow-gate-types.d.ts +31 -0
  101. package/dist/types/modes/tasks-aggregator.d.ts +39 -0
  102. package/dist/types/modes/transcript-item-registry.d.ts +60 -0
  103. package/dist/types/modes/types.d.ts +20 -13
  104. package/dist/types/modes/utils/ui-helpers.d.ts +2 -2
  105. package/dist/types/runtime-mcp/manager.d.ts +1 -1
  106. package/dist/types/sdk/broker/broker.d.ts +78 -12
  107. package/dist/types/sdk/broker/lifecycle-codec.d.ts +4 -0
  108. package/dist/types/sdk/broker/lifecycle-ledger.d.ts +15 -1
  109. package/dist/types/sdk/broker/lifecycle.d.ts +6 -2
  110. package/dist/types/sdk/broker/process-incarnation.d.ts +2 -0
  111. package/dist/types/sdk/broker/session-index.d.ts +0 -1
  112. package/dist/types/sdk/broker/state-version.d.ts +2 -0
  113. package/dist/types/sdk/bus/chat-effect-journal.d.ts +1 -0
  114. package/dist/types/sdk/bus/config-commands.d.ts +1 -1
  115. package/dist/types/sdk/bus/config.d.ts +11 -0
  116. package/dist/types/sdk/bus/daemon-paths.d.ts +1 -0
  117. package/dist/types/sdk/bus/html-format.d.ts +3 -2
  118. package/dist/types/sdk/bus/index.d.ts +29 -0
  119. package/dist/types/sdk/bus/lifecycle-control-runtime.d.ts +4 -0
  120. package/dist/types/sdk/bus/notification-service.d.ts +20 -0
  121. package/dist/types/sdk/bus/rate-limit-pool.d.ts +13 -2
  122. package/dist/types/sdk/bus/recent-activity.d.ts +21 -12
  123. package/dist/types/sdk/bus/rich-document.d.ts +7 -0
  124. package/dist/types/sdk/bus/rich-render.d.ts +18 -41
  125. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +9 -4
  126. package/dist/types/sdk/bus/telegram-daemon.d.ts +46 -3
  127. package/dist/types/sdk/bus/threaded-inbound.d.ts +1 -1
  128. package/dist/types/sdk/bus/threaded-render.d.ts +13 -0
  129. package/dist/types/sdk/bus/topic-registry.d.ts +24 -2
  130. package/dist/types/sdk/host/control/operations.d.ts +1 -1
  131. package/dist/types/sdk/host/host.d.ts +2 -0
  132. package/dist/types/sdk/index.d.ts +1 -0
  133. package/dist/types/sdk/session-directory.d.ts +56 -0
  134. package/dist/types/sdk/session.d.ts +2 -0
  135. package/dist/types/session/agent-session.d.ts +82 -47
  136. package/dist/types/session/agent-storage.d.ts +7 -0
  137. package/dist/types/session/fallback-chain-controller.d.ts +10 -2
  138. package/dist/types/session/internal/managed-session-scope.d.ts +102 -0
  139. package/dist/types/session/internal/managed-session-storage.d.ts +38 -0
  140. package/dist/types/session/messages.d.ts +16 -0
  141. package/dist/types/session/session-manager-internal.d.ts +14 -0
  142. package/dist/types/session/session-manager.d.ts +82 -12
  143. package/dist/types/session/session-storage.d.ts +43 -3
  144. package/dist/types/session/volatile-context-pruning.d.ts +15 -0
  145. package/dist/types/skill-state/{deep-interview-mutation-guard.d.ts → workflow-mutation-guard.d.ts} +24 -8
  146. package/dist/types/skill-state/workflow-state-contract.d.ts +1 -3
  147. package/dist/types/slash-commands/builtin-registry.d.ts +4 -1
  148. package/dist/types/system-prompt.d.ts +2 -11
  149. package/dist/types/task/executor.d.ts +3 -1
  150. package/dist/types/thinking.d.ts +7 -0
  151. package/dist/types/tool-discovery/tool-index.d.ts +1 -50
  152. package/dist/types/tools/ask.d.ts +64 -2
  153. package/dist/types/tools/bash.d.ts +3 -0
  154. package/dist/types/tools/browser/dead-tab-recovery.d.ts +24 -0
  155. package/dist/types/tools/browser/tab-supervisor.d.ts +21 -0
  156. package/dist/types/tools/cron.d.ts +2 -0
  157. package/dist/types/tools/fetch.d.ts +1 -0
  158. package/dist/types/tools/index.d.ts +30 -15
  159. package/dist/types/tools/output-meta.d.ts +1 -0
  160. package/dist/types/tools/read.d.ts +5 -0
  161. package/dist/types/tools/search-tool-bm25.d.ts +3 -4
  162. package/dist/types/tools/subagent.d.ts +1 -0
  163. package/dist/types/utils/event-bus.d.ts +1 -1
  164. package/dist/types/utils/file-mentions.d.ts +3 -3
  165. package/dist/types/web/search/index.d.ts +3 -1
  166. package/package.json +21 -9
  167. package/scripts/build-sdk-package-smoke.ts +34 -1
  168. package/scripts/generate-hotkeys-docs.ts +74 -0
  169. package/scripts/generate-sdk-operation-inventory.ts +64 -20
  170. package/scripts/verify-gjc-sdk-canonicalization.ts +182 -2
  171. package/src/async/job-manager.ts +49 -6
  172. package/src/cli/config-cli.ts +75 -2
  173. package/src/cli/launch-disposition.ts +42 -0
  174. package/src/cli/notify-cli.ts +92 -26
  175. package/src/cli/session-picker.ts +20 -3
  176. package/src/cli/setup-cli.ts +1 -1
  177. package/src/cli.ts +1 -1
  178. package/src/commands/config.ts +1 -1
  179. package/src/commands/harness.ts +34 -106
  180. package/src/commands/launch.ts +6 -4
  181. package/src/commands/mcp-serve.ts +85 -8
  182. package/src/commands/mcp.ts +2 -2
  183. package/src/commands/notify.ts +8 -4
  184. package/src/commands/sdk.ts +61 -40
  185. package/src/commands/ultragoal.ts +4 -1
  186. package/src/config/atomic-yaml-patch.ts +80 -13
  187. package/src/config/file-lock.ts +105 -43
  188. package/src/config/keybindings.ts +64 -20
  189. package/src/config/model-auth.ts +9 -0
  190. package/src/config/model-bindings-applier.ts +139 -0
  191. package/src/config/model-discovery-manager.ts +224 -0
  192. package/src/config/model-equivalence.ts +66 -0
  193. package/src/config/model-registry.ts +169 -302
  194. package/src/config/model-resolver.ts +361 -369
  195. package/src/config/models-config-schema.ts +5 -4
  196. package/src/config/settings-schema.ts +214 -12
  197. package/src/config/settings.ts +458 -482
  198. package/src/coordinator-mcp/policy.ts +76 -11
  199. package/src/coordinator-mcp/question-gate-codec.ts +274 -0
  200. package/src/coordinator-mcp/question-state.ts +778 -0
  201. package/src/coordinator-mcp/server.ts +1702 -238
  202. package/src/debug/index.ts +1 -1
  203. package/src/defaults/gjc/skills/deep-interview/SKILL.md +13 -1
  204. package/src/defaults/gjc/skills/team/SKILL.md +16 -0
  205. package/src/discovery/helpers.ts +1 -50
  206. package/src/edit/index.ts +64 -0
  207. package/src/eval/py/env.ts +26 -0
  208. package/src/eval/py/kernel.ts +5 -3
  209. package/src/extensibility/extensions/loader.ts +9 -1
  210. package/src/extensibility/extensions/runner.ts +12 -3
  211. package/src/extensibility/extensions/types.ts +39 -1
  212. package/src/extensibility/gjc-plugins/installer.ts +16 -16
  213. package/src/extensibility/hooks/runner.ts +2 -2
  214. package/src/extensibility/runtime-skill-discovery.ts +33 -13
  215. package/src/extensibility/shared-events.ts +2 -0
  216. package/src/gjc-runtime/deep-interview-recorder.ts +63 -3
  217. package/src/gjc-runtime/deep-interview-runtime.ts +76 -27
  218. package/src/gjc-runtime/deep-interview-state.ts +317 -5
  219. package/src/gjc-runtime/goal-mode-request.ts +55 -8
  220. package/src/gjc-runtime/launch-tmux.ts +2 -5
  221. package/src/gjc-runtime/launch-worktree.ts +5 -5
  222. package/src/gjc-runtime/linux-proc.ts +71 -0
  223. package/src/gjc-runtime/ralplan-runtime.ts +74 -90
  224. package/src/gjc-runtime/session-resolution.ts +18 -3
  225. package/src/gjc-runtime/session-state-sidecar.ts +6 -107
  226. package/src/gjc-runtime/state-migrations.ts +1 -1
  227. package/src/gjc-runtime/state-runtime.ts +327 -249
  228. package/src/gjc-runtime/state-writer.ts +36 -40
  229. package/src/gjc-runtime/team-launch.ts +319 -0
  230. package/src/gjc-runtime/team-notify.ts +326 -0
  231. package/src/gjc-runtime/team-runtime.ts +1099 -1482
  232. package/src/gjc-runtime/team-store.ts +828 -0
  233. package/src/gjc-runtime/team-workers.ts +962 -0
  234. package/src/gjc-runtime/tmux-owner-isolation-cli.ts +2 -11
  235. package/src/gjc-runtime/tmux-owner-isolation.ts +14 -9
  236. package/src/gjc-runtime/tmux-sessions.ts +4 -21
  237. package/src/gjc-runtime/ultragoal-change-set.ts +172 -0
  238. package/src/gjc-runtime/ultragoal-evidence.ts +874 -0
  239. package/src/gjc-runtime/ultragoal-guard.ts +29 -5
  240. package/src/gjc-runtime/ultragoal-pipeline.ts +306 -0
  241. package/src/gjc-runtime/ultragoal-runtime.ts +84 -1311
  242. package/src/gjc-runtime/workflow-cli-common.ts +30 -0
  243. package/src/gjc-runtime/workflow-manifest.generated.json +58 -0
  244. package/src/gjc-runtime/workflow-manifest.ts +18 -0
  245. package/src/goals/continuation-timeout-guard.ts +79 -0
  246. package/src/goals/runtime.ts +7 -5
  247. package/src/goals/state.ts +18 -0
  248. package/src/harness-control-plane/lifecycle-reconciliation.ts +64 -0
  249. package/src/harness-control-plane/phase-rollup.ts +4 -7
  250. package/src/harness-control-plane/receipt-ingest.ts +5 -0
  251. package/src/harness-control-plane/receipt-spool.ts +51 -7
  252. package/src/harness-control-plane/session-lease.ts +12 -130
  253. package/src/hindsight/backend.ts +26 -27
  254. package/src/hindsight/state.ts +101 -32
  255. package/src/hooks/skill-state.ts +17 -11
  256. package/src/internal-urls/docs-index.generated.ts +21 -18
  257. package/src/lsp/client.ts +1 -1
  258. package/src/lsp/config.ts +145 -26
  259. package/src/lsp/index.ts +1 -1
  260. package/src/lsp/lspmux.ts +39 -10
  261. package/src/lsp/path-trust.ts +81 -0
  262. package/src/main.ts +127 -30
  263. package/src/memories/index.ts +1 -0
  264. package/src/memories/storage.ts +6 -2
  265. package/src/modes/action-registry.ts +165 -0
  266. package/src/modes/components/chrome.ts +40 -0
  267. package/src/modes/components/command-palette.ts +168 -0
  268. package/src/modes/components/custom-editor.ts +1 -1
  269. package/src/modes/components/custom-provider-wizard.ts +51 -14
  270. package/src/modes/components/index.ts +2 -1
  271. package/src/modes/components/pet-selector.ts +11 -17
  272. package/src/modes/components/plan-preview-overlay.ts +295 -0
  273. package/src/modes/components/queue-mode-selector.ts +10 -27
  274. package/src/modes/components/queue-pane.ts +79 -0
  275. package/src/modes/components/read-tool-group.ts +13 -0
  276. package/src/modes/components/session-observer-overlay.ts +207 -772
  277. package/src/modes/components/sessions-dashboard.ts +181 -0
  278. package/src/modes/components/settings-selector.ts +1 -1
  279. package/src/modes/components/show-images-selector.ts +10 -24
  280. package/src/modes/components/status-line/types.ts +1 -1
  281. package/src/modes/components/status-line.ts +1 -969
  282. package/src/modes/components/tasks-pane.ts +73 -0
  283. package/src/modes/components/theme-selector.ts +11 -31
  284. package/src/modes/components/tool-execution.ts +22 -0
  285. package/src/modes/components/tool-status-header.ts +1056 -0
  286. package/src/modes/components/transcript-viewer-overlay.ts +384 -0
  287. package/src/modes/controllers/btw-controller.ts +1 -0
  288. package/src/modes/controllers/event-controller.ts +3 -2
  289. package/src/modes/controllers/extension-ui-controller.ts +24 -1
  290. package/src/modes/controllers/goal-mode-controller.ts +474 -0
  291. package/src/modes/controllers/input-controller.ts +764 -229
  292. package/src/modes/controllers/mode-gate.ts +24 -0
  293. package/src/modes/controllers/plan-mode-controller.ts +517 -0
  294. package/src/modes/controllers/selector-controller.ts +225 -10
  295. package/src/modes/controllers/stt-controller.ts +125 -0
  296. package/src/modes/interactive-mode.ts +289 -1150
  297. package/src/modes/jobs-observer.ts +3 -0
  298. package/src/modes/prompt-action-autocomplete.ts +7 -0
  299. package/src/modes/runtime-init.ts +8 -0
  300. package/src/modes/shared/agent-wire/deep-interview-gate.ts +31 -106
  301. package/src/modes/shared/agent-wire/workflow-gate-broker.ts +71 -16
  302. package/src/modes/shared/agent-wire/workflow-gate-types.ts +177 -0
  303. package/src/modes/tasks-aggregator.ts +199 -0
  304. package/src/modes/transcript-item-registry.ts +229 -0
  305. package/src/modes/types.ts +45 -18
  306. package/src/modes/utils/ui-helpers.ts +17 -9
  307. package/src/prompts/agent-fragments/ralplan-persistence.md +6 -0
  308. package/src/prompts/agent-fragments/restricted-bash.md +1 -0
  309. package/src/prompts/agents/architect.md +2 -8
  310. package/src/prompts/agents/critic.md +2 -8
  311. package/src/prompts/agents/executor.md +3 -0
  312. package/src/prompts/agents/planner.md +4 -12
  313. package/src/prompts/system/custom-system-prompt.md +1 -23
  314. package/src/prompts/system/plan-mode-approved.md +8 -0
  315. package/src/prompts/system/system-prompt.md +17 -96
  316. package/src/prompts/tools/bash.md +4 -4
  317. package/src/prompts/tools/browser.md +15 -52
  318. package/src/prompts/tools/find.md +2 -2
  319. package/src/prompts/tools/hashline.md +13 -55
  320. package/src/prompts/tools/read.md +3 -6
  321. package/src/prompts/tools/search-tool-bm25.md +0 -2
  322. package/src/prompts/tools/search.md +2 -4
  323. package/src/prompts/tools/skill-discovery.md +1 -2
  324. package/src/prompts/tools/task.md +1 -1
  325. package/src/runtime-mcp/manager.ts +1 -1
  326. package/src/sdk/broker/broker.ts +206 -78
  327. package/src/sdk/broker/discovery.ts +1 -1
  328. package/src/sdk/broker/ensure.ts +3 -1
  329. package/src/sdk/broker/lifecycle-codec.ts +11 -0
  330. package/src/sdk/broker/lifecycle-ledger.ts +371 -74
  331. package/src/sdk/broker/lifecycle.ts +1399 -142
  332. package/src/sdk/broker/process-incarnation.ts +5 -13
  333. package/src/sdk/broker/session-index.ts +145 -56
  334. package/src/sdk/broker/state-version.ts +21 -0
  335. package/src/sdk/broker/transport.ts +1 -1
  336. package/src/sdk/bus/chat-daemon-cli.ts +2 -0
  337. package/src/sdk/bus/chat-daemon-control.ts +8 -28
  338. package/src/sdk/bus/chat-effect-journal.ts +10 -2
  339. package/src/sdk/bus/config-commands.ts +5 -4
  340. package/src/sdk/bus/config.ts +98 -0
  341. package/src/sdk/bus/conversation-store.ts +5 -29
  342. package/src/sdk/bus/daemon-paths.ts +2 -0
  343. package/src/sdk/bus/html-format.ts +20 -3
  344. package/src/sdk/bus/index.ts +782 -94
  345. package/src/sdk/bus/lifecycle-control-runtime.ts +91 -33
  346. package/src/sdk/bus/natives-augment.d.ts +26 -1
  347. package/src/sdk/bus/notification-service.ts +168 -20
  348. package/src/sdk/bus/rate-limit-pool.ts +58 -14
  349. package/src/sdk/bus/recent-activity.ts +188 -74
  350. package/src/sdk/bus/rich-document.ts +258 -0
  351. package/src/sdk/bus/rich-render.ts +62 -70
  352. package/src/sdk/bus/telegram-daemon-cli.ts +15 -59
  353. package/src/sdk/bus/telegram-daemon-contract.ts +9 -4
  354. package/src/sdk/bus/telegram-daemon.ts +1389 -237
  355. package/src/sdk/bus/threaded-inbound.ts +8 -3
  356. package/src/sdk/bus/threaded-render.ts +57 -1
  357. package/src/sdk/bus/topic-registry.ts +120 -13
  358. package/src/sdk/host/control/dispatch.ts +14 -2
  359. package/src/sdk/host/control/operations.ts +6 -1
  360. package/src/sdk/host/host.ts +44 -2
  361. package/src/sdk/host/query/handlers.ts +20 -22
  362. package/src/sdk/host/query/revision-store.ts +80 -57
  363. package/src/sdk/index.ts +1 -0
  364. package/src/sdk/protocol/operation-inventory.generated.json +943 -1907
  365. package/src/sdk/session-directory.ts +141 -0
  366. package/src/sdk/session.ts +462 -480
  367. package/src/session/agent-session.ts +1700 -583
  368. package/src/session/agent-storage.ts +18 -0
  369. package/src/session/cache-economics.ts +25 -8
  370. package/src/session/fallback-chain-controller.ts +53 -3
  371. package/src/session/internal/managed-session-scope.ts +2226 -0
  372. package/src/session/internal/managed-session-storage.ts +453 -0
  373. package/src/session/messages.ts +91 -2
  374. package/src/session/session-manager-internal.ts +33 -0
  375. package/src/session/session-manager.ts +1112 -333
  376. package/src/session/session-storage.ts +444 -39
  377. package/src/session/volatile-context-pruning.ts +78 -0
  378. package/src/setup/credential-auto-import.ts +2 -1
  379. package/src/setup/hermes/templates/operator-instructions.v1.md +1 -1
  380. package/src/setup/provider-onboarding.ts +36 -61
  381. package/src/setup/provider-presets.json +5 -0
  382. package/src/skill-state/active-state.ts +3 -13
  383. package/src/skill-state/{deep-interview-mutation-guard.ts → workflow-mutation-guard.ts} +47 -29
  384. package/src/skill-state/workflow-state-contract.ts +6 -41
  385. package/src/slash-commands/builtin-registry.ts +46 -11
  386. package/src/system-prompt.ts +37 -44
  387. package/src/task/agents.ts +19 -1
  388. package/src/task/executor.ts +90 -6
  389. package/src/task/index.ts +36 -21
  390. package/src/thinking.ts +21 -6
  391. package/src/tool-discovery/tool-index.ts +2 -134
  392. package/src/tools/ask.ts +157 -21
  393. package/src/tools/ast-edit.ts +1 -1
  394. package/src/tools/bash.ts +38 -0
  395. package/src/tools/browser/dead-tab-recovery.ts +78 -0
  396. package/src/tools/browser/tab-supervisor.ts +282 -36
  397. package/src/tools/computer.ts +10 -3
  398. package/src/tools/cron.ts +30 -16
  399. package/src/tools/eval.ts +1 -2
  400. package/src/tools/fetch.ts +11 -4
  401. package/src/tools/index.ts +76 -24
  402. package/src/tools/output-meta.ts +19 -7
  403. package/src/tools/read.ts +219 -64
  404. package/src/tools/resource-gc.ts +2 -2
  405. package/src/tools/search-tool-bm25.ts +11 -74
  406. package/src/tools/subagent.ts +43 -2
  407. package/src/utils/event-bus.ts +9 -4
  408. package/src/utils/file-mentions.ts +4 -4
  409. package/src/web/search/index.ts +3 -3
  410. package/dist/types/discovery/plugin-dir-roots.d.ts +0 -15
  411. package/dist/types/runtime-mcp/discoverable-tool-metadata.d.ts +0 -7
  412. package/src/discovery/plugin-dir-roots.ts +0 -28
  413. package/src/runtime-mcp/discoverable-tool-metadata.ts +0 -25
@@ -25,16 +25,25 @@ import {
25
25
  classifyCgroup,
26
26
  isExactScopedBootstrapSuccessReceipt,
27
27
  isOwnerGenerationBaselineCurrentSync,
28
+ isSafeServerProof,
28
29
  type OwnerGenerationBaseline,
29
30
  type OwnerIsolationProbe,
30
31
  observeOwnerTerminal,
31
32
  ownerProcessStartTime,
32
33
  planTmuxOwnerIsolation,
33
34
  replaceOwnerGenerationSync,
35
+ sameServerIdentity,
34
36
  type TmuxServerProof,
35
37
  } from "../gjc-runtime/tmux-owner-isolation";
36
38
  import { classifyRecovery } from "../harness-control-plane/classifier";
37
39
  import { callEndpoint, EndpointUnreachableError } from "../harness-control-plane/control-endpoint";
40
+ import {
41
+ type CompletedTerminalEvent,
42
+ isOwnerLivenessBlocker,
43
+ needsVanishedOwnerBlock,
44
+ OWNER_STARTUP_BLOCKER,
45
+ reconcileOwnerLifecycle,
46
+ } from "../harness-control-plane/lifecycle-reconciliation";
38
47
  import { type ResolvedOwner, RuntimeOwner, resolveOwner, resolveOwnerLive } from "../harness-control-plane/owner";
39
48
  import { preserveDirtyWorktree } from "../harness-control-plane/preserve";
40
49
  import { RECEIPT_SPOOL_DIR_ENV } from "../harness-control-plane/receipt-spool";
@@ -252,12 +261,6 @@ function pushUnique(out: string[], value: unknown): void {
252
261
  if (typeof value === "string" && !out.includes(value)) out.push(value);
253
262
  }
254
263
 
255
- interface CompletedTerminalEvent {
256
- cursor: number;
257
- createdAt: string;
258
- kind: string;
259
- }
260
-
261
264
  function completedTerminalEvent(events: EventEnvelope[]): CompletedTerminalEvent | null {
262
265
  for (const event of [...events].reverse()) {
263
266
  const signal = (event.evidence as { signal?: unknown } | undefined)?.signal;
@@ -461,73 +464,21 @@ function updateStateWithRestoredOwner(state: SessionState, leasePath: string, re
461
464
  state.updatedAt = nowIso();
462
465
  }
463
466
 
464
- function isOwnerLivenessBlocker(blocker: string): boolean {
465
- return blocker === "detached-owner-not-live" || blocker.startsWith("owner-vanished:");
466
- }
467
-
468
- async function reconcileCompletedOwnerExited(
467
+ async function reconcileLifecycle(
469
468
  root: string,
470
469
  state: SessionState,
471
470
  observation: Observation,
472
471
  completedTerminal: CompletedTerminalEvent | null,
472
+ startupBlocked = false,
473
473
  ): Promise<SessionState> {
474
- if (!completedTerminal || observation.ownerLive || observation.gitDelta !== "clean") return state;
475
- if (state.lifecycle === "completed" || state.lifecycle === "retired") return state;
476
- state.lifecycle = "completed";
477
- state.blockers = state.blockers.filter(blocker => !isOwnerLivenessBlocker(blocker));
478
- state.updatedAt = nowIso();
479
- await writeSessionState(root, state);
480
- return state;
481
- }
482
-
483
- function needsVanishedOwnerBlock(
484
- state: SessionState,
485
- observation: Observation,
486
- completedTerminal: CompletedTerminalEvent | null,
487
- ): boolean {
488
- if (observation.ownerLive || state.lifecycle !== "observing") return false;
489
- if (completedTerminal || observation.observedSignals.includes("completed")) return false;
490
- return observation.observedSignals.some(
491
- signal => signal === "prompt-accepted" || signal === "tool-call" || signal === "streaming",
492
- );
493
- }
494
-
495
- async function markVanishedOwnerBlocked(
496
- root: string,
497
- state: SessionState,
498
- observation: Observation,
499
- completedTerminal: CompletedTerminalEvent | null,
500
- ): Promise<SessionState> {
501
- if (!needsVanishedOwnerBlock(state, observation, completedTerminal)) return state;
502
- const blocker = `owner-vanished:${observation.gitDelta}`;
503
- state.lifecycle = "blocked";
504
- state.blockers = state.blockers.includes(blocker) ? state.blockers : [...state.blockers, blocker];
505
- state.updatedAt = nowIso();
506
- await writeSessionState(root, state);
507
- return state;
508
- }
509
-
510
- const OWNER_STARTUP_BLOCKER = "owner-died-before-first-prompt";
511
-
512
- /**
513
- * Persist an explicit startup blocker when an owner started, reported live, but died before
514
- * accepting the first prompt. This makes the failure an actionable lifecycle state instead of a
515
- * silent `owner-not-live` gate, so observe/recover surface it and recover can respawn the owner.
516
- */
517
- async function markStartupOwnerBlocked(
518
- root: string,
519
- state: SessionState,
520
- ownerExit: OwnerExitEvidence,
521
- ): Promise<SessionState> {
522
- if (!ownerExit.startupBlocker) return state;
523
- if (state.lifecycle === "completed" || state.lifecycle === "retired") return state;
524
- state.lifecycle = "blocked";
525
- state.blockers = state.blockers.includes(OWNER_STARTUP_BLOCKER)
526
- ? state.blockers
527
- : [...state.blockers, OWNER_STARTUP_BLOCKER];
528
- state.updatedAt = nowIso();
529
- await writeSessionState(root, state);
530
- return state;
474
+ return reconcileOwnerLifecycle({
475
+ state,
476
+ observation,
477
+ completedTerminal,
478
+ startupBlocked,
479
+ persist: async nextState => writeSessionState(root, nextState),
480
+ nowIso,
481
+ });
531
482
  }
532
483
 
533
484
  function resolveRetryBudget(input: Record<string, unknown>): RetryBudget {
@@ -562,29 +513,6 @@ function isBoundedNoServerDiagnostic(stderr: Uint8Array): boolean {
562
513
  );
563
514
  }
564
515
 
565
- function sameServerIdentity(left: TmuxServerProof, right: TmuxServerProof): boolean {
566
- return (
567
- left.pid === right.pid &&
568
- left.startTime === right.startTime &&
569
- left.cgroup?.classification === right.cgroup?.classification &&
570
- left.cgroup?.scope === right.cgroup?.scope &&
571
- left.cgroup?.diagnostic === right.cgroup?.diagnostic
572
- );
573
- }
574
-
575
- function isSafeServerProof(proof: TmuxServerProof): boolean {
576
- return (
577
- proof.state === "safe" &&
578
- typeof proof.pid === "number" &&
579
- Number.isSafeInteger(proof.pid) &&
580
- proof.pid > 0 &&
581
- typeof proof.startTime === "string" &&
582
- proof.startTime.length > 0 &&
583
- (proof.cgroup?.classification === "safe" ||
584
- (process.platform !== "linux" && proof.cgroup?.classification === "not_applicable"))
585
- );
586
- }
587
-
588
516
  function exactNativeTmuxSessionId(stdout: Uint8Array): string | null {
589
517
  const value = new TextDecoder().decode(stdout);
590
518
  const line = value.endsWith("\n") ? value.slice(0, -1) : value;
@@ -985,7 +913,9 @@ export default class Harness extends Command {
985
913
  proof: TmuxServerProof | null,
986
914
  probeServer: OwnerIsolationProbe["probeServer"],
987
915
  ): Promise<void> {
988
- if (!nativeSessionId || !proof || !isSafeServerProof(proof)) throw new Error("tmux-owner-cleanup_uncertain");
916
+ if (!nativeSessionId || !proof || !isSafeServerProof(proof, ownerIsolationPlatform()))
917
+ throw new Error("tmux-owner-cleanup_uncertain");
918
+
989
919
  if (!(await this.#nativeSessionBoundToName(tmuxCommand, socketKey, nativeSessionId, sessionName)))
990
920
  throw new Error("tmux-owner-cleanup_uncertain");
991
921
  const current = await probeServer(socketKey, [tmuxCommand, "-L", socketKey]);
@@ -1141,7 +1071,7 @@ export default class Harness extends Command {
1141
1071
  const postSpawnServer = await probeServer(socketKey, [tmuxCommand, "-L", socketKey]);
1142
1072
  cleanupProof = postSpawnServer;
1143
1073
  if (postSpawnServer.state === "unsafe") return fail("tmux-owner-server_unsafe");
1144
- if (!isSafeServerProof(postSpawnServer)) return fail("tmux-owner-server_unverifiable");
1074
+ if (!isSafeServerProof(postSpawnServer, ownerIsolationPlatform())) return fail("tmux-owner-server_unverifiable");
1145
1075
  if (
1146
1076
  scopedReceipt &&
1147
1077
  (scopedReceipt.sessionName !== sessionName ||
@@ -1441,14 +1371,10 @@ export default class Harness extends Command {
1441
1371
  let state = await loadState(root, sessionId);
1442
1372
  const ownerLive = ownerLiveFor(state);
1443
1373
  const { observation, completedTerminalEvent } = await buildObservation(root, state, ownerLive);
1444
- state = await reconcileCompletedOwnerExited(root, state, observation, completedTerminalEvent);
1445
1374
  const vanishedOwnerBlock = needsVanishedOwnerBlock(state, observation, completedTerminalEvent);
1446
- state = await markVanishedOwnerBlocked(root, state, observation, completedTerminalEvent);
1447
- // Build owner-exit evidence whenever the owner is gone so a startup death (owner started,
1448
- // reported live, then died before the first prompt) is detectable, not just vanish/completion.
1449
1375
  const ownerExit = !ownerLive ? await buildOwnerExitEvidence(root, state) : null;
1450
1376
  const startupBlocked = ownerExit?.startupBlocker ?? false;
1451
- if (ownerExit && startupBlocked) state = await markStartupOwnerBlocked(root, state, ownerExit);
1377
+ state = await reconcileLifecycle(root, state, observation, completedTerminalEvent, startupBlocked);
1452
1378
  const includeOwnerExit = Boolean(ownerExit && (vanishedOwnerBlock || completedTerminalEvent || startupBlocked));
1453
1379
  writeJson(
1454
1380
  buildResponse(state, ownerLive, {
@@ -1482,12 +1408,7 @@ export default class Harness extends Command {
1482
1408
  if (!observation) {
1483
1409
  const built = await buildObservation(root, stateView, ownerLive);
1484
1410
  observation = built.observation;
1485
- stateView = await markVanishedOwnerBlocked(
1486
- root,
1487
- stateView,
1488
- built.observation,
1489
- built.completedTerminalEvent,
1490
- );
1411
+ stateView = await reconcileLifecycle(root, stateView, built.observation, built.completedTerminalEvent);
1491
1412
  }
1492
1413
  }
1493
1414
  if (!observation) throw new Error("classify_requires_observation_or_session");
@@ -1548,7 +1469,14 @@ export default class Harness extends Command {
1548
1469
  const ownerExit = await buildOwnerExitEvidence(root, state);
1549
1470
  // An owner that started, reported live, then died before accepting the first prompt is a
1550
1471
  // startup blocker, not a healthy `owner-not-live` gate — persist it and report it as such.
1551
- if (ownerExit.startupBlocker) state = await markStartupOwnerBlocked(root, state, ownerExit);
1472
+ const built = await buildObservation(root, state, false);
1473
+ state = await reconcileLifecycle(
1474
+ root,
1475
+ state,
1476
+ built.observation,
1477
+ built.completedTerminalEvent,
1478
+ ownerExit.startupBlocker,
1479
+ );
1552
1480
  const reason = ownerExit.startupBlocker ? ownerExit.reason : "owner-not-live";
1553
1481
  writeJson(
1554
1482
  buildResponse(
@@ -1614,7 +1542,7 @@ export default class Harness extends Command {
1614
1542
  let state = await loadState(root, sessionId);
1615
1543
  const beforeExit = await buildOwnerExitEvidence(root, state);
1616
1544
  const { observation, completedTerminalEvent } = await buildObservation(root, state, false);
1617
- state = await markVanishedOwnerBlocked(root, state, observation, completedTerminalEvent);
1545
+ state = await reconcileLifecycle(root, state, observation, completedTerminalEvent);
1618
1546
  const decision = classifyRecovery({
1619
1547
  observation: { ...observation, lifecycle: state.lifecycle },
1620
1548
  retryBudget: budget,
@@ -9,7 +9,7 @@ import { APP_NAME, setProjectDir } from "@gajae-code/utils";
9
9
  import { Args, Command, Flags } from "@gajae-code/utils/cli";
10
10
  import { parseArgs } from "../cli/args";
11
11
  import { launchDefaultTmuxIfNeeded } from "../gjc-runtime/launch-tmux";
12
- import { prepareLaunchWorktree } from "../gjc-runtime/launch-worktree";
12
+ import { type PreparedLaunchWorktree, prepareLaunchWorktree } from "../gjc-runtime/launch-worktree";
13
13
  import {
14
14
  GJC_COORDINATOR_SESSION_ID_ENV,
15
15
  GJC_COORDINATOR_SESSION_STATE_FILE_ENV,
@@ -128,7 +128,8 @@ export default class Index extends Command {
128
128
  description: "Resume a session (by ID prefix, path, or picker if omitted)",
129
129
  }),
130
130
  "session-dir": Flags.string({
131
- description: "Directory for session storage and lookup",
131
+ description:
132
+ "Explicit session storage directory and lookup override (default uses managed v2 workspace scope)",
132
133
  }),
133
134
  "no-session": Flags.boolean({
134
135
  description: "Don't save session (ephemeral)",
@@ -199,7 +200,8 @@ export default class Index extends Command {
199
200
  `# Pin a stored credential for this session\n ${APP_NAME} --credential email:me@example.com`,
200
201
  `# Activate a model profile for this session\n ${APP_NAME} --mpreset codex-medium`,
201
202
  `# Persist a model profile as the default\n ${APP_NAME} --mpreset opencodego --default`,
202
- `# Export a session file to HTML\n ${APP_NAME} --export ~/.gjc/agent/sessions/--path--/session.jsonl`,
203
+ `# Export a session file to HTML\n ${APP_NAME} --export ~/.gjc/agent/sessions/v2-<scope>/session.jsonl`,
204
+ `# Use an explicit session storage directory\n ${APP_NAME} --session-dir ./sessions`,
203
205
  ];
204
206
 
205
207
  static strict = false;
@@ -212,7 +214,7 @@ export default class Index extends Command {
212
214
  return;
213
215
  }
214
216
 
215
- let launch: ReturnType<typeof prepareLaunchWorktree>;
217
+ let launch: PreparedLaunchWorktree;
216
218
  try {
217
219
  launch = prepareLaunchWorktree(process.cwd(), args);
218
220
  } catch (error) {
@@ -1,3 +1,4 @@
1
+ import { getAgentDir } from "@gajae-code/utils";
1
2
  import { Args, Command, Flags } from "@gajae-code/utils/cli";
2
3
  import {
3
4
  COORDINATOR_MCP_PROTOCOL_VERSION,
@@ -5,12 +6,88 @@ import {
5
6
  COORDINATOR_MCP_TOOL_NAMES,
6
7
  } from "../coordinator/contract";
7
8
  import { runCoordinatorMcpStdio } from "../coordinator-mcp/server";
9
+ import { type BrokerDiscovery, readBrokerDiscovery } from "../sdk/broker/discovery";
10
+ import { UnsupportedStateVersionError } from "../sdk/broker/state-version";
8
11
  import { runSdkMcpStdio, SDK_MCP_TOOL_NAMES } from "../sdk/mcp/server";
9
12
 
10
13
  function writeJson(value: unknown): void {
11
14
  process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
12
15
  }
13
16
 
17
+ export type CoordinatorBrokerDiscoveryStatus = "ready" | "unavailable" | "error";
18
+ export type CoordinatorBrokerDiscoveryReason =
19
+ | null
20
+ | "absent_or_invalid"
21
+ | "unsupported_state_version"
22
+ | "discovery_access_denied"
23
+ | "discovery_read_failed";
24
+
25
+ export interface CoordinatorBrokerObservation {
26
+ discovery_status: CoordinatorBrokerDiscoveryStatus;
27
+ reason: CoordinatorBrokerDiscoveryReason;
28
+ }
29
+
30
+ export interface CoordinatorCheckProbe {
31
+ agentDir?: string;
32
+ readBrokerDiscovery?: (agentDir: string) => Promise<BrokerDiscovery | null>;
33
+ }
34
+
35
+ export interface CoordinatorCheckPayload {
36
+ ok: true;
37
+ server: { name: typeof COORDINATOR_MCP_SERVER_NAME; protocolVersion: typeof COORDINATOR_MCP_PROTOCOL_VERSION };
38
+ readOnly: true;
39
+ tools: readonly string[];
40
+ catalog: { ready: true; reason: null };
41
+ broker: CoordinatorBrokerObservation & {
42
+ operational_ready: null;
43
+ bootstrap_supported: true;
44
+ bootstrap_attempted: false;
45
+ };
46
+ }
47
+
48
+ function discoveryErrorCode(error: unknown): unknown {
49
+ if (typeof error !== "object" || error === null || !("code" in error)) return undefined;
50
+ return error.code;
51
+ }
52
+
53
+ export async function probeCoordinatorBrokerCheck(
54
+ probe: CoordinatorCheckProbe = {},
55
+ ): Promise<CoordinatorBrokerObservation> {
56
+ try {
57
+ const discovery = await (probe.readBrokerDiscovery ?? readBrokerDiscovery)(probe.agentDir ?? getAgentDir());
58
+ return discovery
59
+ ? { discovery_status: "ready", reason: null }
60
+ : { discovery_status: "unavailable", reason: "absent_or_invalid" };
61
+ } catch (error) {
62
+ if (error instanceof UnsupportedStateVersionError)
63
+ return { discovery_status: "error", reason: "unsupported_state_version" };
64
+ const code = discoveryErrorCode(error);
65
+ if (code === "EACCES" || code === "EPERM")
66
+ return { discovery_status: "error", reason: "discovery_access_denied" };
67
+ return { discovery_status: "error", reason: "discovery_read_failed" };
68
+ }
69
+ }
70
+
71
+ export function formatCoordinatorCheckPayload(observation: CoordinatorBrokerObservation): CoordinatorCheckPayload {
72
+ return {
73
+ ok: true,
74
+ server: { name: COORDINATOR_MCP_SERVER_NAME, protocolVersion: COORDINATOR_MCP_PROTOCOL_VERSION },
75
+ readOnly: true,
76
+ tools: [...COORDINATOR_MCP_TOOL_NAMES],
77
+ catalog: { ready: true, reason: null },
78
+ broker: {
79
+ ...observation,
80
+ operational_ready: null,
81
+ bootstrap_supported: true,
82
+ bootstrap_attempted: false,
83
+ },
84
+ };
85
+ }
86
+
87
+ export async function buildCoordinatorCheckPayload(probe?: CoordinatorCheckProbe): Promise<CoordinatorCheckPayload> {
88
+ return formatCoordinatorCheckPayload(await probeCoordinatorBrokerCheck(probe));
89
+ }
90
+
14
91
  export function validateMcpServeSubcommandForTest(server: string | undefined): void {
15
92
  if (server !== "coordinator" && server !== "hermes" && server !== "sdk")
16
93
  throw new Error(`unknown_mcp_serve_subcommand:${server ?? ""}`);
@@ -46,17 +123,17 @@ export default class McpServe extends Command {
46
123
  }
47
124
 
48
125
  if (flags.check) {
126
+ if (!flags.json) {
127
+ const serverName = server === "sdk" ? "gjc-sdk-mcp" : COORDINATOR_MCP_SERVER_NAME;
128
+ const toolCount = server === "sdk" ? SDK_MCP_TOOL_NAMES.length : COORDINATOR_MCP_TOOL_NAMES.length;
129
+ process.stdout.write(`server: ${serverName}\ntools: ${toolCount}\n`);
130
+ return;
131
+ }
49
132
  const payload =
50
133
  server === "sdk"
51
134
  ? { ok: true, server: { name: "gjc-sdk-mcp" }, readOnly: false, tools: [...SDK_MCP_TOOL_NAMES] }
52
- : {
53
- ok: true,
54
- server: { name: COORDINATOR_MCP_SERVER_NAME, protocolVersion: COORDINATOR_MCP_PROTOCOL_VERSION },
55
- readOnly: true,
56
- tools: [...COORDINATOR_MCP_TOOL_NAMES],
57
- };
58
- if (flags.json) writeJson(payload);
59
- else process.stdout.write(`server: ${payload.server.name}\ntools: ${payload.tools.length}\n`);
135
+ : await buildCoordinatorCheckPayload();
136
+ writeJson(payload);
60
137
  return;
61
138
  }
62
139
 
@@ -53,7 +53,7 @@ export default class MCP extends Command {
53
53
 
54
54
  async run(): Promise<void> {
55
55
  if (this.argv.includes("--help") || this.argv.includes("-h")) {
56
- this.printHelp();
56
+ this.#printHelp();
57
57
  return;
58
58
  }
59
59
 
@@ -80,7 +80,7 @@ export default class MCP extends Command {
80
80
  await runMCPCommand(cmd);
81
81
  }
82
82
 
83
- private printHelp(): void {
83
+ #printHelp(): void {
84
84
  process.stdout.write(`Store standalone MCP server definitions in GJC config without loading them at runtime
85
85
 
86
86
  USAGE
@@ -12,9 +12,8 @@ export default class Notify extends Command {
12
12
 
13
13
  static args = {
14
14
  action: Args.string({
15
- description: "Notify action",
15
+ description: "Notify action (setup|status|health|test|recovery|daemon-internal)",
16
16
  required: false,
17
- options: ACTIONS,
18
17
  }),
19
18
  extra: Args.string({
20
19
  description: "Provider or additional internal args",
@@ -49,7 +48,12 @@ export default class Notify extends Command {
49
48
 
50
49
  async run(): Promise<void> {
51
50
  const { args, flags } = await this.parse(Notify);
52
- const action = (args.action ?? "status") as NotifyAction;
51
+ const action = args.action ?? "status";
52
+ if (!ACTIONS.includes(action as NotifyAction)) {
53
+ console.error(`Unknown notify action: ${action}`);
54
+ console.error(`Valid actions: ${ACTIONS.join(", ")}`);
55
+ process.exit(1);
56
+ }
53
57
  const extra = Array.isArray(args.extra) ? args.extra : args.extra ? [args.extra] : [];
54
58
  const flagRec = flags as Record<string, unknown>;
55
59
  const ownerId = flagRec["owner-id"] as string | undefined;
@@ -72,7 +76,7 @@ export default class Notify extends Command {
72
76
  }
73
77
 
74
78
  const cmd: NotifyCommandArgs = {
75
- action,
79
+ action: action as NotifyAction,
76
80
  smoke: flags.smoke,
77
81
  rawArgs,
78
82
  provider: provider === "telegram" || provider === "discord" || provider === "slack" ? provider : undefined,
@@ -3,6 +3,7 @@ import * as fs from "node:fs/promises";
3
3
  import * as path from "node:path";
4
4
  import { Args, Command, Flags } from "@gajae-code/utils/cli";
5
5
  import type { Args as ParsedArgs } from "../cli/args";
6
+ import { Settings } from "../config/settings";
6
7
  import { applyStartupModelProfiles, createSessionManager } from "../main";
7
8
  import { initializeExtensions } from "../modes/runtime-init";
8
9
  import { Broker } from "../sdk/broker/broker";
@@ -16,20 +17,28 @@ import {
16
17
  } from "../sdk/broker/lifecycle";
17
18
  import { processIncarnation } from "../sdk/broker/process-incarnation";
18
19
  import { type CreateLifecycleAgentSessionResult, createLifecycleAgentSession } from "../sdk/lifecycle-session";
20
+ import { listManagedSessionCandidates, resolveManagedSessionScope } from "../sdk/session-directory";
19
21
  import {
20
22
  normalizeSdkStartupFailure,
21
23
  type SdkStartupFailure,
22
24
  type SdkStartupRollbackResult,
23
25
  SdkStartupRollbackTracker,
24
26
  } from "../sdk/startup-capability";
25
-
26
27
  import {
27
28
  type CapturedSessionTranscriptSnapshot,
28
29
  type ResumeSessionIdentity,
29
30
  SessionManager,
30
31
  } from "../session/session-manager";
31
32
 
32
- export function lifecycleArgs(request: SessionLifecycleLaunchRequest, cwd: string, agentDir: string): ParsedArgs {
33
+ export async function lifecycleArgs(
34
+ request: SessionLifecycleLaunchRequest,
35
+ cwd: string,
36
+ agentDir: string,
37
+ ): Promise<ParsedArgs> {
38
+ const targetScope = await resolveManagedSessionScope({ cwd, agentDir });
39
+ if (targetScope.kind !== "resolved") throw new Error(`Lifecycle session scope is invalid: ${targetScope.message}`);
40
+ const forkSessionDir =
41
+ request.operation === "session.fork" ? SessionManager.getDefaultSessionDir(cwd, agentDir) : undefined;
33
42
  return {
34
43
  messages: [],
35
44
  fileArgs: [],
@@ -39,7 +48,7 @@ export function lifecycleArgs(request: SessionLifecycleLaunchRequest, cwd: strin
39
48
  ...(request.operation === "session.fork"
40
49
  ? {
41
50
  fork: request.sourceSessionPath ?? request.sourceSessionId,
42
- sessionDir: SessionManager.getDefaultSessionDirReadOnly(cwd, agentDir),
51
+ sessionDir: forkSessionDir,
43
52
  }
44
53
  : {}),
45
54
  };
@@ -53,7 +62,7 @@ type LifecycleTranscriptSource = {
53
62
  };
54
63
 
55
64
  function sameTranscriptIdentity(
56
- actual: { dev: bigint; ino: bigint; size: number; mtimeMs: number; mtimeNs: bigint },
65
+ actual: { dev: bigint; ino: bigint; size: number; mtimeMs: number; mtimeNs: bigint; sha256: string },
57
66
  expected: SessionLifecycleTranscriptIdentity,
58
67
  ): boolean {
59
68
  return (
@@ -61,7 +70,8 @@ function sameTranscriptIdentity(
61
70
  actual.ino.toString() === expected.ino &&
62
71
  actual.size === expected.size &&
63
72
  actual.mtimeMs === expected.mtimeMs &&
64
- actual.mtimeNs.toString() === expected.mtimeNs
73
+ actual.mtimeNs.toString() === expected.mtimeNs &&
74
+ actual.sha256 === expected.sha256
65
75
  );
66
76
  }
67
77
 
@@ -85,26 +95,38 @@ function lifecycleTranscriptSource(request: SessionLifecycleLaunchRequest, cwd:
85
95
  throw new Error("A new lifecycle session has no persisted transcript authority.");
86
96
  }
87
97
 
88
- function verifyLifecycleTranscript(
98
+ async function captureLifecycleTranscript(
89
99
  request: SessionLifecycleLaunchRequest,
90
100
  cwd: string,
91
101
  agentDir: string,
92
- ): LifecycleTranscriptSource {
102
+ migrationPolicy: "copy-retain" | "disabled",
103
+ ): Promise<CapturedSessionTranscriptSnapshot> {
93
104
  const source = lifecycleTranscriptSource(request, cwd);
94
- const inventory = SessionManager.inventorySessionsStrict(source.cwd, {
95
- sessionDir: SessionManager.getDefaultSessionDir(source.cwd, agentDir),
96
- });
105
+ const scope = await resolveManagedSessionScope({ cwd: source.cwd, agentDir });
106
+ if (scope.kind !== "resolved")
107
+ throw new Error("Lifecycle saved session storage could not be verified for the requested workspace.");
108
+ const inventory = await listManagedSessionCandidates({ scope: scope.scope });
97
109
  if (inventory.kind !== "complete")
98
110
  throw new Error("Lifecycle saved session storage could not be verified for the requested workspace.");
99
- const matches = inventory.candidates.filter(
111
+ const captured = SessionManager.captureTranscriptStrict(source.path);
112
+ if (
113
+ captured.kind !== "captured" ||
114
+ captured.snapshot.sourcePath !== path.resolve(source.path) ||
115
+ captured.snapshot.identity.sessionId !== source.id ||
116
+ !sameTranscriptIdentity(captured.snapshot.identity, source.identity)
117
+ )
118
+ throw new Error("Lifecycle saved session authority changed before the session host consumed it.");
119
+ const matches = inventory.owned.filter(
100
120
  candidate =>
101
- candidate.path === path.resolve(source.path) &&
102
- candidate.id === source.id &&
103
- sameTranscriptIdentity(candidate.identity, source.identity),
121
+ candidate.path === captured.snapshot.sourcePath &&
122
+ candidate.sessionId === source.id &&
123
+ sameLifecycleTranscriptSnapshot(candidate.identity, captured.snapshot.identity),
104
124
  );
105
125
  if (matches.length !== 1)
106
126
  throw new Error("Lifecycle saved session authority changed before the session host started.");
107
- return source;
127
+ if (matches[0]!.provenance === "legacy" && migrationPolicy === "disabled")
128
+ throw new Error("Lifecycle legacy session migration is disabled by policy.");
129
+ return captured.snapshot;
108
130
  }
109
131
 
110
132
  function sameLifecycleTranscriptSnapshot(left: ResumeSessionIdentity, right: ResumeSessionIdentity): boolean {
@@ -120,23 +142,6 @@ function sameLifecycleTranscriptSnapshot(left: ResumeSessionIdentity, right: Res
120
142
  );
121
143
  }
122
144
 
123
- function captureLifecycleTranscript(
124
- request: SessionLifecycleLaunchRequest,
125
- cwd: string,
126
- agentDir: string,
127
- ): CapturedSessionTranscriptSnapshot {
128
- const source = verifyLifecycleTranscript(request, cwd, agentDir);
129
- const captured = SessionManager.captureTranscriptStrict(source.path);
130
- if (
131
- captured.kind !== "captured" ||
132
- captured.snapshot.sourcePath !== path.resolve(source.path) ||
133
- captured.snapshot.identity.sessionId !== source.id ||
134
- !sameTranscriptIdentity(captured.snapshot.identity, source.identity)
135
- )
136
- throw new Error("Lifecycle saved session authority changed before the session host consumed it.");
137
- return captured.snapshot;
138
- }
139
-
140
145
  async function revalidateLifecycleTranscript(snapshot: ResumeSessionIdentity): Promise<void> {
141
146
  const inspected = await SessionManager.inspectSessionTailReadOnly(snapshot.canonicalPath);
142
147
  if (inspected.kind === "error" || !sameLifecycleTranscriptSnapshot(snapshot, inspected.identity))
@@ -149,14 +154,22 @@ export async function openLifecycleSessionManager(
149
154
  cwd: string,
150
155
  agentDir: string,
151
156
  ): Promise<{ parsed: ParsedArgs; sessionManager: SessionManager | undefined }> {
152
- const parsed = lifecycleArgs(request, cwd, agentDir);
157
+ const parsed = await lifecycleArgs(request, cwd, agentDir);
158
+ const lifecycleSettings = await Settings.loadForScope({ cwd, agentDir });
159
+ const migrationPolicy =
160
+ lifecycleSettings.get("session.directoryMigration") === "disabled" ? "disabled" : "copy-retain";
153
161
  if (request.operation === "session.create") {
154
- return { parsed, sessionManager: await createSessionManager(parsed, cwd) };
162
+ return { parsed, sessionManager: await createSessionManager(parsed, cwd, lifecycleSettings) };
155
163
  }
156
- const snapshot = captureLifecycleTranscript(request, cwd, agentDir);
164
+ const snapshot = await captureLifecycleTranscript(request, cwd, agentDir, migrationPolicy);
157
165
  let sessionManager: SessionManager | undefined;
158
166
  if (request.operation === "session.resume") {
159
- const opened = await SessionManager.openExistingStrict(snapshot.identity, parsed.sessionDir);
167
+ const opened = await SessionManager.openExistingStrict(
168
+ snapshot.identity,
169
+ parsed.sessionDir,
170
+ undefined,
171
+ migrationPolicy,
172
+ );
160
173
  if (opened.kind === "error")
161
174
  throw new Error("Lifecycle saved session authority changed while the session host opened it.");
162
175
  sessionManager = opened.manager;
@@ -167,7 +180,7 @@ export async function openLifecycleSessionManager(
167
180
  throw error;
168
181
  }
169
182
  } else {
170
- const forked = await SessionManager.forkFromCaptured(snapshot, cwd, parsed.sessionDir);
183
+ const forked = await SessionManager.forkFromCaptured(snapshot, cwd, parsed.sessionDir, migrationPolicy);
171
184
  if (forked.kind === "error")
172
185
  throw new Error("Lifecycle saved session authority changed while the session host forked it.");
173
186
  sessionManager = forked.manager;
@@ -302,21 +315,23 @@ export async function runSessionHost(
302
315
  fs.readFile(transcriptPath),
303
316
  fs.stat(transcriptPath, { bigint: true }),
304
317
  ]);
318
+ const digest = createHash("sha256").update(bytes).digest("hex");
305
319
  return {
306
- digest: createHash("sha256").update(bytes).digest("hex"),
320
+ digest,
307
321
  identity: {
308
322
  dev: stat.dev.toString(),
309
323
  ino: stat.ino.toString(),
310
324
  size: Number(stat.size),
311
325
  mtimeMs: Number(stat.mtimeMs),
312
326
  mtimeNs: stat.mtimeNs.toString(),
327
+ sha256: digest,
313
328
  },
314
329
  };
315
330
  } catch {
316
331
  return undefined;
317
332
  }
318
333
  })();
319
- return disposal;
334
+ return disposal ?? Promise.resolve(undefined);
320
335
  };
321
336
  let failureRollback: Promise<void> | undefined;
322
337
  const failAfterRollback = (failure: SdkStartupFailure): Promise<void> => {
@@ -415,7 +430,13 @@ export default class Sdk extends Command {
415
430
  }
416
431
  const agentDir = flags["agent-dir"] as string | undefined;
417
432
  if (!agentDir) throw new Error("--agent-dir is required for sdk broker-internal.");
418
- const broker = new Broker({ agentDir });
433
+ const broker = new Broker({
434
+ agentDir,
435
+ resolveDirectoryMigration: async cwd => {
436
+ const policy = (await Settings.loadForScope({ cwd, agentDir })).get("session.directoryMigration");
437
+ return policy === "disabled" ? "disabled" : "copy-retain";
438
+ },
439
+ });
419
440
  await broker.start();
420
441
  if (!broker.ownsDiscovery) return;
421
442
  const stop = () => void broker.stop().finally(() => process.exit(0));
@@ -26,15 +26,18 @@ export default class Ultragoal extends Command {
26
26
  if (isReviewStart && !result.createdReviewPlan && (result.reviewBlockerGoalIds?.length ?? 0) === 0) return;
27
27
 
28
28
  const cwd = process.cwd();
29
- const { objective, goalsPath } = await readUltragoalGjcObjective(cwd);
29
+ const { objective, goalsPath, provenance } = await readUltragoalGjcObjective(cwd);
30
+
30
31
  await writeCurrentSessionGoalModeState({
31
32
  sessionFile: process.env[GJC_SESSION_FILE_ENV],
32
33
  objective,
34
+ provenance,
33
35
  });
34
36
  await writePendingGoalModeRequest({
35
37
  cwd,
36
38
  objective,
37
39
  goalsPath,
40
+ provenance,
38
41
  sessionId: process.env[GJC_SESSION_ID_ENV],
39
42
  });
40
43
  }