@desplega.ai/agent-swarm 2.5.4 → 2.7.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 (354) hide show
  1. package/README.md +4 -2
  2. package/dist/{acp-adapter-ek38cwsv.js → acp-adapter-ma1js5n7.js} +9 -9
  3. package/dist/{actions-92mepq03.js → actions-1vhmtvg9.js} +21 -21
  4. package/dist/{amp-adapter-9gaxg015.js → amp-adapter-sxqqvmdk.js} +4 -4
  5. package/dist/{app-ctn8gsgx.js → app-mwx1d5a9.js} +3 -3
  6. package/dist/{assistant-zyr5kz47.js → assistant-yx1p6g82.js} +30 -26
  7. package/dist/{boot-reembed-w75maga2.js → boot-reembed-5h37a2c2.js} +1 -1
  8. package/dist/{boot-reembed-dwzfttdr.js → boot-reembed-7h78vmvv.js} +2 -1
  9. package/dist/{boot-scrub-sweep-e9kq43kf.js → boot-scrub-sweep-8mawd4gw.js} +4 -4
  10. package/dist/{boot-seeds-x28v3fhb.js → boot-seeds-ca84dhnn.js} +4 -4
  11. package/dist/{claude-adapter-f0afqnne.js → claude-adapter-wqt4hfkq.js} +9 -9
  12. package/dist/{claude-managed-adapter-x81a7r65.js → claude-managed-adapter-6fjqtr2z.js} +2 -2
  13. package/dist/{claude-managed-setup-bqzwjd9x.js → claude-managed-setup-rqv98sea.js} +10 -3
  14. package/dist/{claude-sdk-session-7b7whkaq.js → claude-sdk-session-f29f3b2x.js} +11 -11
  15. package/dist/{cli-sxgtf5fw.js → cli-07q03xm2.js} +1 -1
  16. package/dist/{cli-kxpfx2xr.js → cli-0z1xjzwa.js} +2 -2
  17. package/dist/{cli-g9vd9ece.js → cli-1hhbzkbb.js} +14 -16
  18. package/dist/{cli-qqzmjxkf.js → cli-1m9x8dr5.js} +11 -6
  19. package/dist/{cli-jbnn4vxb.js → cli-2pvzmas1.js} +3 -3
  20. package/dist/{cli-x77gen2p.js → cli-2y7v133v.js} +7 -7
  21. package/dist/{cli-dew6x255.js → cli-39aet655.js} +2 -2
  22. package/dist/{cli-g1cw7xtt.js → cli-39rrw8yp.js} +1 -1
  23. package/dist/{cli-jb30dzvk.js → cli-48gxjmcz.js} +530 -190
  24. package/dist/{cli-pzatvw94.js → cli-54sj64fc.js} +2 -2
  25. package/dist/{cli-bvpgr9ny.js → cli-60sty27p.js} +5 -5
  26. package/dist/{cli-asq5ydm4.js → cli-6a9qfa8b.js} +411 -69
  27. package/dist/{cli-277c31dw.js → cli-6mgdba42.js} +225 -3
  28. package/dist/{cli-19202kew.js → cli-6srv653c.js} +5 -5
  29. package/dist/{cli-n4c8e3s5.js → cli-708wdy32.js} +1 -1
  30. package/dist/{cli-pasyvjmm.js → cli-737pyqxr.js} +1 -1
  31. package/dist/{cli-6x9ma5w5.js → cli-803188pb.js} +1 -1
  32. package/dist/{cli-hh5we352.js → cli-86ehn4s5.js} +7 -7
  33. package/dist/{cli-9s05422w.js → cli-8mbc9za9.js} +1 -1
  34. package/dist/{cli-ff1tm9n9.js → cli-8wmj18cz.js} +1 -1
  35. package/dist/{cli-1r5ad7j5.js → cli-9gsm2rzp.js} +12 -12
  36. package/dist/{cli-mz9afxxf.js → cli-9pshx6rd.js} +17 -3
  37. package/dist/{cli-s682zgqz.js → cli-a6ds2epe.js} +1 -1
  38. package/dist/{cli-6a1xg1p7.js → cli-a89zdqz9.js} +2 -2
  39. package/dist/{cli-03vpq45j.js → cli-ay40dnj3.js} +2 -2
  40. package/dist/{cli-tsma7p8v.js → cli-aypd09nf.js} +2 -2
  41. package/dist/{cli-ethgy7ha.js → cli-b3yzyc57.js} +2 -2
  42. package/dist/{cli-bn0rewsy.js → cli-c081bj3b.js} +2 -2
  43. package/dist/{cli-mmhj8vd7.js → cli-c668vvcf.js} +11 -2
  44. package/dist/{cli-sbwsxvtd.js → cli-d20qvpr2.js} +2 -2
  45. package/dist/{cli-c952c7ac.js → cli-e1595bgx.js} +3 -3
  46. package/dist/{cli-621ce7kw.js → cli-f12mr20z.js} +3 -3
  47. package/dist/{cli-dqygeeh5.js → cli-f1e0ptjj.js} +10 -1
  48. package/dist/{cli-xzfq4at3.js → cli-f4dbh7a5.js} +16 -12
  49. package/dist/{cli-ha9rmwgq.js → cli-fb8m699c.js} +2 -2
  50. package/dist/{cli-5bnsc0e1.js → cli-gsfk58nw.js} +5 -5
  51. package/dist/cli-gt4h8cxw.js +895 -0
  52. package/dist/{cli-nwyw3zhg.js → cli-gxee0bqa.js} +1 -1
  53. package/dist/{cli-25n3mv5d.js → cli-h5jeg46p.js} +6 -6
  54. package/dist/{cli-gn5af0x5.js → cli-he9gbdx0.js} +62 -12
  55. package/dist/{cli-gbfxp48k.js → cli-j0ppywdr.js} +42 -35
  56. package/dist/{cli-k4tjsdx9.js → cli-j3y0x2n4.js} +277 -199
  57. package/dist/{cli-7p4jxgtt.js → cli-j9bpmykh.js} +75 -27
  58. package/dist/{cli-dabehxhp.js → cli-kt907da6.js} +1 -1
  59. package/dist/{cli-wx2nj19m.js → cli-kv7sbc2c.js} +6 -6
  60. package/dist/{cli-abs8ndtr.js → cli-m30k9777.js} +26 -26
  61. package/dist/{cli-cz5nmdxt.js → cli-m5e802r7.js} +2 -2
  62. package/dist/{cli-0shx9j93.js → cli-pfk92eqz.js} +2 -2
  63. package/dist/{cli-xtrz6bzs.js → cli-ptfq202x.js} +5 -3
  64. package/dist/{cli-6n8axjv1.js → cli-qj442fws.js} +2 -2
  65. package/dist/{cli-c61mbdds.js → cli-rd5m70gj.js} +4 -4
  66. package/dist/{cli-eftzyh9y.js → cli-s09j9vp5.js} +2 -2
  67. package/dist/{cli-m4ecdxvz.js → cli-s0mgx214.js} +7 -7
  68. package/dist/{cli-wghjkr0e.js → cli-sgqm2582.js} +10 -7
  69. package/dist/{cli-2655k16q.js → cli-sjctjr48.js} +2 -2
  70. package/dist/{cli-nzfnt2gs.js → cli-tf1n0r0b.js} +1 -1
  71. package/dist/{cli-x0f2v69c.js → cli-twctnkng.js} +12 -7
  72. package/dist/{cli-j6rktc91.js → cli-v6shg7na.js} +1 -1
  73. package/dist/{cli-gx4rm0qx.js → cli-vz78s5wm.js} +1 -1
  74. package/dist/{cli-gwhjmh8g.js → cli-wqr7cea4.js} +5 -5
  75. package/dist/{cli-e42vss7b.js → cli-x37r7qwf.js} +16 -8
  76. package/dist/{cli-4b2z6n0m.js → cli-yd2nreqw.js} +17 -8
  77. package/dist/{cli-64mh9mf3.js → cli-ymjpkxgn.js} +69 -17
  78. package/dist/{cli-5kqnemen.js → cli-yvy48785.js} +1 -1
  79. package/dist/{cli-9j129brq.js → cli-yxbsmx56.js} +6 -6
  80. package/dist/cli.js +22 -20
  81. package/dist/{codex-adapter-wch12q99.js → codex-adapter-zk59x2zh.js} +7 -7
  82. package/dist/{codex-hook-brpnycn5.js → codex-hook-xyjhvxwd.js} +1 -1
  83. package/dist/{codex-login-rn7c5gxt.js → codex-login-8cg0vhf2.js} +1 -1
  84. package/dist/{codex-session-runner-41pfcr95.js → codex-session-runner-kh6s4j3n.js} +8 -8
  85. package/dist/{commands-9849dkj6.js → commands-68et1qv2.js} +2 -2
  86. package/dist/{controller-ja0sd95p.js → controller-fyrbnzg4.js} +4 -4
  87. package/dist/{controllers-connect-xp05dj6x.js → controllers-connect-nep9h2xv.js} +23 -23
  88. package/dist/{cursor-adapter-623qxqew.js → cursor-adapter-yss3pg7t.js} +2 -2
  89. package/dist/{db-w759qmx0.js → db-28gjyvxj.js} +4 -2
  90. package/dist/{db-47vj40dy.js → db-8ftwvzba.js} +3 -3
  91. package/dist/{devin-adapter-4ycy4vrf.js → devin-adapter-byen2cxt.js} +1 -1
  92. package/dist/{dispatcher-7b8e4z2j.js → dispatcher-hayexmkr.js} +20 -20
  93. package/dist/{docker-s84hjs91.js → docker-fdzyewpz.js} +2 -2
  94. package/dist/{dsh-adapter-2ezw3xea.js → dsh-adapter-46wawff9.js} +2 -2
  95. package/dist/{e2b-9gkdhm3c.js → e2b-222hsajc.js} +2 -2
  96. package/dist/{e2b-cjtf8k1z.js → e2b-fn3zacvt.js} +2 -2
  97. package/dist/{easter-egg-3d-e4qv8dxj.js → easter-egg-3d-8d1e0h4m.js} +1 -1
  98. package/dist/{event-bus-3z78ep5n.js → event-bus-pghg8hqy.js} +1 -1
  99. package/dist/{execute-0xpz8950.js → execute-cjrfxfnm.js} +1 -1
  100. package/dist/{external-channel-e2s028da.js → external-channel-xbmxcg09.js} +2 -2
  101. package/dist/{grok-adapter-ys7gaqee.js → grok-adapter-ag4wks2a.js} +10 -10
  102. package/dist/handlers-tzmevqb5.js +41 -0
  103. package/dist/{heartbeat-w3mntghj.js → heartbeat-psfvcgwp.js} +23 -23
  104. package/dist/{hook-g7kvv6x9.js → hook-8pz04697.js} +6 -6
  105. package/dist/{hook-3jjywnpb.js → hook-cyq4mryn.js} +8 -8
  106. package/dist/{http-tkp7d4kb.js → http-haj1nd6k.js} +921 -169
  107. package/dist/{index-q7m26kvs.js → index-jwt2bj6f.js} +265 -97
  108. package/dist/{index-3n8m9ea2.js → index-q52f47pe.js} +1 -1
  109. package/dist/{index-31ceyf42.js → index-syvhnvtw.js} +1 -1
  110. package/dist/index-y1ajx04a.js +43 -0
  111. package/dist/{index-1ef1myq2.js → index-z5h22pes.js} +20 -20
  112. package/dist/{index-xdaahthb.js → index-zyq8ct52.js} +20 -20
  113. package/dist/{keepalive-v4ta8wgg.js → keepalive-xdvsamvj.js} +4 -4
  114. package/dist/lead-hqg57kdp.js +79 -0
  115. package/dist/{maintenance-84n1ex21.js → maintenance-4y2xzh3a.js} +1 -1
  116. package/dist/{oauth-refresh-sweep-vjnnandw.js → oauth-refresh-sweep-jd4r7zbs.js} +9 -4
  117. package/dist/{onboard-sfmpe4np.js → onboard-18447q9q.js} +6 -6
  118. package/dist/{opencode-adapter-jmpst4q4.js → opencode-adapter-26b2frdf.js} +7 -7
  119. package/dist/{otel-impl-v6cc0zve.js → otel-impl-f9tgr8yw.js} +2 -2
  120. package/dist/{pi-mono-adapter-fk8fkcf6.js → pi-mono-adapter-qn6qbga1.js} +38 -17
  121. package/dist/{pricing-refresh-fsk1e1zc.js → pricing-refresh-dw2tgb53.js} +3 -3
  122. package/dist/{rbac-roles-prmkdnkw.js → rbac-roles-aygm2760.js} +2 -2
  123. package/dist/{rbac-roles-zxmxqa39.js → rbac-roles-s4nwj2m3.js} +1 -1
  124. package/dist/render-v2-yfvdfr0x.js +16 -0
  125. package/dist/{resume-frdtgfa0.js → resume-1bmvjbf3.js} +9 -9
  126. package/dist/{runtime-bt5pkpm1.js → runtime-f7tpzedy.js} +1 -1
  127. package/dist/{session-access-fpez4y5q.js → session-access-r5garej6.js} +4 -4
  128. package/dist/session-source-backfill-424wzv0r.js +110 -0
  129. package/dist/{setup-mq6m3m8q.js → setup-8tygvxkq.js} +1 -1
  130. package/dist/{virtual-modules-mnfbh5mr.js → virtual-modules-xsw323b3.js} +2 -2
  131. package/dist/{work-objects-kfahhjsq.js → work-objects-ggnghpgf.js} +23 -23
  132. package/dist/worker-sqjd1nqf.js +79 -0
  133. package/dist/{x-pbpezr0s.js → x-wxrzvzx8.js} +2 -2
  134. package/openapi.json +1324 -14
  135. package/package.json +5 -3
  136. package/src/assets/source-key.ts +95 -0
  137. package/src/be/automation-preflight.ts +2 -0
  138. package/src/be/db/api-keys.ts +89 -0
  139. package/src/be/db/session-labels.ts +28 -0
  140. package/src/be/db/session-moves.ts +5 -6
  141. package/src/be/db/session-tree.ts +153 -14
  142. package/src/be/db/tasks/read.ts +11 -0
  143. package/src/be/db/tasks/write.ts +6 -1
  144. package/src/be/db/workflow-runs.ts +219 -6
  145. package/src/be/db-retention.ts +61 -6
  146. package/src/be/db.ts +135 -132
  147. package/src/be/memory/providers/openai-embedding.ts +5 -1
  148. package/src/be/memory/task-learning.ts +155 -0
  149. package/src/be/migrations/244_api_key_validation.sql +4 -0
  150. package/src/be/migrations/245_script_executor.sql +3 -0
  151. package/src/be/oauth-refresh-sweep.ts +2 -1
  152. package/src/be/onboarding.ts +4 -0
  153. package/src/be/scripts/boot-reembed.ts +2 -0
  154. package/src/be/scripts/db.ts +14 -4
  155. package/src/be/scripts/embeddings.ts +2 -0
  156. package/src/be/scripts/run-saved.ts +1 -0
  157. package/src/be/scripts/typecheck.ts +10 -4
  158. package/src/be/seed-skills/index.ts +7 -0
  159. package/src/be/session-source-backfill.ts +163 -0
  160. package/src/be/swarm-config-guard.ts +1 -0
  161. package/src/comb/review-batch.ts +28 -1
  162. package/src/comb/templates.ts +7 -2
  163. package/src/commands/claude-managed-setup.ts +7 -1
  164. package/src/commands/credential-refresh.ts +76 -1
  165. package/src/commands/credential-wait.ts +2 -2
  166. package/src/commands/onboard/compose-generator.ts +5 -3
  167. package/src/commands/provider-credentials.ts +212 -171
  168. package/src/commands/runner.ts +25 -4
  169. package/src/extensions/apply-task-create.ts +8 -1
  170. package/src/extensions/contract-types.generated.ts +1 -1
  171. package/src/extensions/contract.ts +5 -0
  172. package/src/heartbeat/heartbeat.ts +14 -1
  173. package/src/heartbeat/script-runner-probe.ts +47 -0
  174. package/src/http/all-routes.ts +2 -0
  175. package/src/http/api-keys.ts +77 -9
  176. package/src/http/assets.ts +15 -0
  177. package/src/http/codex-oauth-accounts.ts +191 -0
  178. package/src/http/comb.ts +15 -2
  179. package/src/http/config.ts +1 -1
  180. package/src/http/core.ts +6 -0
  181. package/src/http/fleet-benchmark.ts +5 -2
  182. package/src/http/idempotency-key.ts +1 -1
  183. package/src/http/index.ts +14 -3
  184. package/src/http/integrations.ts +5 -1
  185. package/src/http/kv.ts +8 -3
  186. package/src/http/onboarding.ts +6 -1
  187. package/src/http/pages-public.ts +38 -5
  188. package/src/http/pool-keys.ts +354 -0
  189. package/src/http/scripts.ts +27 -0
  190. package/src/http/sessions.ts +37 -12
  191. package/src/http/stats.ts +1 -0
  192. package/src/http/status.ts +26 -12
  193. package/src/http/tasks.ts +3 -0
  194. package/src/http/used-by.ts +7 -2
  195. package/src/http/workflows.ts +88 -9
  196. package/src/http/x.ts +5 -0
  197. package/src/integrations/chat-sdk/inbound.ts +27 -0
  198. package/src/kv-reserved-namespaces.ts +19 -0
  199. package/src/prompts/base-prompt.ts +21 -1
  200. package/src/prompts/session-templates.ts +17 -3
  201. package/src/providers/acp-targets.ts +1 -1
  202. package/src/providers/amp-adapter.ts +1 -1
  203. package/src/providers/claude-adapter.ts +5 -1
  204. package/src/providers/claude-managed-adapter.ts +16 -9
  205. package/src/providers/codex-adapter.ts +71 -11
  206. package/src/providers/dsh-adapter.ts +1 -1
  207. package/src/providers/pi-mono-adapter.ts +41 -11
  208. package/src/scheduler/scheduler.ts +5 -3
  209. package/src/scripts-runtime/eval-harness.ts +8 -1
  210. package/src/scripts-runtime/executors/native.ts +22 -16
  211. package/src/scripts-runtime/executors/quickjs-prelude.ts +103 -1
  212. package/src/scripts-runtime/executors/quickjs-runner.ts +2 -1
  213. package/src/scripts-runtime/executors/quickjs.ts +7 -0
  214. package/src/scripts-runtime/executors/registry.ts +32 -0
  215. package/src/scripts-runtime/executors/types.ts +7 -0
  216. package/src/scripts-runtime/host-validated-args.ts +133 -0
  217. package/src/scripts-runtime/loader.ts +30 -3
  218. package/src/scripts-runtime/swarm-sdk.ts +16 -3
  219. package/src/scripts-runtime/types/stdlib.d.ts +10 -2
  220. package/src/scripts-runtime/types/swarm-extension.d.ts +17 -8
  221. package/src/scripts-runtime/types/swarm-sdk.d.ts +10 -2
  222. package/src/slack/assistant.ts +7 -0
  223. package/src/slack/channel-labels.ts +74 -0
  224. package/src/slack/handlers.ts +8 -0
  225. package/src/slack/inbound-files.ts +5 -2
  226. package/src/slack/thread-buffer.ts +4 -0
  227. package/src/tasks/sibling-awareness.ts +12 -3
  228. package/src/telemetry-context.ts +5 -6
  229. package/src/telemetry-identity.ts +3 -3
  230. package/src/tests/api-key-status-by-suffix.test.ts +242 -0
  231. package/src/tests/api-keys-validation.test.ts +170 -0
  232. package/src/tests/base-prompt.test.ts +70 -2
  233. package/src/tests/claude-managed-adapter.test.ts +46 -0
  234. package/src/tests/claude-routes-e2e.test.ts +7 -2
  235. package/src/tests/codex-credential-pools.test.ts +120 -0
  236. package/src/tests/codex-gateway-route.test.ts +165 -0
  237. package/src/tests/codex-oauth-accounts.test.ts +357 -0
  238. package/src/tests/comb-review-batch.test.ts +63 -2
  239. package/src/tests/community-linear-delivery-loop.test.ts +2099 -0
  240. package/src/tests/config-pool-keys.test.ts +533 -0
  241. package/src/tests/credential-check.test.ts +294 -4
  242. package/src/tests/credential-refresh.test.ts +172 -1
  243. package/src/tests/db-retention.test.ts +9 -3
  244. package/src/tests/db-task-read-contract.test.ts +1 -0
  245. package/src/tests/db-task-write-contract.test.ts +1 -3
  246. package/src/tests/docs-index-footprint.test.js +3 -3
  247. package/src/tests/docs-index.test.ts +135 -0
  248. package/src/tests/dsh-adapter.test.ts +1 -1
  249. package/src/tests/extensions-pre-task.test.ts +53 -1
  250. package/src/tests/fetch-resolved-env.test.ts +16 -2
  251. package/src/tests/fixtures/extensions/record-task-create/hooks.ts +9 -0
  252. package/src/tests/fixtures/extensions/record-task-create/manifest.json +7 -0
  253. package/src/tests/fleet-benchmark.test.ts +8 -0
  254. package/src/tests/get-workflow-run-tool.test.ts +98 -0
  255. package/src/tests/heartbeat-checklist.test.ts +89 -0
  256. package/src/tests/heartbeat-script-runner-probe.test.ts +83 -0
  257. package/src/tests/integrations-http.test.ts +32 -2
  258. package/src/tests/internal-ai/complete-structured.test.ts +37 -1
  259. package/src/tests/internal-ai/credentials.test.ts +23 -0
  260. package/src/tests/kv-http.test.ts +32 -0
  261. package/src/tests/kv-tool.test.ts +25 -0
  262. package/src/tests/multi-runtime-registration.test.ts +12 -12
  263. package/src/tests/oauth-refresh-sweep.test.ts +34 -1
  264. package/src/tests/onboard-compose.test.ts +20 -0
  265. package/src/tests/onboarding.test.ts +108 -1
  266. package/src/tests/openai-embedding-credentials.test.ts +35 -0
  267. package/src/tests/opencode-adapter.test.ts +2 -1
  268. package/src/tests/openrouter-attribution-call-sites.test.ts +2 -2
  269. package/src/tests/org-website.test.ts +36 -0
  270. package/src/tests/pages-frame-ancestors.test.ts +162 -0
  271. package/src/tests/pi-codemode.test.ts +2 -1
  272. package/src/tests/pi-mono-adapter.test.ts +54 -0
  273. package/src/tests/pi-native-mcp.test.ts +13 -1
  274. package/src/tests/pi-tool-exposure.test.ts +8 -8
  275. package/src/tests/probe-tool-schema-tokens.test.ts +144 -0
  276. package/src/tests/prompt-template-session.test.ts +4 -3
  277. package/src/tests/provider-key-probes.test.ts +181 -0
  278. package/src/tests/rbac-e2e-helpers.test.ts +88 -1
  279. package/src/tests/rbac-e2e-helpers.ts +36 -11
  280. package/src/tests/request-composition-derive.test.ts +329 -0
  281. package/src/tests/script-connections.test.ts +4 -0
  282. package/src/tests/script-executor-conformance.test.ts +36 -1
  283. package/src/tests/script-executor-quickjs-pool.test.ts +50 -0
  284. package/src/tests/script-executor-quickjs.test.ts +140 -0
  285. package/src/tests/script-host-validated-args-native.test.ts +196 -0
  286. package/src/tests/script-per-script-executor.test.ts +415 -0
  287. package/src/tests/script-runs-retention.test.ts +212 -0
  288. package/src/tests/scripts-external-api.test.ts +45 -0
  289. package/src/tests/sdk-allowlist.test.ts +42 -2
  290. package/src/tests/self-improvement.test.ts +4 -4
  291. package/src/tests/session-source-backfill.test.ts +429 -0
  292. package/src/tests/session-source-keys.test.ts +236 -0
  293. package/src/tests/session-source-labels.test.ts +419 -0
  294. package/src/tests/sessions-detail-batch.test.ts +2 -0
  295. package/src/tests/sessions-move.test.ts +131 -0
  296. package/src/tests/sessions-tree.test.ts +299 -2
  297. package/src/tests/slack-inbound-files.test.ts +103 -23
  298. package/src/tests/status.test.ts +101 -18
  299. package/src/tests/store-progress-learning.test.ts +288 -0
  300. package/src/tests/tasks-workflow-run-filter.test.ts +146 -0
  301. package/src/tests/test-net.ts +31 -0
  302. package/src/tests/transcription.test.ts +8 -0
  303. package/src/tests/ui-logs-parser.test.ts +180 -0
  304. package/src/tests/used-by-route.test.ts +11 -0
  305. package/src/tests/workflow-cascade-cancel.test.ts +172 -0
  306. package/src/tests/workflow-engine-v2.test.ts +116 -1
  307. package/src/tests/workflow-http-v2.test.ts +131 -0
  308. package/src/tests/workflow-mcp-trigger-schema.test.ts +209 -0
  309. package/src/tests/workflow-run-finished-event.test.ts +263 -0
  310. package/src/tests/workflow-step-order.test.ts +92 -0
  311. package/src/tests/workflow-sub-workflow.test.ts +30 -0
  312. package/src/tests/workflow-swarm-script.test.ts +34 -0
  313. package/src/tools/get-tasks.ts +8 -0
  314. package/src/tools/kv/kv-read-auth.ts +4 -2
  315. package/src/tools/script-common.ts +1 -0
  316. package/src/tools/script-run.ts +7 -0
  317. package/src/tools/script-upsert.ts +7 -0
  318. package/src/tools/store-progress.ts +67 -1
  319. package/src/tools/task-action.ts +1 -1
  320. package/src/tools/workflows/get-workflow-run.ts +14 -4
  321. package/src/tools/workflows/trigger-workflow.ts +104 -10
  322. package/src/types.ts +36 -1
  323. package/src/utils/company-profile.ts +51 -1
  324. package/src/utils/credentials.ts +10 -4
  325. package/src/utils/internal-ai/complete-structured.ts +5 -0
  326. package/src/utils/internal-ai/credentials.ts +4 -3
  327. package/src/utils/provider-key-probes.ts +328 -0
  328. package/src/utils/transcription.ts +4 -1
  329. package/src/workflows/engine.ts +18 -16
  330. package/src/workflows/executors/sub-workflow.ts +8 -1
  331. package/src/workflows/executors/swarm-script.ts +5 -0
  332. package/src/workflows/foreach-driver.ts +5 -11
  333. package/src/workflows/node-timeout.ts +30 -0
  334. package/templates/ai-toolbox.manifest.json +2 -2
  335. package/templates/community/linear-delivery-loop/PLAYBOOK.md +323 -0
  336. package/templates/community/linear-delivery-loop/README.md +38 -0
  337. package/templates/community/linear-delivery-loop/config.example.json +31 -0
  338. package/templates/community/linear-delivery-loop/lead-prompt.md +34 -0
  339. package/templates/community/linear-delivery-loop/schedule.json +10 -0
  340. package/templates/community/linear-delivery-loop/scripts/linear-delivery-setup.ts +148 -0
  341. package/templates/community/linear-delivery-loop/scripts/linear-delivery-tick.ts +1781 -0
  342. package/templates/skills/researching/content.md +2 -0
  343. package/templates/skills/swarm-docs/config.json +14 -0
  344. package/templates/skills/swarm-docs/content.md +144 -0
  345. package/templates/skills/swarm-scripts/SKILL.md +1 -0
  346. package/templates/skills/swarm-scripts/content.md +1 -0
  347. package/dist/cli-7421jzsw.js +0 -84
  348. package/dist/cli-e45e4m6b.js +0 -413
  349. package/dist/cli-zw88zjba.js +0 -307
  350. package/dist/handlers-wy1dr6ja.js +0 -41
  351. package/dist/index-nmm79qgr.js +0 -43
  352. package/dist/lead-sawnyqxk.js +0 -79
  353. package/dist/render-v2-pjwxvnkw.js +0 -12
  354. package/dist/worker-v5e5rxj3.js +0 -79
