@gajae-code/coding-agent 0.11.1 → 0.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (404) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/dist/types/cli/config-cli.d.ts +11 -1
  3. package/dist/types/cli/notify-cli.d.ts +1 -0
  4. package/dist/types/cli/session-picker.d.ts +2 -1
  5. package/dist/types/cli/setup-cli.d.ts +1 -1
  6. package/dist/types/commands/mcp-serve.d.ts +33 -0
  7. package/dist/types/commands/mcp.d.ts +1 -1
  8. package/dist/types/commands/notify.d.ts +0 -2
  9. package/dist/types/commands/sdk.d.ts +1 -1
  10. package/dist/types/config/atomic-yaml-patch.d.ts +18 -0
  11. package/dist/types/config/file-lock.d.ts +14 -4
  12. package/dist/types/config/keybindings.d.ts +42 -1
  13. package/dist/types/config/model-auth.d.ts +3 -0
  14. package/dist/types/config/model-bindings-applier.d.ts +13 -0
  15. package/dist/types/config/model-discovery-manager.d.ts +49 -0
  16. package/dist/types/config/model-equivalence.d.ts +20 -0
  17. package/dist/types/config/model-registry.d.ts +16 -15
  18. package/dist/types/config/model-resolver.d.ts +28 -18
  19. package/dist/types/config/models-config-schema.d.ts +11 -0
  20. package/dist/types/config/settings-schema.d.ts +56 -1
  21. package/dist/types/config/settings.d.ts +14 -11
  22. package/dist/types/coordinator-mcp/policy.d.ts +5 -0
  23. package/dist/types/coordinator-mcp/question-gate-codec.d.ts +129 -0
  24. package/dist/types/coordinator-mcp/question-state.d.ts +356 -0
  25. package/dist/types/coordinator-mcp/server.d.ts +4 -0
  26. package/dist/types/discovery/helpers.d.ts +0 -6
  27. package/dist/types/edit/index.d.ts +3 -0
  28. package/dist/types/eval/py/env.d.ts +9 -0
  29. package/dist/types/extensibility/extensions/loader.d.ts +2 -1
  30. package/dist/types/extensibility/extensions/runner.d.ts +2 -2
  31. package/dist/types/extensibility/extensions/types.d.ts +34 -3
  32. package/dist/types/extensibility/hooks/runner.d.ts +1 -1
  33. package/dist/types/extensibility/shared-events.d.ts +2 -0
  34. package/dist/types/gjc-runtime/deep-interview-recorder.d.ts +10 -1
  35. package/dist/types/gjc-runtime/deep-interview-state.d.ts +44 -0
  36. package/dist/types/gjc-runtime/goal-mode-request.d.ts +11 -1
  37. package/dist/types/gjc-runtime/launch-worktree.d.ts +4 -2
  38. package/dist/types/gjc-runtime/linux-proc.d.ts +29 -0
  39. package/dist/types/gjc-runtime/session-resolution.d.ts +2 -2
  40. package/dist/types/gjc-runtime/state-migrations.d.ts +1 -1
  41. package/dist/types/gjc-runtime/state-writer.d.ts +2 -1
  42. package/dist/types/gjc-runtime/team-launch.d.ts +59 -0
  43. package/dist/types/gjc-runtime/team-notify.d.ts +45 -0
  44. package/dist/types/gjc-runtime/team-runtime.d.ts +29 -121
  45. package/dist/types/gjc-runtime/team-store.d.ts +160 -0
  46. package/dist/types/gjc-runtime/team-workers.d.ts +78 -0
  47. package/dist/types/gjc-runtime/tmux-owner-isolation.d.ts +8 -0
  48. package/dist/types/gjc-runtime/ultragoal-change-set.d.ts +13 -0
  49. package/dist/types/gjc-runtime/ultragoal-evidence.d.ts +38 -0
  50. package/dist/types/gjc-runtime/ultragoal-guard.d.ts +7 -0
  51. package/dist/types/gjc-runtime/ultragoal-pipeline.d.ts +23 -0
  52. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +55 -33
  53. package/dist/types/gjc-runtime/workflow-cli-common.d.ts +8 -0
  54. package/dist/types/gjc-runtime/workflow-manifest.d.ts +3 -0
  55. package/dist/types/goals/continuation-timeout-guard.d.ts +22 -0
  56. package/dist/types/goals/runtime.d.ts +1 -0
  57. package/dist/types/goals/state.d.ts +8 -0
  58. package/dist/types/harness-control-plane/lifecycle-reconciliation.d.ts +17 -0
  59. package/dist/types/harness-control-plane/phase-rollup.d.ts +4 -7
  60. package/dist/types/harness-control-plane/receipt-ingest.d.ts +5 -0
  61. package/dist/types/harness-control-plane/receipt-spool.d.ts +4 -0
  62. package/dist/types/hindsight/state.d.ts +11 -4
  63. package/dist/types/lsp/lspmux.d.ts +5 -3
  64. package/dist/types/lsp/path-trust.d.ts +1 -0
  65. package/dist/types/main.d.ts +3 -2
  66. package/dist/types/memories/storage.d.ts +1 -0
  67. package/dist/types/modes/action-registry.d.ts +29 -0
  68. package/dist/types/modes/components/chrome.d.ts +14 -0
  69. package/dist/types/modes/components/command-palette.d.ts +27 -0
  70. package/dist/types/modes/components/custom-provider-wizard.d.ts +1 -0
  71. package/dist/types/modes/components/index.d.ts +2 -1
  72. package/dist/types/modes/components/pet-selector.d.ts +1 -1
  73. package/dist/types/modes/components/plan-preview-overlay.d.ts +43 -0
  74. package/dist/types/modes/components/queue-mode-selector.d.ts +1 -1
  75. package/dist/types/modes/components/queue-pane.d.ts +12 -0
  76. package/dist/types/modes/components/read-tool-group.d.ts +6 -0
  77. package/dist/types/modes/components/session-observer-overlay.d.ts +3 -4
  78. package/dist/types/modes/components/sessions-dashboard.d.ts +32 -0
  79. package/dist/types/modes/components/settings-selector.d.ts +1 -1
  80. package/dist/types/modes/components/show-images-selector.d.ts +1 -1
  81. package/dist/types/modes/components/status-line/types.d.ts +1 -1
  82. package/dist/types/modes/components/status-line.d.ts +1 -94
  83. package/dist/types/modes/components/tasks-pane.d.ts +15 -0
  84. package/dist/types/modes/components/theme-selector.d.ts +1 -1
  85. package/dist/types/modes/components/tool-execution.d.ts +15 -0
  86. package/dist/types/modes/components/tool-status-header.d.ts +111 -0
  87. package/dist/types/modes/components/transcript-viewer-overlay.d.ts +42 -0
  88. package/dist/types/modes/controllers/goal-mode-controller.d.ts +62 -0
  89. package/dist/types/modes/controllers/input-controller.d.ts +8 -1
  90. package/dist/types/modes/controllers/mode-gate.d.ts +8 -0
  91. package/dist/types/modes/controllers/plan-mode-controller.d.ts +65 -0
  92. package/dist/types/modes/controllers/selector-controller.d.ts +15 -3
  93. package/dist/types/modes/controllers/stt-controller.d.ts +26 -0
  94. package/dist/types/modes/interactive-mode.d.ts +19 -17
  95. package/dist/types/modes/jobs-observer.d.ts +2 -0
  96. package/dist/types/modes/shared/agent-wire/deep-interview-gate.d.ts +4 -11
  97. package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +20 -2
  98. package/dist/types/modes/shared/agent-wire/workflow-gate-types.d.ts +31 -0
  99. package/dist/types/modes/tasks-aggregator.d.ts +39 -0
  100. package/dist/types/modes/transcript-item-registry.d.ts +60 -0
  101. package/dist/types/modes/types.d.ts +20 -13
  102. package/dist/types/modes/utils/ui-helpers.d.ts +2 -2
  103. package/dist/types/runtime-mcp/manager.d.ts +1 -1
  104. package/dist/types/sdk/broker/broker.d.ts +78 -12
  105. package/dist/types/sdk/broker/lifecycle-codec.d.ts +4 -0
  106. package/dist/types/sdk/broker/lifecycle-ledger.d.ts +15 -1
  107. package/dist/types/sdk/broker/lifecycle.d.ts +6 -2
  108. package/dist/types/sdk/broker/process-incarnation.d.ts +2 -0
  109. package/dist/types/sdk/broker/session-index.d.ts +0 -1
  110. package/dist/types/sdk/broker/state-version.d.ts +2 -0
  111. package/dist/types/sdk/bus/chat-effect-journal.d.ts +1 -0
  112. package/dist/types/sdk/bus/config-commands.d.ts +1 -1
  113. package/dist/types/sdk/bus/config.d.ts +11 -0
  114. package/dist/types/sdk/bus/daemon-paths.d.ts +1 -0
  115. package/dist/types/sdk/bus/html-format.d.ts +3 -2
  116. package/dist/types/sdk/bus/index.d.ts +27 -0
  117. package/dist/types/sdk/bus/lifecycle-control-runtime.d.ts +4 -0
  118. package/dist/types/sdk/bus/notification-service.d.ts +20 -0
  119. package/dist/types/sdk/bus/rate-limit-pool.d.ts +13 -2
  120. package/dist/types/sdk/bus/recent-activity.d.ts +21 -12
  121. package/dist/types/sdk/bus/rich-document.d.ts +7 -0
  122. package/dist/types/sdk/bus/rich-render.d.ts +18 -41
  123. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +9 -4
  124. package/dist/types/sdk/bus/telegram-daemon.d.ts +46 -3
  125. package/dist/types/sdk/bus/threaded-inbound.d.ts +1 -1
  126. package/dist/types/sdk/bus/threaded-render.d.ts +13 -0
  127. package/dist/types/sdk/bus/topic-registry.d.ts +24 -2
  128. package/dist/types/sdk/host/control/operations.d.ts +1 -1
  129. package/dist/types/sdk/host/host.d.ts +2 -0
  130. package/dist/types/sdk/index.d.ts +1 -0
  131. package/dist/types/sdk/session-directory.d.ts +56 -0
  132. package/dist/types/session/agent-session.d.ts +82 -47
  133. package/dist/types/session/agent-storage.d.ts +7 -0
  134. package/dist/types/session/fallback-chain-controller.d.ts +10 -2
  135. package/dist/types/session/internal/managed-session-scope.d.ts +102 -0
  136. package/dist/types/session/internal/managed-session-storage.d.ts +38 -0
  137. package/dist/types/session/messages.d.ts +16 -0
  138. package/dist/types/session/session-manager-internal.d.ts +14 -0
  139. package/dist/types/session/session-manager.d.ts +82 -12
  140. package/dist/types/session/session-storage.d.ts +43 -3
  141. package/dist/types/session/volatile-context-pruning.d.ts +15 -0
  142. package/dist/types/skill-state/{deep-interview-mutation-guard.d.ts → workflow-mutation-guard.d.ts} +24 -8
  143. package/dist/types/skill-state/workflow-state-contract.d.ts +1 -3
  144. package/dist/types/slash-commands/builtin-registry.d.ts +4 -1
  145. package/dist/types/system-prompt.d.ts +2 -11
  146. package/dist/types/task/executor.d.ts +3 -1
  147. package/dist/types/thinking.d.ts +7 -0
  148. package/dist/types/tool-discovery/tool-index.d.ts +1 -50
  149. package/dist/types/tools/ask.d.ts +64 -2
  150. package/dist/types/tools/bash.d.ts +3 -0
  151. package/dist/types/tools/browser/dead-tab-recovery.d.ts +24 -0
  152. package/dist/types/tools/browser/tab-supervisor.d.ts +21 -0
  153. package/dist/types/tools/cron.d.ts +2 -0
  154. package/dist/types/tools/fetch.d.ts +1 -0
  155. package/dist/types/tools/index.d.ts +30 -15
  156. package/dist/types/tools/output-meta.d.ts +1 -0
  157. package/dist/types/tools/read.d.ts +3 -0
  158. package/dist/types/tools/search-tool-bm25.d.ts +3 -4
  159. package/dist/types/utils/event-bus.d.ts +1 -1
  160. package/dist/types/web/search/index.d.ts +3 -1
  161. package/package.json +21 -9
  162. package/scripts/build-sdk-package-smoke.ts +34 -1
  163. package/scripts/generate-hotkeys-docs.ts +74 -0
  164. package/scripts/generate-sdk-operation-inventory.ts +64 -20
  165. package/scripts/verify-gjc-sdk-canonicalization.ts +182 -2
  166. package/src/async/job-manager.ts +49 -6
  167. package/src/cli/config-cli.ts +75 -2
  168. package/src/cli/notify-cli.ts +92 -26
  169. package/src/cli/session-picker.ts +20 -3
  170. package/src/cli/setup-cli.ts +1 -1
  171. package/src/cli.ts +1 -1
  172. package/src/commands/config.ts +1 -1
  173. package/src/commands/harness.ts +34 -106
  174. package/src/commands/launch.ts +6 -4
  175. package/src/commands/mcp-serve.ts +85 -8
  176. package/src/commands/mcp.ts +2 -2
  177. package/src/commands/notify.ts +8 -4
  178. package/src/commands/sdk.ts +61 -40
  179. package/src/commands/ultragoal.ts +4 -1
  180. package/src/config/atomic-yaml-patch.ts +80 -13
  181. package/src/config/file-lock.ts +105 -43
  182. package/src/config/keybindings.ts +64 -20
  183. package/src/config/model-auth.ts +9 -0
  184. package/src/config/model-bindings-applier.ts +139 -0
  185. package/src/config/model-discovery-manager.ts +224 -0
  186. package/src/config/model-equivalence.ts +66 -0
  187. package/src/config/model-registry.ts +169 -302
  188. package/src/config/model-resolver.ts +361 -369
  189. package/src/config/models-config-schema.ts +5 -4
  190. package/src/config/settings-schema.ts +159 -2
  191. package/src/config/settings.ts +458 -482
  192. package/src/coordinator-mcp/policy.ts +76 -11
  193. package/src/coordinator-mcp/question-gate-codec.ts +274 -0
  194. package/src/coordinator-mcp/question-state.ts +778 -0
  195. package/src/coordinator-mcp/server.ts +1702 -238
  196. package/src/debug/index.ts +1 -1
  197. package/src/defaults/gjc/skills/deep-interview/SKILL.md +13 -1
  198. package/src/defaults/gjc/skills/team/SKILL.md +16 -0
  199. package/src/discovery/helpers.ts +1 -50
  200. package/src/edit/index.ts +64 -0
  201. package/src/eval/py/env.ts +26 -0
  202. package/src/eval/py/kernel.ts +5 -3
  203. package/src/extensibility/extensions/loader.ts +9 -1
  204. package/src/extensibility/extensions/runner.ts +12 -3
  205. package/src/extensibility/extensions/types.ts +39 -1
  206. package/src/extensibility/gjc-plugins/installer.ts +16 -16
  207. package/src/extensibility/hooks/runner.ts +2 -2
  208. package/src/extensibility/runtime-skill-discovery.ts +33 -13
  209. package/src/extensibility/shared-events.ts +2 -0
  210. package/src/gjc-runtime/deep-interview-recorder.ts +63 -3
  211. package/src/gjc-runtime/deep-interview-runtime.ts +76 -27
  212. package/src/gjc-runtime/deep-interview-state.ts +317 -5
  213. package/src/gjc-runtime/goal-mode-request.ts +55 -8
  214. package/src/gjc-runtime/launch-tmux.ts +2 -5
  215. package/src/gjc-runtime/launch-worktree.ts +5 -5
  216. package/src/gjc-runtime/linux-proc.ts +71 -0
  217. package/src/gjc-runtime/ralplan-runtime.ts +74 -90
  218. package/src/gjc-runtime/session-resolution.ts +18 -3
  219. package/src/gjc-runtime/session-state-sidecar.ts +6 -107
  220. package/src/gjc-runtime/state-migrations.ts +1 -1
  221. package/src/gjc-runtime/state-runtime.ts +320 -249
  222. package/src/gjc-runtime/state-writer.ts +36 -40
  223. package/src/gjc-runtime/team-launch.ts +319 -0
  224. package/src/gjc-runtime/team-notify.ts +326 -0
  225. package/src/gjc-runtime/team-runtime.ts +1099 -1482
  226. package/src/gjc-runtime/team-store.ts +828 -0
  227. package/src/gjc-runtime/team-workers.ts +962 -0
  228. package/src/gjc-runtime/tmux-owner-isolation-cli.ts +2 -11
  229. package/src/gjc-runtime/tmux-owner-isolation.ts +14 -9
  230. package/src/gjc-runtime/tmux-sessions.ts +4 -21
  231. package/src/gjc-runtime/ultragoal-change-set.ts +172 -0
  232. package/src/gjc-runtime/ultragoal-evidence.ts +874 -0
  233. package/src/gjc-runtime/ultragoal-guard.ts +29 -5
  234. package/src/gjc-runtime/ultragoal-pipeline.ts +306 -0
  235. package/src/gjc-runtime/ultragoal-runtime.ts +84 -1311
  236. package/src/gjc-runtime/workflow-cli-common.ts +30 -0
  237. package/src/gjc-runtime/workflow-manifest.generated.json +58 -0
  238. package/src/gjc-runtime/workflow-manifest.ts +18 -0
  239. package/src/goals/continuation-timeout-guard.ts +79 -0
  240. package/src/goals/runtime.ts +7 -5
  241. package/src/goals/state.ts +18 -0
  242. package/src/harness-control-plane/lifecycle-reconciliation.ts +64 -0
  243. package/src/harness-control-plane/phase-rollup.ts +4 -7
  244. package/src/harness-control-plane/receipt-ingest.ts +5 -0
  245. package/src/harness-control-plane/receipt-spool.ts +51 -7
  246. package/src/harness-control-plane/session-lease.ts +12 -130
  247. package/src/hindsight/backend.ts +26 -27
  248. package/src/hindsight/state.ts +101 -32
  249. package/src/hooks/skill-state.ts +17 -11
  250. package/src/internal-urls/docs-index.generated.ts +21 -18
  251. package/src/lsp/client.ts +1 -1
  252. package/src/lsp/config.ts +145 -26
  253. package/src/lsp/index.ts +1 -1
  254. package/src/lsp/lspmux.ts +39 -10
  255. package/src/lsp/path-trust.ts +81 -0
  256. package/src/main.ts +28 -8
  257. package/src/memories/index.ts +1 -0
  258. package/src/memories/storage.ts +6 -2
  259. package/src/modes/action-registry.ts +165 -0
  260. package/src/modes/components/chrome.ts +40 -0
  261. package/src/modes/components/command-palette.ts +168 -0
  262. package/src/modes/components/custom-editor.ts +1 -1
  263. package/src/modes/components/custom-provider-wizard.ts +51 -14
  264. package/src/modes/components/index.ts +2 -1
  265. package/src/modes/components/pet-selector.ts +11 -17
  266. package/src/modes/components/plan-preview-overlay.ts +295 -0
  267. package/src/modes/components/queue-mode-selector.ts +10 -27
  268. package/src/modes/components/queue-pane.ts +79 -0
  269. package/src/modes/components/read-tool-group.ts +13 -0
  270. package/src/modes/components/session-observer-overlay.ts +207 -772
  271. package/src/modes/components/sessions-dashboard.ts +181 -0
  272. package/src/modes/components/settings-selector.ts +1 -1
  273. package/src/modes/components/show-images-selector.ts +10 -24
  274. package/src/modes/components/status-line/types.ts +1 -1
  275. package/src/modes/components/status-line.ts +1 -969
  276. package/src/modes/components/tasks-pane.ts +73 -0
  277. package/src/modes/components/theme-selector.ts +11 -31
  278. package/src/modes/components/tool-execution.ts +22 -0
  279. package/src/modes/components/tool-status-header.ts +1056 -0
  280. package/src/modes/components/transcript-viewer-overlay.ts +384 -0
  281. package/src/modes/controllers/btw-controller.ts +1 -0
  282. package/src/modes/controllers/event-controller.ts +3 -2
  283. package/src/modes/controllers/extension-ui-controller.ts +24 -1
  284. package/src/modes/controllers/goal-mode-controller.ts +474 -0
  285. package/src/modes/controllers/input-controller.ts +764 -229
  286. package/src/modes/controllers/mode-gate.ts +24 -0
  287. package/src/modes/controllers/plan-mode-controller.ts +517 -0
  288. package/src/modes/controllers/selector-controller.ts +225 -10
  289. package/src/modes/controllers/stt-controller.ts +125 -0
  290. package/src/modes/interactive-mode.ts +289 -1150
  291. package/src/modes/jobs-observer.ts +3 -0
  292. package/src/modes/runtime-init.ts +8 -0
  293. package/src/modes/shared/agent-wire/deep-interview-gate.ts +31 -106
  294. package/src/modes/shared/agent-wire/workflow-gate-broker.ts +71 -16
  295. package/src/modes/shared/agent-wire/workflow-gate-types.ts +177 -0
  296. package/src/modes/tasks-aggregator.ts +199 -0
  297. package/src/modes/transcript-item-registry.ts +229 -0
  298. package/src/modes/types.ts +45 -18
  299. package/src/modes/utils/ui-helpers.ts +17 -9
  300. package/src/prompts/agent-fragments/ralplan-persistence.md +6 -0
  301. package/src/prompts/agent-fragments/restricted-bash.md +1 -0
  302. package/src/prompts/agents/architect.md +2 -8
  303. package/src/prompts/agents/critic.md +2 -8
  304. package/src/prompts/agents/executor.md +3 -0
  305. package/src/prompts/agents/planner.md +4 -12
  306. package/src/prompts/system/custom-system-prompt.md +1 -23
  307. package/src/prompts/system/plan-mode-approved.md +8 -0
  308. package/src/prompts/system/system-prompt.md +17 -96
  309. package/src/prompts/tools/bash.md +4 -4
  310. package/src/prompts/tools/browser.md +15 -52
  311. package/src/prompts/tools/find.md +2 -2
  312. package/src/prompts/tools/hashline.md +13 -55
  313. package/src/prompts/tools/read.md +3 -6
  314. package/src/prompts/tools/search-tool-bm25.md +0 -2
  315. package/src/prompts/tools/search.md +2 -4
  316. package/src/prompts/tools/skill-discovery.md +1 -2
  317. package/src/prompts/tools/task.md +1 -1
  318. package/src/runtime-mcp/manager.ts +1 -1
  319. package/src/sdk/broker/broker.ts +206 -78
  320. package/src/sdk/broker/discovery.ts +1 -1
  321. package/src/sdk/broker/ensure.ts +3 -1
  322. package/src/sdk/broker/lifecycle-codec.ts +11 -0
  323. package/src/sdk/broker/lifecycle-ledger.ts +371 -74
  324. package/src/sdk/broker/lifecycle.ts +1399 -142
  325. package/src/sdk/broker/process-incarnation.ts +5 -13
  326. package/src/sdk/broker/session-index.ts +145 -56
  327. package/src/sdk/broker/state-version.ts +21 -0
  328. package/src/sdk/broker/transport.ts +1 -1
  329. package/src/sdk/bus/chat-daemon-cli.ts +2 -0
  330. package/src/sdk/bus/chat-daemon-control.ts +8 -28
  331. package/src/sdk/bus/chat-effect-journal.ts +10 -2
  332. package/src/sdk/bus/config-commands.ts +5 -4
  333. package/src/sdk/bus/config.ts +98 -0
  334. package/src/sdk/bus/conversation-store.ts +5 -29
  335. package/src/sdk/bus/daemon-paths.ts +2 -0
  336. package/src/sdk/bus/html-format.ts +20 -3
  337. package/src/sdk/bus/index.ts +778 -93
  338. package/src/sdk/bus/lifecycle-control-runtime.ts +91 -33
  339. package/src/sdk/bus/natives-augment.d.ts +26 -1
  340. package/src/sdk/bus/notification-service.ts +168 -20
  341. package/src/sdk/bus/rate-limit-pool.ts +58 -14
  342. package/src/sdk/bus/recent-activity.ts +188 -74
  343. package/src/sdk/bus/rich-document.ts +258 -0
  344. package/src/sdk/bus/rich-render.ts +62 -70
  345. package/src/sdk/bus/telegram-daemon-cli.ts +15 -59
  346. package/src/sdk/bus/telegram-daemon-contract.ts +9 -4
  347. package/src/sdk/bus/telegram-daemon.ts +1389 -237
  348. package/src/sdk/bus/threaded-inbound.ts +8 -3
  349. package/src/sdk/bus/threaded-render.ts +57 -1
  350. package/src/sdk/bus/topic-registry.ts +120 -13
  351. package/src/sdk/host/control/dispatch.ts +14 -2
  352. package/src/sdk/host/control/operations.ts +6 -1
  353. package/src/sdk/host/host.ts +31 -1
  354. package/src/sdk/host/query/handlers.ts +20 -22
  355. package/src/sdk/host/query/revision-store.ts +80 -57
  356. package/src/sdk/index.ts +1 -0
  357. package/src/sdk/protocol/operation-inventory.generated.json +943 -1907
  358. package/src/sdk/session-directory.ts +141 -0
  359. package/src/sdk/session.ts +458 -479
  360. package/src/session/agent-session.ts +1700 -583
  361. package/src/session/agent-storage.ts +18 -0
  362. package/src/session/cache-economics.ts +25 -8
  363. package/src/session/fallback-chain-controller.ts +53 -3
  364. package/src/session/internal/managed-session-scope.ts +2226 -0
  365. package/src/session/internal/managed-session-storage.ts +453 -0
  366. package/src/session/messages.ts +91 -2
  367. package/src/session/session-manager-internal.ts +33 -0
  368. package/src/session/session-manager.ts +1112 -333
  369. package/src/session/session-storage.ts +444 -39
  370. package/src/session/volatile-context-pruning.ts +78 -0
  371. package/src/setup/credential-auto-import.ts +2 -1
  372. package/src/setup/hermes/templates/operator-instructions.v1.md +1 -1
  373. package/src/setup/provider-onboarding.ts +36 -61
  374. package/src/setup/provider-presets.json +5 -0
  375. package/src/skill-state/active-state.ts +3 -13
  376. package/src/skill-state/{deep-interview-mutation-guard.ts → workflow-mutation-guard.ts} +47 -29
  377. package/src/skill-state/workflow-state-contract.ts +6 -41
  378. package/src/slash-commands/builtin-registry.ts +46 -11
  379. package/src/system-prompt.ts +37 -44
  380. package/src/task/agents.ts +19 -1
  381. package/src/task/executor.ts +90 -6
  382. package/src/task/index.ts +36 -21
  383. package/src/thinking.ts +21 -6
  384. package/src/tool-discovery/tool-index.ts +2 -134
  385. package/src/tools/ask.ts +157 -21
  386. package/src/tools/ast-edit.ts +1 -1
  387. package/src/tools/bash.ts +38 -0
  388. package/src/tools/browser/dead-tab-recovery.ts +78 -0
  389. package/src/tools/browser/tab-supervisor.ts +282 -36
  390. package/src/tools/computer.ts +10 -3
  391. package/src/tools/cron.ts +30 -16
  392. package/src/tools/eval.ts +1 -2
  393. package/src/tools/fetch.ts +11 -4
  394. package/src/tools/index.ts +76 -24
  395. package/src/tools/output-meta.ts +13 -5
  396. package/src/tools/read.ts +37 -1
  397. package/src/tools/resource-gc.ts +2 -2
  398. package/src/tools/search-tool-bm25.ts +11 -74
  399. package/src/utils/event-bus.ts +9 -4
  400. package/src/web/search/index.ts +3 -3
  401. package/dist/types/discovery/plugin-dir-roots.d.ts +0 -15
  402. package/dist/types/runtime-mcp/discoverable-tool-metadata.d.ts +0 -7
  403. package/src/discovery/plugin-dir-roots.ts +0 -28
  404. package/src/runtime-mcp/discoverable-tool-metadata.ts +0 -25
