@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
@@ -205,7 +205,7 @@ describe("PiMonoAdapter.createSession — MCP runtime identity header", () => {
205
205
  agentId: "test-agent",
206
206
  taskId: "test-task",
207
207
  apiUrl,
208
- apiKey: "test-key",
208
+ apiKey: "example-test-key",
209
209
  cwd: "/tmp",
210
210
  logFile: `/tmp/pi-mcp-header-test-${Date.now()}-${Math.random().toString(36).slice(2)}.log`,
211
211
  };
@@ -438,28 +438,28 @@ describe("resolveModel — OpenRouter reroute for anthropic shortnames", () => {
438
438
 
439
439
  describe("createPiRuntimeAuth", () => {
440
440
  test("threads resolved OpenRouter key into pi runtime auth without process.env", async () => {
441
- const modelRuntime = await createPiRuntimeAuth({ OPENROUTER_API_KEY: "sk-or-runtime" });
441
+ const modelRuntime = await createPiRuntimeAuth({ OPENROUTER_API_KEY: "example-sk-or-runtime" });
442
442
 
443
443
  await expect(modelRuntime.getAuth("openrouter")).resolves.toMatchObject({
444
- auth: { apiKey: "sk-or-runtime" },
444
+ auth: { apiKey: "example-sk-or-runtime" },
445
445
  });
446
446
  });
447
447
 
448
448
  test("supports all pi env-backed providers", async () => {
449
449
  const modelRuntime = await createPiRuntimeAuth({
450
- ANTHROPIC_API_KEY: "sk-ant-runtime",
451
- OPENAI_API_KEY: "sk-openai-runtime",
452
- GOOGLE_API_KEY: "sk-google-runtime",
450
+ ANTHROPIC_API_KEY: "example-sk-ant-runtime",
451
+ OPENAI_API_KEY: "example-sk-openai-runtime",
452
+ GOOGLE_API_KEY: "example-sk-google-runtime",
453
453
  });
454
454
 
455
455
  await expect(modelRuntime.getAuth("anthropic")).resolves.toMatchObject({
456
- auth: { apiKey: "sk-ant-runtime" },
456
+ auth: { apiKey: "example-sk-ant-runtime" },
457
457
  });
458
458
  await expect(modelRuntime.getAuth("openai")).resolves.toMatchObject({
459
- auth: { apiKey: "sk-openai-runtime" },
459
+ auth: { apiKey: "example-sk-openai-runtime" },
460
460
  });
461
461
  await expect(modelRuntime.getAuth("google")).resolves.toMatchObject({
462
- auth: { apiKey: "sk-google-runtime" },
462
+ auth: { apiKey: "example-sk-google-runtime" },
463
463
  });
464
464
  });
465
465
  });
@@ -641,7 +641,7 @@ function makeSessionConfig(logFile: string): ProviderSessionConfig {
641
641
  agentId: "test-agent-id",
642
642
  taskId: "test-task-id",
643
643
  apiUrl: "http://localhost:3013",
644
- apiKey: "test-key",
644
+ apiKey: "example-test-key",
645
645
  cwd: "/tmp",
646
646
  logFile,
647
647
  iteration: 1,
@@ -27,7 +27,7 @@ import { summarizeSessionForPi } from "../providers/pi-mono-extension";
27
27
  function makeConfig(): SwarmHooksConfig {
28
28
  return {
29
29
  apiUrl: "http://localhost:3013",
30
- apiKey: "test-key",
30
+ apiKey: "example-test-key",
31
31
  agentId: "agent-pi-1",
32
32
  taskId: "task-pi-1",
33
33
  isLead: false,
@@ -135,7 +135,7 @@ describe("summarizeSessionForPi", () => {
135
135
  expect(lastRunSummarizeArgs!.taskContext.sourceTaskId).toBe("task-pi-1");
136
136
  expect(lastRunSummarizeArgs!.taskContext.agentId).toBe("agent-pi-1");
137
137
  expect(lastRunSummarizeArgs!.apiUrl).toBe("http://localhost:3013");
138
- expect(lastRunSummarizeArgs!.apiKey).toBe("test-key");
138
+ expect(lastRunSummarizeArgs!.apiKey).toBe("example-test-key");
139
139
 
140
140
  const indexCalls = fetchCalls.filter((c) => c.url.endsWith("/api/memory/index"));
141
141
  expect(indexCalls.length).toBe(1);
@@ -73,6 +73,11 @@ const testTemplateGlobals = globalThis as typeof globalThis & {
73
73
  // so removing the key just forces the fast failure path (~0ms vs ~2s of API calls).
74
74
  delete process.env.OPENROUTER_API_KEY;
75
75
 
76
+ // Deployment flags must not change the test suite's default registration and
77
+ // task-admission contracts. Multi-runtime suites opt in by setting this to "true"
78
+ // and restore it themselves. Tests of the code default explicitly delete it.
79
+ process.env.MULTI_RUNTIME_ENABLED = "false";
80
+
76
81
  // Fixed fixture key for deterministic test runs (32 bytes of 0x00, base64-encoded).
77
82
  // Never used in production — the key bootstrap's `:memory:` special case requires
78
83
  // an explicit env-var key, so we set one here before initDb runs. Individual tests
@@ -20,7 +20,7 @@ import { CODEX_MODEL_PRICING } from "../providers/codex-models";
20
20
  import { listenOnFreePort } from "./test-net";
21
21
 
22
22
  const TEST_DB_PATH = "./test-pricing-routes.sqlite";
23
- const API_KEY = "test-pricing-secret-key";
23
+ const API_KEY = "example-test-pricing-secret-key";
24
24
 
25
25
  async function removeDbFiles(path: string): Promise<void> {
26
26
  for (const suffix of ["", "-wal", "-shm"]) {
@@ -72,7 +72,7 @@ describe("profile sync rejection session warning", () => {
72
72
  "ORIGINAL TASK PROMPT",
73
73
  {
74
74
  apiUrl: "https://api.example.test",
75
- apiKey: "secret-key",
75
+ apiKey: "example-secret-key",
76
76
  agentId: "agent-1",
77
77
  },
78
78
  fetchImpl,
@@ -92,7 +92,7 @@ describe("profile sync rejection session warning", () => {
92
92
  const taskPrompt = "/work-on-task child-id\n\nTask: follow up";
93
93
  const followUp = await prependProfileSyncRejectionBanner(
94
94
  prependContextPreamble(taskPrompt, context),
95
- { apiUrl: "https://api.example.test", apiKey: "secret-key", agentId: "agent-1" },
95
+ { apiUrl: "https://api.example.test", apiKey: "example-secret-key", agentId: "agent-1" },
96
96
  fetchImpl,
97
97
  );
98
98
  expect(followUp.prompt).toStartWith("/work-on-task child-id\n");
@@ -120,7 +120,7 @@ describe("profile sync rejection session warning", () => {
120
120
  const banner = await fetchProfileSyncRejectionBanner(
121
121
  {
122
122
  apiUrl: "https://api.example.test",
123
- apiKey: "secret-key",
123
+ apiKey: "example-secret-key",
124
124
  agentId: "agent-1",
125
125
  },
126
126
  fetchImpl,
@@ -153,7 +153,7 @@ describe("profile sync rejection session warning", () => {
153
153
  const banner = await fetchProfileSyncRejectionBanner(
154
154
  {
155
155
  apiUrl: "https://api.example.test",
156
- apiKey: "secret-key",
156
+ apiKey: "example-secret-key",
157
157
  agentId: "agent-1",
158
158
  },
159
159
  fetchImpl,
@@ -190,7 +190,7 @@ describe("profile sync rejection session warning", () => {
190
190
  const banner = await fetchProfileSyncRejectionBanner(
191
191
  {
192
192
  apiUrl: "https://api.example.test",
193
- apiKey: "secret-key",
193
+ apiKey: "example-secret-key",
194
194
  agentId: "agent-1",
195
195
  },
196
196
  fetchImpl,
@@ -219,7 +219,7 @@ describe("profile sync rejection session warning", () => {
219
219
  }) as typeof fetch;
220
220
  const config = {
221
221
  apiUrl: "https://api.example.test",
222
- apiKey: "secret-key",
222
+ apiKey: "example-secret-key",
223
223
  agentId: "agent-1",
224
224
  claudeMdPath: WORKSPACE_CLAUDE_MD_PATH,
225
225
  };
@@ -266,7 +266,7 @@ describe("profile sync rejection session warning", () => {
266
266
  const banner = await fetchProfileSyncRejectionBanner(
267
267
  {
268
268
  apiUrl: "https://api.example.test",
269
- apiKey: "secret-key",
269
+ apiKey: "example-secret-key",
270
270
  agentId: "agent-1",
271
271
  },
272
272
  fetchImpl,
@@ -282,7 +282,7 @@ describe("profile sync rejection session warning", () => {
282
282
  const banner = await fetchProfileSyncRejectionBanner(
283
283
  {
284
284
  apiUrl: "https://api.example.test",
285
- apiKey: "secret-key",
285
+ apiKey: "example-secret-key",
286
286
  agentId: "agent-1",
287
287
  },
288
288
  (async () => new Response("unavailable", { status: 503 })) as typeof fetch,
@@ -97,7 +97,7 @@ describe("profile divergence audit", () => {
97
97
  {
98
98
  agentId: "agent-1",
99
99
  apiUrl: "https://api.example.test",
100
- apiKey: "secret-key",
100
+ apiKey: "example-secret-key",
101
101
  claudeMdPath: WORKSPACE_CLAUDE_MD_PATH,
102
102
  },
103
103
  { fetchImpl, readFile },
@@ -131,7 +131,7 @@ describe("profile divergence audit", () => {
131
131
  {
132
132
  agentId: "agent-codex",
133
133
  apiUrl: "https://api.example.test",
134
- apiKey: "secret-key",
134
+ apiKey: "example-secret-key",
135
135
  },
136
136
  { fetchImpl, readFile },
137
137
  );
@@ -153,7 +153,7 @@ describe("profile divergence audit", () => {
153
153
  {
154
154
  agentId: "agent-unregistered",
155
155
  apiUrl: "https://api.example.test",
156
- apiKey: "secret-key",
156
+ apiKey: "example-secret-key",
157
157
  },
158
158
  { fetchImpl, readFile: async () => undefined },
159
159
  ),
@@ -172,7 +172,7 @@ describe("profile divergence audit", () => {
172
172
  {
173
173
  agentId: "agent-unset",
174
174
  apiUrl: "https://api.example.test",
175
- apiKey: "secret-key",
175
+ apiKey: "example-secret-key",
176
176
  claudeMdPath: WORKSPACE_CLAUDE_MD_PATH,
177
177
  },
178
178
  { fetchImpl, readFile },
@@ -415,7 +415,7 @@ describe("postProfileUpdate (non-2xx is surfaced, not swallowed)", () => {
415
415
  const opts = {
416
416
  agentId: "agent-1",
417
417
  apiUrl: "https://api.example.test",
418
- apiKey: "secret-key",
418
+ apiKey: "example-secret-key",
419
419
  };
420
420
  const payload = {
421
421
  label: "setup",
@@ -477,7 +477,7 @@ describe("postProfileUpdate (non-2xx is surfaced, not swallowed)", () => {
477
477
  expect(capturedUrl).toBe("https://api.example.test/api/agents/agent-1/profile");
478
478
  expect(capturedInit?.method).toBe("PUT");
479
479
  const headers = capturedInit?.headers as Record<string, string>;
480
- expect(headers.Authorization).toBe("Bearer secret-key");
480
+ expect(headers.Authorization).toBe("Bearer example-secret-key");
481
481
  expect(headers["X-Agent-ID"]).toBe("agent-1");
482
482
  expect(JSON.parse(String(capturedInit?.body))).toEqual(payload.body);
483
483
  });
@@ -498,7 +498,7 @@ describe("syncProfileFilesToServer (orchestration is non-fatal)", () => {
498
498
  await syncProfileFilesToServer({
499
499
  agentId: "agent-1",
500
500
  apiUrl: "https://api.example.test",
501
- apiKey: "secret-key",
501
+ apiKey: "example-secret-key",
502
502
  changeSource: "session_sync",
503
503
  fields: ["claude"],
504
504
  claudeMdLock: { path: lockPath, waitMs: 100 },
@@ -522,7 +522,7 @@ describe("syncProfileFilesToServer (orchestration is non-fatal)", () => {
522
522
  syncProfileFilesToServer({
523
523
  agentId: "agent-1",
524
524
  apiUrl: "https://api.example.test",
525
- apiKey: "secret-key",
525
+ apiKey: "example-secret-key",
526
526
  changeSource: "session_sync",
527
527
  // No files on a CI box → typically no payloads; still must never throw.
528
528
  claudeMdLock: { path: join(tmpdir(), `claude-md-${crypto.randomUUID()}.lock`) },
@@ -227,7 +227,7 @@ describe("Session templates: MUST pointers", () => {
227
227
  test("the lead contract names the delegation tools", () => {
228
228
  const result = resolveTemplate("system.agent.lead", {});
229
229
  expect(result.text).toContain(
230
- "`send-task`: include `routingReason` with `agentId`. Read results via `get-task-details`.",
230
+ "`send-task`: include `routingReason` and `routingNote` (at least 10 characters after trim, maximum 200) with `agentId`. Read results via `get-task-details`.",
231
231
  );
232
232
  });
233
233
 
@@ -264,17 +264,48 @@ describe("Session templates: composite resolution", () => {
264
264
  expect(result.text).not.toContain("{{@template[");
265
265
  expect(result.text).toContain("You are Ada,");
266
266
  expect(result.text).toContain("composite-agent-001");
267
- // Every provider receives the same reply limits, skill routing, and exceptions.
267
+ // Bind the budget to task output in the shared writing block itself,
268
+ // so a budget elsewhere in the composite cannot mask a reply-only rule.
269
+ const writingBlock = result.text.split("## How you write\n")[1]?.split("\n## ")[0];
270
+ expect(writingBlock).toContain("task output (`output` or a remote final message)");
271
+ expect(writingBlock).toContain(
272
+ "Routine replies and free-text task output: under 120 words by default",
273
+ );
274
+ expect(writingBlock).toContain("requested depth, enumerated results, essential evidence");
275
+ expect(writingBlock).toContain("longer output required by the task's `outputSchema`");
276
+ expect(writingBlock).toContain("Preserve investigation and required artifacts");
277
+ expect(writingBlock).toContain(
278
+ "Schema exemptions apply to `outputSchema`-constrained completions",
279
+ );
280
+ expect(writingBlock).toContain("free-text `output` follows the target");
281
+ expect(writingBlock).toContain("link documents instead of inlining them");
282
+ expect(writingBlock).not.toContain("schema-defined output");
268
283
  expect(result.text).toContain("Simple replies: one to three sentences");
269
- expect(result.text).toContain("Routine replies: under 120 words");
270
- expect(result.text).toContain("Use more detail for requested depth or essential evidence");
271
284
  expect(result.text).toContain("Use the `comms` skill when available");
272
285
  expect(result.text).toContain("Follow the current request and Requester Profile");
273
- expect(result.text).toContain("Do not shorten investigation, required artifacts");
274
286
  expect(result.text).toContain("Output schemas and channel delivery rules");
275
287
  });
276
288
  }
277
289
 
290
+ for (const eventType of ["system.agent.worker", "system.agent.worker.remote"]) {
291
+ test(`${eventType} pairs completion requirements with the output budget`, () => {
292
+ const { text } = resolveTemplate(eventType, {});
293
+ expect(text).toContain("under 120 words by default");
294
+ expect(text).toContain("Link documents instead of inlining them; omit process narration");
295
+ expect(text).toContain("under 120 words by default, with the exceptions in How you write");
296
+ });
297
+ }
298
+
299
+ for (const eventType of ["system.agent.slack", "system.agent.scripts_only_mode.slack"]) {
300
+ test(`${eventType} applies the output budget to the engine-owned card`, () => {
301
+ const { text } = resolveTemplate(eventType, { slackChannelId: "C123", slackThreadTs: "1.2" });
302
+ expect(text).toContain("The outcome card publishes your `output` verbatim");
303
+ expect(text).toContain(
304
+ "Keep free-text `output` under 120 words by default, with the exceptions in How you write",
305
+ );
306
+ });
307
+ }
308
+
278
309
  test("lead and worker differ only in the contract block", () => {
279
310
  const lead = resolveTemplate("system.session.lead", { ...vars, role: "lead" }).text;
280
311
  const worker = resolveTemplate("system.session.worker", vars).text;
@@ -3,7 +3,7 @@ import { mkdtemp, rm, writeFile } from "node:fs/promises";
3
3
  import { tmpdir } from "node:os";
4
4
  import { join } from "node:path";
5
5
  import { ClaudeAdapter } from "../providers/claude-adapter";
6
- import type { ProviderSessionConfig } from "../providers/types";
6
+ import type { ProviderSession, ProviderSessionConfig } from "../providers/types";
7
7
  import { CHILD_PROCESS_TEST_BUDGET_MS } from "./test-proc";
8
8
 
9
9
  function processExists(pid: number): boolean {
@@ -31,6 +31,18 @@ async function waitForProcessGone(pid: number, timeoutMs: number): Promise<boole
31
31
  return true;
32
32
  }
33
33
 
34
+ async function waitForPidFile(path: string, timeoutMs: number): Promise<number> {
35
+ const deadline = Date.now() + timeoutMs;
36
+ while (Date.now() < deadline) {
37
+ if (await Bun.file(path).exists()) {
38
+ const pid = Number(await Bun.file(path).text());
39
+ if (Number.isInteger(pid) && pid > 0) return pid;
40
+ }
41
+ await Bun.sleep(20);
42
+ }
43
+ throw new Error(`Timed out waiting for PID file: ${path}`);
44
+ }
45
+
34
46
  const PROCESS_GONE_TIMEOUT_MS = 5_000;
35
47
 
36
48
  describe("provider process groups", () => {
@@ -44,6 +56,7 @@ describe("provider process groups", () => {
44
56
  const grandchildPidPath = join(dir, "grandchild.pid");
45
57
  const logFile = join(dir, "claude.jsonl");
46
58
  let grandchildPid: number | undefined;
59
+ let session: ProviderSession | undefined;
47
60
 
48
61
  await writeFile(
49
62
  fixturePath,
@@ -75,21 +88,23 @@ describe("provider process groups", () => {
75
88
  logFile,
76
89
  env: {
77
90
  PATH: process.env.PATH ?? "/usr/bin:/bin",
78
- CLAUDE_CODE_OAUTH_TOKEN: "test-oauth-token",
91
+ CLAUDE_CODE_OAUTH_TOKEN: "example-test-oauth-token",
79
92
  CLAUDE_BINARY: `bun ${fixturePath}`,
93
+ CLAUDE_TRANSPORT: "cli",
80
94
  GRANDCHILD_PID_FILE: grandchildPidPath,
81
95
  },
82
96
  };
83
97
 
84
98
  try {
85
- const session = await new ClaudeAdapter(async () => {}).createSession(config);
99
+ session = await new ClaudeAdapter(async () => {}).createSession(config);
100
+ grandchildPid = await waitForPidFile(grandchildPidPath, PROCESS_GONE_TIMEOUT_MS);
86
101
  const result = await session.waitForCompletion();
87
- grandchildPid = Number(await Bun.file(grandchildPidPath).text());
88
102
 
89
103
  expect(result.exitCode).toBe(0);
90
104
  expect(Number.isInteger(grandchildPid)).toBe(true);
91
105
  expect(await waitForProcessGone(grandchildPid, PROCESS_GONE_TIMEOUT_MS)).toBe(true);
92
106
  } finally {
107
+ await session?.abort();
93
108
  if (grandchildPid && processExists(grandchildPid)) {
94
109
  try {
95
110
  process.kill(grandchildPid, "SIGKILL");
@@ -102,4 +117,80 @@ describe("provider process groups", () => {
102
117
  },
103
118
  CHILD_PROCESS_TEST_BUDGET_MS,
104
119
  );
120
+
121
+ posixTest(
122
+ "Claude adapter bounds a hanging version probe",
123
+ async () => {
124
+ const dir = await mkdtemp(join(tmpdir(), "claude-version-probe-"));
125
+ const fixturePath = join(dir, "fake-claude.ts");
126
+ const versionChildPidPath = join(dir, "version-child.pid");
127
+ const logFile = join(dir, "claude.jsonl");
128
+ let session: ProviderSession | undefined;
129
+ let versionChildPid: number | undefined;
130
+
131
+ await writeFile(
132
+ fixturePath,
133
+ `if (Bun.argv.includes("--version")) {
134
+ const child = Bun.spawn(["sh", "-c", "trap '' TERM; while :; do sleep 1; done"], {
135
+ stdin: "ignore",
136
+ stdout: "inherit",
137
+ stderr: "inherit",
138
+ });
139
+ child.unref();
140
+ await Bun.write(process.env.VERSION_CHILD_PID_FILE!, String(child.pid));
141
+ await Bun.sleep(60_000);
142
+ } else {
143
+ console.log(JSON.stringify({ type: "result", total_cost_usd: 0, is_error: false }));
144
+ }
145
+ `,
146
+ );
147
+
148
+ const config: ProviderSessionConfig = {
149
+ prompt: "finish immediately",
150
+ systemPrompt: "",
151
+ model: "sonnet",
152
+ role: "worker",
153
+ agentId: "test-agent-id",
154
+ taskId: crypto.randomUUID(),
155
+ apiUrl: "",
156
+ apiKey: "",
157
+ cwd: dir,
158
+ logFile,
159
+ env: {
160
+ PATH: process.env.PATH ?? "/usr/bin:/bin",
161
+ CLAUDE_CODE_OAUTH_TOKEN: "test-oauth-token",
162
+ CLAUDE_BINARY: `bun ${fixturePath}`,
163
+ CLAUDE_TRANSPORT: "cli",
164
+ VERSION_CHILD_PID_FILE: versionChildPidPath,
165
+ },
166
+ };
167
+
168
+ const startedAt = performance.now();
169
+ try {
170
+ session = await new ClaudeAdapter(async () => {}).createSession(config);
171
+ const sessionCreationMs = performance.now() - startedAt;
172
+ versionChildPid = await waitForPidFile(versionChildPidPath, PROCESS_GONE_TIMEOUT_MS);
173
+
174
+ expect(sessionCreationMs).toBeLessThan(PROCESS_GONE_TIMEOUT_MS);
175
+ expect(await waitForProcessGone(versionChildPid, PROCESS_GONE_TIMEOUT_MS)).toBe(true);
176
+ expect(session.deliverSteering).toBeUndefined();
177
+ const result = await session.waitForCompletion();
178
+ expect(result.exitCode).toBe(0);
179
+ } finally {
180
+ await session?.abort();
181
+ if (!versionChildPid && (await Bun.file(versionChildPidPath).exists())) {
182
+ versionChildPid = Number(await Bun.file(versionChildPidPath).text());
183
+ }
184
+ if (versionChildPid && processExists(versionChildPid)) {
185
+ try {
186
+ process.kill(versionChildPid, "SIGKILL");
187
+ } catch {
188
+ // Already reaped.
189
+ }
190
+ }
191
+ await rm(dir, { recursive: true, force: true });
192
+ }
193
+ },
194
+ CHILD_PROCESS_TEST_BUDGET_MS,
195
+ );
105
196
  });
@@ -85,7 +85,7 @@ function makeConfig(logFile: string): ProviderSessionConfig {
85
85
  agentId: "agent-1",
86
86
  taskId: "task-1",
87
87
  apiUrl: "http://localhost:0",
88
- apiKey: "test-key",
88
+ apiKey: "example-test-key",
89
89
  cwd: "/tmp",
90
90
  logFile,
91
91
  };
@@ -213,7 +213,7 @@ describe("queue stall alarm", () => {
213
213
  });
214
214
 
215
215
  test("scrubs secrets from notification failures before logging", () => {
216
- const token = "ghp_1234567890abcdefABCDEF1234567890ABCD";
216
+ const token = "example-ghp_1234567890abcdefABCDEF1234567890ABCD";
217
217
 
218
218
  const output = _test.formatCheckFailure(new Error(`Slack rejected token ${token}`));
219
219
 
@@ -22,11 +22,11 @@ import { handleFs } from "../http/fs";
22
22
  import { handleMcpOAuth } from "../http/mcp-oauth";
23
23
  import { handleTasks } from "../http/tasks";
24
24
  import { getPathSegments, parseQueryParams } from "../http/utils";
25
- import { decideAdmission, decideToolAdmission, type PermissionVerb } from "../rbac";
25
+ import { decideAdmission, decideToolAdmission, isRbacEnabled, type PermissionVerb } from "../rbac";
26
26
  import { listenOnFreePort } from "./test-net";
27
27
 
28
28
  const TEST_DB_PATH = "./test-rbac-admission.sqlite";
29
- const API_KEY = "test-api-key";
29
+ const API_KEY = "example-test-api-key";
30
30
  const LEAD_ID = "aaaa7000-0000-4000-8000-000000000001";
31
31
  const ACTOR: IdentityActor = { kind: "operator", id: "op:test" };
32
32
  const MISSING_TASK_ID = "00000000-0000-4000-8000-000000000000";
@@ -149,7 +149,7 @@ beforeEach(async () => {
149
149
  closeDb();
150
150
  await removeDbFiles();
151
151
 
152
- delete process.env.RBAC_ENABLED;
152
+ process.env.RBAC_ENABLED = "false";
153
153
  delete process.env.RBAC_AUDIT_DISABLED;
154
154
  delete process.env.RBAC_AUDIT_RETENTION_DAYS;
155
155
 
@@ -387,7 +387,7 @@ describe("handleCore admission wiring", () => {
387
387
  expect(admin.status).not.toBe(403);
388
388
  expect(admin.status).toBe(404);
389
389
 
390
- delete process.env.RBAC_ENABLED;
390
+ process.env.RBAC_ENABLED = "false";
391
391
 
392
392
  const flagOff = await api(port, "GET", "/api/mcp-oauth/missing-server/authorize-url", {
393
393
  bearer: requesterToken,
@@ -482,3 +482,18 @@ describe("handleCore admission wiring", () => {
482
482
  });
483
483
  });
484
484
  });
485
+
486
+ test("RBAC defaults on and accepts explicit opt-outs", () => {
487
+ const previous = process.env.RBAC_ENABLED;
488
+ try {
489
+ delete process.env.RBAC_ENABLED;
490
+ expect(isRbacEnabled()).toBe(true);
491
+ for (const value of ["false", "0"]) {
492
+ process.env.RBAC_ENABLED = value;
493
+ expect(isRbacEnabled()).toBe(false);
494
+ }
495
+ } finally {
496
+ if (previous === undefined) delete process.env.RBAC_ENABLED;
497
+ else process.env.RBAC_ENABLED = previous;
498
+ }
499
+ });
@@ -50,7 +50,7 @@ import { listenOnFreePort } from "./test-net";
50
50
 
51
51
  const TEST_DB_PATH = "./test-rbac-charact-http.sqlite";
52
52
  const TEST_FS_DIR = "./test-rbac-charact-http-data";
53
- const API_KEY = "test-rbac-http-key";
53
+ const API_KEY = "example-test-rbac-http-key";
54
54
  const ACTOR: IdentityActor = { kind: "operator", id: "test" };
55
55
 
56
56
  async function removeDbFiles(path: string): Promise<void> {
@@ -20,7 +20,7 @@ import { getFreePort } from "./test-net";
20
20
  export { getFreePort };
21
21
 
22
22
  export const REPO_ROOT = join(import.meta.dir, "../..");
23
- export const E2E_API_KEY = "rbac-e2e-key";
23
+ export const E2E_API_KEY = "example-rbac-e2e-key";
24
24
 
25
25
  const SERVER_LOG_TAIL_BYTES = 8 * 1024;
26
26
 
@@ -81,6 +81,9 @@ const LEAD_ONLY_VERBS: PermissionVerb[] = [
81
81
  "script.api.delete",
82
82
  ];
83
83
 
84
+ const OPERATOR_ONLY_VERBS: PermissionVerb[] = ["extension.activate"];
85
+ const LEAD_OR_OPERATOR_VERBS: PermissionVerb[] = ["extension.write"];
86
+
84
87
  const LEAD_OR_RESOURCE_OWNER_VERBS: PermissionVerb[] = [
85
88
  "memory.edit.any",
86
89
  "skill.update.any",
@@ -171,6 +174,8 @@ describe("verb-group partition", () => {
171
174
  ...ANY_AUTHENTICATED_VERBS,
172
175
  ...REQUESTER_OWNS_TASK_VERBS,
173
176
  ...COMPOSITE_VERBS,
177
+ ...OPERATOR_ONLY_VERBS,
178
+ ...LEAD_OR_OPERATOR_VERBS,
174
179
  ];
175
180
  expect(new Set(grouped).size).toBe(grouped.length);
176
181
  expect(grouped.sort()).toEqual([...PERMISSION_VERBS].sort());
@@ -216,6 +221,40 @@ describe("lead-only verbs", () => {
216
221
  });
217
222
  });
218
223
 
224
+ describe("operator-or-user verbs", () => {
225
+ const expected: Expected = {
226
+ lead: false,
227
+ worker: false,
228
+ ownerWorker: false,
229
+ creatorWorker: false,
230
+ userRequester: true,
231
+ foreignUser: true,
232
+ operator: true,
233
+ };
234
+ for (const verb of OPERATOR_ONLY_VERBS) {
235
+ test(`${verb}: operator or user allowed`, () => {
236
+ expectDecisions(verb, { kind: "none" }, expected);
237
+ });
238
+ }
239
+ });
240
+
241
+ describe("lead-or-operator-or-user verbs", () => {
242
+ const expected: Expected = {
243
+ lead: true,
244
+ worker: false,
245
+ ownerWorker: false,
246
+ creatorWorker: false,
247
+ userRequester: true,
248
+ foreignUser: true,
249
+ operator: true,
250
+ };
251
+ for (const verb of LEAD_OR_OPERATOR_VERBS) {
252
+ test(`${verb}: lead, operator, or user allowed`, () => {
253
+ expectDecisions(verb, { kind: "none" }, expected);
254
+ });
255
+ }
256
+ });
257
+
219
258
  describe("lead-or-resource-owner verbs", () => {
220
259
  const expected: Expected = {
221
260
  lead: true,
@@ -44,7 +44,7 @@ describe("realtime room namespace guards", () => {
44
44
 
45
45
  test("allows page writes for user and operator contexts when RBAC is disabled", async () => {
46
46
  const previous = process.env.RBAC_ENABLED;
47
- delete process.env.RBAC_ENABLED;
47
+ process.env.RBAC_ENABLED = "false";
48
48
  try {
49
49
  await expect(
50
50
  authorizeRoomNamespace(
@@ -23,7 +23,7 @@ import { registerRoomDecodeTool } from "../tools/rooms";
23
23
  import { listenOnFreePort } from "./test-net";
24
24
 
25
25
  const TEST_DB_PATH = "./test-realtime-room-surfaces.sqlite";
26
- const API_KEY = "test-realtime-room-key";
26
+ const API_KEY = "example-test-realtime-room-key";
27
27
 
28
28
  async function removeDbFiles(): Promise<void> {
29
29
  for (const suffix of ["", "-wal", "-shm"]) {