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,925 @@
1
+ import type { NatsConnection, Msg, Subscription } from "@nats-io/transport-node"
2
+ import { stat } from "node:fs/promises"
3
+ import type { ClientCommand } from "../shared/protocol"
4
+ import type { DiscoveredProject } from "./discovery"
5
+ import type { EventStore } from "./event-store"
6
+ import { openExternal } from "./external-open"
7
+ import { ensureProjectDirectory, resolveLocalPath } from "./paths"
8
+ import type { TerminalManager } from "./terminal-manager"
9
+ import type { UpdateManager } from "./update-manager"
10
+ import type { NatsPublisher } from "./nats-publisher"
11
+ import { commandSubject } from "../shared/nats-subjects"
12
+ import { LOG_PREFIX } from "../shared/branding"
13
+ import { compressPayload } from "../shared/compression"
14
+ import { inspectSessionRuntime, readSessionTranscript } from "./session-discovery"
15
+ import { DEFAULT_RESOURCE_LIMITS } from "../shared/sandbox-types"
16
+ import { readRepoStatus } from "./repo-status"
17
+ import { generateForkPromptForChat } from "./generate-fork-context"
18
+ import { generateMergePromptForChats as defaultGenerateMergePrompt } from "./generate-merge-context"
19
+ import type { TranscriptEntry } from "../shared/types"
20
+ import { deriveTranscriptRenderUnits } from "./read-models"
21
+ import { deriveCoordinationSnapshot, deriveAgentConfigSnapshot } from "./read-models"
22
+ import type { WorkspaceDirectoryPolicy } from "./workspace-directory-policy"
23
+ import type { RepoManager } from "./repo-manager"
24
+ import type { GitClonePolicy } from "./git-clone-policy"
25
+ import type { RuntimeRegistry } from "./runtime-registry"
26
+ import { resolveProfile } from "../shared/profile-types"
27
+ import { RunnerPickRequired } from "./runner-proxy"
28
+
29
+ /** Session coordinator interface — RunnerProxy delegates turn execution to the runner process */
30
+ interface Coordinator {
31
+ send(command: Extract<ClientCommand, { type: "chat.send" }>): Promise<{ chatId: string }>
32
+ queue(command: Extract<ClientCommand, { type: "chat.queue" }>): Promise<{ chatId: string; queued: boolean }>
33
+ cancel(chatId: string): Promise<void>
34
+ respondTool(command: Extract<ClientCommand, { type: "chat.respondTool" }>): Promise<void>
35
+ disposeChat(chatId: string): Promise<void>
36
+ }
37
+
38
+ const encoder = new TextEncoder()
39
+ const MAX_LOCAL_FILE_PREVIEW_BYTES = 256 * 1024
40
+
41
+ function encode(data: unknown): Uint8Array {
42
+ return compressPayload(encoder.encode(JSON.stringify(data)))
43
+ }
44
+
45
+ export interface RegisterRespondersArgs {
46
+ nc: NatsConnection
47
+ store: EventStore
48
+ agent: Coordinator
49
+ terminals: TerminalManager
50
+ refreshDiscovery: () => Promise<DiscoveredProject[]>
51
+ /** @deprecated Unused by responders -- kept for interface compatibility with tests */
52
+ getDiscoveredProjects?: () => DiscoveredProject[]
53
+ /** @deprecated Unused by responders -- kept for interface compatibility with tests */
54
+ machineDisplayName?: string
55
+ updateManager: UpdateManager | null
56
+ publisher: NatsPublisher
57
+ onStateChange: () => void
58
+ generateForkPrompt?: (forkIntent: string, entries: TranscriptEntry[], cwd: string, preset?: string) => Promise<string>
59
+ generateMergePrompt?: (mergeIntent: string, sessions: { chatId: string; entries: TranscriptEntry[] }[], cwd: string, preset?: string) => Promise<string>
60
+ directoryPolicy: WorkspaceDirectoryPolicy | null
61
+ repoManager: RepoManager | null
62
+ clonePolicy: GitClonePolicy | null
63
+ workflowEngine: import("./workflow-engine").WorkflowEngine | null
64
+ workflowStore: import("./workflow-store").WorkflowStore | null
65
+ sandboxManager: import("./sandbox-manager").SandboxManager | null
66
+ runtimeRegistry: RuntimeRegistry | null
67
+ }
68
+
69
+ /** Command types that do NOT mutate state and should NOT trigger onStateChange */
70
+ const NON_MUTATING: ReadonlySet<ClientCommand["type"]> = new Set([
71
+ "system.ping",
72
+ "terminal.input",
73
+ "terminal.resize",
74
+ "terminal.create",
75
+ "update.check",
76
+ "update.install",
77
+ "system.readLocalFilePreview",
78
+ "chat.getMessages",
79
+ "chat.generateForkPrompt",
80
+ "chat.generateMergePrompt",
81
+ "chat.getSessionRuntime",
82
+ "chat.getRepoStatus",
83
+ "chat.getMessageCount",
84
+ "chat.getRenderUnits",
85
+ "chat.getExternalSessionMessages",
86
+ "snapshot.subscribe",
87
+ "snapshot.unsubscribe",
88
+ "workspace.coordination.snapshot",
89
+ "workspace.agent.list",
90
+ "workspace.agent.get",
91
+ "workspace.repo.status",
92
+ "workspace.workflow.list",
93
+ "workspace.sandbox.logs",
94
+ "workspace.sandbox.status",
95
+ "runtime.list",
96
+ "runtime.health",
97
+ "profile.list",
98
+ "profile.resolve",
99
+ "extension.preference.list",
100
+ "team.member.list",
101
+ ])
102
+
103
+ /** Commands handled by the Bun backend. */
104
+ const SERVER_COMMANDS: readonly ClientCommand["type"][] = [
105
+ "project.open",
106
+ "project.create",
107
+ "project.remove",
108
+ "independent-workspace.create",
109
+ "independent-workspace.delete",
110
+ "independent-workspace.rename",
111
+ "independent-workspace.set-pinned",
112
+ "independent-workspace.reorder",
113
+ "system.ping",
114
+ "update.check",
115
+ "update.install",
116
+ "system.openExternal",
117
+ "system.readLocalFilePreview",
118
+ "chat.create",
119
+ "chat.rename",
120
+ "chat.delete",
121
+ "chat.markRead",
122
+ "chat.send",
123
+ "chat.queue",
124
+ "chat.cancel",
125
+ "chat.respondTool",
126
+ "chat.generateForkPrompt",
127
+ "chat.generateMergePrompt",
128
+ "chat.getSessionRuntime",
129
+ "chat.getRepoStatus",
130
+ "chat.getMessageCount",
131
+ "chat.getRenderUnits",
132
+ "chat.getExternalSessionMessages",
133
+ "terminal.create",
134
+ "terminal.input",
135
+ "terminal.resize",
136
+ "terminal.close",
137
+ "chat.getMessages",
138
+ "snapshot.subscribe",
139
+ "snapshot.unsubscribe",
140
+ "workspace.todo.add",
141
+ "workspace.todo.claim",
142
+ "workspace.todo.complete",
143
+ "workspace.todo.abandon",
144
+ "workspace.claim.create",
145
+ "workspace.claim.release",
146
+ "workspace.worktree.create",
147
+ "workspace.worktree.assign",
148
+ "workspace.worktree.remove",
149
+ "workspace.rule.set",
150
+ "workspace.rule.remove",
151
+ "workspace.coordination.snapshot",
152
+ "workspace.agent.save",
153
+ "workspace.agent.list",
154
+ "workspace.agent.get",
155
+ "workspace.agent.remove",
156
+ "workspace.repo.add",
157
+ "workspace.repo.clone",
158
+ "workspace.repo.remove",
159
+ "workspace.repo.label",
160
+ "workspace.repo.status",
161
+ "workspace.repo.pull",
162
+ "workspace.repo.push",
163
+ "workspace.workflow.run",
164
+ "workspace.workflow.cancel",
165
+ "workspace.workflow.list",
166
+ "workspace.sandbox.create",
167
+ "workspace.sandbox.start",
168
+ "workspace.sandbox.stop",
169
+ "workspace.sandbox.destroy",
170
+ "workspace.sandbox.logs",
171
+ "workspace.sandbox.status",
172
+ "runtime.list",
173
+ "runtime.detect",
174
+ "runtime.install",
175
+ "runtime.remove",
176
+ "runtime.health",
177
+ "profile.list",
178
+ "profile.save",
179
+ "profile.remove",
180
+ "profile.resolve",
181
+ "workspace.profile.override.set",
182
+ "workspace.profile.override.remove",
183
+ "extension.preference.set",
184
+ "extension.preference.list",
185
+ "team.member.list",
186
+ "team.member.save",
187
+ "team.member.remove",
188
+ "runner.label.set",
189
+ "runner.label.remove",
190
+ "chat.selectRunner",
191
+ ]
192
+
193
+ const DETECT_OPTIONS: Record<string, { binaryName: string; packageName: string; versionParser: (stdout: string) => string }> = {
194
+ claude: {
195
+ binaryName: "claude",
196
+ packageName: "@anthropic-ai/claude-code",
197
+ versionParser: (stdout: string) => stdout.replace(/[^0-9.]/g, "").trim() || "unknown",
198
+ },
199
+ codex: {
200
+ binaryName: "codex",
201
+ packageName: "@openai/codex",
202
+ versionParser: (stdout: string) => stdout.replace(/[^0-9.]/g, "").trim() || "unknown",
203
+ },
204
+ }
205
+
206
+ const INSTALL_OPTIONS: Record<string, { packageName: string; binaryName: string }> = {
207
+ claude: { packageName: "@anthropic-ai/claude-code", binaryName: "claude" },
208
+ codex: { packageName: "@openai/codex", binaryName: "codex" },
209
+ }
210
+
211
+ export function registerCommandResponders(args: RegisterRespondersArgs): { dispose: () => void } {
212
+ const {
213
+ nc,
214
+ store,
215
+ agent,
216
+ terminals,
217
+ refreshDiscovery,
218
+ updateManager,
219
+ publisher,
220
+ onStateChange,
221
+ generateForkPrompt = generateForkPromptForChat,
222
+ generateMergePrompt = defaultGenerateMergePrompt,
223
+ } = args
224
+
225
+ const subs: Subscription[] = SERVER_COMMANDS.map((type) => nc.subscribe(commandSubject(type)))
226
+
227
+ async function handleMessage(msg: Msg): Promise<void> {
228
+ let command: ClientCommand
229
+ try {
230
+ command = msg.json<ClientCommand>()
231
+ } catch (_err: unknown) {
232
+ msg.respond(encode({ ok: false, error: "Invalid JSON payload" }))
233
+ return
234
+ }
235
+
236
+ if (!command || typeof command !== "object" || typeof command.type !== "string") {
237
+ msg.respond(encode({ ok: false, error: "Missing command type" }))
238
+ return
239
+ }
240
+
241
+ try {
242
+ const result = await executeCommand(command)
243
+ msg.respond(encode({ ok: true, result }))
244
+
245
+ if (!NON_MUTATING.has(command.type)) {
246
+ onStateChange()
247
+ }
248
+ } catch (error) {
249
+ const message = error instanceof Error ? error.message : String(error)
250
+ msg.respond(encode({ ok: false, error: message }))
251
+ }
252
+ }
253
+
254
+ async function executeCommand(command: ClientCommand): Promise<unknown> {
255
+ switch (command.type) {
256
+ case "system.ping":
257
+ return undefined
258
+
259
+ case "update.check": {
260
+ if (!updateManager) {
261
+ return {
262
+ currentVersion: "unknown",
263
+ latestVersion: null,
264
+ status: "error",
265
+ updateAvailable: false,
266
+ lastCheckedAt: Date.now(),
267
+ error: "Update manager unavailable.",
268
+ installAction: "restart",
269
+ }
270
+ }
271
+ return updateManager.checkForUpdates({ force: command.force })
272
+ }
273
+
274
+ case "update.install": {
275
+ if (!updateManager) {
276
+ throw new Error("Update manager unavailable.")
277
+ }
278
+ return updateManager.installUpdate()
279
+ }
280
+
281
+ case "project.open": {
282
+ await ensureProjectDirectory(command.localPath)
283
+ const project = await store.openProject(command.localPath)
284
+ await refreshDiscovery()
285
+ if (args.directoryPolicy) {
286
+ args.directoryPolicy.onWorkspaceOpened(project.id).catch((err: unknown) => {
287
+ console.warn(`${LOG_PREFIX} workspace dir init error:`, err instanceof Error ? err.message : String(err))
288
+ })
289
+ }
290
+ return { workspaceId: project.id }
291
+ }
292
+
293
+ case "project.create": {
294
+ await ensureProjectDirectory(command.localPath)
295
+ const project = await store.openProject(command.localPath, command.title)
296
+ await refreshDiscovery()
297
+ if (args.directoryPolicy) {
298
+ args.directoryPolicy.onWorkspaceOpened(project.id).catch((err: unknown) => {
299
+ console.warn(`${LOG_PREFIX} workspace dir init error:`, err instanceof Error ? err.message : String(err))
300
+ })
301
+ }
302
+ return { workspaceId: project.id }
303
+ }
304
+
305
+ case "project.remove": {
306
+ const project = store.getProject(command.workspaceId)
307
+ for (const chat of store.listChatsByProject(command.workspaceId)) {
308
+ await agent.disposeChat(chat.id)
309
+ }
310
+ if (project) {
311
+ terminals.closeByCwd(project.localPath)
312
+ }
313
+ await store.removeProject(command.workspaceId)
314
+ return undefined
315
+ }
316
+
317
+ case "independent-workspace.create": {
318
+ const workspace = await store.createIndependentWorkspace(command.name)
319
+ return { workspaceId: workspace.id }
320
+ }
321
+
322
+ case "independent-workspace.delete": {
323
+ await store.deleteIndependentWorkspace(command.workspaceId)
324
+ return undefined
325
+ }
326
+
327
+ case "independent-workspace.rename": {
328
+ await store.renameIndependentWorkspace(command.workspaceId, command.name)
329
+ return undefined
330
+ }
331
+
332
+ case "independent-workspace.set-pinned": {
333
+ await store.setIndependentWorkspacePinned(command.workspaceId, command.pinned)
334
+ return undefined
335
+ }
336
+
337
+ case "independent-workspace.reorder": {
338
+ await store.reorderIndependentWorkspaces(command.orderedWorkspaceIds)
339
+ return undefined
340
+ }
341
+
342
+ case "system.openExternal": {
343
+ await openExternal(command)
344
+ return undefined
345
+ }
346
+
347
+ case "system.readLocalFilePreview":
348
+ return readLocalFilePreview(command.localPath)
349
+
350
+ case "chat.create": {
351
+ const chat = await store.createChat(command.workspaceId, command.repoId, command.chatId)
352
+ return { chatId: chat.id }
353
+ }
354
+
355
+ case "chat.rename": {
356
+ await store.renameChat(command.chatId, command.title)
357
+ return undefined
358
+ }
359
+
360
+ case "chat.delete": {
361
+ await agent.disposeChat(command.chatId)
362
+ await store.deleteChat(command.chatId)
363
+ return undefined
364
+ }
365
+
366
+ case "chat.markRead": {
367
+ await store.setChatReadState(command.chatId, false)
368
+ return undefined
369
+ }
370
+
371
+ case "chat.send": {
372
+ try {
373
+ return await agent.send(command)
374
+ } catch (e) {
375
+ if (e instanceof RunnerPickRequired) {
376
+ return { needsPick: true, chatId: e.chatId, candidates: e.candidates, reason: e.reason }
377
+ }
378
+ throw e
379
+ }
380
+ }
381
+
382
+ case "chat.queue": {
383
+ try {
384
+ return await agent.queue(command)
385
+ } catch (e) {
386
+ if (e instanceof RunnerPickRequired) {
387
+ return { needsPick: true, chatId: e.chatId, candidates: e.candidates, reason: e.reason }
388
+ }
389
+ throw e
390
+ }
391
+ }
392
+
393
+ case "chat.selectRunner": {
394
+ await store.setChatRunner(command.chatId, command.runnerId)
395
+ return { ok: true }
396
+ }
397
+
398
+ case "chat.cancel": {
399
+ await agent.cancel(command.chatId)
400
+ return undefined
401
+ }
402
+
403
+ case "chat.respondTool": {
404
+ await agent.respondTool(command)
405
+ return undefined
406
+ }
407
+
408
+ case "chat.generateForkPrompt": {
409
+ const chat = store.getChat(command.chatId)
410
+ if (!chat) {
411
+ throw new Error("Chat not found")
412
+ }
413
+ const project = store.getProject(chat.workspaceId)
414
+ if (!project) {
415
+ throw new Error("Project not found")
416
+ }
417
+ return {
418
+ prompt: await generateForkPrompt(command.intent, await store.getMessages(command.chatId), project.localPath, command.preset),
419
+ }
420
+ }
421
+
422
+ case "chat.generateMergePrompt": {
423
+ if (!command.chatIds || command.chatIds.length < 1) {
424
+ throw new Error("At least 1 session is required for merge")
425
+ }
426
+ const firstChat = store.getChat(command.chatIds[0]!)
427
+ if (!firstChat) {
428
+ throw new Error(`Chat not found: ${command.chatIds[0]}`)
429
+ }
430
+ const mergeProject = store.getProject(firstChat.workspaceId)
431
+ if (!mergeProject) {
432
+ throw new Error("Project not found")
433
+ }
434
+ const sessions = await Promise.all(command.chatIds.map(async (chatId) => {
435
+ const chat = store.getChat(chatId)
436
+ if (!chat) {
437
+ throw new Error(`Chat not found: ${chatId}`)
438
+ }
439
+ return { chatId, entries: await store.getMessages(chatId) }
440
+ }))
441
+ return {
442
+ prompt: await generateMergePrompt(command.intent, sessions, mergeProject.localPath, command.preset),
443
+ }
444
+ }
445
+
446
+ case "terminal.create": {
447
+ const project = store.getProject(command.workspaceId)
448
+ if (!project) {
449
+ throw new Error("Project not found")
450
+ }
451
+ return terminals.createTerminal({
452
+ workspacePath: project.localPath,
453
+ terminalId: command.terminalId,
454
+ cols: command.cols,
455
+ rows: command.rows,
456
+ scrollback: command.scrollback,
457
+ })
458
+ }
459
+
460
+ case "terminal.input": {
461
+ terminals.write(command.terminalId, command.data)
462
+ return undefined
463
+ }
464
+
465
+ case "terminal.resize": {
466
+ terminals.resize(command.terminalId, command.cols, command.rows)
467
+ return undefined
468
+ }
469
+
470
+ case "terminal.close": {
471
+ terminals.close(command.terminalId)
472
+ return undefined
473
+ }
474
+
475
+ case "chat.getMessages": {
476
+ return await store.getMessages(command.chatId, {
477
+ offset: command.offset,
478
+ limit: command.limit,
479
+ })
480
+ }
481
+
482
+ case "chat.getRenderUnits": {
483
+ const entries = await store.getMessages(command.chatId, {
484
+ offset: command.offset,
485
+ limit: command.limit,
486
+ })
487
+ return deriveTranscriptRenderUnits(entries, command.isLoading ? "running" : undefined)
488
+ }
489
+
490
+ case "chat.getSessionRuntime": {
491
+ const chat = store.getChat(command.chatId)
492
+ if (!chat?.sessionToken || !chat.provider) {
493
+ return { runtime: null }
494
+ }
495
+ const project = store.getProject(chat.workspaceId)
496
+ if (!project) {
497
+ return { runtime: null }
498
+ }
499
+ return {
500
+ runtime: await inspectSessionRuntime(chat.sessionToken, chat.provider, project.localPath),
501
+ }
502
+ }
503
+
504
+ case "chat.getRepoStatus": {
505
+ const chat = store.getChat(command.chatId)
506
+ if (!chat) {
507
+ return { repoStatus: null }
508
+ }
509
+ const project = store.getProject(chat.workspaceId)
510
+ if (!project) {
511
+ return { repoStatus: null }
512
+ }
513
+ return {
514
+ repoStatus: await readRepoStatus(project.localPath),
515
+ }
516
+ }
517
+
518
+ case "chat.getMessageCount": {
519
+ return {
520
+ messageCount: await store.getMessageCount(command.chatId),
521
+ }
522
+ }
523
+
524
+ case "chat.getExternalSessionMessages": {
525
+ const chat = store.getChat(command.parentChatId)
526
+ if (!chat?.provider) {
527
+ return []
528
+ }
529
+ const project = store.getProject(chat.workspaceId)
530
+ if (!project) {
531
+ return []
532
+ }
533
+ return await readSessionTranscript(command.sessionId, chat.provider, project.localPath)
534
+ }
535
+
536
+ case "snapshot.subscribe": {
537
+ publisher.addSubscription(command.subscriptionId, command.topic)
538
+ if (command.topic.type === "local-workspaces") {
539
+ await refreshDiscovery()
540
+ }
541
+ return await publisher.getSnapshot(command.topic)
542
+ }
543
+
544
+ case "snapshot.unsubscribe": {
545
+ publisher.removeSubscription(command.subscriptionId)
546
+ return undefined
547
+ }
548
+
549
+ case "workspace.todo.add": {
550
+ await store.addTodo(command.workspaceId, command.todoId, command.description, command.priority ?? "normal", command.createdBy ?? "user")
551
+ return { ok: true }
552
+ }
553
+ case "workspace.todo.claim": {
554
+ await store.claimTodo(command.workspaceId, command.todoId, command.sessionId)
555
+ return { ok: true }
556
+ }
557
+ case "workspace.todo.complete": {
558
+ await store.completeTodo(command.workspaceId, command.todoId, command.outputs)
559
+ return { ok: true }
560
+ }
561
+ case "workspace.todo.abandon": {
562
+ await store.abandonTodo(command.workspaceId, command.todoId)
563
+ return { ok: true }
564
+ }
565
+ case "workspace.claim.create": {
566
+ await store.createClaim(command.workspaceId, command.claimId, command.intent, command.files, command.sessionId)
567
+ return { ok: true }
568
+ }
569
+ case "workspace.claim.release": {
570
+ await store.releaseClaim(command.workspaceId, command.claimId)
571
+ return { ok: true }
572
+ }
573
+ case "workspace.worktree.create": {
574
+ await store.createWorktree(command.workspaceId, command.worktreeId, command.branch, command.baseBranch ?? "main", "")
575
+ return { ok: true }
576
+ }
577
+ case "workspace.worktree.assign": {
578
+ await store.assignWorktree(command.workspaceId, command.worktreeId, command.sessionId)
579
+ return { ok: true }
580
+ }
581
+ case "workspace.worktree.remove": {
582
+ await store.removeWorktree(command.workspaceId, command.worktreeId)
583
+ return { ok: true }
584
+ }
585
+ case "workspace.rule.set": {
586
+ await store.setRule(command.workspaceId, command.ruleId, command.content, command.setBy)
587
+ return { ok: true }
588
+ }
589
+ case "workspace.rule.remove": {
590
+ await store.removeRule(command.workspaceId, command.ruleId)
591
+ return { ok: true }
592
+ }
593
+
594
+ case "workspace.coordination.snapshot": {
595
+ return deriveCoordinationSnapshot(store.state, command.workspaceId)
596
+ }
597
+
598
+ case "workspace.agent.save": {
599
+ await store.saveAgentConfig(command.workspaceId, command.config.id, command.config)
600
+ if (args.directoryPolicy) {
601
+ args.directoryPolicy.onAgentConfigSaved(command.workspaceId, command.config.id, command.config).catch((err: unknown) => {
602
+ console.warn(`${LOG_PREFIX} agent config save policy error:`, err instanceof Error ? err.message : String(err))
603
+ })
604
+ }
605
+ return { ok: true }
606
+ }
607
+ case "workspace.agent.list": {
608
+ return deriveAgentConfigSnapshot(store.state, command.workspaceId)
609
+ }
610
+ case "workspace.agent.get": {
611
+ return store.state.agentConfigsByWorkspace.get(command.workspaceId)?.get(command.agentId) ?? null
612
+ }
613
+ case "workspace.agent.remove": {
614
+ await store.removeAgentConfig(command.workspaceId, command.agentId)
615
+ if (args.directoryPolicy) {
616
+ args.directoryPolicy.onAgentConfigRemoved(command.workspaceId, command.agentId).catch((err: unknown) => {
617
+ console.warn(`${LOG_PREFIX} agent config remove policy error:`, err instanceof Error ? err.message : String(err))
618
+ })
619
+ }
620
+ return { ok: true }
621
+ }
622
+
623
+ case "workspace.repo.add": {
624
+ if (!args.repoManager) throw new Error("RepoManager not available")
625
+ const info = await args.repoManager.addLocal(command.localPath)
626
+ const repoId = crypto.randomUUID()
627
+ await store.addRepo(repoId, command.workspaceId, command.localPath, info.origin, command.label ?? null, info.branch)
628
+ return { id: repoId, origin: info.origin, branch: info.branch }
629
+ }
630
+
631
+ case "workspace.repo.clone": {
632
+ const repoId = crypto.randomUUID()
633
+ await store.startRepoClone(repoId, command.workspaceId, command.origin, command.targetPath, command.label ?? null)
634
+ if (args.clonePolicy) {
635
+ args.clonePolicy.onRepoCloneStarted(repoId, command.origin, command.targetPath).catch((err: unknown) => {
636
+ console.warn(`${LOG_PREFIX} clone policy error:`, err instanceof Error ? err.message : String(err))
637
+ })
638
+ }
639
+ return { id: repoId }
640
+ }
641
+
642
+ case "workspace.repo.remove": {
643
+ await store.removeRepo(command.repoId, command.workspaceId)
644
+ return { ok: true }
645
+ }
646
+
647
+ case "workspace.repo.label": {
648
+ await store.updateRepoLabel(command.repoId, command.label)
649
+ return { ok: true }
650
+ }
651
+
652
+ case "workspace.repo.status": {
653
+ if (!args.repoManager) throw new Error("RepoManager not available")
654
+ const repo = store.state.reposById.get(command.repoId)
655
+ if (!repo) throw new Error("Repo not found")
656
+ const statusResult = await args.repoManager.status(repo.localPath)
657
+ return statusResult
658
+ }
659
+
660
+ case "workspace.repo.pull": {
661
+ if (!args.repoManager) throw new Error("RepoManager not available")
662
+ const repo = store.state.reposById.get(command.repoId)
663
+ if (!repo) throw new Error("Repo not found")
664
+ const output = await args.repoManager.pull(repo.localPath, command.branch)
665
+ return { output }
666
+ }
667
+
668
+ case "workspace.repo.push": {
669
+ if (!args.repoManager) throw new Error("RepoManager not available")
670
+ const repo = store.state.reposById.get(command.repoId)
671
+ if (!repo) throw new Error("Repo not found")
672
+ const output = await args.repoManager.push(repo.localPath, command.branch)
673
+ return { output }
674
+ }
675
+
676
+ case "workspace.workflow.run": {
677
+ if (!args.workflowStore || !args.workflowEngine) throw new Error("Workflow engine not available")
678
+ const def = await args.workflowStore.get(command.workflowId)
679
+ if (!def) throw new Error(`Workflow ${command.workflowId} not found`)
680
+ const runId = await args.workflowEngine.start(command.workflowId, command.workspaceId, def, command.triggeredBy ?? "user")
681
+ return { status: "started", runId }
682
+ }
683
+
684
+ case "workspace.workflow.cancel": {
685
+ if (!args.workflowEngine) throw new Error("Workflow engine not available")
686
+ await args.workflowEngine.cancel(command.runId, command.workspaceId)
687
+ return { ok: true }
688
+ }
689
+
690
+ case "workspace.workflow.list": {
691
+ if (!args.workflowStore) return { workflows: [] }
692
+ const workflows = await args.workflowStore.list()
693
+ return { workflows }
694
+ }
695
+
696
+ case "workspace.sandbox.create": {
697
+ if (!args.sandboxManager) throw new Error("Sandbox manager not available")
698
+ const workspace = store.state.workspacesById.get(command.workspaceId)
699
+ if (!workspace) throw new Error(`Workspace ${command.workspaceId} not found`)
700
+ const sandboxId = `sb-${command.workspaceId.slice(0, 12)}-${Date.now()}`
701
+ const limits = command.resourceLimits ?? DEFAULT_RESOURCE_LIMITS
702
+ const repos = [...store.state.reposById.values()].filter(r => r.workspaceId === command.workspaceId)
703
+ const containerId = await args.sandboxManager.create(command.workspaceId, {
704
+ repos: repos.map(r => ({ id: r.id, localPath: r.localPath })),
705
+ limits,
706
+ })
707
+ await store.emitSandboxCreated(sandboxId, command.workspaceId, limits)
708
+ try {
709
+ await args.sandboxManager.start(containerId)
710
+ await store.emitSandboxStarted(sandboxId, containerId, args.sandboxManager.getNatsUrl())
711
+ } catch (err: unknown) {
712
+ const msg = err instanceof Error ? err.message : String(err)
713
+ await store.emitSandboxError(sandboxId, msg)
714
+ throw err
715
+ }
716
+ return { status: "created", sandboxId, containerId }
717
+ }
718
+
719
+ case "workspace.sandbox.start": {
720
+ if (!args.sandboxManager) throw new Error("Sandbox manager not available")
721
+ const sandbox = store.state.sandboxByWorkspace.get(command.workspaceId)
722
+ if (!sandbox?.containerId) throw new Error("No sandbox found for workspace")
723
+ await args.sandboxManager.start(sandbox.containerId)
724
+ await store.emitSandboxStarted(sandbox.id, sandbox.containerId, sandbox.natsUrl)
725
+ return { status: "started" }
726
+ }
727
+
728
+ case "workspace.sandbox.stop": {
729
+ if (!args.sandboxManager) throw new Error("Sandbox manager not available")
730
+ const sandbox = store.state.sandboxByWorkspace.get(command.workspaceId)
731
+ if (!sandbox?.containerId) throw new Error("No sandbox found for workspace")
732
+ await args.sandboxManager.stop(sandbox.containerId, command.reason)
733
+ await store.emitSandboxStopped(sandbox.id, command.reason ?? "user_request")
734
+ return { status: "stopped" }
735
+ }
736
+
737
+ case "workspace.sandbox.destroy": {
738
+ if (!args.sandboxManager) throw new Error("Sandbox manager not available")
739
+ const sandbox = store.state.sandboxByWorkspace.get(command.workspaceId)
740
+ if (!sandbox?.containerId) throw new Error("No sandbox found for workspace")
741
+ await args.sandboxManager.destroy(sandbox.containerId)
742
+ await store.emitSandboxDestroyed(sandbox.id)
743
+ return { status: "destroyed" }
744
+ }
745
+
746
+ case "workspace.sandbox.logs": {
747
+ if (!args.sandboxManager) throw new Error("Sandbox manager not available")
748
+ const sandbox = store.state.sandboxByWorkspace.get(command.workspaceId)
749
+ if (!sandbox?.containerId) throw new Error("No sandbox found for workspace")
750
+ const logs = await args.sandboxManager.logs(sandbox.containerId, command.tail)
751
+ return { logs }
752
+ }
753
+
754
+ case "workspace.sandbox.status": {
755
+ if (!args.sandboxManager) throw new Error("Sandbox manager not available")
756
+ const sandbox = store.state.sandboxByWorkspace.get(command.workspaceId)
757
+ if (!sandbox?.containerId) throw new Error("No sandbox found for workspace")
758
+ const inspect = await args.sandboxManager.inspect(sandbox.containerId)
759
+ return { inspect }
760
+ }
761
+
762
+ // --- Runtime management ---
763
+
764
+ case "runtime.list": {
765
+ if (!args.runtimeRegistry) throw new Error("Runtime registry not available")
766
+ return args.runtimeRegistry.getSnapshot()
767
+ }
768
+
769
+ case "runtime.detect": {
770
+ if (!args.runtimeRegistry) throw new Error("Runtime registry not available")
771
+ const detectOpts = DETECT_OPTIONS[command.provider]
772
+ if (!detectOpts) throw new Error(`Unknown provider: ${command.provider}`)
773
+ const result = await args.runtimeRegistry.detectSystemRuntime(command.provider, detectOpts)
774
+ void args.runtimeRegistry.probeCapabilities(command.provider)
775
+ return result
776
+ }
777
+
778
+ case "runtime.install": {
779
+ if (!args.runtimeRegistry) throw new Error("Runtime registry not available")
780
+ const installOpts = INSTALL_OPTIONS[command.provider]
781
+ if (!installOpts) throw new Error(`Unknown provider: ${command.provider}`)
782
+ return args.runtimeRegistry.installManaged(command.provider, {
783
+ ...installOpts,
784
+ version: command.version,
785
+ })
786
+ }
787
+
788
+ case "runtime.remove": {
789
+ if (!args.runtimeRegistry) throw new Error("Runtime registry not available")
790
+ return args.runtimeRegistry.removeManaged(command.provider, command.version)
791
+ }
792
+
793
+ case "runtime.health": {
794
+ if (!args.runtimeRegistry) throw new Error("Runtime registry not available")
795
+ return args.runtimeRegistry.healthCheck(command.provider, command.version)
796
+ }
797
+
798
+ // --- Provider profiles ---
799
+
800
+ case "profile.list": {
801
+ return {
802
+ profiles: [...store.state.providerProfiles.values()],
803
+ }
804
+ }
805
+
806
+ case "profile.save": {
807
+ await store.saveProviderProfile(command.profile.id, command.profile)
808
+ return { ok: true }
809
+ }
810
+
811
+ case "profile.remove": {
812
+ await store.removeProviderProfile(command.profileId)
813
+ return { ok: true }
814
+ }
815
+
816
+ case "profile.resolve": {
817
+ const record = store.state.providerProfiles.get(command.profileId)
818
+ if (!record) throw new Error(`Profile not found: ${command.profileId}`)
819
+ const override = store.state.workspaceProfileOverrides.get(command.workspaceId)?.get(command.profileId)
820
+ return { profile: resolveProfile(record.profile, override?.overrides) }
821
+ }
822
+
823
+ case "workspace.profile.override.set": {
824
+ await store.setWorkspaceProfileOverride(command.workspaceId, command.profileId, command.overrides)
825
+ return { ok: true }
826
+ }
827
+
828
+ case "workspace.profile.override.remove": {
829
+ await store.removeWorkspaceProfileOverride(command.workspaceId, command.profileId)
830
+ return { ok: true }
831
+ }
832
+
833
+ // --- Extension preferences ---
834
+
835
+ case "extension.preference.list": {
836
+ return {
837
+ preferences: [...store.state.extensionPreferences.values()],
838
+ }
839
+ }
840
+
841
+ case "extension.preference.set": {
842
+ await store.setExtensionPreference(command.extensionId, command.enabled)
843
+ return { ok: true }
844
+ }
845
+
846
+ // --- Runner team (US-RTN) ---
847
+
848
+ case "team.member.list": {
849
+ return {
850
+ members: [...store.state.teamMembers.values()],
851
+ }
852
+ }
853
+
854
+ case "team.member.save": {
855
+ await store.saveTeamMember(command.member)
856
+ return { ok: true }
857
+ }
858
+
859
+ case "team.member.remove": {
860
+ await store.removeTeamMember(command.memberId)
861
+ return { ok: true }
862
+ }
863
+
864
+ case "runner.label.set": {
865
+ await store.setRunnerLabel(command.runnerId, command.name, command.memberId)
866
+ return { ok: true }
867
+ }
868
+
869
+ case "runner.label.remove": {
870
+ await store.removeRunnerLabel(command.runnerId)
871
+ return { ok: true }
872
+ }
873
+
874
+ default: {
875
+ throw new Error("Unknown command type")
876
+ }
877
+ }
878
+ }
879
+
880
+ // Process messages in the background
881
+ void (async () => {
882
+ await Promise.all(subs.map(async (sub) => {
883
+ for await (const msg of sub) {
884
+ try {
885
+ await handleMessage(msg)
886
+ } catch (error) {
887
+ const message = error instanceof Error ? error.message : String(error)
888
+ console.warn(LOG_PREFIX, `Unhandled error in command responder: ${message}`)
889
+ }
890
+ }
891
+ }))
892
+ })()
893
+
894
+ return {
895
+ dispose() {
896
+ for (const sub of subs) {
897
+ sub.unsubscribe()
898
+ }
899
+ },
900
+ }
901
+ }
902
+
903
+ async function readLocalFilePreview(localPath: string) {
904
+ const resolvedPath = resolveLocalPath(localPath)
905
+ const info = await stat(resolvedPath).catch(() => null)
906
+
907
+ if (!info) {
908
+ throw new Error(`Path not found: ${resolvedPath}`)
909
+ }
910
+ if (!info.isFile()) {
911
+ throw new Error(`Path is not a file: ${resolvedPath}`)
912
+ }
913
+ if (info.size > MAX_LOCAL_FILE_PREVIEW_BYTES) {
914
+ throw new Error(`File too large to preview: ${resolvedPath}`)
915
+ }
916
+
917
+ try {
918
+ return {
919
+ localPath: resolvedPath,
920
+ content: await Bun.file(resolvedPath).text(),
921
+ }
922
+ } catch (error: unknown) {
923
+ throw new Error(`Failed to read file: ${resolvedPath}: ${error instanceof Error ? error.message : String(error)}`)
924
+ }
925
+ }