@desplega.ai/agent-swarm 1.165.0 → 1.167.0

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 (296) hide show
  1. package/dist/acp-adapter-zpvy6321.js +34 -0
  2. package/dist/{actions-jna0b3wm.js → actions-fq2zrwtf.js} +30 -34
  3. package/dist/{amp-adapter-0eve81pz.js → amp-adapter-5gbk7501.js} +7 -7
  4. package/dist/{anthropic-messages-hst62ws9.js → anthropic-messages-13yn502s.js} +4 -4
  5. package/dist/{app-75hm5cfa.js → app-nctetn1e.js} +11 -11
  6. package/dist/{assistant-yzd51j33.js → assistant-0aq8gjvj.js} +31 -35
  7. package/dist/{azure-openai-responses-mh8tvf78.js → azure-openai-responses-9st34pfz.js} +5 -5
  8. package/dist/{boot-reembed-z158xq32.js → boot-reembed-1ze5853n.js} +14 -16
  9. package/dist/{boot-reembed-2ex2mcsh.js → boot-reembed-fmp5ww69.js} +15 -16
  10. package/dist/boot-scrub-sweep-cbp8xd4e.js +212 -0
  11. package/dist/{boot-seeds-2bmnh18p.js → boot-seeds-22tx8a53.js} +13 -12
  12. package/dist/{claude-adapter-jbj1mycz.js → claude-adapter-0jhgeh1d.js} +25 -25
  13. package/dist/{claude-managed-adapter-17ggz09t.js → claude-managed-adapter-tzwxy803.js} +5 -5
  14. package/dist/{claude-managed-setup-ptm1nzm2.js → claude-managed-setup-nrhfx5b0.js} +5 -5
  15. package/dist/{claude-sdk-session-9re1g7r2.js → claude-sdk-session-wh77rh83.js} +2632 -2614
  16. package/dist/{cli-zsh093hk.js → cli-014vns2y.js} +63 -1
  17. package/dist/{cli-qvfk83fy.js → cli-13xwcqvj.js} +2 -2
  18. package/dist/{cli-8gpbwy09.js → cli-1yrcfa5s.js} +5 -5
  19. package/dist/{cli-xtgtyafv.js → cli-577bxkf6.js} +212 -451
  20. package/dist/{cli-ma3zvh39.js → cli-5qkcdv8c.js} +6118 -5874
  21. package/dist/{cli-cwxhbf43.js → cli-5t5my0h8.js} +85 -2
  22. package/dist/{cli-zvckv750.js → cli-69egj654.js} +2 -2
  23. package/dist/{cli-9xb89xca.js → cli-6bpvv8h4.js} +9 -9
  24. package/dist/{cli-90v942q1.js → cli-6qxmjpem.js} +8 -8
  25. package/dist/{cli-9866bd07.js → cli-6vfz44sr.js} +1 -1
  26. package/dist/{cli-32bca7nr.js → cli-7avy4v8w.js} +1 -1
  27. package/dist/{cli-xb3c6aat.js → cli-7mhy3ths.js} +21 -18
  28. package/dist/{cli-q38n4bq0.js → cli-95zs84qw.js} +3 -3
  29. package/dist/cli-a35hzdve.js +33 -0
  30. package/dist/{cli-x3x0qwky.js → cli-bxqez1p0.js} +51 -23
  31. package/dist/{cli-prt9emct.js → cli-c2tpw9ck.js} +3 -3
  32. package/dist/{cli-0n4fasz0.js → cli-c8r99akr.js} +16 -16
  33. package/dist/{cli-5anb0ev3.js → cli-cexctgn5.js} +89 -26
  34. package/dist/{cli-bns5c8k9.js → cli-cf2vgn9d.js} +105 -91
  35. package/dist/{cli-ng97fjq7.js → cli-cmxkbzzs.js} +33 -7
  36. package/dist/{cli-nexwh8zg.js → cli-g7k7zbcz.js} +12 -5
  37. package/dist/{cli-mmzwwptd.js → cli-hf5s9pgf.js} +1 -1
  38. package/dist/{cli-nvvfd8bq.js → cli-jbzbr36n.js} +4091 -3793
  39. package/dist/{cli-zn2v3t8v.js → cli-jvmtxqtc.js} +27 -15
  40. package/dist/{cli-pkke6geq.js → cli-km4x66j0.js} +83 -65
  41. package/dist/cli-kw0jcfje.js +516 -0
  42. package/dist/{cli-28smfvbn.js → cli-m7vmeepg.js} +32 -19
  43. package/dist/{cli-hpryr6em.js → cli-mb75wpxf.js} +1 -1
  44. package/dist/{cli-qdv8kgz7.js → cli-mkdsy1nq.js} +14018 -3333
  45. package/dist/{cli-b0f70z24.js → cli-mn8qkd8v.js} +1 -1
  46. package/dist/{cli-420bdgw0.js → cli-mv2520nm.js} +1 -1
  47. package/dist/{cli-n9ehc28t.js → cli-mxry91sa.js} +31 -10
  48. package/dist/{cli-wfajtmf7.js → cli-mxvnnv5q.js} +596 -13
  49. package/dist/cli-nkqjj42q.js +104 -0
  50. package/dist/{cli-e7t4snpa.js → cli-p8rt8spp.js} +5 -5
  51. package/dist/{cli-gh5yqzpe.js → cli-pkj1w46r.js} +12 -7
  52. package/dist/cli-q1vnz8wv.js +96 -0
  53. package/dist/{cli-fj86xr3c.js → cli-qd97v6z2.js} +2 -2
  54. package/dist/{cli-ba66wyhy.js → cli-qzmzwegq.js} +60 -20
  55. package/dist/{cli-5b2fjjzh.js → cli-r7eeddkq.js} +14 -9
  56. package/dist/{cli-8ssjez7e.js → cli-rhy7z1rp.js} +22 -11
  57. package/dist/{cli-4mevd1hf.js → cli-s9y81s7j.js} +5 -5
  58. package/dist/{cli-59jn5twa.js → cli-tc5zec7v.js} +7 -7
  59. package/dist/{cli-ttbsse3f.js → cli-tmhsxhb8.js} +1 -1
  60. package/dist/{cli-k6xx3pve.js → cli-tx2zvn23.js} +4 -4
  61. package/dist/{cli-pjxnr1jn.js → cli-ty4bzkqr.js} +5 -5
  62. package/dist/{cli-nfygw434.js → cli-v1pwxreq.js} +55 -52
  63. package/dist/{cli-ftry7975.js → cli-v1w7pbd8.js} +3 -2
  64. package/dist/{cli-10zmp1p7.js → cli-vr5avem2.js} +27 -32
  65. package/dist/{cli-bzr0ftht.js → cli-wnb9b2g3.js} +19 -0
  66. package/dist/cli-wt7ccy4r.js +2654 -0
  67. package/dist/{cli-50eg13rj.js → cli-wydz3feg.js} +549 -321
  68. package/dist/{cli-krqm5f11.js → cli-xezn9nkh.js} +16 -13
  69. package/dist/{cli-8kt0bmgx.js → cli-xf713zz0.js} +2 -2
  70. package/dist/{cli-x7afk5wm.js → cli-xvc3q9br.js} +1 -1
  71. package/dist/{cli-9s3h836g.js → cli-xvdgasgy.js} +1 -1
  72. package/dist/{cli-j0pdrmwg.js → cli-y0kjpfm9.js} +3 -3
  73. package/dist/{cli-6zcfw0x7.js → cli-y195hv1a.js} +1 -1
  74. package/dist/{cli-amwhs8h2.js → cli-ykt8f7va.js} +22 -9
  75. package/dist/{cli-1kzfvd1z.js → cli-ymmc1zxg.js} +15 -11
  76. package/dist/{cli-xnzrzets.js → cli-ypgba1a8.js} +2 -2
  77. package/dist/{cli-bdv39kgj.js → cli-z1dqhc9y.js} +31 -20
  78. package/dist/{cli-fw6vdcq5.js → cli-zp67qg5x.js} +34 -1
  79. package/dist/{cli-qbksc292.js → cli-zy39d433.js} +2 -0
  80. package/dist/cli.js +36 -32
  81. package/dist/{cloudflare-workers-ai-system-one-tt484t61.js → cloudflare-workers-ai-system-one-sta45jf9.js} +7 -5
  82. package/dist/{codex-adapter-3qnxshje.js → codex-adapter-cgesnjkr.js} +20 -20
  83. package/dist/{codex-login-brkxhhdg.js → codex-login-g1cyt5zm.js} +2 -2
  84. package/dist/{codex-session-runner-612wnapp.js → codex-session-runner-8kd7ddhr.js} +20 -20
  85. package/dist/{commands-2ybfcxkj.js → commands-h6zaaxym.js} +11 -10
  86. package/dist/{cursor-adapter-p3jgdehv.js → cursor-adapter-v8mm6bp5.js} +7 -7
  87. package/dist/{db-f4ans0jj.js → db-qg3myn53.js} +13 -10
  88. package/dist/{devin-adapter-dhzt01ff.js → devin-adapter-bffjj5n4.js} +2 -2
  89. package/dist/{dispatcher-pk182apd.js → dispatcher-7vnwj9qw.js} +28 -32
  90. package/dist/{dsh-adapter-7twaeps1.js → dsh-adapter-tz6hfp5r.js} +7 -7
  91. package/dist/{e2b-y8t3jzyz.js → e2b-nd50eccg.js} +1 -1
  92. package/dist/{easter-egg-3d-mtpnw06s.js → easter-egg-3d-66zxervv.js} +2 -2
  93. package/dist/{event-bus-w7ac4n3c.js → event-bus-vnfthafg.js} +2 -2
  94. package/dist/{execute-s4ccjq3n.js → execute-h4jgevyw.js} +61 -11
  95. package/dist/{google-generative-ai-d6nphg3q.js → google-generative-ai-b8zxrpax.js} +5 -5
  96. package/dist/{google-vertex-cpshkref.js → google-vertex-nrdd697t.js} +5 -5
  97. package/dist/grok-adapter-jdt2dz2s.js +39 -0
  98. package/dist/{handlers-g2wnr4t9.js → handlers-2qtkpncr.js} +31 -35
  99. package/dist/{hook-f7jt9vnm.js → hook-51yfcgsv.js} +48 -39
  100. package/dist/{hook-bbdpnkb4.js → hook-qnbdgwvd.js} +15 -17
  101. package/dist/{http-w40q4w94.js → http-jsmtag08.js} +536 -231
  102. package/dist/{index-056j5kzn.js → index-2t9kesn1.js} +13 -12
  103. package/dist/{index-cj1r9q83.js → index-bt8wkv1w.js} +29 -33
  104. package/dist/{index-7n70jwbb.js → index-cx1sb9bq.js} +42 -35
  105. package/dist/{index-9bfssf54.js → index-ekywyv2v.js} +28 -32
  106. package/dist/{index-fdk1t4d6.js → index-n0rxa4ca.js} +11962 -9900
  107. package/dist/{index-k8xc083e.js → index-t4g06w93.js} +28 -32
  108. package/dist/{keepalive-1tj10tf4.js → keepalive-4aezx4bj.js} +16 -12
  109. package/dist/{lead-st0bg7v4.js → lead-r44bkpm5.js} +52 -56
  110. package/dist/{llama-cpp-classify-tgj35k8d.js → llama-cpp-classify-6erb7wwv.js} +3 -1
  111. package/dist/{maintenance-nz71zats.js → maintenance-grz5jrzh.js} +12 -13
  112. package/dist/{mistral-conversations-8445ddjn.js → mistral-conversations-059y51zt.js} +4 -4
  113. package/dist/{node-f0ykebbv.js → node-qm9eb6z0.js} +25 -7
  114. package/dist/{oauth-refresh-sweep-aefzwvvq.js → oauth-refresh-sweep-wm4ctjfj.js} +15 -11
  115. package/dist/{onboard-kgpr9mbn.js → onboard-v60zgqf0.js} +2 -2
  116. package/dist/{openai-codex-responses-9ynm88zy.js → openai-codex-responses-jzxkta9b.js} +8 -7
  117. package/dist/{openai-completions-nhqwjmaw.js → openai-completions-663yncfq.js} +4 -4
  118. package/dist/openai-decisions-vj9nkpf8.js +162 -0
  119. package/dist/{openai-responses-xx1c4kgm.js → openai-responses-m3g43rrt.js} +5 -5
  120. package/dist/{opencode-adapter-0c8e70dk.js → opencode-adapter-yjyqynzf.js} +8 -8
  121. package/dist/{openrouter-images-8yx3487g.js → openrouter-images-kr60n6b9.js} +1 -1
  122. package/dist/{otel-impl-x8zp4y5a.js → otel-impl-ghh4dyf8.js} +2 -2
  123. package/dist/{pi-messages-vxdt8v7j.js → pi-messages-xszk613n.js} +1 -1
  124. package/dist/{pi-mono-adapter-t280ah5c.js → pi-mono-adapter-0eg8kw2c.js} +69 -52
  125. package/dist/{pricing-refresh-9e0q7cwk.js → pricing-refresh-mjrqvnvw.js} +12 -11
  126. package/dist/{rbac-roles-790j3ga8.js → rbac-roles-axv4d74x.js} +11 -10
  127. package/dist/{rbac-roles-kcp6zge2.js → rbac-roles-fd5tskj9.js} +11 -10
  128. package/dist/{render-v2-tch4nefj.js → render-v2-k50j33qd.js} +11 -11
  129. package/dist/{runtime-v2t1r79e.js → runtime-h9ha1mq6.js} +4 -4
  130. package/dist/{setup-rcm303ns.js → setup-4syh0pd2.js} +2 -2
  131. package/dist/{typesafe-system-one-datfr82p.js → typesafe-system-one-e988vty7.js} +7 -5
  132. package/dist/{virtual-modules-wm8mxdxx.js → virtual-modules-ftr9kwe8.js} +11 -11
  133. package/dist/{work-objects-ctg7t70w.js → work-objects-jcdbg8rr.js} +32 -36
  134. package/dist/{worker-5dp0xm55.js → worker-x8j8c9sx.js} +52 -56
  135. package/dist/{x-v3yw66zs.js → x-ma4gnfgy.js} +2 -2
  136. package/openapi.json +5 -2
  137. package/package.json +15 -11
  138. package/src/be/automation-preflight.ts +9 -4
  139. package/src/be/boot-scrub-sweep.ts +302 -0
  140. package/src/be/crypto/key-bootstrap.ts +1 -1
  141. package/src/be/db/approvals.ts +15 -1
  142. package/src/be/db/codex-oauth-device-flows.ts +40 -0
  143. package/src/be/db/config-secrets.ts +31 -0
  144. package/src/be/db/runtime.ts +4 -0
  145. package/src/be/db/script-runs.ts +15 -0
  146. package/src/be/db/tasks/write.ts +1 -1
  147. package/src/be/db-queries/mcp-oauth.ts +5 -0
  148. package/src/be/db-queries/oauth.ts +77 -0
  149. package/src/be/db.ts +162 -59
  150. package/src/be/events.ts +17 -1
  151. package/src/be/memory/index-content.ts +2 -2
  152. package/src/be/memory/providers/openai-embedding.ts +7 -2
  153. package/src/be/memory/providers/sqlite-store.ts +63 -11
  154. package/src/be/memory/raters/llm-summarizer.ts +7 -2
  155. package/src/be/memory/types.ts +14 -0
  156. package/src/be/migrations/201_workflow_replay_columns.sql +10 -0
  157. package/src/be/migrations/202_codex_oauth_device_flows.sql +24 -0
  158. package/src/be/modelsdev-cache.json +61 -0
  159. package/src/be/scripts/db.ts +28 -4
  160. package/src/be/scripts/source-secrets.ts +37 -0
  161. package/src/be/scrub-json.ts +32 -0
  162. package/src/be/sealed-json.ts +59 -0
  163. package/src/be/secret-registry.ts +131 -0
  164. package/src/be/seed-pricing.ts +84 -53
  165. package/src/be/swarm-config-guard.ts +13 -0
  166. package/src/be/workflow-replay.ts +77 -0
  167. package/src/commands/provider-credentials.ts +28 -5
  168. package/src/commands/runner.ts +7 -12
  169. package/src/heartbeat/heartbeat.ts +91 -19
  170. package/src/hooks/hook.ts +72 -27
  171. package/src/http/codex-oauth-device.ts +8 -10
  172. package/src/http/db-query-bounded.ts +3 -0
  173. package/src/http/db-query-shared.ts +107 -15
  174. package/src/http/db-query.ts +10 -2
  175. package/src/http/index.ts +23 -6
  176. package/src/http/mcp.ts +5 -0
  177. package/src/http/onboarding.ts +2 -0
  178. package/src/http/script-runs.ts +9 -1
  179. package/src/http/scripts.ts +15 -0
  180. package/src/http/workflows.ts +3 -2
  181. package/src/oauth/mcp-wrapper.ts +1 -1
  182. package/src/providers/acp-adapter.ts +25 -11
  183. package/src/providers/acp-target-catalog.ts +35 -1
  184. package/src/providers/acp-targets.ts +78 -7
  185. package/src/providers/amp-adapter.ts +1 -1
  186. package/src/providers/claude-adapter.ts +26 -0
  187. package/src/providers/codex-adapter.ts +30 -3
  188. package/src/providers/codex-oauth/auth-json.ts +21 -4
  189. package/src/providers/codex-oauth/types.ts +2 -0
  190. package/src/providers/cursor-adapter.ts +1 -1
  191. package/src/providers/dsh-adapter.ts +10 -1
  192. package/src/providers/grok-adapter.ts +18 -2
  193. package/src/providers/opencode-adapter.ts +21 -5
  194. package/src/providers/pi-mono-extension.ts +56 -25
  195. package/src/providers/pricing-sources.md +2 -0
  196. package/src/script-workflows/supervisor.ts +11 -2
  197. package/src/scripts-runtime/eval-harness.ts +2 -12
  198. package/src/scripts-runtime/executors/quickjs-bundle.ts +152 -0
  199. package/src/scripts-runtime/executors/quickjs-prelude.ts +285 -0
  200. package/src/scripts-runtime/executors/quickjs-runner.ts +580 -0
  201. package/src/scripts-runtime/executors/quickjs-worker.ts +81 -0
  202. package/src/scripts-runtime/executors/quickjs.ts +196 -0
  203. package/src/scripts-runtime/executors/registry.ts +2 -0
  204. package/src/scripts-runtime/executors/sourcemap.ts +79 -0
  205. package/src/scripts-runtime/script-error-hints.ts +14 -0
  206. package/src/server.ts +66 -4
  207. package/src/tests/acp-adapter.test.ts +277 -12
  208. package/src/tests/boot-scrub-sweep.test.ts +390 -0
  209. package/src/tests/check-text-columns.test.ts +145 -0
  210. package/src/tests/ci-unit-test-report.test.ts +73 -0
  211. package/src/tests/claude-default-route.test.ts +75 -0
  212. package/src/tests/claude-hook-output.test.ts +233 -0
  213. package/src/tests/claude-sdk-process.fixture.ts +13 -2
  214. package/src/tests/codex-adapter-pool-auth-revalidate.test.ts +4 -2
  215. package/src/tests/codex-adapter.test.ts +166 -26
  216. package/src/tests/codex-oauth-auth-timestamps.test.ts +76 -0
  217. package/src/tests/codex-oauth-device.test.ts +23 -37
  218. package/src/tests/codex-oauth.test.ts +4 -1
  219. package/src/tests/context-window.test.ts +2 -2
  220. package/src/tests/credential-check.test.ts +51 -1
  221. package/src/tests/db-query-denylist.test.ts +202 -0
  222. package/src/tests/db-task-read-contract.test.ts +1 -0
  223. package/src/tests/db-task-write-contract.test.ts +1 -0
  224. package/src/tests/dsh-adapter.test.ts +23 -1
  225. package/src/tests/enabled-tools.test.ts +269 -0
  226. package/src/tests/entrypoint-acp-target-binary.test.ts +31 -1
  227. package/src/tests/entrypoint-codex-oauth-seed.test.ts +12 -0
  228. package/src/tests/events-scrub.test.ts +88 -0
  229. package/src/tests/fixtures/secret-corpus.ts +320 -0
  230. package/src/tests/grok-adapter.test.ts +13 -0
  231. package/src/tests/haiku-5-5-pricing.test.ts +38 -0
  232. package/src/tests/heartbeat-checklist.test.ts +158 -1
  233. package/src/tests/onboarding.test.ts +44 -0
  234. package/src/tests/opencode-adapter.test.ts +66 -3
  235. package/src/tests/opencode-plugin.test.ts +37 -0
  236. package/src/tests/openrouter-attribution-call-sites.test.ts +204 -0
  237. package/src/tests/openrouter-base-url.test.ts +30 -39
  238. package/src/tests/pi-mono-extension.test.ts +161 -2
  239. package/src/tests/pricing-refresh.test.ts +70 -1
  240. package/src/tests/reasoning-effort.test.ts +3 -1
  241. package/src/tests/script-connections.test.ts +5 -0
  242. package/src/tests/script-executor-conformance.test.ts +3 -0
  243. package/src/tests/script-executor-quickjs.test.ts +442 -0
  244. package/src/tests/script-executor-registry.test.ts +6 -1
  245. package/src/tests/script-runs-http.test.ts +88 -1
  246. package/src/tests/script-runs-scrub.test.ts +275 -0
  247. package/src/tests/scripts-http.test.ts +82 -1
  248. package/src/tests/scrubbed-text-12e.test.ts +289 -0
  249. package/src/tests/sealed-key-guard.test.ts +166 -0
  250. package/src/tests/secret-canary-sweep.test.ts +958 -0
  251. package/src/tests/secret-registry.test.ts +355 -0
  252. package/src/tests/secret-rules.test.ts +230 -0
  253. package/src/tests/secret-scrubber.test.ts +3 -2
  254. package/src/tests/telemetry-trigger.test.ts +12 -1
  255. package/src/tests/workflow-llm.test.ts +14 -0
  256. package/src/tests/workflow-replay.test.ts +518 -0
  257. package/src/tests/workflow-scrub.test.ts +242 -0
  258. package/src/tests/workflow-system-one-decision-providers.test.ts +33 -0
  259. package/src/tools/db-query.ts +1 -1
  260. package/src/tools/inject-learning.ts +1 -1
  261. package/src/tools/request-human-input.ts +7 -2
  262. package/src/tools/workflows/get-workflow-run.ts +3 -2
  263. package/src/types.ts +1 -1
  264. package/src/utils/enabled-tools.ts +27 -0
  265. package/src/utils/internal-ai/complete-structured.ts +11 -3
  266. package/src/utils/openrouter-base-url.ts +23 -0
  267. package/src/utils/secret-rules.generated.ts +2055 -0
  268. package/src/utils/secret-scrubber.ts +363 -29
  269. package/src/workflows/engine.ts +39 -4
  270. package/src/workflows/executors/raw-llm.ts +1 -0
  271. package/src/workflows/executors/system-one-decision.ts +2 -0
  272. package/src/workflows/executors/validate.ts +1 -0
  273. package/src/workflows/executors/workflow-llm.ts +9 -2
  274. package/src/workflows/recovery.ts +10 -1
  275. package/src/workflows/resume.ts +62 -3
  276. package/src/workflows/retry-poller.ts +3 -0
  277. package/templates/skills/agent-browser/SKILL.md +2 -0
  278. package/templates/skills/agent-browser/content.md +2 -0
  279. package/templates/skills/code-quality/content.md +1 -0
  280. package/templates/skills/heartbeat-runbook/content.md +1 -1
  281. package/templates/skills/work-on-task/SKILL.md +4 -0
  282. package/templates/skills/work-on-task/content.md +4 -0
  283. package/templates/skills/workflow-iterate/content.md +9 -0
  284. package/dist/acp-adapter-w6zws6me.js +0 -23
  285. package/dist/boot-scrub-logs-246yn076.js +0 -99
  286. package/dist/cli-3a4m1aws.js +0 -572
  287. package/dist/cli-3dpj7atn.js +0 -11
  288. package/dist/cli-a87b04k8.js +0 -951
  289. package/dist/cli-cvk6yzw5.js +0 -40
  290. package/dist/cli-gvcgmx69.js +0 -183
  291. package/dist/cli-h1spv8v4.js +0 -427
  292. package/dist/cli-jqt9hrnz.js +0 -168
  293. package/dist/cli-yhmwmv0g.js +0 -9281
  294. package/dist/grok-adapter-yt9pab3k.js +0 -29
  295. package/src/be/boot-scrub-logs.ts +0 -132
  296. package/dist/{codex-hook-d2rkvf39.js → codex-hook-15dgc4cb.js} +1 -1
