@desplega.ai/agent-swarm 1.149.1 → 1.151.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 (538) hide show
  1. package/README.md +18 -3
  2. package/dist/{acp-adapter-vhkzfpjg.js → acp-adapter-ex8hzjfc.js} +5 -5
  3. package/dist/{actions-9d2694yk.js → actions-2bgpyhww.js} +39 -11
  4. package/dist/{app-fq2ggynt.js → app-1706zhr1.js} +7 -7
  5. package/dist/{artifact-gj9arwrr.js → artifact-td4q4dch.js} +1 -1
  6. package/dist/{assistant-edb6n9nn.js → assistant-bavke5p7.js} +44 -20
  7. package/dist/{azure-openai-responses-cqar64rc.js → azure-openai-responses-f38x2avq.js} +13 -13
  8. package/dist/{boot-reembed-msweabbp.js → boot-reembed-3cmrrmpa.js} +9 -9
  9. package/dist/{boot-reembed-q5wd3tha.js → boot-reembed-nafcmmmc.js} +14 -16
  10. package/dist/{boot-scrub-logs-3g1az933.js → boot-scrub-logs-cd6a2sq0.js} +5 -5
  11. package/dist/{claude-adapter-v3rnzsdc.js → claude-adapter-wfp2gzvz.js} +15 -16
  12. package/dist/{claude-managed-adapter-qvsmh6mv.js → claude-managed-adapter-dsmkcrjy.js} +3 -3
  13. package/dist/{claude-sdk-session-qxrpsna1.js → claude-sdk-session-bht9jjak.js} +15 -16
  14. package/dist/{cli-5m0qmvdp.js → cli-0qb1z6s2.js} +1 -1
  15. package/dist/{cli-9d8ntetj.js → cli-2658f6at.js} +1 -1
  16. package/dist/{cli-7evafqvy.js → cli-2tbvf1z1.js} +85 -69
  17. package/dist/{cli-k351hv5k.js → cli-3v9xhjcn.js} +24 -12
  18. package/dist/{cli-1ebpar1q.js → cli-4wppfkcm.js} +350 -20
  19. package/dist/{cli-4260r1tg.js → cli-5jd2z7av.js} +97 -84
  20. package/dist/{cli-cv7s5zdq.js → cli-5tpgq60f.js} +9865 -715
  21. package/dist/{cli-6skz3rk8.js → cli-7tgcstn2.js} +9 -4
  22. package/dist/{cli-01g3x1ca.js → cli-9004vfdf.js} +108 -56
  23. package/dist/{cli-1c94wvcw.js → cli-a1z3h107.js} +124 -99
  24. package/dist/{cli-9br8ypfv.js → cli-czjtgfys.js} +2 -2
  25. package/dist/{cli-5my3bjsd.js → cli-d3p82erb.js} +7 -7
  26. package/dist/{cli-e29gmdmw.js → cli-dv6cdjs2.js} +2 -1
  27. package/dist/{cli-wby1xnnb.js → cli-f1wky6zp.js} +1 -1
  28. package/dist/{cli-zvz62chv.js → cli-fm4ytsdk.js} +4 -4
  29. package/dist/{cli-tg8qj8ee.js → cli-frcta2w4.js} +6 -6
  30. package/dist/{cli-7xx10h0a.js → cli-g69fdc9g.js} +2 -2
  31. package/dist/{cli-cmp8g3sw.js → cli-gbfwcd3k.js} +44 -9
  32. package/dist/{handlers-nsg0bcye.js → cli-gjyvhmmh.js} +97 -45
  33. package/dist/{cli-08b07b4r.js → cli-ht5rs63n.js} +1 -1
  34. package/dist/{cli-jecc01cb.js → cli-j4nv2wqy.js} +2 -4
  35. package/dist/{cli-cd60fv6j.js → cli-j9xczhaq.js} +1 -1
  36. package/dist/cli-pf9q3696.js +172 -0
  37. package/dist/{cli-xm87hzbw.js → cli-pgj4a5fb.js} +1 -1
  38. package/dist/{cli-jezx9b9c.js → cli-ppm4975n.js} +9 -3
  39. package/dist/{cli-3z634pqe.js → cli-q88st9aj.js} +2 -2
  40. package/dist/{cli-3sysyjve.js → cli-r2q6pevn.js} +142 -49
  41. package/dist/{cli-07jd68a1.js → cli-re8z5p8p.js} +1 -1
  42. package/dist/{cli-qgd4sqz5.js → cli-s14agm5s.js} +121 -14
  43. package/dist/{cli-svbrpf5q.js → cli-sjaae6ff.js} +9872 -424
  44. package/dist/{cli-73gq0zxn.js → cli-vwm416m6.js} +13 -13
  45. package/dist/{cli-4wtq5jjv.js → cli-wbyk465z.js} +1 -1
  46. package/dist/{cli-3apbzgyk.js → cli-z61ykvam.js} +19 -14
  47. package/dist/{cli-e06a8a7y.js → cli-zkxymas5.js} +4 -3
  48. package/dist/cli.js +26 -25
  49. package/dist/{codex-adapter-jyw7a91z.js → codex-adapter-jjjk8w4m.js} +8 -9
  50. package/dist/{codex-hook-hfrt9shr.js → codex-hook-8jexc34x.js} +3 -3
  51. package/dist/{codex-session-runner-bmngj0s5.js → codex-session-runner-nd6ayxkx.js} +8 -9
  52. package/dist/{commands-n755g391.js → commands-9v4psyq1.js} +5 -5
  53. package/dist/{db-s1cgh5gv.js → db-wnt58tpe.js} +5 -5
  54. package/dist/dispatcher-05jh1aqk.js +74 -0
  55. package/dist/{e2b-p04vmtx0.js → e2b-413b8t4v.js} +1 -1
  56. package/dist/{google-generative-ai-tsskx7te.js → google-generative-ai-ndjmj5fa.js} +7 -7
  57. package/dist/{google-vertex-ppw8ydpa.js → google-vertex-fr665tqs.js} +10 -10
  58. package/dist/handlers-tw90pkh5.js +65 -0
  59. package/dist/{hook-jf0xe8zh.js → hook-123e2scb.js} +11 -12
  60. package/dist/{hook-h9cqrm8q.js → hook-sxe3r349.js} +11 -12
  61. package/dist/{http-nc6pydw5.js → http-ecsar8ez.js} +1442 -581
  62. package/dist/{index-ezxkds2n.js → index-16js521z.js} +335 -107
  63. package/dist/{index-769nc012.js → index-hw26vj40.js} +25 -19
  64. package/dist/{index-0wdy6gwc.js → index-nnrbpcjp.js} +25 -17
  65. package/dist/index-ymn7em0p.js +25 -0
  66. package/dist/{index-x1zcj09z.js → index-zj518gf9.js} +26 -20
  67. package/dist/{keepalive-nesm3xb6.js → keepalive-asqtcm4y.js} +7 -7
  68. package/dist/{lead-bwy6t2za.js → lead-xbfr7fvt.js} +40 -48
  69. package/dist/{maintenance-8w393zf0.js → maintenance-qma55qvw.js} +9 -9
  70. package/dist/{oauth-refresh-sweep-sh8xjy08.js → oauth-refresh-sweep-3s04c6qw.js} +6 -6
  71. package/dist/{onboard-25ps29h1.js → onboard-drskd386.js} +13 -4
  72. package/dist/{openai-codex-responses-g7w48y30.js → openai-codex-responses-wy6a43wd.js} +13 -13
  73. package/dist/{openai-responses-nmeyptke.js → openai-responses-6xwf7bzg.js} +19 -19
  74. package/dist/{opencode-adapter-dce4wskd.js → opencode-adapter-28axqa09.js} +4 -4
  75. package/dist/{otel-impl-b93gxnz5.js → otel-impl-943c96er.js} +1 -1
  76. package/dist/{pi-mono-adapter-zvshk5cj.js → pi-mono-adapter-jcqt71cg.js} +17 -19
  77. package/dist/{pricing-refresh-5v56x7gb.js → pricing-refresh-mx51az05.js} +7 -7
  78. package/dist/{rbac-roles-x55cnezn.js → rbac-roles-78baecqd.js} +13 -9
  79. package/dist/{rbac-roles-0p0s6pbj.js → rbac-roles-wcmrg6sv.js} +7 -7
  80. package/dist/{render-v2-hyd45w8b.js → render-v2-8zjntgf5.js} +7 -7
  81. package/dist/{seed-pricing-49gbgn96.js → seed-pricing-jqjs6cws.js} +6 -6
  82. package/dist/{setup-qvq64vzq.js → setup-4pks0vfk.js} +2 -2
  83. package/dist/work-objects-wangt792.js +165 -0
  84. package/dist/{worker-scj60cxg.js → worker-p2mr422x.js} +40 -48
  85. package/openapi.json +1365 -268
  86. package/package.json +4 -3
  87. package/src/agentmail/handlers.ts +95 -66
  88. package/src/be/budget-refusal-notify.ts +1 -0
  89. package/src/be/db/tasks/read.ts +3 -0
  90. package/src/be/db/tasks/write.ts +13 -1
  91. package/src/be/db-client.ts +5 -0
  92. package/src/be/db.ts +15 -5
  93. package/src/be/extensions/db.ts +461 -0
  94. package/src/be/extensions/validate.ts +107 -0
  95. package/src/be/memory/boot-reembed.ts +17 -12
  96. package/src/be/memory/index.ts +12 -0
  97. package/src/be/memory/providers/openai-embedding.ts +4 -0
  98. package/src/be/memory/types.ts +2 -0
  99. package/src/be/migrations/153_deferred_task_wait_members.sql +25 -0
  100. package/src/be/migrations/154_routing_source.sql +3 -0
  101. package/src/be/migrations/155_extensions.sql +66 -0
  102. package/src/be/migrations/156_inbox_item_state_read_at.sql +7 -0
  103. package/src/be/rbac-roles.ts +3 -2
  104. package/src/be/scripts/typecheck.ts +59 -41
  105. package/src/be/seed/schedules-seeder.ts +25 -2
  106. package/src/be/seed/workflows-seeder.ts +17 -0
  107. package/src/be/seed-scripts/catalog/delegate.ts +3 -1
  108. package/src/be/seed-skills/bundled-files.generated.json +1 -1
  109. package/src/be/seed-skills/index.ts +7 -0
  110. package/src/be/steering.ts +1 -0
  111. package/src/be/swarm-config-guard.ts +3 -1
  112. package/src/commands/credential-refresh.ts +70 -0
  113. package/src/commands/onboard/compose-generator.ts +14 -2
  114. package/src/commands/onboard/env-generator.ts +7 -0
  115. package/src/commands/provider-credentials.ts +2 -25
  116. package/src/commands/runner.ts +24 -57
  117. package/src/extensions/apply-task-create.ts +135 -0
  118. package/src/extensions/bundle-path.ts +10 -0
  119. package/src/extensions/contract-runtime.ts +7 -0
  120. package/src/extensions/contract-types.generated.ts +4 -0
  121. package/src/extensions/contract.ts +270 -0
  122. package/src/extensions/ctx.ts +186 -0
  123. package/src/extensions/dispatcher.ts +479 -0
  124. package/src/extensions/identity.ts +44 -0
  125. package/src/extensions/lifecycle.ts +281 -0
  126. package/src/extensions/loader.ts +207 -0
  127. package/src/extensions/post-bridge.ts +161 -0
  128. package/src/github/handlers.ts +185 -140
  129. package/src/gitlab/handlers.ts +97 -77
  130. package/src/heartbeat/heartbeat.ts +155 -83
  131. package/src/http/agents.ts +1 -1
  132. package/src/http/all-routes.ts +1 -0
  133. package/src/http/approval-requests.ts +1 -0
  134. package/src/http/apps.ts +14 -9
  135. package/src/http/config.ts +4 -1
  136. package/src/http/core.ts +38 -2
  137. package/src/http/extensions.ts +547 -0
  138. package/src/http/inbox-state.ts +2 -0
  139. package/src/http/index.ts +41 -3
  140. package/src/http/mcp-bridge.ts +96 -62
  141. package/src/http/mcp.ts +1 -1
  142. package/src/http/script-runs.ts +5 -0
  143. package/src/http/status.ts +6 -4
  144. package/src/http/tasks.ts +51 -30
  145. package/src/integrations/kapso/inbound.ts +15 -10
  146. package/src/jira/sync.ts +26 -16
  147. package/src/linear/sync.ts +26 -16
  148. package/src/prompts/session-templates.ts +18 -13
  149. package/src/providers/claude-adapter.ts +21 -8
  150. package/src/rbac/admission.ts +1 -1
  151. package/src/rbac/elevated-agents.ts +24 -0
  152. package/src/rbac/legacy-policy.ts +35 -6
  153. package/src/rbac/permissions.ts +8 -0
  154. package/src/scheduler/deferred-task-waits.ts +138 -27
  155. package/src/scheduler/schedule-task.ts +54 -24
  156. package/src/scheduler/scheduler.ts +108 -125
  157. package/src/scripts-runtime/executors/native.ts +5 -1
  158. package/src/scripts-runtime/executors/types.ts +5 -0
  159. package/src/scripts-runtime/import-allowlist.ts +79 -19
  160. package/src/scripts-runtime/sdk-allowlist.ts +4 -0
  161. package/src/scripts-runtime/swarm-config.ts +8 -0
  162. package/src/scripts-runtime/swarm-sdk.ts +3 -0
  163. package/src/scripts-runtime/types/stdlib.d.ts +16 -3
  164. package/src/scripts-runtime/types/swarm-extension.d.ts +562 -0
  165. package/src/scripts-runtime/types/swarm-sdk.d.ts +16 -3
  166. package/src/server.ts +6 -0
  167. package/src/slack/HEURISTICS.md +3 -1
  168. package/src/slack/actions.ts +21 -16
  169. package/src/slack/app.ts +2 -0
  170. package/src/slack/assistant.ts +4 -12
  171. package/src/slack/blocks.ts +1 -1
  172. package/src/slack/handlers.ts +107 -19
  173. package/src/slack/inbound-files.ts +9 -5
  174. package/src/slack/render-v2.ts +188 -38
  175. package/src/slack/router.ts +13 -3
  176. package/src/slack/steering.ts +3 -3
  177. package/src/slack/thread-buffer.ts +66 -23
  178. package/src/slack/work-objects.test.ts +252 -0
  179. package/src/slack/work-objects.ts +118 -0
  180. package/src/tasks/errors.ts +9 -0
  181. package/src/tasks/sibling-awareness.ts +35 -1
  182. package/src/tasks/worker-follow-up.ts +67 -11
  183. package/src/tests/acp-adapter.test.ts +10 -10
  184. package/src/tests/agent-fs-live-url.test.ts +40 -0
  185. package/src/tests/agent-fs-provision-seeder.test.ts +12 -12
  186. package/src/tests/api-key-tracking.test.ts +18 -18
  187. package/src/tests/api-key.test.ts +4 -2
  188. package/src/tests/apps-rbac.test.ts +1 -1
  189. package/src/tests/apps-spike5.test.ts +1 -1
  190. package/src/tests/apps-sync-engine.test.ts +8 -8
  191. package/src/tests/apps-user-config.test.ts +1 -1
  192. package/src/tests/artifact-sdk.test.ts +8 -8
  193. package/src/tests/asset-key-mcp.test.ts +2 -0
  194. package/src/tests/automation-preflight-alert.test.ts +1 -1
  195. package/src/tests/base-prompt.test.ts +7 -6
  196. package/src/tests/budget-user-scope.test.ts +1 -1
  197. package/src/tests/budgets-routes.test.ts +1 -1
  198. package/src/tests/claude-adapter-binary.test.ts +22 -40
  199. package/src/tests/claude-adapter-otel.test.ts +13 -7
  200. package/src/tests/claude-adapter.test.ts +8 -6
  201. package/src/tests/claude-hook-credentials.test.ts +3 -3
  202. package/src/tests/claude-managed-adapter.test.ts +4 -4
  203. package/src/tests/claude-managed-setup.test.ts +3 -3
  204. package/src/tests/claude-sdk-lifecycle.test.ts +1 -1
  205. package/src/tests/claude-sdk-transport.test.ts +6 -6
  206. package/src/tests/claude-stop-hook.test.ts +8 -8
  207. package/src/tests/claude-worker-parity.test.ts +3 -3
  208. package/src/tests/codex-adapter-pool-auth-revalidate.test.ts +5 -5
  209. package/src/tests/codex-adapter.test.ts +7 -5
  210. package/src/tests/codex-app-server.test.ts +2 -2
  211. package/src/tests/codex-login.test.ts +15 -15
  212. package/src/tests/codex-oauth-credential-info.test.ts +4 -4
  213. package/src/tests/codex-oauth-keep-warm.test.ts +4 -4
  214. package/src/tests/codex-oauth-refresh-lock.test.ts +1 -1
  215. package/src/tests/codex-oauth-storage.test.ts +7 -7
  216. package/src/tests/codex-pool.test.ts +1 -1
  217. package/src/tests/codex-steering-hook.test.ts +1 -1
  218. package/src/tests/codex-swarm-events.test.ts +1 -1
  219. package/src/tests/config-api-only-keys.test.ts +1 -1
  220. package/src/tests/config-session-auth.test.ts +2 -2
  221. package/src/tests/connection-embedded-auth.test.ts +20 -18
  222. package/src/tests/core-auth.test.ts +1 -1
  223. package/src/tests/create-page-tool.test.ts +3 -3
  224. package/src/tests/credential-refresh.test.ts +115 -0
  225. package/src/tests/credential-wait.test.ts +2 -2
  226. package/src/tests/credentials.test.ts +6 -4
  227. package/src/tests/db-queries-oauth.test.ts +40 -40
  228. package/src/tests/defer-task.test.ts +73 -8
  229. package/src/tests/deferred-task-wait-migration.test.ts +64 -0
  230. package/src/tests/deferred-task-wake.test.ts +349 -8
  231. package/src/tests/devin-adapter.test.ts +1 -1
  232. package/src/tests/devin-api.test.ts +1 -1
  233. package/src/tests/docs-index-footprint.test.js +3 -3
  234. package/src/tests/e2b-dispatch.test.ts +21 -19
  235. package/src/tests/e2e-claude-transport.test.ts +3 -3
  236. package/src/tests/e2e-redact.test.ts +6 -6
  237. package/src/tests/ensure-token.test.ts +68 -68
  238. package/src/tests/entrypoint-api-readiness.test.ts +1 -1
  239. package/src/tests/entrypoint-codex-oauth-seed.test.ts +13 -13
  240. package/src/tests/env-flag.test.ts +1 -0
  241. package/src/tests/events-http.test.ts +1 -1
  242. package/src/tests/extensions-db.test.ts +216 -0
  243. package/src/tests/extensions-dispatcher.test.ts +275 -0
  244. package/src/tests/extensions-example-heartbeat-remediate.test.ts +69 -0
  245. package/src/tests/extensions-example-mcp-install.test.ts +63 -0
  246. package/src/tests/extensions-example-no-exclamation-marks.test.ts +72 -0
  247. package/src/tests/extensions-example-rewrite-and-suppress.test.ts +70 -0
  248. package/src/tests/extensions-example-route-slack-channel.test.ts +217 -0
  249. package/src/tests/extensions-heartbeat.test.ts +291 -0
  250. package/src/tests/extensions-http.test.ts +431 -0
  251. package/src/tests/extensions-lead-equivalence.test.ts +49 -0
  252. package/src/tests/extensions-lifecycle.test.ts +209 -0
  253. package/src/tests/extensions-loader.test.ts +95 -0
  254. package/src/tests/extensions-mcp-tools.test.ts +245 -0
  255. package/src/tests/extensions-pre-task.test.ts +487 -0
  256. package/src/tests/extensions-run-context.test.ts +41 -0
  257. package/src/tests/extensions-tool-call.test.ts +288 -0
  258. package/src/tests/extensions-validate.test.ts +196 -0
  259. package/src/tests/fixtures/extensions/bad-import/hooks.ts +8 -0
  260. package/src/tests/fixtures/extensions/bad-import/manifest.json +9 -0
  261. package/src/tests/fixtures/extensions/bad-return-shape/hooks.ts +10 -0
  262. package/src/tests/fixtures/extensions/bad-return-shape/manifest.json +9 -0
  263. package/src/tests/fixtures/extensions/block-tasks-from-source/hooks.ts +22 -0
  264. package/src/tests/fixtures/extensions/block-tasks-from-source/manifest.json +9 -0
  265. package/src/tests/fixtures/extensions/ignore-channel/hooks.ts +22 -0
  266. package/src/tests/fixtures/extensions/ignore-channel/manifest.json +9 -0
  267. package/src/tests/fixtures/extensions/load.ts +10 -0
  268. package/src/tests/fixtures/extensions/minimal/hooks.ts +7 -0
  269. package/src/tests/fixtures/extensions/minimal/manifest.json +9 -0
  270. package/src/tests/fixtures/extensions/never-fail-long-tasks/hooks.ts +11 -0
  271. package/src/tests/fixtures/extensions/never-fail-long-tasks/manifest.json +9 -0
  272. package/src/tests/fixtures/extensions/no-exclamation-marks/hooks.ts +23 -0
  273. package/src/tests/fixtures/extensions/no-exclamation-marks/manifest.json +9 -0
  274. package/src/tests/fixtures/extensions/post-logger/hooks.ts +9 -0
  275. package/src/tests/fixtures/extensions/post-logger/manifest.json +9 -0
  276. package/src/tests/fixtures/extensions/priority-a/hooks.ts +7 -0
  277. package/src/tests/fixtures/extensions/priority-a/manifest.json +9 -0
  278. package/src/tests/fixtures/extensions/priority-b/hooks.ts +7 -0
  279. package/src/tests/fixtures/extensions/priority-b/manifest.json +9 -0
  280. package/src/tests/fixtures/extensions/record-only-on-tag/hooks.ts +16 -0
  281. package/src/tests/fixtures/extensions/record-only-on-tag/manifest.json +9 -0
  282. package/src/tests/fixtures/extensions/reserved-assets/hooks.ts +5 -0
  283. package/src/tests/fixtures/extensions/reserved-assets/manifest.json +10 -0
  284. package/src/tests/fixtures/extensions/rewrite-progress-prefix/hooks.ts +22 -0
  285. package/src/tests/fixtures/extensions/rewrite-progress-prefix/manifest.json +9 -0
  286. package/src/tests/fixtures/extensions/rewrite-task-priority/hooks.ts +7 -0
  287. package/src/tests/fixtures/extensions/rewrite-task-priority/manifest.json +9 -0
  288. package/src/tests/fixtures/extensions/route-channel-to-agent/hooks.ts +26 -0
  289. package/src/tests/fixtures/extensions/route-channel-to-agent/manifest.json +9 -0
  290. package/src/tests/fixtures/extensions/slow/hooks.ts +10 -0
  291. package/src/tests/fixtures/extensions/slow/manifest.json +9 -0
  292. package/src/tests/fixtures/extensions/suppress-lead-follow-up/hooks.ts +12 -0
  293. package/src/tests/fixtures/extensions/suppress-lead-follow-up/manifest.json +9 -0
  294. package/src/tests/fixtures/extensions/throws/hooks.ts +12 -0
  295. package/src/tests/fixtures/extensions/throws/manifest.json +9 -0
  296. package/src/tests/fixtures/extensions/worker-runtime/hooks.ts +5 -0
  297. package/src/tests/fixtures/extensions/worker-runtime/manifest.json +9 -0
  298. package/src/tests/fs-routes.test.ts +1 -1
  299. package/src/tests/gitlab-auth.test.ts +10 -10
  300. package/src/tests/harness-provider-resolution.test.ts +8 -5
  301. package/src/tests/heartbeat-reroute-decision.test.ts +1 -0
  302. package/src/tests/helper-credentials.test.ts +137 -0
  303. package/src/tests/http/context-routes.test.ts +2 -2
  304. package/src/tests/http-api-integration.test.ts +5 -2
  305. package/src/tests/http-users.test.ts +1 -1
  306. package/src/tests/identity-refresh.test.ts +2 -2
  307. package/src/tests/internal-ai/complete-structured.test.ts +2 -2
  308. package/src/tests/internal-ai/credentials.test.ts +19 -17
  309. package/src/tests/jira-metadata.test.ts +1 -1
  310. package/src/tests/jira-oauth.test.ts +5 -5
  311. package/src/tests/jira-sync.test.ts +1 -1
  312. package/src/tests/jira-webhook-lifecycle.test.ts +3 -3
  313. package/src/tests/jira-webhook.test.ts +2 -2
  314. package/src/tests/kapso-inbound.test.ts +2 -2
  315. package/src/tests/kv-http.test.ts +1 -1
  316. package/src/tests/kv-namespace-resolution.test.ts +1 -1
  317. package/src/tests/kv-page-proxy.test.ts +2 -2
  318. package/src/tests/launch-password-rejection.test.ts +2 -2
  319. package/src/tests/linear-webhook.test.ts +1 -1
  320. package/src/tests/mcp-oauth-dcr-reuse.test.ts +6 -6
  321. package/src/tests/mcp-oauth-ensure-token.test.ts +28 -22
  322. package/src/tests/mcp-oauth-manual-client.test.ts +16 -12
  323. package/src/tests/mcp-oauth-queries.test.ts +35 -32
  324. package/src/tests/mcp-oauth-resolve-secrets.test.ts +8 -8
  325. package/src/tests/mcp-oauth-wrapper.test.ts +20 -20
  326. package/src/tests/mcp-user-route.test.ts +1 -1
  327. package/src/tests/memory-edges.test.ts +1 -1
  328. package/src/tests/memory-edit-authorization.test.ts +32 -0
  329. package/src/tests/memory-rate-endpoint.test.ts +1 -1
  330. package/src/tests/memory-rate-tool.test.ts +2 -2
  331. package/src/tests/memory-rater-e2e.test.ts +1 -1
  332. package/src/tests/memory-rater-llm-summarizer.test.ts +3 -3
  333. package/src/tests/memory-rater-llm.test.ts +1 -1
  334. package/src/tests/model-control.test.ts +3 -0
  335. package/src/tests/multi-runtime-enabled-stats.test.ts +2 -2
  336. package/src/tests/multi-runtime-registration.test.ts +111 -17
  337. package/src/tests/oauth-access-token-tool.test.ts +18 -18
  338. package/src/tests/oauth-callback-flow.test.ts +8 -8
  339. package/src/tests/oauth-credential-bindings.test.ts +29 -27
  340. package/src/tests/oauth-keepalive.test.ts +10 -10
  341. package/src/tests/oauth-presets.test.ts +13 -5
  342. package/src/tests/oauth-refresh-failure.test.ts +9 -9
  343. package/src/tests/oauth-refresh-sweep.test.ts +20 -13
  344. package/src/tests/oauth-wrapper.test.ts +1 -1
  345. package/src/tests/onboard-compose.test.ts +47 -3
  346. package/src/tests/onboard-env.test.ts +26 -26
  347. package/src/tests/onboard-non-interactive.test.ts +4 -4
  348. package/src/tests/opencode-adapter.test.ts +1 -1
  349. package/src/tests/opencode-plugin.test.ts +2 -2
  350. package/src/tests/otel-session-cost-metrics.test.ts +1 -1
  351. package/src/tests/page-proxy-authed.test.ts +2 -2
  352. package/src/tests/page-proxy.test.ts +2 -2
  353. package/src/tests/page-session.test.ts +7 -7
  354. package/src/tests/page-viewer-auth.test.ts +2 -2
  355. package/src/tests/pages-authed-mode.test.ts +1 -1
  356. package/src/tests/pages-http.test.ts +1 -1
  357. package/src/tests/pages-password-mode.test.ts +1 -1
  358. package/src/tests/pages-public-authed-401.test.ts +1 -1
  359. package/src/tests/pages-public-html.test.ts +2 -2
  360. package/src/tests/pages-view-count.test.ts +1 -1
  361. package/src/tests/pi-mono-adapter.test.ts +10 -10
  362. package/src/tests/pi-mono-extension.test.ts +2 -2
  363. package/src/tests/preload.ts +5 -0
  364. package/src/tests/pricing-routes.test.ts +1 -1
  365. package/src/tests/profile-sync-warning.test.ts +8 -8
  366. package/src/tests/profile-sync.test.ts +8 -8
  367. package/src/tests/prompt-template-session.test.ts +36 -5
  368. package/src/tests/provider-process-group.test.ts +95 -4
  369. package/src/tests/providers/pi-cost.test.ts +1 -1
  370. package/src/tests/queue-stall-alarm.test.ts +1 -1
  371. package/src/tests/rbac-admission.test.ts +19 -4
  372. package/src/tests/rbac-charact-http.test.ts +1 -1
  373. package/src/tests/rbac-e2e-helpers.ts +1 -1
  374. package/src/tests/rbac-engine.test.ts +39 -0
  375. package/src/tests/realtime-room-auth.test.ts +1 -1
  376. package/src/tests/realtime-room-surfaces.test.ts +1 -1
  377. package/src/tests/reload-config.test.ts +45 -1
  378. package/src/tests/routing-affinity-inventory.test.ts +1 -1
  379. package/src/tests/routing-reason-contract.test.ts +76 -3
  380. package/src/tests/routing-reason-inventory.test.ts +11 -6
  381. package/src/tests/routing-source.test.ts +53 -0
  382. package/src/tests/runner-agent-fs-provision-retry.test.ts +1 -1
  383. package/src/tests/runner-context-preamble.test.ts +1 -1
  384. package/src/tests/runner-deployment-resume.test.ts +1 -1
  385. package/src/tests/runner-fallback-output.test.ts +1 -1
  386. package/src/tests/runner-identity-refresh.test.ts +1 -1
  387. package/src/tests/runner-skills-refresh.test.ts +1 -1
  388. package/src/tests/schedule-target-type.test.ts +3 -3
  389. package/src/tests/scheduled-tasks.test.ts +14 -5
  390. package/src/tests/scheduler-occurrence.test.ts +347 -0
  391. package/src/tests/script-apis-mcp.test.ts +1 -1
  392. package/src/tests/script-connections-http.test.ts +61 -58
  393. package/src/tests/script-connections-mcp.test.ts +1 -1
  394. package/src/tests/script-connections.test.ts +3 -1
  395. package/src/tests/script-runs-http.test.ts +15 -7
  396. package/src/tests/script-workflows-runtime-e2e.test.ts +1 -1
  397. package/src/tests/scripts-boot-reembed.test.ts +4 -0
  398. package/src/tests/scripts-embeddings.test.ts +4 -0
  399. package/src/tests/scripts-external-api.test.ts +1 -1
  400. package/src/tests/scripts-http.test.ts +1 -1
  401. package/src/tests/scripts-import-allowlist.test.ts +44 -1
  402. package/src/tests/scripts-mcp-e2e.test.ts +81 -1
  403. package/src/tests/scripts-only-gating.test.ts +4 -2
  404. package/src/tests/scripts-retention.test.ts +1 -1
  405. package/src/tests/scripts-runtime-identity.test.ts +2 -2
  406. package/src/tests/scripts-runtime-secret-egress.test.ts +1 -1
  407. package/src/tests/scripts-runtime.test.ts +6 -4
  408. package/src/tests/scripts-typecheck.test.ts +21 -0
  409. package/src/tests/sdk-allowlist.test.ts +1 -1
  410. package/src/tests/secret-scrubber.test.ts +38 -31
  411. package/src/tests/seed-registry.test.ts +46 -8
  412. package/src/tests/seed-schedules.test.ts +44 -9
  413. package/src/tests/seed-workflows.test.ts +21 -9
  414. package/src/tests/send-task-output-schema.test.ts +9 -1
  415. package/src/tests/send-task-requested-by.test.ts +1 -0
  416. package/src/tests/send-task-slack-routing-guard.test.ts +2 -0
  417. package/src/tests/session-costs-codex-recompute.test.ts +1 -1
  418. package/src/tests/session-costs-golden.test.ts +2 -2
  419. package/src/tests/session-costs-model-key-normalize.test.ts +2 -2
  420. package/src/tests/session-costs-recompute-all-providers.test.ts +1 -1
  421. package/src/tests/session-tokens.test.ts +1 -1
  422. package/src/tests/shutdown-error-scrubbing.test.ts +1 -1
  423. package/src/tests/slack-blocks.test.ts +12 -1
  424. package/src/tests/slack-file-tools-attachments.test.ts +1 -1
  425. package/src/tests/slack-inbound-files.test.ts +222 -86
  426. package/src/tests/slack-reaction-config.test.ts +5 -4
  427. package/src/tests/slack-read-boundaries.test.ts +1 -1
  428. package/src/tests/slack-render-v2.test.ts +196 -4
  429. package/src/tests/slack-router.test.ts +17 -2
  430. package/src/tests/slack-steering.test.ts +19 -0
  431. package/src/tests/status.test.ts +19 -7
  432. package/src/tests/steering-core.test.ts +1 -1
  433. package/src/tests/steering-enabled.test.ts +6 -8
  434. package/src/tests/steering-transport.test.ts +4 -4
  435. package/src/tests/store-progress-output-guidance.test.ts +34 -0
  436. package/src/tests/swarm-tool-result-gate.test.ts +11 -11
  437. package/src/tests/swarm-x-tool.test.ts +7 -5
  438. package/src/tests/sync-ai-toolbox-skills.test.ts +19 -0
  439. package/src/tests/task-supersede-resume.test.ts +1 -1
  440. package/src/tests/task-tool-preload-mcp.test.ts +4 -1
  441. package/src/tests/task-tools-ctx.test.ts +2 -0
  442. package/src/tests/tasks-requested-by-filter.test.ts +2 -2
  443. package/src/tests/telemetry-init.test.ts +11 -3
  444. package/src/tests/tool-annotations.test.ts +1 -1
  445. package/src/tests/tool-output-agent-id.test.ts +1 -0
  446. package/src/tests/tool-registrar-no-input.test.ts +42 -1
  447. package/src/tests/tracker-fold.test.ts +7 -7
  448. package/src/tests/tracker-tools.test.ts +3 -3
  449. package/src/tests/ui-followup-lead-delegation.test.ts +1 -0
  450. package/src/tests/unified-oauth-migration.test.ts +5 -5
  451. package/src/tests/user-token-rest-auth.test.ts +1 -1
  452. package/src/tests/user-token-routes.test.ts +1 -1
  453. package/src/tests/whoami-route.test.ts +1 -1
  454. package/src/tests/workflow-agent-task.test.ts +15 -13
  455. package/src/tests/workflow-ctx.test.ts +1 -1
  456. package/src/tests/workflow-e2e.test.ts +1 -1
  457. package/src/tests/workflow-engine-v2.test.ts +3 -1
  458. package/src/tests/workflow-executors.test.ts +2 -2
  459. package/src/tests/workflow-http-v2.test.ts +8 -6
  460. package/src/tests/workflow-input-redaction.test.ts +7 -5
  461. package/src/tests/workflow-integration-io.test.ts +2 -2
  462. package/src/tests/workflow-llm.test.ts +5 -5
  463. package/src/tests/workflow-registry.test.ts +1 -1
  464. package/src/tests/workflow-swarm-script.test.ts +1 -1
  465. package/src/tests/workflow-triggers-v2.test.ts +23 -21
  466. package/src/tests/x-composio.test.ts +9 -7
  467. package/src/tests/x402-client.test.ts +1 -1
  468. package/src/tests/x402-config.test.ts +28 -41
  469. package/src/tools/defer-task.ts +156 -24
  470. package/src/tools/extension-common.ts +84 -0
  471. package/src/tools/extension-install.ts +65 -0
  472. package/src/tools/extension-list.ts +66 -0
  473. package/src/tools/script-common.ts +43 -18
  474. package/src/tools/send-task.ts +87 -105
  475. package/src/tools/skills/skill-publish.ts +1 -0
  476. package/src/tools/store-progress.ts +1 -1
  477. package/src/tools/task-action.ts +43 -22
  478. package/src/tools/task-tool-ctx.ts +2 -0
  479. package/src/tools/templates.ts +2 -1
  480. package/src/tools/tool-config.ts +3 -1
  481. package/src/tools/utils.ts +140 -16
  482. package/src/types.ts +144 -0
  483. package/src/utils/constants.ts +7 -1
  484. package/src/utils/credentials.test.ts +16 -16
  485. package/src/utils/multi-runtime.ts +2 -2
  486. package/src/utils/steering-enabled.ts +4 -4
  487. package/src/workflows/executors/agent-task.ts +18 -3
  488. package/templates/ai-toolbox.manifest.json +7 -1
  489. package/templates/extensions/README.md +17 -0
  490. package/templates/extensions/notify-on-complete/README.md +11 -0
  491. package/templates/extensions/notify-on-complete/hooks.ts +61 -0
  492. package/templates/extensions/notify-on-complete/manifest.json +7 -0
  493. package/templates/extensions/require-ticket-ref/README.md +11 -0
  494. package/templates/extensions/require-ticket-ref/hooks.ts +30 -0
  495. package/templates/extensions/require-ticket-ref/manifest.json +7 -0
  496. package/templates/extensions/require-verification-note/README.md +11 -0
  497. package/templates/extensions/require-verification-note/hooks.ts +32 -0
  498. package/templates/extensions/require-verification-note/manifest.json +7 -0
  499. package/templates/schedules/daily-hn-briefing/config.json +1 -1
  500. package/templates/schedules/gtm-weekly-review/config.json +1 -1
  501. package/templates/schedules/weekly-code-health-reports/config.json +1 -1
  502. package/templates/schedules/weekly-dependabot-triage/config.json +1 -1
  503. package/templates/schedules/weekly-dora-metrics/config.json +1 -1
  504. package/templates/schedules/weekly-harness-upgrade-check/config.json +1 -1
  505. package/templates/skills/delegate-work/files/scripts/codex-exec.sh +1 -1
  506. package/templates/skills/scheduling/content.md +2 -0
  507. package/templates/skills/serply-search/SKILL.md +95 -0
  508. package/templates/skills/serply-search/config.json +13 -0
  509. package/templates/skills/serply-search/content.md +90 -0
  510. package/templates/skills/swarm-extensions/config.json +14 -0
  511. package/templates/skills/swarm-extensions/content.md +120 -0
  512. package/templates/skills/swarm-scripts/SKILL.md +2 -2
  513. package/templates/skills/swarm-scripts/content.md +2 -2
  514. package/templates/workflows/claude-code-changelog-watch/config.json +1 -1
  515. package/templates/workflows/gsc-topic-miner/config.json +1 -1
  516. package/templates/workflows/linear-drain-loop/config.json +1 -1
  517. package/templates/workflows/llm-safe-release-context/config.json +1 -1
  518. package/templates/workflows/ralph-loop/config.json +1 -1
  519. package/dist/cli-7fehefdf.js +0 -562
  520. package/dist/cli-ayvy5kde.js +0 -164
  521. package/dist/cli-ddfw1mc4.js +0 -4322
  522. package/dist/cli-hzqmgcm2.js +0 -3066
  523. package/dist/cli-j4d4f6hv.js +0 -338
  524. package/dist/cli-qgm2pfpq.js +0 -6377
  525. package/dist/cli-sdzq01t9.js +0 -823
  526. package/dist/cli-xvkmedgn.js +0 -332
  527. package/dist/cli-y3pq4v9g.js +0 -664
  528. package/dist/{anthropic-messages-vs2rabzp.js → anthropic-messages-2y8nktar.js} +19 -19
  529. package/dist/{claude-managed-setup-f5pmsyrp.js → claude-managed-setup-48dwg9bv.js} +3 -3
  530. package/dist/{cli-81r683bv.js → cli-ch38q5z4.js} +0 -0
  531. package/dist/{cli-6664w7y4.js → cli-kj76p1ez.js} +8 -8
  532. package/dist/{cli-c71mg51n.js → cli-r2fpe7cx.js} +5 -5
  533. package/dist/{cli-4xz3pmrq.js → cli-y6x0gqtg.js} +16 -16
  534. package/dist/{index-aa3sa6s8.js → index-2wsdsnmm.js} +1 -1
  535. package/dist/{mistral-conversations-4ryk7h83.js → mistral-conversations-qhr84ph3.js} +9 -9
  536. package/dist/{openai-completions-0bqmsajw.js → openai-completions-32rdwmze.js} +19 -19
  537. package/dist/{openrouter-images-qx18fyp8.js → openrouter-images-9f9ek4rw.js} +3 -3
  538. package/dist/{pi-messages-79jvzz1d.js → pi-messages-b1mbr6gp.js} +4 -4
