airaknit 1.1.2-rc.9

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 (440) hide show
  1. package/LICENSE +84 -0
  2. package/README.md +202 -0
  3. package/bin/airaknit +9 -0
  4. package/bin/airaknit-project +14 -0
  5. package/bin/kanna +9 -0
  6. package/dist/client/assets/CompactSummaryMessage-Yw0BDWEJ.js +1 -0
  7. package/dist/client/assets/ExitPlanModeMessage-DIdkQ4uF.js +1 -0
  8. package/dist/client/assets/LocalFilePreviewDialog-DQx2eiCc.js +3 -0
  9. package/dist/client/assets/LocalProjectsSection-C4xlWkgS.js +1 -0
  10. package/dist/client/assets/TextMessage-B5G39DEJ.js +1 -0
  11. package/dist/client/assets/UserMessage-CIkWk-0L.js +1 -0
  12. package/dist/client/assets/_basePickBy-CVrAFfnZ.js +1 -0
  13. package/dist/client/assets/_baseUniq-JL-aaF4P.js +1 -0
  14. package/dist/client/assets/arc-B07zg7ol.js +1 -0
  15. package/dist/client/assets/architecture-YZFGNWBL-PSLVJL3p.js +1 -0
  16. package/dist/client/assets/architectureDiagram-Q4EWVU46-DfWIF1G_.js +36 -0
  17. package/dist/client/assets/array-BGFCBI0e.js +1 -0
  18. package/dist/client/assets/blockDiagram-DXYQGD6D-CzwIeo_B.js +132 -0
  19. package/dist/client/assets/bundle-mjs-BDE2gWbQ.js +1 -0
  20. package/dist/client/assets/button-DO50qOGv.js +1 -0
  21. package/dist/client/assets/c4Diagram-AHTNJAMY-CR8DCQRE.js +10 -0
  22. package/dist/client/assets/channel-Dj-UUfaF.js +1 -0
  23. package/dist/client/assets/chunk-2KRD3SAO-dznP-cn8.js +1 -0
  24. package/dist/client/assets/chunk-336JU56O-Dqss5Vu6.js +2 -0
  25. package/dist/client/assets/chunk-426QAEUC-CEKis_0_.js +1 -0
  26. package/dist/client/assets/chunk-4BX2VUAB-BYOv0Gm1.js +1 -0
  27. package/dist/client/assets/chunk-4TB4RGXK-BxzubH5S.js +206 -0
  28. package/dist/client/assets/chunk-55IACEB6-BSlTj03a.js +1 -0
  29. package/dist/client/assets/chunk-5FUZZQ4R-9Au93Bi1.js +62 -0
  30. package/dist/client/assets/chunk-5PVQY5BW-BhksHFEZ.js +2 -0
  31. package/dist/client/assets/chunk-67CJDMHE-BFwhz-8t.js +1 -0
  32. package/dist/client/assets/chunk-7N4EOEYR-BDUPds87.js +1 -0
  33. package/dist/client/assets/chunk-AA7GKIK3-CEWTdyXO.js +1 -0
  34. package/dist/client/assets/chunk-BO2N2NFS-D0LvxnhU.js +103 -0
  35. package/dist/client/assets/chunk-BSJP7CBP-BNJnK6sq.js +1 -0
  36. package/dist/client/assets/chunk-Bj-mKKzh.js +1 -0
  37. package/dist/client/assets/chunk-CIAEETIT-CYhfoCeN.js +1 -0
  38. package/dist/client/assets/chunk-EDXVE4YY-C5ovJLc0.js +1 -0
  39. package/dist/client/assets/chunk-ENJZ2VHE-HOhYaeGr.js +10 -0
  40. package/dist/client/assets/chunk-FMBD7UC4-BLCiKcAQ.js +15 -0
  41. package/dist/client/assets/chunk-FOC6F5B3-B6GtY2ek.js +1 -0
  42. package/dist/client/assets/chunk-ICPOFSXX-DPoIZoC5.js +122 -0
  43. package/dist/client/assets/chunk-K5T4RW27-BsKN63rv.js +94 -0
  44. package/dist/client/assets/chunk-KGLVRYIC-BUGn9uuY.js +1 -0
  45. package/dist/client/assets/chunk-LIHQZDEY-DhaZyo03.js +1 -0
  46. package/dist/client/assets/chunk-ORNJ4GCN-DlpeeJyi.js +1 -0
  47. package/dist/client/assets/chunk-OYMX7WX6-Dc9q7aYA.js +231 -0
  48. package/dist/client/assets/chunk-QZHKN3VN-BEdrPoSb.js +1 -0
  49. package/dist/client/assets/chunk-U2HBQHQK-CIB3Bjjd.js +70 -0
  50. package/dist/client/assets/chunk-X2U36JSP-CtB-o8Yp.js +1 -0
  51. package/dist/client/assets/chunk-XPW4576I-C6iHhX_8.js +32 -0
  52. package/dist/client/assets/chunk-YZCP3GAM-CTmKr6ZH.js +1 -0
  53. package/dist/client/assets/chunk-ZZ45TVLE-BgU8A2RF.js +1 -0
  54. package/dist/client/assets/classDiagram-6PBFFD2Q-Bqk5e679.js +1 -0
  55. package/dist/client/assets/classDiagram-v2-HSJHXN6E-6pSaZOkC.js +1 -0
  56. package/dist/client/assets/client-BrKWI4CM.js +1 -0
  57. package/dist/client/assets/client-CGgNRU9w.js +1 -0
  58. package/dist/client/assets/client-DMSLRzg9.js +6 -0
  59. package/dist/client/assets/clone-DWcL7whJ.js +1 -0
  60. package/dist/client/assets/cose-bilkent-S5V4N54A-CrV5wsV_.js +1 -0
  61. package/dist/client/assets/cytoscape.esm--aLzKuep.js +321 -0
  62. package/dist/client/assets/dagre-CuRxWcrj.js +1 -0
  63. package/dist/client/assets/dagre-KV5264BT-BIDiVnkA.js +4 -0
  64. package/dist/client/assets/defaultLocale-CRZydyG6.js +1 -0
  65. package/dist/client/assets/diagram-5BDNPKRD-i1kjKRCB.js +10 -0
  66. package/dist/client/assets/diagram-G4DWMVQ6-9ZSLuhbl.js +24 -0
  67. package/dist/client/assets/diagram-MMDJMWI5-B4_CUjgv.js +43 -0
  68. package/dist/client/assets/diagram-TYMM5635-Ct5eTGS8.js +24 -0
  69. package/dist/client/assets/dist-CuB4kiSK.js +1 -0
  70. package/dist/client/assets/erDiagram-SMLLAGMA-Cy38ercc.js +85 -0
  71. package/dist/client/assets/flowDiagram-DWJPFMVM-CZKuYl0V.js +162 -0
  72. package/dist/client/assets/ganttDiagram-T4ZO3ILL-DLPjCh7a.js +292 -0
  73. package/dist/client/assets/gitGraph-7Q5UKJZL-DqbrtEp9.js +1 -0
  74. package/dist/client/assets/gitGraphDiagram-UUTBAWPF-BoRBkDhQ.js +106 -0
  75. package/dist/client/assets/graphlib-BcQ6qlQh.js +1 -0
  76. package/dist/client/assets/highlighted-body-OFNGDK62-BEpBVDTX.js +1 -0
  77. package/dist/client/assets/index-CetCiuqP.js +105 -0
  78. package/dist/client/assets/index-N29Mip7A.css +1 -0
  79. package/dist/client/assets/info-OMHHGYJF-D98DRBJX.js +1 -0
  80. package/dist/client/assets/infoDiagram-42DDH7IO-BAcdTWbt.js +2 -0
  81. package/dist/client/assets/init-B8gtcn7T.js +1 -0
  82. package/dist/client/assets/isArrayLikeObject-D8SJFmkN.js +1 -0
  83. package/dist/client/assets/isEmpty-BF3YX5Jk.js +1 -0
  84. package/dist/client/assets/ishikawaDiagram-UXIWVN3A-Ynu2VKdC.js +70 -0
  85. package/dist/client/assets/journeyDiagram-VCZTEJTY-BjfhQaN3.js +139 -0
  86. package/dist/client/assets/jsx-runtime-CyI9ICYU.js +1 -0
  87. package/dist/client/assets/kanban-definition-6JOO6SKY-JLXH9zUJ.js +89 -0
  88. package/dist/client/assets/katex-B94qP8b6.js +265 -0
  89. package/dist/client/assets/lib--QVjyxmL.js +29 -0
  90. package/dist/client/assets/lib-B6rgJiZ9.js +1 -0
  91. package/dist/client/assets/line-DCrYfLBn.js +1 -0
  92. package/dist/client/assets/linear-_4upLmeo.js +1 -0
  93. package/dist/client/assets/mermaid-GHXKKRXX-rwJHYUmW.js +1 -0
  94. package/dist/client/assets/mermaid-parser.core-KZinfW8o.js +4 -0
  95. package/dist/client/assets/mermaid.core-QqY9gSNe.js +11 -0
  96. package/dist/client/assets/mindmap-definition-QFDTVHPH-TWgHDAzp.js +96 -0
  97. package/dist/client/assets/ordinal-CCj7PWgZ.js +1 -0
  98. package/dist/client/assets/packet-4T2RLAQJ-DEvfkn3F.js +1 -0
  99. package/dist/client/assets/path-DZF-JdEe.js +1 -0
  100. package/dist/client/assets/pie-ZZUOXDRM-72e6WVjb.js +1 -0
  101. package/dist/client/assets/pieDiagram-DEJITSTG-Cl8PCsoj.js +30 -0
  102. package/dist/client/assets/preload-helper-rov5CBGT.js +1 -0
  103. package/dist/client/assets/pty-client-DZ27IS00.js +1 -0
  104. package/dist/client/assets/ptyInstancesStore-D9ag7SYd.js +1 -0
  105. package/dist/client/assets/quadrantDiagram-34T5L4WZ-CHyVGp9E.js +7 -0
  106. package/dist/client/assets/radar-PYXPWWZC-Cp7xd_EY.js +1 -0
  107. package/dist/client/assets/react-CClhXMB2.js +1 -0
  108. package/dist/client/assets/react-Dd6D81m0.js +1 -0
  109. package/dist/client/assets/react-dom--G6_6fQ_.js +1 -0
  110. package/dist/client/assets/requirementDiagram-MS252O5E-DaanG2iM.js +84 -0
  111. package/dist/client/assets/rough.esm-BsmKo2S5.js +1 -0
  112. package/dist/client/assets/sankeyDiagram-XADWPNL6-B_fhLY36.js +10 -0
  113. package/dist/client/assets/sequenceDiagram-FGHM5R23-C5FNrveI.js +157 -0
  114. package/dist/client/assets/src-DeTlMJAU.js +1 -0
  115. package/dist/client/assets/stateDiagram-FHFEXIEX-nTTcdjjQ.js +1 -0
  116. package/dist/client/assets/stateDiagram-v2-QKLJ7IA2-Dw0632j_.js +1 -0
  117. package/dist/client/assets/timeline-definition-GMOUNBTQ-DkQV1yP8.js +120 -0
  118. package/dist/client/assets/treeView-SZITEDCU-ZLIgC7_K.js +1 -0
  119. package/dist/client/assets/treemap-W4RFUUIX-BqaMbB6N.js +1 -0
  120. package/dist/client/assets/uiIdentityOverlay-Ba7GNj7m.js +1 -0
  121. package/dist/client/assets/vennDiagram-DHZGUBPP-DbZ2xgs6.js +34 -0
  122. package/dist/client/assets/wardley-RL74JXVD-DXQS8zf4.js +1 -0
  123. package/dist/client/assets/wardleyDiagram-NUSXRM2D-BzCJ6MAu.js +20 -0
  124. package/dist/client/assets/xychartDiagram-5P7HB3ND-BSlFecop.js +7 -0
  125. package/dist/client/favicon.png +0 -0
  126. package/dist/client/favicon.svg +15 -0
  127. package/dist/client/fonts/body-medium.woff2 +0 -0
  128. package/dist/client/fonts/body-regular-italic.woff2 +0 -0
  129. package/dist/client/fonts/body-regular.woff2 +0 -0
  130. package/dist/client/fonts/body-semibold.woff2 +0 -0
  131. package/dist/client/index.html +31 -0
  132. package/dist/client/manifest.webmanifest +12 -0
  133. package/dist/client/sw.js +32 -0
  134. package/package.json +122 -0
  135. package/src/nats/auth-callout/callout-config.test.ts +93 -0
  136. package/src/nats/auth-callout/callout-config.ts +109 -0
  137. package/src/nats/auth-callout/callout.integration.test.ts +332 -0
  138. package/src/nats/auth-callout/keys.ts +103 -0
  139. package/src/nats/auth-callout/responder.ts +241 -0
  140. package/src/nats/auth-callout/scope-policy.test.ts +159 -0
  141. package/src/nats/auth-callout/scope-policy.ts +210 -0
  142. package/src/nats/auth-callout/token.test.ts +163 -0
  143. package/src/nats/auth-callout/token.ts +157 -0
  144. package/src/nats/nats-daemon-callout.ts +194 -0
  145. package/src/nats/nats-daemon.test.ts +77 -0
  146. package/src/nats/nats-daemon.ts +50 -0
  147. package/src/nats/nats-token.test.ts +61 -0
  148. package/src/nats/nats-token.ts +59 -0
  149. package/src/runner/coordination-mcp-integration.test.ts +134 -0
  150. package/src/runner/nats-coordination-client.test.ts +49 -0
  151. package/src/runner/nats-coordination-client.ts +94 -0
  152. package/src/runner/runner-agent.test.ts +469 -0
  153. package/src/runner/runner-agent.ts +453 -0
  154. package/src/runner/runner-credential.test.ts +93 -0
  155. package/src/runner/runner-credential.ts +82 -0
  156. package/src/runner/runner-nats.test.ts +495 -0
  157. package/src/runner/runner-nats.ts +323 -0
  158. package/src/runner/runner-pair.test.ts +107 -0
  159. package/src/runner/runner-pair.ts +81 -0
  160. package/src/runner/runner.test.ts +135 -0
  161. package/src/runner/runner.ts +212 -0
  162. package/src/runner/turn-factories.test.ts +97 -0
  163. package/src/runner/turn-factories.ts +475 -0
  164. package/src/server/agent-config-journey.test.ts +106 -0
  165. package/src/server/agent.ts +8 -0
  166. package/src/server/auto-continue/auth-error-detector.ts +66 -0
  167. package/src/server/auto-continue/limit-detector.ts +194 -0
  168. package/src/server/bm25.test.ts +92 -0
  169. package/src/server/bm25.ts +101 -0
  170. package/src/server/chat-events-jetstream.test.ts +135 -0
  171. package/src/server/claude-harness.ts +360 -0
  172. package/src/server/claude-pty/agent-normalizers.ts +309 -0
  173. package/src/server/claude-pty/auth.test.ts +38 -0
  174. package/src/server/claude-pty/auth.ts +32 -0
  175. package/src/server/claude-pty/claude-session-registry.adapter.ts +81 -0
  176. package/src/server/claude-pty/claude-session-registry.test.ts +149 -0
  177. package/src/server/claude-pty/driver.test.ts +902 -0
  178. package/src/server/claude-pty/driver.ts +807 -0
  179. package/src/server/claude-pty/jsonl-path.adapter.ts +57 -0
  180. package/src/server/claude-pty/jsonl-path.test.ts +114 -0
  181. package/src/server/claude-pty/jsonl-to-event.test.ts +241 -0
  182. package/src/server/claude-pty/jsonl-to-event.ts +174 -0
  183. package/src/server/claude-pty/output-ring.test.ts +35 -0
  184. package/src/server/claude-pty/output-ring.ts +25 -0
  185. package/src/server/claude-pty/parity-matrix.test.ts +227 -0
  186. package/src/server/claude-pty/pid-registry.adapter.ts +135 -0
  187. package/src/server/claude-pty/pid-registry.test.ts +122 -0
  188. package/src/server/claude-pty/preflight/binary-fingerprint.adapter.ts +20 -0
  189. package/src/server/claude-pty/preflight/binary-fingerprint.test.ts +32 -0
  190. package/src/server/claude-pty/pty-instance-registry.test.ts +177 -0
  191. package/src/server/claude-pty/pty-instance-registry.ts +166 -0
  192. package/src/server/claude-pty/pty-memory-sampler.adapter.test.ts +103 -0
  193. package/src/server/claude-pty/pty-memory-sampler.adapter.ts +85 -0
  194. package/src/server/claude-pty/pty-process.adapter.ts +66 -0
  195. package/src/server/claude-pty/pty-process.test.ts +49 -0
  196. package/src/server/claude-pty/resolve-binary.adapter.ts +106 -0
  197. package/src/server/claude-pty/resolve-binary.test.ts +118 -0
  198. package/src/server/claude-pty/runtime-dir.adapter.ts +19 -0
  199. package/src/server/claude-pty/settings-writer.adapter.ts +27 -0
  200. package/src/server/claude-pty/settings-writer.test.ts +22 -0
  201. package/src/server/claude-pty/smoke-test-io.adapter.ts +28 -0
  202. package/src/server/claude-pty/smoke-test.test.ts +191 -0
  203. package/src/server/claude-pty/smoke-test.ts +185 -0
  204. package/src/server/claude-pty/subagent-orchestrator.ts +887 -0
  205. package/src/server/claude-pty/tool-callback.ts +274 -0
  206. package/src/server/claude-pty/tui-control.test.ts +272 -0
  207. package/src/server/claude-pty/tui-control.ts +182 -0
  208. package/src/server/claude-pty/tui-source.adapter.test.ts +360 -0
  209. package/src/server/claude-pty/tui-source.adapter.ts +343 -0
  210. package/src/server/claude-pty/tunnel-gateway.ts +12 -0
  211. package/src/server/claude-pty-mcp/canonical-args.ts +15 -0
  212. package/src/server/claude-pty-mcp/fs-stat.adapter.ts +8 -0
  213. package/src/server/claude-pty-mcp/history-primer.ts +90 -0
  214. package/src/server/claude-pty-mcp/http-server.adapter.ts +33 -0
  215. package/src/server/claude-pty-mcp/mcp-http.ts +177 -0
  216. package/src/server/claude-pty-mcp/mcp.ts +412 -0
  217. package/src/server/claude-pty-mcp/mention-parser.ts +25 -0
  218. package/src/server/claude-pty-mcp/paths.ts +24 -0
  219. package/src/server/claude-pty-mcp/permission-gate.ts +243 -0
  220. package/src/server/claude-pty-mcp/terminal-pid-registry.adapter.ts +107 -0
  221. package/src/server/claude-pty-mcp/tools/ask-user-question.test.ts +119 -0
  222. package/src/server/claude-pty-mcp/tools/ask-user-question.ts +61 -0
  223. package/src/server/claude-pty-mcp/tools/bash.adapter.ts +76 -0
  224. package/src/server/claude-pty-mcp/tools/bash.test.ts +56 -0
  225. package/src/server/claude-pty-mcp/tools/delegate-subagent.test.ts +155 -0
  226. package/src/server/claude-pty-mcp/tools/delegate-subagent.ts +111 -0
  227. package/src/server/claude-pty-mcp/tools/edit.adapter.ts +95 -0
  228. package/src/server/claude-pty-mcp/tools/edit.test.ts +93 -0
  229. package/src/server/claude-pty-mcp/tools/exit-plan-mode.test.ts +61 -0
  230. package/src/server/claude-pty-mcp/tools/exit-plan-mode.ts +50 -0
  231. package/src/server/claude-pty-mcp/tools/glob.adapter.ts +86 -0
  232. package/src/server/claude-pty-mcp/tools/glob.test.ts +61 -0
  233. package/src/server/claude-pty-mcp/tools/grep.adapter.ts +126 -0
  234. package/src/server/claude-pty-mcp/tools/grep.test.ts +62 -0
  235. package/src/server/claude-pty-mcp/tools/read.adapter.ts +58 -0
  236. package/src/server/claude-pty-mcp/tools/read.test.ts +62 -0
  237. package/src/server/claude-pty-mcp/tools/tool-callback-shim.ts +42 -0
  238. package/src/server/claude-pty-mcp/tools/webfetch.test.ts +81 -0
  239. package/src/server/claude-pty-mcp/tools/webfetch.ts +82 -0
  240. package/src/server/claude-pty-mcp/tools/websearch.test.ts +40 -0
  241. package/src/server/claude-pty-mcp/tools/websearch.ts +42 -0
  242. package/src/server/claude-pty-mcp/tools/write.adapter.ts +60 -0
  243. package/src/server/claude-pty-mcp/tools/write.test.ts +52 -0
  244. package/src/server/claude-pty-mcp/uploads.adapter.ts +98 -0
  245. package/src/server/claude-pty-mcp/uploads.ts +38 -0
  246. package/src/server/claude-turn.test.ts +176 -0
  247. package/src/server/cli-runtime.test.ts +456 -0
  248. package/src/server/cli-runtime.ts +374 -0
  249. package/src/server/cli-supervisor.ts +81 -0
  250. package/src/server/cli.ts +78 -0
  251. package/src/server/client-log-forwarder.test.ts +74 -0
  252. package/src/server/client-log-forwarder.ts +75 -0
  253. package/src/server/codex-app-server-protocol.ts +449 -0
  254. package/src/server/codex-app-server.test.ts +2990 -0
  255. package/src/server/codex-app-server.ts +1713 -0
  256. package/src/server/coordination-integration.test.ts +63 -0
  257. package/src/server/coordination-mcp.test.ts +149 -0
  258. package/src/server/coordination-mcp.ts +197 -0
  259. package/src/server/delegation-coordinator.test.ts +675 -0
  260. package/src/server/delegation-coordinator.ts +454 -0
  261. package/src/server/discovery.test.ts +211 -0
  262. package/src/server/discovery.ts +301 -0
  263. package/src/server/event-store-agent-config.test.ts +124 -0
  264. package/src/server/event-store-coordination.test.ts +149 -0
  265. package/src/server/event-store-profile.test.ts +132 -0
  266. package/src/server/event-store-repo.test.ts +154 -0
  267. package/src/server/event-store-runner-team.test.ts +104 -0
  268. package/src/server/event-store.test.ts +342 -0
  269. package/src/server/event-store.ts +2208 -0
  270. package/src/server/events.ts +379 -0
  271. package/src/server/extension-router.test.ts +183 -0
  272. package/src/server/extension-router.ts +114 -0
  273. package/src/server/extensions/agents/server.test.ts +191 -0
  274. package/src/server/extensions/agents/server.ts +108 -0
  275. package/src/server/extensions/c3/server.test.ts +284 -0
  276. package/src/server/extensions/c3/server.ts +212 -0
  277. package/src/server/extensions/code/server.test.ts +200 -0
  278. package/src/server/extensions/code/server.ts +150 -0
  279. package/src/server/extensions.config.ts +10 -0
  280. package/src/server/external-open.ts +69 -0
  281. package/src/server/generate-fork-context.ts +58 -0
  282. package/src/server/generate-merge-context.test.ts +290 -0
  283. package/src/server/generate-merge-context.ts +141 -0
  284. package/src/server/generate-title.ts +36 -0
  285. package/src/server/git-clone-policy.test.ts +138 -0
  286. package/src/server/git-clone-policy.ts +27 -0
  287. package/src/server/harness-types.ts +1 -0
  288. package/src/server/journey-verification.test.ts +640 -0
  289. package/src/server/journey-verification.ts +195 -0
  290. package/src/server/machine-name.ts +22 -0
  291. package/src/server/nats-auth.test.ts +92 -0
  292. package/src/server/nats-auth.ts +6 -0
  293. package/src/server/nats-bind-guard.test.ts +71 -0
  294. package/src/server/nats-bind-guard.ts +42 -0
  295. package/src/server/nats-bridge.test.ts +141 -0
  296. package/src/server/nats-bridge.ts +111 -0
  297. package/src/server/nats-connector.test.ts +56 -0
  298. package/src/server/nats-connector.ts +71 -0
  299. package/src/server/nats-daemon-manager.test.ts +76 -0
  300. package/src/server/nats-daemon-manager.ts +174 -0
  301. package/src/server/nats-publisher.test.ts +356 -0
  302. package/src/server/nats-publisher.ts +271 -0
  303. package/src/server/nats-responders.test.ts +1018 -0
  304. package/src/server/nats-responders.ts +925 -0
  305. package/src/server/nats-streams.test.ts +112 -0
  306. package/src/server/nats-streams.ts +129 -0
  307. package/src/server/oauth-pool/oauth-responders.ts +185 -0
  308. package/src/server/oauth-pool/oauth-settings-store.ts +173 -0
  309. package/src/server/oauth-pool/oauth-token-pool.ts +303 -0
  310. package/src/server/orchestration.test.ts +1063 -0
  311. package/src/server/orchestration.ts +716 -0
  312. package/src/server/pairing-endpoints.test.ts +171 -0
  313. package/src/server/pairing-store.test.ts +154 -0
  314. package/src/server/pairing-store.ts +124 -0
  315. package/src/server/paths.ts +27 -0
  316. package/src/server/pr3-liveness.test.ts +252 -0
  317. package/src/server/process-utils.ts +10 -0
  318. package/src/server/project-cli.ts +180 -0
  319. package/src/server/provider-catalog.test.ts +177 -0
  320. package/src/server/provider-catalog.ts +146 -0
  321. package/src/server/pty-responders.ts +345 -0
  322. package/src/server/push-notifications.test.ts +234 -0
  323. package/src/server/push-notifications.ts +188 -0
  324. package/src/server/quick-response.test.ts +196 -0
  325. package/src/server/quick-response.ts +154 -0
  326. package/src/server/read-models-agent-config.test.ts +59 -0
  327. package/src/server/read-models-coordination.test.ts +69 -0
  328. package/src/server/read-models.test.ts +332 -0
  329. package/src/server/read-models.ts +258 -0
  330. package/src/server/repo-journey.test.ts +96 -0
  331. package/src/server/repo-manager.test.ts +118 -0
  332. package/src/server/repo-manager.ts +97 -0
  333. package/src/server/repo-status.test.ts +54 -0
  334. package/src/server/repo-status.ts +82 -0
  335. package/src/server/restart.test.ts +27 -0
  336. package/src/server/restart.ts +30 -0
  337. package/src/server/runner-incompatible-gate.test.ts +383 -0
  338. package/src/server/runner-manager.test.ts +72 -0
  339. package/src/server/runner-manager.ts +312 -0
  340. package/src/server/runner-pairing-urls.test.ts +59 -0
  341. package/src/server/runner-pairing-urls.ts +67 -0
  342. package/src/server/runner-proxy.test.ts +456 -0
  343. package/src/server/runner-proxy.ts +494 -0
  344. package/src/server/runner-router.test.ts +429 -0
  345. package/src/server/runner-router.ts +212 -0
  346. package/src/server/runner-routing.test.ts +584 -0
  347. package/src/server/runtime-registry.test.ts +436 -0
  348. package/src/server/runtime-registry.ts +307 -0
  349. package/src/server/sandbox-health.test.ts +127 -0
  350. package/src/server/sandbox-health.ts +94 -0
  351. package/src/server/sandbox-journey.test.ts +232 -0
  352. package/src/server/sandbox-manager.test.ts +146 -0
  353. package/src/server/sandbox-manager.ts +159 -0
  354. package/src/server/server.test.ts +287 -0
  355. package/src/server/server.ts +1108 -0
  356. package/src/server/session-discovery.test.ts +129 -0
  357. package/src/server/session-discovery.ts +475 -0
  358. package/src/server/session-index.test.ts +362 -0
  359. package/src/server/session-index.ts +119 -0
  360. package/src/server/session-seed.ts +288 -0
  361. package/src/server/share.test.ts +108 -0
  362. package/src/server/share.ts +113 -0
  363. package/src/server/skill-discovery.test.ts +201 -0
  364. package/src/server/skill-discovery.ts +77 -0
  365. package/src/server/storage/test-helpers.ts +67 -0
  366. package/src/server/terminal-manager.test.ts +309 -0
  367. package/src/server/terminal-manager.ts +354 -0
  368. package/src/server/transcript-consumer.test.ts +339 -0
  369. package/src/server/transcript-consumer.ts +162 -0
  370. package/src/server/transcript-search.test.ts +193 -0
  371. package/src/server/transcript-search.ts +83 -0
  372. package/src/server/transcript-utils.ts +52 -0
  373. package/src/server/update-manager.test.ts +107 -0
  374. package/src/server/update-manager.ts +230 -0
  375. package/src/server/workflow-engine.test.ts +251 -0
  376. package/src/server/workflow-engine.ts +169 -0
  377. package/src/server/workflow-mcp.ts +49 -0
  378. package/src/server/workflow-store.test.ts +155 -0
  379. package/src/server/workflow-store.ts +139 -0
  380. package/src/server/workspace-agent-integration.test.ts +167 -0
  381. package/src/server/workspace-agent-routes.test.ts +127 -0
  382. package/src/server/workspace-agent-routes.ts +89 -0
  383. package/src/server/workspace-agent.test.ts +103 -0
  384. package/src/server/workspace-agent.ts +102 -0
  385. package/src/server/workspace-cli.test.ts +79 -0
  386. package/src/server/workspace-config-manager.test.ts +109 -0
  387. package/src/server/workspace-config-manager.ts +83 -0
  388. package/src/server/workspace-directory-policy.test.ts +109 -0
  389. package/src/server/workspace-directory-policy.ts +56 -0
  390. package/src/shared/agent-config-types.ts +25 -0
  391. package/src/shared/branding.test.ts +42 -0
  392. package/src/shared/branding.ts +54 -0
  393. package/src/shared/compression.test.ts +85 -0
  394. package/src/shared/compression.ts +42 -0
  395. package/src/shared/coordination-store.test.ts +24 -0
  396. package/src/shared/coordination-store.ts +26 -0
  397. package/src/shared/dev-ports.test.ts +84 -0
  398. package/src/shared/dev-ports.ts +100 -0
  399. package/src/shared/extension-types.ts +45 -0
  400. package/src/shared/fork-presets.ts +54 -0
  401. package/src/shared/harness-types.test.ts +15 -0
  402. package/src/shared/harness-types.ts +21 -0
  403. package/src/shared/log-sink.test.ts +112 -0
  404. package/src/shared/log-sink.ts +185 -0
  405. package/src/shared/mention-pattern.ts +7 -0
  406. package/src/shared/merge-presets.ts +41 -0
  407. package/src/shared/nats-subjects.test.ts +61 -0
  408. package/src/shared/nats-subjects.ts +131 -0
  409. package/src/shared/permission-policy.ts +136 -0
  410. package/src/shared/ports.ts +3 -0
  411. package/src/shared/preset-types.ts +15 -0
  412. package/src/shared/profile-types.ts +49 -0
  413. package/src/shared/projectFileUrl.ts +36 -0
  414. package/src/shared/protocol.ts +153 -0
  415. package/src/shared/pty-instance.ts +43 -0
  416. package/src/shared/puggy/diagnostics/result.ts +18 -0
  417. package/src/shared/puggy/expressions/evaluate.ts +292 -0
  418. package/src/shared/puggy/index.test.ts +101 -0
  419. package/src/shared/puggy/index.ts +69 -0
  420. package/src/shared/puggy/parser/ast.ts +110 -0
  421. package/src/shared/puggy/parser/parser.ts +624 -0
  422. package/src/shared/puggy/renderer/html.ts +447 -0
  423. package/src/shared/runner-protocol.test.ts +277 -0
  424. package/src/shared/runner-protocol.ts +210 -0
  425. package/src/shared/runner-team-types.ts +73 -0
  426. package/src/shared/runtime-types.ts +48 -0
  427. package/src/shared/sandbox-types.ts +53 -0
  428. package/src/shared/tailwind-build.test.ts +12 -0
  429. package/src/shared/tinkaria-system-prompt.ts +101 -0
  430. package/src/shared/tools.test.ts +335 -0
  431. package/src/shared/tools.ts +397 -0
  432. package/src/shared/transcript-entries.ts +27 -0
  433. package/src/shared/transcript-render.test.ts +225 -0
  434. package/src/shared/transcript-render.ts +467 -0
  435. package/src/shared/types.ts +1031 -0
  436. package/src/shared/vite-config.test.ts +47 -0
  437. package/src/shared/web-context.test.ts +110 -0
  438. package/src/shared/web-context.ts +76 -0
  439. package/src/shared/workflow-types.ts +51 -0
  440. package/src/shared/workspace-types.ts +100 -0
