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,194 @@
1
+ /**
2
+ * NATS daemon — callout mode (Stage A, PR1).
3
+ *
4
+ * Spawns the bundled nats-server binary directly (via resolveBinary()) with a
5
+ * self-generated auth-callout config, discovers the TCP + WS ports from stderr,
6
+ * starts the CalloutResponder as the auth-service connection, then writes the
7
+ * JSON handshake to stdout (same shape as nats-daemon.ts so NatsDaemonManager
8
+ * can parse it).
9
+ *
10
+ * Invoked by NatsDaemonManager when NATS_AUTH_MODE=callout.
11
+ * NOT used in token mode — that path stays in nats-daemon.ts unchanged.
12
+ */
13
+
14
+ import { spawn } from "node:child_process"
15
+ import { mkdtempSync, writeFileSync, rmSync } from "node:fs"
16
+ import { join } from "node:path"
17
+ import { tmpdir } from "node:os"
18
+ import { resolveBinary } from "@lagz0ne/nats-embedded"
19
+ import { ensureCalloutKeys } from "./auth-callout/keys"
20
+ import { buildCalloutConfig } from "./auth-callout/callout-config"
21
+ import { CalloutResponder } from "./auth-callout/responder"
22
+
23
+ const LOG_PREFIX = "[nats-daemon-callout]"
24
+
25
+ const host = process.env.NATS_HOST ?? "127.0.0.1"
26
+ const port = process.env.NATS_PORT ? Number(process.env.NATS_PORT) : -1
27
+ const wsPort = process.env.NATS_WS_PORT ? Number(process.env.NATS_WS_PORT) : -1
28
+ const storeDir = process.env.NATS_STORE_DIR
29
+ const dataDir = process.env.NATS_DATA_DIR
30
+ // Opt-in localhost-only HTTP monitoring for diagnostics (/connz, /subsz, /varz).
31
+ const monitorPort = process.env.NATS_MONITOR_PORT ? Number(process.env.NATS_MONITOR_PORT) : undefined
32
+
33
+ if (!dataDir) {
34
+ console.error(LOG_PREFIX, "NATS_DATA_DIR is required in callout mode (key storage)")
35
+ process.exit(1)
36
+ }
37
+
38
+ // ── 1. Ensure signing keys ────────────────────────────────────────────────────
39
+
40
+ const keys = await ensureCalloutKeys(dataDir)
41
+ console.warn(LOG_PREFIX, `Callout account public key: ${keys.accountPublicKey}`)
42
+ console.warn(LOG_PREFIX, `Auth-service user public key: ${keys.authUserPublicKey}`)
43
+
44
+ // ── 2. Generate config and write to temp file ─────────────────────────────────
45
+
46
+ const configContent = buildCalloutConfig({
47
+ host,
48
+ port,
49
+ wsPort,
50
+ storeDir,
51
+ monitorPort,
52
+ accountPublicKey: keys.accountPublicKey,
53
+ authUserPublicKey: keys.authUserPublicKey,
54
+ })
55
+
56
+ const configDir = mkdtempSync(join(tmpdir(), "nats-callout-"))
57
+ const configPath = join(configDir, "callout.conf")
58
+ writeFileSync(configPath, configContent)
59
+
60
+ // ── 3. Spawn binary directly, parse ports from stderr ─────────────────────────
61
+
62
+ const binaryPath = resolveBinary()
63
+ console.warn(LOG_PREFIX, `Spawning binary: ${binaryPath}`)
64
+
65
+ const child = spawn(binaryPath, ["-c", configPath], {
66
+ stdio: ["ignore", "pipe", "pipe"],
67
+ })
68
+
69
+ interface PortResult {
70
+ tcpPort: number
71
+ wsPort: number
72
+ }
73
+
74
+ const portResult = await new Promise<PortResult>((resolve, reject) => {
75
+ const timeout = setTimeout(() => {
76
+ child.kill("SIGKILL")
77
+ reject(new Error("nats-server (callout mode) did not start within 10s"))
78
+ }, 10_000)
79
+
80
+ child.on("error", (err) => {
81
+ clearTimeout(timeout)
82
+ reject(err)
83
+ })
84
+
85
+ child.on("exit", (code) => {
86
+ clearTimeout(timeout)
87
+ reject(new Error(`nats-server exited with code ${code} before ready`))
88
+ })
89
+
90
+ let tcpPort: number | null = null
91
+ let wsPort: number | null = null
92
+ let buffer = ""
93
+
94
+ const onStderr = (chunk: Buffer) => {
95
+ const text = chunk.toString()
96
+ buffer += text
97
+ const lines = buffer.split("\n")
98
+ buffer = lines.pop() ?? ""
99
+
100
+ for (const line of lines) {
101
+ // "Listening for client connections on host:port"
102
+ const tcpMatch = line.match(/Listening for client connections on .+:(\d+)/)
103
+ if (tcpMatch) tcpPort = Number(tcpMatch[1])
104
+
105
+ // "Listening for websocket clients on host:port"
106
+ const wsMatch = line.match(/Listening for websocket clients on .+:(\d+)/)
107
+ if (wsMatch) wsPort = Number(wsMatch[1])
108
+
109
+ if (tcpPort !== null && wsPort !== null) {
110
+ clearTimeout(timeout)
111
+ child.removeAllListeners("exit")
112
+ child.stderr.removeListener("data", onStderr)
113
+ resolve({ tcpPort, wsPort })
114
+ return
115
+ }
116
+ }
117
+ }
118
+
119
+ child.stderr.on("data", onStderr)
120
+ })
121
+
122
+ const natsUrl = `nats://${host}:${portResult.tcpPort}`
123
+ const wsUrl = `ws://${host}:${portResult.wsPort}`
124
+
125
+ // Observability (decision 0012): forward nats-server's own runtime logs onward
126
+ // (to this process's stderr, which the daemon manager pipes into VictoriaLogs).
127
+ // Previously the stderr listener was removed after port parsing and stdout was
128
+ // discarded, hiding the entire NATS layer — slow-consumer drops, per-connection
129
+ // delivery errors, auth violations, and disconnects. Continuously draining also
130
+ // prevents the pipe buffer from backing up.
131
+ function forwardNatsServerOutput(stream: NodeJS.ReadableStream | null): void {
132
+ if (!stream) return
133
+ let buf = ""
134
+ stream.on("data", (chunk: Buffer) => {
135
+ buf += chunk.toString()
136
+ const lines = buf.split("\n")
137
+ buf = lines.pop() ?? ""
138
+ for (const line of lines) {
139
+ if (line.trim()) console.warn("[nats-server]", line)
140
+ }
141
+ })
142
+ }
143
+ forwardNatsServerOutput(child.stdout)
144
+ forwardNatsServerOutput(child.stderr)
145
+
146
+ console.warn(LOG_PREFIX, `nats-server ready — url: ${natsUrl}, ws: ${wsUrl}`)
147
+
148
+ // ── 4. Start the callout responder ────────────────────────────────────────────
149
+
150
+ const responder = new CalloutResponder({
151
+ natsUrl,
152
+ authUserKp: keys.authUserKp,
153
+ accountKp: keys.accountKp,
154
+ accountPublicKey: keys.accountPublicKey,
155
+ accountName: "CALLOUT_ACCOUNT",
156
+ tokenSecret: keys.tokenSecret,
157
+ })
158
+
159
+ await responder.start()
160
+ console.warn(LOG_PREFIX, "Callout responder started")
161
+
162
+ // ── 5. Emit handshake JSON to stdout (same shape as nats-daemon.ts) ───────────
163
+
164
+ const info = {
165
+ url: natsUrl,
166
+ wsUrl,
167
+ wsPort: portResult.wsPort,
168
+ pid: process.pid,
169
+ }
170
+
171
+ process.stdout.write(JSON.stringify(info) + "\n")
172
+
173
+ // ── 6. Lifecycle ──────────────────────────────────────────────────────────────
174
+
175
+ async function shutdown(signal: string) {
176
+ console.warn(LOG_PREFIX, `Received ${signal}, shutting down`)
177
+ await responder.stop()
178
+ child.kill("SIGTERM")
179
+ try {
180
+ rmSync(configDir, { recursive: true })
181
+ } catch { /* best-effort */ }
182
+ process.exit(0)
183
+ }
184
+
185
+ process.on("SIGTERM", () => void shutdown("SIGTERM"))
186
+ process.on("SIGINT", () => void shutdown("SIGINT"))
187
+
188
+ // Keep the process alive until nats-server exits.
189
+ await new Promise<void>((resolve) => {
190
+ child.on("exit", () => resolve())
191
+ })
192
+
193
+ // Clean up config dir on abnormal exit.
194
+ try { rmSync(configDir, { recursive: true }) } catch { /* best-effort */ }
@@ -0,0 +1,77 @@
1
+ import { describe, test, expect, afterEach } from "bun:test"
2
+ import { connect } from "@nats-io/transport-node"
3
+
4
+ function createDaemonTestEnv(token: string): NodeJS.ProcessEnv {
5
+ const {
6
+ NATS_DATA_DIR: _natsDataDir,
7
+ NATS_URL: _natsUrl,
8
+ NATS_MODE: _natsMode,
9
+ NATS_WS_PORT: _natsWsPort,
10
+ NATS_PORT: _natsPort,
11
+ NATS_STORE_DIR: _natsStoreDir,
12
+ NATS_HTTP_PORT: _natsHttpPort,
13
+ ...spawnEnv
14
+ } = process.env
15
+
16
+ return {
17
+ ...spawnEnv,
18
+ NATS_TOKEN: token,
19
+ }
20
+ }
21
+
22
+ describe("nats-daemon", () => {
23
+ let proc: ReturnType<typeof Bun.spawn> | null = null
24
+
25
+ afterEach(async () => {
26
+ if (proc) {
27
+ proc.kill("SIGTERM")
28
+ await proc.exited
29
+ proc = null
30
+ }
31
+ })
32
+
33
+ test("starts and outputs JSON with url, wsUrl, wsPort, pid", async () => {
34
+ const token = "test-token-" + Date.now()
35
+ proc = Bun.spawn(["bun", "run", "src/nats/nats-daemon.ts"], {
36
+ env: createDaemonTestEnv(token),
37
+ stdio: ["ignore", "pipe", "inherit"],
38
+ })
39
+ const reader = proc.stdout.getReader()
40
+ const { value } = await reader.read()
41
+ const info = JSON.parse(new TextDecoder().decode(value))
42
+ expect(info).toHaveProperty("url")
43
+ expect(info).toHaveProperty("wsUrl")
44
+ expect(info).toHaveProperty("wsPort")
45
+ expect(info).toHaveProperty("pid")
46
+ expect(typeof info.pid).toBe("number")
47
+ })
48
+
49
+ test("accepts NATS connections with token auth", async () => {
50
+ const token = "test-token-" + Date.now()
51
+ proc = Bun.spawn(["bun", "run", "src/nats/nats-daemon.ts"], {
52
+ env: createDaemonTestEnv(token),
53
+ stdio: ["ignore", "pipe", "inherit"],
54
+ })
55
+ const reader = proc.stdout.getReader()
56
+ const { value } = await reader.read()
57
+ const info = JSON.parse(new TextDecoder().decode(value))
58
+
59
+ const nc = await connect({ servers: info.url, token })
60
+ expect(nc).toBeDefined()
61
+ await nc.drain()
62
+ })
63
+
64
+ test("shuts down cleanly on SIGTERM", async () => {
65
+ proc = Bun.spawn(["bun", "run", "src/nats/nats-daemon.ts"], {
66
+ env: createDaemonTestEnv("test"),
67
+ stdio: ["ignore", "pipe", "inherit"],
68
+ })
69
+ const reader = proc.stdout.getReader()
70
+ await reader.read() // wait for startup
71
+
72
+ proc.kill("SIGTERM")
73
+ const exitCode = await proc.exited
74
+ expect(exitCode).toBe(0)
75
+ proc = null // already exited
76
+ })
77
+ })
@@ -0,0 +1,50 @@
1
+ import { NatsServer } from "@lagz0ne/nats-embedded"
2
+ import { ensureToken } from "./nats-token"
3
+
4
+ const LOG_PREFIX = "[nats-daemon]"
5
+
6
+ const host = process.env.NATS_HOST ?? "127.0.0.1"
7
+ const port = process.env.NATS_PORT ? Number(process.env.NATS_PORT) : -1
8
+ const wsPort = process.env.NATS_WS_PORT ? Number(process.env.NATS_WS_PORT) : undefined
9
+ const httpPort = process.env.NATS_HTTP_PORT ? Number(process.env.NATS_HTTP_PORT) : undefined
10
+ const storeDir = process.env.NATS_STORE_DIR
11
+ const dataDir = process.env.NATS_DATA_DIR
12
+
13
+ // Token resolution: NATS_DATA_DIR (file-based) > NATS_TOKEN (env) > none
14
+ const token = dataDir
15
+ ? await ensureToken(dataDir)
16
+ : process.env.NATS_TOKEN || undefined
17
+
18
+ const server = await NatsServer.start({
19
+ host,
20
+ port,
21
+ websocket: wsPort ? { port: wsPort, no_tls: true } : true,
22
+ jetstream: true,
23
+ ...(httpPort ? { httpPort } : {}),
24
+ ...(storeDir ? { storeDir } : {}),
25
+ ...(token ? { token } : {}),
26
+ })
27
+
28
+ if (!server.wsUrl || !server.wsPort) {
29
+ console.warn(LOG_PREFIX, "NATS server started without WebSocket support")
30
+ await server.stop()
31
+ process.exit(1)
32
+ }
33
+
34
+ const info = {
35
+ url: server.url,
36
+ wsUrl: server.wsUrl,
37
+ wsPort: server.wsPort,
38
+ pid: process.pid,
39
+ }
40
+
41
+ process.stdout.write(JSON.stringify(info) + "\n")
42
+
43
+ process.on("SIGTERM", async () => {
44
+ console.warn(LOG_PREFIX, "Received SIGTERM, shutting down")
45
+ await server.stop()
46
+ process.exit(0)
47
+ })
48
+
49
+ // Keep process alive until NATS server exits
50
+ await server.exited
@@ -0,0 +1,61 @@
1
+ import { describe, test, expect, beforeEach, afterEach } from "bun:test"
2
+ import { ensureToken, readToken } from "./nats-token"
3
+ import { mkdtempSync, rmSync } from "node:fs"
4
+ import { join } from "node:path"
5
+ import { tmpdir } from "node:os"
6
+
7
+ describe("nats-token", () => {
8
+ let dataDir: string
9
+
10
+ beforeEach(() => {
11
+ dataDir = mkdtempSync(join(tmpdir(), "nats-token-test-"))
12
+ })
13
+
14
+ afterEach(() => {
15
+ rmSync(dataDir, { recursive: true, force: true })
16
+ })
17
+
18
+ describe("ensureToken", () => {
19
+ test("generates and persists a token when none exists", async () => {
20
+ const token = await ensureToken(dataDir)
21
+ expect(token).toBeString()
22
+ expect(token.length).toBeGreaterThan(20)
23
+
24
+ // File should exist now
25
+ const file = Bun.file(join(dataDir, "nats.token"))
26
+ expect(await file.exists()).toBe(true)
27
+ expect((await file.text()).trim()).toBe(token)
28
+ })
29
+
30
+ test("returns existing token on subsequent calls", async () => {
31
+ const first = await ensureToken(dataDir)
32
+ const second = await ensureToken(dataDir)
33
+ expect(second).toBe(first)
34
+ })
35
+
36
+ test("creates data directory if it does not exist", async () => {
37
+ const nested = join(dataDir, "sub", "deep")
38
+ const token = await ensureToken(nested)
39
+ expect(token).toBeString()
40
+ expect(token.length).toBeGreaterThan(20)
41
+ })
42
+ })
43
+
44
+ describe("readToken", () => {
45
+ test("reads token written by ensureToken", async () => {
46
+ const written = await ensureToken(dataDir)
47
+ const read = await readToken(dataDir)
48
+ expect(read).toBe(written)
49
+ })
50
+
51
+ test("throws when token file does not exist", async () => {
52
+ expect(readToken(dataDir)).rejects.toThrow()
53
+ })
54
+
55
+ test("trims whitespace from token file", async () => {
56
+ await Bun.write(join(dataDir, "nats.token"), " my-token-value \n")
57
+ const token = await readToken(dataDir)
58
+ expect(token).toBe("my-token-value")
59
+ })
60
+ })
61
+ })
@@ -0,0 +1,59 @@
1
+ import { join } from "node:path"
2
+ import { mkdirSync } from "node:fs"
3
+
4
+ const TOKEN_FILE = "nats.token"
5
+
6
+ /** Generate a cryptographically random token string. */
7
+ function generateToken(): string {
8
+ const bytes = new Uint8Array(32)
9
+ crypto.getRandomValues(bytes)
10
+ return Buffer.from(bytes).toString("base64url")
11
+ }
12
+
13
+ /**
14
+ * Ensure a NATS auth token exists in `dataDir/nats.token`.
15
+ * If missing, generates one with atomic write (tmp + rename).
16
+ * Called by the NATS daemon only (single owner).
17
+ */
18
+ export async function ensureToken(dataDir: string): Promise<string> {
19
+ const tokenPath = join(dataDir, TOKEN_FILE)
20
+ const file = Bun.file(tokenPath)
21
+
22
+ if (await file.exists()) {
23
+ const existing = (await file.text()).trim()
24
+ if (existing.length > 0) return existing
25
+ }
26
+
27
+ mkdirSync(dataDir, { recursive: true })
28
+
29
+ const token = generateToken()
30
+ const tmpPath = `${tokenPath}.tmp.${process.pid}`
31
+ await Bun.write(tmpPath, token + "\n")
32
+
33
+ // Atomic rename — prevents partial reads by other processes
34
+ const { renameSync } = await import("node:fs")
35
+ renameSync(tmpPath, tokenPath)
36
+
37
+ return token
38
+ }
39
+
40
+ /**
41
+ * Read the NATS auth token from `dataDir/nats.token`.
42
+ * Called by server and runner processes.
43
+ * Throws if the file does not exist (daemon not started yet).
44
+ */
45
+ export async function readToken(dataDir: string): Promise<string> {
46
+ const tokenPath = join(dataDir, TOKEN_FILE)
47
+ const file = Bun.file(tokenPath)
48
+
49
+ if (!(await file.exists())) {
50
+ throw new Error(`NATS token file not found: ${tokenPath} — is the NATS daemon running?`)
51
+ }
52
+
53
+ const content = (await file.text()).trim()
54
+ if (content.length === 0) {
55
+ throw new Error(`NATS token file is empty: ${tokenPath}`)
56
+ }
57
+
58
+ return content
59
+ }
@@ -0,0 +1,134 @@
1
+ import { describe, test, expect, afterEach, beforeEach } from "bun:test"
2
+ import { mkdtempSync, rmSync } from "node:fs"
3
+ import { join } from "node:path"
4
+ import { tmpdir } from "node:os"
5
+ import { NatsServer } from "@lagz0ne/nats-embedded"
6
+ import { connect, type NatsConnection } from "@nats-io/transport-node"
7
+ import { EventStore } from "../server/event-store"
8
+ import { registerCommandResponders } from "../server/nats-responders"
9
+ import { NatsCoordinationClient } from "./nats-coordination-client"
10
+ import { createCoordinationMcpServer } from "../server/coordination-mcp"
11
+
12
+ describe("coordination MCP via runner NATS client", () => {
13
+ let natsServer: NatsServer
14
+ let serverNc: NatsConnection
15
+ let clientNc: NatsConnection
16
+ let store: EventStore
17
+ let tmpDir: string
18
+ let dispose: (() => void) | null = null
19
+
20
+ beforeEach(async () => {
21
+ tmpDir = mkdtempSync(join(tmpdir(), "coord-mcp-int-test-"))
22
+ natsServer = await NatsServer.start()
23
+ serverNc = await connect({ servers: natsServer.url })
24
+ clientNc = await connect({ servers: natsServer.url })
25
+
26
+ store = new EventStore(tmpDir)
27
+ await store.initialize()
28
+
29
+ const { dispose: d } = registerCommandResponders({
30
+ nc: serverNc,
31
+ store,
32
+ agent: {
33
+ send: async () => ({ chatId: "c" }),
34
+ cancel: async () => {},
35
+ disposeChat: async () => {},
36
+ respondTool: async () => {},
37
+ getActiveStatuses: () => new Map(),
38
+ } as never,
39
+ terminals: {
40
+ createTerminal: () => ({ terminalId: "t1", title: "bash", cwd: "/tmp", shell: "/bin/bash", cols: 80, rows: 24, scrollback: 0, serializedState: "", status: "running", exitCode: null }),
41
+ write: () => {},
42
+ resize: () => {},
43
+ close: () => {},
44
+ closeByCwd: () => {},
45
+ getSnapshot: () => null,
46
+ onEvent: () => () => {},
47
+ } as never,
48
+ refreshDiscovery: async () => [],
49
+ updateManager: null,
50
+ publisher: {
51
+ addSubscription: () => {},
52
+ removeSubscription: () => {},
53
+ getSnapshot: async () => null,
54
+ broadcastSnapshots: async () => {},
55
+ publishChatMessage: () => {},
56
+ refreshSessions: async () => {},
57
+ dispose: () => {},
58
+ } as never,
59
+ onStateChange: () => {},
60
+ directoryPolicy: null,
61
+ repoManager: null,
62
+ clonePolicy: null,
63
+ })
64
+ dispose = d
65
+ await serverNc.flush()
66
+ })
67
+
68
+ afterEach(async () => {
69
+ dispose?.()
70
+ dispose = null
71
+ await clientNc?.drain()
72
+ await serverNc?.drain()
73
+ await natsServer?.stop()
74
+ rmSync(tmpDir, { recursive: true, force: true })
75
+ })
76
+
77
+ test("NatsCoordinationClient can add a todo via NATS and retrieve via getSnapshot", async () => {
78
+ const project = await store.openProject("/tmp/test-coord-mcp-runner", "Test")
79
+ const workspaceId = project.id
80
+
81
+ const client = new NatsCoordinationClient(clientNc)
82
+
83
+ await client.addTodo(workspaceId, "t-1", "Implement feature X", "high", "session-runner")
84
+
85
+ // Verify via direct store (server-side truth)
86
+ const serverSnapshot = await store.state.coordinationByWorkspace.get(workspaceId)
87
+ expect(serverSnapshot?.todos.get("t-1")?.description).toBe("Implement feature X")
88
+
89
+ // Verify via getSnapshot (NATS round-trip)
90
+ const snapshot = await client.getSnapshot(workspaceId)
91
+ expect(snapshot.todos).toHaveLength(1)
92
+ expect(snapshot.todos[0].description).toBe("Implement feature X")
93
+ expect(snapshot.todos[0].status).toBe("open")
94
+ })
95
+
96
+ test("createCoordinationMcpServer works with NatsCoordinationClient", () => {
97
+ const client = new NatsCoordinationClient(clientNc)
98
+ const mcpServer = createCoordinationMcpServer(client)
99
+ // The MCP server should be defined with tools
100
+ expect(mcpServer).toBeDefined()
101
+ expect(typeof mcpServer).toBe("object")
102
+ })
103
+
104
+ test("NatsCoordinationClient full coordination lifecycle via NATS", async () => {
105
+ const project = await store.openProject("/tmp/test-coord-lifecycle", "Lifecycle")
106
+ const workspaceId = project.id
107
+
108
+ const client = new NatsCoordinationClient(clientNc)
109
+
110
+ // Add and claim a todo
111
+ await client.addTodo(workspaceId, "t-1", "Build feature", "normal", "session-a")
112
+ await client.claimTodo(workspaceId, "t-1", "session-b")
113
+
114
+ let snapshot = await client.getSnapshot(workspaceId)
115
+ expect(snapshot.todos[0].status).toBe("claimed")
116
+
117
+ // Complete the todo
118
+ await client.completeTodo(workspaceId, "t-1", ["feature.ts"])
119
+ snapshot = await client.getSnapshot(workspaceId)
120
+ expect(snapshot.todos[0].status).toBe("complete")
121
+
122
+ // Create a file claim
123
+ await client.createClaim(workspaceId, "c-1", "Refactor auth", ["src/auth.ts"], "session-a")
124
+ snapshot = await client.getSnapshot(workspaceId)
125
+ expect(snapshot.claims).toHaveLength(1)
126
+ expect(snapshot.claims[0].status).toBe("active")
127
+
128
+ // Set a rule
129
+ await client.setRule(workspaceId, "r-1", "No any types", "session-a")
130
+ snapshot = await client.getSnapshot(workspaceId)
131
+ expect(snapshot.rules).toHaveLength(1)
132
+ expect(snapshot.rules[0].content).toBe("No any types")
133
+ })
134
+ })
@@ -0,0 +1,49 @@
1
+ import { describe, test, expect, mock } from "bun:test"
2
+ import { NatsCoordinationClient } from "./nats-coordination-client"
3
+
4
+ describe("NatsCoordinationClient", () => {
5
+ test("addTodo sends NATS command and returns", async () => {
6
+ const mockNc = {
7
+ request: mock(() => Promise.resolve({
8
+ data: new TextEncoder().encode(JSON.stringify({ ok: true, result: { ok: true } })),
9
+ })),
10
+ }
11
+ const client = new NatsCoordinationClient(mockNc as any)
12
+
13
+ await client.addTodo("proj-1", "todo-1", "Fix bug", "normal", "session-1")
14
+
15
+ expect(mockNc.request).toHaveBeenCalled()
16
+ const callArgs = mockNc.request.mock.calls[0]
17
+ expect(callArgs[0]).toBe("runtime.cmd.workspace.todo.add")
18
+ })
19
+
20
+ test("state.coordinationByWorkspace returns empty map initially", () => {
21
+ const client = new NatsCoordinationClient({} as any)
22
+ expect(client.state.coordinationByWorkspace.size).toBe(0)
23
+ })
24
+
25
+ test("throws when server returns error", async () => {
26
+ const mockNc = {
27
+ request: mock(() => Promise.resolve({
28
+ data: new TextEncoder().encode(JSON.stringify({ ok: false, error: "Project not found" })),
29
+ })),
30
+ }
31
+ const client = new NatsCoordinationClient(mockNc as any)
32
+ await expect(client.addTodo("proj-1", "todo-1", "Fix bug", "normal", "session-1")).rejects.toThrow("Project not found")
33
+ })
34
+
35
+ test("implements CoordinationStore interface", () => {
36
+ const client = new NatsCoordinationClient({} as any)
37
+ expect(typeof client.addTodo).toBe("function")
38
+ expect(typeof client.claimTodo).toBe("function")
39
+ expect(typeof client.completeTodo).toBe("function")
40
+ expect(typeof client.abandonTodo).toBe("function")
41
+ expect(typeof client.createClaim).toBe("function")
42
+ expect(typeof client.releaseClaim).toBe("function")
43
+ expect(typeof client.createWorktree).toBe("function")
44
+ expect(typeof client.assignWorktree).toBe("function")
45
+ expect(typeof client.removeWorktree).toBe("function")
46
+ expect(typeof client.setRule).toBe("function")
47
+ expect(typeof client.removeRule).toBe("function")
48
+ })
49
+ })