@@ -0,0 +1,3 @@
1
+ -- Historical routing reasons have unknown provenance; do not backfill them.
2
+ ALTER TABLE agent_tasks ADD COLUMN routing_source TEXT
3
+ CHECK (routing_source IN ('declared', 'engine_default'));
@@ -0,0 +1,66 @@
1
+ CREATE TABLE extensions (
2
+ id TEXT PRIMARY KEY,
3
+ name TEXT NOT NULL UNIQUE,
4
+ description TEXT NOT NULL DEFAULT '',
5
+ runtime TEXT NOT NULL DEFAULT 'api' CHECK(runtime IN ('api', 'worker')),
6
+ manifestJson TEXT NOT NULL,
7
+ contentHash TEXT NOT NULL,
8
+ version INTEGER NOT NULL DEFAULT 1,
9
+ activeVersion INTEGER NOT NULL DEFAULT 1,
10
+ enabled INTEGER NOT NULL DEFAULT 0,
11
+ priority INTEGER NOT NULL DEFAULT 100,
12
+ configJson TEXT NOT NULL DEFAULT '{}',
13
+ status TEXT NOT NULL DEFAULT 'disabled'
14
+ CHECK(status IN ('disabled', 'enabled', 'error', 'auto-disabled')),
15
+ consecutiveFailures INTEGER NOT NULL DEFAULT 0,
16
+ lastError TEXT,
17
+ agentId TEXT,
18
+ createdByAgentId TEXT,
19
+ created_by TEXT,
20
+ updated_by TEXT,
21
+ createdAt TEXT NOT NULL DEFAULT (datetime('now')),
22
+ updatedAt TEXT NOT NULL DEFAULT (datetime('now'))
23
+ );
24
+
25
+ CREATE TABLE extension_files (
26
+ id TEXT PRIMARY KEY,
27
+ extensionId TEXT NOT NULL REFERENCES extensions(id) ON DELETE CASCADE,
28
+ path TEXT NOT NULL,
29
+ content TEXT NOT NULL,
30
+ contentHash TEXT NOT NULL,
31
+ created_by TEXT,
32
+ updated_by TEXT,
33
+ UNIQUE(extensionId, path)
34
+ );
35
+
36
+ CREATE TABLE extension_versions (
37
+ id TEXT PRIMARY KEY,
38
+ extensionId TEXT NOT NULL REFERENCES extensions(id) ON DELETE CASCADE,
39
+ version INTEGER NOT NULL,
40
+ manifestJson TEXT NOT NULL,
41
+ filesJson TEXT NOT NULL,
42
+ contentHash TEXT NOT NULL,
43
+ changedByAgentId TEXT,
44
+ changedAt TEXT NOT NULL DEFAULT (datetime('now')),
45
+ changeReason TEXT,
46
+ created_by TEXT,
47
+ updated_by TEXT,
48
+ UNIQUE(extensionId, version)
49
+ );
50
+
51
+ CREATE TABLE extension_runs (
52
+ id TEXT PRIMARY KEY,
53
+ extensionId TEXT NOT NULL REFERENCES extensions(id) ON DELETE CASCADE,
54
+ version INTEGER NOT NULL,
55
+ event TEXT NOT NULL,
56
+ action TEXT NOT NULL
57
+ CHECK(action IN ('continue', 'modify', 'block', 'error', 'timeout', 'load-error')),
58
+ durationMs INTEGER,
59
+ message TEXT,
60
+ agentId TEXT,
61
+ subject TEXT,
62
+ createdAt TEXT NOT NULL DEFAULT (datetime('now'))
63
+ );
64
+
65
+ CREATE INDEX idx_extension_runs_extension_created
66
+ ON extension_runs(extensionId, createdAt);
@@ -0,0 +1,7 @@
1
+ -- Adds a first-viewed timestamp to inbox_item_state, independent of status.
2
+ --
3
+ -- The notification bell needs to stop counting an item as unread once the
4
+ -- user has opened the panel and seen it, without moving the item out of the
5
+ -- "open" (un-actioned) bucket -- dismiss/done stay reserved for explicit user
6
+ -- actions. readAt is set once on first view and never cleared.
7
+ ALTER TABLE inbox_item_state ADD COLUMN readAt TEXT;
@@ -1,5 +1,6 @@
1
1
  import type { PermissionVerb } from "../rbac";