@@ -0,0 +1,716 @@
1
+ import { createSdkMcpServer, tool } from "@anthropic-ai/claude-agent-sdk"
2
+ import { z } from "zod/v4"
3
+ import type { AgentProvider, DelegationMode, DelegationResumeMode, OrchestrationChildNode, OrchestrationChildStatus, OrchestrationHierarchySnapshot, TranscriptEntry, SessionStatus } from "../shared/types"
4
+ import type { DelegationCoordinator } from "./delegation-coordinator"
5
+ import { LOG_PREFIX } from "../shared/branding"
6
+ import { normalizeServerModel } from "./provider-catalog"
7
+ import { toTranscriptLine } from "./transcript-utils"
8
+
9
+ interface OriginRecord {
10
+ originChatId: string
11
+ depth: number
12
+ instruction: string
13
+ spawnedAt: number
14
+ lastStatus: OrchestrationChildStatus
15
+ lastStatusAt: number
16
+ }
17
+
18
+ interface OrchestratorCoordinator {
19
+ activeTurns: { has(key: string): boolean }
20
+ getActiveStatuses(): Map<string, SessionStatus>
21
+ startTurnForChat(args: {
22
+ chatId: string
23
+ provider: AgentProvider
24
+ content: string
25
+ delegatedContext?: string
26
+ isSpawned?: boolean
27
+ model: string
28
+ effort?: string
29
+ planMode: boolean
30
+ appendUserPrompt: boolean
31
+ }): Promise<void>
32
+ queue(args: {
33
+ type: "chat.queue"
34
+ chatId: string
35
+ provider?: AgentProvider
36
+ content: string
37
+ model?: string
38
+ effort?: string
39
+ planMode?: boolean
40
+ }): Promise<{ chatId: string; queued: boolean }>
41
+ cancel(chatId: string): Promise<void>
42
+ disposeChat(chatId: string): Promise<void>
43
+ }
44
+
45
+ interface OrchestratorStore {
46
+ createChat(workspaceId: string): Promise<{ id: string; workspaceId: string }>
47
+ requireChat(chatId: string): { id: string; workspaceId: string; provider: AgentProvider | null }
48
+ getProject(workspaceId: string): { id: string; localPath: string } | null
49
+ listChatsByProject(workspaceId: string): Array<{ id: string }>
50
+ getMessages(chatId: string): Promise<TranscriptEntry[]>
51
+ }
52
+
53
+ export interface SessionOrchestratorArgs {
54
+ store: OrchestratorStore
55
+ coordinator: OrchestratorCoordinator
56
+ delegationCoordinator?: DelegationCoordinator
57
+ onMessageAppended?: (chatId: string, entry: TranscriptEntry) => void
58
+ maxDepth?: number
59
+ maxConcurrency?: number
60
+ }
61
+
62
+ interface PendingWaiter {
63
+ resolve: (value: { result: string; isError: boolean }) => void
64
+ reject: (reason: Error) => void
65
+ timer: ReturnType<typeof setTimeout>
66
+ }
67
+
68
+ interface ExternalAgentStateRecord {
69
+ chatId: string
70
+ status: OrchestrationChildStatus
71
+ spawnedAt: number
72
+ lastStatusAt: number
73
+ instruction: string
74
+ }
75
+
76
+ const MAX_DELEGATED_CONTEXT_ENTRIES = 24
77
+ const MAX_DELEGATED_CONTEXT_CHARS = 12_000
78
+ const MAX_DELEGATED_CONTEXT_LINE_CHARS = 600
79
+
80
+ function entryToDelegatedContextLine(entry: TranscriptEntry): string | null {
81
+ return toTranscriptLine(entry, MAX_DELEGATED_CONTEXT_LINE_CHARS)
82
+ }
83
+
84
+ function buildDelegatedContext(entries: TranscriptEntry[]): string | undefined {
85
+ const relevantEntries = entries
86
+ .map(entryToDelegatedContextLine)
87
+ .filter((line): line is string => Boolean(line))
88
+
89
+ if (relevantEntries.length === 0) return undefined
90
+
91
+ const selected = relevantEntries.slice(-MAX_DELEGATED_CONTEXT_ENTRIES)
92
+ const omittedCount = relevantEntries.length - selected.length
93
+ const headerLines = [
94
+ "Forked parent chat context:",
95
+ "Treat this as background context copied from the spawning chat before your task starts.",
96
+ "Do not re-answer it directly unless the new task asks you to.",
97
+ ]
98
+ if (omittedCount > 0) {
99
+ headerLines.push(`Older transcript lines omitted: ${omittedCount}.`)
100
+ }
101
+
102
+ const lines = [...headerLines, ...selected]
103
+ let serialized = lines.join("\n")
104
+
105
+ if (serialized.length <= MAX_DELEGATED_CONTEXT_CHARS) {
106
+ return serialized
107
+ }
108
+
109
+ const trimmedSelected: string[] = []
110
+ let remaining = MAX_DELEGATED_CONTEXT_CHARS - headerLines.join("\n").length - 1
111
+ for (let index = selected.length - 1; index >= 0; index -= 1) {
112
+ const line = selected[index]!
113
+ const cost = line.length + 1
114
+ if (remaining - cost < 0) break
115
+ trimmedSelected.unshift(line)
116
+ remaining -= cost
117
+ }
118
+
119
+ if (trimmedSelected.length === 0) {
120
+ return headerLines.join("\n")
121
+ }
122
+
123
+ return [...headerLines, ...trimmedSelected].join("\n")
124
+ }
125
+
126
+ export class SessionOrchestrator {
127
+ private readonly store: OrchestratorStore
128
+ private readonly coordinator: OrchestratorCoordinator
129
+ private readonly delegationCoordinator?: DelegationCoordinator
130
+ private readonly maxDepth: number
131
+ private readonly maxConcurrency: number
132
+ private readonly origins = new Map<string, OriginRecord>()
133
+ private readonly children = new Map<string, Set<string>>()
134
+ private readonly waiters = new Map<string, PendingWaiter>()
135
+ private readonly externalChildren = new Map<string, Map<string, ExternalAgentStateRecord>>()
136
+
137
+ constructor(args: SessionOrchestratorArgs) {
138
+ this.store = args.store
139
+ this.coordinator = args.coordinator
140
+ this.delegationCoordinator = args.delegationCoordinator
141
+ this.maxDepth = args.maxDepth ?? 3
142
+ this.maxConcurrency = args.maxConcurrency ?? 10
143
+ }
144
+
145
+ async spawnAgent(
146
+ callerChatId: string,
147
+ args: {
148
+ instruction: string
149
+ provider?: AgentProvider
150
+ model?: string
151
+ forkContext?: boolean
152
+ mode?: DelegationMode
153
+ resume?: DelegationResumeMode
154
+ resumeHint?: string
155
+ },
156
+ ): Promise<{ chatId: string; delegationId?: string }> {
157
+ const callerChat = this.store.requireChat(callerChatId)
158
+ const provider = args.provider ?? callerChat.provider ?? "claude"
159
+ const callerDepth = this.origins.get(callerChatId)?.depth ?? 0
160
+
161
+ const newDepth = callerDepth + 1
162
+ if (newDepth > this.maxDepth) {
163
+ if (callerDepth > 0) {
164
+ throw new Error(
165
+ `Circular orchestration detected: spawned session at depth ${callerDepth} cannot spawn (max depth ${this.maxDepth})`,
166
+ )
167
+ }
168
+ throw new Error(
169
+ `Max orchestration depth (${this.maxDepth}) exceeded — cannot spawn at depth ${newDepth}`,
170
+ )
171
+ }
172
+
173
+ const activeSteered = this.countActiveSteered(callerChat.workspaceId)
174
+ if (activeSteered >= this.maxConcurrency) {
175
+ throw new Error(
176
+ `Max concurrency (${this.maxConcurrency}) reached for project ${callerChat.workspaceId}`,
177
+ )
178
+ }
179
+
180
+ const newChat = await this.store.createChat(callerChat.workspaceId)
181
+ const now = Date.now()
182
+ this.origins.set(newChat.id, {
183
+ originChatId: callerChatId,
184
+ depth: newDepth,
185
+ instruction: args.instruction.slice(0, 120),
186
+ spawnedAt: now,
187
+ lastStatus: "spawning",
188
+ lastStatusAt: now,
189
+ })
190
+
191
+ let siblings = this.children.get(callerChatId)
192
+ if (!siblings) {
193
+ siblings = new Set()
194
+ this.children.set(callerChatId, siblings)
195
+ }
196
+ siblings.add(newChat.id)
197
+
198
+ const model = args.model ?? normalizeServerModel(provider)
199
+ const delegatedContext = args.forkContext
200
+ ? buildDelegatedContext(await this.store.getMessages(callerChatId))
201
+ : undefined
202
+
203
+ // Create durable delegation record if coordinator is present
204
+ let delegationId: string | undefined
205
+ if (this.delegationCoordinator) {
206
+ const mode = args.mode ?? "blocking"
207
+ const resume = args.resume ?? "gate"
208
+ const parentMessages = await this.store.getMessages(callerChatId)
209
+ const resumeHint = args.resumeHint ?? this.delegationCoordinator.generateResumeHint(parentMessages)
210
+
211
+ const result = await this.delegationCoordinator.createDelegation({
212
+ workspaceId: callerChat.workspaceId,
213
+ parentChatId: callerChatId,
214
+ childChatId: newChat.id,
215
+ childProvider: provider,
216
+ instructionPreview: args.instruction,
217
+ mode,
218
+ resume,
219
+ depth: newDepth,
220
+ resumeHint,
221
+ })
222
+ delegationId = result.delegationId
223
+ }
224
+
225
+ console.warn(`${LOG_PREFIX} spawnAgent: ${callerChatId} -> ${newChat.id} (depth=${newDepth}, provider=${provider})`)
226
+
227
+ await this.coordinator.startTurnForChat({
228
+ chatId: newChat.id,
229
+ provider,
230
+ content: args.instruction,
231
+ delegatedContext,
232
+ isSpawned: true,
233
+ model,
234
+ planMode: false,
235
+ appendUserPrompt: true,
236
+ })
237
+
238
+ const result: { chatId: string; delegationId?: string } = { chatId: newChat.id }
239
+ if (delegationId) result.delegationId = delegationId
240
+ return result
241
+ }
242
+
243
+ async sendInput(
244
+ callerChatId: string,
245
+ args: { targetChatId: string; content: string; model?: string },
246
+ ): Promise<void> {
247
+ this.requireOwnedTarget(callerChatId, args.targetChatId)
248
+ const targetChat = this.store.requireChat(args.targetChatId)
249
+ const provider = targetChat.provider ?? "claude"
250
+ const model = args.model ?? normalizeServerModel(provider)
251
+
252
+ if (this.coordinator.activeTurns.has(args.targetChatId)) {
253
+ await this.coordinator.queue({
254
+ type: "chat.queue",
255
+ chatId: args.targetChatId,
256
+ provider,
257
+ content: args.content,
258
+ model,
259
+ planMode: false,
260
+ })
261
+ return
262
+ }
263
+
264
+ await this.coordinator.startTurnForChat({
265
+ chatId: args.targetChatId,
266
+ provider,
267
+ content: args.content,
268
+ model,
269
+ planMode: false,
270
+ appendUserPrompt: true,
271
+ })
272
+ }
273
+
274
+ async waitForResult(
275
+ callerChatId: string,
276
+ args: { targetChatId: string; timeoutMs?: number },
277
+ ): Promise<{ result: string; isError: boolean }> {
278
+ this.requireOwnedTarget(callerChatId, args.targetChatId)
279
+ const timeoutMs = args.timeoutMs ?? 120_000
280
+
281
+ return new Promise<{ result: string; isError: boolean }>((resolve, reject) => {
282
+ const timer = setTimeout(() => {
283
+ this.waiters.delete(args.targetChatId)
284
+ void this.coordinator.cancel(args.targetChatId).catch(() => undefined)
285
+ reject(new Error(`Timed out waiting for result from ${args.targetChatId} after ${timeoutMs}ms`))
286
+ }, timeoutMs)
287
+
288
+ this.waiters.set(args.targetChatId, { resolve, reject, timer })
289
+ })
290
+ }
291
+
292
+ onMessageAppended(chatId: string, entry: TranscriptEntry): void {
293
+ const waiter = this.waiters.get(chatId)
294
+ if (waiter && entry.kind === "result") {
295
+ this.waiters.delete(chatId)
296
+ clearTimeout(waiter.timer)
297
+ waiter.resolve({ result: entry.result, isError: entry.isError })
298
+ }
299
+
300
+ this.updateExternalHierarchy(chatId, entry)
301
+ }
302
+
303
+ async closeAgent(
304
+ callerChatId: string,
305
+ args: { targetChatId: string },
306
+ ): Promise<void> {
307
+ this.requireOwnedTarget(callerChatId, args.targetChatId)
308
+ // Mark as closed tombstone first (visible in hierarchy)
309
+ const origin = this.origins.get(args.targetChatId)
310
+ if (origin) {
311
+ origin.lastStatus = "closed"
312
+ origin.lastStatusAt = Date.now()
313
+ }
314
+
315
+ // Clear any pending waiter
316
+ const waiter = this.waiters.get(args.targetChatId)
317
+ if (waiter) {
318
+ clearTimeout(waiter.timer)
319
+ this.waiters.delete(args.targetChatId)
320
+ }
321
+
322
+ // Dispose the underlying chat (async)
323
+ await this.coordinator.disposeChat(args.targetChatId)
324
+ }
325
+
326
+ pruneTombstones(): void {
327
+ const toRemove: string[] = []
328
+ for (const [chatId, origin] of this.origins) {
329
+ if (origin.lastStatus === "closed") {
330
+ toRemove.push(chatId)
331
+ }
332
+ }
333
+ for (const chatId of toRemove) {
334
+ this.cleanup(chatId)
335
+ }
336
+ }
337
+
338
+ destroy(): void {
339
+ for (const [, waiter] of this.waiters) {
340
+ clearTimeout(waiter.timer)
341
+ waiter.reject(new Error("Orchestrator disposed"))
342
+ }
343
+ this.waiters.clear()
344
+ this.origins.clear()
345
+ this.children.clear()
346
+ this.externalChildren.clear()
347
+ }
348
+
349
+ getHierarchy(chatId: string): OrchestrationHierarchySnapshot {
350
+ const childSet = this.children.get(chatId)
351
+ const externalChildren = this.externalChildren.get(chatId)
352
+ if ((!childSet || childSet.size === 0) && (!externalChildren || externalChildren.size === 0)) {
353
+ return { children: [] }
354
+ }
355
+
356
+ const statuses = this.coordinator.getActiveStatuses()
357
+ const internalChildren = childSet
358
+ ? [...childSet].map((childId) => this.buildChildNode(childId, statuses))
359
+ : []
360
+ const seenIds = new Set(internalChildren.map((child) => child.chatId))
361
+ const externalNodes = externalChildren
362
+ ? [...externalChildren.values()]
363
+ .filter((child) => !seenIds.has(child.chatId))
364
+ .map((child) => ({
365
+ chatId: child.chatId,
366
+ externalSessionId: child.chatId,
367
+ status: child.status,
368
+ spawnedAt: child.spawnedAt,
369
+ lastStatusAt: child.lastStatusAt,
370
+ instruction: child.instruction,
371
+ children: [],
372
+ }))
373
+ : []
374
+
375
+ return {
376
+ children: [...internalChildren, ...externalNodes],
377
+ }
378
+ }
379
+
380
+ listAgents(chatId: string): OrchestrationHierarchySnapshot {
381
+ return this.getHierarchy(chatId)
382
+ }
383
+
384
+ private buildChildNode(
385
+ childId: string,
386
+ statuses: Map<string, SessionStatus>,
387
+ ): OrchestrationChildNode {
388
+ const origin = this.origins.get(childId)
389
+ const now = Date.now()
390
+
391
+ if (!origin) {
392
+ return {
393
+ chatId: childId,
394
+ status: "closed",
395
+ spawnedAt: now,
396
+ lastStatusAt: now,
397
+ instruction: "",
398
+ children: [],
399
+ }
400
+ }
401
+
402
+ const resolvedStatus = this.resolveChildStatus(childId, origin, statuses)
403
+ if (resolvedStatus !== origin.lastStatus) {
404
+ origin.lastStatus = resolvedStatus
405
+ origin.lastStatusAt = now
406
+ }
407
+
408
+ const nestedChildren = this.children.get(childId)
409
+ return {
410
+ chatId: childId,
411
+ status: origin.lastStatus,
412
+ spawnedAt: origin.spawnedAt,
413
+ lastStatusAt: origin.lastStatusAt,
414
+ instruction: origin.instruction,
415
+ children: nestedChildren
416
+ ? [...nestedChildren].map((id) => this.buildChildNode(id, statuses))
417
+ : [],
418
+ }
419
+ }
420
+
421
+ private resolveChildStatus(
422
+ _childId: string,
423
+ origin: OriginRecord,
424
+ statuses: Map<string, SessionStatus>,
425
+ ): OrchestrationChildStatus {
426
+ if (origin.lastStatus === "closed") return "closed"
427
+
428
+ const tinkariaStatus = statuses.get(_childId)
429
+ if (!tinkariaStatus) {
430
+ return "completed"
431
+ }
432
+
433
+ switch (tinkariaStatus) {
434
+ case "starting":
435
+ case "running":
436
+ return "running"
437
+ case "waiting_for_user":
438
+ return "waiting"
439
+ case "failed":
440
+ return "failed"
441
+ default:
442
+ return "running"
443
+ }
444
+ }
445
+
446
+ async cancelWithCascade(chatId: string): Promise<void> {
447
+ const childSet = this.children.get(chatId)
448
+ if (childSet) {
449
+ for (const childId of childSet) {
450
+ await this.cancelWithCascade(childId)
451
+ }
452
+ }
453
+ await this.coordinator.cancel(chatId)
454
+ this.cleanup(chatId)
455
+ }
456
+
457
+ private countActiveSteered(workspaceId: string): number {
458
+ const statuses = this.coordinator.getActiveStatuses()
459
+ let count = 0
460
+ for (const [chatId, origin] of this.origins) {
461
+ try {
462
+ const chat = this.store.requireChat(chatId)
463
+ if (chat.workspaceId !== workspaceId) continue
464
+ const status = this.resolveChildStatus(chatId, origin, statuses)
465
+ if (status === "spawning" || status === "running" || status === "waiting") {
466
+ count += 1
467
+ }
468
+ } catch (error) {
469
+ void (error instanceof Error ? error.message : String(error))
470
+ // Chat may have been disposed — skip
471
+ }
472
+ }
473
+ return count
474
+ }
475
+
476
+ private cleanup(chatId: string): void {
477
+ const origin = this.origins.get(chatId)
478
+ if (origin) {
479
+ this.children.get(origin.originChatId)?.delete(chatId)
480
+ }
481
+ this.origins.delete(chatId)
482
+ this.children.delete(chatId)
483
+
484
+ const waiter = this.waiters.get(chatId)
485
+ if (waiter) {
486
+ clearTimeout(waiter.timer)
487
+ this.waiters.delete(chatId)
488
+ }
489
+ }
490
+
491
+ private updateExternalHierarchy(chatId: string, entry: TranscriptEntry): void {
492
+ const payload = this.extractCollabPayload(entry)
493
+ if (!payload) return
494
+
495
+ const receiverIds = this.extractReceiverThreadIds(payload)
496
+ if (receiverIds.length === 0) return
497
+
498
+ let children = this.externalChildren.get(chatId)
499
+ if (!children) {
500
+ children = new Map()
501
+ this.externalChildren.set(chatId, children)
502
+ }
503
+
504
+ const now = Date.now()
505
+ const instruction = this.extractExternalInstruction(payload)
506
+ const entryIsError = entry.kind === "tool_result" ? Boolean(entry.isError) : false
507
+ for (const receiverId of receiverIds) {
508
+ const existing = children.get(receiverId)
509
+ children.set(receiverId, {
510
+ chatId: receiverId,
511
+ status: this.resolveExternalStatus(payload, receiverId, entryIsError, existing?.status),
512
+ spawnedAt: existing?.spawnedAt ?? entry.createdAt ?? now,
513
+ lastStatusAt: now,
514
+ instruction: instruction ?? existing?.instruction ?? "Delegated task",
515
+ })
516
+ }
517
+ }
518
+
519
+ private extractCollabPayload(entry: TranscriptEntry): Record<string, unknown> | null {
520
+ if (entry.kind === "tool_call" && entry.tool.toolKind === "subagent_task") {
521
+ return entry.tool.rawInput ?? null
522
+ }
523
+ if (entry.kind === "tool_result" && entry.content && typeof entry.content === "object" && !Array.isArray(entry.content)) {
524
+ const record = entry.content as Record<string, unknown>
525
+ if (Array.isArray(record.receiverThreadIds)) {
526
+ return record
527
+ }
528
+ }
529
+ return null
530
+ }
531
+
532
+ private extractReceiverThreadIds(payload: Record<string, unknown>): string[] {
533
+ const rawReceiverIds = payload.receiverThreadIds
534
+ if (!Array.isArray(rawReceiverIds)) return []
535
+ return rawReceiverIds.filter((value): value is string => typeof value === "string")
536
+ }
537
+
538
+ private extractExternalInstruction(payload: Record<string, unknown>): string | null {
539
+ const prompt = payload.prompt
540
+ if (typeof prompt !== "string" || prompt.length === 0) return null
541
+ return prompt.slice(0, 120)
542
+ }
543
+
544
+ private resolveExternalStatus(
545
+ payload: Record<string, unknown>,
546
+ receiverId: string,
547
+ isError: boolean,
548
+ previousStatus?: OrchestrationChildStatus,
549
+ ): OrchestrationChildStatus {
550
+ if (isError) return "failed"
551
+
552
+ const toolName = typeof payload.tool === "string" ? payload.tool : null
553
+ const agentStates = payload.agentsStates
554
+ const stateRecord = agentStates && typeof agentStates === "object" && !Array.isArray(agentStates)
555
+ ? (agentStates as Record<string, unknown>)[receiverId]
556
+ : null
557
+ const stateStatus = stateRecord && typeof stateRecord === "object" && !Array.isArray(stateRecord)
558
+ ? (stateRecord as Record<string, unknown>).status
559
+ : null
560
+ const normalizedState = this.normalizeExternalStatus(typeof stateStatus === "string" ? stateStatus : null)
561
+ if (normalizedState) return normalizedState
562
+
563
+ if (toolName === "closeAgent") return "closed"
564
+ if (toolName === "wait") return previousStatus === "failed" ? "failed" : "completed"
565
+ if (toolName === "spawnAgent") {
566
+ return this.normalizeExternalStatus(typeof payload.status === "string" ? payload.status : null) ?? "spawning"
567
+ }
568
+ if (toolName === "sendInput" || toolName === "resumeAgent") return "running"
569
+
570
+ return this.normalizeExternalStatus(typeof payload.status === "string" ? payload.status : null) ?? previousStatus ?? "running"
571
+ }
572
+
573
+ private normalizeExternalStatus(status: string | null): OrchestrationChildStatus | null {
574
+ if (!status) return null
575
+ switch (status.toLowerCase()) {
576
+ case "pending":
577
+ case "queued":
578
+ case "created":
579
+ case "starting":
580
+ case "spawning":
581
+ return "spawning"
582
+ case "running":
583
+ case "inprogress":
584
+ case "in_progress":
585
+ case "working":
586
+ return "running"
587
+ case "waiting":
588
+ case "waiting_for_user":
589
+ case "paused":
590
+ return "waiting"
591
+ case "completed":
592
+ case "done":
593
+ case "success":
594
+ return "completed"
595
+ case "failed":
596
+ case "error":
597
+ return "failed"
598
+ case "closed":
599
+ case "cancelled":
600
+ case "interrupted":
601
+ return "closed"
602
+ default:
603
+ return null
604
+ }
605
+ }
606
+
607
+ private requireOwnedTarget(callerChatId: string, targetChatId: string): OriginRecord {
608
+ const origin = this.origins.get(targetChatId)
609
+ if (!origin) {
610
+ throw new Error(`Target chat ${targetChatId} is not a spawned agent`)
611
+ }
612
+ if (origin.originChatId !== callerChatId) {
613
+ throw new Error(`Caller ${callerChatId} does not own spawned agent ${targetChatId}`)
614
+ }
615
+ return origin
616
+ }
617
+ }
618
+
619
+ /**
620
+ * Creates an in-process MCP server with orchestration tools for a specific session.
621
+ * Each Claude turn gets its own server instance scoped to the caller's chatId.
622
+ */
623
+ export function createOrchestrationMcpServer(
624
+ orchestrator: SessionOrchestrator,
625
+ callerChatId: string,
626
+ ) {
627
+ return createSdkMcpServer({
628
+ name: "session-orchestration",
629
+ tools: [
630
+ tool(
631
+ "spawn_agent",
632
+ "Spawn a new agent session in the same project. Returns the new session's chatId and delegationId. " +
633
+ "Delegation persists across session boundaries: blocking children auto-resume the parent when done; " +
634
+ "background children inject results passively. Use wait_agent for synchronous result, or rely on auto-resume for durable async workflows.",
635
+ {
636
+ instruction: z.string().describe("Task instruction for the new agent"),
637
+ provider: z.enum(["claude", "codex"]).optional().describe("AI provider — defaults to caller's provider"),
638
+ fork_context: z.boolean().optional().describe(
639
+ "When true, seed the new agent with a bounded snapshot of the current chat transcript before its first task message.",
640
+ ),
641
+ mode: z
642
+ .enum(["blocking", "background"])
643
+ .optional()
644
+ .describe(
645
+ "Delegation mode. 'blocking' (default): parent auto-resumes when child completes. " +
646
+ "'background': fire-and-forget — result injected into parent transcript but no auto-resume.",
647
+ ),
648
+ resume: z
649
+ .enum(["immediate", "gate"])
650
+ .optional()
651
+ .describe(
652
+ "Multi-child resume strategy. 'gate' (default): parent resumes only after ALL blocking children complete. " +
653
+ "'immediate': parent resumes after EACH child completes.",
654
+ ),
655
+ },
656
+ async (args) => {
657
+ const result = await orchestrator.spawnAgent(callerChatId, {
658
+ instruction: args.instruction,
659
+ provider: args.provider as AgentProvider | undefined,
660
+ forkContext: args.fork_context,
661
+ mode: args.mode,
662
+ resume: args.resume,
663
+ })
664
+ return { content: [{ type: "text" as const, text: JSON.stringify(result) }] }
665
+ },
666
+ ),
667
+ tool(
668
+ "list_agents",
669
+ "List the current caller's spawned agent tree and statuses.",
670
+ {},
671
+ async () => {
672
+ const result = orchestrator.listAgents(callerChatId)
673
+ return { content: [{ type: "text" as const, text: JSON.stringify(result) }] }
674
+ },
675
+ ),
676
+ tool(
677
+ "send_input",
678
+ "Send a follow-up message to an existing steered session. Use this to steer a child after its first turn, request additional work, or accumulate incremental results across multiple exchanges. The child resumes with its full conversation context preserved.",
679
+ {
680
+ targetChatId: z.string().describe("The chatId of the target session"),
681
+ content: z.string().describe("Message content to send"),
682
+ },
683
+ async (args) => {
684
+ await orchestrator.sendInput(callerChatId, args)
685
+ return { content: [{ type: "text" as const, text: "Input sent" }] }
686
+ },
687
+ ),
688
+ tool(
689
+ "wait_agent",
690
+ "Block until a steered session completes its current turn. Returns the result text.",
691
+ {
692
+ targetChatId: z.string().describe("The chatId of the session to wait for"),
693
+ timeoutMs: z.number().optional().describe("Max wait time in milliseconds (default: 120000)"),
694
+ },
695
+ async (args) => {
696
+ const result = await orchestrator.waitForResult(callerChatId, args)
697
+ return {
698
+ content: [{ type: "text" as const, text: JSON.stringify(result) }],
699
+ isError: result.isError,
700
+ }
701
+ },
702
+ ),
703
+ tool(
704
+ "close_agent",
705
+ "Dispose a steered session and free resources.",
706
+ {
707
+ targetChatId: z.string().describe("The chatId of the session to close"),
708
+ },
709
+ async (args) => {
710
+ await orchestrator.closeAgent(callerChatId, args)
711
+ return { content: [{ type: "text" as const, text: "Agent closed" }] }
712
+ },
713
+ ),
714
+ ],
715
+ })
716
+ }