@gajae-code/coding-agent 0.17.2 → 0.17.5

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 (390) hide show
  1. package/CHANGELOG.md +267 -0
  2. package/dist/types/cli/daemon-cli.d.ts +3 -1
  3. package/dist/types/cli/github-release.d.ts +17 -0
  4. package/dist/types/cli/public-command-entry.d.ts +56 -0
  5. package/dist/types/cli/public-command-errors.d.ts +126 -0
  6. package/dist/types/cli/public-command-evidence.d.ts +99 -0
  7. package/dist/types/cli/public-command-help.d.ts +65 -0
  8. package/dist/types/cli/public-command-registry.d.ts +69 -0
  9. package/dist/types/cli/session-picker.d.ts +1 -1
  10. package/dist/types/cli/setup-cli.d.ts +1 -0
  11. package/dist/types/cli/skills-cli.d.ts +5 -0
  12. package/dist/types/cli.d.ts +3 -0
  13. package/dist/types/commands/daemon.d.ts +4 -50
  14. package/dist/types/commands/sdk.d.ts +20 -37
  15. package/dist/types/commands/setup.d.ts +3 -0
  16. package/dist/types/commands/skills.d.ts +9 -0
  17. package/dist/types/config/autorouting-tier-map.d.ts +1049 -3
  18. package/dist/types/config/file-lock.d.ts +13 -3
  19. package/dist/types/config/model-profile-activation.d.ts +45 -1
  20. package/dist/types/config/model-registry.d.ts +14 -3
  21. package/dist/types/config/model-resolver.d.ts +1 -1
  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/daemon/operator-contract.d.ts +5 -1
  25. package/dist/types/eval/js/worker-protocol.d.ts +2 -0
  26. package/dist/types/exec/bash-executor.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/gjc-plugins/runtime-adapters.d.ts +11 -2
  30. package/dist/types/extensibility/runtime-skill-discovery.d.ts +18 -0
  31. package/dist/types/extensibility/shared-events.d.ts +3 -1
  32. package/dist/types/gjc-runtime/session-state-lock.d.ts +61 -0
  33. package/dist/types/gjc-runtime/state-writer.d.ts +14 -1
  34. package/dist/types/harness-control-plane/control-endpoint.d.ts +4 -1
  35. package/dist/types/harness-control-plane/finalize.d.ts +14 -3
  36. package/dist/types/internal-urls/embedded-protocol.d.ts +9 -0
  37. package/dist/types/internal-urls/index.d.ts +1 -0
  38. package/dist/types/internal-urls/parse.d.ts +9 -1
  39. package/dist/types/main.d.ts +23 -1
  40. package/dist/types/modes/acp/acp-agent.d.ts +55 -1
  41. package/dist/types/modes/acp/startup-provenance.d.ts +16 -0
  42. package/dist/types/modes/components/custom-provider-wizard.d.ts +19 -1
  43. package/dist/types/modes/components/session-selector.d.ts +5 -2
  44. package/dist/types/modes/components/user-message-selector.d.ts +5 -2
  45. package/dist/types/modes/controllers/command-controller.d.ts +1 -1
  46. package/dist/types/modes/controllers/selector-controller.d.ts +1 -1
  47. package/dist/types/modes/interactive-mode.d.ts +1 -1
  48. package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +11 -1
  49. package/dist/types/modes/shared/agent-wire/workflow-gate-types.d.ts +14 -1
  50. package/dist/types/modes/types.d.ts +2 -2
  51. package/dist/types/runtime/process-lifecycle.d.ts +2 -0
  52. package/dist/types/runtime-mcp/loader.d.ts +2 -0
  53. package/dist/types/runtime-mcp/manager.d.ts +69 -6
  54. package/dist/types/runtime-mcp/pool.d.ts +17 -0
  55. package/dist/types/runtime-mcp/redaction.d.ts +20 -0
  56. package/dist/types/runtime-mcp/startup-policy.d.ts +6 -0
  57. package/dist/types/runtime-mcp/tool-bridge.d.ts +9 -0
  58. package/dist/types/runtime-mcp/transports/http.d.ts +11 -0
  59. package/dist/types/sdk/broker/broker.d.ts +17 -4
  60. package/dist/types/sdk/broker/ensure.d.ts +3 -0
  61. package/dist/types/sdk/broker/identity.d.ts +5 -1
  62. package/dist/types/sdk/broker/lifecycle-ledger.d.ts +23 -3
  63. package/dist/types/sdk/broker/lifecycle.d.ts +15 -8
  64. package/dist/types/sdk/broker/managed-task-dag.d.ts +1335 -0
  65. package/dist/types/sdk/broker/managed-task-verification.d.ts +37 -0
  66. package/dist/types/sdk/broker/runtime.d.ts +1 -1
  67. package/dist/types/sdk/broker/session-index.d.ts +22 -3
  68. package/dist/types/sdk/broker/spawn-authority.d.ts +12 -0
  69. package/dist/types/sdk/broker/startup-failure.d.ts +4 -0
  70. package/dist/types/sdk/broker/stderr-drainer.d.ts +13 -0
  71. package/dist/types/sdk/bus/index.d.ts +19 -0
  72. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +7 -1
  73. package/dist/types/sdk/bus/telegram-daemon.d.ts +5 -0
  74. package/dist/types/sdk/cli/master-cli.d.ts +6 -10
  75. package/dist/types/sdk/cli/rows.d.ts +19 -1
  76. package/dist/types/sdk/cli/session-cli.d.ts +22 -5
  77. package/dist/types/sdk/client/client.d.ts +2 -0
  78. package/dist/types/sdk/guides/cli.d.ts +3 -4
  79. package/dist/types/sdk/guides/verify.d.ts +2 -0
  80. package/dist/types/sdk/host/host.d.ts +9 -0
  81. package/dist/types/sdk/host/session-runtime.d.ts +31 -0
  82. package/dist/types/sdk/host/types.d.ts +10 -0
  83. package/dist/types/sdk/index.d.ts +1 -0
  84. package/dist/types/sdk/prompt-deadline-flush.d.ts +85 -0
  85. package/dist/types/sdk/prompt-deadline-manager.d.ts +37 -0
  86. package/dist/types/sdk/prompt-tool-boundary.d.ts +73 -0
  87. package/dist/types/sdk/router/session-router.d.ts +2 -0
  88. package/dist/types/sdk/session.d.ts +3 -3
  89. package/dist/types/sdk/startup-capability.d.ts +2 -0
  90. package/dist/types/sdk/transport/relay.d.ts +1 -0
  91. package/dist/types/sdk/transport/serve-cli.d.ts +48 -4
  92. package/dist/types/sdk/transport/stdio.d.ts +5 -1
  93. package/dist/types/session/agent-session.d.ts +175 -23
  94. package/dist/types/session/fallback-chain-controller.d.ts +6 -6
  95. package/dist/types/session/fold-coordinator.d.ts +17 -3
  96. package/dist/types/session/internal/managed-session-storage.d.ts +7 -1
  97. package/dist/types/session/session-manager.d.ts +64 -1
  98. package/dist/types/session/session-work-lease.d.ts +14 -0
  99. package/dist/types/setup/model-onboarding-guidance.d.ts +1 -1
  100. package/dist/types/setup/provider-onboarding.d.ts +81 -1
  101. package/dist/types/task/types.d.ts +2 -0
  102. package/dist/types/tools/bash-interactive.d.ts +1 -0
  103. package/dist/types/tools/bash.d.ts +37 -11
  104. package/dist/types/tools/fetch.d.ts +10 -1
  105. package/dist/types/tools/job.d.ts +1 -1
  106. package/dist/types/tools/steer-fold.d.ts +31 -0
  107. package/dist/types/tools/subagent.d.ts +8 -1
  108. package/dist/types/utils/git.d.ts +28 -2
  109. package/dist/types/utils/mupdf-embedded.d.ts +2 -0
  110. package/dist/types/utils/mupdf.d.ts +4 -0
  111. package/dist/types/utils/session-title-generation.d.ts +6 -0
  112. package/dist/types/utils/title-generator.d.ts +11 -2
  113. package/dist/types/web/scrapers/types.d.ts +3 -0
  114. package/package.json +18 -10
  115. package/scripts/build-binary.ts +9 -3
  116. package/scripts/compile-args.ts +0 -9
  117. package/scripts/embed-mupdf.ts +52 -0
  118. package/scripts/generate-sdk-operation-inventory.ts +31 -1
  119. package/scripts/vendor-markit.ts +196 -0
  120. package/src/async/job-manager.ts +22 -1
  121. package/src/cli/daemon-cli.ts +53 -18
  122. package/src/cli/github-release.ts +87 -5
  123. package/src/cli/mcp-cli.ts +38 -4
  124. package/src/cli/public-command-entry.ts +450 -0
  125. package/src/cli/public-command-errors.ts +581 -0
  126. package/src/cli/public-command-evidence.ts +717 -0
  127. package/src/cli/public-command-help.ts +360 -0
  128. package/src/cli/public-command-registry.ts +541 -0
  129. package/src/cli/session-picker.ts +2 -1
  130. package/src/cli/setup-cli.ts +10 -1
  131. package/src/cli/skills-cli.ts +46 -2
  132. package/src/cli/stats-cli.ts +11 -1
  133. package/src/cli.ts +61 -1
  134. package/src/commands/daemon.ts +65 -69
  135. package/src/commands/sdk.ts +175 -117
  136. package/src/commands/setup.ts +2 -0
  137. package/src/commands/skills.ts +11 -0
  138. package/src/config/autorouting-tier-map.ts +543 -3
  139. package/src/config/file-lock.ts +206 -65
  140. package/src/config/model-discovery-manager.ts +4 -4
  141. package/src/config/model-profile-activation.ts +417 -66
  142. package/src/config/model-registry.ts +254 -36
  143. package/src/config/model-resolver.ts +6 -1
  144. package/src/config/settings-schema.ts +26 -2
  145. package/src/coordinator-mcp/policy.ts +10 -5
  146. package/src/coordinator-mcp/question-gate-codec.ts +17 -0
  147. package/src/coordinator-mcp/question-state.ts +179 -9
  148. package/src/coordinator-mcp/server.ts +521 -87
  149. package/src/coordinator-mcp/session-reaper.ts +6 -4
  150. package/src/crash/record-loader.ts +6 -2
  151. package/src/daemon/operator-contract.ts +26 -12
  152. package/src/defaults/gjc/skills/ultragoal/SKILL.md +1 -1
  153. package/src/eval/js/context-manager.ts +8 -8
  154. package/src/eval/js/worker-core.ts +9 -4
  155. package/src/eval/js/worker-protocol.ts +2 -0
  156. package/src/exec/bash-executor.ts +3 -0
  157. package/src/extensibility/extensions/runner.ts +52 -4
  158. package/src/extensibility/extensions/types.ts +10 -0
  159. package/src/extensibility/gjc-plugins/registry.ts +196 -37
  160. package/src/extensibility/gjc-plugins/runtime-adapters.ts +46 -8
  161. package/src/extensibility/runtime-skill-discovery.ts +61 -3
  162. package/src/extensibility/shared-events.ts +3 -1
  163. package/src/gjc-runtime/session-state-lock.ts +165 -24
  164. package/src/gjc-runtime/state-writer.ts +317 -6
  165. package/src/gjc-runtime/ultragoal-succession.ts +31 -3
  166. package/src/harness-control-plane/control-endpoint.ts +24 -6
  167. package/src/harness-control-plane/finalize.ts +312 -25
  168. package/src/harness-control-plane/owner.ts +323 -89
  169. package/src/internal-urls/docs-index.generated.ts +23 -20
  170. package/src/internal-urls/embedded-protocol.ts +83 -0
  171. package/src/internal-urls/index.ts +1 -0
  172. package/src/internal-urls/parse.ts +21 -1
  173. package/src/internal-urls/router.ts +4 -2
  174. package/src/main.ts +192 -74
  175. package/src/modes/acp/acp-agent.ts +973 -56
  176. package/src/modes/acp/startup-provenance.ts +59 -0
  177. package/src/modes/components/custom-provider-wizard.ts +308 -7
  178. package/src/modes/components/gjc-bundle-settings.ts +21 -1
  179. package/src/modes/components/oauth-selector.ts +9 -0
  180. package/src/modes/components/session-selector.ts +47 -4
  181. package/src/modes/components/tool-status-header.ts +72 -6
  182. package/src/modes/components/user-message-selector.ts +57 -15
  183. package/src/modes/controllers/command-controller.ts +58 -32
  184. package/src/modes/controllers/extension-ui-controller.ts +33 -7
  185. package/src/modes/controllers/input-controller.ts +4 -0
  186. package/src/modes/controllers/runtime-mcp-command-controller.ts +1 -1
  187. package/src/modes/controllers/selector-controller.ts +161 -15
  188. package/src/modes/interactive-mode.ts +21 -7
  189. package/src/modes/runtime-init.ts +1 -0
  190. package/src/modes/shared/agent-wire/workflow-gate-broker.ts +124 -7
  191. package/src/modes/shared/agent-wire/workflow-gate-types.ts +16 -2
  192. package/src/modes/types.ts +2 -2
  193. package/src/prompts/agent-fragments/browser-aside.md +1 -0
  194. package/src/prompts/system/title-system.md +1 -1
  195. package/src/prompts/tools/bash.md +1 -1
  196. package/src/prompts/tools/job.md +1 -1
  197. package/src/prompts/tools/read.md +2 -0
  198. package/src/runtime/network-prewarm-service.test.ts +36 -1
  199. package/src/runtime/network-prewarm-service.ts +28 -3
  200. package/src/runtime/process-lifecycle.ts +22 -11
  201. package/src/runtime-mcp/config.ts +16 -1
  202. package/src/runtime-mcp/loader.ts +6 -3
  203. package/src/runtime-mcp/manager.ts +845 -109
  204. package/src/runtime-mcp/pool.test.ts +31 -0
  205. package/src/runtime-mcp/pool.ts +304 -28
  206. package/src/runtime-mcp/redaction.ts +42 -0
  207. package/src/runtime-mcp/startup-policy.ts +7 -0
  208. package/src/runtime-mcp/tool-bridge.ts +71 -0
  209. package/src/runtime-mcp/transports/http.ts +108 -25
  210. package/src/sdk/acp/adapter.ts +27 -8
  211. package/src/sdk/broker/broker.ts +1431 -198
  212. package/src/sdk/broker/ensure.ts +21 -3
  213. package/src/sdk/broker/identity.ts +22 -1
  214. package/src/sdk/broker/lifecycle-ledger.ts +95 -31
  215. package/src/sdk/broker/lifecycle.ts +690 -141
  216. package/src/sdk/broker/managed-task-dag.ts +1927 -0
  217. package/src/sdk/broker/managed-task-verification.ts +642 -0
  218. package/src/sdk/broker/runtime.ts +1 -1
  219. package/src/sdk/broker/session-index.ts +97 -4
  220. package/src/sdk/broker/spawn-authority.ts +175 -14
  221. package/src/sdk/broker/startup-failure.ts +80 -1
  222. package/src/sdk/broker/stderr-drainer.ts +59 -0
  223. package/src/sdk/broker/transport.ts +1 -0
  224. package/src/sdk/bus/chat-daemon-control.ts +2 -2
  225. package/src/sdk/bus/chat-daemon-runtime.ts +1 -0
  226. package/src/sdk/bus/index.ts +707 -81
  227. package/src/sdk/bus/telegram-daemon-cli.ts +31 -2
  228. package/src/sdk/bus/telegram-daemon-contract.ts +7 -1
  229. package/src/sdk/bus/telegram-daemon.ts +10 -3
  230. package/src/sdk/cli/master-cli.ts +47 -36
  231. package/src/sdk/cli/rows.ts +30 -7
  232. package/src/sdk/cli/session-cli.ts +705 -184
  233. package/src/sdk/client/client.ts +18 -0
  234. package/src/sdk/guides/catalog.ts +2 -2
  235. package/src/sdk/guides/cli.ts +20 -62
  236. package/src/sdk/guides/verify.ts +14 -0
  237. package/src/sdk/host/host.ts +49 -5
  238. package/src/sdk/host/session-runtime.test.ts +184 -2
  239. package/src/sdk/host/session-runtime.ts +322 -101
  240. package/src/sdk/host/types.ts +12 -1
  241. package/src/sdk/host/websocket-transport.lifecycle.test.ts +84 -0
  242. package/src/sdk/host/websocket-transport.ts +40 -6
  243. package/src/sdk/index.ts +11 -0
  244. package/src/sdk/lifecycle/service.ts +2 -0
  245. package/src/sdk/prompt-deadline-flush.ts +356 -0
  246. package/src/sdk/prompt-deadline-manager.ts +133 -1
  247. package/src/sdk/prompt-tool-boundary.ts +121 -0
  248. package/src/sdk/protocol/operation-inventory.generated.json +106 -0
  249. package/src/sdk/router/session-router.ts +9 -1
  250. package/src/sdk/session.ts +763 -116
  251. package/src/sdk/startup-capability.ts +1 -1
  252. package/src/sdk/transport/relay.ts +71 -6
  253. package/src/sdk/transport/serve-cli.ts +397 -42
  254. package/src/sdk/transport/socket.ts +12 -11
  255. package/src/sdk/transport/stdio.ts +7 -3
  256. package/src/session/agent-session.ts +2472 -407
  257. package/src/session/fallback-chain-controller.ts +6 -7
  258. package/src/session/fold-coordinator.ts +24 -5
  259. package/src/session/internal/managed-session-scope.ts +68 -18
  260. package/src/session/internal/managed-session-storage.ts +334 -12
  261. package/src/session/session-manager.ts +382 -44
  262. package/src/session/session-work-lease.ts +34 -0
  263. package/src/setup/model-onboarding-guidance.ts +1 -1
  264. package/src/setup/provider-onboarding.ts +397 -24
  265. package/src/setup/provider-presets.json +2 -1
  266. package/src/slash-commands/builtin-registry.ts +259 -15
  267. package/src/task/executor.ts +46 -17
  268. package/src/task/index.ts +14 -2
  269. package/src/task/types.ts +2 -0
  270. package/src/tools/bash-interactive.ts +2 -0
  271. package/src/tools/bash.ts +118 -78
  272. package/src/tools/fetch.ts +140 -25
  273. package/src/tools/job.ts +151 -25
  274. package/src/tools/output-meta.ts +15 -2
  275. package/src/tools/path-utils.ts +27 -3
  276. package/src/tools/read.ts +3 -3
  277. package/src/tools/steer-fold.ts +107 -0
  278. package/src/tools/subagent-render.ts +24 -1
  279. package/src/tools/subagent.ts +27 -1
  280. package/src/tools/tool-catalog.generated.ts +29 -2
  281. package/src/tools/tool-errors.ts +4 -0
  282. package/src/utils/git.ts +53 -3
  283. package/src/utils/markit.ts +55 -41
  284. package/src/utils/mupdf-assets.d.ts +4 -0
  285. package/src/utils/mupdf-embedded.ts +4 -0
  286. package/src/utils/mupdf.ts +136 -0
  287. package/src/utils/session-title-generation.ts +29 -0
  288. package/src/utils/title-generator.ts +46 -2
  289. package/src/web/scrapers/types.ts +24 -3
  290. package/vendor/markit-ai/LICENSE +21 -0
  291. package/vendor/markit-ai/MANIFEST.json +412 -0
  292. package/vendor/markit-ai/dist/commands/config.d.ts +4 -0
  293. package/vendor/markit-ai/dist/commands/config.js +139 -0
  294. package/vendor/markit-ai/dist/commands/convert.d.ts +6 -0
  295. package/vendor/markit-ai/dist/commands/convert.js +113 -0
  296. package/vendor/markit-ai/dist/commands/formats.d.ts +2 -0
  297. package/vendor/markit-ai/dist/commands/formats.js +92 -0
  298. package/vendor/markit-ai/dist/commands/init.d.ts +2 -0
  299. package/vendor/markit-ai/dist/commands/init.js +29 -0
  300. package/vendor/markit-ai/dist/commands/onboard.d.ts +2 -0
  301. package/vendor/markit-ai/dist/commands/onboard.js +61 -0
  302. package/vendor/markit-ai/dist/commands/plugin.d.ts +4 -0
  303. package/vendor/markit-ai/dist/commands/plugin.js +58 -0
  304. package/vendor/markit-ai/dist/config.d.ts +26 -0
  305. package/vendor/markit-ai/dist/config.js +42 -0
  306. package/vendor/markit-ai/dist/converters/audio.d.ts +7 -0
  307. package/vendor/markit-ai/dist/converters/audio.js +104 -0
  308. package/vendor/markit-ai/dist/converters/csv.d.ts +7 -0
  309. package/vendor/markit-ai/dist/converters/csv.js +83 -0
  310. package/vendor/markit-ai/dist/converters/docx.d.ts +6 -0
  311. package/vendor/markit-ai/dist/converters/docx.js +57 -0
  312. package/vendor/markit-ai/dist/converters/epub.d.ts +8 -0
  313. package/vendor/markit-ai/dist/converters/epub.js +128 -0
  314. package/vendor/markit-ai/dist/converters/github.d.ts +18 -0
  315. package/vendor/markit-ai/dist/converters/github.js +148 -0
  316. package/vendor/markit-ai/dist/converters/html.d.ts +6 -0
  317. package/vendor/markit-ai/dist/converters/html.js +30 -0
  318. package/vendor/markit-ai/dist/converters/image.d.ts +6 -0
  319. package/vendor/markit-ai/dist/converters/image.js +124 -0
  320. package/vendor/markit-ai/dist/converters/ipynb.d.ts +6 -0
  321. package/vendor/markit-ai/dist/converters/ipynb.js +75 -0
  322. package/vendor/markit-ai/dist/converters/iwork.d.ts +20 -0
  323. package/vendor/markit-ai/dist/converters/iwork.js +391 -0
  324. package/vendor/markit-ai/dist/converters/json.d.ts +6 -0
  325. package/vendor/markit-ai/dist/converters/json.js +21 -0
  326. package/vendor/markit-ai/dist/converters/pdf/columns.d.ts +35 -0
  327. package/vendor/markit-ai/dist/converters/pdf/columns.js +93 -0
  328. package/vendor/markit-ai/dist/converters/pdf/extract.d.ts +19 -0
  329. package/vendor/markit-ai/dist/converters/pdf/extract.js +514 -0
  330. package/vendor/markit-ai/dist/converters/pdf/grid.d.ts +25 -0
  331. package/vendor/markit-ai/dist/converters/pdf/grid.js +795 -0
  332. package/vendor/markit-ai/dist/converters/pdf/headers.d.ts +24 -0
  333. package/vendor/markit-ai/dist/converters/pdf/headers.js +108 -0
  334. package/vendor/markit-ai/dist/converters/pdf/index.d.ts +19 -0
  335. package/vendor/markit-ai/dist/converters/pdf/index.js +136 -0
  336. package/vendor/markit-ai/dist/converters/pdf/mupdf-loader.js +9 -0
  337. package/vendor/markit-ai/dist/converters/pdf/render.d.ts +24 -0
  338. package/vendor/markit-ai/dist/converters/pdf/render.js +513 -0
  339. package/vendor/markit-ai/dist/converters/pdf/types.d.ts +75 -0
  340. package/vendor/markit-ai/dist/converters/pdf/types.js +1 -0
  341. package/vendor/markit-ai/dist/converters/plain-text.d.ts +6 -0
  342. package/vendor/markit-ai/dist/converters/plain-text.js +87 -0
  343. package/vendor/markit-ai/dist/converters/pptx.d.ts +8 -0
  344. package/vendor/markit-ai/dist/converters/pptx.js +289 -0
  345. package/vendor/markit-ai/dist/converters/rss.d.ts +11 -0
  346. package/vendor/markit-ai/dist/converters/rss.js +138 -0
  347. package/vendor/markit-ai/dist/converters/wikipedia.d.ts +6 -0
  348. package/vendor/markit-ai/dist/converters/wikipedia.js +33 -0
  349. package/vendor/markit-ai/dist/converters/xlsx.d.ts +8 -0
  350. package/vendor/markit-ai/dist/converters/xlsx.js +147 -0
  351. package/vendor/markit-ai/dist/converters/xml.d.ts +6 -0
  352. package/vendor/markit-ai/dist/converters/xml.js +18 -0
  353. package/vendor/markit-ai/dist/converters/yaml.d.ts +6 -0
  354. package/vendor/markit-ai/dist/converters/yaml.js +17 -0
  355. package/vendor/markit-ai/dist/converters/zip.d.ts +8 -0
  356. package/vendor/markit-ai/dist/converters/zip.js +57 -0
  357. package/vendor/markit-ai/dist/index.d.ts +30 -0
  358. package/vendor/markit-ai/dist/index.js +26 -0
  359. package/vendor/markit-ai/dist/main.d.ts +2 -0
  360. package/vendor/markit-ai/dist/main.js +191 -0
  361. package/vendor/markit-ai/dist/markit.d.ts +45 -0
  362. package/vendor/markit-ai/dist/markit.js +267 -0
  363. package/vendor/markit-ai/dist/plugins/api.d.ts +7 -0
  364. package/vendor/markit-ai/dist/plugins/api.js +42 -0
  365. package/vendor/markit-ai/dist/plugins/index.d.ts +4 -0
  366. package/vendor/markit-ai/dist/plugins/index.js +3 -0
  367. package/vendor/markit-ai/dist/plugins/installer.d.ts +25 -0
  368. package/vendor/markit-ai/dist/plugins/installer.js +176 -0
  369. package/vendor/markit-ai/dist/plugins/loader.d.ts +6 -0
  370. package/vendor/markit-ai/dist/plugins/loader.js +61 -0
  371. package/vendor/markit-ai/dist/plugins/types.d.ts +25 -0
  372. package/vendor/markit-ai/dist/plugins/types.js +1 -0
  373. package/vendor/markit-ai/dist/providers/anthropic.d.ts +2 -0
  374. package/vendor/markit-ai/dist/providers/anthropic.js +47 -0
  375. package/vendor/markit-ai/dist/providers/index.d.ts +21 -0
  376. package/vendor/markit-ai/dist/providers/index.js +56 -0
  377. package/vendor/markit-ai/dist/providers/openai.d.ts +2 -0
  378. package/vendor/markit-ai/dist/providers/openai.js +76 -0
  379. package/vendor/markit-ai/dist/providers/types.d.ts +26 -0
  380. package/vendor/markit-ai/dist/providers/types.js +1 -0
  381. package/vendor/markit-ai/dist/types.d.ts +36 -0
  382. package/vendor/markit-ai/dist/types.js +1 -0
  383. package/vendor/markit-ai/dist/utils/exit-codes.d.ts +4 -0
  384. package/vendor/markit-ai/dist/utils/exit-codes.js +4 -0
  385. package/vendor/markit-ai/dist/utils/output.d.ts +22 -0
  386. package/vendor/markit-ai/dist/utils/output.js +31 -0
  387. package/vendor/markit-ai/dist/utils/turndown.d.ts +8 -0
  388. package/vendor/markit-ai/dist/utils/turndown.js +70 -0
  389. package/vendor/markit-ai/package.json +74 -0
  390. package/vendor/markit-ai.patch +49 -0