2
2
  import { PermissionVerbSchema } from "../rbac";
3
+ import { isEnvFlagEnabled } from "../utils/env-flag";
3
4
  import { getDb, getDbClient } from "./db";
4
5
 
5
6
  export const DEFAULT_ROLE_ID = "rbac-role-admin";
@@ -358,8 +359,8 @@ export function ensureRbacSeedsSynced(opts?: { quiet?: boolean }): RbacSeedSyncS
358
359
 
359
360
  function describeRbacFlag(): string {
360
361
  const raw = process.env.RBAC_ENABLED;
361
- if (raw === undefined) return "unset (off)";
362
- return `${raw} (${raw === "true" ? "on" : "off"})`;
362
+ if (raw === undefined) return "unset (on)";
363
+ return `${raw} (${isEnvFlagEnabled("RBAC_ENABLED", true) ? "on" : "off"})`;
363
364
  }
364
365
 
365
366
  function printRolesTable(rows: RbacRoleSummaryRow[]): void {
@@ -38,10 +38,14 @@ export type ScriptApiDefaultOptions = { raw?: false };
38
38
  export type RoutingReason = "skill" | "continuity" | "overflow" | "human_pinned" | "reroute_fault";
39
39
  export type TaskSendArgs = Record<string, unknown> & {
40
40
  task: string;
41
- routingNote?: string;
42
41
  } & (
43
- | { agentId: string; routingReason: RoutingReason }
44
- | { agentId?: never; routingReason?: never }
42
+ | {
43
+ agentId: string;
44
+ routingReason: RoutingReason;
45
+ /** At least 10 characters after trim; maximum 200. */
46
+ routingNote: string;
47
+ }
48
+ | { agentId?: never; routingReason?: never; routingNote?: string }
45
49
  );
46
50
  export type AgentTaskStepConfig = {
47
51
  template?: string;
@@ -311,6 +315,10 @@ export interface SwarmSdk {
311
315
  script_getRun(args: { id: string }): Promise<unknown>;
312
316
  script_listRuns(args?: { status?: "running" | "paused" | "completed" | "failed" | "cancelled" | "aborted_limit"; agentId?: string; limit?: number; offset?: number }): Promise<unknown>;
313
317
 
318
+ // --- write: extensions ---
319
+ extension_install(args: { manifest: Record<string, unknown>; files: Record<string, string>; priority?: number; config?: Record<string, unknown> }): Promise<unknown>;
320
+ extension_list(args?: { enabledOnly?: boolean }): Promise<unknown>;
321
+
314
322
  // --- write: repos ---
315
323
  repo_update(args: Record<string, unknown>): Promise<unknown>;
316
324
 
@@ -457,7 +465,7 @@ export async function scriptSdkTypesWithGeneratedApis(
457
465
  return `${SCRIPT_SDK_TYPES}\n${apiTypes}\n${mcpTypes}\n${resolvedAppTypes}\n`;
458
466
  }
459
467
 
460
- const STDLIB_MODULE_TYPES = `
468
+ export const SCRIPT_STDLIB_MODULE_TYPES = `
461
469
  declare module "stdlib" {
462
470
  export interface Redacted<T> {
463
471
  readonly __redactedBrand?: T;
@@ -478,7 +486,7 @@ declare module "stdlib" {
478
486
  `;
479
487
 
480
488
  function stdlibTypesFor(sdkModuleBody: string): string {
481
- return `${STDLIB_MODULE_TYPES}
489
+ return `${SCRIPT_STDLIB_MODULE_TYPES}
482
490
  declare module "swarm-sdk" {
483
491
  ${sdkModuleBody.replace(/^/gm, " ")}
484
492
  }
@@ -836,8 +844,6 @@ interface Window {
836
844
 
837
845
  const USER_FILE = "/virtual/user-script.ts";
838
846
  const CHECK_FILE = "/virtual/check.ts";
839
- const SDK_FILE = "/virtual/swarm-sdk.d.ts";
840
- const STDLIB_FILE = "/virtual/stdlib.d.ts";
841
847
  const RUNTIME_GLOBALS_FILE = "/virtual/runtime-globals.d.ts";
842
848
 
843
849
  /**
@@ -859,6 +865,7 @@ function scriptTypesBase(): string {
859
865
  function createCompilerHost(
860
866
  files: Map<string, string>,
861
867
  options: ts.CompilerOptions,
868
+ virtualModules: ReadonlyMap<string, string> = new Map(),
862
869
  ): ts.CompilerHost {
863
870
  const host = ts.createCompilerHost(options, true);
864
871
  const originalGetSourceFile = host.getSourceFile.bind(host);
@@ -891,11 +898,9 @@ function createCompilerHost(
891
898
  if (moduleName === "./user-script") {
892
899
  return { resolvedFileName: USER_FILE, extension: ts.Extension.Ts };
893
900
  }
894
- if (moduleName === "swarm-sdk") {
895
- return { resolvedFileName: SDK_FILE, extension: ts.Extension.Dts };
896
- }
897
- if (moduleName === "stdlib") {
898
- return { resolvedFileName: STDLIB_FILE, extension: ts.Extension.Dts };
901
+ const virtualModule = virtualModules.get(moduleName);
902
+ if (virtualModule) {
903
+ return { resolvedFileName: virtualModule, extension: ts.Extension.Dts };
899
904
  }
900
905
  // For external packages, resolve from project root so node_modules is found
901
906
  const base = containingFile.startsWith("/virtual/") ? projectBase : containingFile;
@@ -980,10 +985,12 @@ function toStructured(diag: ts.Diagnostic): ScriptDiagnostic {
980
985
  };
981
986
  }
982
987
 
983
- export async function typecheckScript(
984
- source: string,
985
- context: ScriptTypeContext = {},
986
- ): Promise<ScriptTypecheckResult> {
988
+ export async function typecheckWithAmbient(args: {
989
+ source: string;
990
+ modules: Record<string, string>;
991
+ ambient?: Record<string, string>;
992
+ checkFile: string;
993
+ }): Promise<ScriptTypecheckResult> {
987
994
  const options: ts.CompilerOptions = {
988
995
  allowImportingTsExtensions: true,
989
996
  lib: ["lib.es2022.d.ts"],
@@ -996,35 +1003,23 @@ export async function typecheckScript(
996
1003
  types: [],
997
1004
  };
998
1005
 
999
- const apiTypes = getScriptApiTypes(context);
1000
- const mcpTypes = getScriptMcpTypes(context);
1001
- const appTypes = await getScriptAppTypes(context);
1002
- const sdkTypes = await scriptSdkTypesWithGeneratedApis(apiTypes, mcpTypes, appTypes);
1003
- const stdlibTypes = appTypes
1004
- ? await scriptStdlibTypesWithGeneratedApis(apiTypes, mcpTypes, appTypes)
1005
- : SCRIPT_STDLIB_TYPES;
1006
1006
  const files = new Map<string, string>([
1007
- [USER_FILE, source],
1008
- [SDK_FILE, sdkTypes],
1009
- [STDLIB_FILE, stdlibTypes],
1007
+ [USER_FILE, args.source],
1010
1008
  [RUNTIME_GLOBALS_FILE, SCRIPT_RUNTIME_GLOBALS],
1011
- [
1012
- CHECK_FILE,
1013
- `/// <reference path="./runtime-globals.d.ts" />
1014
- import run from "./user-script";
1015
- import type { ScriptMain } from "swarm-sdk";
1016
- const _scriptMain: ScriptMain = run;
1017
- void _scriptMain;
1018
- `,
1019
- ],
1009
+ [CHECK_FILE, args.checkFile],
1020
1010
  ]);
1011
+ const virtualModules = new Map<string, string>();
1012
+ for (const [moduleName, source] of Object.entries(args.modules)) {
1013
+ const fileName = `/virtual/${moduleName.replace(/[^A-Za-z0-9_.-]/g, "_")}.d.ts`;
1014
+ files.set(fileName, source);
1015
+ virtualModules.set(moduleName, fileName);
1016
+ }
1017
+ for (const [name, source] of Object.entries(args.ambient ?? {})) {
1018
+ files.set(`/virtual/ambient-${name.replace(/[^A-Za-z0-9_.-]/g, "_")}.d.ts`, source);
1019
+ }
1021
1020
 
1022
- const host = createCompilerHost(files, options);
1023
- const program = ts.createProgram(
1024
- [USER_FILE, CHECK_FILE, SDK_FILE, STDLIB_FILE, RUNTIME_GLOBALS_FILE],
1025
- options,
1026
- host,
1027
- );
1021
+ const host = createCompilerHost(files, options, virtualModules);
1022
+ const program = ts.createProgram([...files.keys()], options, host);
1028
1023
  const diagnostics = [
1029
1024
  ...program.getSyntacticDiagnostics(),
1030
1025
  ...program.getSemanticDiagnostics(),
@@ -1049,3 +1044,26 @@ void _scriptMain;
1049
1044
  structured: diagnostics.map(toStructured),
1050
1045
  };
1051
1046
  }
1047
+
1048
+ export async function typecheckScript(
1049
+ source: string,
1050
+ context: ScriptTypeContext = {},
1051
+ ): Promise<ScriptTypecheckResult> {
1052
+ const apiTypes = getScriptApiTypes(context);
1053
+ const mcpTypes = getScriptMcpTypes(context);
1054
+ const appTypes = await getScriptAppTypes(context);
1055
+ const sdkTypes = await scriptSdkTypesWithGeneratedApis(apiTypes, mcpTypes, appTypes);
1056
+ const stdlibTypes = appTypes
1057
+ ? await scriptStdlibTypesWithGeneratedApis(apiTypes, mcpTypes, appTypes)
1058
+ : SCRIPT_STDLIB_TYPES;
1059
+ return typecheckWithAmbient({
1060
+ source,
1061
+ modules: { "swarm-sdk": sdkTypes, stdlib: stdlibTypes },
1062
+ checkFile: `/// <reference path="./runtime-globals.d.ts" />
1063
+ import run from "./user-script";
1064
+ import type { ScriptMain } from "swarm-sdk";
1065
+ const _scriptMain: ScriptMain = run;
1066
+ void _scriptMain;
1067
+ `,
1068
+ });
1069
+ }
@@ -11,6 +11,12 @@ import dailyCompoundingReflectionConfig from "../../../templates/schedules/daily
11
11
  import dailyCompoundingReflectionContent from "../../../templates/schedules/daily-compounding-reflection/content.md" with {
12
12
  type: "text",
13
13
  };
14
+ import dailyHnBriefingConfig from "../../../templates/schedules/daily-hn-briefing/config.json" with {
15
+ type: "text",
16
+ };
17
+ import dailyHnBriefingContent from "../../../templates/schedules/daily-hn-briefing/content.md" with {
18
+ type: "text",
19
+ };
14
20
  import dailyStatusReportConfig from "../../../templates/schedules/daily-status-report/config.json" with {
15
21
  type: "text",
16
22
  };
@@ -53,6 +59,12 @@ import weeklyDoraMetricsConfig from "../../../templates/schedules/weekly-dora-me
53
59
  import weeklyDoraMetricsContent from "../../../templates/schedules/weekly-dora-metrics/content.md" with {
54
60
  type: "text",
55
61
  };
62
+ import weeklyHarnessUpgradeCheckConfig from "../../../templates/schedules/weekly-harness-upgrade-check/config.json" with {
63
+ type: "text",
64
+ };
65
+ import weeklyHarnessUpgradeCheckContent from "../../../templates/schedules/weekly-harness-upgrade-check/content.md" with {
66
+ type: "text",
67
+ };
56
68
  import type { AutomationIntegrationId, ScheduledTask } from "../../types";
57
69
  import {
58
70
  computeContentHash,
@@ -107,6 +119,7 @@ const BUILT_IN_SCHEDULE_SOURCES: readonly ScheduleTemplateSource[] = [
107
119
  config: asText(dailyCompoundingReflectionConfig),
108
120
  content: asText(dailyCompoundingReflectionContent),
109
121
  },
122
+ { config: asText(dailyHnBriefingConfig), content: asText(dailyHnBriefingContent) },
110
123
  { config: asText(dailyStatusReportConfig), content: asText(dailyStatusReportContent) },
111
124
  {
112
125
  config: asText(dailySwarmUpdateCheckConfig),
@@ -126,6 +139,10 @@ const BUILT_IN_SCHEDULE_SOURCES: readonly ScheduleTemplateSource[] = [
126
139
  content: asText(weeklyDependabotTriageContent),
127
140
  },
128
141
  { config: asText(weeklyDoraMetricsConfig), content: asText(weeklyDoraMetricsContent) },
142
+ {
143
+ config: asText(weeklyHarnessUpgradeCheckConfig),
144
+ content: asText(weeklyHarnessUpgradeCheckContent),
145
+ },
129
146
  ];
130
147
 
131
148
  function parseScheduleSource(source: ScheduleTemplateSource): SeedSchedule | null {
@@ -137,7 +154,8 @@ function parseScheduleSource(source: ScheduleTemplateSource): SeedSchedule | nul
137
154
  ? scheduleHeading.index! + scheduleHeading[0].length
138
155
  : source.content.indexOf("```json");
139
156
  const scheduleText = source.content.slice(scheduleStart);
140
- const blockMatch = scheduleText.match(/(?:```json\s*\n)?(\{[\s\S]*?\})(?:\n```)?/);
157
+ const blockMatch =
158
+ scheduleText.match(/^\s*```json\s*\n([\s\S]*?)\n```/) ?? scheduleText.match(/(\{[\s\S]*?\})/);
141
159
  if (!blockMatch?.[1]) throw new Error(`Schedule template ${config.name} has no schedule JSON`);
142
160
  const block = JSON.parse(blockMatch[1]) as ScheduleBlock;
143
161
  const afterBlock = scheduleStart + blockMatch.index! + blockMatch[0].length;
@@ -205,9 +223,14 @@ function scheduleFromRow(schedule: ScheduledTask): SeedSchedule {
205
223
 
206
224
  function nextRunAt(schedule: SeedSchedule): string | null {
207
225
  try {
226
+ // Disabled templates can await a required timezone parameter. Validate the
227
+ // cron in UTC until setup supplies it, retaining the placeholder in the row.
228
+ const timezonePending =
229
+ !schedule.enabled &&
230
+ schedule.requiredParams.some((param) => schedule.timezone.includes(`{{${param}}}`));
208
231
  const interval = CronExpressionParser.parse(schedule.cronExpression, {
209
232
  currentDate: new Date(),
210
- tz: schedule.timezone,
233
+ tz: timezonePending ? "UTC" : schedule.timezone,
211
234
  });
212
235
  return schedule.enabled ? interval.next().toISOString() : null;
213
236
  } catch (error) {
@@ -10,6 +10,12 @@ import autopilotConfig from "../../../templates/workflows/autopilot/config.json"
10
10
  import autopilotContent from "../../../templates/workflows/autopilot/content.md" with {
11
11
  type: "text",
12
12
  };
13
+ import claudeCodeChangelogWatchConfig from "../../../templates/workflows/claude-code-changelog-watch/config.json" with {
14
+ type: "text",
15
+ };
16
+ import claudeCodeChangelogWatchContent from "../../../templates/workflows/claude-code-changelog-watch/content.md" with {
17
+ type: "text",
18
+ };
13
19
  import competitorRadarConfig from "../../../templates/workflows/competitor-radar/config.json" with {
14
20
  type: "text",
15
21
  };
@@ -22,6 +28,12 @@ import docsSiteReleasesConfig from "../../../templates/workflows/docs-site-relea
22
28
  import docsSiteReleasesContent from "../../../templates/workflows/docs-site-releases/content.md" with {
23
29
  type: "text",
24
30
  };
31
+ import gscTopicMinerConfig from "../../../templates/workflows/gsc-topic-miner/config.json" with {
32
+ type: "text",
33
+ };
34
+ import gscTopicMinerContent from "../../../templates/workflows/gsc-topic-miner/content.md" with {
35
+ type: "text",
36
+ };
25
37
  import linearDrainLoopConfig from "../../../templates/workflows/linear-drain-loop/config.json" with {
26
38
  type: "text",
27
39
  };
@@ -101,8 +113,13 @@ const asText = (value: unknown): string => value as string;
101
113
  const BUILT_IN_WORKFLOW_SOURCES: readonly WorkflowTemplateSource[] = [
102
114
  { config: asText(alertsTriageConfig), content: asText(alertsTriageContent) },
103
115
  { config: asText(autopilotConfig), content: asText(autopilotContent) },
116
+ {
117
+ config: asText(claudeCodeChangelogWatchConfig),
118
+ content: asText(claudeCodeChangelogWatchContent),
119
+ },
104
120
  { config: asText(competitorRadarConfig), content: asText(competitorRadarContent) },
105
121
  { config: asText(docsSiteReleasesConfig), content: asText(docsSiteReleasesContent) },
122
+ { config: asText(gscTopicMinerConfig), content: asText(gscTopicMinerContent) },
106
123
  { config: asText(linearDrainLoopConfig), content: asText(linearDrainLoopContent) },
107
124
  { config: asText(llmSafeReleaseContextConfig), content: asText(llmSafeReleaseContextContent) },
108
125
  { config: asText(prReviewStatusSweepConfig), content: asText(prReviewStatusSweepContent) },
@@ -3,7 +3,9 @@ import { z } from "zod";
3
3
  export const argsSchema = z.object({
4
4
  agentName: z.string().describe("Target agent's name (case-insensitive) — resolved to its id"),
5
5
  routingReason: z.enum(["skill", "continuity", "overflow", "human_pinned", "reroute_fault"]),
6
- routingNote: z.string().max(200).optional(),
6
+ routingNote: z.string().max(200).refine((note) => note.trim().length >= 10, {
7
+ message: "routingNote must contain at least 10 characters after trim",
8
+ }),
7
9
  task: z.string().describe("Full task prompt for the target agent"),
8
10
  parentTaskId: z
9
11
  .string()
@@ -36,7 +36,7 @@
36
36
  "delegate-work": [
37
37
  {
38
38
  "path": "scripts/codex-exec.sh",
39
- "content": "#!/usr/bin/env bash\n#\n# codex-exec.sh — invoke `codex exec` (non-interactive) for delegated\n# implementation work. This is the SINGLE SOURCE OF TRUTH for the invocation\n# flags. The delegate-work skill calls only this script; its routing matrix\n# decides WHICH gpt-5.6 variant (-m) and effort (-e) each task gets:\n# luna = mechanical/bounded terra = everyday frozen-spec slice\n# sol = hard/long-horizon effort: medium|high|xhigh|max (never ultra)\n#\n# Usage:\n# codex-exec.sh [-m <model>] [-e <effort>] -C <workdir> -o <last-message-file> [-l <log-file>] \"PROMPT\"\n# printf '%s' \"$PROMPT\" | codex-exec.sh -C <workdir> -o <file> # prompt via stdin (preferred)\n#\n# Notes:\n# * -C sets codex's working root (the git worktree, for parallel isolation).\n# * -o writes codex's final message (its report) to a file you can read back.\n# * Reads the prompt from stdin when no positional PROMPT is given.\n# * In `exec` mode approvals are already \"never\", so nothing hangs waiting for\n# a human. The sandbox mode below bounds what codex may WRITE.\n#\n# Sandbox default: `workspace-write` — codex may freely edit files inside its\n# working root (the worktree) and read elsewhere on disk (so it can read the\n# plan by absolute path), but cannot write outside the workspace. This keeps\n# parallel worktree runs from clobbering each other or the main tree.\n#\n# Env overrides (flags -m/-e take precedence):\n# CODEX_MODEL default: gpt-5.6-sol gpt-5.6-sol | gpt-5.6-terra | gpt-5.6-luna\n# CODEX_EFFORT default: high reasoning effort (never \"fast\"/low)\n# CODEX_SANDBOX default: workspace-write read-only | workspace-write | danger-full-access\n# CODEX_BYPASS set to 1 to use --dangerously-bypass-approvals-and-sandbox\n# (fully unsandboxed — opt in only when a phase must write\n# outside its worktree; overrides CODEX_SANDBOX)\nset -euo pipefail\n\nWORKDIR=\".\"\nOUTFILE=\"\"\nLOGFILE=\"\"\nPROMPT=\"\"\nMODEL_FLAG=\"\"\nEFFORT_FLAG=\"\"\n\nwhile [[ $# -gt 0 ]]; do\n case \"$1\" in\n -m|--model) MODEL_FLAG=\"$2\"; shift 2 ;;\n -e|--effort) EFFORT_FLAG=\"$2\"; shift 2 ;;\n -C|--cd) WORKDIR=\"$2\"; shift 2 ;;\n -o|--out) OUTFILE=\"$2\"; shift 2 ;;\n -l|--log) LOGFILE=\"$2\"; shift 2 ;;\n --) shift; PROMPT=\"${1:-}\"; break ;;\n -*) echo \"codex-exec.sh: unknown flag: $1\" >&2; exit 2 ;;\n *) PROMPT=\"$1\"; shift ;;\n esac\ndone\n\nMODEL=\"${MODEL_FLAG:-${CODEX_MODEL:-gpt-5.6-sol}}\"\nEFFORT=\"${EFFORT_FLAG:-${CODEX_EFFORT:-high}}\"\nSANDBOX=\"${CODEX_SANDBOX:-workspace-write}\"\n\nargs=( exec\n -m \"$MODEL\"\n -c \"model_reasoning_effort=\\\"$EFFORT\\\"\"\n -C \"$WORKDIR\"\n)\nif [[ \"${CODEX_BYPASS:-0}\" == \"1\" ]]; then\n args+=( --dangerously-bypass-approvals-and-sandbox )\nelse\n args+=( -s \"$SANDBOX\" )\nfi\n[[ -n \"$OUTFILE\" ]] && args+=( -o \"$OUTFILE\" )\n\n# Prompt source: positional arg if present, otherwise stdin (`-`).\nif [[ -n \"$PROMPT\" ]]; then\n set -- \"$PROMPT\"\nelse\n set -- \"-\"\nfi\n\nif [[ -n \"$LOGFILE\" ]]; then\n codex \"${args[@]}\" \"$@\" 2>&1 | tee \"$LOGFILE\"\nelse\n codex \"${args[@]}\" \"$@\"\nfi\n"
39
+ "content": "#!/usr/bin/env bash\n#\n# codex-exec.sh — invoke `codex exec` (non-interactive) for delegated\n# implementation work. This is the SINGLE SOURCE OF TRUTH for the invocation\n# flags. The delegate-work skill calls only this script; its routing matrix\n# decides WHICH gpt-5.6 variant (-m) and effort (-e) each task gets:\n# luna = mechanical/bounded terra = everyday frozen-spec slice\n# sol = hard/long-horizon effort: medium|high|xhigh|max (never ultra)\n#\n# Usage:\n# codex-exec.sh [-m <model>] [-e <effort>] -C <workdir> -o <last-message-file> [-l <log-file>] \"PROMPT\"\n# printf '%s' \"$PROMPT\" | codex-exec.sh -C <workdir> -o <file> # prompt via stdin (preferred)\n#\n# Notes:\n# * -C sets codex's working root (the git worktree, for parallel isolation).\n# * -o writes codex's final message (its report) to a file you can read back.\n# * Reads the prompt from stdin when no positional PROMPT is given.\n# * In `exec` mode approvals are already \"never\", so nothing hangs waiting for\n# a human. The sandbox mode below bounds what codex may WRITE.\n#\n# Sandbox default: `workspace-write` — codex may freely edit files inside its\n# working root (the worktree) and read elsewhere on disk (so it can read the\n# plan by absolute path), but cannot write outside the workspace. This keeps\n# parallel worktree runs from clobbering each other or the main tree.\n#\n# Env overrides (flags -m/-e take precedence):\n# CODEX_MODEL default: gpt-5.6-sol gpt-5.6-sol | gpt-5.6-terra | gpt-5.6-luna\n# CODEX_EFFORT default: high reasoning effort (never \"fast\"/low)\n# CODEX_SANDBOX default: workspace-write (passed to codex's -s option)\n# CODEX_BYPASS set to 1 to use --dangerously-bypass-approvals-and-sandbox\n# (fully unsandboxed — opt in only when a phase must write\n# outside its worktree; overrides CODEX_SANDBOX)\nset -euo pipefail\n\nWORKDIR=\".\"\nOUTFILE=\"\"\nLOGFILE=\"\"\nPROMPT=\"\"\nMODEL_FLAG=\"\"\nEFFORT_FLAG=\"\"\n\nwhile [[ $# -gt 0 ]]; do\n case \"$1\" in\n -m|--model) MODEL_FLAG=\"$2\"; shift 2 ;;\n -e|--effort) EFFORT_FLAG=\"$2\"; shift 2 ;;\n -C|--cd) WORKDIR=\"$2\"; shift 2 ;;\n -o|--out) OUTFILE=\"$2\"; shift 2 ;;\n -l|--log) LOGFILE=\"$2\"; shift 2 ;;\n --) shift; PROMPT=\"${1:-}\"; break ;;\n -*) echo \"codex-exec.sh: unknown flag: $1\" >&2; exit 2 ;;\n *) PROMPT=\"$1\"; shift ;;\n esac\ndone\n\nMODEL=\"${MODEL_FLAG:-${CODEX_MODEL:-gpt-5.6-sol}}\"\nEFFORT=\"${EFFORT_FLAG:-${CODEX_EFFORT:-high}}\"\nSANDBOX=\"${CODEX_SANDBOX:-workspace-write}\"\n\nargs=( exec\n -m \"$MODEL\"\n -c \"model_reasoning_effort=\\\"$EFFORT\\\"\"\n -C \"$WORKDIR\"\n)\nif [[ \"${CODEX_BYPASS:-0}\" == \"1\" ]]; then\n args+=( --dangerously-bypass-approvals-and-sandbox )\nelse\n args+=( -s \"$SANDBOX\" )\nfi\n[[ -n \"$OUTFILE\" ]] && args+=( -o \"$OUTFILE\" )\n\n# Prompt source: positional arg if present, otherwise stdin (`-`).\nif [[ -n \"$PROMPT\" ]]; then\n set -- \"$PROMPT\"\nelse\n set -- \"-\"\nfi\n\nif [[ -n \"$LOGFILE\" ]]; then\n codex \"${args[@]}\" \"$@\" 2>&1 | tee \"$LOGFILE\"\nelse\n codex \"${args[@]}\" \"$@\"\nfi\n"
40
40
  }
41
41
  ],
42
42
  "design-docs": [
@@ -200,6 +200,12 @@ import stepRunningConfig from "../../../templates/skills/step-running/config.jso
200
200
  import stepRunningContent from "../../../templates/skills/step-running/content.md" with {
201
201
  type: "text",
202
202
  };
203
+ import swarmExtensionsConfig from "../../../templates/skills/swarm-extensions/config.json" with {
204
+ type: "text",
205
+ };
206
+ import swarmExtensionsContent from "../../../templates/skills/swarm-extensions/content.md" with {
207
+ type: "text",
208
+ };
203
209
  import swarmScriptsConfig from "../../../templates/skills/swarm-scripts/config.json" with {
204
210
  type: "text",
205
211
  };
@@ -347,6 +353,7 @@ const BUILT_IN_SKILL_SOURCES = [
347
353
  { config: reviewingConfig, body: reviewingContent },
348
354
  { config: scheduledTaskResilienceConfig, body: scheduledTaskResilienceContent },
349
355
  { config: schedulingConfig, body: schedulingContent },
356
+ { config: swarmExtensionsConfig, body: swarmExtensionsContent },
350
357
  { config: scriptBuilderConfig, body: scriptBuilderContent },
351
358
  { config: scriptWorkflowsConfig, body: scriptWorkflowsContent },
352
359
  { config: slackInteractionConfig, body: slackInteractionContent },
@@ -76,6 +76,7 @@ export async function promoteSteeringToTask(
76
76
  return await createTaskExtended(message.body, {
77
77
  agentId: task.agentId,
78
78
  routingReason: task.agentId ? "continuity" : undefined,
79
+ routingSource: task.agentId ? "engine_default" : undefined,
79
80
  creatorAgentId: message.createdByAgentId,
80
81
  source: message.source === "script" ? "api" : message.source,
81
82
  taskType: "follow-up",
@@ -284,7 +284,7 @@ const VALIDATED_KEYS: Record<string, ConfigValidator> = {
284
284
  "DB_QUERY_BOUNDED_ENABLED",
285
285
  "DB_RETENTION_DRY_RUN",
286
286
  ]),
287
- ...enumValidator("SLACK_THREAD_STEERING", ["lead", "all"]),
287
+ ...enumValidator("SLACK_THREAD_STEERING", ["off", "lead", "all"]),
288
288
  ...enumValidator("SLACK_THREAD_STEERING_MODE", ["steer", "queue"]),
289
289
  ...shortcodeValidators([
290
290
  "SLACK_REACTION_ACCEPTED",
@@ -308,6 +308,8 @@ const VALIDATED_KEYS: Record<string, ConfigValidator> = {
308
308
  "WORKFLOW_MAX_ITERATIONS",
309
309
  "WORKFLOW_MAX_STEPS_PER_RUN",
310
310
  "SCHEDULER_INTERVAL_MS",
311
+ "EXTENSION_HANDLER_TIMEOUT_MS",
312
+ "EXTENSION_MAX_CONSECUTIVE_FAILURES",
311
313
  "RUNTIME_STALE_THRESHOLD_MIN",
312
314
  "SCRIPT_RUN_CONCURRENCY_CAP",
313
315
  "WORKER_API_READY_TIMEOUT_SECONDS",
@@ -0,0 +1,70 @@
1
+ import {
2
+ buildCredStatusReport,
3
+ isCredCheckDisabled,
4
+ sendCredStatusReport,
5
+ shouldRefreshBedrockStatus,
6
+ } from "./provider-credentials";
7
+ import type { ApiConfig } from "./runner";
8
+
9
+ export const CREDENTIAL_RETRY_INTERVAL_MS = 30_000;
10
+ const BEDROCK_REFRESH_INTERVAL_MS = 5 * 60 * 1000;
11
+
12
+ export interface CredentialRefreshState {
13
+ harnessProvider: string | null;
14
+ // null means the last attempt failed before readiness could be acknowledged.
15
+ ready: boolean | null;
16
+ lastRefreshAt: number;
17
+ inFlight: boolean;
18
+ }
19
+
20
+ /**
21
+ * Called on each runner tick after env reconciliation. Provider changes refresh
22
+ * immediately; blocked/failed reports retry on a bounded interval until the API
23
+ * acknowledges readiness. Only one build/report may be in flight at a time.
24
+ */
25
+ export async function refreshCredentialStatus(
26
+ api: ApiConfig,
27
+ state: CredentialRefreshState,
28
+ harnessProvider: string,
29
+ env: Record<string, string | undefined>,
30
+ now = Date.now(),
31
+ ): Promise<void> {
32
+ if (isCredCheckDisabled(env) || state.inFlight) return;
33
+ const providerChanged = state.harnessProvider !== harnessProvider;
34
+ const retryDue =
35
+ state.ready !== true && now - state.lastRefreshAt >= CREDENTIAL_RETRY_INTERVAL_MS;
36
+ if (
37
+ !providerChanged &&
38
+ !retryDue &&
39
+ !shouldRefreshBedrockStatus({
40
+ harnessProvider,
41
+ env,
42
+ lastRefreshAt: state.lastRefreshAt,
43
+ now,
44
+ intervalMs: BEDROCK_REFRESH_INTERVAL_MS,
45
+ })
46
+ ) {
47
+ return;
48
+ }
49
+
50
+ state.harnessProvider = harnessProvider;
51
+ state.lastRefreshAt = now;
52
+ state.ready = null;
53
+ state.inFlight = true;
54
+ try {
55
+ const snapshot = await buildCredStatusReport(harnessProvider, { ...env }, {}, "post_task");
56
+ // The runner invalidates this cache on a live provider swap. Discard a
57
+ // snapshot built for the old provider; the next tick checks the new one.
58
+ if (state.harnessProvider !== harnessProvider) return;
59
+ await sendCredStatusReport(api.apiUrl, api.apiKey, api.agentId, api.runtimeInstanceId, {
60
+ ready: snapshot.ready,
61
+ missing: snapshot.missing,
62
+ credStatus: snapshot,
63
+ });
64
+ if (state.harnessProvider === harnessProvider) state.ready = snapshot.ready;
65
+ } finally {
66
+ // Errors propagate to the runner's non-fatal logger, leaving ready unknown
67
+ // so even a lost ready:true write is retried without a restart.
68
+ state.inFlight = false;
69
+ }
70
+ }
@@ -8,6 +8,10 @@ const DEFAULT_WORKER_MAX_CONCURRENT_TASKS = 1;
8
8
  // noTemplateCurlyInString rule. We collect them via a helper to keep the
9
9
  // suppression comments in one place.
10
10
 
11
+ // Image tag for the API and agent images. Blank or unset resolves to `latest`,
12
+ // which moves on every commit to main; operators pin a release in .env.
13
+ // biome-ignore lint/suspicious/noTemplateCurlyInString: Docker Compose env var syntax
14
+ const IMAGE_TAG_EXPRESSION = "${AGENT_SWARM_VERSION:-latest}";
11
15
  // biome-ignore lint/suspicious/noTemplateCurlyInString: Docker Compose env var syntax
12
16
  const ENV_API_KEY = " - API_KEY=${API_KEY}";
13
17
  // biome-ignore lint/suspicious/noTemplateCurlyInString: Docker Compose env var syntax
@@ -108,12 +112,20 @@ export function generateCompose(state: OnboardState): string {
108
112
  lines.push("#");
109
113
  lines.push("# Usage:");
110
114
  lines.push("# docker compose --env-file .env up -d");
115
+ lines.push("#");
116
+ lines.push("# Image version: set AGENT_SWARM_VERSION in .env to a published release.");
117
+ lines.push("# Blank falls back to `latest`, which moves on every commit to main and is");
118
+ lines.push("# not a release. Releases: https://github.com/desplega-ai/agent-swarm/releases");
119
+ lines.push("# Upgrade/rollback (migrations are forward-only, so back up first):");
120
+ lines.push(
121
+ "# https://github.com/desplega-ai/agent-swarm/blob/main/skills/agent-swarm/references/upgrade.md",
122
+ );
111
123
  lines.push("");
112
124
  lines.push("services:");
113
125
 
114
126
  // ── API service ──
115
127
  lines.push(" swarm-api:");
116
- lines.push(' image: "ghcr.io/desplega-ai/agent-swarm:latest"');
128
+ lines.push(` image: "ghcr.io/desplega-ai/agent-swarm:${IMAGE_TAG_EXPRESSION}"`);
117
129
  lines.push(" container_name: swarm-api");
118
130
  lines.push(` pull_policy: ${state.pullPolicy}`);
119
131
  lines.push(" stop_grace_period: 60s");
@@ -165,7 +177,7 @@ export function generateCompose(state: OnboardState): string {
165
177
 
166
178
  lines.push("");
167
179
  lines.push(` ${svc.name}:`);
168
- lines.push(' image: "ghcr.io/desplega-ai/agent-swarm-worker:latest"');
180
+ lines.push(` image: "ghcr.io/desplega-ai/agent-swarm-worker:${IMAGE_TAG_EXPRESSION}"`);
169
181
  lines.push(` container_name: ${svc.containerName}`);
170
182
  lines.push(` pull_policy: ${state.pullPolicy}`);
171
183
  lines.push(" stop_grace_period: 60s");
@@ -16,6 +16,13 @@ export function generateEnv(state: OnboardState): string {
16
16
  lines.push(`MCP_BASE_URL=http://localhost:${port}`);
17
17
  lines.push("APP_URL=https://app.agent-swarm.dev");
18
18
 
19
+ // Image pin. Blank resolves to `latest`, which moves on every commit to main
20
+ // and is not a release. Left blank so a fresh install behaves as before;
21
+ // operators set a published release from
22
+ // https://github.com/desplega-ai/agent-swarm/releases before depending on it.
23
+ lines.push("# Pin a release, e.g. AGENT_SWARM_VERSION=1.150.0. Blank tracks `latest`.");
24
+ lines.push("AGENT_SWARM_VERSION=");
25
+
19
26
  // Install path — read by src/telemetry.ts at boot to attribute the
20
27
  // "which entry point produced this install" cohort. Boolean/enum only,
21
28
  // never an identifier. Installs that never ran the wizard (hand-written
@@ -10,8 +10,8 @@
10
10
  * Used by:
11
11
  * - The worker boot loop (`src/commands/credential-wait.ts`) to decide
12
12
  * whether the worker can claim tasks yet.
13
- * - The worker post-task hook (`src/commands/runner.ts`) to refresh on
14
- * harness_provider changes.
13
+ * - The worker steady-state refresh (`src/commands/credential-refresh.ts`)
14
+ * to check provider changes and recover blocked credentials.
15
15
  *
16
16
  * Reports flow worker → API as JSON via the existing PATCH /agents/:id
17
17
  * endpoint (see `AgentCredStatusSchema` in `src/types.ts`). The API never
@@ -537,29 +537,6 @@ export async function sendCredStatusReport(
537
537
  }
538
538
  }
539
539
 
540
- /**
541
- * Fire-and-forget wrapper around {@link sendCredStatusReport}. Used by the
542
- * post-task cache-miss path (`runner.ts`), where a stale dashboard is
543
- * acceptable and blocking the worker is not.
544
- */
545
- export async function reportCredStatus(
546
- apiUrl: string,
547
- apiKey: string,
548
- agentId: string,
549
- runtimeInstanceId: string | undefined,
550
- credStatus: AgentCredStatus,
551
- ): Promise<void> {
552
- try {
553
- await sendCredStatusReport(apiUrl, apiKey, agentId, runtimeInstanceId, {
554
- ready: credStatus.ready,
555
- missing: credStatus.missing,
556
- credStatus,
557
- });
558
- } catch (err) {
559
- console.warn(`[cred-status] POST failed (non-fatal): ${err}`);
560
- }
561
- }
562
-
563
540
  export async function reportLatestModel(
564
541
  apiUrl: string,
565
542
  apiKey: string,