@gajae-code/coding-agent 0.17.1 → 0.17.4

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 (375) hide show
  1. package/CHANGELOG.md +266 -0
  2. package/dist/types/async/job-manager.d.ts +7 -6
  3. package/dist/types/cli/daemon-cli.d.ts +3 -1
  4. package/dist/types/cli/github-release.d.ts +17 -0
  5. package/dist/types/cli/public-command-entry.d.ts +56 -0
  6. package/dist/types/cli/public-command-errors.d.ts +126 -0
  7. package/dist/types/cli/public-command-evidence.d.ts +99 -0
  8. package/dist/types/cli/public-command-help.d.ts +65 -0
  9. package/dist/types/cli/public-command-registry.d.ts +69 -0
  10. package/dist/types/cli/session-picker.d.ts +1 -1
  11. package/dist/types/cli/setup-cli.d.ts +1 -0
  12. package/dist/types/cli/skills-cli.d.ts +5 -0
  13. package/dist/types/cli.d.ts +3 -0
  14. package/dist/types/commands/daemon.d.ts +4 -50
  15. package/dist/types/commands/sdk.d.ts +20 -37
  16. package/dist/types/commands/setup.d.ts +3 -0
  17. package/dist/types/commands/skills.d.ts +9 -0
  18. package/dist/types/config/autorouting-tier-map.d.ts +24 -0
  19. package/dist/types/config/file-lock.d.ts +10 -1
  20. package/dist/types/config/model-profile-activation.d.ts +63 -4
  21. package/dist/types/config/model-registry.d.ts +20 -2
  22. package/dist/types/config/settings-schema.d.ts +11 -0
  23. package/dist/types/coordinator-mcp/question-state.d.ts +6 -1
  24. package/dist/types/coordinator-mcp/server.d.ts +3 -0
  25. package/dist/types/daemon/operator-contract.d.ts +5 -1
  26. package/dist/types/eval/js/worker-protocol.d.ts +2 -0
  27. package/dist/types/extensibility/extensions/types.d.ts +12 -0
  28. package/dist/types/extensibility/gjc-plugins/registry.d.ts +4 -0
  29. package/dist/types/extensibility/runtime-skill-discovery.d.ts +18 -0
  30. package/dist/types/extensibility/shared-events.d.ts +3 -1
  31. package/dist/types/gjc-runtime/session-state-lock.d.ts +61 -0
  32. package/dist/types/internal-urls/embedded-protocol.d.ts +9 -0
  33. package/dist/types/internal-urls/index.d.ts +1 -0
  34. package/dist/types/internal-urls/parse.d.ts +9 -1
  35. package/dist/types/main.d.ts +22 -0
  36. package/dist/types/modes/acp/acp-agent.d.ts +94 -1
  37. package/dist/types/modes/acp/startup-provenance.d.ts +16 -0
  38. package/dist/types/modes/components/custom-provider-wizard.d.ts +19 -1
  39. package/dist/types/modes/components/session-selector.d.ts +5 -2
  40. package/dist/types/modes/components/thinking-selector.d.ts +2 -1
  41. package/dist/types/modes/components/user-message-selector.d.ts +5 -2
  42. package/dist/types/modes/controllers/command-controller.d.ts +1 -1
  43. package/dist/types/modes/controllers/selector-controller.d.ts +1 -1
  44. package/dist/types/modes/interactive-mode.d.ts +1 -1
  45. package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +11 -1
  46. package/dist/types/modes/shared/agent-wire/workflow-gate-types.d.ts +14 -1
  47. package/dist/types/modes/types.d.ts +2 -2
  48. package/dist/types/runtime/process-lifecycle.d.ts +2 -0
  49. package/dist/types/runtime-mcp/manager.d.ts +56 -0
  50. package/dist/types/runtime-mcp/pool.d.ts +17 -0
  51. package/dist/types/runtime-mcp/redaction.d.ts +20 -0
  52. package/dist/types/runtime-mcp/startup-policy.d.ts +6 -0
  53. package/dist/types/runtime-mcp/tool-bridge.d.ts +9 -0
  54. package/dist/types/runtime-mcp/transports/http.d.ts +11 -0
  55. package/dist/types/sdk/acp/adapter.d.ts +27 -0
  56. package/dist/types/sdk/acp/final-text.d.ts +8 -0
  57. package/dist/types/sdk/broker/broker.d.ts +13 -2
  58. package/dist/types/sdk/broker/ensure.d.ts +46 -1
  59. package/dist/types/sdk/broker/identity.d.ts +3 -1
  60. package/dist/types/sdk/broker/lifecycle-ledger.d.ts +23 -3
  61. package/dist/types/sdk/broker/lifecycle.d.ts +15 -8
  62. package/dist/types/sdk/broker/runtime.d.ts +1 -1
  63. package/dist/types/sdk/broker/session-index.d.ts +22 -3
  64. package/dist/types/sdk/broker/spawn-authority.d.ts +4 -0
  65. package/dist/types/sdk/broker/stderr-drainer.d.ts +13 -0
  66. package/dist/types/sdk/bus/index.d.ts +19 -0
  67. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +3 -1
  68. package/dist/types/sdk/bus/telegram-daemon.d.ts +5 -0
  69. package/dist/types/sdk/cli/master-cli.d.ts +6 -10
  70. package/dist/types/sdk/cli/rows.d.ts +19 -1
  71. package/dist/types/sdk/cli/session-cli.d.ts +22 -5
  72. package/dist/types/sdk/client/client.d.ts +2 -0
  73. package/dist/types/sdk/guides/cli.d.ts +3 -4
  74. package/dist/types/sdk/guides/verify.d.ts +2 -0
  75. package/dist/types/sdk/host/host.d.ts +9 -0
  76. package/dist/types/sdk/host/session-runtime.d.ts +31 -0
  77. package/dist/types/sdk/host/types.d.ts +10 -0
  78. package/dist/types/sdk/index.d.ts +1 -0
  79. package/dist/types/sdk/prompt-deadline-flush.d.ts +83 -0
  80. package/dist/types/sdk/prompt-deadline-manager.d.ts +38 -1
  81. package/dist/types/sdk/prompt-failure.d.ts +30 -1
  82. package/dist/types/sdk/prompt-status.d.ts +8 -0
  83. package/dist/types/sdk/prompt-tool-boundary.d.ts +73 -0
  84. package/dist/types/sdk/router/replay-retention-gap-cache.d.ts +13 -0
  85. package/dist/types/sdk/router/session-router.d.ts +2 -0
  86. package/dist/types/sdk/startup-capability.d.ts +2 -0
  87. package/dist/types/sdk/transport/relay.d.ts +1 -0
  88. package/dist/types/sdk/transport/serve-cli.d.ts +73 -2
  89. package/dist/types/sdk/transport/stdio.d.ts +5 -1
  90. package/dist/types/session/agent-session.d.ts +168 -21
  91. package/dist/types/session/fallback-chain-controller.d.ts +6 -6
  92. package/dist/types/session/fold-coordinator.d.ts +17 -3
  93. package/dist/types/session/internal/managed-session-storage.d.ts +7 -1
  94. package/dist/types/session/session-manager.d.ts +64 -1
  95. package/dist/types/session/session-work-lease.d.ts +14 -0
  96. package/dist/types/setup/model-onboarding-guidance.d.ts +1 -1
  97. package/dist/types/setup/provider-onboarding.d.ts +81 -1
  98. package/dist/types/thinking.d.ts +3 -1
  99. package/dist/types/tools/bash.d.ts +37 -11
  100. package/dist/types/tools/job.d.ts +1 -1
  101. package/dist/types/tools/steer-fold.d.ts +31 -0
  102. package/dist/types/utils/git.d.ts +28 -2
  103. package/dist/types/utils/mupdf-embedded.d.ts +2 -0
  104. package/dist/types/utils/mupdf-wasm-embedded.d.ts +2 -0
  105. package/dist/types/utils/mupdf.d.ts +4 -0
  106. package/dist/types/utils/session-title-generation.d.ts +6 -0
  107. package/dist/types/utils/title-generator.d.ts +11 -2
  108. package/dist/types/web/scrapers/types.d.ts +3 -0
  109. package/package.json +18 -10
  110. package/scripts/build-binary.ts +9 -3
  111. package/scripts/compile-args.ts +0 -9
  112. package/scripts/embed-mupdf.ts +52 -0
  113. package/scripts/generate-sdk-operation-inventory.ts +31 -1
  114. package/scripts/vendor-markit.ts +196 -0
  115. package/src/async/job-manager.ts +60 -9
  116. package/src/cli/daemon-cli.ts +53 -18
  117. package/src/cli/github-release.ts +87 -5
  118. package/src/cli/mcp-cli.ts +38 -4
  119. package/src/cli/public-command-entry.ts +450 -0
  120. package/src/cli/public-command-errors.ts +581 -0
  121. package/src/cli/public-command-evidence.ts +717 -0
  122. package/src/cli/public-command-help.ts +360 -0
  123. package/src/cli/public-command-registry.ts +535 -0
  124. package/src/cli/session-picker.ts +2 -1
  125. package/src/cli/setup-cli.ts +9 -1
  126. package/src/cli/skills-cli.ts +46 -2
  127. package/src/cli.ts +61 -1
  128. package/src/commands/daemon.ts +65 -69
  129. package/src/commands/sdk.ts +232 -100
  130. package/src/commands/setup.ts +2 -0
  131. package/src/commands/skills.ts +11 -0
  132. package/src/config/autorouting-tier-map.ts +16 -0
  133. package/src/config/file-lock.ts +199 -68
  134. package/src/config/model-profile-activation.ts +406 -53
  135. package/src/config/model-registry.ts +204 -25
  136. package/src/config/settings-schema.ts +26 -2
  137. package/src/coordinator-mcp/policy.ts +10 -5
  138. package/src/coordinator-mcp/question-gate-codec.ts +17 -0
  139. package/src/coordinator-mcp/question-state.ts +175 -8
  140. package/src/coordinator-mcp/server.ts +528 -87
  141. package/src/coordinator-mcp/session-reaper.ts +6 -4
  142. package/src/crash/record-loader.ts +6 -2
  143. package/src/daemon/operator-contract.ts +26 -12
  144. package/src/debug/report-bundle.ts +114 -24
  145. package/src/defaults/gjc/skills/ultragoal/SKILL.md +1 -1
  146. package/src/eval/js/context-manager.ts +8 -8
  147. package/src/eval/js/worker-core.ts +9 -4
  148. package/src/eval/js/worker-protocol.ts +2 -0
  149. package/src/extensibility/extensions/runner.ts +52 -4
  150. package/src/extensibility/extensions/types.ts +10 -0
  151. package/src/extensibility/gjc-plugins/registry.ts +196 -37
  152. package/src/extensibility/runtime-skill-discovery.ts +61 -3
  153. package/src/extensibility/shared-events.ts +3 -1
  154. package/src/gjc-runtime/managed-owner-admission.ts +67 -50
  155. package/src/gjc-runtime/session-state-lock.ts +165 -24
  156. package/src/gjc-runtime/ultragoal-succession.ts +31 -3
  157. package/src/internal-urls/docs-index.generated.ts +21 -19
  158. package/src/internal-urls/embedded-protocol.ts +83 -0
  159. package/src/internal-urls/index.ts +1 -0
  160. package/src/internal-urls/parse.ts +21 -1
  161. package/src/internal-urls/router.ts +4 -2
  162. package/src/main.ts +123 -55
  163. package/src/modes/acp/acp-agent.ts +593 -47
  164. package/src/modes/acp/acp-event-mapper.ts +9 -0
  165. package/src/modes/acp/startup-provenance.ts +59 -0
  166. package/src/modes/components/custom-provider-wizard.ts +308 -7
  167. package/src/modes/components/model-selector.ts +31 -15
  168. package/src/modes/components/oauth-selector.ts +9 -0
  169. package/src/modes/components/session-selector.ts +47 -4
  170. package/src/modes/components/status-line/segments.ts +6 -1
  171. package/src/modes/components/thinking-selector.ts +7 -3
  172. package/src/modes/components/user-message-selector.ts +57 -15
  173. package/src/modes/controllers/command-controller.ts +58 -32
  174. package/src/modes/controllers/extension-ui-controller.ts +33 -7
  175. package/src/modes/controllers/input-controller.ts +4 -0
  176. package/src/modes/controllers/selector-controller.ts +177 -18
  177. package/src/modes/interactive-mode.ts +21 -7
  178. package/src/modes/runtime-init.ts +1 -0
  179. package/src/modes/shared/agent-wire/workflow-gate-broker.ts +124 -7
  180. package/src/modes/shared/agent-wire/workflow-gate-types.ts +16 -2
  181. package/src/modes/types.ts +2 -2
  182. package/src/prompts/agent-fragments/browser-aside.md +1 -0
  183. package/src/prompts/system/title-system.md +1 -1
  184. package/src/prompts/tools/bash.md +1 -1
  185. package/src/prompts/tools/job.md +1 -1
  186. package/src/prompts/tools/read.md +2 -0
  187. package/src/runtime/network-prewarm-service.test.ts +36 -1
  188. package/src/runtime/network-prewarm-service.ts +28 -3
  189. package/src/runtime/process-lifecycle.ts +22 -11
  190. package/src/runtime-mcp/config.ts +16 -1
  191. package/src/runtime-mcp/manager.ts +689 -55
  192. package/src/runtime-mcp/pool.test.ts +31 -0
  193. package/src/runtime-mcp/pool.ts +304 -28
  194. package/src/runtime-mcp/redaction.ts +42 -0
  195. package/src/runtime-mcp/startup-policy.ts +7 -0
  196. package/src/runtime-mcp/tool-bridge.ts +71 -0
  197. package/src/runtime-mcp/transports/http.ts +108 -25
  198. package/src/sdk/acp/adapter.ts +90 -9
  199. package/src/sdk/acp/final-text.ts +19 -2
  200. package/src/sdk/broker/broker.ts +378 -52
  201. package/src/sdk/broker/ensure.ts +97 -19
  202. package/src/sdk/broker/identity.ts +9 -1
  203. package/src/sdk/broker/lifecycle-ledger.ts +95 -31
  204. package/src/sdk/broker/lifecycle.ts +690 -141
  205. package/src/sdk/broker/runtime.ts +1 -1
  206. package/src/sdk/broker/session-index.ts +97 -4
  207. package/src/sdk/broker/spawn-authority.ts +35 -7
  208. package/src/sdk/broker/stderr-drainer.ts +59 -0
  209. package/src/sdk/bus/chat-daemon-control.ts +2 -2
  210. package/src/sdk/bus/chat-daemon-runtime.ts +1 -0
  211. package/src/sdk/bus/index.ts +721 -84
  212. package/src/sdk/bus/telegram-daemon-cli.ts +31 -2
  213. package/src/sdk/bus/telegram-daemon-contract.ts +3 -1
  214. package/src/sdk/bus/telegram-daemon.ts +10 -3
  215. package/src/sdk/cli/master-cli.ts +47 -36
  216. package/src/sdk/cli/rows.ts +30 -7
  217. package/src/sdk/cli/session-cli.ts +687 -184
  218. package/src/sdk/client/client.ts +18 -0
  219. package/src/sdk/guides/catalog.ts +2 -2
  220. package/src/sdk/guides/cli.ts +20 -62
  221. package/src/sdk/guides/verify.ts +14 -0
  222. package/src/sdk/host/host.ts +49 -5
  223. package/src/sdk/host/session-runtime.test.ts +636 -9
  224. package/src/sdk/host/session-runtime.ts +499 -118
  225. package/src/sdk/host/types.ts +12 -1
  226. package/src/sdk/host/websocket-transport.lifecycle.test.ts +84 -0
  227. package/src/sdk/host/websocket-transport.ts +40 -6
  228. package/src/sdk/index.ts +11 -0
  229. package/src/sdk/prompt-deadline-flush.ts +334 -0
  230. package/src/sdk/prompt-deadline-manager.ts +136 -4
  231. package/src/sdk/prompt-failure.ts +43 -1
  232. package/src/sdk/prompt-status.ts +8 -0
  233. package/src/sdk/prompt-tool-boundary.ts +121 -0
  234. package/src/sdk/protocol/operation-inventory.generated.json +106 -0
  235. package/src/sdk/router/replay-retention-gap-cache.ts +27 -0
  236. package/src/sdk/router/session-router.ts +31 -4
  237. package/src/sdk/session.ts +194 -16
  238. package/src/sdk/startup-capability.ts +1 -1
  239. package/src/sdk/transport/relay.ts +71 -6
  240. package/src/sdk/transport/serve-cli.ts +494 -49
  241. package/src/sdk/transport/socket.ts +12 -11
  242. package/src/sdk/transport/stdio.ts +7 -3
  243. package/src/session/agent-session.ts +2437 -400
  244. package/src/session/fallback-chain-controller.ts +6 -7
  245. package/src/session/fold-coordinator.ts +24 -5
  246. package/src/session/internal/managed-session-scope.ts +58 -18
  247. package/src/session/internal/managed-session-storage.ts +304 -11
  248. package/src/session/session-manager.ts +382 -44
  249. package/src/session/session-work-lease.ts +34 -0
  250. package/src/session-import/codex.ts +12 -3
  251. package/src/setup/model-onboarding-guidance.ts +1 -1
  252. package/src/setup/provider-onboarding.ts +397 -24
  253. package/src/slash-commands/builtin-registry.ts +258 -14
  254. package/src/task/index.ts +14 -2
  255. package/src/thinking.ts +21 -2
  256. package/src/tools/bash.ts +98 -78
  257. package/src/tools/fetch.ts +119 -20
  258. package/src/tools/job.ts +151 -25
  259. package/src/tools/output-meta.ts +15 -2
  260. package/src/tools/path-utils.ts +27 -3
  261. package/src/tools/read.ts +3 -3
  262. package/src/tools/steer-fold.ts +107 -0
  263. package/src/tools/tool-catalog.generated.ts +29 -2
  264. package/src/tools/tool-errors.ts +4 -0
  265. package/src/utils/git.ts +53 -3
  266. package/src/utils/markit.ts +55 -41
  267. package/src/utils/mupdf-assets.d.ts +4 -0
  268. package/src/utils/mupdf-embedded.ts +4 -0
  269. package/src/utils/mupdf-wasm-embedded.ts +3 -0
  270. package/src/utils/mupdf-wasm.ts +24 -2
  271. package/src/utils/mupdf.ts +129 -0
  272. package/src/utils/session-title-generation.ts +29 -0
  273. package/src/utils/title-generator.ts +46 -2
  274. package/src/web/scrapers/types.ts +24 -3
  275. package/vendor/markit-ai/LICENSE +21 -0
  276. package/vendor/markit-ai/MANIFEST.json +412 -0
  277. package/vendor/markit-ai/dist/commands/config.d.ts +4 -0
  278. package/vendor/markit-ai/dist/commands/config.js +139 -0
  279. package/vendor/markit-ai/dist/commands/convert.d.ts +6 -0
  280. package/vendor/markit-ai/dist/commands/convert.js +113 -0
  281. package/vendor/markit-ai/dist/commands/formats.d.ts +2 -0
  282. package/vendor/markit-ai/dist/commands/formats.js +92 -0
  283. package/vendor/markit-ai/dist/commands/init.d.ts +2 -0
  284. package/vendor/markit-ai/dist/commands/init.js +29 -0
  285. package/vendor/markit-ai/dist/commands/onboard.d.ts +2 -0
  286. package/vendor/markit-ai/dist/commands/onboard.js +61 -0
  287. package/vendor/markit-ai/dist/commands/plugin.d.ts +4 -0
  288. package/vendor/markit-ai/dist/commands/plugin.js +58 -0
  289. package/vendor/markit-ai/dist/config.d.ts +26 -0
  290. package/vendor/markit-ai/dist/config.js +42 -0
  291. package/vendor/markit-ai/dist/converters/audio.d.ts +7 -0
  292. package/vendor/markit-ai/dist/converters/audio.js +104 -0
  293. package/vendor/markit-ai/dist/converters/csv.d.ts +7 -0
  294. package/vendor/markit-ai/dist/converters/csv.js +83 -0
  295. package/vendor/markit-ai/dist/converters/docx.d.ts +6 -0
  296. package/vendor/markit-ai/dist/converters/docx.js +57 -0
  297. package/vendor/markit-ai/dist/converters/epub.d.ts +8 -0
  298. package/vendor/markit-ai/dist/converters/epub.js +128 -0
  299. package/vendor/markit-ai/dist/converters/github.d.ts +18 -0
  300. package/vendor/markit-ai/dist/converters/github.js +148 -0
  301. package/vendor/markit-ai/dist/converters/html.d.ts +6 -0
  302. package/vendor/markit-ai/dist/converters/html.js +30 -0
  303. package/vendor/markit-ai/dist/converters/image.d.ts +6 -0
  304. package/vendor/markit-ai/dist/converters/image.js +124 -0
  305. package/vendor/markit-ai/dist/converters/ipynb.d.ts +6 -0
  306. package/vendor/markit-ai/dist/converters/ipynb.js +75 -0
  307. package/vendor/markit-ai/dist/converters/iwork.d.ts +20 -0
  308. package/vendor/markit-ai/dist/converters/iwork.js +391 -0
  309. package/vendor/markit-ai/dist/converters/json.d.ts +6 -0
  310. package/vendor/markit-ai/dist/converters/json.js +21 -0
  311. package/vendor/markit-ai/dist/converters/pdf/columns.d.ts +35 -0
  312. package/vendor/markit-ai/dist/converters/pdf/columns.js +93 -0
  313. package/vendor/markit-ai/dist/converters/pdf/extract.d.ts +19 -0
  314. package/vendor/markit-ai/dist/converters/pdf/extract.js +514 -0
  315. package/vendor/markit-ai/dist/converters/pdf/grid.d.ts +25 -0
  316. package/vendor/markit-ai/dist/converters/pdf/grid.js +795 -0
  317. package/vendor/markit-ai/dist/converters/pdf/headers.d.ts +24 -0
  318. package/vendor/markit-ai/dist/converters/pdf/headers.js +108 -0
  319. package/vendor/markit-ai/dist/converters/pdf/index.d.ts +19 -0
  320. package/vendor/markit-ai/dist/converters/pdf/index.js +136 -0
  321. package/vendor/markit-ai/dist/converters/pdf/mupdf-loader.js +9 -0
  322. package/vendor/markit-ai/dist/converters/pdf/render.d.ts +24 -0
  323. package/vendor/markit-ai/dist/converters/pdf/render.js +513 -0
  324. package/vendor/markit-ai/dist/converters/pdf/types.d.ts +75 -0
  325. package/vendor/markit-ai/dist/converters/pdf/types.js +1 -0
  326. package/vendor/markit-ai/dist/converters/plain-text.d.ts +6 -0
  327. package/vendor/markit-ai/dist/converters/plain-text.js +87 -0
  328. package/vendor/markit-ai/dist/converters/pptx.d.ts +8 -0
  329. package/vendor/markit-ai/dist/converters/pptx.js +289 -0
  330. package/vendor/markit-ai/dist/converters/rss.d.ts +11 -0
  331. package/vendor/markit-ai/dist/converters/rss.js +138 -0
  332. package/vendor/markit-ai/dist/converters/wikipedia.d.ts +6 -0
  333. package/vendor/markit-ai/dist/converters/wikipedia.js +33 -0
  334. package/vendor/markit-ai/dist/converters/xlsx.d.ts +8 -0
  335. package/vendor/markit-ai/dist/converters/xlsx.js +147 -0
  336. package/vendor/markit-ai/dist/converters/xml.d.ts +6 -0
  337. package/vendor/markit-ai/dist/converters/xml.js +18 -0
  338. package/vendor/markit-ai/dist/converters/yaml.d.ts +6 -0
  339. package/vendor/markit-ai/dist/converters/yaml.js +17 -0
  340. package/vendor/markit-ai/dist/converters/zip.d.ts +8 -0
  341. package/vendor/markit-ai/dist/converters/zip.js +57 -0
  342. package/vendor/markit-ai/dist/index.d.ts +30 -0
  343. package/vendor/markit-ai/dist/index.js +26 -0
  344. package/vendor/markit-ai/dist/main.d.ts +2 -0
  345. package/vendor/markit-ai/dist/main.js +191 -0
  346. package/vendor/markit-ai/dist/markit.d.ts +45 -0
  347. package/vendor/markit-ai/dist/markit.js +267 -0
  348. package/vendor/markit-ai/dist/plugins/api.d.ts +7 -0
  349. package/vendor/markit-ai/dist/plugins/api.js +42 -0
  350. package/vendor/markit-ai/dist/plugins/index.d.ts +4 -0
  351. package/vendor/markit-ai/dist/plugins/index.js +3 -0
  352. package/vendor/markit-ai/dist/plugins/installer.d.ts +25 -0
  353. package/vendor/markit-ai/dist/plugins/installer.js +176 -0
  354. package/vendor/markit-ai/dist/plugins/loader.d.ts +6 -0
  355. package/vendor/markit-ai/dist/plugins/loader.js +61 -0
  356. package/vendor/markit-ai/dist/plugins/types.d.ts +25 -0
  357. package/vendor/markit-ai/dist/plugins/types.js +1 -0
  358. package/vendor/markit-ai/dist/providers/anthropic.d.ts +2 -0
  359. package/vendor/markit-ai/dist/providers/anthropic.js +47 -0
  360. package/vendor/markit-ai/dist/providers/index.d.ts +21 -0
  361. package/vendor/markit-ai/dist/providers/index.js +56 -0
  362. package/vendor/markit-ai/dist/providers/openai.d.ts +2 -0
  363. package/vendor/markit-ai/dist/providers/openai.js +76 -0
  364. package/vendor/markit-ai/dist/providers/types.d.ts +26 -0
  365. package/vendor/markit-ai/dist/providers/types.js +1 -0
  366. package/vendor/markit-ai/dist/types.d.ts +36 -0
  367. package/vendor/markit-ai/dist/types.js +1 -0
  368. package/vendor/markit-ai/dist/utils/exit-codes.d.ts +4 -0
  369. package/vendor/markit-ai/dist/utils/exit-codes.js +4 -0
  370. package/vendor/markit-ai/dist/utils/output.d.ts +22 -0
  371. package/vendor/markit-ai/dist/utils/output.js +31 -0
  372. package/vendor/markit-ai/dist/utils/turndown.d.ts +8 -0
  373. package/vendor/markit-ai/dist/utils/turndown.js +70 -0
  374. package/vendor/markit-ai/package.json +74 -0
  375. package/vendor/markit-ai.patch +49 -0
