@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
@@ -12,6 +12,7 @@ const DELIVERY_MAX_TEXT_BYTES = 64 * 1024;
12
12
  const DELIVERY_PREVIEW_HEAD_BYTES = 32 * 1024;
13
13
  const DELIVERY_PREVIEW_TAIL_BYTES = 32 * 1024;
14
14
  const DELIVERY_MAX_ATTEMPTS = 3;
15
+ const MAX_DEAD_LETTERED_DELIVERIES = 50;
15
16
 
16
17
  export interface AsyncJob {
17
18
  id: string;
@@ -207,6 +208,12 @@ interface AsyncJobDelivery {
207
208
  promise?: Promise<void>;
208
209
  }
209
210
 
211
+ interface DeadLetteredDelivery {
212
+ jobId: string;
213
+ attempt: number;
214
+ lastError?: string;
215
+ }
216
+
210
217
  export interface AsyncJobDeliveryState {
211
218
  queued: number;
212
219
  delivering: boolean;
@@ -381,7 +388,8 @@ export class AsyncJobManager {
381
388
  * resume fails closed with reason "no_runner".
382
389
  */
383
390
  readonly #descriptorResumeRunners = new Map<string, ResumeRunner>();
384
- readonly #deadLetteredDeliveries = new Map<string, AsyncJobDelivery>();
391
+ readonly #deadLetteredDeliveries = new Map<string, DeadLetteredDelivery>();
392
+ readonly #deadLetteredDeliveryOwners = new Map<string, string | undefined>();
385
393
  readonly #ownerSubagentShutdownLeases = new Map<string, OwnerSubagentShutdownLeaseState>();
386
394
  #ownerSubagentShutdownSeq = 0;
387
395
  #lastDisposeDiagnostics: AsyncJobDisposeDiagnostics = { stuckJobIds: [], deliveriesDrained: true };
@@ -1333,12 +1341,16 @@ export class AsyncJobManager {
1333
1341
  }
1334
1342
 
1335
1343
  getDeliveryState(filter?: AsyncJobFilter): AsyncJobDeliveryState {
1344
+ this.#expireMonitorTombstones();
1345
+ this.#pruneEvictedDeadLetters();
1336
1346
  const deliveries = this.#filterDeliveries(filter);
1337
1347
  const inFlightDeliveries = this.#filterInFlightDeliveries(filter);
1338
1348
  const ownerId = filter?.ownerId;
1339
- const deadLettered = Array.from(this.#deadLetteredDeliveries.values()).filter(
1340
- delivery => !ownerId || delivery.ownerId === ownerId,
1341
- ).length;
1349
+ const deadLettered = ownerId
1350
+ ? Array.from(this.#deadLetteredDeliveries.keys()).filter(
1351
+ jobId => this.#deadLetteredDeliveryOwners.get(jobId) === ownerId,
1352
+ ).length
1353
+ : this.#deadLetteredDeliveries.size;
1342
1354
  const nextRetryAt = deliveries.reduce<number | undefined>((next, delivery) => {
1343
1355
  if (next === undefined) return delivery.nextAttemptAt;
1344
1356
  return Math.min(next, delivery.nextAttemptAt);
@@ -1553,6 +1565,7 @@ export class AsyncJobManager {
1553
1565
  this.#deliveries.length = 0;
1554
1566
  this.#inFlightDeliveries.length = 0;
1555
1567
  this.#deadLetteredDeliveries.clear();
1568
+ this.#deadLetteredDeliveryOwners.clear();
1556
1569
  this.#suppressedDeliveries.clear();
1557
1570
  this.#watchedJobs.clear();
1558
1571
  this.#outputState.clear();
@@ -1615,12 +1628,15 @@ export class AsyncJobManager {
1615
1628
  }
1616
1629
 
1617
1630
  #evictJob(jobId: string): void {
1631
+ this.#expireMonitorTombstones();
1618
1632
  this.#recordMonitorTombstone(jobId);
1619
1633
  this.#runLifecycle(jobId, "evict");
1620
1634
  this.#purgeTerminalSubagentStateForJob(jobId);
1621
1635
  this.#jobs.delete(jobId);
1622
1636
  this.#lifecycles.delete(jobId);
1623
1637
  this.#lifecyclePhases.delete(jobId);
1638
+ this.#deadLetteredDeliveries.delete(jobId);
1639
+ this.#deadLetteredDeliveryOwners.delete(jobId);
1624
1640
  this.#suppressedDeliveries.delete(jobId);
1625
1641
  this.#watchedJobs.delete(jobId);
1626
1642
  this.#outputState.delete(jobId);
@@ -1700,6 +1716,33 @@ export class AsyncJobManager {
1700
1716
  return this.#isDeliveryAcknowledged(jobId) || this.#watchedJobs.has(jobId);
1701
1717
  }
1702
1718
 
1719
+ #pruneEvictedDeadLetters(): void {
1720
+ for (const jobId of this.#deadLetteredDeliveries.keys()) {
1721
+ if (this.#jobs.has(jobId)) continue;
1722
+ this.#deadLetteredDeliveries.delete(jobId);
1723
+ this.#deadLetteredDeliveryOwners.delete(jobId);
1724
+ }
1725
+ }
1726
+
1727
+ #recordDeadLetter(delivery: AsyncJobDelivery): void {
1728
+ this.#pruneEvictedDeadLetters();
1729
+ if (!this.#jobs.has(delivery.jobId)) return;
1730
+ this.#deadLetteredDeliveries.delete(delivery.jobId);
1731
+ this.#deadLetteredDeliveryOwners.delete(delivery.jobId);
1732
+ this.#deadLetteredDeliveries.set(delivery.jobId, {
1733
+ jobId: delivery.jobId,
1734
+ attempt: delivery.attempt,
1735
+ lastError: delivery.lastError,
1736
+ });
1737
+ this.#deadLetteredDeliveryOwners.set(delivery.jobId, delivery.ownerId);
1738
+ while (this.#deadLetteredDeliveries.size > MAX_DEAD_LETTERED_DELIVERIES) {
1739
+ const oldestJobId = this.#deadLetteredDeliveries.keys().next().value;
1740
+ if (oldestJobId === undefined) return;
1741
+ this.#deadLetteredDeliveries.delete(oldestJobId);
1742
+ this.#deadLetteredDeliveryOwners.delete(oldestJobId);
1743
+ }
1744
+ }
1745
+
1703
1746
  #enqueueDelivery(jobId: string, text: string): void {
1704
1747
  // Skip delivery if already acknowledged
1705
1748
  if (this.#isDeliveryAcknowledged(jobId)) {
@@ -1717,7 +1760,7 @@ export class AsyncJobManager {
1717
1760
  });
1718
1761
  while (this.#deliveries.length > DEFAULT_MAX_DELIVERY_QUEUE) {
1719
1762
  const dropped = this.#deliveries.shift();
1720
- if (dropped) this.#deadLetteredDeliveries.set(dropped.jobId, dropped);
1763
+ if (dropped) this.#recordDeadLetter(dropped);
1721
1764
  }
1722
1765
  this.#ensureDeliveryLoop();
1723
1766
  }
@@ -1781,7 +1824,7 @@ export class AsyncJobManager {
1781
1824
  delivery.attempt += 1;
1782
1825
  delivery.lastError = error instanceof Error ? error.message : String(error);
1783
1826
  if (delivery.attempt >= DELIVERY_MAX_ATTEMPTS) {
1784
- this.#deadLetteredDeliveries.set(delivery.jobId, delivery);
1827
+ this.#recordDeadLetter(delivery);
1785
1828
  logger.warn("Async job completion delivery reached retry cap", {
1786
1829
  jobId: delivery.jobId,
1787
1830
  attempt: delivery.attempt,
@@ -5,7 +5,10 @@
5
5
  * Uses the settings schema as the source of truth for available settings.
6
6
  */
7
7
 
8
+ import * as fs from "node:fs/promises";
9
+ import type * as path from "node:path";
8
10
  import { APP_NAME, getAgentDir } from "@gajae-code/utils";
11
+ import { YAML } from "bun";
9
12
  import chalk from "chalk";
10
13
  import {
11
14
  getDefault,
@@ -25,7 +28,7 @@ import { initXdg } from "./commands/init-xdg";
25
28
  // Types
26
29
  // =============================================================================
27
30
 
28
- export type ConfigAction = "list" | "get" | "set" | "reset" | "path" | "init-xdg";
31
+ export type ConfigAction = "list" | "get" | "set" | "reset" | "path" | "doctor" | "init-xdg";
29
32
 
30
33
  export interface ConfigCommandArgs {
31
34
  action: ConfigAction;
@@ -111,7 +114,7 @@ function getSettingValues(def: CliSettingDef): readonly string[] | undefined {
111
114
  // Argument Parser
112
115
  // =============================================================================
113
116
 
114
- const VALID_ACTIONS: ConfigAction[] = ["list", "get", "set", "reset", "path", "init-xdg"];
117
+ const VALID_ACTIONS: ConfigAction[] = ["list", "get", "set", "reset", "path", "doctor", "init-xdg"];
115
118
 
116
119
  /**
117
120
  * Parse config subcommand arguments.
@@ -299,6 +302,9 @@ export async function runConfigCommand(cmd: ConfigCommandArgs): Promise<void> {
299
302
  case "path":
300
303
  handlePath();
301
304
  break;
305
+ case "doctor":
306
+ handleDoctor(cmd.flags);
307
+ break;
302
308
  case "init-xdg":
303
309
  await initXdg();
304
310
  break;
@@ -443,6 +449,70 @@ function handlePath(): void {
443
449
  console.log(getAgentDir());
444
450
  }
445
451
 
452
+ function handleDoctor(flags: { json?: boolean }): void {
453
+ const report = settings.getSchemaReport();
454
+ if (flags.json) {
455
+ console.log(JSON.stringify(report, null, 2));
456
+ return;
457
+ }
458
+ if (report.issues.length === 0) {
459
+ console.log(chalk.green("Settings schema is healthy."));
460
+ return;
461
+ }
462
+ for (const issue of report.issues) console.log(`${issue.kind}\t${issue.path}\t${issue.detail}`);
463
+ }
464
+
465
+ type ConfigDoctorReport = {
466
+ unknownKeys: string[];
467
+ invalidValues: Array<{ path: string; value: unknown }>;
468
+ legacyShapes: string[];
469
+ };
470
+
471
+ function flattenConfig(value: unknown, prefix = ""): Array<[string, unknown]> {
472
+ if (prefix && ALL_SETTING_PATHS.includes(prefix as SettingPath)) return [[prefix, value]];
473
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return prefix ? [[prefix, value]] : [];
474
+ return Object.entries(value).flatMap(([key, child]) => flattenConfig(child, prefix ? `${prefix}.${key}` : key));
475
+ }
476
+
477
+ function matchesSettingType(path: SettingPath, value: unknown): boolean {
478
+ const definition = SETTINGS_SCHEMA[path];
479
+ switch (definition.type) {
480
+ case "string":
481
+ case "enum":
482
+ return (
483
+ typeof value === "string" && (definition.type !== "enum" || getEnumValues(path)?.includes(value) === true)
484
+ );
485
+ case "number":
486
+ return typeof value === "number" && Number.isFinite(value);
487
+ case "boolean":
488
+ return typeof value === "boolean";
489
+ case "array":
490
+ return Array.isArray(value);
491
+ case "record":
492
+ return value !== null && typeof value === "object" && !Array.isArray(value);
493
+ }
494
+ }
495
+
496
+ export async function inspectConfigFile(configPath: string): Promise<ConfigDoctorReport> {
497
+ const report: ConfigDoctorReport = { unknownKeys: [], invalidValues: [], legacyShapes: [] };
498
+ try {
499
+ const raw = YAML.parse(await fs.readFile(configPath, "utf8"));
500
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
501
+ report.legacyShapes.push("config root is not a mapping");
502
+ return report;
503
+ }
504
+ for (const [settingPath, value] of flattenConfig(raw)) {
505
+ if (!ALL_SETTING_PATHS.includes(settingPath as SettingPath)) report.unknownKeys.push(settingPath);
506
+ else if (!matchesSettingType(settingPath as SettingPath, value))
507
+ report.invalidValues.push({ path: settingPath, value: redactConfigValue(settingPath, value) });
508
+ }
509
+ } catch (error) {
510
+ if ((error as NodeJS.ErrnoException).code !== "ENOENT")
511
+ report.legacyShapes.push(`unable to parse config: ${String(error)}`);
512
+ }
513
+ return report;
514
+ }
515
+
446
516
  // =============================================================================
447
517
  // Help
448
518
  // =============================================================================
@@ -455,8 +525,10 @@ ${chalk.bold("Commands:")}
455
525
  get <key> Get a specific setting value
456
526
  set <key> <value> Set a setting value
457
527
  reset <key> Reset a setting to its default value
528
+ doctor Report unknown, invalid, and pending settings migrations
458
529
  path Print the config directory path
459
530
  init-xdg Initialize XDG Base Directory structure
531
+ doctor Report unknown, invalid, and legacy config entries
460
532
 
461
533
  ${chalk.bold("Options:")}
462
534
  --json Output as JSON
@@ -472,6 +544,7 @@ ${chalk.bold("Examples:")}
472
544
  ${APP_NAME} config list --json
473
545
  ${APP_NAME} config get auth.broker.token --show-secrets
474
546
  ${APP_NAME} config init-xdg
547
+ ${APP_NAME} config doctor --json
475
548
 
476
549
  ${chalk.bold("Boolean Values:")}
477
550
  true, false, yes, no, on, off, 1, 0
@@ -0,0 +1,42 @@
1
+ export type LaunchMode = "text" | "json" | "acp";
2
+
3
+ export interface LaunchDisposition {
4
+ autoPrint: boolean;
5
+ isInteractive: boolean;
6
+ /** Set when an interactive launch is impossible (non-TTY stdin, nothing to run). */
7
+ nonInteractiveError?: string;
8
+ }
9
+
10
+ /**
11
+ * Decides between interactive, auto-print, and fail-fast launches.
12
+ *
13
+ * A non-TTY stdin means the TUI can never receive input, so an interactive
14
+ * launch would execute the initial prompt and then block in the event loop
15
+ * forever. Prepared command-line input degrades to print mode; without any
16
+ * input to run we fail fast instead of hanging. Explicit `--print` and
17
+ * `--mode` launches are left untouched.
18
+ */
19
+ export function resolveLaunchDisposition(args: {
20
+ stdinIsTTY: boolean | undefined;
21
+ pipedInput: string | undefined;
22
+ hasPreparedInput: boolean;
23
+ print: boolean;
24
+ mode: LaunchMode | undefined;
25
+ }): LaunchDisposition {
26
+ const explicitNonInteractive = args.print || args.mode !== undefined;
27
+ const hasPreparedInput = args.pipedInput !== undefined || args.hasPreparedInput;
28
+ const hasNonTtyStdin = args.stdinIsTTY !== true;
29
+ const autoPrint = !explicitNonInteractive && hasNonTtyStdin && hasPreparedInput;
30
+ const isInteractive = !explicitNonInteractive && !autoPrint;
31
+
32
+ if (isInteractive && args.stdinIsTTY !== true) {
33
+ return {
34
+ autoPrint: false,
35
+ isInteractive: false,
36
+ nonInteractiveError:
37
+ "stdin is not a TTY and no prompt or prepared input was provided; use -p/--print (or pass a prompt or @file) for non-interactive runs.",
38
+ };
39
+ }
40
+
41
+ return { autoPrint, isInteractive };
42
+ }
@@ -75,6 +75,7 @@ export interface NotifyCommandDeps {
75
75
  tokenPrompt?: () => Promise<string>;
76
76
  setExitCode?: (code: number) => void;
77
77
  exitProcess?: (code: number) => void;
78
+ valuePrompt?: (label: string, masked: boolean) => Promise<string>;
78
79
  /** Optional daemon ownership facts collected by an embedding host. */
79
80
  setupPreflight?: TelegramSetupPreflight;
80
81
  /** Injectable timers and cancellation for setup pairing. */
@@ -99,6 +100,27 @@ export function parseNotifyArgs(args: string[]): NotifyCommandArgs | undefined {
99
100
  const i = rest.indexOf(name);
100
101
  return i >= 0 ? rest[i + 1] : undefined;
101
102
  };
103
+ const valueFlags = [
104
+ "--token",
105
+ "--chat-id",
106
+ "--discord-bot-token",
107
+ "--discord-application-id",
108
+ "--discord-guild-id",
109
+ "--discord-parent-channel-id",
110
+ "--slack-bot-token",
111
+ "--slack-app-token",
112
+ "--slack-workspace-id",
113
+ "--slack-channel-id",
114
+ "--slack-authorized-user-id",
115
+ ];
116
+ if (
117
+ valueFlags.some(name => {
118
+ const index = rest.indexOf(name);
119
+ const value = index >= 0 ? rest[index + 1] : undefined;
120
+ return index >= 0 && (!value || value.startsWith("--"));
121
+ })
122
+ )
123
+ return undefined;
102
124
  const provider = rest[0]?.startsWith("--") ? undefined : rest[0];
103
125
  if (provider !== undefined && provider !== "telegram" && provider !== "discord" && provider !== "slack") {
104
126
  return undefined;
@@ -144,7 +166,7 @@ export function parseNotifyArgs(args: string[]): NotifyCommandArgs | undefined {
144
166
  };
145
167
  }
146
168
 
147
- return { action: "status", rawArgs: args.slice(1) };
169
+ return undefined;
148
170
  }
149
171
 
150
172
  export async function runNotifyCommand(cmd: NotifyCommandArgs, deps: NotifyCommandDeps = {}): Promise<void> {
@@ -221,22 +243,41 @@ async function runSetup(cmd: NotifyCommandArgs, deps: NotifyCommandDeps): Promis
221
243
 
222
244
  function requiredSetupValue(value: string | undefined, flag: string): string {
223
245
  if (!value?.trim()) throw new Error(`${flag} is required for non-interactive setup.`);
246
+ if (value.trim().startsWith("--")) throw new Error(`${flag} must not start with --.`);
224
247
  return value.trim();
225
248
  }
226
249
 
250
+ async function promptSetupValue(
251
+ value: string | undefined,
252
+ flag: string,
253
+ masked: boolean,
254
+ deps: NotifyCommandDeps,
255
+ ): Promise<string> {
256
+ if (value?.trim()) return requiredSetupValue(value, flag);
257
+ if (!resolveSetupInteractive(deps)) return requiredSetupValue(value, flag);
258
+ return requiredSetupValue(await (deps.valuePrompt ?? promptForValue)(`${flag.slice(2)}: `, masked), flag);
259
+ }
260
+
227
261
  async function runDiscordSetup(cmd: NotifyCommandArgs, deps: NotifyCommandDeps): Promise<void> {
228
- const botToken = requiredSetupValue(cmd.discordBotToken, "--discord-bot-token");
229
- const applicationId = requiredSetupValue(cmd.discordApplicationId, "--discord-application-id");
230
- const guildId = requiredSetupValue(cmd.discordGuildId, "--discord-guild-id");
231
- const parentChannelId = requiredSetupValue(cmd.discordParentChannelId, "--discord-parent-channel-id");
262
+ const botToken = await promptSetupValue(cmd.discordBotToken, "--discord-bot-token", true, deps);
263
+ const applicationId = await promptSetupValue(cmd.discordApplicationId, "--discord-application-id", false, deps);
264
+ const guildId = await promptSetupValue(cmd.discordGuildId, "--discord-guild-id", false, deps);
265
+ const parentChannelId = await promptSetupValue(
266
+ cmd.discordParentChannelId,
267
+ "--discord-parent-channel-id",
268
+ false,
269
+ deps,
270
+ );
232
271
  const settings = await getSettings(deps);
233
- settings.set("notifications.discord.botToken", botToken);
234
- settings.set("notifications.discord.applicationId", applicationId);
235
- settings.set("notifications.discord.guildId", guildId);
236
- settings.set("notifications.discord.parentChannelId", parentChannelId);
237
- settings.set("notifications.enabled", true);
238
- if (cmd.redact) settings.set("notifications.redact", true);
239
- await settings.flushOrThrow();
272
+ const patches: SettingsAtomicPatch[] = [
273
+ { path: "notifications.discord.botToken", op: "set", value: botToken },
274
+ { path: "notifications.discord.applicationId", op: "set", value: applicationId },
275
+ { path: "notifications.discord.guildId", op: "set", value: guildId },
276
+ { path: "notifications.discord.parentChannelId", op: "set", value: parentChannelId },
277
+ { path: "notifications.enabled", op: "set", value: true },
278
+ ];
279
+ if (cmd.redact) patches.push({ path: "notifications.redact", op: "set", value: true });
280
+ await settings.commitAtomicBatch(patches);
240
281
  const daemon = await ensureConfiguredProviderDaemon("discord", settings, deps);
241
282
  process.stdout.write(
242
283
  `Discord notifications enabled. botToken=${maskToken(botToken)} applicationId=${applicationId} guildId=${guildId} parentChannelId=${parentChannelId} daemon=${daemon}\n`,
@@ -244,20 +285,24 @@ async function runDiscordSetup(cmd: NotifyCommandArgs, deps: NotifyCommandDeps):
244
285
  }
245
286
 
246
287
  async function runSlackSetup(cmd: NotifyCommandArgs, deps: NotifyCommandDeps): Promise<void> {
247
- const botToken = requiredSetupValue(cmd.slackBotToken, "--slack-bot-token");
248
- const appToken = requiredSetupValue(cmd.slackAppToken, "--slack-app-token");
249
- const workspaceId = requiredSetupValue(cmd.slackWorkspaceId, "--slack-workspace-id");
250
- const channelId = requiredSetupValue(cmd.slackChannelId, "--slack-channel-id");
288
+ const botToken = await promptSetupValue(cmd.slackBotToken, "--slack-bot-token", true, deps);
289
+ const appToken = await promptSetupValue(cmd.slackAppToken, "--slack-app-token", true, deps);
290
+ const workspaceId = await promptSetupValue(cmd.slackWorkspaceId, "--slack-workspace-id", false, deps);
291
+ const channelId = await promptSetupValue(cmd.slackChannelId, "--slack-channel-id", false, deps);
251
292
  const authorizedUserId = cmd.slackAuthorizedUserId?.trim() || undefined;
252
293
  const settings = await getSettings(deps);
253
- settings.set("notifications.slack.botToken", botToken);
254
- settings.set("notifications.slack.appToken", appToken);
255
- settings.set("notifications.slack.workspaceId", workspaceId);
256
- settings.set("notifications.slack.channelId", channelId);
257
- settings.set("notifications.slack.authorizedUserId", authorizedUserId);
258
- settings.set("notifications.enabled", true);
259
- if (cmd.redact) settings.set("notifications.redact", true);
260
- await settings.flushOrThrow();
294
+ const patches: SettingsAtomicPatch[] = [
295
+ { path: "notifications.slack.botToken", op: "set", value: botToken },
296
+ { path: "notifications.slack.appToken", op: "set", value: appToken },
297
+ { path: "notifications.slack.workspaceId", op: "set", value: workspaceId },
298
+ { path: "notifications.slack.channelId", op: "set", value: channelId },
299
+ authorizedUserId === undefined
300
+ ? { path: "notifications.slack.authorizedUserId", op: "unset" }
301
+ : { path: "notifications.slack.authorizedUserId", op: "set", value: authorizedUserId },
302
+ { path: "notifications.enabled", op: "set", value: true },
303
+ ];
304
+ if (cmd.redact) patches.push({ path: "notifications.redact", op: "set", value: true });
305
+ await settings.commitAtomicBatch(patches);
261
306
  const daemon = await ensureConfiguredProviderDaemon("slack", settings, deps);
262
307
  process.stdout.write(
263
308
  `Slack notifications enabled. botToken=${maskToken(botToken)} appToken=${maskToken(appToken)} workspaceId=${workspaceId} channelId=${channelId} authorizedUserId=${authorizedUserId ?? "(unset; inbound denied)"} daemon=${daemon}\n`,
@@ -437,7 +482,8 @@ type TokenPromptInput = NodeJS.ReadStream & {
437
482
 
438
483
  type TokenPromptOutput = Pick<NodeJS.WriteStream, "write">;
439
484
 
440
- export async function promptForToken(
485
+ async function promptForMaskedValue(
486
+ label: string,
441
487
  input: TokenPromptInput = process.stdin,
442
488
  output: TokenPromptOutput = process.stdout,
443
489
  ): Promise<string> {
@@ -448,7 +494,7 @@ export async function promptForToken(
448
494
  throw new Error("notify setup requires a TTY with raw input support unless setupToken is injected.");
449
495
  }
450
496
 
451
- output.write("Telegram BotFather token: ");
497
+ output.write(label);
452
498
  const wasRaw = input.isRaw === true;
453
499
  input.setRawMode(true);
454
500
 
@@ -503,6 +549,26 @@ export async function promptForToken(
503
549
  });
504
550
  }
505
551
 
552
+ export async function promptForToken(
553
+ input: TokenPromptInput = process.stdin,
554
+ output: TokenPromptOutput = process.stdout,
555
+ ): Promise<string> {
556
+ return await promptForMaskedValue("Telegram BotFather token: ", input, output);
557
+ }
558
+
559
+ async function promptForValue(label: string, masked: boolean): Promise<string> {
560
+ if (masked) return await promptForMaskedValue(label);
561
+ if (!process.stdin.isTTY) {
562
+ throw new Error("notify setup requires an interactive TTY unless all setup values are supplied as flags.");
563
+ }
564
+ const rl = createInterface({ input: process.stdin, output: process.stdout, terminal: true });
565
+ try {
566
+ return (await rl.question(label)).trim();
567
+ } finally {
568
+ rl.close();
569
+ }
570
+ }
571
+
506
572
  function resolveSetupInteractive(deps: NotifyCommandDeps): boolean {
507
573
  if (deps.setupInteractive !== undefined) return deps.setupInteractive;
508
574
  return Boolean(process.stdin.isTTY) && !deps.setupChatId?.trim();
@@ -1,13 +1,30 @@
1
+ import * as path from "node:path";
1
2
  import { ProcessTerminal, TUI } from "@gajae-code/tui";
3
+ import { pathIsWithin } from "@gajae-code/utils";
2
4
  import { type SessionSelectionResult, SessionSelectorComponent } from "../modes/components/session-selector";
3
5
  import { type SessionInfo, SessionManager } from "../session/session-manager";
4
6
  import { FileSessionStorage } from "../session/session-storage";
5
7
 
8
+ export async function deleteSessionPickerCandidate(sessionPath: string, explicitSessionDir?: string): Promise<void> {
9
+ if (!explicitSessionDir) {
10
+ await SessionManager.deleteManagedCandidate(sessionPath);
11
+ return;
12
+ }
13
+ const root = path.resolve(explicitSessionDir);
14
+ const target = path.resolve(sessionPath);
15
+ if (!pathIsWithin(root, target))
16
+ throw new Error("Explicit session deletion escaped the configured session directory.");
17
+ await new FileSessionStorage().deleteSessionWithArtifacts(target);
18
+ }
19
+
6
20
  /** Show the read-only TUI session picker and return the user's consent intent. */
7
- export async function selectSession(sessions: SessionInfo[]): Promise<SessionSelectionResult> {
21
+ export async function selectSession(
22
+ sessions: SessionInfo[],
23
+ explicitSessionDir?: string,
24
+ ): Promise<SessionSelectionResult> {
8
25
  const { promise, resolve } = Promise.withResolvers<SessionSelectionResult>();
9
26
  const ui = new TUI(new ProcessTerminal());
10
- const storage = new FileSessionStorage();
27
+
11
28
  let settled = false;
12
29
  const settle = (selection: SessionSelectionResult): void => {
13
30
  if (settled) return;
@@ -21,7 +38,7 @@ export async function selectSession(sessions: SessionInfo[]): Promise<SessionSel
21
38
  () => settle({ kind: "cancelled" }),
22
39
  () => settle({ kind: "cancelled" }),
23
40
  async session => {
24
- await storage.deleteSessionWithArtifacts(session.path);
41
+ await deleteSessionPickerCandidate(session.path, explicitSessionDir);
25
42
  return true;
26
43
  },
27
44
  SessionManager.inspectSessionTailReadOnly,
@@ -564,7 +564,7 @@ async function confirmImport(count: number): Promise<boolean> {
564
564
  */
565
565
  export interface CredentialsSetupDependencies {
566
566
  openStore?: typeof SqliteAuthCredentialStore.open;
567
- createAuthStorage?: (store: Awaited<ReturnType<typeof SqliteAuthCredentialStore.open>>) => AuthStorage;
567
+ createAuthStorage?: (store: SqliteAuthCredentialStore) => AuthStorage;
568
568
  discover?: Parameters<typeof runExternalCredentialAutoImport>[0]["discover"];
569
569
  }
570
570
 
package/src/cli.ts CHANGED
@@ -9,7 +9,6 @@ import { Args, type CliConfig, Command, type CommandEntry, Flags, run } from "@g
9
9
  import { APP_NAME, formatBunRuntimeError, MIN_BUN_VERSION, VERSION } from "@gajae-code/utils/dirs";
10
10
  import { runFixtureReport } from "./cli/fixture-report";
11
11
  import { isTmuxOwnerIsolationCliArgv, runTmuxOwnerIsolationCliFromStdin } from "./gjc-runtime/tmux-owner-isolation-cli";
12
- import { runChatDaemonInternal } from "./sdk/bus/chat-daemon-cli";
13
12
 
14
13
  if (Bun.semver.order(Bun.version, MIN_BUN_VERSION) < 0) {
15
14
  process.stderr.write(
@@ -134,6 +133,7 @@ async function runChatDaemonInternalFastPath(argv: string[]): Promise<void> {
134
133
  if (action !== "discord-internal" && action !== "slack-internal") {
135
134
  throw new Error("invalid chat daemon internal fast path");
136
135
  }
136
+ const { runChatDaemonInternal } = await import("./sdk/bus/chat-daemon-cli");
137
137
  await runChatDaemonInternal(action === "discord-internal" ? "discord" : "slack", argv.slice(2));
138
138
  }
139
139
 
@@ -5,7 +5,7 @@ import { Args, Command, Flags } from "@gajae-code/utils/cli";
5
5
  import { type ConfigAction, type ConfigCommandArgs, runConfigCommand } from "../cli/config-cli";
6
6
  import { initTheme } from "../modes/theme/theme";
7
7
 
8
- const ACTIONS: ConfigAction[] = ["list", "get", "set", "reset", "path", "init-xdg"];
8
+ const ACTIONS: ConfigAction[] = ["list", "get", "set", "reset", "path", "init-xdg", "doctor"];
9
9
 
10
10
  export default class Config extends Command {
11
11
  static description = "Manage configuration settings";