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,212 @@
1
+ import type { ServerExtension, ExtensionRoute } from "../../../shared/extension-types"
2
+ import { homedir } from "node:os"
3
+ import path from "node:path"
4
+
5
+ const LOG_PREFIX = "[c3-ext]"
6
+
7
+ interface C3ListEntity {
8
+ id: string
9
+ type: string
10
+ title?: string
11
+ name?: string
12
+ parent?: string
13
+ status?: string
14
+ children?: C3ListEntity[]
15
+ [key: string]: unknown
16
+ }
17
+
18
+ interface C3ListJsonOutput {
19
+ entities?: C3ListEntity[]
20
+ items?: C3ListEntity[]
21
+ [key: string]: unknown
22
+ }
23
+
24
+ export function buildC3EntityTree(entities: C3ListEntity[]): C3ListEntity[] {
25
+ const byId = new Map<string, C3ListEntity>()
26
+ const roots: C3ListEntity[] = []
27
+
28
+ for (const entity of entities) {
29
+ const { children: _children, ...rest } = entity
30
+ byId.set(entity.id, { ...rest })
31
+ }
32
+
33
+ for (const entity of entities) {
34
+ const node = byId.get(entity.id)
35
+ if (!node) continue
36
+
37
+ const parentId = typeof entity.parent === "string" ? entity.parent : null
38
+ const parent = parentId && parentId !== entity.id ? byId.get(parentId) : undefined
39
+
40
+ if (parent) {
41
+ parent.children = parent.children ?? []
42
+ parent.children.push(node)
43
+ } else {
44
+ roots.push(node)
45
+ }
46
+ }
47
+
48
+ return roots
49
+ }
50
+
51
+ function normalizeListData(parsed: C3ListJsonOutput): C3ListEntity[] | C3ListJsonOutput {
52
+ if (Array.isArray(parsed.entities)) return buildC3EntityTree(parsed.entities)
53
+ if (Array.isArray(parsed.items)) return buildC3EntityTree(parsed.items)
54
+ return parsed
55
+ }
56
+
57
+ function jsonResponse(data: unknown, status = 200): Response {
58
+ return new Response(JSON.stringify(data), {
59
+ status,
60
+ headers: { "Content-Type": "application/json" },
61
+ })
62
+ }
63
+
64
+ function errorResponse(error: string, code: number): Response {
65
+ return jsonResponse({ error, code }, code)
66
+ }
67
+
68
+ /** Resolve c3x path: PATH first, then known install location */
69
+ async function resolveC3xPath(): Promise<string | null> {
70
+ try {
71
+ const proc = Bun.spawn(["which", "c3x"], { stdout: "pipe", stderr: "pipe" })
72
+ const out = await new Response(proc.stdout).text()
73
+ const exitCode = await proc.exited
74
+ if (exitCode === 0 && out.trim()) return out.trim()
75
+ } catch (_e: unknown) {
76
+ // fall through
77
+ }
78
+
79
+ const fallbacks = [
80
+ path.join(homedir(), ".agents/skills/c3/bin/c3x.sh"),
81
+ path.join(
82
+ homedir(),
83
+ ".claude/plugins/marketplaces/c3-skill-marketplace/skills/c3/bin/c3x.sh",
84
+ ),
85
+ ]
86
+ for (const fallback of fallbacks) {
87
+ const file = Bun.file(fallback)
88
+ if (await file.exists()) return fallback
89
+ }
90
+
91
+ return null
92
+ }
93
+
94
+ function c3xEnv(): Record<string, string> {
95
+ const env: Record<string, string> = {}
96
+ for (const [key, value] of Object.entries(process.env)) {
97
+ if (key === "C3X_MODE" || value === undefined) continue
98
+ env[key] = value
99
+ }
100
+ return env
101
+ }
102
+
103
+ async function runC3x(
104
+ args: string[],
105
+ projectPath: string,
106
+ ): Promise<{ stdout: string; exitCode: number }> {
107
+ const c3xPath = await resolveC3xPath()
108
+ if (!c3xPath) throw new Error("c3x not found")
109
+
110
+ // If c3xPath is a shell script, run via bash; if binary, run directly
111
+ const cmd = c3xPath.endsWith(".sh")
112
+ ? ["bash", c3xPath, ...args]
113
+ : [c3xPath, ...args]
114
+
115
+ const proc = Bun.spawn(cmd, {
116
+ cwd: projectPath,
117
+ env: c3xEnv(),
118
+ stdout: "pipe",
119
+ stderr: "pipe",
120
+ })
121
+
122
+ const stdout = await new Response(proc.stdout).text()
123
+ const exitCode = await proc.exited
124
+ return { stdout, exitCode }
125
+ }
126
+
127
+ function handleList(projectPath: string): ExtensionRoute["handler"] {
128
+ return async (_req, _params) => {
129
+ try {
130
+ const { stdout, exitCode } = await runC3x(["list", "--compact", "--json"], projectPath)
131
+ if (exitCode !== 0) {
132
+ console.warn(LOG_PREFIX, "c3x list exited with code", exitCode)
133
+ return errorResponse("c3x execution failed", 503)
134
+ }
135
+ try {
136
+ const parsed = JSON.parse(stdout) as C3ListJsonOutput
137
+ return jsonResponse({ data: normalizeListData(parsed) })
138
+ } catch (_e: unknown) {
139
+ return jsonResponse({ data: stdout.trim() })
140
+ }
141
+ } catch (error: unknown) {
142
+ const msg = error instanceof Error ? error.message : String(error)
143
+ console.warn(LOG_PREFIX, "list failed:", msg)
144
+ return errorResponse("c3x execution failed", 503)
145
+ }
146
+ }
147
+ }
148
+
149
+ function handleRead(projectPath: string): ExtensionRoute["handler"] {
150
+ return async (req, _params) => {
151
+ const url = new URL(req.url)
152
+ const id = url.searchParams.get("id")
153
+ if (!id) {
154
+ return errorResponse("Missing required 'id' query parameter", 400)
155
+ }
156
+
157
+ try {
158
+ const { stdout, exitCode } = await runC3x(["read", id, "--full", "--json"], projectPath)
159
+ if (exitCode !== 0) {
160
+ console.warn(LOG_PREFIX, "c3x read exited with code", exitCode)
161
+ return errorResponse("c3x execution failed", 503)
162
+ }
163
+ try {
164
+ const parsed = JSON.parse(stdout) as unknown
165
+ return jsonResponse({ data: parsed })
166
+ } catch (_error: unknown) {
167
+ return jsonResponse({ data: stdout.trim() })
168
+ }
169
+ } catch (error: unknown) {
170
+ const msg = error instanceof Error ? error.message : String(error)
171
+ console.warn(LOG_PREFIX, "read failed:", msg)
172
+ return errorResponse("c3x execution failed", 503)
173
+ }
174
+ }
175
+ }
176
+
177
+ function handleGraph(projectPath: string): ExtensionRoute["handler"] {
178
+ return async (req, _params) => {
179
+ const url = new URL(req.url)
180
+ const id = url.searchParams.get("id")
181
+ if (!id) {
182
+ return errorResponse("Missing required 'id' query parameter", 400)
183
+ }
184
+
185
+ try {
186
+ const { stdout, exitCode } = await runC3x(["graph", id, "--format", "mermaid"], projectPath)
187
+ if (exitCode !== 0) {
188
+ console.warn(LOG_PREFIX, "c3x graph exited with code", exitCode)
189
+ return errorResponse("c3x execution failed", 503)
190
+ }
191
+ return jsonResponse({ data: stdout.trim() })
192
+ } catch (error: unknown) {
193
+ const msg = error instanceof Error ? error.message : String(error)
194
+ console.warn(LOG_PREFIX, "graph failed:", msg)
195
+ return errorResponse("c3x execution failed", 503)
196
+ }
197
+ }
198
+ }
199
+
200
+ export const c3Extension: ServerExtension = {
201
+ id: "c3",
202
+ name: "Architecture",
203
+ icon: "building-2",
204
+ detect: [".c3/"],
205
+ routes(ctx) {
206
+ return [
207
+ { method: "GET", path: "/list", handler: handleList(ctx.projectPath) },
208
+ { method: "GET", path: "/read", handler: handleRead(ctx.projectPath) },
209
+ { method: "GET", path: "/graph", handler: handleGraph(ctx.projectPath) },
210
+ ]
211
+ },
212
+ }
@@ -0,0 +1,200 @@
1
+ import { describe, test, expect, afterEach } from "bun:test"
2
+ import { mkdtemp, rm, writeFile } from "node:fs/promises"
3
+ import { join } from "node:path"
4
+ import { tmpdir } from "node:os"
5
+ import { codeExtension } from "./server"
6
+
7
+ let tempDirs: string[] = []
8
+
9
+ async function makeTempDir(): Promise<string> {
10
+ const dir = await mkdtemp(join(tmpdir(), "code-ext-test-"))
11
+ tempDirs.push(dir)
12
+ return dir
13
+ }
14
+
15
+ function getManifestHandler(projectPath: string) {
16
+ const routes = codeExtension.routes({ projectPath })
17
+ const route = routes.find((r) => r.path === "/manifest" && r.method === "GET")
18
+ if (!route) throw new Error("No /manifest route found")
19
+ return route.handler
20
+ }
21
+
22
+ async function callManifest(projectPath: string): Promise<{ status: number; body: unknown }> {
23
+ const handler = getManifestHandler(projectPath)
24
+ const req = new Request(`http://localhost/api/ext/code/manifest?projectPath=${encodeURIComponent(projectPath)}`)
25
+ const res = await handler(req, {})
26
+ const body = await res.json()
27
+ return { status: res.status, body }
28
+ }
29
+
30
+ afterEach(async () => {
31
+ for (const dir of tempDirs) {
32
+ await rm(dir, { recursive: true, force: true }).catch(() => {})
33
+ }
34
+ tempDirs = []
35
+ })
36
+
37
+ describe("code extension", () => {
38
+ test("has correct manifest metadata", () => {
39
+ expect(codeExtension.id).toBe("code")
40
+ expect(codeExtension.name).toBe("Code")
41
+ expect(codeExtension.detect).toContain("package.json")
42
+ expect(codeExtension.detect).toContain("Cargo.toml")
43
+ expect(codeExtension.detect).toContain("go.mod")
44
+ expect(codeExtension.detect).toContain("pyproject.toml")
45
+ })
46
+
47
+ test("exposes /manifest GET route", () => {
48
+ const routes = codeExtension.routes({ projectPath: "/tmp/fake" })
49
+ const manifest = routes.find((r) => r.path === "/manifest")
50
+ expect(manifest).toBeDefined()
51
+ expect(manifest!.method).toBe("GET")
52
+ })
53
+ })
54
+
55
+ describe("/manifest with package.json", () => {
56
+ test("parses valid package.json", async () => {
57
+ const dir = await makeTempDir()
58
+ await writeFile(
59
+ join(dir, "package.json"),
60
+ JSON.stringify({
61
+ name: "test",
62
+ version: "1.0.0",
63
+ scripts: { dev: "vite" },
64
+ dependencies: { react: "^19" },
65
+ devDependencies: { typescript: "^5" },
66
+ }),
67
+ )
68
+
69
+ const { status, body } = await callManifest(dir)
70
+ expect(status).toBe(200)
71
+
72
+ const result = body as { manifests: Array<Record<string, unknown>> }
73
+ expect(result.manifests).toHaveLength(1)
74
+
75
+ const m = result.manifests[0]
76
+ expect(m.language).toBe("javascript")
77
+ expect(m.name).toBe("test")
78
+ expect(m.version).toBe("1.0.0")
79
+ expect(m.scripts).toEqual({ dev: "vite" })
80
+ expect(m.dependencies).toEqual({ react: "^19" })
81
+ expect(m.devDependencies).toEqual({ typescript: "^5" })
82
+ })
83
+ })
84
+
85
+ describe("/manifest with no manifest files", () => {
86
+ test("returns empty manifests array", async () => {
87
+ const dir = await makeTempDir()
88
+
89
+ const { status, body } = await callManifest(dir)
90
+ expect(status).toBe(200)
91
+
92
+ const result = body as { manifests: unknown[] }
93
+ expect(result.manifests).toEqual([])
94
+ })
95
+ })
96
+
97
+ describe("/manifest with malformed JSON", () => {
98
+ test("handles malformed package.json gracefully", async () => {
99
+ const dir = await makeTempDir()
100
+ await writeFile(join(dir, "package.json"), "{ not valid json !!!")
101
+
102
+ const { status, body } = await callManifest(dir)
103
+ expect(status).toBe(200)
104
+
105
+ const result = body as { manifests: Array<Record<string, unknown>> }
106
+ expect(result.manifests).toHaveLength(1)
107
+ expect(result.manifests[0].error).toBeDefined()
108
+ expect(result.manifests[0].language).toBe("javascript")
109
+ })
110
+ })
111
+
112
+ describe("/manifest with Cargo.toml", () => {
113
+ test("parses valid Cargo.toml", async () => {
114
+ const dir = await makeTempDir()
115
+ await writeFile(
116
+ join(dir, "Cargo.toml"),
117
+ `[package]
118
+ name = "my-crate"
119
+ version = "0.3.1"
120
+ edition = "2021"
121
+
122
+ [dependencies]
123
+ serde = "1.0"
124
+ tokio = "1.28"
125
+ `,
126
+ )
127
+
128
+ const { status, body } = await callManifest(dir)
129
+ expect(status).toBe(200)
130
+
131
+ const result = body as { manifests: Array<Record<string, unknown>> }
132
+ expect(result.manifests).toHaveLength(1)
133
+
134
+ const m = result.manifests[0]
135
+ expect(m.language).toBe("rust")
136
+ expect(m.name).toBe("my-crate")
137
+ expect(m.version).toBe("0.3.1")
138
+ expect(m.dependencies).toEqual({ serde: "1.0", tokio: "1.28" })
139
+ })
140
+ })
141
+
142
+ describe("/manifest with go.mod", () => {
143
+ test("parses valid go.mod", async () => {
144
+ const dir = await makeTempDir()
145
+ await writeFile(
146
+ join(dir, "go.mod"),
147
+ `module github.com/user/myapp
148
+
149
+ go 1.21
150
+
151
+ require (
152
+ \tgolang.org/x/text v0.14.0
153
+ \tgithub.com/gin-gonic/gin v1.9.1
154
+ )
155
+ `,
156
+ )
157
+
158
+ const { status, body } = await callManifest(dir)
159
+ expect(status).toBe(200)
160
+
161
+ const result = body as { manifests: Array<Record<string, unknown>> }
162
+ expect(result.manifests).toHaveLength(1)
163
+
164
+ const m = result.manifests[0]
165
+ expect(m.language).toBe("go")
166
+ expect(m.name).toBe("github.com/user/myapp")
167
+ expect(m.version).toBe("1.21")
168
+ expect(m.dependencies).toEqual({
169
+ "golang.org/x/text": "v0.14.0",
170
+ "github.com/gin-gonic/gin": "v1.9.1",
171
+ })
172
+ })
173
+ })
174
+
175
+ describe("/manifest with multiple manifests", () => {
176
+ test("returns all detected manifests", async () => {
177
+ const dir = await makeTempDir()
178
+ await writeFile(
179
+ join(dir, "package.json"),
180
+ JSON.stringify({ name: "frontend", version: "2.0.0" }),
181
+ )
182
+ await writeFile(
183
+ join(dir, "go.mod"),
184
+ `module github.com/user/backend
185
+
186
+ go 1.22
187
+ `,
188
+ )
189
+
190
+ const { status, body } = await callManifest(dir)
191
+ expect(status).toBe(200)
192
+
193
+ const result = body as { manifests: Array<Record<string, unknown>> }
194
+ expect(result.manifests).toHaveLength(2)
195
+
196
+ const languages = result.manifests.map((m) => m.language)
197
+ expect(languages).toContain("javascript")
198
+ expect(languages).toContain("go")
199
+ })
200
+ })
@@ -0,0 +1,150 @@
1
+ import type { ServerExtension } from "../../../shared/extension-types"
2
+
3
+ interface ManifestResult {
4
+ language: string
5
+ name: string
6
+ version: string
7
+ scripts: Record<string, string>
8
+ dependencies: Record<string, string>
9
+ devDependencies: Record<string, string>
10
+ error?: string
11
+ }
12
+
13
+ const MANIFEST_FILES = [
14
+ { file: "package.json", parser: parsePackageJson },
15
+ { file: "Cargo.toml", parser: parseCargoToml },
16
+ { file: "go.mod", parser: parseGoMod },
17
+ { file: "pyproject.toml", parser: parsePyprojectToml },
18
+ ] as const
19
+
20
+ function jsonResponse(data: unknown, status = 200): Response {
21
+ return new Response(JSON.stringify(data), {
22
+ status,
23
+ headers: { "Content-Type": "application/json" },
24
+ })
25
+ }
26
+
27
+ async function parsePackageJson(filePath: string): Promise<ManifestResult> {
28
+ const text = await Bun.file(filePath).text()
29
+ const pkg = JSON.parse(text)
30
+ return {
31
+ language: "javascript",
32
+ name: pkg.name ?? "",
33
+ version: pkg.version ?? "",
34
+ scripts: pkg.scripts ?? {},
35
+ dependencies: pkg.dependencies ?? {},
36
+ devDependencies: pkg.devDependencies ?? {},
37
+ }
38
+ }
39
+
40
+ async function parseCargoToml(filePath: string): Promise<ManifestResult> {
41
+ const text = await Bun.file(filePath).text()
42
+ const name = text.match(/\[package\][\s\S]*?name\s*=\s*"([^"]+)"/)?.[1] ?? ""
43
+ const version = text.match(/\[package\][\s\S]*?version\s*=\s*"([^"]+)"/)?.[1] ?? ""
44
+ const depsMatch = text.match(/\[dependencies\]([\s\S]*?)(?:\[|$)/)
45
+ const deps: Record<string, string> = {}
46
+ if (depsMatch) {
47
+ for (const line of depsMatch[1].split("\n")) {
48
+ const m = line.match(/^(\S+)\s*=\s*"?([^"\n]+)"?/)
49
+ if (m) deps[m[1]] = m[2].trim()
50
+ }
51
+ }
52
+ return {
53
+ language: "rust",
54
+ name,
55
+ version,
56
+ scripts: {},
57
+ dependencies: deps,
58
+ devDependencies: {},
59
+ }
60
+ }
61
+
62
+ async function parseGoMod(filePath: string): Promise<ManifestResult> {
63
+ const text = await Bun.file(filePath).text()
64
+ const moduleName = text.match(/^module\s+(\S+)/m)?.[1] ?? ""
65
+ const goVersion = text.match(/^go\s+(\S+)/m)?.[1] ?? ""
66
+ const requireBlock = text.match(/require\s*\(([\s\S]*?)\)/)
67
+ const deps: Record<string, string> = {}
68
+ if (requireBlock) {
69
+ for (const line of requireBlock[1].split("\n")) {
70
+ const m = line.trim().match(/^(\S+)\s+(\S+)/)
71
+ if (m) deps[m[1]] = m[2]
72
+ }
73
+ }
74
+ return {
75
+ language: "go",
76
+ name: moduleName,
77
+ version: goVersion,
78
+ scripts: {},
79
+ dependencies: deps,
80
+ devDependencies: {},
81
+ }
82
+ }
83
+
84
+ async function parsePyprojectToml(filePath: string): Promise<ManifestResult> {
85
+ const text = await Bun.file(filePath).text()
86
+ const name = text.match(/\[project\][\s\S]*?name\s*=\s*"([^"]+)"/)?.[1] ?? ""
87
+ const version = text.match(/\[project\][\s\S]*?version\s*=\s*"([^"]+)"/)?.[1] ?? ""
88
+ const depsMatch = text.match(/dependencies\s*=\s*\[([\s\S]*?)\]/)
89
+ const deps: Record<string, string> = {}
90
+ if (depsMatch) {
91
+ for (const m of depsMatch[1].matchAll(/"([^"]+)"/g)) {
92
+ const parts = m[1].split(/[><=~!]+/)
93
+ deps[parts[0].trim()] = m[1].replace(parts[0].trim(), "").trim() || "*"
94
+ }
95
+ }
96
+ return {
97
+ language: "python",
98
+ name,
99
+ version,
100
+ scripts: {},
101
+ dependencies: deps,
102
+ devDependencies: {},
103
+ }
104
+ }
105
+
106
+ function handleManifest(projectPath: string) {
107
+ return async (_req: Request, _params: Record<string, string>): Promise<Response> => {
108
+ const results: ManifestResult[] = []
109
+
110
+ for (const { file, parser } of MANIFEST_FILES) {
111
+ const filePath = `${projectPath}/${file}`
112
+ const bunFile = Bun.file(filePath)
113
+ const exists = await bunFile.exists()
114
+ if (!exists) continue
115
+
116
+ try {
117
+ const result = await parser(filePath)
118
+ results.push(result)
119
+ } catch (err: unknown) {
120
+ const language = file === "package.json" ? "javascript"
121
+ : file === "Cargo.toml" ? "rust"
122
+ : file === "go.mod" ? "go"
123
+ : "python"
124
+ results.push({
125
+ language,
126
+ name: "",
127
+ version: "",
128
+ scripts: {},
129
+ dependencies: {},
130
+ devDependencies: {},
131
+ error: err instanceof Error ? err.message : String(err),
132
+ })
133
+ }
134
+ }
135
+
136
+ return jsonResponse({ manifests: results })
137
+ }
138
+ }
139
+
140
+ export const codeExtension: ServerExtension = {
141
+ id: "code",
142
+ name: "Code",
143
+ icon: "code",
144
+ detect: ["package.json", "Cargo.toml", "go.mod", "pyproject.toml"],
145
+ routes(ctx) {
146
+ return [
147
+ { method: "GET", path: "/manifest", handler: handleManifest(ctx.projectPath) },
148
+ ]
149
+ },
150
+ }
@@ -0,0 +1,10 @@
1
+ import { c3Extension } from "./extensions/c3/server"
2
+ import { agentsExtension } from "./extensions/agents/server"
3
+ import { codeExtension } from "./extensions/code/server"
4
+ import type { ServerExtension } from "../shared/extension-types"
5
+
6
+ export const serverExtensions: ServerExtension[] = [
7
+ c3Extension,
8
+ agentsExtension,
9
+ codeExtension,
10
+ ]
@@ -0,0 +1,69 @@
1
+ import { stat } from "node:fs/promises"
2
+ import path from "node:path"
3
+ import process from "node:process"
4
+ import type { ClientCommand } from "../shared/protocol"
5
+ import { resolveLocalPath } from "./paths"
6
+ import { hasCommand, spawnDetached } from "./process-utils"
7
+
8
+ type OpenExternalCommand = Extract<ClientCommand, { type: "system.openExternal" }>
9
+
10
+ export async function openExternal(command: OpenExternalCommand) {
11
+ const resolvedPath = resolveLocalPath(command.localPath)
12
+ const platform = process.platform
13
+ const info = command.action === "open_finder"
14
+ ? await stat(resolvedPath).catch(() => null)
15
+ : null
16
+
17
+ if (platform === "darwin") {
18
+ if (command.action === "open_finder") {
19
+ if (info?.isDirectory()) {
20
+ spawnDetached("open", [resolvedPath])
21
+ } else {
22
+ spawnDetached("open", ["-R", resolvedPath])
23
+ }
24
+ return
25
+ }
26
+ if (command.action === "open_terminal") {
27
+ spawnDetached("open", ["-a", "Terminal", resolvedPath])
28
+ return
29
+ }
30
+ }
31
+
32
+ if (platform === "win32") {
33
+ if (command.action === "open_finder") {
34
+ if (info?.isDirectory()) {
35
+ spawnDetached("explorer", [resolvedPath])
36
+ } else {
37
+ spawnDetached("explorer", ["/select,", resolvedPath])
38
+ }
39
+ return
40
+ }
41
+ if (command.action === "open_terminal") {
42
+ if (hasCommand("wt")) {
43
+ spawnDetached("wt", ["-d", resolvedPath])
44
+ return
45
+ }
46
+ spawnDetached("cmd", ["/c", "start", "", "cmd", "/K", `cd /d ${resolvedPath}`])
47
+ return
48
+ }
49
+ }
50
+
51
+ if (command.action === "open_finder") {
52
+ spawnDetached("xdg-open", [info?.isDirectory() ? resolvedPath : path.dirname(resolvedPath)])
53
+ return
54
+ }
55
+ if (command.action === "open_terminal") {
56
+ for (const terminalCommand of ["x-terminal-emulator", "gnome-terminal", "konsole"]) {
57
+ if (!hasCommand(terminalCommand)) continue
58
+ if (terminalCommand === "gnome-terminal") {
59
+ spawnDetached(terminalCommand, ["--working-directory", resolvedPath])
60
+ } else if (terminalCommand === "konsole") {
61
+ spawnDetached(terminalCommand, ["--workdir", resolvedPath])
62
+ } else {
63
+ spawnDetached(terminalCommand, ["--working-directory", resolvedPath])
64
+ }
65
+ return
66
+ }
67
+ spawnDetached("xdg-open", [resolvedPath])
68
+ }
69
+ }
@@ -0,0 +1,58 @@
1
+ import type { TranscriptEntry } from "../shared/types"
2
+ import { getForkPreset } from "../shared/fork-presets"
3
+ import { QuickResponseAdapter } from "./quick-response"
4
+ import { toTranscriptLine } from "./transcript-utils"
5
+ import { buildSessionSeedPrompt } from "./session-seed"
6
+
7
+ const MAX_FORK_TRANSCRIPT_LINES = 32
8
+ const MAX_FORK_TRANSCRIPT_CHARS = 14_000
9
+ const MAX_FORK_LINE_CHARS = 700
10
+ /** Build a bounded transcript excerpt from a list of transcript entries.
11
+ * Exported for reuse by merge-context generation. */
12
+ export function buildForkTranscriptExcerpt(entries: TranscriptEntry[]): string {
13
+ const lines = entries
14
+ .map((e) => toTranscriptLine(e, MAX_FORK_LINE_CHARS))
15
+ .filter((line): line is string => Boolean(line))
16
+
17
+ if (lines.length === 0) return "No prior transcript context was available."
18
+
19
+ const selected = lines.slice(-MAX_FORK_TRANSCRIPT_LINES)
20
+ const omittedCount = lines.length - selected.length
21
+ const header = omittedCount > 0
22
+ ? [`Recent source transcript excerpt. Older relevant lines omitted: ${omittedCount}.`]
23
+ : ["Recent source transcript excerpt:"]
24
+
25
+ const combined = [...header, ...selected]
26
+ let serialized = combined.join("\n")
27
+ if (serialized.length <= MAX_FORK_TRANSCRIPT_CHARS) return serialized
28
+
29
+ const trimmed: string[] = []
30
+ let remaining = MAX_FORK_TRANSCRIPT_CHARS - header[0]!.length - 1
31
+ for (let index = selected.length - 1; index >= 0; index -= 1) {
32
+ const line = selected[index]!
33
+ const cost = line.length + 1
34
+ if (remaining - cost < 0) break
35
+ trimmed.unshift(line)
36
+ remaining -= cost
37
+ }
38
+
39
+ return [...header, ...trimmed].join("\n")
40
+ }
41
+
42
+ export async function generateForkPromptForChat(
43
+ forkIntent: string,
44
+ entries: TranscriptEntry[],
45
+ cwd: string,
46
+ presetId?: string,
47
+ adapter = new QuickResponseAdapter(),
48
+ ): Promise<string> {
49
+ const preset = getForkPreset(presetId)
50
+ return buildSessionSeedPrompt({
51
+ mode: "fork",
52
+ intent: forkIntent,
53
+ preset,
54
+ sources: [{ chatId: "current-session", entries }],
55
+ cwd,
56
+ adapter,
57
+ })
58
+ }