@@ -57,10 +57,12 @@ export function selectReapableSessions(
57
57
  /**
58
58
  * Only a stale/absent endpoint makes a session permanently unreapable, so it is
59
59
  * the sole failure that advances the force-eviction counter. Every other reap
60
- * failure (close_failed, broker unavailability, filesystem errors) is transient
61
- * and must keep retrying without ever escalating to force eviction. The server
62
- * wires `reapSession` to throw `new Error(reason)`, so the reason code is the
63
- * error message here.
60
+ * failure (a close_failed without a stale endpoint, broker unavailability,
61
+ * filesystem errors) is transient and must keep retrying without ever escalating
62
+ * to force eviction. The server wires `reapSession` to throw `new Error(reason)`,
63
+ * except that a close the broker answered with endpoint_stale (close_failed with
64
+ * that detail) is thrown as endpoint_stale, so the reason code is the error
65
+ * message here.
64
66
  */
65
67
  function isEndpointStaleReapError(err: unknown): boolean {
66
68
  return (err instanceof Error ? err.message : String(err)) === "endpoint_stale";
@@ -17,6 +17,7 @@ import {
17
17
  type CrashFingerprint,
18
18
  type CrashProvenance,
19
19
  computeCrashFingerprint,
20
+ computeHandledErrorFingerprint,
20
21
  parseCrashRecordMarker,
21
22
  } from "@gajae-code/utils";
22
23
 
@@ -60,8 +61,11 @@ function findBoundFingerprint(
60
61
  // suffix omission against the marker rather than trusting its syntax.
61
62
  if (remaining.length > 0) stackCandidates.push(remaining.slice(0, -1).join("\n").trimEnd());
62
63
  for (const stack of stackCandidates) {
63
- const fingerprint = computeCrashFingerprint({ name, message, stack });
64
- if (fingerprint.fingerprint === markerFingerprint) return fingerprint;
64
+ const input = { name, message, stack };
65
+ const fatalFingerprint = computeCrashFingerprint(input);
66
+ if (fatalFingerprint.fingerprint === markerFingerprint) return fatalFingerprint;
67
+ const handledFingerprint = computeHandledErrorFingerprint(input);
68
+ if (handledFingerprint.fingerprint === markerFingerprint) return handledFingerprint;
65
69
  }
66
70
  }
67
71
  }
@@ -12,6 +12,8 @@
12
12
  * (automation); the default human output stays a concise per-daemon result.
13
13
  */
14
14
 
15
+ import { replaceTabs, truncateToWidth } from "@gajae-code/tui";
16
+ import { sanitizeDisplayLine } from "@gajae-code/utils";
15
17
  import type { DaemonAction, DaemonOperationResult, DaemonRecovery, DaemonStatus } from "./control-types";
16
18
 
17
19
  /** Canonical daemon actions accepted as the leading verb. */
@@ -39,8 +41,14 @@ export function resolveDaemonAction(token: string | undefined): DaemonAction | u
39
41
  return DAEMON_ACTION_ALIASES[token];
40
42
  }
