@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,5 +1,6 @@
1
1
  import { createHash, randomUUID } from "node:crypto";
2
- import type { Stats } from "node:fs";
2
+ import { constants as fsConstants, type Stats } from "node:fs";
3
+ import type { FileHandle } from "node:fs/promises";
3
4
  import * as fs from "node:fs/promises";
4
5
  import * as path from "node:path";
5
6
  import { type FileLockOptions, withFileLock } from "../config/file-lock";
@@ -114,6 +115,12 @@ export function guardedStateWriteReceipt(result: GuardedWriteResult): GuardedSta
114
115
 
115
116
  export interface StateWriterOptions {
116
117
  cwd?: string;
118
+ /**
119
+ * Linux-only private durable source publication. The supplied directory is
120
+ * the exact private subtree containing the target; existing paths are never
121
+ * chmodded or repaired.
122
+ */
123
+ privateDurable?: { directory: string };
117
124
  receipt?: StateWriterReceiptContext;
118
125
  audit?: StateWriterAuditContext;
119
126
  sourceRevision?: number;
@@ -149,6 +156,16 @@ export interface DeleteIfOwnedOptions extends StateWriterOptions {
149
156
  predicate?: (current: unknown) => boolean | Promise<boolean>;
150
157
  }
151
158
 
159
+ export class StatePublicationUncertainError extends Error {
160
+ constructor(
161
+ public readonly path: string,
162
+ public readonly cause: unknown,
163
+ ) {
164
+ super(`state publication requires authoritative reload: ${path}`);
165
+ this.name = "StatePublicationUncertainError";
166
+ }
167
+ }
168
+
152
169
  export interface DeleteResult {
153
170
  path: string;
154
171
  deleted: boolean;
@@ -528,13 +545,293 @@ async function atomicWrite(filePath: string, content: string): Promise<string> {
528
545
  return filePath;
529
546
  }
530
547
 
548
+ function currentUid(): number {
549
+ const uid = process.getuid?.();
550
+ if (uid === undefined) throw new Error("private durable publication requires a POSIX uid");
551
+ return uid;
552
+ }
553
+
554
+ interface PrivatePublicationDirectory {
555
+ handle: FileHandle;
556
+ parent?: PrivatePublicationDirectory;
557
+ name?: string;
558
+ dev: number;
559
+ ino: number;
560
+ privateSubtree: boolean;
561
+ }
562
+
563
+ interface PrivatePublicationContext {
564
+ root: string;
565
+ directories: PrivatePublicationDirectory[];
566
+ targetParent: PrivatePublicationDirectory;
567
+ anchoredTarget: string;
568
+ }
569
+
570
+ function assertSafePublicationDirectory(stat: Stats, directory: string, privateSubtree: boolean): void {
571
+ if (!stat.isDirectory() || stat.isSymbolicLink()) throw new Error("unsafe publication directory");
572
+ if ((stat.mode & 0o022) !== 0 || stat.uid !== currentUid()) {
573
+ const mode = (stat.mode & 0o777).toString(8);
574
+ throw new Error(
575
+ `publication parent is not exclusively owned (uid=${stat.uid}, mode=${mode}, directory=${path.basename(directory)})`,
576
+ );
577
+ }
578
+ if (privateSubtree && (stat.mode & 0o777) !== 0o700)
579
+ throw new Error("private publication directory is not owned mode 0700");
580
+ }
581
+
582
+ function procPath(handle: FileHandle): string {
583
+ return `/proc/self/fd/${handle.fd}`;
584
+ }
585
+
586
+ function directoryPath(directory: PrivatePublicationDirectory): string {
587
+ return procPath(directory.handle);
588
+ }
589
+
590
+ const LINUX_O_PATH = 0o10000000;
591
+
592
+ async function readPrivateExistingStateForMutation(filePath: string): Promise<StrictMutationReadResult> {
593
+ let handle: FileHandle | undefined;
594
+ try {
595
+ handle = await fs.open(filePath, fsConstants.O_RDONLY | fsConstants.O_NOFOLLOW | fsConstants.O_NONBLOCK);
596
+ const stat = await handle.stat();
597
+ if (!stat.isFile() || stat.nlink !== 1 || (stat.mode & 0o777) !== 0o600 || stat.uid !== currentUid())
598
+ throw new Error("unsafe private publication file");
599
+ const parsed = JSON.parse(await handle.readFile("utf-8"));
600
+ if (isPlainObject(parsed)) return { kind: "valid", value: parsed };
601
+ return { kind: "corrupt", error: "state file must contain a JSON object" };
602
+ } catch (error) {
603
+ if (isErrno(error, "ENOENT")) return { kind: "absent" };
604
+ return { kind: "corrupt", error: error instanceof Error ? error.message : String(error) };
605
+ } finally {
606
+ await handle?.close();
607
+ }
608
+ }
609
+
610
+ async function assertPrivatePublicationDirectories(context: PrivatePublicationContext): Promise<void> {
611
+ for (const expected of context.directories) {
612
+ const current = await expected.handle.stat();
613
+ const directory =
614
+ expected.parent && expected.name ? path.join(directoryPath(expected.parent), expected.name) : context.root;
615
+ assertSafePublicationDirectory(current, directory, expected.privateSubtree);
616
+ if (current.dev !== expected.dev || current.ino !== expected.ino)
617
+ throw new Error("private publication directory changed during publication");
618
+ if (expected.parent && expected.name) {
619
+ const linked = await fs.lstat(path.join(directoryPath(expected.parent), expected.name));
620
+ if (
621
+ !linked.isDirectory() ||
622
+ linked.isSymbolicLink() ||
623
+ linked.dev !== expected.dev ||
624
+ linked.ino !== expected.ino
625
+ )
626
+ throw new Error("private publication directory changed during publication");
627
+ }
628
+ }
629
+ const namedRoot = await fs.lstat(context.root);
630
+ const root = context.directories[0];
631
+ if (
632
+ !root ||
633
+ !namedRoot.isDirectory() ||
634
+ namedRoot.isSymbolicLink() ||
635
+ namedRoot.dev !== root.dev ||
636
+ namedRoot.ino !== root.ino
637
+ )
638
+ throw new Error("private publication root changed during publication");
639
+ }
640
+
641
+ async function closePrivatePublicationContext(context: PrivatePublicationContext): Promise<void> {
642
+ await Promise.all(
643
+ context.directories
644
+ .splice(0)
645
+ .reverse()
646
+ .map(directory => directory.handle.close()),
647
+ );
648
+ }
649
+
650
+ async function preparePrivateDirectory(
651
+ filePath: string,
652
+ options: StateWriterOptions,
653
+ ): Promise<PrivatePublicationContext> {
654
+ if (process.platform !== "linux") throw new Error("private durable publication requires Linux");
655
+ const boundary = resolveGjcTarget(options.privateDurable!.directory, cwdForOptions(options));
656
+ if (boundary !== path.dirname(filePath)) throw new Error("private publication directory must be the target parent");
657
+ const root = cwdForOptions(options);
658
+ if ((await fs.realpath(root)) !== root) throw new Error("private publication requires canonical cwd");
659
+ const directories: PrivatePublicationDirectory[] = [];
660
+ const openFlags = fsConstants.O_RDONLY | fsConstants.O_DIRECTORY | fsConstants.O_NOFOLLOW;
661
+ try {
662
+ const rootHandle = await fs.open(root, openFlags);
663
+ let rootStat: Stats;
664
+ try {
665
+ rootStat = await rootHandle.stat();
666
+ } catch (error) {
667
+ await rootHandle.close();
668
+ throw error;
669
+ }
670
+ directories.push({
671
+ handle: rootHandle,
672
+ dev: rootStat.dev,
673
+ ino: rootStat.ino,
674
+ privateSubtree: false,
675
+ });
676
+ assertSafePublicationDirectory(rootStat, root, false);
677
+ const namedRoot = await fs.lstat(root);
678
+ if (namedRoot.isSymbolicLink() || namedRoot.dev !== rootStat.dev || namedRoot.ino !== rootStat.ino)
679
+ throw new Error("private publication root changed during publication");
680
+
681
+ let parent = directories[0];
682
+ if (!parent) throw new Error("private publication root was not opened");
683
+ let directory = root;
684
+ for (const segment of path.relative(root, path.dirname(filePath)).split(path.sep)) {
685
+ const childPath = path.join(directoryPath(parent), segment);
686
+ directory = path.join(directory, segment);
687
+ let created = false;
688
+ try {
689
+ await fs.mkdir(childPath, { mode: 0o700 });
690
+ created = true;
691
+ } catch (error) {
692
+ if (!isErrno(error, "EEXIST")) throw error;
693
+ }
694
+ let createdIdentity: { dev: number; ino: number } | undefined;
695
+ if (created) {
696
+ const pathHandle = await fs.open(
697
+ childPath,
698
+ LINUX_O_PATH | fsConstants.O_DIRECTORY | fsConstants.O_NOFOLLOW,
699
+ );
700
+ try {
701
+ const beforeChmod = await pathHandle.stat();
702
+ if (!beforeChmod.isDirectory() || beforeChmod.uid !== currentUid() || (beforeChmod.mode & 0o022) !== 0)
703
+ throw new Error("unsafe newly created private publication directory");
704
+ await fs.chmod(procPath(pathHandle), 0o700);
705
+ const afterChmod = await pathHandle.stat();
706
+ if ((afterChmod.mode & 0o777) !== 0o700)
707
+ throw new Error("private publication directory is not owned mode 0700");
708
+ createdIdentity = { dev: afterChmod.dev, ino: afterChmod.ino };
709
+ } finally {
710
+ await pathHandle.close();
711
+ }
712
+ }
713
+ const childHandle = await fs.open(childPath, openFlags);
714
+ let childStat: Stats;
715
+ try {
716
+ childStat = await childHandle.stat();
717
+ } catch (error) {
718
+ await childHandle.close();
719
+ throw error;
720
+ }
721
+ if (createdIdentity && (childStat.dev !== createdIdentity.dev || childStat.ino !== createdIdentity.ino)) {
722
+ await childHandle.close();
723
+ throw new Error("private publication directory changed during creation");
724
+ }
725
+ const privateSubtree = directory === boundary || directory.startsWith(`${boundary}${path.sep}`);
726
+ const child: PrivatePublicationDirectory = {
727
+ handle: childHandle,
728
+ parent,
729
+ name: segment,
730
+ dev: childStat.dev,
731
+ ino: childStat.ino,
732
+ privateSubtree,
733
+ };
734
+ directories.push(child);
735
+ assertSafePublicationDirectory(childStat, directory, privateSubtree);
736
+ if (created || directory === boundary) {
737
+ // The newly linked entry is durable only after both the child and its
738
+ // parent have been synced. Newly created directories are chmodded first
739
+ // so umask cannot weaken their required mode.
740
+ await childHandle.sync();
741
+ await parent.handle.sync();
742
+ }
743
+ parent = child;
744
+ }
745
+ const targetParent = directories[directories.length - 1];
746
+ if (!targetParent) throw new Error("private publication target parent was not opened");
747
+ const context: PrivatePublicationContext = {
748
+ root,
749
+ directories,
750
+ targetParent,
751
+ anchoredTarget: path.join(directoryPath(targetParent), path.basename(filePath)),
752
+ };
753
+ await assertPrivatePublicationDirectories(context);
754
+ try {
755
+ const stat = await fs.lstat(context.anchoredTarget);
756
+ if (
757
+ !stat.isFile() ||
758
+ stat.isSymbolicLink() ||
759
+ stat.nlink !== 1 ||
760
+ (stat.mode & 0o777) !== 0o600 ||
761
+ stat.uid !== currentUid()
762
+ )
763
+ throw new Error("unsafe private publication file");
764
+ } catch (error) {
765
+ if (!isErrno(error, "ENOENT")) throw error;
766
+ }
767
+ return context;
768
+ } catch (error) {
769
+ await Promise.all(directories.reverse().map(directory => directory.handle.close().catch(() => undefined)));
770
+ throw error;
771
+ }
772
+ }
773
+
774
+ async function privateAtomicWrite(
775
+ filePath: string,
776
+ content: string,
777
+ options: StateWriterOptions,
778
+ context: PrivatePublicationContext,
779
+ ): Promise<void> {
780
+ await assertPrivatePublicationDirectories(context);
781
+ const temporary = tempPathFor(filePath);
782
+ const anchoredTemporary = path.join(directoryPath(context.targetParent), path.basename(temporary));
783
+ let renameAttempted = false;
784
+ try {
785
+ const handle = await fs.open(anchoredTemporary, "wx", 0o600);
786
+ try {
787
+ await handle.chmod(0o600);
788
+ const created = await handle.stat();
789
+ if (!created.isFile() || created.uid !== currentUid() || (created.mode & 0o777) !== 0o600)
790
+ throw new Error("unsafe private publication temporary file");
791
+ await handle.writeFile(content, "utf8");
792
+ await handle.sync();
793
+ } finally {
794
+ await handle.close();
795
+ }
796
+ await assertPrivatePublicationDirectories(context);
797
+ renameAttempted = true;
798
+ await fs.rename(anchoredTemporary, context.anchoredTarget);
799
+ await context.targetParent.handle.sync();
800
+ await assertPrivatePublicationDirectories(context);
801
+ await maybeAudit(filePath, options);
802
+ } catch (error) {
803
+ // A rename call or anything after it can have committed the replacement
804
+ // before returning an error. The caller must reload instead of retrying
805
+ // with a new authority record.
806
+ if (renameAttempted) throw new StatePublicationUncertainError(filePath, error);
807
+ await fs.rm(anchoredTemporary, { force: true }).catch(() => undefined);
808
+ throw error;
809
+ }
810
+ }
811
+
531
812
  async function writeGuardedResolvedJsonAtomic(
532
813
  filePath: string,
533
814
  value: unknown,
534
815
  options: GuardedStateWriterOptions,
535
816
  ): Promise<GuardedWriteResult> {
817
+ let privateContext: PrivatePublicationContext | undefined;
818
+ if (options.privateDurable) {
819
+ if (options.policy !== "source" || options.expectedRevision === undefined)
820
+ throw new Error("private durable publication requires source CAS");
821
+ privateContext = await preparePrivateDirectory(filePath, options);
822
+ }
536
823
  const write = async (): Promise<GuardedWriteResult> => {
537
- const current = await readJsonIfPresentTolerant(filePath);
824
+ if (privateContext) await assertPrivatePublicationDirectories(privateContext);
825
+ const strict = privateContext
826
+ ? await readPrivateExistingStateForMutation(privateContext.anchoredTarget)
827
+ : undefined;
828
+ if (strict?.kind === "corrupt") throw new Error(strict.error);
829
+ if (strict?.kind === "absent" && options.expectedRevision !== 0) throw new Error("established state missing");
830
+ const current = strict
831
+ ? strict.kind === "valid"
832
+ ? strict.value
833
+ : undefined
834
+ : await readJsonIfPresentTolerant(filePath);
538
835
  const currentRevision = persistedStateRevision(current);
539
836
 
540
837
  if (options.policy === "source") {
@@ -542,8 +839,13 @@ async function writeGuardedResolvedJsonAtomic(
542
839
  throw new StateWriteConflictError(filePath, options.expectedRevision, currentRevision);
543
840
  }
544
841
  const next = stampStateRevision(withWorkflowReceipt(value, buildReceipt(options)), currentRevision + 1);
545
- await atomicWrite(filePath, jsonText(next));
546
- await maybeAudit(filePath, options);
842
+ if (options.privateDurable) {
843
+ if (!privateContext) throw new Error("private publication directories were not prepared");
844
+ await privateAtomicWrite(filePath, jsonText(next), options, privateContext);
845
+ } else {
846
+ await atomicWrite(filePath, jsonText(next));
847
+ await maybeAudit(filePath, options);
848
+ }
547
849
  return { path: filePath, written: true, revision: currentRevision + 1, stamped: next };
548
850
  }
549
851
 
@@ -567,7 +869,11 @@ async function writeGuardedResolvedJsonAtomic(
567
869
  // that already holds this target's lock (via `withWorkflowStateLock`) must say
568
870
  // so rather than deadlocking against itself — the same `lockHeld` contract the
569
871
  // envelope writers already use.
570
- return options.lockHeld ? write() : lockResolvedWorkflowTarget(filePath, write, options.lock);
872
+ try {
873
+ return options.lockHeld ? await write() : await lockResolvedWorkflowTarget(filePath, write, options.lock);
874
+ } finally {
875
+ if (privateContext) await closePrivatePublicationContext(privateContext);
876
+ }
571
877
  }
572
878
 
573
879
  export async function writeGuardedJsonAtomic(
@@ -798,7 +1104,12 @@ export async function withWorkflowStateLock<T>(
798
1104
  options?: StateWriterOptions,
799
1105
  ): Promise<T> {
800
1106
  const filePath = resolveGjcTarget(targetPath, cwdForOptions(options));
801
- return lockResolvedWorkflowTarget(filePath, fn, options?.lock);
1107
+ const privateContext = options?.privateDurable ? await preparePrivateDirectory(filePath, options) : undefined;
1108
+ try {
1109
+ return await lockResolvedWorkflowTarget(filePath, fn, options?.lock);
1110
+ } finally {
1111
+ if (privateContext) await closePrivatePublicationContext(privateContext);
1112
+ }
802
1113
  }
803
1114
 
804
1115
  async function lockResolvedWorkflowTarget<T>(
@@ -382,6 +382,26 @@ function repositoryIdentity(binding: RepositoryBinding): Record<string, unknown>
382
382
  };
383
383
  }
384
384
 
385
+ /**
386
+ * Self-transfer guards are narrower than repository identity guards: linked
387
+ * worktrees share a common dir but carry independent `.gjc` state, so they are
388
+ * valid succession peers. `captureRepositoryBinding` records a realpath for
389
+ * active roots, but persisted plan bindings are operator-controlled and may
390
+ * contain a symlink alias.
391
+ * Resolve both roots through the filesystem before comparing them; a failed
392
+ * resolution is a refusal, never a fallback to lexical path comparison.
393
+ */
394
+ async function canonicalWorktreeRoot(binding: RepositoryBinding, side: "source" | "target"): Promise<string> {
395
+ try {
396
+ return await fs.realpath(binding.worktreeRoot);
397
+ } catch {
398
+ throw new UltragoalSuccessionError(
399
+ "unsafe_target",
400
+ `Cannot resolve the ${side} worktree root physically (${binding.worktreeRoot}); refusing succession.`,
401
+ );
402
+ }
403
+ }
404
+
385
405
  function successionOperationId(input: {
386
406
  sourceRepository: RepositoryBinding;
387
407
  sourceSessionId: string;
@@ -781,11 +801,15 @@ async function resolveTargetRepositoryBinding(
781
801
  throw new UltragoalSuccessionError("unsafe_target", `--target-repo is not a directory: ${raw}`);
782
802
  }
783
803
  const target = publicRepositoryBinding(await captureRepositoryBinding(resolved, { displayPath: resolved }));
784
- if (repositoryBindingsMatch(target, sourceBinding)) {
804
+ const [targetRoot, sourceRoot] = await Promise.all([
805
+ canonicalWorktreeRoot(target, "target"),
806
+ canonicalWorktreeRoot(sourceBinding, "source"),
807
+ ]);
808
+ if (targetRoot === sourceRoot) {
785
809
  throw new UltragoalSuccessionError(
786
810
  "unsafe_target",
787
811
  `--target-repo resolves to the source repository itself (${target.worktreeRoot}). ` +
788
- "Succession moves work across repositories; it is not a rebind of the original run.",
812
+ "Succession requires a distinct worktree or repository; it is not a rebind of the original run.",
789
813
  );
790
814
  }
791
815
  return target;
@@ -1277,7 +1301,11 @@ export async function adoptUltragoalSuccession(
1277
1301
  "adoption is pinned to the exact worktree the offer named.",
1278
1302
  );
1279
1303
  }
1280
- if (repositoryBindingsMatch(targetActual, sourceRepository)) {
1304
+ const [targetRoot, sourceRoot] = await Promise.all([
1305
+ canonicalWorktreeRoot(targetActual, "target"),
1306
+ canonicalWorktreeRoot(sourceRepository, "source"),
1307
+ ]);
1308
+ if (targetRoot === sourceRoot) {
1281
1309
  throw new UltragoalSuccessionError(
1282
1310
  "unsafe_target",
1283
1311
  "Refusing to adopt a succession offer into its own source repository.",
@@ -20,7 +20,11 @@ export interface EndpointRequest {
20
20
  input: Record<string, unknown>;
21
21
  }
22
22
 
23
- export type EndpointHandler = (req: EndpointRequest) => Promise<unknown>;
23
+ export interface EndpointHandlerRequest extends EndpointRequest {
24
+ signal: AbortSignal;
25
+ }
26
+
27
+ export type EndpointHandler = (req: EndpointHandlerRequest) => Promise<unknown>;
24
28
 
25
29
  function frame(value: unknown): string {
26
30
  return `${JSON.stringify(value)}\n`;
@@ -54,6 +58,14 @@ export class ControlServer {
54
58
  socket.setEncoding("utf8");
55
59
  let buffer = "";
56
60
  let handled = false;
61
+ let responseSent = false;
62
+ const controller = new AbortController();
63
+ socket.once("close", () => {
64
+ if (!responseSent) controller.abort(new Error("endpoint_client_disconnected"));
65
+ });
66
+ socket.on("error", () => {
67
+ if (!responseSent) controller.abort(new Error("endpoint_client_disconnected"));
68
+ });
57
69
  socket.on("data", (chunk: string) => {
58
70
  if (handled) return;
59
71
  buffer += chunk;
@@ -61,20 +73,26 @@ export class ControlServer {
61
73
  if (idx < 0) return;
62
74
  handled = true;
63
75
  const line = buffer.slice(0, idx).trim();
64
- void this.#dispatch(line)
76
+ void this.#dispatch(line, controller.signal)
65
77
  .then(response => {
66
- socket.end(frame(response));
78
+ if (!socket.destroyed && !controller.signal.aborted) {
79
+ responseSent = true;
80
+ socket.end(frame(response));
81
+ }
67
82
  })
68
83
  .catch((error: unknown) => {
69
- socket.end(frame({ ok: false, error: error instanceof Error ? error.message : String(error) }));
84
+ if (!socket.destroyed && !controller.signal.aborted) {
85
+ responseSent = true;
86
+ socket.end(frame({ ok: false, error: error instanceof Error ? error.message : String(error) }));
87
+ }
70
88
  });
71
89
  });
72
90
  }
73
91
 
74
- async #dispatch(line: string): Promise<unknown> {
92
+ async #dispatch(line: string, signal: AbortSignal): Promise<unknown> {
75
93
  const req = JSON.parse(line) as EndpointRequest;
76
94
  if (!req || typeof req.verb !== "string") throw new Error("bad_request");
77
- return this.handler({ verb: req.verb, input: req.input ?? {} });
95
+ return this.handler({ verb: req.verb, input: req.input ?? {}, signal });
78
96
  }
79
97
 
80
98
  async close(): Promise<void> {