@@ -443,7 +443,7 @@ export class DebugSelectorComponent extends Container {
443
443
  return {
444
444
  model: this.ctx.session.model?.id,
445
445
  thinkingLevel: this.ctx.session.thinkingLevel,
446
- planModeEnabled: this.ctx.planModeEnabled,
446
+ planModeEnabled: this.ctx.planModeController.enabled,
447
447
  toolOutputExpanded: this.ctx.toolOutputExpanded,
448
448
  hideThinkingBlock: this.ctx.hideThinkingBlock,
449
449
  };
@@ -248,11 +248,19 @@ I'm reading this as {N} top-level component(s):
248
248
  1. {component_name}: {one_sentence_description}
249
249
  2. ...
250
250
 
251
- Is that topology right? Should any component be added, removed, merged, split, or explicitly deferred?
251
+ Locked intent:
252
+ - Artifacts: {category-prefixed IDs and concrete outputs}
253
+ - Surfaces: {category-prefixed IDs and user-visible surfaces}
254
+ - Integrations: {category-prefixed IDs and external/system boundaries}
255
+ - Constraints: {category-prefixed IDs and user-locked constraints}
256
+
257
+ Is that topology and locked intent right? Should any component or intent be added, removed, merged, split, or explicitly deferred?
252
258
  ```
253
259
 
254
260
  Options should include contextually relevant choices such as **Looks right**, **Add/remove/merge components**, **Defer one or more components**, plus free-text, translated/localized according to `language.instruction` when present. This is the only pre-scoring question and preserves the one-question-per-round rule.
255
261
 
262
+ The Round 0 `ask` call MUST include `deepInterview.round = 0`, `deepInterview.component = "review-topology"`, `deepInterview.dimension = "topology"`, `deepInterview.intent_contract.items` containing the exact displayed locked-intent items, and `deepInterview.intent_contract.confirmation_options` listing only the displayed affirmative labels that lock the proposal (normally **Looks right**). The runtime recorder canonicalizes and locks this contract only when the user selects one of those labels; correction, deferral, free-text, and clarification answers never lock the pre-question proposal. Do not manually copy raw free text into intent evidence, and do not continue if this required recorder write fails.
263
+
256
264
  3. **Lock topology into state** after the answer. Store a normalized component list and confirmation timestamp:
257
265
 
258
266
  ```json
@@ -288,6 +296,10 @@ Options should include contextually relevant choices such as **Looks right**, **
288
296
  }
