@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
@@ -26,7 +26,12 @@ import {
26
26
  import { isAuthenticated, kNoAuth } from "../../config/model-registry";
27
27
  import { resolveModelChainWithAuth, splitSelectorThinkingSuffix } from "../../config/model-resolver";
28
28
  import { type ModelSelectorValue, normalizeModelSelectorValue } from "../../config/model-selector-value";
29
- import { type Settings, validateSettingPatch } from "../../config/settings";
29
+ import {
30
+ resolveSdkPromptDeadlineMs,
31
+ resolveSdkPromptMaxRuntimeMs,
32
+ type Settings,
33
+ validateSettingPatch,
34
+ } from "../../config/settings";
30
35
  import type { ExtensionAPI, ExtensionCommandContext, ExtensionContext } from "../../extensibility/extensions";
31
36
  import type { AgentEndEvent } from "../../extensibility/shared-events";
32
37
  import { normalizeGoal } from "../../goals/state";
@@ -59,6 +64,7 @@ import {
59
64
  syntheticNamespaceCollision,
60
65
  } from "../model-profile-model";
61
66
  import { projectQ10Models } from "../models.js";
67
+ import { flushWorktreeOnPromptDeadline } from "../prompt-deadline-flush";
62
68
  import { PromptDeadlineManager, type PromptTerminalTransitionEvidence } from "../prompt-deadline-manager";
63
69
  import {
64
70
  assistantFailureCode,
@@ -92,7 +98,12 @@ import {
92
98
  BROKER_RUNTIME_CLOSE_CAPABILITY_FIELD,
93
99
  hasBrokerRuntimeAbortCapability,
94
100
  } from "./control/runtime-gate";
95
- import { SessionSdkHost, type SessionSdkHostOptions } from "./host";
101
+ import {
102
+ SESSION_HOST_OBSERVER_CAPABILITY,
103
+ SessionSdkHost,
104
+ type SessionSdkHostOptions,
105
+ TURN_STREAM_CAPABILITY,
106
+ } from "./host";
96
107
  import { clearAutoroutingInactive, isAutoroutingInactive, markAutoroutingInactive } from "./internal-autorouting-state";
97
108
  import { CursorRegistry, QueryHandlers, RevisionStore, type SessionSurface } from "./query";
98
109
  import { createSdkRunCapability } from "./sdk-run-capability";
@@ -196,6 +207,13 @@ export function verifyMasterCapabilityFrame(input: {
196
207
 
197
208
  /** Maximum time a replaced runtime may retain a lifecycle persistence task. */
198
209
  const LIFECYCLE_QUIESCENCE_MS = 1_000;
210
+ /**
211
+ * Keep a live session's broker discovery recoverable well inside the session
212
+ * index's two-minute heartbeat freshness window. `ensureBroker` has its own
213
+ * bounded startup/recovery budget; the in-flight guard below prevents those
214
+ * budgets from stacking when one attempt outlives this cadence.
215
+ */
216
+ export const SESSION_BROKER_RECOVERY_INTERVAL_MS = 30_000;
199
217
 
200
218
  class DiffQueryError extends Error {
201
219
  constructor(
@@ -357,6 +375,17 @@ export interface SdkOnlyTerminalAbortSeams {
357
375
  terminal?: { scope: "turn" | "owned"; expectedEpoch?: number; steeringSnapshotToken?: number };
358
376
  },
359
377
  ) => Promise<{ status: string; terminalScope?: unknown }>;
378
+ /**
379
+ * Live, SYNCHRONOUS view of the dispatched tool calls the run resource
380
+ * ledger holds for an execution handle (#5637). Strictly read-only: it
381
+ * never claims, reserves, seals or quarantines ledger state. Declared here
382
+ * so both hosts expose ONE seam contract — the bus route consumes it for its
383
+ * deadline tool-boundary wait, and this route threads it so a future boundary
384
+ * wait or deadline abort reads the ledger rather than silently falling back
385
+ * to the event-derived set. Optional so an older host that does not thread it
386
+ * degrades to that fallback instead of failing to construct.
387
+ */
388
+ pendingToolExecutions?: (handle: string) => readonly string[];
360
389
  /** Test override for the maximum durable terminal reservation rows. */
361
390
  maxDurableTerminalReservationsForTests?: number;
362
391
  }
@@ -372,6 +401,9 @@ export interface SdkOnlyTerminalAbortSeams {
372
401
  export class SessionSdkSessionRuntime {
373
402
  readonly host: SessionSdkHost;
374
403
  readonly transport: SessionSdkTransport;
404
+ readonly #connectionCapabilities = new Map<string, ReadonlySet<string>>();
405
+ readonly #connectionIds = new Set<string>();
406
+ readonly #connectionCapabilitiesProvider: (connectionId: string) => ReadonlySet<string> | undefined;
375
407
  readonly #connectionDisposer?: () => void;
376
408
  readonly #malformedDisposer?: () => void;
377
409
  readonly #capabilitiesDisposer?: () => void;
@@ -380,10 +412,11 @@ export class SessionSdkSessionRuntime {
380
412
 
381
413
  constructor(options: SessionSdkRuntimeOptions) {
382
414
  this.transport = options.transport;
383
- const capabilities = new Map<string, ReadonlySet<string>>();
415
+ this.#connectionCapabilitiesProvider =
416
+ options.connectionCapabilities ?? (connectionId => this.#connectionCapabilities.get(connectionId));
384
417
  this.host = new SessionSdkHost({
385
418
  ...options,
386
- connectionCapabilities: options.connectionCapabilities ?? (connectionId => capabilities.get(connectionId)),
419
+ connectionCapabilities: this.#connectionCapabilitiesProvider,
387
420
  sessionId: options.transport.sessionId,
388
421
  stateRoot: options.transport.stateRoot,
389
422
  token: options.transport.token,
@@ -392,14 +425,21 @@ export class SessionSdkSessionRuntime {
392
425
  if (result instanceof Promise) return result.then(outcome => outcome ?? "written");
393
426
  return result ?? "written";
394
427
  },
395
- onFrame: options.transport.onFrame,
428
+ onFrame: handler =>
429
+ options.transport.onFrame((connectionId, frame) => {
430
+ this.#connectionIds.add(connectionId);
431
+ handler(connectionId, frame);
432
+ }),
396
433
  });
397
434
  this.#connectionDisposer = options.transport.onConnectionClose?.(connectionId => {
398
- capabilities.delete(connectionId);
435
+ this.#connectionIds.delete(connectionId);
436
+ this.#connectionCapabilities.delete(connectionId);
399
437
  this.host.handleDisconnect(connectionId);
400
438
  });
401
439
  this.#capabilitiesDisposer = options.transport.onNegotiatedCapabilities?.((connectionId, negotiated) => {
402
- capabilities.set(connectionId, new Set(negotiated));
440
+ if (options.connectionCapabilities && this.#connectionCapabilitiesProvider(connectionId) === undefined) return;
441
+ this.#connectionIds.add(connectionId);
442
+ this.#connectionCapabilities.set(connectionId, new Set(negotiated));
403
443
  });
404
444
  this.#malformedDisposer = options.transport.onMalformedFrame?.((connectionId, message) => {
405
445
  this.host.handleMalformedFrame(connectionId, message);
@@ -418,6 +458,11 @@ export class SessionSdkSessionRuntime {
418
458
  return this.host.getProviderDefinitions(capability);
419
459
  }
420
460
 
461
+ /** Persist the host's current observable activity for broker/session-list consumers. */
462
+ async reportActivity(state: "active" | "idle", at = Date.now()): Promise<void> {
463
+ await this.host.reportActivity(state, at);
464
+ }
465
+
421
466
  emitEvent(frame: SdkFrame): void {
422
467
  const eventInput =
423
468
  typeof frame.kind === "string"
@@ -447,6 +492,27 @@ export class SessionSdkSessionRuntime {
447
492
  }
448
493
  }
449
494
 
495
+ /** Snapshot connections that negotiated every capability in the requirement set. */
496
+ connectionIdsWithCapabilities(required: readonly string[]): string[] {
497
+ return [...this.#connectionIds].flatMap(connectionId => {
498
+ const capabilities = this.#connectionCapabilitiesProvider(connectionId);
499
+ return capabilities !== undefined && required.every(capability => capabilities.has(capability))
500
+ ? [connectionId]
501
+ : [];
502
+ });
503
+ }
504
+ /** Deliver a non-replayable frame to connections with an explicit capability intersection. */
505
+ sendFrameToCapabilities(
506
+ required: readonly string[],
507
+ frame: SdkFrame,
508
+ excluding: ReadonlySet<string> = new Set(),
509
+ ): void {
510
+ for (const connectionId of this.connectionIdsWithCapabilities(required)) {
511
+ if (excluding.has(connectionId)) continue;
512
+ this.sendFrameTo(connectionId, frame);
513
+ }
514
+ }
515
+
450
516
  publish(frame: SdkFrame): void {
451
517
  this.emitEvent(frame);
452
518
  }
@@ -500,7 +566,7 @@ export class SessionSdkSessionRuntime {
500
566
  }
501
567
  }
502
568
 
503
- async stop(options: { allowLockContention?: boolean } = {}): Promise<void> {
569
+ async stop(options: { allowLockContention?: boolean; unregisterReason?: "detached_idle" } = {}): Promise<void> {
504
570
  this.#connectionDisposer?.();
505
571
  this.#capabilitiesDisposer?.();
506
572
  this.#malformedDisposer?.();
@@ -558,6 +624,11 @@ export interface CreateSdkSessionRuntimeOptions {
558
624
  terminalAbortSeams?: SdkOnlyTerminalAbortSeams;
559
625
  /** Callback when a frame is admitted to the runtime (test harness). */
560
626
  onFrameAdmitted?: () => void;
627
+ /** Timer seams for deterministic broker-recovery lifecycle tests. */
628
+ setIntervalImpl?: typeof setInterval;
629
+ clearIntervalImpl?: typeof clearInterval;
630
+ /** Test-only broker ensure seam; production always uses the owner-fenced helper. */
631
+ ensureBrokerImpl?: typeof ensureBroker;
561
632
  /** Test-only observation of a genuinely timed-out lifecycle drain. */
562
633
  onLifecycleDrainTimeoutForTests?: () => void;
563
634
  /** Test-only observation of bounded failure-diagnostic deduplication state. */
@@ -1947,6 +2018,7 @@ function createQuerySurface(
1947
2018
  ...gate,
1948
2019
  id: `pending:${gate.gate_id}`,
1949
2020
  tag: "pending" as const,
2021
+ answer_recorded: false as const,
1950
2022
  })) ??
1951
2023
  []
1952
2024
  );
@@ -4167,6 +4239,7 @@ export function createSdkSessionRuntimeExtension(api: ExtensionAPI, options: Cre
4167
4239
  sdkRunToken: string;
4168
4240
  }>;
4169
4241
  registerBroker: () => Promise<void>;
4242
+ stopBrokerRecovery: () => void;
4170
4243
  quiesceInput: () => void;
4171
4244
  fenceGateResolutions: () => void;
4172
4245
  waitForGateResolutionQuiescence: () => Promise<void>;
@@ -4462,10 +4535,12 @@ export function createSdkSessionRuntimeExtension(api: ExtensionAPI, options: Cre
4462
4535
  return task;
4463
4536
  };
4464
4537
  /**
4465
- * Publish one content frame per owning invocation, each carrying its own
4466
- * correlation, so a shared run lets every submitter attribute the content to
4467
- * its own prompt. Content is best-effort and bypasses the lifecycle replay
4468
- * ring; the turn producing it is authoritative.
4538
+ * Publish one correlated content frame per owning invocation, plus one
4539
+ * unpositioned copy for connections that explicitly negotiated observer
4540
+ * streaming. A shared run therefore lets every submitter attribute the content
4541
+ * to its own prompt without exposing it to ordinary attached clients.
4542
+ * Content is best-effort and bypasses the lifecycle replay ring; the turn
4543
+ * producing it is authoritative.
4469
4544
  */
4470
4545
  const publishContentFrames = (
4471
4546
  current: RuntimeState,
@@ -4474,8 +4549,10 @@ export function createSdkSessionRuntimeExtension(api: ExtensionAPI, options: Cre
4474
4549
  ): void => {
4475
4550
  try {
4476
4551
  const payload = toAgentWireEventPayload(event);
4552
+ const delivered = new Set<string>();
4477
4553
  for (const invocation of invocations) {
4478
4554
  if (invocation.connectionId === undefined) continue;
4555
+ delivered.add(invocation.connectionId);
4479
4556
  current.runtime.sendFrameTo(invocation.connectionId, {
4480
4557
  type: "event",
4481
4558
  kind: event.type,
@@ -4483,6 +4560,14 @@ export function createSdkSessionRuntimeExtension(api: ExtensionAPI, options: Cre
4483
4560
  ...invocation.correlation,
4484
4561
  });
4485
4562
  }
4563
+ // A relay or dashboard can observe a turn submitted by another client. It
4564
+ // explicitly negotiates both the stream and observer capabilities, so give it
4565
+ // the same live content frames without inventing a submitter correlation.
4566
+ current.runtime.sendFrameToCapabilities(
4567
+ [TURN_STREAM_CAPABILITY, SESSION_HOST_OBSERVER_CAPABILITY],
4568
+ { type: "event", kind: event.type, payload },
4569
+ delivered,
4570
+ );
4486
4571
  } catch {
4487
4572
  // Streamed content is best-effort; the turn producing it is authoritative.
4488
4573
  }
@@ -5031,7 +5116,16 @@ export function createSdkSessionRuntimeExtension(api: ExtensionAPI, options: Cre
5031
5116
  };
5032
5117
  api.on("agent_start", (event, ctx) => {
5033
5118
  const owner = lifecycleStateForEvent(ctx, "agent_start", event.sdkRunToken);
5034
- return trackLifecycle(
5119
+ // The activity checkpoint is already fire-and-forget and does not depend on
5120
+ // the handler awaiting trackLifecycle, so it composes with #5683 unchanged.
5121
+ void (owner?.runtime ?? lifecycleStateForContext(ctx, "agent_start")?.runtime)
5122
+ ?.reportActivity("active")
5123
+ .catch(error => logger.warn(`sdk: active activity checkpoint failed: ${String(error)}`));
5124
+ // Interactive/skill turns must not wait on durable start persist. Keep
5125
+ // trackLifecycle so drain, persist-then-publish, content-hold release, and
5126
+ // shutdown still run; do not return that promise to the extension runner
5127
+ // (EXTENSION_HANDLER_TIMEOUT_MS would otherwise stall the prompt).
5128
+ void trackLifecycle(
5035
5129
  async () =>
5036
5130
  emitLifecycle(
5037
5131
  "agent_start",
@@ -5047,12 +5141,19 @@ export function createSdkSessionRuntimeExtension(api: ExtensionAPI, options: Cre
5047
5141
  event.sdkRunTokens,
5048
5142
  ),
5049
5143
  owner,
5050
- );
5144
+ ).catch(error => {
5145
+ logger.error("SDK agent_start lifecycle task failed", {
5146
+ error: sanitizePromptFailure(error),
5147
+ });
5148
+ });
5051
5149
  });
5052
5150
  api.on("agent_end", (event, ctx) => {
5053
5151
  const tokenBinding =
5054
5152
  typeof event.sdkRunToken === "string" ? lifecycleRunOwners.get(event.sdkRunToken) : undefined;
5055
5153
  const owner = tokenBinding?.state ?? lifecycleStateForEvent(ctx, "agent_end", event.sdkRunToken);
5154
+ void (owner?.runtime ?? lifecycleStateForContext(ctx, "agent_end")?.runtime)
5155
+ ?.reportActivity("idle")
5156
+ .catch(error => logger.warn(`sdk: idle activity checkpoint failed: ${String(error)}`));
5056
5157
  // Capture the oldest unmatched batch synchronously. A successor may start
5057
5158
  // while the failed diagnostic persists; that must not retarget the
5058
5159
  // predecessor's reason or terminal boundary to the successor invocation.
@@ -5218,10 +5319,10 @@ export function createSdkSessionRuntimeExtension(api: ExtensionAPI, options: Cre
5218
5319
  * the session and see the turn settle but never receive a single word of the
5219
5320
  * answer.
5220
5321
  *
5221
- * Scoped to the owning invocations of the batch that is actually running: a
5222
- * turn nobody submitted over the SDK (an ordinary terminal prompt, an
5223
- * autonomous continuation, cron, monitor) has no owner connection and streams
5224
- * nothing at all, so a session with no attached client pays one map lookup.
5322
+ * Correlated content is scoped to the owning invocations of the batch that is
5323
+ * actually running. Explicit observer connections additionally receive the
5324
+ * uncorrelated copy, including for agent-owned runs with no SDK submitter.
5325
+ * A session with no owner or eligible observer pays one capability-map lookup.
5225
5326
  */
5226
5327
  const STREAMED_TURN_EVENT_TYPES: ReadonlySet<string> = new Set([
5227
5328
  "message_update",
@@ -5234,6 +5335,10 @@ export function createSdkSessionRuntimeExtension(api: ExtensionAPI, options: Cre
5234
5335
  const current = lifecycleStateForContext(ctx, "agent_start");
5235
5336
  const activeInvocation = current?.activeInvocation;
5236
5337
  if (!current) return;
5338
+ const observerConnections = current.runtime.connectionIdsWithCapabilities([
5339
+ TURN_STREAM_CAPABILITY,
5340
+ SESSION_HOST_OBSERVER_CAPABILITY,
5341
+ ]);
5237
5342
  const batch = activeInvocation
5238
5343
  ? current.openLifecycleBatches.find(candidate =>
5239
5344
  candidate.invocations.some(
@@ -5248,7 +5353,7 @@ export function createSdkSessionRuntimeExtension(api: ExtensionAPI, options: Cre
5248
5353
  : current.lifecycleActive
5249
5354
  ? (current.attachedInvocations ?? [])
5250
5355
  : [];
5251
- if (invocations.length === 0) return;
5356
+ if (invocations.length === 0 && observerConnections.length === 0) return;
5252
5357
  // Content bypasses the lifecycle replay ring and must never interrupt its producer.
5253
5358
  if (!event || typeof event.type !== "string" || !STREAMED_TURN_EVENT_TYPES.has(event.type)) return;
5254
5359
  // emitLifecycle("agent_start") awaits durable persistence before it
@@ -5291,6 +5396,10 @@ export function createSdkSessionRuntimeExtension(api: ExtensionAPI, options: Cre
5291
5396
  typeof (error as { code?: unknown }).code === "string"
5292
5397
  ? (error as { code: string }).code
5293
5398
  : undefined;
5399
+ const brokerDiagnosticCode = (error: unknown): string => {
5400
+ const code = errorCode(error);
5401
+ return code !== undefined && /^[A-Za-z0-9_.-]{1,64}$/u.test(code) ? code : "unavailable";
5402
+ };
5294
5403
  const startRuntime = async (ctx: ExtensionContext): Promise<void> => {
5295
5404
  if (active) return;
5296
5405
  const sessionId = ctx.sessionManager.getSessionId();
@@ -5315,13 +5424,28 @@ export function createSdkSessionRuntimeExtension(api: ExtensionAPI, options: Cre
5315
5424
  await steerReconciliation.hydrateFromStore();
5316
5425
  const deadlineManager = new PromptDeadlineManager({
5317
5426
  reconciliation,
5318
- getLeaseMs: () => {
5319
- const v = options.settings?.get("sdk.promptDeadlineMs" as never) as number | undefined;
5320
- return typeof v === "number" && Number.isFinite(v) ? v : 1_800_000;
5321
- },
5322
- getMaxMs: () => {
5323
- const v = options.settings?.get("sdk.promptMaxRuntimeMs" as never) as number | undefined;
5324
- return typeof v === "number" && Number.isFinite(v) ? v : 21_600_000;
5427
+ getLeaseMs: () => resolveSdkPromptDeadlineMs(options.settings?.get("sdk.promptDeadlineMs" as never)),
5428
+ getMaxMs: () => resolveSdkPromptMaxRuntimeMs(options.settings?.get("sdk.promptMaxRuntimeMs" as never)),
5429
+ // Persist the agent's uncommitted work before the retirement below tears
5430
+ // the session down (#5583). Best effort by contract: failures are logged
5431
+ // inside the flush and the deadline outcome is unaffected.
5432
+ onDeadlineExceeded: async (_correlation, signal, isCurrent) => {
5433
+ if (options.settings?.get("sdk.flushWorktreeOnDeadline" as never) === false) return;
5434
+ // `has` is true only for a value the user actually wrote, so this
5435
+ // separates an explicit opt-in from the schema default. The flush only
5436
+ // honours the default inside a linked worktree the session owns.
5437
+ const configured = options.settings?.get("sdk.flushWorktreeOnDeadline" as never);
5438
+ const hasExplicitSetting =
5439
+ typeof options.settings?.has === "function"
5440
+ ? options.settings.has("sdk.flushWorktreeOnDeadline" as never)
5441
+ : configured === true;
5442
+ const explicitOptIn = hasExplicitSetting === true && configured === true;
5443
+ await flushWorktreeOnPromptDeadline(ctx.cwd, {
5444
+ agentDir: options.settings?.getAgentDir(),
5445
+ explicitOptIn,
5446
+ isCurrent,
5447
+ signal,
5448
+ });
5325
5449
  },
5326
5450
  onExpired: (correlation, deadlineOutcome) => {
5327
5451
  const owner = lifecycleOwnerHolder.state;
@@ -6025,83 +6149,168 @@ export function createSdkSessionRuntimeExtension(api: ExtensionAPI, options: Cre
6025
6149
  };
6026
6150
  let publishedEndpointUrl: string | undefined;
6027
6151
  let brokerRegistered = false;
6152
+ let brokerRegistrationInFlight: Promise<void> | undefined;
6153
+ let brokerRecoveryStopped = false;
6028
6154
  const registerBroker = async (): Promise<void> => {
6029
6155
  if (brokerRegistered) return;
6156
+ if (brokerRegistrationInFlight !== undefined) {
6157
+ await brokerRegistrationInFlight;
6158
+ return;
6159
+ }
6160
+ const registration = (async (): Promise<void> => {
6161
+ try {
6162
+ if (options.brokerRegistrationRequired && !options.lifecycleRequestId)
6163
+ throw new Error("Lifecycle broker registration requires a request identity.");
6164
+ await (options.ensureBrokerImpl ?? ensureBroker)({ agentDir: options.agentDir });
6165
+ if (brokerRecoveryStopped) return;
6166
+ const index = await new SessionIndex(options.agentDir).open();
6167
+ if (brokerRecoveryStopped) return;
6168
+ const locator = await resolveSessionLocator(ctx.cwd, stateRoot);
6169
+ const effectiveIncarnation = processIncarnation(process.pid);
6170
+ const direct = await reattestMasterSessionIdentity({
6171
+ index,
6172
+ locator,
6173
+ masterCapability: options.masterCapability,
6174
+ attestationEpoch: options.masterAttestationEpoch,
6175
+ ownerSessionId: options.masterOwnerSessionId,
6176
+ sessionId,
6177
+ pid: process.pid,
6178
+ processIncarnation: effectiveIncarnation,
6179
+ });
6180
+ if (brokerRecoveryStopped) return;
6181
+ let brokerRegistrationEvent: SessionIndexEvent | undefined;
6182
+ await runtime.registerWithBroker({
6183
+ register: async input => {
6184
+ if (publishedEndpointUrl === undefined)
6185
+ throw new Error("SDK transport endpoint was not published before broker registration.");
6186
+ const endpointPath = path.join(input.stateRoot, "sdk", `${input.sessionId}.json`);
6187
+ const file = await readEndpointFile(endpointPath);
6188
+ if (!file) throw new Error("SDK endpoint could not be read as a stable regular file.");
6189
+ const endpoint = JSON.parse(file.source) as Record<string, unknown>;
6190
+ if (
6191
+ endpoint.sessionId !== input.sessionId ||
6192
+ endpoint.pid !== process.pid ||
6193
+ endpoint.url !== publishedEndpointUrl ||
6194
+ endpoint.token !== transport.token
6195
+ )
6196
+ throw new Error("SDK endpoint did not match the published transport authority.");
6197
+ const endpointMtimeMs = file.mtimeMs;
6198
+ const endpointFileId = `${file.dev}:${file.ino}`;
6199
+ const masterRole = masterAttestationForEffectiveHost({
6200
+ masterCapability: options.masterCapability,
6201
+ attestationEpoch: options.masterAttestationEpoch,
6202
+ ownerSessionId: options.masterOwnerSessionId,
6203
+ sessionId: input.sessionId,
6204
+ pid: process.pid,
6205
+ processIncarnation: effectiveIncarnation,
6206
+ direct,
6207
+ });
6208
+ const published = await index.append({
6209
+ type: "host_registered",
6210
+ ...input,
6211
+ locator,
6212
+ pid: process.pid,
6213
+ endpointMtimeMs,
6214
+ endpointFileId,
6215
+ ...(options.lifecycleRequestId ? { lifecycleRequestId: options.lifecycleRequestId } : {}),
6216
+ ...(masterRole ? { masterRole } : {}),
6217
+ });
6218
+ brokerRegistrationEvent = published;
6219
+ if (brokerRecoveryStopped) {
6220
+ // Teardown may have run before append returned its ownership proof.
6221
+ await index.unregisterIfCurrent(published);
6222
+ if (brokerRegistrationEvent === published) brokerRegistrationEvent = undefined;
6223
+ }
6224
+ },
6225
+ heartbeat: async input => {
6226
+ // Heartbeat only ever speaks for the publication this host proved it
6227
+ // owns. A stale or foreign generation must not renew liveness.
6228
+ const expected = brokerRegistrationEvent;
6229
+ if (
6230
+ !expected ||
6231
+ expected.sessionId !== input.sessionId ||
6232
+ expected.endpointGeneration !== input.endpointGeneration ||
6233
+ path.resolve(expected.locator.stateRoot) !== path.resolve(input.stateRoot)
6234
+ )
6235
+ return;
6236
+ await index.append({
6237
+ type: "host_heartbeat",
6238
+ sessionId: expected.sessionId,
6239
+ locator: expected.locator,
6240
+ endpointGeneration: expected.endpointGeneration,
6241
+ pid: expected.pid,
6242
+ ...(expected.processIncarnation === undefined
6243
+ ? {}
6244
+ : { processIncarnation: expected.processIncarnation }),
6245
+ ...(expected.hostIncarnation === undefined
6246
+ ? {}
6247
+ : { hostIncarnation: expected.hostIncarnation }),
6248
+ ...(expected.masterRole === undefined ? {} : { masterRole: expected.masterRole }),
6249
+ activity: input.activity,
6250
+ ts: input.activity.at,
6251
+ });
6252
+ },
6253
+ unregister: async input => {
6254
+ const expected = brokerRegistrationEvent;
6255
+ if (
6256
+ !expected ||
6257
+ expected.sessionId !== input.sessionId ||
6258
+ expected.endpointGeneration !== input.endpointGeneration ||
6259
+ path.resolve(expected.locator.stateRoot) !== path.resolve(input.stateRoot)
6260
+ )
6261
+ return;
6262
+ // Use the successful publication's proof, never a teardown-time file read.
6263
+ await index.unregisterIfCurrent(expected, input.reason);
6264
+ if (brokerRegistrationEvent === expected) brokerRegistrationEvent = undefined;
6265
+ },
6266
+ });
6267
+ if (brokerRecoveryStopped) return;
6268
+ brokerRegistered = true;
6269
+ } catch (error) {
6270
+ if (options.brokerRegistrationRequired) throw error;
6271
+ logger.warn("sdk broker registration unavailable", { code: brokerDiagnosticCode(error) });
6272
+ }
6273
+ })();
6274
+ brokerRegistrationInFlight = registration;
6030
6275
  try {
6031
- if (options.brokerRegistrationRequired && !options.lifecycleRequestId)
6032
- throw new Error("Lifecycle broker registration requires a request identity.");
6033
- await ensureBroker({ agentDir: options.agentDir });
6034
- const index = await new SessionIndex(options.agentDir).open();
6035
- const locator = await resolveSessionLocator(ctx.cwd, stateRoot);
6036
- const effectiveIncarnation = processIncarnation(process.pid);
6037
- const direct = await reattestMasterSessionIdentity({
6038
- index,
6039
- locator,
6040
- masterCapability: options.masterCapability,
6041
- attestationEpoch: options.masterAttestationEpoch,
6042
- ownerSessionId: options.masterOwnerSessionId,
6043
- sessionId,
6044
- pid: process.pid,
6045
- processIncarnation: effectiveIncarnation,
6046
- });
6047
- let registration: SessionIndexEvent | undefined;
6048
- await runtime.registerWithBroker({
6049
- register: async input => {
6050
- if (publishedEndpointUrl === undefined)
6051
- throw new Error("SDK transport endpoint was not published before broker registration.");
6052
- const endpointPath = path.join(input.stateRoot, "sdk", `${input.sessionId}.json`);
6053
- const file = await readEndpointFile(endpointPath);
6054
- if (!file) throw new Error("SDK endpoint could not be read as a stable regular file.");
6055
- const endpoint = JSON.parse(file.source) as Record<string, unknown>;
6056
- if (
6057
- endpoint.sessionId !== input.sessionId ||
6058
- endpoint.pid !== process.pid ||
6059
- endpoint.url !== publishedEndpointUrl ||
6060
- endpoint.token !== transport.token
6061
- )
6062
- throw new Error("SDK endpoint did not match the published transport authority.");
6063
- const endpointMtimeMs = file.mtimeMs;
6064
- const endpointFileId = `${file.dev}:${file.ino}`;
6065
- const masterRole = masterAttestationForEffectiveHost({
6066
- masterCapability: options.masterCapability,
6067
- attestationEpoch: options.masterAttestationEpoch,
6068
- ownerSessionId: options.masterOwnerSessionId,
6069
- sessionId: input.sessionId,
6070
- pid: process.pid,
6071
- processIncarnation: effectiveIncarnation,
6072
- direct,
6073
- });
6074
- registration = await index.append({
6075
- type: "host_registered",
6076
- ...input,
6077
- locator,
6078
- pid: process.pid,
6079
- endpointMtimeMs,
6080
- endpointFileId,
6081
- ...(options.lifecycleRequestId ? { lifecycleRequestId: options.lifecycleRequestId } : {}),
6082
- ...(masterRole ? { masterRole } : {}),
6083
- });
6084
- },
6085
- unregister: async input => {
6086
- const expected = registration;
6087
- if (
6088
- !expected ||
6089
- expected.sessionId !== input.sessionId ||
6090
- expected.endpointGeneration !== input.endpointGeneration ||
6091
- path.resolve(expected.locator.stateRoot) !== path.resolve(input.stateRoot)
6092
- )
6093
- return;
6094
- // Use the successful publication's proof, never a teardown-time file read.
6095
- await index.unregisterIfCurrent(expected);
6096
- if (registration === expected) registration = undefined;
6097
- },
6098
- });
6099
- brokerRegistered = true;
6276
+ await registration;
6277
+ } finally {
6278
+ if (brokerRegistrationInFlight === registration) brokerRegistrationInFlight = undefined;
6279
+ }
6280
+ };
6281
+ let brokerRecoveryTimer: NodeJS.Timeout | undefined;
6282
+ let brokerRecoveryInFlight: Promise<void> | undefined;
6283
+ const runBrokerRecovery = async (): Promise<void> => {
6284
+ if (brokerRecoveryStopped || brokerRecoveryInFlight !== undefined) return;
6285
+ const recovery = (async (): Promise<void> => {
6286
+ if (brokerRecoveryStopped) return;
6287
+ if (brokerRegistered) await (options.ensureBrokerImpl ?? ensureBroker)({ agentDir: options.agentDir });
6288
+ else await registerBroker();
6289
+ })();
6290
+ brokerRecoveryInFlight = recovery;
6291
+ try {
6292
+ await recovery;
6100
6293
  } catch (error) {
6101
- if (options.brokerRegistrationRequired) throw error;
6102
- logger.warn(`sdk broker registration unavailable: ${String(error)}`);
6294
+ logger.warn("sdk broker recovery unavailable", { code: brokerDiagnosticCode(error) });
6295
+ } finally {
6296
+ if (brokerRecoveryInFlight === recovery) brokerRecoveryInFlight = undefined;
6103
6297
  }
6104
6298
  };
6299
+ const startBrokerRecovery = (): void => {
6300
+ if (brokerRecoveryStopped || brokerRecoveryTimer !== undefined) return;
6301
+ const timer = (options.setIntervalImpl ?? setInterval)(
6302
+ () => void runBrokerRecovery(),
6303
+ SESSION_BROKER_RECOVERY_INTERVAL_MS,
6304
+ ) as NodeJS.Timeout;
6305
+ brokerRecoveryTimer = timer;
6306
+ timer.unref?.();
6307
+ };
6308
+ const stopBrokerRecovery = (): void => {
6309
+ brokerRecoveryStopped = true;
6310
+ if (brokerRecoveryTimer === undefined) return;
6311
+ (options.clearIntervalImpl ?? clearInterval)(brokerRecoveryTimer);
6312
+ brokerRecoveryTimer = undefined;
6313
+ };
6105
6314
  const runtimeOwner: RuntimeState = {
6106
6315
  sessionId,
6107
6316
  sessionIdentity,
@@ -6114,6 +6323,7 @@ export function createSdkSessionRuntimeExtension(api: ExtensionAPI, options: Cre
6114
6323
  pending,
6115
6324
  openLifecycleBatches,
6116
6325
  registerBroker,
6326
+ stopBrokerRecovery,
6117
6327
  quiesceInput: () => {
6118
6328
  inputGate.quiescing = true;
6119
6329
  lifecycleOwnerHolder.quiescing = true;
@@ -6129,13 +6339,19 @@ export function createSdkSessionRuntimeExtension(api: ExtensionAPI, options: Cre
6129
6339
  failureDiagnosticCodes: new Map(),
6130
6340
  lifecycleTasks: new Set(),
6131
6341
  };
6342
+ // Capture the SDK turn that owns a headless workflow gate before it is
6343
+ // persisted. Q12 can then explain both sides of a stalled turn: the gate
6344
+ // identity and whether an answer was recorded for that originating turn.
6345
+ ctx.workflowGate?.setRuntimeTurnProvider?.(() => active?.activeInvocation?.correlation.turnId);
6132
6346
  lifecycleOwnerHolder.state = runtimeOwner;
6133
6347
  active = runtimeOwner;
6134
6348
  try {
6135
6349
  publishedEndpointUrl = (await runtime.start()).url;
6136
6350
  await registerBroker();
6351
+ if (!brokerRecoveryStopped) startBrokerRecovery();
6137
6352
  } catch (error) {
6138
6353
  active = undefined;
6354
+ stopBrokerRecovery();
6139
6355
  disposeGate?.();
6140
6356
  try {
6141
6357
  await runtime.stop();
@@ -6156,6 +6372,7 @@ export function createSdkSessionRuntimeExtension(api: ExtensionAPI, options: Cre
6156
6372
  pending,
6157
6373
  openLifecycleBatches,
6158
6374
  registerBroker,
6375
+ stopBrokerRecovery,
6159
6376
  quiesceInput: () => {
6160
6377
  inputGate.quiescing = true;
6161
6378
  lifecycleOwnerHolder.quiescing = true;
@@ -6180,7 +6397,7 @@ export function createSdkSessionRuntimeExtension(api: ExtensionAPI, options: Cre
6180
6397
  throw error;
6181
6398
  }
6182
6399
  };
6183
- const stopActive = async (cancelSkillRecovery = false): Promise<void> => {
6400
+ const stopActive = async (cancelSkillRecovery = false, unregisterReason?: "detached_idle"): Promise<void> => {
6184
6401
  const current = active;
6185
6402
  if (!current) return;
6186
6403
  if (cancelSkillRecovery) {
@@ -6189,6 +6406,7 @@ export function createSdkSessionRuntimeExtension(api: ExtensionAPI, options: Cre
6189
6406
  }
6190
6407
  activePromptOwnerHolder.connectionIds = undefined;
6191
6408
  activePromptOwnerHolder.lifecycleEpoch = undefined;
6409
+ current.stopBrokerRecovery();
6192
6410
  current.quiesceInput();
6193
6411
  current.fenceGateResolutions();
6194
6412
  try {
@@ -6237,7 +6455,10 @@ export function createSdkSessionRuntimeExtension(api: ExtensionAPI, options: Cre
6237
6455
  retiredLifecycleOwnerTimers.set(current, timer);
6238
6456
  } else current.deadlineManager.clearAll();
6239
6457
  current.disposeGate?.();
6240
- await current.runtime.stop({ allowLockContention: cancelSkillRecovery });
6458
+ await current.runtime.stop({
6459
+ allowLockContention: cancelSkillRecovery,
6460
+ ...(unregisterReason === undefined ? {} : { unregisterReason }),
6461
+ });
6241
6462
  } catch (error) {
6242
6463
  // Keep the immutable owner available for a retry when transport teardown
6243
6464
  // fails after quiescing. Clearing `active` before stop prevents a second
@@ -6260,7 +6481,7 @@ export function createSdkSessionRuntimeExtension(api: ExtensionAPI, options: Cre
6260
6481
  await stopActive();
6261
6482
  await startRuntime(ctx);
6262
6483
  });
6263
- api.on("session_shutdown", async () => {
6264
- await stopActive(true);
6484
+ api.on("session_shutdown", async event => {
6485
+ await stopActive(true, event.reason);
6265
6486
  });
6266
6487
  }