@@ -1,8 +1,17 @@
1
+ import * as crypto from "node:crypto";
1
2
  import { getAgentDir } from "@gajae-code/utils";
2
3
  import { CliParseError } from "@gajae-code/utils/cli";
4
+ import {
5
+ normalizePublicCommandFailure,
6
+ type PublicCommandDiagnosticCode,
7
+ PublicCommandFailure,
8
+ } from "../../cli/public-command-errors";
9
+ import { normalizeBrokerInput } from "../broker/broker";
3
10
  import type { BrokerDiscovery } from "../broker/discovery";
11
+ import { lifecycleRequestTimeoutMs } from "../broker/startup-budget";
4
12
  import { readSdkBrokerDiscovery, SdkClient, SdkClientError, SdkDiscoveryError } from "../client";
5
13
  import { SessionListTraversalError, sessionListPageFromResponse, traverseSessionList } from "../session-list";
14
+ import type { ServeHandle } from "./index";
6
15
  import { DEFAULT_PENDING_CEILING_BYTES, MIN_PENDING_CEILING_BYTES, startSocketServe, startStdioServe } from "./index";
7
16
 
8
17
  type ServeMode = { kind: "stdio" } | { kind: "socket"; socketPath: string };
@@ -13,16 +22,21 @@ interface ServeArguments {
13
22
  pendingCeiling?: string;
14
23
  }