289
297
  ```
290
298
 
299
+ In the same Round 0 answer, the runtime recorder persists `state.intent_contract` version 1 from `deepInterview.intent_contract.items`. It contains the four exact categories `artifact`, `surface`, `integration`, and `constraint`; every item has a unique category-prefixed ID (for example `surface:review`) and a bounded non-empty statement. The recorder canonically sorts items, persists the full SHA-256 manifest digest, and binds confirmation to a redacted answer-hash reference. The confirmation answer locks this manifest before Round 1; later prose, inferred implementation detail, raw answer content, or a regenerated digest cannot replace it.
300
+
301
+ Before spec persistence, include every preserved locked ID literally in the final spec. Additions and clarifications need no extra question; the runtime derives and persists a `not_required` review when every locked ID remains. For any proposed missing locked ID, ask one intent-review question through `ask` and include `deepInterview.intent_review` with the proposed `observed_items`, every `supporting_substitution`, and the exact `approval_options` labels that count as approval. The runtime recorder writes `pending` when the user does not approve and writes `approved` only when an approval option is selected, binding the review to the recorder-generated answer hash without storing raw answer text. Approved reductions require every removed ID to map to an observed replacement ID. Spec persistence and handoff fail closed for missing, pending, malformed, stale, or unrecorded reduction review evidence. Intent review approves only that output reduction and never authorizes execution or ralplan handoff.
302
+
291
303
  4. **Legacy state migration:** When resuming an existing `deep-interview` state file that lacks `topology`, treat it as `"status": "legacy_missing"`. If no final `spec_path` exists yet, run Round 0 before the next ambiguity scoring pass and then continue with the existing transcript. If a final spec already exists, do not rewrite history; note in any handoff that topology was not captured for that legacy interview.
292
304
 
293
305
  5. **Single-component pass-through:** If the user confirms one active component, Phase 2 proceeds with the existing flow while still carrying `topology.components[0]` into scoring and spec output.
@@ -203,6 +203,22 @@ sleep 30 && gjc team monitor <team-name>
203
203
  ```