@@ -1,6 +1,6 @@
1
1
  import { afterEach, describe, expect, spyOn, test } from "bun:test";
2
- import { mkdtempSync, rmSync } from "node:fs";
3
- import { createServer, type IncomingMessage, type Server, type ServerResponse } from "node:http";
2
+ import { chmodSync, existsSync, mkdirSync, mkdtempSync, rmSync } from "node:fs";
3
+ import { createServer, type IncomingMessage, type ServerResponse } from "node:http";
4
4
  import { tmpdir } from "node:os";
5
5
  import { join } from "node:path";
6
6
  import type { Usage } from "@agentclientprotocol/sdk";
@@ -22,7 +22,12 @@ import {
22
22
  sanitizeAcpConfigOptions,
23
23
  toAcpMcpServers,
24
24
  } from "../providers/acp-adapter";
25
- import { AcpTargetResolutionError, resolveAcpTarget } from "../providers/acp-targets";
25
+ import {
26
+ AcpTargetResolutionError,
27
+ COPILOT_INSTRUCTIONS_FILE,
28
+ copilotInstructionsDir,
29
+ resolveAcpTarget,
30
+ } from "../providers/acp-targets";
26
31
  import type { ProviderEvent, ProviderSessionConfig } from "../providers/types";
27
32
  import { listenOnFreePort } from "./test-net";