15
24
 
16
- function usageError(message: string): never {
17
- throw new CliParseError(`gjc sdk serve: ${message}`);
25
+ /**
26
+ * Usage failures keep a static, allowlisted reason instead of the parser's raw text:
27
+ * the concrete diagnostic is what makes an unknown flag or a missing operand
28
+ * actionable, and it never echoes caller argv back into output or the evidence store.
29
+ */
30
+ function usageError(diagnostic: PublicCommandDiagnosticCode): never {
31
+ throw new PublicCommandFailure({ kind: "usage", proof: "pre-effect", diagnostics: [diagnostic] });
18
32
  }
19
33
 
20
34
  /**
21
35
  * A `gjc sdk serve` operational failure with a stable machine-readable code and a
22
36
  * documented exit code, mirroring `SdkSessionCliError`. Usage errors keep their own
23
- * `CliParseError` path; this type covers only failures an embedder must branch on.
37
+ * public failure envelope; this type covers only failures an embedder must branch on.
24
38
  */
25
- export class SdkServeError extends Error {
39
+ export class SdkServeError extends PublicCommandFailure {
26
40
  /**
27
41
  * Diagnostics for a broker-teardown failure that happened alongside this primary
28
42
  * failure. It rides beside `details` rather than inside it because `details`
@@ -36,8 +50,65 @@ export class SdkServeError extends Error {
36
50
  readonly exitCode: 1,
37
51
  readonly details?: unknown,
38
52
  ) {
39
- super(message);
53
+ super(sdkServeFailureInput(code));
40
54
  this.name = "SdkServeError";
55
+ this.message = message;
56
+ }
57
+ }
58
+
59
+ function sdkServeFailureInput(code: string): {
60
+ kind:
61
+ | "usage"
62
+ | "invalid_json"
63
+ | "unavailable"
64
+ | "broker_unavailable"
65
+ | "endpoint_stale"
66
+ | "broker_restarting"
67
+ | "authorization_denied"
68
+ | "timeout"
69
+ | "wait_timeout"
70
+ | "uncertain_after_send"
71
+ | "daemon_unhealthy"
72
+ | "daemon_stale"
73
+ | "daemon_mixed"
74
+ | "operation_failed"
75
+ | "internal";
76
+ proof?: "pre-send" | "pre-effect" | "accepted" | "completed" | "sent" | "unknown";
77
+ } {
78
+ switch (code) {
79
+ case "broker_restarting":
80
+ return { kind: "broker_restarting", proof: "pre-effect" };
81
+ case "broker_unavailable":
82
+ case "broker_discovery_unreadable":
83
+ return { kind: "broker_unavailable", proof: "pre-effect" };
84
+ case "endpoint_stale":
85
+ return { kind: "endpoint_stale", proof: "pre-effect" };
86
+ case "authorization_denied":
87
+ case "unauthorized":
88
+ case "forbidden":
89
+ case "master_context_required":
90
+ case "adapter_operation_prohibited":
91
+ case "endpoint_credential_forbidden":
92
+ return { kind: "authorization_denied", proof: "pre-effect" };
93
+ case "timeout":
94
+ return { kind: "timeout", proof: "unknown" };
95
+ case "uncertain_after_send":
96
+ return { kind: "uncertain_after_send", proof: "sent" };
97
+ case "usage":
98
+ case "invalid_input":
99
+ case "invalid_json":
100
+ return { kind: "usage", proof: "pre-effect" };
101
+ case "unavailable":
102
+ case "unsupported_platform":
103
+ case "not_found":
104
+ case "ambiguous_session":
105
+ return { kind: "unavailable", proof: "pre-effect" };
106
+ case "no_live_endpoint":
107
+ return { kind: "endpoint_stale", proof: "pre-effect" };
108
+ case "multiple_live_endpoints":
109
+ return { kind: "usage", proof: "pre-effect" };
110
+ default:
111
+ return { kind: "operation_failed" };
41
112
  }
42
113
  }
43
114
 
@@ -91,7 +162,10 @@ async function brokerCloseFailure(broker: SdkClient): Promise<Error | undefined>
91
162
  */
92
163
  export function resolveServeOutcome(primary: Error | undefined, cleanup: Error | undefined): Error | undefined {
93
164
  if (primary) {
94
- if (cleanup && primary instanceof SdkServeError) primary.cleanupError = cleanupDiagnostics(cleanup);
165
+ if (cleanup && primary instanceof SdkServeError) {
166
+ primary.cleanupError = cleanupDiagnostics(cleanup);
167
+ primary.input.diagnostics = [...(primary.input.diagnostics ?? []), "broker_cleanup_failed"];
168
+ }
95
169
  return primary;
96
170
  }
97
171
  if (!cleanup) return undefined;
@@ -99,9 +173,9 @@ export function resolveServeOutcome(primary: Error | undefined, cleanup: Error |
99
173
  return new SdkServeError("serve_cleanup_failed", `SDK broker cleanup failed: ${cleanup.message}`, 1, diagnostics);
100
174
  }
101
175
 
102
- function readFlagValue(argv: string[], index: number, flag: string): string {
176
+ function readFlagValue(argv: string[], index: number): string {
103
177
  const value = argv[index + 1];
104
- if (value === undefined || value.startsWith("-")) usageError(`${flag} requires a value`);
178
+ if (value === undefined || value.startsWith("-")) usageError("usage_missing_value");
105
179
  return value;
106
180
  }
107
181
 
@@ -113,29 +187,29 @@ function parseServeArguments(argv: string[]): ServeArguments {
113
187
  for (let index = 0; index < argv.length; index++) {
114
188
  switch (argv[index]) {
115
189
  case "--stdio":
116
- if (stdio) usageError("--stdio may only be specified once");
190
+ if (stdio) usageError("usage_duplicate_option");
117
191
  stdio = true;
118
192
  break;
119
193
  case "--socket":
120
- if (socketPath !== undefined) usageError("--socket may only be specified once");
121
- socketPath = readFlagValue(argv, index, "--socket");
194
+ if (socketPath !== undefined) usageError("usage_duplicate_option");
195
+ socketPath = readFlagValue(argv, index);
122
196
  index++;
123
197
  break;
124
198
  case "--session":
125
- if (sessionId !== undefined) usageError("--session may only be specified once");
126
- sessionId = readFlagValue(argv, index, "--session");
199
+ if (sessionId !== undefined) usageError("usage_duplicate_option");
200
+ sessionId = readFlagValue(argv, index);
127
201
  index++;
128
202
  break;
129
203
  case "--pending-ceiling":
130
- if (pendingCeiling !== undefined) usageError("--pending-ceiling may only be specified once");
131
- pendingCeiling = readFlagValue(argv, index, "--pending-ceiling");
204
+ if (pendingCeiling !== undefined) usageError("usage_duplicate_option");
205
+ pendingCeiling = readFlagValue(argv, index);
132
206
  index++;
133
207
  break;
134
208
  default:
135
- usageError(`unknown argument: ${argv[index]}`);
209
+ usageError("usage_unknown_argument");
136
210
  }
137
211
  }
138
- if (stdio === (socketPath !== undefined)) usageError("specify exactly one of --stdio or --socket <path>");
212
+ if (stdio === (socketPath !== undefined)) usageError("usage_transport_exclusive");
139
213
  return { mode: stdio ? { kind: "stdio" } : { kind: "socket", socketPath: socketPath! }, sessionId, pendingCeiling };
140
214
  }
141
215
 
@@ -143,14 +217,32 @@ function parseServeArguments(argv: string[]): ServeArguments {
143
217
  export function resolveServePendingCeiling(flagValue: string | undefined, envValue: string | undefined): number {
144
218
  const value = flagValue ?? envValue;
145
219
  if (value === undefined) return DEFAULT_PENDING_CEILING_BYTES;
146
- if (!/^\d+$/.test(value)) usageError("--pending-ceiling must be a positive integer");
220
+ if (!/^\d+$/.test(value)) usageError("usage_invalid_option_value");
147
221
  const ceiling = Number(value);
148
- if (!Number.isSafeInteger(ceiling) || ceiling < MIN_PENDING_CEILING_BYTES)
149
- usageError(`--pending-ceiling must be an integer of at least ${MIN_PENDING_CEILING_BYTES}`);
222
+ if (!Number.isSafeInteger(ceiling) || ceiling < MIN_PENDING_CEILING_BYTES) usageError("usage_invalid_option_value");
150
223
  return ceiling;
151
224
  }
152
225
 
153
- type BrokerSessionRow = { sessionId: string; live: boolean; ambiguous: boolean };
226
+ type BrokerTranscriptIdentity = {
227
+ dev: string;
228
+ ino: string;
229
+ size: number;
230
+ mtimeMs: number;
231
+ mtimeNs: string;
232
+ sha256: string;
233
+ };
234
+ type BrokerSavedSession = { id: string; path: string; identity: BrokerTranscriptIdentity };
235
+ type BrokerSessionLocator = { cwd: string; worktreeRoot: string | null; stateRoot: string };
236
+ type BrokerSessionRow = {
237
+ sessionId: string;
238
+ live: boolean;
239
+ ambiguous: boolean;
240
+ terminal?: boolean;
241
+ hostUnregisteredReason?: "process_exited" | "detached_idle";
242
+ terminalUncertain?: boolean;
243
+ locator?: BrokerSessionLocator;
244
+ savedSession?: BrokerSavedSession;
245
+ };
154
246
 
155
247
  function isRecord(value: unknown): value is Record<string, unknown> {
156
248
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -167,54 +259,277 @@ function brokerResult(value: unknown): Record<string, unknown> {
167
259
  return isRecord(value) && isRecord(value.result) ? value.result : {};
168
260
  }
169
261
 
170
- function brokerSessionRows(sessions: readonly unknown[]): BrokerSessionRow[] {
262
+ function brokerSessionLocator(value: unknown): BrokerSessionLocator | undefined {
263
+ if (!isRecord(value)) return undefined;
264
+ const { cwd, worktreeRoot, stateRoot } = value;
265
+ return typeof cwd === "string" &&
266
+ cwd.length > 0 &&
267
+ (worktreeRoot === null || typeof worktreeRoot === "string") &&
268
+ typeof stateRoot === "string" &&
269
+ stateRoot.length > 0
270
+ ? { cwd, worktreeRoot, stateRoot }
271
+ : undefined;
272
+ }
273
+
274
+ function brokerSavedSession(value: unknown): BrokerSavedSession | undefined {
275
+ if (!isRecord(value) || typeof value.id !== "string" || !value.id || typeof value.path !== "string" || !value.path)
276
+ return undefined;
277
+ if (!isRecord(value.identity)) return undefined;
278
+ const { dev, ino, size, mtimeMs, mtimeNs, sha256 } = value.identity;
279
+ if (
280
+ typeof dev !== "string" ||
281
+ !/^[0-9]+$/.test(dev) ||
282
+ typeof ino !== "string" ||
283
+ !/^[0-9]+$/.test(ino) ||
284
+ typeof size !== "number" ||
285
+ !Number.isSafeInteger(size) ||
286
+ size < 0 ||
287
+ typeof mtimeMs !== "number" ||
288
+ !Number.isFinite(mtimeMs) ||
289
+ mtimeMs < 0 ||
290
+ typeof mtimeNs !== "string" ||
291
+ !/^[0-9]+$/.test(mtimeNs) ||
292
+ typeof sha256 !== "string" ||
293
+ !/^[a-f0-9]{64}$/.test(sha256)
294
+ )
295
+ return undefined;
296
+ return { id: value.id, path: value.path, identity: { dev, ino, size, mtimeMs, mtimeNs, sha256 } };
297
+ }
298
+
299
+ function brokerSessionRows(sessions: readonly unknown[], savedSession?: unknown): BrokerSessionRow[] {
300
+ const pageSavedSession = brokerSavedSession(savedSession);
171
301
  return sessions.flatMap(item => {
172
302
  if (!isRecord(item) || typeof item.sessionId !== "string" || !item.sessionId) return [];
173
- return [{ sessionId: item.sessionId, live: item.live === true, ambiguous: item.ambiguous === true }];
303
+ const locator = brokerSessionLocator(item.locator);
304
+ const saved = pageSavedSession?.id === item.sessionId ? pageSavedSession : brokerSavedSession(item.savedSession);
305
+ const hostUnregisteredReason =
306
+ item.hostUnregisteredReason === "process_exited" || item.hostUnregisteredReason === "detached_idle"
307
+ ? item.hostUnregisteredReason
308
+ : undefined;
309
+ const terminalUncertain = item.terminalUncertain === true || item.terminal_uncertain === true;
310
+ return [
311
+ {
312
+ sessionId: item.sessionId,
313
+ live: item.live === true,
314
+ ambiguous: item.ambiguous === true,
315
+ ...(item.terminal === true ? { terminal: true } : {}),
316
+ ...(hostUnregisteredReason === undefined ? {} : { hostUnregisteredReason }),
317
+ ...(terminalUncertain ? { terminalUncertain: true } : {}),
318
+ ...(locator === undefined ? {} : { locator }),
319
+ ...(saved === undefined ? {} : { savedSession: saved }),
320
+ },
321
+ ];
174
322
  });
175
323
  }
176
324
 
177
325
  /** Exhausts strict broker `session.list` pages into one full session snapshot. */
178
- export async function listBrokerSessions(broker: SdkClient, explicitSessionId?: string): Promise<BrokerSessionRow[]> {
326
+ export async function listBrokerSessions(
327
+ broker: Pick<SdkClient, "global">,
328
+ explicitSessionId?: string,
329
+ cwd?: string,
330
+ ): Promise<BrokerSessionRow[]> {
179
331
  try {
180
332
  const pages = await traverseSessionList(
181
- { ...(explicitSessionId ? { resolveSessionId: explicitSessionId } : {}) },
333
+ {
334
+ ...(explicitSessionId ? { resolveSessionId: explicitSessionId } : {}),
335
+ ...(cwd === undefined ? {} : { cwd }),
336
+ },
182
337
  async input => await broker.global("session.list", input),
183
338
  response => {
184
339
  brokerResult(response);
185
340
  return sessionListPageFromResponse(response);
186
341
  },
187
342
  );
188
- return pages.flatMap(page => brokerSessionRows(page.sessions));
343
+ return pages.flatMap(page =>
344
+ brokerSessionRows(page.sessions, isRecord(page.page) ? page.page.savedSession : undefined),
345
+ );
189
346
  } catch (error) {
190
347
  if (error instanceof SessionListTraversalError) throw new SdkClientError("protocol_error", error.message);
191
348
  throw error;
192
349
  }
193
350
  }
194
351
 
352
+ function endpointStaleError(sessionId: string): Error {
353
+ // A typed error, because `toServeError` only passes `SdkServeError` through: a plain
354
+ // Error here is rewritten to `serve_failed`, which hides the one code that tells a
355
+ // caller recovery was attempted and the endpoint is still not live.
356
+ return new SdkServeError("endpoint_stale", `session ${sessionId} endpoint is not live`, 1);
357
+ }
358
+
359
+ async function recoverBrokerSession(broker: SdkClient, row: BrokerSessionRow, sessionId: string): Promise<void> {
360
+ const locator = row.locator;
361
+ const authority =
362
+ row.savedSession?.id === sessionId
363
+ ? row.savedSession
364
+ : locator === undefined
365
+ ? undefined
366
+ : (await listBrokerSessions(broker, sessionId, locator.cwd)).find(
367
+ candidate => candidate.sessionId === sessionId,
368
+ )?.savedSession;
369
+ if (locator === undefined || authority?.id !== sessionId) throw endpointStaleError(sessionId);
370
+ const normalized = normalizeBrokerInput("session.resume", { sessionId, cwd: locator.cwd });
371
+ if (!("input" in normalized)) {
372
+ brokerResult(normalized);
373
+ throw endpointStaleError(sessionId);
374
+ }
375
+ const input = {
376
+ ...normalized.input,
377
+ sessionPath: authority.path,
378
+ sessionIdentity: authority.identity,
379
+ };
380
+ const timeoutMs = lifecycleRequestTimeoutMs("session.resume", input);
381
+ brokerResult(
382
+ await broker.global("session.resume", input, {
383
+ idempotencyKey: crypto.randomUUID(),
384
+ ...(timeoutMs === undefined ? {} : { timeoutMs }),
385
+ }),
386
+ );
387
+ }
388
+
389
+ /** Resolves an explicit or automatic serve target, reattaching one stale explicit session at most once. */
390
+ export async function resolveServeSession(broker: SdkClient, explicitSessionId?: string): Promise<string> {
391
+ const sessions = await listBrokerSessions(broker, explicitSessionId);
392
+ if (explicitSessionId !== undefined) {
393
+ const row = sessions.find(session => session.sessionId === explicitSessionId);
394
+ // An indexed, unambiguous row that is not live is the recoverable
395
+ // self-reap case (#5633). Every other targeting outcome — unindexed,
396
+ // ambiguous, no explicit id — stays the selector's to report, so this
397
+ // decision does not depend on the selector's error text.
398
+ // Recovery requires durable retirement provenance. A non-live row without a terminal
399
+ // retirement event may only have stale heartbeat evidence, which does not prove that the
400
+ // previous host exited and must not authorize a second host for the same transcript.
401
+ if (
402
+ row !== undefined &&
403
+ !row.ambiguous &&
404
+ !row.terminalUncertain &&
405
+ !row.live &&
406
+ row.terminal === true &&
407
+ (row.hostUnregisteredReason === "process_exited" || row.hostUnregisteredReason === "detached_idle")
408
+ ) {
409
+ await recoverBrokerSession(broker, row, explicitSessionId);
410
+ return selectBrokerSession(await listBrokerSessions(broker, explicitSessionId), explicitSessionId);
411
+ }
412
+ }
413
+ return selectBrokerSession(sessions, explicitSessionId);
414
+ }
415
+
195
416
  /** Selects the session to serve through broker `session.list` truth (C10); exported for tests. */
196
417
  export function selectBrokerSession(sessions: BrokerSessionRow[], explicitSessionId: string | undefined): string {
197
418
  if (explicitSessionId !== undefined) {
198
419
  const row = sessions.find(session => session.sessionId === explicitSessionId);
199
420
  if (!row) throw new SdkServeError("not_found", `session ${explicitSessionId} is not indexed by the broker`, 1);
200
421
  if (row.ambiguous) throw new SdkServeError("ambiguous_session", "session id maps to more than one state root", 1);
422
+ if (row.terminalUncertain)
423
+ throw new SdkServeError("terminal_uncertain", `session ${explicitSessionId} ownership is uncertain`, 1);
201
424
  if (!row.live) throw new SdkServeError("endpoint_stale", `session ${explicitSessionId} endpoint is not live`, 1);
202
425
  return row.sessionId;
203
426
  }
204
- const live = sessions.filter(session => session.live && !session.ambiguous);
427
+ const live = sessions.filter(session => session.live && !session.ambiguous && !session.terminalUncertain);
205
428
  if (live.length === 0) throw new SdkServeError("no_live_endpoint", "no live session endpoint", 1);
206
429
  if (live.length > 1)
207
430
  throw new SdkServeError("multiple_live_endpoints", "more than one live session; specify --session <id>", 1);
208
431
  return live[0]!.sessionId;
209
432
  }
210
433
 
434
+ /** Only SDK-owned error codes carry classification authority at preflight. */
435
+ function servePreflightFailure(error: unknown): PublicCommandFailure {
436
+ if (!(error instanceof SdkClientError)) return normalizePublicCommandFailure(error);
437
+ switch (error.code) {
438
+ case "broker_restarting":
439
+ return new PublicCommandFailure({ kind: "broker_restarting", proof: "pre-effect" });
440
+ case "broker_unavailable":
441
+ return new PublicCommandFailure({ kind: "broker_unavailable", proof: "pre-effect" });
442
+ case "endpoint_stale":
443
+ return new PublicCommandFailure({ kind: "endpoint_stale", proof: "pre-effect" });
444
+ case "authorization_denied":
445
+ case "unauthorized":
446
+ case "forbidden":
447
+ case "master_context_required":
448
+ case "adapter_operation_prohibited":
449
+ case "endpoint_credential_forbidden":
450
+ return new PublicCommandFailure({ kind: "authorization_denied", proof: "pre-effect" });
451
+ case "timeout":
452
+ return new PublicCommandFailure({ kind: "timeout", proof: "unknown" });
453
+ case "unavailable":
454
+ return new PublicCommandFailure({ kind: "unavailable", proof: "unknown" });
455
+ case "uncertain_after_send":
456
+ return new PublicCommandFailure({ kind: "uncertain_after_send", proof: "sent" });
457
+ default:
458
+ return normalizePublicCommandFailure(error);
459
+ }
460
+ }
461
+
462
+ /** Bounded dependency seam for preflight tests; production keeps the same transport factories. */
463
+ export interface SdkServeDependencies {
464
+ readDiscovery: (agentDir: string) => Promise<{ url: string; token: string } | null>;
465
+ connect: (url: string, token: string) => Promise<Pick<SdkClient, "global" | "close">>;
466
+ startStdio: typeof startStdioServe;
467
+ startSocket: typeof startSocketServe;
468
+ }
469
+
211
470
  /**
212
471
  * Attaches a stdio or Unix-socket relay to one live SDK session endpoint.
213
472
  * Session targeting is broker-bound (C10): `session.list` resolves the session
214
473
  * and `session.get_endpoint` mints the exact credential — never a direct
215
474
  * endpoint-file read. A missing or unreachable broker fails closed.
216
475
  */
217
- export async function runSdkServe(argv: string[]): Promise<void> {
476
+ export async function runSdkServe(argv: string[], dependencies?: SdkServeDependencies): Promise<void> {
477
+ if (dependencies !== undefined) {
478
+ await runSdkServePublic(argv, dependencies);
479
+ return;
480
+ }
481
+ await runSdkServeTyped(argv);
482
+ }
483
+
484
+ /** Public-boundary adapter used by dependency-injected preflight tests and the CLI scanner. */
485
+ async function runSdkServePublic(argv: string[], dependencies: SdkServeDependencies): Promise<void> {
486
+ let broker: Pick<SdkClient, "global" | "close"> | undefined;
487
+ let transport: ServeHandle | undefined;
488
+ try {
489
+ const parsed = parseServeArguments(argv);
490
+ if (parsed.mode.kind === "socket" && process.platform === "win32")
491
+ throw new PublicCommandFailure({ kind: "unavailable", proof: "pre-effect" });
492
+ const pendingCeilingBytes = resolveServePendingCeiling(
493
+ parsed.pendingCeiling,
494
+ process.env.GJC_SDK_SERVE_PENDING_CEILING_BYTES,
495
+ );
496
+ const discovery = await dependencies.readDiscovery(getAgentDir());
497
+ if (!discovery) throw new PublicCommandFailure({ kind: "broker_unavailable", proof: "pre-effect" });
498
+ try {
499
+ broker = await dependencies.connect(discovery.url, discovery.token);
500
+ } catch (error) {
501
+ if (error instanceof SdkClientError || error instanceof PublicCommandFailure) throw error;
502
+ throw new PublicCommandFailure({ kind: "broker_unavailable", proof: "pre-effect" });
503
+ }
504
+ const sessionId = selectBrokerSession(await listBrokerSessions(broker, parsed.sessionId), parsed.sessionId);
505
+ const endpoint = brokerResult(await broker.global("session.get_endpoint", { sessionId }));
506
+ const url = typeof endpoint.url === "string" && endpoint.url ? endpoint.url : undefined;
507
+ const token = typeof endpoint.token === "string" ? endpoint.token : "";
508
+ // An endpoint without its minted credential cannot authenticate any relayed
509
+ // client, so starting the listener would advertise a serve that always fails.
510
+ if (!url || !token) throw new PublicCommandFailure({ kind: "unavailable", proof: "pre-effect" });
511
+ const options = { url, token, pendingCeilingBytes };
512
+ transport =
513
+ parsed.mode.kind === "stdio"
514
+ ? await dependencies.startStdio(options)
515
+ : await dependencies.startSocket({ ...options, socketPath: parsed.mode.socketPath });
516
+ } catch (error) {
517
+ // No transport handle has transferred ownership. Cleanup diagnostics are
518
+ // attached to the original failure instance, never substituted for it, and
519
+ // broker credentials never reach a raw error.
520
+ const failure = servePreflightFailure(error);
521
+ try {
522
+ await broker?.close();
523
+ } catch {
524
+ failure.input.diagnostics = [...(failure.input.diagnostics ?? []), "broker_cleanup_failed"];
525
+ }
526
+ throw failure;
527
+ }
528
+ await ownSdkServeTransport(transport!, () => broker!.close());
529
+ }
530
+
531
+ /** Native serve path: operational failures remain typed for direct SDK embedders. */
532
+ async function runSdkServeTyped(argv: string[]): Promise<void> {
218
533
  const parsed = parseServeArguments(argv);
219
534
  if (parsed.mode.kind === "socket" && process.platform === "win32")
220
535
  throw new SdkServeError("unsupported_platform", "--socket is unavailable on Windows.", 1);
@@ -231,8 +546,9 @@ export async function runSdkServe(argv: string[]): Promise<void> {
231
546
  throw new SdkServeError("broker_unavailable", "SDK broker is not reachable", 1);
232
547
  }
233
548
  let primary: Error | undefined;
549
+ let transport: ServeHandle | undefined;
234
550
  try {
235
- const sessionId = selectBrokerSession(await listBrokerSessions(broker, parsed.sessionId), parsed.sessionId);
551
+ const sessionId = await resolveServeSession(broker, parsed.sessionId);
236
552
  const endpoint = brokerResult(await broker.global("session.get_endpoint", { sessionId }));
237
553
  const url = typeof endpoint.url === "string" && endpoint.url ? endpoint.url : undefined;
238
554
  const token = typeof endpoint.token === "string" && endpoint.token ? endpoint.token : undefined;
@@ -241,26 +557,65 @@ export async function runSdkServe(argv: string[]): Promise<void> {
241
557
  // connection failure and this stable malformed-endpoint code is lost.
242
558
  if (!url || !token) throw new SdkServeError("unavailable", "broker returned an invalid endpoint record", 1);
243
559
  const options = { url, token, pendingCeilingBytes };
244
- const handle =
560
+ transport =
245
561
  parsed.mode.kind === "stdio"
246
562
  ? await startStdioServe(options)
247
563
  : await startSocketServe({ ...options, socketPath: parsed.mode.socketPath });
248
- const stop = () => {
249
- void handle.close();
250
- };
251
- process.once("SIGINT", stop);
252
- process.once("SIGTERM", stop);
253
- try {
254
- await handle.done;
255
- } finally {
256
- process.removeListener("SIGINT", stop);
257
- process.removeListener("SIGTERM", stop);
258
- }
259
564
  } catch (error) {
260
565
  primary = toServeError(error);
261
566
  }
567
+ if (transport) {
568
+ // Once the relay owns stdout, post-start failures must never cross back into
569
+ // the public command renderer. That boundary writes JSON to stdout, which is
570
+ // the stdio frame channel; the transport owner reports only a fixed stderr
571
+ // diagnostic and exit status instead.
572
+ await ownSdkServeTransport(transport, () => broker.close());
573
+ return;
574
+ }
262
575
  // Teardown always runs, but never through a `finally` throw: a rejected
263
- // `broker.close()` there would replace the typed failure with its own.
576
+ // broker.close() there would replace the typed failure with its own.
264
577
  const failure = resolveServeOutcome(primary, await brokerCloseFailure(broker));
265
578
  if (failure) throw failure;
266
579
  }
580
+
581
+ /**
582
+ * Acquiring a ServeHandle transfers output/termination ownership to transport.
583
+ * This boundary never rejects into the ordinary public command writer, even
584
+ * when no frame has been written. Raw relay framing remains transport-owned.
585
+ */
586
+ export async function ownSdkServeTransport(handle: ServeHandle, closeBroker: () => Promise<void>): Promise<void> {
587
+ let failed = false;
588
+ const reportFailure = (): void => {
589
+ process.exitCode = 1;
590
+ if (failed) return;
591
+ failed = true;
592
+ try {
593
+ process.stderr.write(`${JSON.stringify({ type: "transport_error", code: "serve_failed" })}\n`);
594
+ } catch {
595
+ // A broken diagnostic stream cannot transfer ownership back to the CLI.
596
+ }
597
+ };
598
+ const stop = (): void => {
599
+ void handle.close().catch(reportFailure);
600
+ };
601
+ try {
602
+ process.once("SIGINT", stop);
603
+ process.once("SIGTERM", stop);
604
+ await handle.done;
605
+ } catch {
606
+ reportFailure();
607
+ } finally {
608
+ process.removeListener("SIGINT", stop);
609
+ process.removeListener("SIGTERM", stop);
610
+ try {
611
+ await handle.close();
612
+ } catch {
613
+ reportFailure();
614
+ }
615
+ try {
616
+ await closeBroker();
617
+ } catch {
618
+ reportFailure();
619
+ }
620
+ }
621
+ }
@@ -177,20 +177,21 @@ export async function startSocketServe(
177
177
  void task;
178
178
  });
179
179
  server.on("error", error => void close(error).catch(() => undefined));
180
- await new Promise<void>((resolve, reject) => {
181
- server?.once("error", reject);
182
- server?.listen(options.socketPath, () => resolve());
183
- });
184
- const bound = await fs.lstat(options.socketPath);
185
- if (!bound.isSocket()) {
186
- await close();
187
- throw socketFailure("socket_bind_failed");
188
- }
189
- ownedIdentity = { dev: bound.dev, ino: bound.ino };
190
180
  try {
181
+ await new Promise<void>((resolve, reject) => {
182
+ server?.once("error", reject);
183
+ server?.listen(options.socketPath, () => resolve());
184
+ });
185
+ const bound = await fs.lstat(options.socketPath);
186
+ if (!bound.isSocket()) throw socketFailure("socket_bind_failed");
187
+ ownedIdentity = { dev: bound.dev, ino: bound.ino };
191
188
  await fs.chmod(options.socketPath, 0o600);
192
189
  } catch (error) {
193
- await close();
190
+ try {
191
+ await close();
192
+ } catch (cleanupError) {
193
+ throw new AggregateError([error, cleanupError], "socket_serve_startup_cleanup_failed", { cause: error });
194
+ }
194
195
  throw error;
195
196
  }
196
197
  return { close, done: done.promise };
@@ -1,3 +1,4 @@
1
+ import type { Readable, Writable } from "node:stream";
1
2
  import type { ServeHandle, ServeOptions } from "./index";
2
3
  import { startRelayPair } from "./relay";
3
4
 
@@ -6,11 +7,14 @@ function writeDiagnostic(value: unknown): void {
6
7
  }
7
8
 
8
9
  /** Serves one parent-owned JSONL connection over the process standard streams. */
9
- export async function startStdioServe(options: ServeOptions): Promise<ServeHandle> {
10
+ export async function startStdioServe(
11
+ options: ServeOptions,
12
+ streams: { readonly input?: Readable; readonly output?: Writable } = {},
13
+ ): Promise<ServeHandle> {
10
14
  const pair = await startRelayPair({
11
15
  ...options,
12
- downstream: process.stdin,
13
- downstreamSink: process.stdout,
16
+ downstream: streams.input ?? process.stdin,
17
+ downstreamSink: streams.output ?? process.stdout,
14
18
  onTransportError: writeDiagnostic,
15
19
  });
16
20
  return { close: pair.close, done: pair.done };