204
204
  The mutating monitor path also performs bounded liveness recovery: expired task claims, stale heartbeat claims, and missing recorded worker panes are requeued instead of leaving work permanently `in_progress`.
205
205
 
206
+ ### Opt-in stalled-worker continuation
207
+
208
+ `GJC_TEAM_AUTO_CONTINUE_STALLED_WORKERS=1` enables a separate, default-off monitor-only nudge for a stalled live worker. It is considered only when the team is running (not dry-run), the worker heartbeat is stale (using `GJC_TEAM_HEARTBEAT_STALE_MS`, default `120000` ms), and all of these checks pass:
209
+
210
+ - The recorded pane id is a non-leader `%<number>` pane that tmux currently reports in the recorded `tmux_target` as that same pane id; no other pane is targeted.
211
+ - Shutdown authority is proven absent; valid-present and invalid/unreadable records veto continuation without suppressing normal stale-claim recovery.
212
+ - Lifecycle is `ready` or `working`, and worker status is a structurally valid non-terminal state (not `draining`, `failed`, or `unknown`).
213
+ - One current non-terminal task is `in_progress`, assigned to and claimed by that worker; the stored claim record exactly matches its owner, token, and lease.
214
+ - The lease remains valid through the entire next hold interval.
215
+
216
+ The policy has at most two attempts per immutable incident: attempt 1 reserves a 30-second hold, then attempt 2 reserves a 120-second hold only after attempt 1 was recorded as sent and its hold elapsed. A retry still requires the heartbeat to be stale and every fence above to pass. Reservations and outcomes are create-without-clobber journal records keyed to the incident identity; a pre-existing reservation, an unknown/missing/non-sent outcome after restart, or a second-attempt record fails closed rather than sending again.
217
+
218
+ Each eligible attempt sends only the fixed continuation prompt to that verified recorded worker pane, followed by Enter. It does not replay provider output or a prior prompt, inspect or inject dynamic pane content, cross pane boundaries, kill or relaunch workers, create/split panes, or extend/rewrite claims. This bounded nudge is not automatic recovery for a dead, shutdown, reassigned, terminal, or lease-expired worker. When it cannot act, use `gjc team status <team-name>` / `gjc team monitor <team-name>` and the documented state evidence; manual pane intervention remains the last-resort fallback.
219
+
220
+ Continuation input is unsupported on psmux and native Windows send-keys fallback transports: the fixed prompt is not dispatched there because equivalent literal-input semantics are not proven. Startup's existing empty-pane worker command fallback is separate and unchanged.
221
+
206
222
  ## Operational Commands