28
33
 
@@ -59,20 +64,29 @@ function baseConfig(overrides: Partial<ProviderSessionConfig> = {}): ProviderSes
59
64
 
60
65
  /**
61
66
  * Start a minimal swarm API stub that handles POST /api/sessions/tokens and
62
- * DELETE /api/sessions/tokens/:id. Returns the server and its base URL.
63
- * The caller is responsible for closing the server.
67
+ * DELETE /api/sessions/tokens/:id. Returns its base URL and `close()`, which
68
+ * the caller must await. The adapter revokes a minted token fire-and-forget,
69
+ * so closing before that DELETE lands fails it and leaks a revoke warning
70
+ * into a later test.
64
71
  */
65
72
  async function startTokenStubServer(
66
73
  tokenId: string,
67
74
  plaintext: string,
68
- ): Promise<{ server: Server; apiUrl: string }> {
75
+ ): Promise<{ apiUrl: string; close: () => Promise<void> }> {
76
+ let minted = false;
77
+ let resolveRevoked!: () => void;
78
+ const revoked = new Promise<void>((resolve) => {
79
+ resolveRevoked = resolve;
80
+ });
69
81
  const stub = createServer(async (req: IncomingMessage, res: ServerResponse) => {
70
82
  if (req.method === "POST" && req.url === "/api/sessions/tokens") {
83
+ minted = true;
71
84
  res.writeHead(200, { "Content-Type": "application/json" });
72
85
  res.end(JSON.stringify({ tokenId, plaintext }));
73
86
  } else if (req.method === "DELETE" && req.url?.startsWith("/api/sessions/tokens/")) {
74
87
  res.writeHead(204);
75
88
  res.end();
89
+ resolveRevoked();
76
90
  } else {
77
91
  res.writeHead(404);
78
92
  res.end();
@@ -80,7 +94,13 @@ async function startTokenStubServer(
80
94
  });
81
95
  await new Promise<void>((resolve) => stub.listen(0, "127.0.0.1", resolve));
82
96
  const addr = stub.address() as import("net").AddressInfo;
83
- return { server: stub, apiUrl: `http://127.0.0.1:${addr.port}` };
97
+ const close = async () => {
98
+ // A minted token is always revoked; wait for it, bounded so a failed test
99
+ // still tears down.
100
+ if (minted) await Promise.race([revoked, Bun.sleep(5_000)]);
101
+ await new Promise<void>((resolve) => stub.close(() => resolve()));
102
+ };
103
+ return { apiUrl: `http://127.0.0.1:${addr.port}`, close };
84
104
  }
85
105
 
86
106
  describe("ACPAdapter", () => {
@@ -300,7 +320,7 @@ new AgentSideConnection((connection) => new FakeAgent(connection), stream);
300
320
  `,
301
321
  );
302
322
 
303
- const { server: tokenStub, apiUrl } = await startTokenStubServer(
323
+ const { close: closeTokenStub, apiUrl } = await startTokenStubServer(
304
324
  "stub-token-id",
305
325
  "aseph_stubtokenfortest1234567890",
306
326
  );
@@ -498,7 +518,7 @@ new AgentSideConnection((connection) => new FakeAgent(connection), stream);
498
518
  closeDb();
499
519
  }
500
520
  } finally {
501
- await new Promise<void>((resolve) => tokenStub.close(() => resolve()));
521
+ await closeTokenStub();
502
522
  }
503
523
  });
504
524
 
@@ -532,8 +552,130 @@ new AgentSideConnection((connection) => new FakeAgent(connection), stream);
532
552
  ),
533
553
  ).toMatchObject({
534
554
  OPENAI_API_KEY: "example-test-key",
535
- OPENCODE_CONFIG_CONTENT: JSON.stringify({ theme: "dark", model: "opencode/model" }),
555
+ OPENCODE_CONFIG_CONTENT: JSON.stringify({
556
+ theme: "dark",
557
+ model: "opencode/model",
558
+ provider: {
559
+ openrouter: {
560
+ options: {
561
+ headers: {
562
+ "HTTP-Referer": "https://agent-swarm.dev",
563
+ "X-OpenRouter-Title": "Agent Swarm",
564
+ "X-OpenRouter-Categories": "personal-agent,cloud-agent",
565
+ "X-Title": "Agent Swarm",
566
+ },
567
+ },
568
+ },
569
+ },
570
+ }),
571
+ });
572
+ });
573
+
574
+ test("OpenCode preset merges the OpenRouter gateway with model and provider config", () => {
575
+ const config = baseConfig({
576
+ model: " openrouter/openai/gpt-4o-mini ",
577
+ env: {
578
+ ACP_TARGET: "opencode",
579
+ OPENROUTER_BASE_URL: " http://127.0.0.1:8080/api/v1/ ",
580
+ OPENCODE_CONFIG_CONTENT: JSON.stringify({
581
+ theme: "dark",
582
+ provider: { openrouter: { options: { apiKey: "dummy" } } },
583
+ }),
584
+ },
585
+ });
586
+ const env = resolveAcpTarget(config).env(config);
587
+ expect(JSON.parse(env.OPENCODE_CONFIG_CONTENT!)).toEqual({
588
+ theme: "dark",
589
+ model: "openrouter/openai/gpt-4o-mini",
590
+ provider: {
591
+ openrouter: { options: { apiKey: "dummy", baseURL: "http://127.0.0.1:8080/api/v1" } },
592
+ },
593
+ });
594
+ });
595
+
596
+ test("OpenCode preset omits gateway override for unset, blank, or default URL", () => {
597
+ for (const url of [undefined, "", "https://openrouter.ai/api/v1/"]) {
598
+ const config = baseConfig({
599
+ env: { ACP_TARGET: "opencode", OPENROUTER_BASE_URL: url },
600
+ });
601
+ const env = resolveAcpTarget(config).env(config);
602
+ const content = JSON.parse(env.OPENCODE_CONFIG_CONTENT!);
603
+ expect(content).toEqual({
604
+ model: config.model,
605
+ provider: {
606
+ openrouter: {
607
+ options: {
608
+ headers: {
609
+ "HTTP-Referer": "https://agent-swarm.dev",
610
+ "X-OpenRouter-Title": "Agent Swarm",
611
+ "X-OpenRouter-Categories": "personal-agent,cloud-agent",
612
+ "X-Title": "Agent Swarm",
613
+ },
614
+ },
615
+ },
616
+ },
617
+ });
618
+ expect(content.provider.openrouter.options.baseURL).toBeUndefined();
619
+ }
620
+ });
621
+
622
+ test("OpenCode preset adds attribution headers to OPENCODE_CONFIG_CONTENT for an OpenRouter host", () => {
623
+ const config = baseConfig({
624
+ model: "",
625
+ env: {
626
+ ACP_TARGET: "opencode",
627
+ OPENROUTER_BASE_URL: "https://openrouter.ai/api/v1",
628
+ OPENCODE_CONFIG_CONTENT: JSON.stringify({
629
+ theme: "dark",
630
+ provider: { openrouter: { options: { headers: { "X-Custom": "preserved" } } } },
631
+ }),
632
+ },
633
+ });
634
+ const env = resolveAcpTarget(config).env(config);
635
+ expect(JSON.parse(env.OPENCODE_CONFIG_CONTENT!)).toEqual({
636
+ theme: "dark",
637
+ provider: {
638
+ openrouter: {
639
+ options: {
640
+ headers: {
641
+ "X-Custom": "preserved",
642
+ "HTTP-Referer": "https://agent-swarm.dev",
643
+ "X-OpenRouter-Title": "Agent Swarm",
644
+ "X-OpenRouter-Categories": "personal-agent,cloud-agent",
645
+ "X-Title": "Agent Swarm",
646
+ },
647
+ },
648
+ },
649
+ },
650
+ });
651
+ });
652
+
653
+ test("OpenCode preset leaves OPENCODE_CONFIG_CONTENT unchanged when attribution is disabled", () => {
654
+ const content = JSON.stringify({
655
+ theme: "dark",
656
+ provider: { openrouter: { options: { headers: { "X-Custom": "preserved" } } } },
657
+ });
658
+ const config = baseConfig({
659
+ model: "",
660
+ env: {
661
+ ACP_TARGET: "opencode",
662
+ OPENROUTER_BASE_URL: "https://openrouter.ai/api/v1",
663
+ OPENROUTER_APP_ATTRIBUTION: "false",
664
+ OPENCODE_CONFIG_CONTENT: content,
665
+ },
536
666
  });
667
+ expect(resolveAcpTarget(config).env(config).OPENCODE_CONFIG_CONTENT).toBe(content);
668
+ });
669
+
670
+ test("OpenCode preset injects gateway even without a model fallback", () => {
671
+ const config = baseConfig({
672
+ model: "",
673
+ env: { ACP_TARGET: "opencode", OPENROUTER_BASE_URL: "http://127.0.0.1:8080/api/v1" },
674
+ });
675
+ const env = resolveAcpTarget(config).env(config);
676
+ expect(JSON.parse(env.OPENCODE_CONFIG_CONTENT!).provider.openrouter.options.baseURL).toBe(
677
+ "http://127.0.0.1:8080/api/v1",
678
+ );
537
679
  });
538
680
 
539
681
  test("Gemini preset supplies command, credentials, trust, and a model environment fallback", () => {
@@ -600,6 +742,129 @@ new AgentSideConnection((connection) => new FakeAgent(connection), stream);
600
742
  expect(target.env(config).GEMINI_SYSTEM_MD).toBeUndefined();
601
743
  });
602
744
 
745
+ test("Copilot preset forwards its own credentials, pins the model, and never forwards GITHUB_TOKEN", () => {
746
+ const config = baseConfig({
747
+ model: "openai/gpt-5.2",
748
+ env: {
749
+ PATH: "/bin",
750
+ HOME: "/home/test",
751
+ ACP_TARGET: "copilot",
752
+ COPILOT_GITHUB_TOKEN: "example-copilot-token",
753
+ COPILOT_PROVIDER_BASE_URL: "https://llm.example/v1",
754
+ COPILOT_PROVIDER_API_KEY: "example-provider-key",
755
+ COPILOT_CUSTOM_INSTRUCTIONS_DIRS: "/opt/team-instructions",
756
+ GITHUB_TOKEN: "example-git-token",
757
+ GH_TOKEN: "example-gh-token",
758
+ },
759
+ });
760
+ const target = resolveAcpTarget(config);
761
+
762
+ expect(target.target).toBe("copilot");
763
+ expect(target.command(config)).toEqual(["copilot", "--acp"]);
764
+ const env = target.env(config);
765
+ expect(env).toMatchObject({
766
+ COPILOT_GITHUB_TOKEN: "example-copilot-token",
767
+ COPILOT_PROVIDER_BASE_URL: "https://llm.example/v1",
768
+ COPILOT_PROVIDER_API_KEY: "example-provider-key",
769
+ COPILOT_MODEL: "openai/gpt-5.2",
770
+ COPILOT_AUTO_UPDATE: "false",
771
+ COPILOT_CUSTOM_INSTRUCTIONS_DIRS: `${copilotInstructionsDir(config)},/opt/team-instructions`,
772
+ });
773
+ // The worker's git token lacks the Copilot Requests permission and would
774
+ // shadow a BYOK or COPILOT_GITHUB_TOKEN setup.
775
+ expect(env.GITHUB_TOKEN).toBeUndefined();
776
+ expect(env.GH_TOKEN).toBeUndefined();
777
+ });
778
+
779
+ test("Copilot preset delivers the system prompt outside the repo and removes it after the session", async () => {
780
+ const cwd = makeTempDir();
781
+ const binDir = makeTempDir();
782
+ const captureFile = join(binDir, "capture.json");
783
+ const agentPath = join(binDir, "fake-copilot-acp.ts");
784
+ const sdkPath = join(process.cwd(), "node_modules/@agentclientprotocol/sdk/dist/acp.js");
785
+ const repoAgentsMd = "# Repo rules\nKeep this file as is.\n";
786
+ await Bun.write(join(cwd, "AGENTS.md"), repoAgentsMd);
787
+ await Bun.write(
788
+ agentPath,
789
+ `
790
+ import { readFileSync } from "node:fs";
791
+ import { join } from "node:path";
792
+ import { Readable, Writable } from "node:stream";
793
+ import { AgentSideConnection, PROTOCOL_VERSION, ndJsonStream } from "${sdkPath}";
794
+ class FakeCopilot {
795
+ constructor(connection) { this.connection = connection; }
796
+ async initialize() {
797
+ return { protocolVersion: PROTOCOL_VERSION, agentCapabilities: { loadSession: false } };
798
+ }
799
+ async newSession() {
800
+ const dir = process.env.COPILOT_CUSTOM_INSTRUCTIONS_DIRS.split(",")[0];
801
+ await Bun.write(${JSON.stringify(captureFile)}, JSON.stringify({
802
+ argv: process.argv.slice(2),
803
+ dir,
804
+ instructions: readFileSync(join(dir, ${JSON.stringify(COPILOT_INSTRUCTIONS_FILE)}), "utf8"),
805
+ model: process.env.COPILOT_MODEL,
806
+ }));
807
+ return { sessionId: "copilot-session-1" };
808
+ }
809
+ async prompt(params) {
810
+ await this.connection.sessionUpdate({
811
+ sessionId: params.sessionId,
812
+ update: { sessionUpdate: "agent_message_chunk", content: { type: "text", text: "done" }, messageId: "m1" },
813
+ });
814
+ return { stopReason: "end_turn" };
815
+ }
816
+ async cancel() {}
817
+ }
818
+ const stream = ndJsonStream(Writable.toWeb(process.stdout), Readable.toWeb(process.stdin));
819
+ new AgentSideConnection((connection) => new FakeCopilot(connection), stream);
820
+ `,
821
+ );
822
+ const copilotStub = join(binDir, "copilot");
823
+ await Bun.write(copilotStub, `#!/bin/sh\nexec "${process.execPath}" "${agentPath}" "$@"\n`);
824
+ chmodSync(copilotStub, 0o755);
825
+ mkdirSync(join(binDir, "home"));
826
+
827
+ const { close: closeTokenStub, apiUrl } = await startTokenStubServer(
828
+ "copilot-token-id",
829
+ "example-aseph_x",
830
+ );
831
+ try {
832
+ const config = baseConfig({
833
+ cwd,
834
+ apiUrl,
835
+ model: "openai/gpt-5.2",
836
+ systemPrompt: "You are a swarm worker.",
837
+ env: {
838
+ PATH: `${binDir}:${process.env.PATH ?? ""}`,
839
+ HOME: join(binDir, "home"),
840
+ ACP_TARGET: "copilot",
841
+ },
842
+ });
843
+ const session = await new ACPAdapter().createSession(config);
844
+ const result = await session.waitForCompletion();
845
+ expect(result.isError).toBe(false);
846
+
847
+ const captured = JSON.parse(await Bun.file(captureFile).text()) as {
848
+ argv: string[];
849
+ dir: string;
850
+ instructions: string;
851
+ model: string;
852
+ };
853
+ expect(captured.argv).toEqual(["--acp"]);
854
+ expect(captured.dir).toBe(copilotInstructionsDir(config));
855
+ expect(captured.dir.startsWith(cwd)).toBe(false);
856
+ expect(captured.instructions).toBe('---\napplyTo: "**"\n---\n\nYou are a swarm worker.\n');
857
+ expect(captured.model).toBe("openai/gpt-5.2");
858
+ expect(await Bun.file(join(cwd, "AGENTS.md")).text()).toBe(repoAgentsMd);
859
+
860
+ const deadline = Date.now() + 2_000;
861
+ while (existsSync(captured.dir) && Date.now() < deadline) await Bun.sleep(10);
862
+ expect(existsSync(captured.dir)).toBe(false);
863
+ } finally {
864
+ await closeTokenStub();
865
+ }
866
+ });
867
+
603
868
  test("custom target passes through only explicitly named env and supports a model env fallback", () => {
604
869
  const config = baseConfig({
605
870
  model: "custom-model",
@@ -952,7 +1217,7 @@ const stream = ndJsonStream(Writable.toWeb(process.stdout), Readable.toWeb(proce
952
1217
  new AgentSideConnection((connection) => new FakeAgent(connection), stream);
953
1218
  `,
954
1219
  );
955
- const { server: tokenStub, apiUrl } = await startTokenStubServer(
1220
+ const { close: closeTokenStub, apiUrl } = await startTokenStubServer(
956
1221
  "stub-token-id",
957
1222
  "aseph_stubtokenfortest1234567890",
958
1223
  );
@@ -1015,7 +1280,7 @@ new AgentSideConnection((connection) => new FakeAgent(connection), stream);
1015
1280
  closeDb();
1016
1281
  }
1017
1282
  } finally {
1018
- await new Promise<void>((resolve) => tokenStub.close(() => resolve()));
1283
+ await closeTokenStub();
1019
1284
  }
1020
1285
  });
1021
1286
  });