@@ -0,0 +1,895 @@
1
+ import {
2
+ openAICompatibleProviders,
3
+ providerKeyVars,
4
+ providerForModel,
5
+ providerForKeyVar,
6
+ init_src2
7
+ } from "./cli-gxee0bqa.js";
8
+ import {
9
+ __esm
10
+ } from "./cli-242037k3.js";
11
+
12
+ // packages/model-routing/src/env.ts
13
+ function envValue(env, key) {
14
+ const value = env[key]?.trim();
15
+ return value ? value : undefined;
16
+ }
17
+ function isEnvTruthy(env, key) {
18
+ const value = envValue(env, key)?.toLowerCase();
19
+ return value === "1" || value === "true" || value === "yes" || value === "on";
20
+ }
21
+ var init_env = () => {};
22
+
23
+ // packages/model-routing/src/protocols.ts
24
+ function defineRouteProvider(p) {
25
+ return {
26
+ ...p,
27
+ isHarnessDefaultProtocol: p.isHarnessDefaultProtocol ?? ((harness, protocol) => HARNESS_DEFAULT_PROTOCOL[harness] === protocol)
28
+ };
29
+ }
30
+ var HARNESS_DEFAULT_PROTOCOL;
31
+ var init_protocols = __esm(() => {
32
+ HARNESS_DEFAULT_PROTOCOL = {
33
+ claude: "anthropic-messages",
34
+ codex: "openai-responses",
35
+ pi: "openai-chat",
36
+ opencode: "openai-chat",
37
+ dsh: "openai-chat"
38
+ };
39
+ });
40
+
41
+ // packages/model-routing/src/providers/anthropic-models.ts
42
+ function routeAuthHeaders(ctx) {
43
+ const { auth } = ctx.route;
44
+ if (auth.kind !== "bearer" && auth.kind !== "x-api-key" && auth.kind !== "header")
45
+ return {};
46
+ const secret = envValue(ctx.env, auth.secretKey);
47
+ if (!secret)
48
+ return {};
49
+ if (auth.kind === "bearer")
50
+ return { Authorization: `Bearer ${secret}` };
51
+ if (auth.kind === "x-api-key")
52
+ return { "x-api-key": secret };
53
+ return { [auth.header]: secret };
54
+ }
55
+ async function readBody(res) {
56
+ try {
57
+ return await res.text();
58
+ } catch {
59
+ return "";
60
+ }
61
+ }
62
+ function modelIds(body) {
63
+ try {
64
+ const parsed = JSON.parse(body);
65
+ if (!Array.isArray(parsed.data))
66
+ return;
67
+ return parsed.data.flatMap((m) => typeof m.id === "string" ? [m.id] : []);
68
+ } catch {
69
+ return;
70
+ }
71
+ }
72
+ async function checkAnthropicModels(ctx, opts = {}) {
73
+ const res = await ctx.fetch("/v1/models", {
74
+ method: "GET",
75
+ headers: {
76
+ "anthropic-version": ANTHROPIC_VERSION,
77
+ ...opts.extraHeaders,
78
+ ...routeAuthHeaders(ctx)
79
+ },
80
+ signal: ctx.signal
81
+ });
82
+ const body = await readBody(res);
83
+ if (res.ok)
84
+ return { status: "verified", models: modelIds(body) };
85
+ if (opts.notFoundIsConfigured && (res.status === 404 || res.status === 405)) {
86
+ return {
87
+ status: "configured",
88
+ reason: `HTTP ${res.status}: the endpoint does not list models, so the key was not checked`
89
+ };
90
+ }
91
+ return {
92
+ status: "failed",
93
+ reason: `HTTP ${res.status}: ${body.slice(0, 200)}`,
94
+ httpStatus: res.status
95
+ };
96
+ }
97
+ var ANTHROPIC_VERSION = "2023-06-01";
98
+ var init_anthropic_models = __esm(() => {
99
+ init_env();
100
+ });
101
+
102
+ // packages/model-routing/src/providers/secret-env.ts
103
+ function secretEnv(route) {
104
+ const { auth } = route;
105
+ return "secretKey" in auth ? [auth.secretKey] : [];
106
+ }
107
+ var init_secret_env = () => {};
108
+
109
+ // packages/model-routing/src/providers/anthropic.ts
110
+ var ANTHROPIC_API_BASE_URL = "https://api.anthropic.com", anthropicProvider;
111
+ var init_anthropic = __esm(() => {
112
+ init_protocols();
113
+ init_anthropic_models();
114
+ init_secret_env();
115
+ anthropicProvider = defineRouteProvider({
116
+ id: "anthropic",
117
+ name: "Anthropic API",
118
+ protocols: ["anthropic-messages"],
119
+ defaultBaseUrl: ANTHROPIC_API_BASE_URL,
120
+ requiredEnv: (route) => secretEnv(route),
121
+ validate: (ctx) => checkAnthropicModels(ctx)
122
+ });
123
+ });
124
+
125
+ // packages/model-routing/src/providers/anthropic-gateway.ts
126
+ function customHeaders(route, env) {
127
+ if (route.source !== "default")
128
+ return {};
129
+ const raw = envValue(env, "ANTHROPIC_CUSTOM_HEADERS");
130
+ if (!raw)
131
+ return {};
132
+ const headers = {};
133
+ for (const line of raw.split(`
134
+ `)) {
135
+ const colon = line.indexOf(":");
136
+ if (colon <= 0)
137
+ continue;
138
+ const name = line.slice(0, colon).trim();
139
+ const value = line.slice(colon + 1).trim();
140
+ if (name && value)
141
+ headers[name] = value;
142
+ }
143
+ return headers;
144
+ }
145
+ var anthropicGatewayProvider;
146
+ var init_anthropic_gateway = __esm(() => {
147
+ init_env();
148
+ init_protocols();
149
+ init_anthropic_models();
150
+ init_secret_env();
151
+ anthropicGatewayProvider = defineRouteProvider({
152
+ id: "anthropic-gateway",
153
+ name: "Anthropic-compatible gateway",
154
+ protocols: ["anthropic-messages"],
155
+ requiredEnv: (route) => secretEnv(route),
156
+ validate: (ctx) => checkAnthropicModels(ctx, {
157
+ extraHeaders: customHeaders(ctx.route, ctx.env),
158
+ notFoundIsConfigured: true
159
+ })
160
+ });
161
+ });
162
+
163
+ // packages/model-routing/src/providers/bedrock.ts
164
+ var bedrockProvider;
165
+ var init_bedrock = __esm(() => {
166
+ init_protocols();
167
+ init_secret_env();
168
+ bedrockProvider = defineRouteProvider({
169
+ id: "bedrock",
170
+ name: "Amazon Bedrock",
171
+ protocols: ["bedrock"],
172
+ requiredEnv: (route) => ["AWS_REGION", ...secretEnv(route)]
173
+ });
174
+ });
175
+
176
+ // packages/model-routing/src/providers/claude-subscription.ts
177
+ function errorType(body) {
178
+ try {
179
+ const parsed = JSON.parse(body);
180
+ return typeof parsed.error?.type === "string" ? parsed.error.type : undefined;
181
+ } catch {
182
+ return;
183
+ }
184
+ }
185
+ var claudeSubscriptionProvider;
186
+ var init_claude_subscription = __esm(() => {
187
+ init_env();
188
+ init_protocols();
189
+ init_anthropic();
190
+ claudeSubscriptionProvider = defineRouteProvider({
191
+ id: "claude-subscription",
192
+ name: "Claude subscription",
193
+ protocols: ["anthropic-messages"],
194
+ harnesses: ["claude"],
195
+ defaultBaseUrl: ANTHROPIC_API_BASE_URL,
196
+ requiredEnv: () => ["CLAUDE_CODE_OAUTH_TOKEN"],
197
+ validate: async (ctx) => {
198
+ const token = envValue(ctx.env, "CLAUDE_CODE_OAUTH_TOKEN");
199
+ const res = await ctx.fetch("/api/oauth/profile", {
200
+ method: "GET",
201
+ headers: { Authorization: `Bearer ${token}` },
202
+ signal: ctx.signal
203
+ });
204
+ if (res.ok)
205
+ return { status: "verified" };
206
+ const body = await res.text().catch(() => "");
207
+ if (res.status === 403 && errorType(body) === "permission_error") {
208
+ return { status: "verified" };
209
+ }
210
+ if (res.status === 429 || res.status >= 500) {
211
+ return {
212
+ status: "configured",
213
+ reason: `Anthropic did not answer the token check (HTTP ${res.status}), so it was not tested.`
214
+ };
215
+ }
216
+ if (res.status === 401) {
217
+ return {
218
+ status: "failed",
219
+ reason: "Anthropic rejected the Claude subscription token (HTTP 401). Make a new one with the claude setup-token command.",
220
+ httpStatus: 401
221
+ };
222
+ }
223
+ return {
224
+ status: "failed",
225
+ reason: `HTTP ${res.status}: ${body.slice(0, 200)}`,
226
+ httpStatus: res.status
227
+ };
228
+ }
229
+ });
230
+ });
231
+
232
+ // packages/model-routing/src/providers/foundry.ts
233
+ function foundryBaseUrl(resource) {
234
+ return `https://${resource}.services.ai.azure.com/anthropic`;
235
+ }
236
+ var foundryProvider;
237
+ var init_foundry = __esm(() => {
238
+ init_protocols();
239
+ init_secret_env();
240
+ foundryProvider = defineRouteProvider({
241
+ id: "foundry",
242
+ name: "Microsoft Foundry",
243
+ protocols: ["foundry"],
244
+ requiredEnv: (route) => [
245
+ ...route.baseUrl ? [] : ["ANTHROPIC_FOUNDRY_RESOURCE"],
246
+ ...secretEnv(route)
247
+ ]
248
+ });
249
+ });
250
+
251
+ // packages/model-routing/src/providers/openai-gateway.ts
252
+ async function checkOpenAiModels(ctx) {
253
+ const res = await ctx.fetch("/models", {
254
+ method: "GET",
255
+ headers: routeAuthHeaders(ctx),
256
+ signal: ctx.signal
257
+ });
258
+ const body = await readBody(res);
259
+ if (res.ok)
260
+ return { status: "verified", models: modelIds(body) };
261
+ if (res.status === 404 || res.status === 405) {
262
+ return {
263
+ status: "configured",
264
+ reason: `HTTP ${res.status}: the endpoint does not list models, so the key was not checked`
265
+ };
266
+ }
267
+ return {
268
+ status: "failed",
269
+ reason: `HTTP ${res.status}: ${body.slice(0, 200)}`,
270
+ httpStatus: res.status
271
+ };
272
+ }
273
+ var OPENAI_API_BASE_URL = "https://api.openai.com", openAiGatewayProvider;
274
+ var init_openai_gateway = __esm(() => {
275
+ init_protocols();
276
+ init_anthropic_models();
277
+ init_secret_env();
278
+ openAiGatewayProvider = defineRouteProvider({
279
+ id: "openai-gateway",
280
+ name: "OpenAI-compatible gateway",
281
+ protocols: ["openai-responses"],
282
+ harnesses: ["codex"],
283
+ requiredEnv: (route) => secretEnv(route),
284
+ validate: checkOpenAiModels
285
+ });
286
+ });
287
+
288
+ // packages/model-routing/src/providers/vertex.ts
289
+ var vertexProvider;
290
+ var init_vertex = __esm(() => {
291
+ init_protocols();
292
+ vertexProvider = defineRouteProvider({
293
+ id: "vertex",
294
+ name: "Google Vertex AI",
295
+ protocols: ["vertex"],
296
+ requiredEnv: () => ["CLOUD_ML_REGION", "ANTHROPIC_VERTEX_PROJECT_ID"]
297
+ });
298
+ });
299
+
300
+ // packages/model-routing/src/providers/index.ts
301
+ function getRouteProvider(id) {
302
+ return ROUTE_PROVIDERS.find((p) => p.id === id);
303
+ }
304
+ var ROUTE_PROVIDERS;
305
+ var init_providers = __esm(() => {
306
+ init_anthropic();
307
+ init_anthropic_gateway();
308
+ init_bedrock();
309
+ init_claude_subscription();
310
+ init_foundry();
311
+ init_openai_gateway();
312
+ init_vertex();
313
+ ROUTE_PROVIDERS = [
314
+ anthropicProvider,
315
+ claudeSubscriptionProvider,
316
+ anthropicGatewayProvider,
317
+ foundryProvider,
318
+ bedrockProvider,
319
+ vertexProvider,
320
+ openAiGatewayProvider
321
+ ];
322
+ });
323
+
324
+ // packages/model-routing/src/scoped-fetch.ts
325
+ function isAbsolute(path) {
326
+ return /^[a-z][a-z0-9+.-]*:/i.test(path) || path.startsWith("//");
327
+ }
328
+ function createScopedFetch(baseUrl, impl) {
329
+ let base;
330
+ try {
331
+ base = new URL(baseUrl);
332
+ } catch {
333
+ throw new ScopedFetchError(`Invalid route base URL: ${baseUrl}`);
334
+ }
335
+ const prefix = base.href.replace(/\/+$/, "");
336
+ return (path, init) => {
337
+ let target;
338
+ try {
339
+ target = isAbsolute(path) ? new URL(path, base) : new URL(`${prefix}/${path.replace(/^\/+/, "")}`);
340
+ } catch {
341
+ return Promise.reject(new ScopedFetchError(`Invalid route path: ${path}`));
342
+ }
343
+ if (target.origin !== base.origin) {
344
+ return Promise.reject(new ScopedFetchError(`Refusing request to ${target.origin}: route is scoped to ${base.origin}`));
345
+ }
346
+ const doFetch = impl ?? globalThis.fetch;
347
+ return doFetch(target.href, { ...init, redirect: "manual" });
348
+ };
349
+ }
350
+ var ScopedFetchError;
351
+ var init_scoped_fetch = __esm(() => {
352
+ ScopedFetchError = class ScopedFetchError extends Error {
353
+ name = "ScopedFetchError";
354
+ };
355
+ });
356
+
357
+ // packages/model-routing/src/credential-status.ts
358
+ function describeRoute(route, providerName) {
359
+ return route.baseUrl ? `${providerName} at ${route.baseUrl}` : providerName;
360
+ }
361
+ function routeCredentialStatus(route, env) {
362
+ const provider = getRouteProvider(route.provider);
363
+ if (!provider) {
364
+ return { ready: false, missing: [], hint: `Unknown route provider "${route.provider}".` };
365
+ }
366
+ const missing = provider.requiredEnv(route).filter((key) => !envValue(env, key));
367
+ const where = describeRoute(route, provider.name);
368
+ return missing.length === 0 ? { ready: true, missing: [], hint: `Routing through ${where}.` } : { ready: false, missing, hint: `${where} needs ${missing.join(", ")}.` };
369
+ }
370
+ async function validateRoute(route, env, opts = {}) {
371
+ const provider = getRouteProvider(route.provider);
372
+ const status = routeCredentialStatus(route, env);
373
+ if (!provider || !status.ready) {
374
+ return { status: "failed", reason: status.hint, missing: status.missing };
375
+ }
376
+ if (!provider.validate) {
377
+ return {
378
+ status: "configured",
379
+ reason: `${provider.name} has no free credential check; the first task proves the route.`
380
+ };
381
+ }
382
+ const baseUrl = route.baseUrl ?? provider.defaultBaseUrl;
383
+ const controller = new AbortController;
384
+ const timer = setTimeout(() => controller.abort(), opts.timeoutMs ?? VALIDATE_TIMEOUT_MS);
385
+ try {
386
+ const scopedFetch = baseUrl ? createScopedFetch(baseUrl) : () => Promise.reject(new ScopedFetchError(`Route "${route.name}" has no base URL.`));
387
+ return await provider.validate({ route, env, fetch: scopedFetch, signal: controller.signal });
388
+ } catch (err) {
389
+ return { status: "failed", reason: err instanceof Error ? err.message : String(err) };
390
+ } finally {
391
+ clearTimeout(timer);
392
+ }
393
+ }
394
+ var VALIDATE_TIMEOUT_MS = 5000;
395
+ var init_credential_status = __esm(() => {
396
+ init_env();
397
+ init_protocols();
398
+ init_providers();
399
+ init_scoped_fetch();
400
+ });
401
+
402
+ // packages/model-routing/src/default-route.ts
403
+ function isFirstPartyAnthropicUrl(url) {
404
+ try {
405
+ return new URL(url).origin === ANTHROPIC_API_BASE_URL;
406
+ } catch {
407
+ return false;
408
+ }
409
+ }
410
+ function isFirstPartyOpenAiUrl(url) {
411
+ try {
412
+ return new URL(url).origin === OPENAI_API_BASE_URL;
413
+ } catch {
414
+ return false;
415
+ }
416
+ }
417
+ function defaultRoute(harness, route) {
418
+ return { id: `default:${harness}`, name: `default:${harness}`, source: "default", ...route };
419
+ }
420
+ function deriveClaudeDefaultRoute(env) {
421
+ if (isEnvTruthy(env, "CLAUDE_CODE_USE_FOUNDRY")) {
422
+ const resource = envValue(env, "ANTHROPIC_FOUNDRY_RESOURCE");
423
+ const auth = envValue(env, "ANTHROPIC_FOUNDRY_AUTH_TOKEN") ? { kind: "bearer", secretKey: "ANTHROPIC_FOUNDRY_AUTH_TOKEN" } : envValue(env, "ANTHROPIC_FOUNDRY_API_KEY") ? { kind: "x-api-key", secretKey: "ANTHROPIC_FOUNDRY_API_KEY" } : { kind: "cloud-chain" };
424
+ return defaultRoute("claude", {
425
+ provider: "foundry",
426
+ protocol: "foundry",
427
+ baseUrl: envValue(env, "ANTHROPIC_FOUNDRY_BASE_URL") ?? (resource ? foundryBaseUrl(resource) : undefined),
428
+ auth,
429
+ cloud: { resource }
430
+ });
431
+ }
432
+ if (isEnvTruthy(env, "CLAUDE_CODE_USE_BEDROCK")) {
433
+ const region = envValue(env, "AWS_REGION");
434
+ return defaultRoute("claude", {
435
+ provider: "bedrock",
436
+ protocol: "bedrock",
437
+ baseUrl: envValue(env, "ANTHROPIC_BEDROCK_BASE_URL") ?? (region ? `https://bedrock-runtime.${region}.amazonaws.com` : undefined),
438
+ auth: envValue(env, "AWS_BEARER_TOKEN_BEDROCK") ? { kind: "bearer", secretKey: "AWS_BEARER_TOKEN_BEDROCK" } : { kind: "cloud-chain" },
439
+ cloud: { region }
440
+ });
441
+ }
442
+ if (isEnvTruthy(env, "CLAUDE_CODE_USE_VERTEX")) {
443
+ const region = envValue(env, "CLOUD_ML_REGION");
444
+ const vertexHost = region === "global" ? "aiplatform.googleapis.com" : `${region}-aiplatform.googleapis.com`;
445
+ return defaultRoute("claude", {
446
+ provider: "vertex",
447
+ protocol: "vertex",
448
+ baseUrl: envValue(env, "ANTHROPIC_VERTEX_BASE_URL") ?? (region ? `https://${vertexHost}` : undefined),
449
+ auth: { kind: "cloud-chain" },
450
+ cloud: { region, project: envValue(env, "ANTHROPIC_VERTEX_PROJECT_ID") }
451
+ });
452
+ }
453
+ const oauthToken = envValue(env, "CLAUDE_CODE_OAUTH_TOKEN");
454
+ const baseUrl = envValue(env, "ANTHROPIC_BASE_URL");
455
+ if (baseUrl && !isFirstPartyAnthropicUrl(baseUrl)) {
456
+ const authToken = envValue(env, "ANTHROPIC_AUTH_TOKEN");
457
+ const apiKey = envValue(env, "ANTHROPIC_API_KEY");
458
+ return defaultRoute("claude", {
459
+ provider: "anthropic-gateway",
460
+ protocol: "anthropic-messages",
461
+ baseUrl,
462
+ auth: authToken || !apiKey ? { kind: "bearer", secretKey: "ANTHROPIC_AUTH_TOKEN" } : { kind: "x-api-key", secretKey: "ANTHROPIC_API_KEY" }
463
+ });
464
+ }
465
+ if (oauthToken) {
466
+ return defaultRoute("claude", {
467
+ provider: "claude-subscription",
468
+ protocol: "anthropic-messages",
469
+ baseUrl: baseUrl ?? ANTHROPIC_API_BASE_URL,
470
+ auth: { kind: "subscription", plan: "claude" }
471
+ });
472
+ }
473
+ if (envValue(env, "ANTHROPIC_API_KEY")) {
474
+ return defaultRoute("claude", {
475
+ provider: "anthropic",
476
+ protocol: "anthropic-messages",
477
+ baseUrl: baseUrl ?? ANTHROPIC_API_BASE_URL,
478
+ auth: { kind: "x-api-key", secretKey: "ANTHROPIC_API_KEY" }
479
+ });
480
+ }
481
+ return null;
482
+ }
483
+ function deriveCodexDefaultRoute(env) {
484
+ const baseUrl = envValue(env, CODEX_GATEWAY_BASE_URL);
485
+ if (!baseUrl || isFirstPartyOpenAiUrl(baseUrl))
486
+ return null;
487
+ return defaultRoute("codex", {
488
+ provider: "openai-gateway",
489
+ protocol: "openai-responses",
490
+ baseUrl,
491
+ auth: { kind: "bearer", secretKey: CODEX_GATEWAY_API_KEY }
492
+ });
493
+ }
494
+ function deriveDefaultRoute(harness, env) {
495
+ if (harness === "claude")
496
+ return deriveClaudeDefaultRoute(env);
497
+ if (harness === "codex")
498
+ return deriveCodexDefaultRoute(env);
499
+ return null;
500
+ }
501
+ function routeUnsetEnv(harness, route) {
502
+ if (harness === "claude" && route.provider !== "claude-subscription") {
503
+ return ["CLAUDE_CODE_OAUTH_TOKEN"];
504
+ }
505
+ if (harness === "codex" && route.provider === "openai-gateway") {
506
+ return ["CODEX_OAUTH", "OPENAI_API_KEY"];
507
+ }
508
+ return [];
509
+ }
510
+ var CODEX_GATEWAY_BASE_URL = "CODEX_GATEWAY_BASE_URL", CODEX_GATEWAY_API_KEY = "CODEX_GATEWAY_API_KEY";
511
+ var init_default_route = __esm(() => {
512
+ init_env();
513
+ init_anthropic();
514
+ init_foundry();
515
+ init_openai_gateway();
516
+ });
517
+
518
+ // packages/model-routing/src/index.ts
519
+ var init_src = __esm(() => {
520
+ init_credential_status();
521
+ init_default_route();
522
+ init_protocols();
523
+ init_anthropic();
524
+ init_providers();
525
+ init_openai_gateway();
526
+ init_scoped_fetch();
527
+ });
528
+
529
+ // src/utils/model-rate-limit-windows.ts
530
+ function modelFamilyOf(model) {
531
+ if (!model)
532
+ return;
533
+ const lower = model.toLowerCase();
534
+ const families = ["fable", "opus", "sonnet", "haiku"];
535
+ for (const family of families) {
536
+ if (lower.includes(family))
537
+ return family;
538
+ }
539
+ return;
540
+ }
541
+ function windowForModelFamily(family) {
542
+ switch (family) {
543
+ case "fable":
544
+ return FABLE_WINDOW;
545
+ case "opus":
546
+ return OPUS_WINDOW;
547
+ case "sonnet":
548
+ return SONNET_WINDOW;
549
+ default:
550
+ return;
551
+ }
552
+ }
553
+ function isModelScopedWindow(type) {
554
+ return Object.hasOwn(MODEL_SCOPED_WINDOWS, type) && MODEL_SCOPED_WINDOWS[type] !== undefined;
555
+ }
556
+ function parseModelLimitMessage(text) {
557
+ const match = text.match(/reached your (Fable|Opus|Sonnet) limit/i);
558
+ if (!match)
559
+ return;
560
+ return match[1].toLowerCase();
561
+ }
562
+ function parseCreditsRequiredMessage(text) {
563
+ const match = text.match(/(Fable|Opus|Sonnet)(?:[^.]|\.(?=\d)){0,40}requires usage credits/i);
564
+ if (!match)
565
+ return;
566
+ return match[1].toLowerCase();
567
+ }
568
+ function activeModelBlock(windows, family, nowMs) {
569
+ if (!windows)
570
+ return;
571
+ const window = windowForModelFamily(family);
572
+ if (!window)
573
+ return;
574
+ const entry = windows[window];
575
+ if (!entry)
576
+ return;
577
+ if (entry.status !== "rejected")
578
+ return;
579
+ if (typeof entry.resetsAt !== "number" || entry.resetsAt * 1000 <= nowMs)
580
+ return;
581
+ return { window, resetsAt: entry.resetsAt };
582
+ }
583
+ function activeModelBlocks(windows, nowMs) {
584
+ if (!windows)
585
+ return [];
586
+ const blocks = [];
587
+ for (const [window, model] of Object.entries(MODEL_SCOPED_WINDOWS)) {
588
+ const entry = windows[window];
589
+ if (!entry)
590
+ continue;
591
+ if (entry.status !== "rejected")
592
+ continue;
593
+ if (typeof entry.resetsAt !== "number" || entry.resetsAt * 1000 <= nowMs)
594
+ continue;
595
+ blocks.push({ model, window, resetsAt: entry.resetsAt });
596
+ }
597
+ return blocks;
598
+ }
599
+ var FABLE_WINDOW = "seven_day_overage_included", OPUS_WINDOW = "seven_day_opus", SONNET_WINDOW = "seven_day_sonnet", MODEL_SCOPED_WINDOWS;
600
+ var init_model_rate_limit_windows = __esm(() => {
601
+ MODEL_SCOPED_WINDOWS = {
602
+ [FABLE_WINDOW]: "fable",
603
+ [OPUS_WINDOW]: "opus",
604
+ [SONNET_WINDOW]: "sonnet"
605
+ };
606
+ });
607
+
608
+ // src/utils/credentials.ts
609
+ import { existsSync } from "node:fs";
610
+ function normalizeProviderKeyAliases(env) {
611
+ for (const provider of openAICompatibleProviders()) {
612
+ if (env[provider.envVar]?.trim())
613
+ continue;
614
+ const alias = provider.aliasEnvVars.find((name) => env[name]?.trim());
615
+ if (alias)
616
+ env[provider.envVar] = env[alias];
617
+ }
618
+ }
619
+ function getModelAwareCredentialVars(provider, model) {
620
+ const base = PROVIDER_CREDENTIAL_VARS[provider];
621
+ if (!base)
622
+ return CREDENTIAL_POOL_VARS;
623
+ if (provider === "dsh" && model) {
624
+ return model.startsWith("openrouter/") ? ["OPENROUTER_API_KEY"] : ["DEEPSEEK_API_KEY"];
625
+ }
626
+ if (provider === "grok" && model) {
627
+ return model.startsWith("openrouter/") ? ["OPENROUTER_API_KEY"] : ["XAI_API_KEY"];
628
+ }
629
+ if (!SLASH_MODEL_PROVIDERS.has(provider) || !model)
630
+ return base;
631
+ const direct = providerForModel(model);
632
+ if (direct)
633
+ return [direct.envVar];
634
+ if (model.includes("/")) {
635
+ return base.filter((v) => v !== "OPENAI_API_KEY");
636
+ }
637
+ return base;
638
+ }
639
+ function deriveProviderFromKeyType(keyType) {
640
+ if (providerForKeyVar(keyType))
641
+ return "pi";
642
+ switch (keyType) {
643
+ case "CLAUDE_CODE_OAUTH_TOKEN":
644
+ case "ANTHROPIC_API_KEY":
645
+ return "claude";
646
+ case "OPENROUTER_API_KEY":
647
+ return "pi";
648
+ case "OPENAI_API_KEY":
649
+ case "CODEX_OAUTH":
650
+ return "codex";
651
+ case "DEEPSEEK_API_KEY":
652
+ return "dsh";
653
+ case "AMP_API_KEY":
654
+ return "amp";
655
+ case "CURSOR_API_KEY":
656
+ return "cursor";
657
+ case "XAI_API_KEY":
658
+ return "grok";
659
+ case "DEVIN_API_KEY":
660
+ return "devin";
661
+ default:
662
+ return "claude";
663
+ }
664
+ }
665
+ function isJsonObject(value) {
666
+ const trimmed = value.trim();
667
+ if (!trimmed.startsWith("{") || !trimmed.endsWith("}"))
668
+ return false;
669
+ try {
670
+ const parsed = JSON.parse(trimmed);
671
+ return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed);
672
+ } catch {
673
+ return false;
674
+ }
675
+ }
676
+ function splitCredentialPool(value) {
677
+ return isJsonObject(value) ? [value.trim()] : value.split(",").map((s) => s.trim()).filter(Boolean);
678
+ }
679
+ function selectCredential(value, availableIndices, keyType = "ANTHROPIC_API_KEY") {
680
+ const credentials = splitCredentialPool(value);
681
+ if (credentials.length <= 1) {
682
+ const selected = value.trim();
683
+ const isRateLimitFallback = availableIndices !== undefined && availableIndices.length === 0;
684
+ return {
685
+ selected,
686
+ index: 0,
687
+ total: 1,
688
+ keySuffix: selected.slice(-5),
689
+ keyType,
690
+ isRateLimitFallback
691
+ };
692
+ }
693
+ let index;
694
+ let isRateLimitFallback = false;
695
+ if (availableIndices && availableIndices.length > 0) {
696
+ const validIndices = availableIndices.filter((i) => i >= 0 && i < credentials.length);
697
+ if (validIndices.length > 0) {
698
+ index = validIndices[Math.floor(Math.random() * validIndices.length)];
699
+ } else {
700
+ index = Math.floor(Math.random() * credentials.length);
701
+ isRateLimitFallback = true;
702
+ }
703
+ } else if (availableIndices && availableIndices.length === 0) {
704
+ index = Math.floor(Math.random() * credentials.length);
705
+ isRateLimitFallback = true;
706
+ } else {
707
+ index = Math.floor(Math.random() * credentials.length);
708
+ }
709
+ const selected = credentials[index];
710
+ return {
711
+ selected,
712
+ index,
713
+ total: credentials.length,
714
+ keySuffix: selected.slice(-5),
715
+ keyType,
716
+ isRateLimitFallback
717
+ };
718
+ }
719
+ function validateClaudeCredentials(env) {
720
+ const route = deriveDefaultRoute("claude", env);
721
+ if (!route)
722
+ throw new Error(`No Claude credentials found. ${CLAUDE_CREDENTIALS_HINT}`);
723
+ const status = routeCredentialStatus(route, env);
724
+ if (!status.ready)
725
+ throw new Error(`No Claude credentials found. ${status.hint}`);
726
+ return CLAUDE_CREDENTIAL_TYPE_BY_PROVIDER[route.provider] ?? route.provider;
727
+ }
728
+ function openAICompatibleKeyLabels() {
729
+ return openAICompatibleProviders().map((p) => p.aliasEnvVars.length > 0 ? `${p.envVar} (or ${p.aliasEnvVars.join(" or ")})` : p.envVar);
730
+ }
731
+ function validateOpencodeCredentials(env) {
732
+ if (env.OPENROUTER_API_KEY)
733
+ return "openrouter_api_key";
734
+ if (env.ANTHROPIC_API_KEY)
735
+ return "anthropic_api_key";
736
+ if (env.OPENAI_API_KEY)
737
+ return "openai_api_key";
738
+ const direct = openAICompatibleProviders().find((p) => providerKeyVars(p).some((n) => env[n]));
739
+ if (direct)
740
+ return direct.envVar.toLowerCase();
741
+ const authFile = `${process.env.HOME ?? "/root"}/.local/share/opencode/auth.json`;
742
+ if (existsSync(authFile))
743
+ return "auth_file";
744
+ throw new Error(`No opencode credentials found. Set OPENROUTER_API_KEY, ANTHROPIC_API_KEY, OPENAI_API_KEY, ${openAICompatibleKeyLabels().map((label) => `${label}, `).join("")}or provide ~/.local/share/opencode/auth.json.`);
745
+ }
746
+ async function fetchAvailableIndices(env, apiUrl, apiKey, poolVars = CREDENTIAL_POOL_VARS, modelFamily) {
747
+ const availableIndicesMap = {};
748
+ const window = modelFamily ? windowForModelFamily(modelFamily) : undefined;
749
+ const modelParam = window ? `&model=${encodeURIComponent(modelFamily)}` : "";
750
+ for (const envVar of poolVars) {
751
+ const val = env[envVar];
752
+ if (val) {
753
+ const keySuffixes = splitCredentialPool(val).map((key) => key.slice(-5));
754
+ const totalKeys = keySuffixes.length;
755
+ try {
756
+ const resp = await fetch(`${apiUrl}/api/keys/available?keyType=${encodeURIComponent(envVar)}&totalKeys=${totalKeys}${modelParam}&keySuffixes=${encodeURIComponent(keySuffixes.join(","))}`, { headers: { Authorization: `Bearer ${apiKey}` } });
757
+ if (resp.ok) {
758
+ const data = await resp.json();
759
+ availableIndicesMap[envVar] = {
760
+ availableIndices: data.availableIndices,
761
+ rejectedIndices: data.rejectedIndices,
762
+ modelBlockedIndices: data.modelBlockedIndices,
763
+ earliestModelResetAt: data.earliestModelResetAt,
764
+ seatBlockedIndices: data.seatBlockedIndices
765
+ };
766
+ if (data.availableIndices.length < totalKeys) {
767
+ console.log(`[credentials] ${envVar}: ${data.availableIndices.length}/${totalKeys} keys available (${totalKeys - data.availableIndices.length} unavailable)`);
768
+ }
769
+ }
770
+ } catch {}
771
+ }
772
+ }
773
+ return availableIndicesMap;
774
+ }
775
+ async function resolveCredentialPools(env, opts) {
776
+ const providerVars = opts?.provider ? getModelAwareCredentialVars(opts.provider, opts.model) : CREDENTIAL_POOL_VARS;
777
+ const modelFamily = modelFamilyOf(opts?.model);
778
+ const window = modelFamily ? windowForModelFamily(modelFamily) : undefined;
779
+ const availableIndicesMap = opts?.availableIndicesMap ?? (opts?.apiUrl && opts?.apiKey ? await fetchAvailableIndices(env, opts.apiUrl, opts.apiKey, providerVars, modelFamily) : undefined);
780
+ const nowMs = Date.now();
781
+ const selections = [];
782
+ for (const envVar of providerVars) {
783
+ const val = env[envVar];
784
+ if (val) {
785
+ const info = availableIndicesMap?.[envVar];
786
+ let available = info?.availableIndices;
787
+ let modelBlockedCount = info?.modelBlockedIndices?.length ?? 0;
788
+ if (available && window && opts?.localBlocks) {
789
+ const beforeCount = available.length;
790
+ available = available.filter((i) => {
791
+ const blockedUntilMs = opts.localBlocks?.get(`${envVar}:${i}:${window}`);
792
+ return blockedUntilMs === undefined || blockedUntilMs <= nowMs;
793
+ });
794
+ modelBlockedCount += beforeCount - available.length;
795
+ }
796
+ const seatBlockedIndices = info?.seatBlockedIndices ?? [];
797
+ const seatBlockedCount = seatBlockedIndices.length;
798
+ let seatFallbackIndices;
799
+ if (opts?.enforceModelCapacity && modelFamily && available && available.length === 0) {
800
+ const policy = (env.MODEL_WINDOW_EXHAUSTED_POLICY ?? "fail").trim().toLowerCase();
801
+ const windowExhausted = window !== undefined && modelBlockedCount > 0 && policy !== "fallback";
802
+ if (seatBlockedCount > 0) {
803
+ seatFallbackIndices = splitCredentialPool(val).map((_, i) => i).filter((i) => !seatBlockedIndices.includes(i));
804
+ }
805
+ if (windowExhausted || seatFallbackIndices?.length === 0) {
806
+ throw new ModelWindowExhaustedError({
807
+ model: modelFamily,
808
+ window: window ?? "",
809
+ earliestResetAt: info?.earliestModelResetAt ?? null,
810
+ keyType: envVar,
811
+ seatBlockedCount,
812
+ modelBlockedCount
813
+ });
814
+ }
815
+ }
816
+ const result = seatFallbackIndices ? { ...selectCredential(val, seatFallbackIndices, envVar), isRateLimitFallback: true } : selectCredential(val, available, envVar);
817
+ env[envVar] = result.selected;
818
+ const availInfo = available ? ` (${available.length} available of ${result.total})` : "";
819
+ console.log(`[credentials] Selected ${envVar} credential ${result.index + 1}/${result.total}${availInfo} [...${result.keySuffix}]${info?.rejectedIndices?.length ? ` (${info.rejectedIndices.length} rejected)` : ""}`);
820
+ selections.push({
821
+ ...result,
822
+ modelBlockedIndices: info?.modelBlockedIndices,
823
+ earliestModelResetAt: info?.earliestModelResetAt,
824
+ seatBlockedIndices: info?.seatBlockedIndices
825
+ });
826
+ }
827
+ }
828
+ return selections;
829
+ }
830
+ var CREDENTIAL_POOL_VARS, PROVIDER_CREDENTIAL_VARS, SLASH_MODEL_PROVIDERS, MODEL_LABELS, ModelWindowExhaustedError, CLAUDE_CREDENTIALS_HINT = "Set CLAUDE_CODE_OAUTH_TOKEN or ANTHROPIC_API_KEY, or route Claude Code through a gateway (ANTHROPIC_BASE_URL + ANTHROPIC_AUTH_TOKEN or ANTHROPIC_API_KEY), Microsoft Foundry (CLAUDE_CODE_USE_FOUNDRY), Amazon Bedrock (CLAUDE_CODE_USE_BEDROCK), or Google Vertex AI (CLAUDE_CODE_USE_VERTEX).", CLAUDE_CREDENTIAL_TYPE_BY_PROVIDER;
831
+ var init_credentials = __esm(() => {
832
+ init_src2();
833
+ init_src();
834
+ init_model_rate_limit_windows();
835
+ CREDENTIAL_POOL_VARS = [
836
+ "CLAUDE_CODE_OAUTH_TOKEN",
837
+ "ANTHROPIC_API_KEY",
838
+ "OPENROUTER_API_KEY",
839
+ "OPENAI_API_KEY",
840
+ "CODEX_OAUTH",
841
+ "DEVIN_API_KEY",
842
+ "DEEPSEEK_API_KEY",
843
+ "AMP_API_KEY",
844
+ "CURSOR_API_KEY",
845
+ "XAI_API_KEY",
846
+ ...openAICompatibleProviders().map((p) => p.envVar)
847
+ ];
848
+ PROVIDER_CREDENTIAL_VARS = {
849
+ claude: ["CLAUDE_CODE_OAUTH_TOKEN", "ANTHROPIC_API_KEY"],
850
+ pi: ["OPENROUTER_API_KEY", "ANTHROPIC_API_KEY", "OPENAI_API_KEY"],
851
+ codex: ["OPENAI_API_KEY", "CODEX_OAUTH"],
852
+ devin: ["DEVIN_API_KEY"],
853
+ dsh: ["OPENROUTER_API_KEY", "DEEPSEEK_API_KEY"],
854
+ amp: ["AMP_API_KEY"],
855
+ cursor: ["CURSOR_API_KEY"],
856
+ grok: ["XAI_API_KEY", "OPENROUTER_API_KEY"],
857
+ opencode: ["OPENROUTER_API_KEY", "ANTHROPIC_API_KEY", "OPENAI_API_KEY"]
858
+ };
859
+ SLASH_MODEL_PROVIDERS = new Set(["opencode", "pi"]);
860
+ MODEL_LABELS = {
861
+ fable: "Fable",
862
+ opus: "Opus",
863
+ sonnet: "Sonnet",
864
+ haiku: "Haiku"
865
+ };
866
+ ModelWindowExhaustedError = class ModelWindowExhaustedError extends Error {
867
+ model;
868
+ window;
869
+ earliestResetAt;
870
+ keyType;
871
+ seatBlockedCount;
872
+ modelBlockedCount;
873
+ constructor(opts) {
874
+ const modelLabel = MODEL_LABELS[opts.model];
875
+ const seatBlockedCount = opts.seatBlockedCount ?? 0;
876
+ const modelBlockedCount = opts.modelBlockedCount ?? 0;
877
+ const windowClause = modelBlockedCount > 0 && opts.earliestResetAt ? `${modelBlockedCount} keys have the ${modelLabel} window exhausted until ${opts.earliestResetAt}` : `${modelBlockedCount} keys have the ${modelLabel} window exhausted`;
878
+ super(seatBlockedCount > 0 ? `No ${opts.keyType} key can run ${modelLabel}: ${seatBlockedCount} keys are on a seat without ${modelLabel}, ${windowClause}. Re-dispatch with another model or modelTier.` : `No ${opts.keyType} key has ${modelLabel} capacity until ${opts.earliestResetAt ?? "unknown"}. Re-dispatch with another model or modelTier.`);
879
+ this.name = "ModelWindowExhaustedError";
880
+ this.model = opts.model;
881
+ this.window = opts.window;
882
+ this.earliestResetAt = opts.earliestResetAt;
883
+ this.keyType = opts.keyType;
884
+ this.seatBlockedCount = seatBlockedCount;
885
+ this.modelBlockedCount = modelBlockedCount;
886
+ }
887
+ };
888
+ CLAUDE_CREDENTIAL_TYPE_BY_PROVIDER = {
889
+ "claude-subscription": "oauth",
890
+ anthropic: "api_key",
891
+ "anthropic-gateway": "gateway"
892
+ };
893
+ });
894
+
895
+ export { getRouteProvider, createScopedFetch, routeCredentialStatus, validateRoute, isFirstPartyAnthropicUrl, CODEX_GATEWAY_API_KEY, deriveDefaultRoute, routeUnsetEnv, init_src, MODEL_SCOPED_WINDOWS, modelFamilyOf, windowForModelFamily, isModelScopedWindow, parseModelLimitMessage, parseCreditsRequiredMessage, activeModelBlock, activeModelBlocks, init_model_rate_limit_windows, CREDENTIAL_POOL_VARS, normalizeProviderKeyAliases, deriveProviderFromKeyType, ModelWindowExhaustedError, splitCredentialPool, selectCredential, CLAUDE_CREDENTIALS_HINT, validateClaudeCredentials, openAICompatibleKeyLabels, validateOpencodeCredentials, resolveCredentialPools, init_credentials };