207
223
 
208
224
  ```bash
@@ -20,8 +20,6 @@ import type { LoadContext, LoadResult, SourceMeta } from "../capability/types";
20
20
  import type { ForkContextPolicy } from "../task/types";
21
21
  import { parseThinkingLevel } from "../thinking";
22
22
 
23
- import { buildPluginDirRoot } from "./plugin-dir-roots";
24
-
25
23
  /**
26
24
  * Standard paths for each config source.
27
25
  */
@@ -900,14 +898,6 @@ export async function listClaudePluginRoots(
900
898
  roots.push(...projectRoots, ...deduped);
901
899
  }
902
900
 
903
- // Merge --plugin-dir roots (highest precedence) on every fresh load
904
- if (injectedPluginDirRoots.length > 0) {
905
- const injectedIds = new Set(injectedPluginDirRoots.map(r => r.id));
906
- const filtered = roots.filter(r => !injectedIds.has(r.id));
907
- roots.length = 0;
908
- roots.push(...injectedPluginDirRoots, ...filtered);
909
- }
910
-
911
901
  const result = { roots, warnings };
912
902
  pluginRootsCache.set(cacheKey, result);
913
903
  return result;
@@ -918,7 +908,7 @@ export async function listClaudePluginRoots(
918
908
  */
919
909
  export function clearClaudePluginRootsCache(): void {
920
910
  pluginRootsCache.clear();
921
- preloadedPluginRoots = [...injectedPluginDirRoots];
911
+ preloadedPluginRoots = [];
922
912
  // Re-warm preloaded roots asynchronously so sync LSP config reads stay valid
923
913
  if (lastPreloadHome) {
924
914
  void preloadPluginRoots(lastPreloadHome, getProjectDir());
@@ -941,7 +931,6 @@ export function clearPluginRootsAndCaches(extraPaths?: readonly string[]): void
941
931
  // getPreloadedPluginRoots(). Safe degradation: empty array if not warmed.
942
932
 
943
933
  let preloadedPluginRoots: ClaudePluginRoot[] = [];
944
- let injectedPluginDirRoots: ClaudePluginRoot[] = [];
945
934
  let lastPreloadHome: string | undefined;
946
935
 
947
936
  /**
@@ -962,41 +951,3 @@ export async function preloadPluginRoots(home: string, cwd?: string): Promise<vo
962
951
  export function getPreloadedPluginRoots(): readonly ClaudePluginRoot[] {
963
952
  return preloadedPluginRoots;
964
953
  }
965
-
966
- // ── --plugin-dir injection ──────────────────────────────────────────────────
967
-
968
- /**
969
- * Inject synthetic plugin roots from --plugin-dir paths.
970
- * These are prepended to the cache with highest precedence (before GJC/Anthropic model entries).
971
- * Must be called before any listAnthropic modelPluginRoots() access.
972
- */
973
- export async function injectPluginDirRoots(home: string, dirs: string[], cwd?: string): Promise<void> {
974
- const injected: ClaudePluginRoot[] = [];
975
- for (const dir of dirs) {
976
- const resolved = path.resolve(dir);
977
- // Read plugin name from manifest
978
- let pluginName = path.basename(resolved);
979
- try {
980
- const manifestPath = path.join(resolved, ".claude-plugin", "plugin.json");
981
- const content = await Bun.file(manifestPath).text();
982
- const manifest = JSON.parse(content);
983
- if (typeof manifest.name === "string" && manifest.name) {
984
- pluginName = manifest.name;
985
- }
986
- } catch {
987
- // No manifest or invalid — use directory name
988
- }
989
-
990
- injected.push(buildPluginDirRoot(resolved, pluginName));
991
- }
992
-
993
- // Set injected roots BEFORE populating cache so listAnthropic modelPluginRoots merges them.
994
- injectedPluginDirRoots = injected;
995
- lastPreloadHome = home; // ensure cache-clear re-warm fires even when injectPluginDirRoots was the startup path
996
- // Clear any stale cache entries (populated before injected roots were set).
997
- pluginRootsCache.clear();
998
- // Rebuild — cache miss triggers fresh load that includes both user+project registries
999
- // and prepends injectedPluginDirRoots at highest precedence.
1000
- const { roots } = await listClaudePluginRoots(home, cwd);
1001
- preloadedPluginRoots = roots;
1002
- }
package/src/edit/index.ts CHANGED
@@ -57,6 +57,69 @@ type VimParams = z.infer<typeof vimSchema>;
57
57
  type EditParams = ReplaceParams | PatchParams | HashlineParams | VimParams | ApplyPatchParams;
58
58
  type EditToolResultDetails = EditToolDetails | VimToolDetails;
59
59
 
60
+ const UNSAFE_EDIT_SUMMARY_PATH =
61
+ /(?:\b(?:https?|wss?):\/\/|\b(?:api[-_ ]?key|access[-_ ]?token|bearer|secret|password)\b|\b(?:sk|pk|rk)-[A-Za-z0-9_-]{12,})/i;
62
+
63
+ const MAX_APPLY_PATCH_ACTIVITY_FILES = 2;
64
+
65
+ function isSafeEditSummaryPath(value: unknown): value is string {
66
+ return typeof value === "string" && value.length > 0 && value.length <= 100 && !UNSAFE_EDIT_SUMMARY_PATH.test(value);
67
+ }
68
+
69
+ /** Summarize only apply_patch file-operation headers, never its patch body. */
70
+ function summarizeApplyPatchActivity(input: string): string | undefined {
71
+ if (!input.trimStart().startsWith("*** Begin Patch")) return undefined;
72
+
73
+ const paths: string[] = [];
74
+ const marker = /^\*\*\* (?:Add|Delete|Update) File: ([^\r\n]+)\r?$/gm;
75
+ let count = 0;
76
+ let match = marker.exec(input);
77
+ while (match !== null) {
78
+ const editPath = match[1]!.trim();
79
+ if (!isSafeEditSummaryPath(editPath)) return undefined;
80
+ count++;
81
+ if (paths.length < MAX_APPLY_PATCH_ACTIVITY_FILES) paths.push(editPath);
82
+ match = marker.exec(input);
83
+ }
84
+ if (count === 0) return undefined;
85
+
86
+ const displayedPaths =
87
+ count > MAX_APPLY_PATCH_ACTIVITY_FILES ? `${paths.join(", ")}, +${count - paths.length} more` : paths.join(", ");
88
+ return `${displayedPaths}, ${count} edit${count === 1 ? "" : "s"}`;
89
+ }
90
+
91
+ /** Project edit targets and operation counts without exposing patches, diffs, or file contents. */
92
+ export function summarizeEditToolActivity(kind: "args" | "result", value: unknown): string | undefined {
93
+ if (!value || typeof value !== "object" || Array.isArray(value)) return undefined;
94
+ const record = value as Record<string, unknown>;
95
+ if (kind === "args") {
96
+ const applyPatchInput = record.input;
97
+ if (typeof applyPatchInput === "string") return summarizeApplyPatchActivity(applyPatchInput);
98
+
99
+ const editPath = record.path;
100
+ if (!isSafeEditSummaryPath(editPath)) return undefined;
101
+ const edits = record.edits;
102
+ const count = Array.isArray(edits) ? edits.length : 1;
103
+ return `${editPath}, ${count} edit${count === 1 ? "" : "s"}`;
104
+ }
105
+
106
+ const details = record.details;
107
+ if (!details || typeof details !== "object" || Array.isArray(details)) return undefined;
108
+ const perFileResults = (details as Record<string, unknown>).perFileResults;
109
+ const count = Array.isArray(perFileResults)
110
+ ? perFileResults.length
111
+ : "path" in (details as Record<string, unknown>)
112
+ ? 1
113
+ : 0;
114
+ if (count === 0) return undefined;
115
+ const failed =
116
+ record.isError === true ||
117
+ (Array.isArray(perFileResults) &&
118
+ perFileResults.some(
119
+ entry => typeof entry === "object" && entry !== null && (entry as Record<string, unknown>).isError === true,
120
+ ));
121
+ return `${failed ? "failed" : "applied"}, ${count} file${count === 1 ? "" : "s"}`;
122
+ }
60
123
  type EditModeDefinition = {
61
124
  description: (session: ToolSession) => string;
62
125
  parameters: TInput;
@@ -279,6 +342,7 @@ export class EditTool implements AgentTool<TInput> {
279
342
  readonly nonAbortable = true;
280
343
  readonly concurrency = "exclusive";
281
344
  readonly strict = true;
345
+ readonly safeSummary = summarizeEditToolActivity;
282
346
 
283
347
  readonly #allowFuzzy: boolean;
284
348
  readonly #fuzzyThreshold: number;
@@ -0,0 +1,26 @@
1
+ /** Environment values consulted by the Python subprocess integration. */
2
+ export type PythonEnv = Record<string, string | undefined>;
3
+
4
+ const PYTHON_TRUTHY = new Set(["1", "true", "yes", "on", "y"]);
5
+
6
+ /** True when `value` is a non-empty string matching a truthy boolean token. */
7
+ export function isTruthyPythonFlag(value: string | undefined): boolean {
8
+ return value !== undefined && PYTHON_TRUTHY.has(value.trim().toLowerCase());
9
+ }
10
+
11
+ /** Resolve paired GJC/legacy PI flags using OR semantics. */
12
+ export function resolvePythonFlag(env: PythonEnv, gjcName: string, piName: string): boolean {
13
+ return isTruthyPythonFlag(env[gjcName]) || isTruthyPythonFlag(env[piName]);
14
+ }
15
+
16
+ export function resolvePythonSkipCheck(env: PythonEnv): boolean {
17
+ return resolvePythonFlag(env, "GJC_PYTHON_SKIP_CHECK", "PI_PYTHON_SKIP_CHECK");
18
+ }
19
+
20
+ export function resolvePythonIpcTrace(env: PythonEnv): boolean {
21
+ return resolvePythonFlag(env, "GJC_PYTHON_IPC_TRACE", "PI_PYTHON_IPC_TRACE");
22
+ }
23
+
24
+ export function resolvePythonIntegrationGate(env: PythonEnv): boolean {
25
+ return resolvePythonFlag(env, "GJC_PYTHON_INTEGRATION", "PI_PYTHON_INTEGRATION");
26
+ }
@@ -11,11 +11,12 @@
11
11
  import * as fs from "node:fs";
12
12
  import * as os from "node:os";
13
13
  import * as path from "node:path";
14
- import { $flag, isBunTestRuntime, logger, Snowflake } from "@gajae-code/utils";
14
+ import { $env, isBunTestRuntime, logger, Snowflake } from "@gajae-code/utils";
15
15
  import type { Subprocess } from "bun";
16
16
  import { $ } from "bun";
17
17
  import { Settings } from "../../config/settings";
18
18
  import { type KernelDisplayOutput, renderKernelDisplay } from "./display";
19
+ import { resolvePythonIpcTrace, resolvePythonSkipCheck } from "./env";
19
20
  import { PYTHON_PRELUDE } from "./prelude";
20
21
  import RUNNER_SCRIPT from "./runner.py" with { type: "text" };
21
22
  import { ensurePythonRuntime, filterEnv, type PythonRuntimeOptions } from "./runtime";
@@ -23,7 +24,8 @@ import { ensurePythonRuntime, filterEnv, type PythonRuntimeOptions } from "./run
23
24
  export type { KernelDisplayOutput, PythonStatusEvent } from "./display";
24
25
  export { renderKernelDisplay } from "./display";
25
26
 
26
- const TRACE_IPC = $flag("PI_PYTHON_IPC_TRACE");
27
+ // Dual-read: `GJC_PYTHON_IPC_TRACE` is preferred, then legacy `PI_PYTHON_IPC_TRACE`.
28
+ const TRACE_IPC = resolvePythonIpcTrace($env);
27
29
 
28
30
  // Cache the runner script on disk so the subprocess loads it normally. Cached
29
31
  // per script hash so installs don't race across versions.
@@ -125,7 +127,7 @@ export async function checkPythonKernelAvailability(
125
127
  cwd: string,
126
128
  runtimeOptions?: PythonRuntimeOptions,
127
129
  ): Promise<PythonKernelAvailability> {
128
- if (isBunTestRuntime() || $flag("PI_PYTHON_SKIP_CHECK")) {
130
+ if (isBunTestRuntime() || resolvePythonSkipCheck($env)) {
129
131
  return { ok: true };
130
132
  }
131
133
  try {
@@ -5,7 +5,7 @@ import type * as fs1 from "node:fs";
5
5
  import * as fs from "node:fs/promises";
6
6
  import * as path from "node:path";
7
7
  import type { ThinkingLevel } from "@gajae-code/agent-core";
8
- import type { ImageContent, Model, TextContent, UsageReport } from "@gajae-code/ai";
8
+ import type { ImageContent, Model, TextContent, Tool, UsageReport } from "@gajae-code/ai";
9
9
  import type { KeyId } from "@gajae-code/tui";
10
10
  import { hasFsCode, isEacces, isEnoent, logger } from "@gajae-code/utils";
11
11
  import * as Zod from "zod/v4";
@@ -82,6 +82,10 @@ export class ExtensionRuntime implements IExtensionRuntime {
82
82
  throw new ExtensionRuntimeNotInitializedError();
83
83
  }
84
84
 
85
+ resolveTool(): Pick<Tool, "safeSummary" | "safeSummaryFields"> | undefined {
86
+ throw new ExtensionRuntimeNotInitializedError();
87
+ }
88
+
85
89
  setActiveTools(): Promise<void> {
86
90
  throw new ExtensionRuntimeNotInitializedError();
87
91
  }
@@ -257,6 +261,10 @@ class ConcreteExtensionAPI implements ExtensionAPI, IExtensionRuntime {
257
261
  return this.runtime.getAllTools();
258
262
  }
259
263
 
264
+ resolveTool(name: string): Pick<Tool, "safeSummary" | "safeSummaryFields"> | undefined {
265
+ return this.runtime.resolveTool(name);
266
+ }
267
+
260
268
  setActiveTools(toolNames: string[]): Promise<void> {
261
269
  return this.runtime.setActiveTools(toolNames);
262
270
  }
@@ -8,7 +8,7 @@ import { logger } from "@gajae-code/utils";
8
8
  import type { ModelRegistry } from "../../config/model-registry";
9
9
  import type { WorkflowGateEmitter } from "../../modes/shared/agent-wire/workflow-gate-broker";
10
10
  import { type Theme, theme } from "../../modes/theme/theme";
11
- import type { SessionManager } from "../../session/session-manager";
11
+ import { createReadonlySessionManager, type SessionManager } from "../../session/session-manager";
12
12
  import type {
13
13
  AfterProviderResponseEvent,
14
14
  BeforeAgentStartEvent,
@@ -199,6 +199,7 @@ export class ExtensionRunner {
199
199
  #getQueuedMessagesFn: ExtensionContext["getQueuedMessages"] = () => [];
200
200
  #getActiveToolsFn: ExtensionContext["getActiveTools"] = () => [];
201
201
  #getAllToolsFn: ExtensionContext["getAllTools"] = () => [];
202
+ #getResolveToolFn: ExtensionContext["resolveTool"] = () => undefined;
202
203
  #cycleModelFn: ExtensionContextActions["cycleModel"] = undefined;
203
204
  #cycleThinkingLevelFn: ExtensionContextActions["cycleThinkingLevel"] = undefined;
204
205
  #setQueueModeFn: ExtensionContextActions["setQueueMode"] = undefined;
@@ -275,6 +276,7 @@ export class ExtensionRunner {
275
276
  this.runtime.appendEntry = actions.appendEntry;
276
277
  this.runtime.getActiveTools = actions.getActiveTools;
277
278
  this.runtime.getAllTools = actions.getAllTools;
279
+ this.runtime.resolveTool = actions.resolveTool ?? (() => undefined);
278
280
  this.runtime.setActiveTools = actions.setActiveTools;
279
281
  this.runtime.getCommands = actions.getCommands;
280
282
  this.runtime.setModel = actions.setModel;
@@ -309,6 +311,7 @@ export class ExtensionRunner {
309
311
  this.#getQueuedMessagesFn = contextActions.getQueuedMessages ?? (() => []);
310
312
  this.#getActiveToolsFn = contextActions.getActiveTools ?? (() => []);
311
313
  this.#getAllToolsFn = contextActions.getAllTools ?? (() => []);
314
+ this.#getResolveToolFn = contextActions.resolveTool ?? (() => undefined);
312
315
  this.#cycleModelFn = contextActions.cycleModel;
313
316
  this.#cycleThinkingLevelFn = contextActions.cycleThinkingLevel;
314
317
  this.#setQueueModeFn = contextActions.setQueueMode;
@@ -540,7 +543,7 @@ export class ExtensionRunner {
540
543
  compact: instructionsOrOptions => this.#compactFn(instructionsOrOptions),
541
544
  hasUI: this.hasUI(),
542
545
  cwd: this.cwd,
543
- sessionManager: this.sessionManager,
546
+ sessionManager: createReadonlySessionManager(this.sessionManager),
544
547
  sessionMetadata: this.sessionMetadata,
545
548
  modelRegistry: this.modelRegistry,
546
549
  get model() {
@@ -557,6 +560,7 @@ export class ExtensionRunner {
557
560
  getQueuedMessages: () => this.#getQueuedMessagesFn(),
558
561
  getActiveTools: () => this.#getActiveToolsFn(),
559
562
  getAllTools: () => this.#getAllToolsFn(),
563
+ resolveTool: name => this.#getResolveToolFn(name),
560
564
  cycleModel: async () => await this.#cycleModelFn?.(),
561
565
  cycleThinkingLevel: () => this.#cycleThinkingLevelFn?.(),
562
566
  setQueueMode: (kind, mode) => this.#setQueueModeFn?.(kind, mode) ?? false,
@@ -678,7 +682,10 @@ export class ExtensionRunner {
678
682
  }
679
683
  }
680
684
 
681
- async emit<TEvent extends RunnerEmitEvent>(event: TEvent): Promise<RunnerEmitResult<TEvent>> {
685
+ async emit<TEvent extends RunnerEmitEvent>(
686
+ event: TEvent,
687
+ continueWhile?: () => boolean,
688
+ ): Promise<RunnerEmitResult<TEvent>> {
682
689
  const handlers = this.#handlersByEvent.get(event.type) ?? [];
683
690
  if (handlers.length === 0) return undefined as RunnerEmitResult<TEvent>;
684
691
 
@@ -686,7 +693,9 @@ export class ExtensionRunner {
686
693
  let result: SessionBeforeEventResult | SessionCompactingResult | undefined;
687
694
 
688
695
  for (const { ext, handler } of handlers) {
696
+ if (continueWhile && !continueWhile()) return result as RunnerEmitResult<TEvent>;
689
697
  const handlerResult = await this.#runHandlerWithTimeout(handler, event, ctx, ext, extensionHandlerTimeoutMs);
698
+ if (continueWhile && !continueWhile()) return result as RunnerEmitResult<TEvent>;
690
699
 
691
700
  if (this.#isSessionBeforeEvent(event) && handlerResult) {
692
701
  result = handlerResult as SessionBeforeEventResult;
@@ -21,6 +21,7 @@ import type {
21
21
  SimpleStreamOptions,
22
22
  Static,
23
23
  TextContent,
24
+ Tool,
24
25
  TSchema,
25
26
  UsageReport,
26
27
  } from "@gajae-code/ai";
@@ -271,7 +272,11 @@ export interface ExtensionUIContext {
271
272
  /** Get current tool output expansion state. */
272
273
  getToolsExpanded(): boolean;
273
274
 
274
- /** Set tool output expansion state. */
275
+ /**
276
+ * Set tool output expansion state. This is an explicit fold choice, pinning
277
+ * existing tool and read components for their renderer instance lifetime,
278
+ * the same as the user shortcut.
279
+ */
275
280
  setToolsExpanded(expanded: boolean): void;
276
281
  }
277
282
 
@@ -352,6 +357,8 @@ export interface ExtensionContext {
352
357
  getQueuedMessages(): unknown[];
353
358
  getActiveTools(): string[];
354
359
  getAllTools(): string[];
360
+ /** Resolve display-safe metadata for a configured tool without exposing its implementation. */
361
+ resolveTool(name: string): Pick<Tool, "safeSummary" | "safeSummaryFields"> | undefined;
355
362
  /** Session control seams used by the SDK host. */
356
363
  cycleModel(): Promise<{ model: Model; thinkingLevel: ThinkingLevel | undefined } | undefined>;
357
364
  cycleThinkingLevel(): ThinkingLevel | undefined;
@@ -589,6 +596,26 @@ export interface MessageUpdateEvent {
589
596
  assistantMessageEvent: AssistantMessageEvent;
590
597
  }
591
598
 
599
+ export interface ReasoningSummaryStartEvent {
600
+ type: "reasoning_summary_start";
601
+ message: AgentMessage;
602
+ contentIndex: number;
603
+ }
604
+
605
+ export interface ReasoningSummaryDeltaEvent {
606
+ type: "reasoning_summary_delta";
607
+ message: AgentMessage;
608
+ contentIndex: number;
609
+ delta: string;
610
+ }
611
+
612
+ export interface ReasoningSummaryEndEvent {
613
+ type: "reasoning_summary_end";
614
+ message: AgentMessage;
615
+ contentIndex: number;
616
+ content: string;
617
+ }
618
+
592
619
  /** Fired when a message ends */
593
620
  export interface MessageEndEvent {
594
621
  type: "message_end";
@@ -838,6 +865,9 @@ export type ExtensionEvent =
838
865
  | MessageStartEvent
839
866
  | MessageUpdateEvent
840
867
  | MessageEndEvent
868
+ | ReasoningSummaryStartEvent
869
+ | ReasoningSummaryDeltaEvent
870
+ | ReasoningSummaryEndEvent
841
871
  | ToolExecutionStartEvent
842
872
  | ToolExecutionUpdateEvent
843
873
  | ToolExecutionEndEvent
@@ -999,6 +1029,9 @@ export interface ExtensionAPI {
999
1029
  on(event: "turn_end", handler: ExtensionHandler<TurnEndEvent>): void;
1000
1030
  on(event: "message_start", handler: ExtensionHandler<MessageStartEvent>): void;
1001
1031
  on(event: "message_update", handler: ExtensionHandler<MessageUpdateEvent>): void;
1032
+ on(event: "reasoning_summary_start", handler: ExtensionHandler<ReasoningSummaryStartEvent>): void;
1033
+ on(event: "reasoning_summary_delta", handler: ExtensionHandler<ReasoningSummaryDeltaEvent>): void;
1034
+ on(event: "reasoning_summary_end", handler: ExtensionHandler<ReasoningSummaryEndEvent>): void;
1002
1035
  on(event: "message_end", handler: ExtensionHandler<MessageEndEvent>): void;
1003
1036
  on(event: "tool_execution_start", handler: ExtensionHandler<ToolExecutionStartEvent>): void;
1004
1037
  on(event: "tool_execution_update", handler: ExtensionHandler<ToolExecutionUpdateEvent>): void;
@@ -1103,6 +1136,8 @@ export interface ExtensionAPI {
1103
1136
 
1104
1137
  /** Get all configured tools (built-in + extension tools). */
1105
1138
  getAllTools(): string[];
1139
+ /** Resolve display-safe metadata for a configured tool without exposing its implementation. */
1140
+ resolveTool(name: string): Pick<Tool, "safeSummary" | "safeSummaryFields"> | undefined;
1106
1141
 
1107
1142
  /** Set the active tools by name. */
1108
1143
  setActiveTools(toolNames: string[]): Promise<void>;
@@ -1304,6 +1339,7 @@ export type AppendEntryHandler = <T = unknown>(customType: string, data?: T) =>
1304
1339
  export type GetActiveToolsHandler = () => string[];
1305
1340
 
1306
1341
  export type GetAllToolsHandler = () => string[];
1342
+ export type ResolveToolHandler = (name: string) => Pick<Tool, "safeSummary" | "safeSummaryFields"> | undefined;
1307
1343
 
1308
1344
  export type GetCommandsHandler = () => SlashCommandInfo[];
1309
1345
 
@@ -1349,6 +1385,7 @@ export interface ExtensionActions {
1349
1385
  setLabel: (targetId: string, label: string | undefined) => void;
1350
1386
  getActiveTools: GetActiveToolsHandler;
1351
1387
  getAllTools: GetAllToolsHandler;
1388
+ resolveTool: ResolveToolHandler;
1352
1389
  setActiveTools: SetActiveToolsHandler;
1353
1390
  getCommands: GetCommandsHandler;
1354
1391
  setModel: SetModelHandler;
@@ -1381,6 +1418,7 @@ export interface ExtensionContextActions {
1381
1418
  getQueuedMessages?: () => unknown[];
1382
1419
  getActiveTools?: () => string[];
1383
1420
  getAllTools?: () => string[];
1421
+ resolveTool?: (name: string) => Pick<Tool, "safeSummary" | "safeSummaryFields"> | undefined;
1384
1422
  shutdown: () => void;
1385
1423
  getContextUsage: () => ContextUsage | undefined;
1386
1424
  compact: (instructionsOrOptions?: string | CompactOptions) => Promise<void>;
@@ -211,23 +211,23 @@ async function resolveTarball(source: string): Promise<ResolvedSource> {
211
211
  }
212
212
 
213
213
  function runGit(args: string[], cwd?: string): Promise<string> {
214
- return new Promise((resolve, reject) => {
215
- // argv array (no shell) — repo/ref are passed as discrete args, not interpolated.
216
- const child = spawn("git", args, { cwd, stdio: ["ignore", "pipe", "pipe"] });
217
- let stdout = "";
218
- let stderr = "";
219
- child.stdout.on("data", d => {
220
- stdout += d;
221
- });
222
- child.stderr.on("data", d => {
223
- stderr += d;
224
- });
225
- child.on("error", reject);
226
- child.on("close", code => {
227
- if (code === 0) resolve(stdout.trim());
228
- else reject(new GjcPluginLoadError("install_conflict", `git ${args[0]} failed: ${stderr.trim()}`));
229
- });
214
+ const { promise, resolve, reject } = Promise.withResolvers<string>();
215
+ // argv array (no shell) — repo/ref are passed as discrete args, not interpolated.
216
+ const child = spawn("git", args, { cwd, stdio: ["ignore", "pipe", "pipe"] });
217
+ let stdout = "";
218
+ let stderr = "";
219
+ child.stdout.on("data", d => {
220
+ stdout += d;
221
+ });
222
+ child.stderr.on("data", d => {
223
+ stderr += d;
224
+ });
225
+ child.on("error", reject);
226
+ child.on("close", code => {
227
+ if (code === 0) resolve(stdout.trim());
228
+ else reject(new GjcPluginLoadError("install_conflict", `git ${args[0]} failed: ${stderr.trim()}`));
230
229
  });
230
+ return promise;
231
231
  }
232
232
 
233
233
  async function resolveGit(source: string): Promise<ResolvedSource> {
@@ -4,7 +4,7 @@
4
4
  import type { AgentMessage } from "@gajae-code/agent-core";
5
5
  import type { Model } from "@gajae-code/ai";
6
6
  import type { ModelRegistry } from "../../config/model-registry";
7
- import type { SessionManager } from "../../session/session-manager";
7
+ import { createReadonlySessionManager, type SessionManager } from "../../session/session-manager";
8
8
  import { createNoOpUIContext } from "../utils";
9
9
  import type {
10
10
  AppendEntryHandler,
@@ -226,7 +226,7 @@ export class HookRunner {
226
226
  ui: this.#uiContext,
227
227
  hasUI: this.#hasUI,
228
228
  cwd: this.cwd,
229
- sessionManager: this.sessionManager,
229
+ sessionManager: createReadonlySessionManager(this.sessionManager),
230
230
  modelRegistry: this.modelRegistry,
231
231
  model: this.#getModel(),
232
232
  isIdle: () => this.#isIdleFn(),
@@ -4,7 +4,8 @@ import * as path from "node:path";
4
4
  import { findRepoRoot } from "../capability/fs";
5
5
  import type { Skill as CapabilitySkill } from "../capability/skill";
6
6
  import type { SkillsSettings } from "../config/settings-schema";
7
- import { compareSkillOrder, scanSkillsFromDir } from "../discovery/helpers";
7
+ import { compareSkillOrder, SOURCE_PATHS, scanSkillsFromDir } from "../discovery/helpers";
8
+ import { CANONICAL_GJC_WORKFLOW_SKILLS } from "../skill-state/canonical-skills";
8
9
  import type { Skill } from "./skills";
9
10
 
10
11
  export type RuntimeSkillDiscoverySource = "project" | "user";
@@ -32,6 +33,7 @@ function getRuntimeHome(): string {
32
33
 
33
34
  const DEFAULT_LIMIT = 20;
34
35
  const MAX_LIMIT = 50;
36
+ const BUILT_IN_SKILL_NAMES = new Set<string>(CANONICAL_GJC_WORKFLOW_SKILLS);
35
37
 
36
38
  function normalizeLimit(limit: number | undefined): number {
37
39
  if (limit === undefined || !Number.isFinite(limit)) return DEFAULT_LIMIT;
@@ -56,6 +58,18 @@ async function getProjectSkillDirs(cwd: string, home: string): Promise<{ dirs: s
56
58
  return { dirs, repoRoot };
57
59
  }
58
60
 
61
+ function getUserSkillDirs(home: string): string[] {
62
+ const canonicalUserDir = SOURCE_PATHS.native.userAgent;
63
+ const configuredLegacyDir = SOURCE_PATHS.native.userBase;
64
+ return [
65
+ ...new Set([
66
+ path.join(home, canonicalUserDir, "skills"),
67
+ path.join(home, configuredLegacyDir, "skills"),
68
+ path.join(home, ".gjc", "skills"),
69
+ ]),
70
+ ];
71
+ }
72
+
59
73
  function getUseWhen(skill: CapabilitySkill): string[] | undefined {
60
74
  const frontmatter = skill.frontmatter as Record<string, unknown> | undefined;
61
75
  const values: string[] = [];
@@ -110,6 +124,7 @@ function isAllowedByPolicy(
110
124
  source: RuntimeSkillDiscoverySource,
111
125
  policy: SkillsSettings | undefined,
112
126
  ): boolean {
127
+ if (BUILT_IN_SKILL_NAMES.has(skill.name)) return false;
113
128
  if (!sourceEnabled(source, policy)) return false;
114
129
  if (isDisabledSkill(skill.name, policy?.disabledExtensions)) return false;
115
130
  if (matchesIgnorePatterns(skill.name, policy?.ignoredSkills)) return false;
@@ -158,12 +173,14 @@ export async function discoverRuntimeSkills(
158
173
  }
159
174
  }
160
175
  if ((source === "all" || source === "user") && sourceEnabled("user", policy)) {
161
- scanJobs.push(
162
- scanSkillsFromDir(
163
- { cwd: options.cwd, home, repoRoot: home },
164
- { dir: path.join(home, ".gjc", "skills"), providerId: "runtime", level: "user", requireDescription: true },
165
- ).then(result => result.items.map(skill => ({ skill, source: "user" as const }))),
166
- );
176
+ for (const dir of getUserSkillDirs(home)) {
177
+ scanJobs.push(
178
+ scanSkillsFromDir(
179
+ { cwd: options.cwd, home, repoRoot: home },
180
+ { dir, providerId: "runtime", level: "user", requireDescription: true },
181
+ ).then(result => result.items.map(skill => ({ skill, source: "user" as const }))),
182
+ );
183
+ }
167
184
  }
168
185
 
169
186
  const seenNames = new Set<string>();
@@ -175,6 +192,7 @@ export async function discoverRuntimeSkills(
175
192
  if (seenPaths.has(realPath) || seenNames.has(entry.skill.name)) continue;
176
193
  seenPaths.add(realPath);
177
194
  seenNames.add(entry.skill.name);
195
+
178
196
  const candidate: RuntimeSkillDiscoveryCandidate = {
179
197
  name: entry.skill.name,
180
198
  description:
@@ -213,12 +231,14 @@ export async function findRuntimeSkillByName(
213
231
  );
214
232
  }
215
233
  if (sourceEnabled("user", policy)) {
216
- scanJobs.push(
217
- scanSkillsFromDir(
218
- { cwd, home, repoRoot: home },
219
- { dir: path.join(home, ".gjc", "skills"), providerId: "runtime", level: "user", requireDescription: true },
220
- ).then(result => result.items.map(skill => ({ skill, source: "user" as const }))),
221
- );
234
+ for (const dir of getUserSkillDirs(home)) {
235
+ scanJobs.push(
236
+ scanSkillsFromDir(
237
+ { cwd, home, repoRoot: home },
238
+ { dir, providerId: "runtime", level: "user", requireDescription: true },
239
+ ).then(result => result.items.map(skill => ({ skill, source: "user" as const }))),
240
+ );
241
+ }
222
242
  }
223
243
  for (const entry of (await Promise.all(scanJobs)).flat()) {
224
244
  if (entry.skill.name === normalized && isAllowedByPolicy(entry.skill, entry.source, policy)) {