41
43
 
42
- /** Exit codes for `gjc daemon`. Backward compatible: success 0, any failure 1. */
43
- export const DAEMON_EXIT = { ok: 0, failure: 1 } as const;
44
+ /** Public input failures exit 2; operational failures retain exit 1. */
45
+ export const DAEMON_EXIT = { ok: 0, failure: 1, usage: 2 } as const;
46
+
47
+ /** A refused result may follow a successful stop or spawn; snapshots and prose
48
+ * do not prove that no effect occurred. Only completed results prove applied. */
49
+ export function daemonOperationOutcome(result: DaemonOperationResult): "applied" | "unknown" {
50
+ return result.ok ? "applied" : "unknown";
51
+ }
44
52
 
45
53
  /** Human-facing headline when a spawn/reload is refused by a live foreign identity. */
46
54
  export const OWNERSHIP_MISMATCH_MESSAGE =
@@ -59,6 +67,10 @@ export function ownershipMismatchRecovery(): DaemonRecovery {
59
67
  };
60
68
  }
61
69
 
70
+ function safeDaemonText(value: string): string {
71
+ return truncateToWidth(replaceTabs(sanitizeDisplayLine(value).replaceAll(/[\u2028\u2029]/gu, " ")), 512);
72
+ }
73
+
62
74
  function timestamp(ms: number | undefined): string | undefined {
63
75
  if (ms === undefined) return undefined;
64
76
  const date = new Date(ms);
@@ -73,31 +85,31 @@ export function formatDaemonStatus(status: DaemonStatus, opts: { verbose?: boole
73
85
  const lines: string[] = [];
74
86
  if (!status.configured) {
75
87
  lines.push(`${status.kind}: not configured`);
76
- if (status.runtime.warning) lines.push(` warning: ${status.runtime.warning}`);
88
+ if (status.runtime.warning) lines.push(` warning: ${safeDaemonText(status.runtime.warning)}`);
77
89
  return lines.join("\n");
78
90
  }
79
91
 
80
92
  const meta: string[] = [];
81
93
  if (status.pid !== undefined) meta.push(`pid ${status.pid}`);
82
- if (status.ownerId) meta.push(`owner ${status.ownerId}`);
94
+ if (status.ownerId) meta.push(`owner ${safeDaemonText(status.ownerId)}`);
83
95
  const rootCount = status.rootCount ?? status.roots?.length ?? 0;
84
96
  if (rootCount > 0) meta.push(`${rootCount} root${rootCount === 1 ? "" : "s"}`);
85
97
 
86
98
  let head = `${status.kind}: ${status.health}`;
87
99
  if (meta.length > 0) head += ` (${meta.join(", ")})`;
88
- if (status.detail) head += ` — ${status.detail}`;
100
+ if (status.detail) head += ` — ${safeDaemonText(status.detail)}`;
89
101
  lines.push(head);
90
- if (status.runtime.warning) lines.push(` warning: ${status.runtime.warning}`);
102
+ if (status.runtime.warning) lines.push(` warning: ${safeDaemonText(status.runtime.warning)}`);
91
103
 
92
104
  if (opts.verbose) {
93
- lines.push(` runtime: ${status.runtime.mode} (${status.runtime.execPath})`);
105
+ lines.push(` runtime: ${status.runtime.mode} (${safeDaemonText(status.runtime.execPath)})`);
94
106
  const started = timestamp(status.startedAt);
95
107
  if (started) lines.push(` started: ${started}`);
96
108
  const heartbeat = timestamp(status.heartbeatAt);
97
109
  if (heartbeat) lines.push(` heartbeat: ${heartbeat}`);
98
110
  const roots = status.roots ?? [];
99
111
  lines.push(` roots: ${rootCount}`);
100
- for (const root of roots) lines.push(` - ${root}`);
112
+ for (const root of roots) lines.push(` - ${safeDaemonText(root)}`);
101
113
  }
102
114
 
103
115
  return lines.join("\n");
@@ -108,13 +120,15 @@ export function formatDaemonStatus(status: DaemonStatus, opts: { verbose?: boole
108
120
  * <message>` head line, then any warnings, then actionable recovery steps.
109
121
  */
110
122
  export function formatDaemonResult(result: DaemonOperationResult): string {
111
- const lines = [`${result.kind} ${result.action}: ${result.ok ? "ok" : "failed"} — ${result.message}`];
112
- for (const warning of result.warnings) lines.push(` warning: ${warning}`);
123
+ const lines = [
124
+ `${result.kind} ${result.action}: ${result.ok ? "ok" : "failed"} — ${safeDaemonText(result.message)}`,
125
+ ];
126
+ for (const warning of result.warnings) lines.push(` warning: ${safeDaemonText(warning)}`);
113
127
  if (result.recovery) {
114
- lines.push(` ${result.recovery.summary}`);
128
+ lines.push(` ${safeDaemonText(result.recovery.summary)}`);
115
129
  lines.push(" to recover:");
116
130
  result.recovery.steps.forEach((step, i) => {
117
- lines.push(` ${i + 1}. ${step}`);
131
+ lines.push(` ${i + 1}. ${safeDaemonText(step)}`);
118
132
  });
119
133
  }
120
134
  return lines.join("\n");
@@ -6,7 +6,16 @@
6
6
  import * as fs from "node:fs/promises";
7
7
  import * as path from "node:path";
8
8
  import type { WorkProfile } from "@gajae-code/natives";
9
- import { APP_NAME, getLogPath, getLogsDir, getReportsDir, isEnoent } from "@gajae-code/utils";
9
+ import {
10
+ APP_NAME,
11
+ getEffectiveLogPath,
12
+ getEffectiveLogsDir,
13
+ getLogPath,
14
+ getLogsDir,
15
+ getReportsDir,
16
+ isEnoent,
17
+ resolveEquivalentPath,
18
+ } from "@gajae-code/utils";
10
19
  import type { CpuProfile, HeapSnapshot } from "./profiler";
11
20
  import { collectSystemInfo, sanitizeEnv } from "./system-info";
12
21
 
@@ -34,6 +43,70 @@ async function readLastLines(filePath: string, n: number, maxBytes = MAX_LOG_BYT
34
43
  }
35
44
  }
36
45
 
46
+ /**
47
+ * Both log directories can legitimately hold dated `gjc.<date>.log` files, and a
48
+ * reader that consults only one of them is wrong in one direction or the other.
49
+ *
50
+ * The *effective* directory is where this process writes — a trusted
51
+ * `GJC_LOG_DIR` pin, which the test preload sets to a per-process temp sink
52
+ * (issue #5618). The *canonical* directory is the config root, which carries
53
+ * history: previous runs, other processes, and anything written through
54
+ * `getLogsDir()` before this process pinned anything.
55
+ *
56
+ * Deduplicated by equivalent path, effective first. In production — and in any
57
+ * process that never pinned `GJC_LOG_DIR` — the two resolve to the same
58
+ * directory and this collapses to the single entry these readers have always
59
+ * used, so nothing is listed twice and no ordering changes.
60
+ */
61
+ function logSearchDirs(): string[] {
62
+ const dirs: string[] = [];
63
+ for (const resolve of [getEffectiveLogsDir, getLogsDir]) {
64
+ const resolved = attemptPath(resolve);
65
+ if (resolved !== undefined && !dirs.includes(resolved)) dirs.push(resolved);
66
+ }
67
+ return dirs;
68
+ }
69
+
70
+ /**
71
+ * Resolve a log path, or `undefined` when it is unavailable.
72
+ *
73
+ * `getLogsDir()`/`getLogPath()` throw when there is no trustworthy home. That
74
+ * must not deny the caller the *other* directory, which a pinned `GJC_LOG_DIR`
75
+ * can still supply.
76
+ */
77
+ function attemptPath(resolve: () => string): string | undefined {
78
+ try {
79
+ return resolveEquivalentPath(resolve());
80
+ } catch {
81
+ return undefined;
82
+ }
83
+ }
84
+
85
+ /**
86
+ * Today's log text, oldest content first.
87
+ *
88
+ * Concatenated canonical-then-effective so the tail stays chronological, and the
89
+ * line cap is applied to the COMBINED result: capping per file would let a large
90
+ * history file push this process's own entries out of a bundle that still looks
91
+ * complete. When the two paths are the same file — production, and any process
92
+ * without a `GJC_LOG_DIR` pin — this is a single read of exactly the bytes the
93
+ * previous single-path implementation returned.
94
+ */
95
+ async function readTodayLogText(maxLines: number): Promise<string> {
96
+ const parts: string[] = [];
97
+ const seen = new Set<string>();
98
+ for (const resolve of [getLogPath, getEffectiveLogPath]) {
99
+ const candidate = attemptPath(resolve);
100
+ if (candidate === undefined || seen.has(candidate)) continue;
101
+ seen.add(candidate);
102
+ const text = await readLastLines(candidate, maxLines);
103
+ if (text.length > 0) parts.push(text);
104
+ }
105
+ const combined = parts.join("\n");
106
+ const lines = combined.split("\n");
107
+ return lines.length > maxLines ? lines.slice(-maxLines).join("\n") : combined;
108
+ }
109
+
37
110
  export interface ReportBundleOptions {
38
111
  /** Session file path */
39
112
  sessionFile: string | undefined;
@@ -101,9 +174,8 @@ export async function createReportBundle(options: ReportBundleOptions): Promise<
101
174
  files.push("config.json");
102
175
  }
103
176
 
104
- // Recent logs (last 1000 lines)
105
- const logPath = getLogPath();
106
- const logs = await readLastLines(logPath, 1000);
177
+ // Recent logs (last 1000 lines, across both log directories)
178
+ const logs = await readTodayLogText(1000);
107
179
  if (logs) {
108
180
  data["logs.txt"] = logs;
109
181
  files.push("logs.txt");
@@ -228,31 +300,50 @@ async function addSubagentSessions(
228
300
 
229
301
  /** Get recent log entries for display (tail-limited to avoid OOM on large files). */
230
302
  export async function getLogText(): Promise<string> {
231
- return readLastLines(getLogPath(), MAX_LOG_LINES);
303
+ return readTodayLogText(MAX_LOG_LINES);
232
304
  }
233
305
 
234
306
  const LOG_FILE_PATTERN = new RegExp(`^${APP_NAME}\\.(\\d{4}-\\d{2}-\\d{2})\\.log$`);
235
307
 
308
+ /**
309
+ * Today's log file: the one this process is writing when it exists, else the
310
+ * canonical one. Both spellings share a basename, so the "is this today's file"
311
+ * filter below is unaffected by which is chosen.
312
+ */
313
+ async function resolveTodayLogPath(): Promise<string> {
314
+ const effective = getEffectiveLogPath();
315
+ if (await Bun.file(effective).exists()) return effective;
316
+ const canonical = attemptPath(getLogPath);
317
+ if (canonical !== undefined && (await Bun.file(canonical).exists())) return canonical;
318
+ return effective;
319
+ }
320
+
236
321
  export async function createDebugLogSource(): Promise<DebugLogSource> {
237
- const logsDir = getLogsDir();
238
- const todayPath = getLogPath();
322
+ const todayPath = await resolveTodayLogPath();
239
323
  const todayName = path.basename(todayPath);
240
- let olderFiles: string[] = [];
241
- try {
242
- const entries = await fs.readdir(logsDir, { withFileTypes: true });
243
- const datedFiles = entries
244
- .filter(entry => entry.isFile())
245
- .map(entry => {
246
- const match = LOG_FILE_PATTERN.exec(entry.name);
247
- return match ? { name: entry.name, date: match[1] } : undefined;
248
- })
249
- .filter((entry): entry is { name: string; date: string } => entry !== undefined)
250
- .filter(entry => entry.name !== todayName)
251
- .sort((a, b) => b.date.localeCompare(a.date));
252
- olderFiles = datedFiles.map(entry => entry.name);
253
- } catch {
254
- olderFiles = [];
324
+ // Absolute paths, not bare names: entries can come from either log directory
325
+ // (see {@link logSearchDirs}), so the name alone no longer locates the file.
326
+ const olderFiles: string[] = [];
327
+ const dated: { path: string; date: string }[] = [];
328
+ const seen = new Set<string>();
329
+ for (const dir of logSearchDirs()) {
330
+ // A missing directory contributes nothing; the other one may still exist.
331
+ const entries = await fs.readdir(dir, { withFileTypes: true }).catch(() => []);
332
+ for (const entry of entries) {
333
+ if (!entry.isFile()) continue;
334
+ const match = LOG_FILE_PATTERN.exec(entry.name);
335
+ if (!match || entry.name === todayName) continue;
336
+ const filePath = path.join(dir, entry.name);
337
+ if (seen.has(filePath)) continue;
338
+ seen.add(filePath);
339
+ dated.push({ path: filePath, date: match[1]! });
340
+ }
255
341
  }
342
+ // Newest first. `sort` is stable, so same-date files keep the directory order
343
+ // above (effective before canonical) and the single-directory case is ordered
344
+ // exactly as it was before the second directory was added.
345
+ dated.sort((a, b) => b.date.localeCompare(a.date));
346
+ olderFiles.push(...dated.map(entry => entry.path));
256
347
 
257
348
  let cursor = 0;
258
349
 
@@ -270,8 +361,7 @@ export async function createDebugLogSource(): Promise<DebugLogSource> {
270
361
  const slice = olderFiles.slice(cursor, cursor + count);
271
362
  cursor += slice.length;
272
363
  const chunks: string[] = [];
273
- for (const filename of slice.reverse()) {
274
- const filePath = path.join(logsDir, filename);
364
+ for (const filePath of slice.reverse()) {
275
365
  try {
276
366
  const content = await readLastLines(filePath, MAX_LOG_LINES);
277
367
  if (content.length > 0) {
@@ -458,7 +458,7 @@ Because unselected goals stay schedulable, ordinary source progress moves whole-
458
458
 
459
459
  `adopt` runs in the target repository and starts a genuinely fresh run: new pending goals, fresh timestamps, the target repository's own binding, and no inherited receipts, quality gates, validation batches, steering or activated objective. The source brief and every selected objective are carried verbatim, together with the unresolved obligations recorded against those goals — requirements are carried forward in full, never summarized down. Dependency groups travel as explicit obligations with source-to-target id mapping: the source's batch metadata and receipts are not inherited, but the requirement to validate those goals together is.
460
460
 
461
- Selection and authorization must be explicit. Only unfinished goals (`pending`, `failed`, `blocked`, `review_blocked`) may be handed off; the source run must be quiescent with no `active` goal; there is no implicit or wildcard selection; and a selection that takes only part of a validation batch, or splits a review blocker from the goal it still blocks, is rejected rather than silently dropping that obligation. Adoption fails closed on changed offered work, an altered or unfenced offer, an offer path that escapes the source worktree, a target the offer does not name, a linked worktree that is not the exact named target, an occupied target session, and any duplicate or simultaneous adoption anywhere in the target repository. A retry reconciles the exact recorded operation or fails closed — a matching operation id is never authority to overwrite target work it did not write, and a published plan that has disappeared is never reconstructed.
461
+ Selection and authorization must be explicit. Only unfinished goals (`pending`, `failed`, `blocked`, `review_blocked`) may be handed off; the source run must be quiescent with no `active` goal; there is no implicit or wildcard selection; and a selection that takes only part of a validation batch, or splits a review blocker from the goal it still blocks, is rejected rather than silently dropping that obligation. Adoption fails closed on changed offered work, an altered or unfenced offer, an offer path that escapes the source worktree, a target the offer does not name, a different linked worktree from the exact named target, an occupied target session, and any duplicate or simultaneous adoption anywhere in the target repository. A linked worktree is a valid target when the offer names that exact worktree; the source and target may therefore be sibling worktrees, but aliases of the same source worktree remain self-transfers and are rejected using physical path identity, and an unavailable bound worktree root is refused rather than compared lexically. A retry reconciles the exact recorded operation or fails closed — a matching operation id is never authority to overwrite target work it did not write, and a published plan that has disappeared is never reconstructed.
462
462
 
463
463
  Until publication completes, the target refuses to execute: a visible `goals.json` is not admission evidence, the adoption record is. `start`/`complete-goals` and `checkpoint` reject while an adoption remains pending.
464
464
 
@@ -1,4 +1,5 @@
1
1
  import { isCompiledBinary, logger, Snowflake } from "@gajae-code/utils";
2
+ import { isDesignedError } from "@gajae-code/utils/error-classification";
2
3
  import { registerResourceOwner } from "../../runtime/process-lifecycle";
3
4
  import type { ToolSession } from "../../tools";
4
5
  import { ToolAbortError, ToolError } from "../../tools/tool-errors";
@@ -460,13 +461,11 @@ function reasonToError(reason: unknown, fallback: string): Error {
460
461
  }
461
462
 
462
463
  function errorFromPayload(payload: RunErrorPayload): Error {
463
- if (payload.isAbort) {
464
- const err = new ToolAbortError(payload.message || "Execution aborted");
465
- if (payload.stack) err.stack = payload.stack;
466
- return err;
467
- }
468
- const ctor = payload.isToolError ? ToolError : Error;
469
- const error = new ctor(payload.message);
464
+ const error = payload.isDesigned
465
+ ? payload.isAbort
466
+ ? new ToolAbortError(payload.message || "Execution aborted")
467
+ : new ToolError(payload.message)
468
+ : new Error(payload.message);
470
469
  if (payload.name) error.name = payload.name;
471
470
  if (payload.stack) error.stack = payload.stack;
472
471
  return error;
@@ -479,7 +478,8 @@ function toErrorPayload(error: unknown): RunErrorPayload {
479
478
  message: error.message,
480
479
  stack: error.stack,
481
480
  isAbort: error.name === "AbortError" || error.name === "ToolAbortError",
482
- isToolError: error instanceof ToolError || error.name === "ToolError",
481
+ isToolError: error instanceof ToolError,
482
+ isDesigned: isDesignedError(error),
483
483
  };
484
484
  }
485
485
  return { message: String(error) };
@@ -1,4 +1,5 @@
1
- import { ToolError } from "../../tools/tool-errors";
1
+ import { isDesignedError } from "@gajae-code/utils/error-classification";
2
+ import { ToolAbortError, ToolError } from "../../tools/tool-errors";
2
3
  import { JsRuntime, type RuntimeHooks } from "./shared/runtime";
3
4
  import type { RunErrorPayload, SessionSnapshot, ToolReply, Transport, WorkerInbound } from "./worker-protocol";
4
5
 
@@ -24,15 +25,19 @@ function errorPayload(error: unknown): RunErrorPayload {
24
25
  message: error.message,
25
26
  stack: error.stack,
26
27
  isAbort: error.name === "AbortError" || error.name === "ToolAbortError",
27
- isToolError: error.name === "ToolError" || error instanceof ToolError,
28
+ isToolError: error instanceof ToolError,
29
+ isDesigned: isDesignedError(error),
28
30
  };
29
31
  }
30
32
  return { message: String(error) };
31
33
  }
32
34
 
33
35
  function errorFromPayload(payload: RunErrorPayload): Error {
34
- const ctor = payload.isToolError ? ToolError : Error;
35
- const error = new ctor(payload.message);
36
+ const error = payload.isDesigned
37
+ ? payload.isAbort
38
+ ? new ToolAbortError(payload.message)
39
+ : new ToolError(payload.message)
40
+ : new Error(payload.message);
36
41
  if (payload.name) error.name = payload.name;
37
42
  if (payload.stack) error.stack = payload.stack;
38
43
  return error;
@@ -13,6 +13,8 @@ export interface RunErrorPayload {
13
13
  stack?: string;
14
14
  isAbort?: boolean;
15
15
  isToolError?: boolean;
16
+ /** Set only when the originating error carried the trusted designed marker. */
17
+ isDesigned?: boolean;
16
18
  }
17
19
 
18
20
  export type ToolReply = { ok: true; value: unknown } | { ok: false; error: RunErrorPayload };
@@ -192,6 +192,7 @@ type RunnerEmitResult<TEvent extends RunnerEmitEvent> = TEvent extends { type: "
192
192
  type Handler = Extension["handlers"] extends Map<string, Array<infer T>> ? T : never;
193
193
  type IndexedHandler = { ext: Extension; handler: Handler; registrationOrder: number };
194
194
  type IndexedFunctionHook = IndexedHandler & { registration: FunctionHookRegistration };
195
+ type CommandAliasTarget = { extensionPath: string; commandName: string };
195
196
 
196
197
  export type FunctionHookDispatchResult<TEvent extends ExtensionEvent> =
197
198
  | { action: "continue"; event: TEvent; transformed?: boolean }
@@ -272,6 +273,7 @@ export class ExtensionRunner {
272
273
  #getCredentialSessionId: () => string = () => "";
273
274
  #isIdleFn: () => boolean = () => true;
274
275
  #getActivePromptHandleFn: () => string | undefined = () => undefined;
276
+ #getSessionWorkLeaseFn: ExtensionContextActions["getSessionWorkLease"] = undefined;
275
277
  #waitForIdleFn: () => Promise<void> = async () => {};
276
278
  #abortFn: () => void | Promise<void> = () => {};
277
279
  #abortPromptAndWaitFn: NonNullable<ExtensionContextActions["abortPromptAndWait"]> = async () => {
@@ -328,6 +330,9 @@ export class ExtensionRunner {
328
330
  #reloadHandler: () => Promise<void> = async () => {};
329
331
  #shutdownHandler: ShutdownHandler = () => {};
330
332
  #commandDiagnostics: Array<{ type: string; message: string; path: string }> = [];
333
+ #commandAliases = new Map<string, RegisteredCommand>();
334
+ #commandAliasAssignments = new Map<string, string>();
335
+ #commandAliasTargets = new Map<string, CommandAliasTarget>();
331
336
  #initialized = false;
332
337
  /**
333
338
  * Buffer for `credential_disabled` events received via {@link emitCredentialDisabled}
@@ -424,6 +429,7 @@ export class ExtensionRunner {
424
429
  this.#getCredentialSessionId = contextActions.getCredentialSessionId ?? (() => "");
425
430
  this.#isIdleFn = contextActions.isIdle;
426
431
  this.#getActivePromptHandleFn = contextActions.getActivePromptHandle ?? (() => undefined);
432
+ this.#getSessionWorkLeaseFn = contextActions.getSessionWorkLease;
427
433
  this.#abortFn = contextActions.abort;
428
434
  this.#abortPromptAndWaitFn =
429
435
  contextActions.abortPromptAndWait ??
@@ -701,16 +707,49 @@ export class ExtensionRunner {
701
707
 
702
708
  getRegisteredCommands(reserved?: Set<string>): RegisteredCommand[] {
703
709
  this.#commandDiagnostics = [];
710
+ this.#commandAliases.clear();
704
711
 
705
712
  const commands = new Map<string, RegisteredCommand>();
706
713
  for (const ext of this.extensions) {
707
714
  for (const command of ext.commands.values()) {
708
715
  if (reserved?.has(command.name)) {
709
- const message = `Extension command '${command.name}' from ${ext.path} conflicts with built-in commands. Skipping.`;
710
- this.#commandDiagnostics.push({ type: "warning", message, path: ext.path });
711
- if (!this.hasUI()) {
712
- logger.warn(message);
716
+ const assignmentKey = `${ext.path}\u0000${command.name}`;
717
+ let alias = this.#commandAliasAssignments.get(assignmentKey);
718
+ const aliasTarget = alias ? this.#commandAliasTargets.get(alias) : undefined;
719
+ const aliasOwnedByCommand =
720
+ aliasTarget?.extensionPath === ext.path && aliasTarget.commandName === command.name;
721
+ if (
722
+ !alias ||
723
+ reserved.has(alias) ||
724
+ commands.has(alias) ||
725
+ (aliasTarget !== undefined && !aliasOwnedByCommand)
726
+ ) {
727
+ let candidate = alias ?? `extension:${command.name}`;
728
+ while (
729
+ reserved.has(candidate) ||
730
+ commands.has(candidate) ||
731
+ this.#commandAliases.has(candidate) ||
732
+ (this.#commandAliasTargets.has(candidate) &&
733
+ (this.#commandAliasTargets.get(candidate)?.extensionPath !== ext.path ||
734
+ this.#commandAliasTargets.get(candidate)?.commandName !== command.name))
735
+ )
736
+ candidate = `extension:${candidate}`;
737
+ if (
738
+ alias &&
739
+ this.#commandAliasTargets.get(alias)?.extensionPath === ext.path &&
740
+ this.#commandAliasTargets.get(alias)?.commandName === command.name
741
+ ) {
742
+ this.#commandAliasTargets.delete(alias);
743
+ }
744
+ alias = candidate;
745
+ this.#commandAliasAssignments.set(assignmentKey, alias);
713
746
  }
747
+ this.#commandAliasTargets.set(alias, { extensionPath: ext.path, commandName: command.name });
748
+ const namespaced = { ...command, name: alias };
749
+ this.#commandAliases.set(alias, namespaced);
750
+ commands.set(alias, namespaced);
751
+ const message = `Extension command '${command.name}' from ${ext.path} was renamed to '${alias}' to avoid a built-in command collision.`;
752
+ this.#commandDiagnostics.push({ type: "info", message, path: ext.path });
714
753
  continue;
715
754
  }
716
755
 
@@ -725,6 +764,14 @@ export class ExtensionRunner {
725
764
  }
726
765
 
727
766
  getCommand(name: string): RegisteredCommand | undefined {
767
+ const aliased = this.#commandAliases.get(name);
768
+ if (aliased) return aliased;
769
+ const aliasTarget = this.#commandAliasTargets.get(name);
770
+ if (aliasTarget) {
771
+ const extension = this.extensions.find(ext => ext.path === aliasTarget.extensionPath);
772
+ const command = extension?.commands.get(aliasTarget.commandName);
773
+ if (command) return { ...command, name };
774
+ }
728
775
  for (let index = this.extensions.length - 1; index >= 0; index -= 1) {
729
776
  const command = this.extensions[index]?.commands.get(name);
730
777
  if (command) {
@@ -754,6 +801,7 @@ export class ExtensionRunner {
754
801
  return getModel();
755
802
  },
756
803
  getActivePromptHandle: () => this.#getActivePromptHandleFn(),
804
+ getSessionWorkLease: () => this.#getSessionWorkLeaseFn?.(),
757
805
  isIdle: () => this.#isIdleFn(),
758
806
  abort: () => this.#abortFn(),
759
807
  abortPromptAndWait: (handle, options) => this.#abortPromptAndWaitFn(handle, options),
@@ -58,6 +58,7 @@ import type {
58
58
  } from "../../session/client-bridge";
59
59
  import type { CustomMessage } from "../../session/messages";
60
60
  import type { ReadonlySessionManager, SessionManager } from "../../session/session-manager";
61
+ import type { SessionWorkLease } from "../../session/session-work-lease";
61
62
  import type {
62
63
  BashToolDetails,
63
64
  BashToolInput,
@@ -482,6 +483,8 @@ export interface ExtensionContext {
482
483
  isIdle(): boolean;
483
484
  /** Stable resource ownership identifier for the active prompt run. */
484
485
  getActivePromptHandle(): string | undefined;
486
+ /** The session's authoritative host-liveness lease. */
487
+ getSessionWorkLease?(): SessionWorkLease | undefined;
485
488
  /** Abort the current agent operation */
486
489
  abort(): void | Promise<void>;
487
490
  /** Abort and prove whether resources for a specific prompt settled. */
@@ -1569,6 +1572,11 @@ export type SendUserMessageHandler = (
1569
1572
  * grants root abort ownership.
1570
1573
  */
1571
1574
  onQueuedPromoted?: (promotion: { startsOwnRun?: boolean; removed?: boolean }) => void;
1575
+ /**
1576
+ * Fired synchronously when a plain prompt's dispatch resolves at queue
1577
+ * time instead of run end (diverted into an in-flight run's steering).
1578
+ */
1579
+ onDispatchDisposition?: (promotion: { startsOwnRun: boolean }) => void;
1572
1580
  preflightSignal?: AbortSignal;
1573
1581
  /** Internal SDK correlation owner for an exact queued follow-up. */
1574
1582
  },
@@ -1660,6 +1668,8 @@ export interface ExtensionContextActions {
1660
1668
  isIdle: () => boolean;
1661
1669
  /** Stable resource ownership identifier for the active prompt run. */
1662
1670
  getActivePromptHandle?: () => string | undefined;
1671
+ /** The session's authoritative host-liveness lease. */
1672
+ getSessionWorkLease?: () => SessionWorkLease | undefined;
1663
1673
  abort: () => void | Promise<void>;
1664
1674
  abortPromptAndWait?: (handle: string, options: { graceMs: number }) => Promise<RunSettlementProof>;
1665
1675