@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
@@ -3,7 +3,7 @@
3
3
  * handlers on both sides of MULTI_RUNTIME_ENABLED.
4
4
  */
5
5
 
6
- import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test";
6
+ import { afterAll, beforeAll, beforeEach, describe, expect, spyOn, test } from "bun:test";
7
7
  import { unlink } from "node:fs/promises";
8
8
  import { createServer as createHttpServer, type Server } from "node:http";
9
9
  import {
@@ -15,6 +15,7 @@ import {
15
15
  getActiveTaskCount,
16
16
  getAgentById,
17
17
  getDbClient,
18
+ getIdleWorkersWithCapacity,
18
19
  getSwarmConfigs,
19
20
  getTaskById,
20
21
  hasCapacity,
@@ -22,6 +23,7 @@ import {
22
23
  releaseStaleOfferedTasksForOfflineAgents,
23
24
  startTask,
24
25
  updateAgentStatus,
26
+ updateAgentStatusFromCapacity,
25
27
  upsertSwarmConfig,
26
28
  } from "../be/db";
27
29
  import {
@@ -32,8 +34,16 @@ import {
32
34
  getRuntimeInstanceById,
33
35
  hasReadyLiveRuntime,
34
36
  } from "../be/multi-runtime";
37
+ import {
38
+ CREDENTIAL_RETRY_INTERVAL_MS,
39
+ type CredentialRefreshState,
40
+ refreshCredentialStatus,
41
+ } from "../commands/credential-refresh";
35
42
  import { retryBootStep } from "../commands/credential-wait";
36
- import { sendCredStatusReport } from "../commands/provider-credentials";
43
+ import {
44
+ CREDENTIAL_PROVIDER_CHECKERS,
45
+ sendCredStatusReport,
46
+ } from "../commands/provider-credentials";
37
47
  import { runHeartbeatSweep } from "../heartbeat/heartbeat";
38
48
  import { handleActiveSessions } from "../http/active-sessions";
39
49
  import { handleAgentRegister, handleAgentsRest } from "../http/agents";
@@ -49,7 +59,7 @@ import { listenOnFreePort } from "./test-net";
49
59
 
50
60
  const TEST_DB_PATH = "./test-multi-runtime-registration.sqlite";
51
61
  let baseUrl = "";
52
- const API_KEY = "test-multi-runtime-key";
62
+ const API_KEY = "example-test-multi-runtime-key";
53
63
 
54
64
  const LEAD_ID = "44444444-4444-4444-4444-444444444444";
55
65
 
@@ -295,7 +305,7 @@ afterAll(async () => {
295
305
  });
296
306
 
297
307
  beforeEach(async () => {
298
- delete process.env.MULTI_RUNTIME_ENABLED;
308
+ process.env.MULTI_RUNTIME_ENABLED = "false";
299
309
  await getDbClient().run("DELETE FROM runtime_instances");
300
310
  await getDbClient().run("DELETE FROM active_sessions");
301
311
  // Pool sweeps cap how many tasks they assign per tick, so leftovers from an
@@ -532,7 +542,7 @@ describe("disable / legacy restoration", () => {
532
542
  expect((await getAgentById(id))?.maxTasks).toBe(3);
533
543
  expect((await getAgentMaxTasksConfig(id))?.value).toBe("3");
534
544
 
535
- delete process.env.MULTI_RUNTIME_ENABLED;
545
+ process.env.MULTI_RUNTIME_ENABLED = "false";
536
546
  const { status } = await register(id, { maxTasks: 8 });
537
547
  expect(status).toBe(200);
538
548
  expect((await getAgentById(id))?.maxTasks).toBe(8);
@@ -794,7 +804,7 @@ describe("GET /api/agents/{id}/runtime-instances", () => {
794
804
 
795
805
  await listRuntimes(id);
796
806
  // Rows written while the flag was on stay readable after a rollback.
797
- delete process.env.MULTI_RUNTIME_ENABLED;
807
+ process.env.MULTI_RUNTIME_ENABLED = "false";
798
808
  const { status, body } = await listRuntimes(id);
799
809
  expect(status).toBe(200);
800
810
  expect(body.runtimeInstances).toHaveLength(1);
@@ -859,7 +869,7 @@ describe("runtime-aware close", () => {
859
869
  const rA = crypto.randomUUID();
860
870
  await register(id, { maxTasks: 1, runtimeInstanceId: rA });
861
871
 
862
- delete process.env.MULTI_RUNTIME_ENABLED;
872
+ process.env.MULTI_RUNTIME_ENABLED = "false";
863
873
  expect(await closeRuntime(id, rA)).toBe(204);
864
874
  // Runtime rows stay inert while the flag is off.
865
875
  expect((await getAgentById(id))?.status).toBe("offline");
@@ -980,7 +990,7 @@ describe("runtime liveness via ping", () => {
980
990
  await register(id, { maxTasks: 1, runtimeInstanceId: rA });
981
991
  const before = await getRuntimeInstanceById(rA);
982
992
 
983
- delete process.env.MULTI_RUNTIME_ENABLED;
993
+ process.env.MULTI_RUNTIME_ENABLED = "false";
984
994
  await Bun.sleep(10);
985
995
  expect(await pingAgent(id, rA)).toBe(204);
986
996
  expect((await getRuntimeInstanceById(rA))?.lastSeenAt).toBe(before?.lastSeenAt ?? "");
@@ -1181,7 +1191,7 @@ describe("stale runtime liveness", () => {
1181
1191
  await register(id, { maxTasks: 1, runtimeInstanceId: rA });
1182
1192
 
1183
1193
  // Flag off: close takes the legacy path and leaves the row active.
1184
- delete process.env.MULTI_RUNTIME_ENABLED;
1194
+ process.env.MULTI_RUNTIME_ENABLED = "false";
1185
1195
  await closeRuntime(id, rA);
1186
1196
  expect((await getRuntimeInstanceById(rA))?.status).toBe("active");
1187
1197
  expect((await getAgentById(id))?.status).toBe("offline");
@@ -1376,7 +1386,7 @@ describe("rollback to legacy mode", () => {
1376
1386
  await register(id, { maxTasks: 1, runtimeInstanceId: rA });
1377
1387
 
1378
1388
  // Operator rolls back; workers stop refreshing their rows.
1379
- delete process.env.MULTI_RUNTIME_ENABLED;
1389
+ process.env.MULTI_RUNTIME_ENABLED = "false";
1380
1390
  await makeRuntimeStale(rA);
1381
1391
 
1382
1392
  const result = await expireStaleRuntimeInstances();
@@ -1392,7 +1402,7 @@ describe("rollback to legacy mode", () => {
1392
1402
  const rA = crypto.randomUUID();
1393
1403
  await register(id, { maxTasks: 1, runtimeInstanceId: rA });
1394
1404
 
1395
- delete process.env.MULTI_RUNTIME_ENABLED;
1405
+ process.env.MULTI_RUNTIME_ENABLED = "false";
1396
1406
  await makeRuntimeStale(rA);
1397
1407
  await expireStaleRuntimeInstances();
1398
1408
  expect((await getAgentById(id))?.status).toBe("idle");
@@ -1459,7 +1469,7 @@ describe("flag re-enable cycle preserves live sessions", () => {
1459
1469
 
1460
1470
  // Operator disables the flag: nothing refreshes runtime rows, but the
1461
1471
  // worker keeps executing and heartbeating its session.
1462
- delete process.env.MULTI_RUNTIME_ENABLED;
1472
+ process.env.MULTI_RUNTIME_ENABLED = "false";
1463
1473
  await makeRuntimeStale(rt);
1464
1474
 
1465
1475
  // Re-enable past the stale window; the first sweep runs expiry.
@@ -1487,7 +1497,7 @@ describe("flag re-enable cycle preserves live sessions", () => {
1487
1497
  await startTask(task.id);
1488
1498
  await startSessionFor(id, task.id, rt);
1489
1499
 
1490
- delete process.env.MULTI_RUNTIME_ENABLED;
1500
+ process.env.MULTI_RUNTIME_ENABLED = "false";
1491
1501
  await makeRuntimeStale(rt);
1492
1502
  // Sessions heartbeat on tool activity only: a long model call or shell
1493
1503
  // command can be quiet past the runtime cutoff while the worker is fine.
@@ -1516,7 +1526,7 @@ describe("flag re-enable cycle preserves live sessions", () => {
1516
1526
  await startTask(task.id);
1517
1527
  await startSessionFor(id, task.id, rt);
1518
1528
 
1519
- delete process.env.MULTI_RUNTIME_ENABLED;
1529
+ process.env.MULTI_RUNTIME_ENABLED = "false";
1520
1530
  await makeRuntimeStale(rt);
1521
1531
  await makeSessionStale(task.id, 20);
1522
1532
  // The task itself progressed recently (store-progress traffic).
@@ -1541,7 +1551,7 @@ describe("flag re-enable cycle preserves live sessions", () => {
1541
1551
  await startTask(task.id);
1542
1552
  await startSessionFor(id, task.id, rt);
1543
1553
 
1544
- delete process.env.MULTI_RUNTIME_ENABLED;
1554
+ process.env.MULTI_RUNTIME_ENABLED = "false";
1545
1555
  await makeRuntimeStale(rt);
1546
1556
  // The process died: session heartbeat AND task progress both went stale.
1547
1557
  await makeSessionStale(task.id, 30);
@@ -1568,7 +1578,7 @@ describe("flag re-enable cycle preserves live sessions", () => {
1568
1578
  await startTask(task.id);
1569
1579
  await startSessionFor(id, task.id, rt);
1570
1580
 
1571
- delete process.env.MULTI_RUNTIME_ENABLED;
1581
+ process.env.MULTI_RUNTIME_ENABLED = "false";
1572
1582
  await makeRuntimeStale(rt);
1573
1583
 
1574
1584
  const result = await expireStaleRuntimeInstances();
@@ -1762,7 +1772,7 @@ describe("sweep coverage and rollback inertness", () => {
1762
1772
  await register(id, { maxTasks: 1, runtimeInstanceId: rt });
1763
1773
 
1764
1774
  // Rolled back; the legacy worker stops refreshing its retained row.
1765
- delete process.env.MULTI_RUNTIME_ENABLED;
1775
+ process.env.MULTI_RUNTIME_ENABLED = "false";
1766
1776
  await makeRuntimeStale(rt);
1767
1777
  const task = await createTaskExtended("pool-work-legacy");
1768
1778
 
@@ -2840,3 +2850,87 @@ describe("MCP task-action accept requires a live runtime", () => {
2840
2850
  expect((await getTaskById(task.id))?.agentId).toBe(id);
2841
2851
  });
2842
2852
  });
2853
+
2854
+ describe("post-task credential recovery without a restart", () => {
2855
+ for (const multiRuntime of [false, true]) {
2856
+ test(`parked worker recovers with multi-runtime ${multiRuntime ? "on" : "off"}`, async () => {
2857
+ process.env.MULTI_RUNTIME_ENABLED = String(multiRuntime);
2858
+ const id = await makeAgent(1);
2859
+ const runtimeInstanceId = crypto.randomUUID();
2860
+ await register(id, { maxTasks: 1, runtimeInstanceId });
2861
+ const api = { apiUrl: baseUrl, apiKey: API_KEY, agentId: id, runtimeInstanceId };
2862
+ const refresh: CredentialRefreshState = {
2863
+ harnessProvider: "acp",
2864
+ ready: true,
2865
+ lastRefreshAt: 0,
2866
+ inFlight: false,
2867
+ };
2868
+ const check = spyOn(CREDENTIAL_PROVIDER_CHECKERS, "claude");
2869
+ const originalOAuth = process.env.CLAUDE_CODE_OAUTH_TOKEN;
2870
+ // The real Claude checker and live-test use OAuth presence, no upstream I/O.
2871
+ process.env.CLAUDE_CODE_OAUTH_TOKEN = "test-credential-recovery";
2872
+ try {
2873
+ // A live provider swap produces a real not-ready post-task snapshot.
2874
+ await refreshCredentialStatus(api, refresh, "claude", {}, 1);
2875
+ expect((await getAgentById(id))?.status).toBe("waiting_for_credentials");
2876
+ expect((await getAgentById(id))?.credStatus?.reportKind).toBe("post_task");
2877
+ expect((await getIdleWorkersWithCapacity()).some((agent) => agent.id === id)).toBe(false);
2878
+ if (multiRuntime) {
2879
+ expect((await getRuntimeInstanceById(runtimeInstanceId))?.credentialReady).toBe(false);
2880
+ }
2881
+
2882
+ // Ping and completion/capacity reconciliation cannot recover it.
2883
+ await pingAgent(id, runtimeInstanceId);
2884
+ await updateAgentStatusFromCapacity(id);
2885
+ expect((await getAgentById(id))?.status).toBe("waiting_for_credentials");
2886
+ await refreshCredentialStatus(api, refresh, "claude", {}, CREDENTIAL_RETRY_INTERVAL_MS);
2887
+ expect(check).toHaveBeenCalledTimes(1);
2888
+
2889
+ // A still-missing snapshot stays parked, and starts a new throttle window.
2890
+ await refreshCredentialStatus(api, refresh, "claude", {}, CREDENTIAL_RETRY_INTERVAL_MS + 1);
2891
+ expect(check).toHaveBeenCalledTimes(2);
2892
+ expect((await getAgentById(id))?.status).toBe("waiting_for_credentials");
2893
+ const env = { CLAUDE_CODE_OAUTH_TOKEN: "test-credential-recovery" };
2894
+ await refreshCredentialStatus(
2895
+ api,
2896
+ refresh,
2897
+ "claude",
2898
+ env,
2899
+ 2 * CREDENTIAL_RETRY_INTERVAL_MS,
2900
+ );
2901
+ expect(check).toHaveBeenCalledTimes(2);
2902
+ expect((await getAgentById(id))?.status).toBe("waiting_for_credentials");
2903
+
2904
+ // Credentials resolve. Same runner state, provider, and runtime identity.
2905
+ await refreshCredentialStatus(
2906
+ api,
2907
+ refresh,
2908
+ "claude",
2909
+ env,
2910
+ 2 * CREDENTIAL_RETRY_INTERVAL_MS + 1,
2911
+ );
2912
+ expect(check).toHaveBeenCalledTimes(3);
2913
+ expect((await getAgentById(id))?.status).toBe("idle");
2914
+ expect((await getAgentById(id))?.credStatus?.ready).toBe(true);
2915
+ expect((await getAgentById(id))?.credentialMissing).toBeNull();
2916
+ expect((await getIdleWorkersWithCapacity()).some((agent) => agent.id === id)).toBe(true);
2917
+ if (multiRuntime) {
2918
+ expect((await getRuntimeInstanceById(runtimeInstanceId))?.credentialReady).toBe(true);
2919
+ expect(await countActiveRuntimeInstancesForAgent(id)).toBe(1);
2920
+ }
2921
+ await refreshCredentialStatus(
2922
+ api,
2923
+ refresh,
2924
+ "claude",
2925
+ env,
2926
+ 10 * CREDENTIAL_RETRY_INTERVAL_MS,
2927
+ );
2928
+ expect(check).toHaveBeenCalledTimes(3);
2929
+ } finally {
2930
+ check.mockRestore();
2931
+ if (originalOAuth === undefined) delete process.env.CLAUDE_CODE_OAUTH_TOKEN;
2932
+ else process.env.CLAUDE_CODE_OAUTH_TOKEN = originalOAuth;
2933
+ }
2934
+ });
2935
+ }
2936
+ });
@@ -23,7 +23,7 @@ const originalFetch = globalThis.fetch;
23
23
 
24
24
  const testApp = {
25
25
  clientId: "client-id",
26
- clientSecret: "client-secret",
26
+ clientSecret: "example-client-secret",
27
27
  authorizeUrl: "https://example.com/oauth/authorize",
28
28
  tokenUrl: "https://example.com/oauth/token",
29
29
  redirectUri: "http://localhost:3013/callback",
@@ -69,8 +69,8 @@ afterAll(async () => {
69
69
  describe("resolveOAuthAccessToken", () => {
70
70
  test("registered MCP tool returns a seeded provider token", async () => {
71
71
  await storeOAuthTokens("custom-provider", {
72
- accessToken: "mcp-tool-access-token-plain-value",
73
- refreshToken: "mcp-tool-refresh-token",
72
+ accessToken: "example-mcp-tool-access-token-plain-value",
73
+ refreshToken: "example-mcp-tool-refresh-token",
74
74
  expiresAt: new Date(Date.now() + 3600_000).toISOString(),
75
75
  });
76
76
  const server = new McpServer({ name: "oauth-access-token-test", version: "1.0.0" });
@@ -112,7 +112,7 @@ describe("resolveOAuthAccessToken", () => {
112
112
  expect(result.structuredContent).toMatchObject({
113
113
  success: true,
114
114
  provider: "custom-provider",
115
- accessToken: "mcp-tool-access-token-plain-value",
115
+ accessToken: "example-mcp-tool-access-token-plain-value",
116
116
  expiresAt: expect.any(String),
117
117
  tokenType: "Bearer",
118
118
  });
@@ -123,7 +123,7 @@ describe("resolveOAuthAccessToken", () => {
123
123
  // details carries the actual token payload (allowSecretEgress: true means
124
124
  // the central scrubber does not redact it, since the tool's whole purpose
125
125
  // is handing over the plaintext token).
126
- expect(result.structuredContent.details).toBe("mcp-tool-access-token-plain-value");
126
+ expect(result.structuredContent.details).toBe("example-mcp-tool-access-token-plain-value");
127
127
 
128
128
  // content[0].text is composed as message + "\n\n" + details, so both
129
129
  // channels (text for pi/opencode/claude-managed, structuredContent for
@@ -132,7 +132,7 @@ describe("resolveOAuthAccessToken", () => {
132
132
  expect(result.content).toHaveLength(1);
133
133
  expect(result.content[0].type).toBe("text");
134
134
  expect(result.content[0].text).toBe(
135
- `custom-provider OAuth access token resolved; expires at ${expiresAt}.\n\nmcp-tool-access-token-plain-value`,
135
+ `custom-provider OAuth access token resolved; expires at ${expiresAt}.\n\nexample-mcp-tool-access-token-plain-value`,
136
136
  );
137
137
  });
138
138
 
@@ -170,10 +170,10 @@ describe("resolveOAuthAccessToken", () => {
170
170
  });
171
171
 
172
172
  test("returns a fresh access token and registers it for scrubber redaction", async () => {
173
- const accessToken = "linear-access-token-plain-value-1234567890";
173
+ const accessToken = "example-linear-access-token-plain-value-1234567890";
174
174
  await storeOAuthTokens("linear", {
175
175
  accessToken,
176
- refreshToken: "linear-refresh-token",
176
+ refreshToken: "example-linear-refresh-token",
177
177
  expiresAt: new Date(Date.now() + 3600_000).toISOString(),
178
178
  });
179
179
 
@@ -192,21 +192,21 @@ describe("resolveOAuthAccessToken", () => {
192
192
 
193
193
  test("supports any configured OAuth provider slug", async () => {
194
194
  await storeOAuthTokens("custom-provider", {
195
- accessToken: "custom-provider-access-token-plain-value",
196
- refreshToken: "custom-provider-refresh-token",
195
+ accessToken: "example-custom-provider-access-token-plain-value",
196
+ refreshToken: "example-custom-provider-refresh-token",
197
197
  expiresAt: new Date(Date.now() + 3600_000).toISOString(),
198
198
  });
199
199
 
200
200
  const result = await resolveOAuthAccessToken("custom-provider");
201
201
 
202
202
  expect(result.provider).toBe("custom-provider");
203
- expect(result.accessToken).toBe("custom-provider-access-token-plain-value");
203
+ expect(result.accessToken).toBe("example-custom-provider-access-token-plain-value");
204
204
  });
205
205
 
206
206
  test("refreshes Jira before returning a near-expiry token", async () => {
207
207
  await storeOAuthTokens("jira", {
208
- accessToken: "old-jira-access-token",
209
- refreshToken: "old-jira-refresh-token",
208
+ accessToken: "example-old-jira-access-token",
209
+ refreshToken: "example-old-jira-refresh-token",
210
210
  expiresAt: new Date(Date.now() + 60_000).toISOString(),
211
211
  });
212
212
 
@@ -214,10 +214,10 @@ describe("resolveOAuthAccessToken", () => {
214
214
  Promise.resolve(
215
215
  new Response(
216
216
  JSON.stringify({
217
- access_token: "new-jira-access-token-plain-value",
217
+ access_token: "example-new-jira-access-token-plain-value",
218
218
  token_type: "Bearer",
219
219
  expires_in: 3600,
220
- refresh_token: "new-jira-refresh-token",
220
+ refresh_token: "example-new-jira-refresh-token",
221
221
  }),
222
222
  { status: 200, headers: { "Content-Type": "application/json" } },
223
223
  ),
@@ -228,13 +228,13 @@ describe("resolveOAuthAccessToken", () => {
228
228
  const result = await resolveOAuthAccessToken("jira");
229
229
 
230
230
  expect(fetchSpy).toHaveBeenCalledTimes(1);
231
- expect(result.accessToken).toBe("new-jira-access-token-plain-value");
232
- expect((await getOAuthTokens("jira"))?.refreshToken).toBe("new-jira-refresh-token");
231
+ expect(result.accessToken).toBe("example-new-jira-access-token-plain-value");
232
+ expect((await getOAuthTokens("jira"))?.refreshToken).toBe("example-new-jira-refresh-token");
233
233
  });
234
234
 
235
235
  test("rejects a near-expiry token when no refresh token is available", async () => {
236
236
  await storeOAuthTokens("jira", {
237
- accessToken: "stale-jira-access-token",
237
+ accessToken: "example-stale-jira-access-token",
238
238
  refreshToken: null,
239
239
  expiresAt: new Date(Date.now() + 60_000).toISOString(),
240
240
  });
@@ -85,10 +85,10 @@ beforeAll(async () => {
85
85
  if (url.pathname === "/token") {
86
86
  lastTokenBody = await req.text();
87
87
  return Response.json({
88
- access_token: "mock-access-token",
88
+ access_token: "example-mock-access-token",
89
89
  token_type: "Bearer",
90
90
  expires_in: 3600,
91
- refresh_token: "mock-refresh-token",
91
+ refresh_token: "example-mock-refresh-token",
92
92
  scope: "read write",
93
93
  });
94
94
  }
@@ -98,7 +98,7 @@ beforeAll(async () => {
98
98
  // fabricated one.
99
99
  lastTokenBody = await req.text();
100
100
  return Response.json({
101
- access_token: "mock-access-token",
101
+ access_token: "example-mock-access-token",
102
102
  token_type: "bearer",
103
103
  scope: "read",
104
104
  });
@@ -183,8 +183,8 @@ describe("static OAuth callback + multi-authorization flow", () => {
183
183
  expect(supportAuth.accountEmail).toBe("connected@example.test");
184
184
  // Tokens are encrypted at rest but decrypt to the mock values on read.
185
185
  expect(supportAuth.tokensEncrypted).toBe(true);
186
- expect(supportAuth.accessToken).toBe("mock-access-token");
187
- expect(supportAuth.refreshToken).toBe("mock-refresh-token");
186
+ expect(supportAuth.accessToken).toBe("example-mock-access-token");
187
+ expect(supportAuth.refreshToken).toBe("example-mock-refresh-token");
188
188
 
189
189
  // Second label: "sales" — first authorization must be untouched.
190
190
  const sales = await buildAuthorizationUrl(config, { appId, label: "sales", flow: "generic" });
@@ -383,7 +383,7 @@ describe("static OAuth callback + multi-authorization flow", () => {
383
383
  tokenUrl: `${providerBase}/token`,
384
384
  scopes: "read",
385
385
  dcrClientId: "mcp-client",
386
- dcrClientSecret: "mcp-secret",
386
+ dcrClientSecret: "example-mcp-secret",
387
387
  redirectUri: `${appBase}/api/oauth/callback`,
388
388
  });
389
389
 
@@ -464,7 +464,7 @@ describe("step-4 security hardening", () => {
464
464
  try {
465
465
  const identity = await captureIdentity({
466
466
  userinfoUrl: "http://127.0.0.1/userinfo",
467
- accessToken: "live-bearer",
467
+ accessToken: "example-live-bearer",
468
468
  });
469
469
  expect(identity).toBeNull();
470
470
  } finally {
@@ -476,7 +476,7 @@ describe("step-4 security hardening", () => {
476
476
  test("captureIdentity does not follow a redirect to a private host", async () => {
477
477
  const identity = await captureIdentity({
478
478
  userinfoUrl: `${providerBase}/userinfo-redirect`,
479
- accessToken: "live-bearer",
479
+ accessToken: "example-live-bearer",
480
480
  });
481
481
  // The 302 is not followed (redirect: manual → not .ok), so no identity.
482
482
  expect(identity).toBeNull();
@@ -144,7 +144,7 @@ describe("OAuth credential bindings", () => {
144
144
 
145
145
  await upsertOAuthApp("phase2-roundtrip", testApp("phase2-roundtrip"));
146
146
  await storeOAuthTokens("phase2-roundtrip", {
147
- accessToken: "roundtrip-access",
147
+ accessToken: "example-roundtrip-access",
148
148
  expiresAt: new Date(Date.now() + 60 * 60 * 1000).toISOString(),
149
149
  });
150
150
  const authorizationId = (await getOAuthTokens("phase2-roundtrip"))!.id;
@@ -170,8 +170,8 @@ describe("OAuth credential bindings", () => {
170
170
  test("OAuth binding resolves through the stored access token", async () => {
171
171
  await upsertOAuthApp("phase2-resolve", testApp("phase2-resolve"));
172
172
  await storeOAuthTokens("phase2-resolve", {
173
- accessToken: "stored-oauth-access",
174
- refreshToken: "stored-oauth-refresh",
173
+ accessToken: "example-stored-oauth-access",
174
+ refreshToken: "example-stored-oauth-refresh",
175
175
  expiresAt: new Date(Date.now() + 60 * 60 * 1000).toISOString(),
176
176
  });
177
177
  await upsertCredentialBinding({
@@ -188,7 +188,7 @@ describe("OAuth credential bindings", () => {
188
188
  expect(bindings).toContainEqual(
189
189
  expect.objectContaining({
190
190
  configKey: "PHASE2_RESOLVE_OAUTH",
191
- value: "stored-oauth-access",
191
+ value: "example-stored-oauth-access",
192
192
  }),
193
193
  );
194
194
  });
@@ -196,8 +196,8 @@ describe("OAuth credential bindings", () => {
196
196
  test("expiring OAuth binding token is refreshed before resolution", async () => {
197
197
  await upsertOAuthApp("phase2-refresh", testApp("phase2-refresh"));
198
198
  await storeOAuthTokens("phase2-refresh", {
199
- accessToken: "old-access-token",
200
- refreshToken: "old-refresh-token",
199
+ accessToken: "example-old-access-token",
200
+ refreshToken: "example-old-refresh-token",
201
201
  expiresAt: new Date(Date.now() + 60 * 1000).toISOString(),
202
202
  });
203
203
  await upsertCredentialBinding({
@@ -215,13 +215,13 @@ describe("OAuth credential bindings", () => {
215
215
  }
216
216
  expect(init?.method).toBe("POST");
217
217
  expect(String(init?.body)).toContain("grant_type=refresh_token");
218
- expect(String(init?.body)).toContain("refresh_token=old-refresh-token");
218
+ expect(String(init?.body)).toContain("refresh_token=example-old-refresh-token");
219
219
  return Promise.resolve(
220
220
  Response.json({
221
- access_token: "new-access-token",
221
+ access_token: "example-new-access-token",
222
222
  token_type: "Bearer",
223
223
  expires_in: 3600,
224
- refresh_token: "new-refresh-token",
224
+ refresh_token: "example-new-refresh-token",
225
225
  }),
226
226
  );
227
227
  });
@@ -233,10 +233,12 @@ describe("OAuth credential bindings", () => {
233
233
  expect(bindings).toContainEqual(
234
234
  expect.objectContaining({
235
235
  configKey: "PHASE2_REFRESH_OAUTH",
236
- value: "new-access-token",
236
+ value: "example-new-access-token",
237
237
  }),
238
238
  );
239
- expect((await getOAuthTokens("phase2-refresh"))?.refreshToken).toBe("new-refresh-token");
239
+ expect((await getOAuthTokens("phase2-refresh"))?.refreshToken).toBe(
240
+ "example-new-refresh-token",
241
+ );
240
242
  });
241
243
 
242
244
  test("basic tokenAuthStyle + json tokenBodyFormat reach the token endpoint (Notion-style)", async () => {
@@ -245,8 +247,8 @@ describe("OAuth credential bindings", () => {
245
247
  metadata: JSON.stringify({ tokenAuthStyle: "basic", tokenBodyFormat: "json" }),
246
248
  });
247
249
  await storeOAuthTokens("phase2-basic", {
248
- accessToken: "old-basic-access",
249
- refreshToken: "old-basic-refresh",
250
+ accessToken: "example-old-basic-access",
251
+ refreshToken: "example-old-basic-refresh",
250
252
  expiresAt: new Date(Date.now() + 60 * 1000).toISOString(),
251
253
  });
252
254
  await upsertCredentialBinding({
@@ -272,16 +274,16 @@ describe("OAuth credential bindings", () => {
272
274
  expect(headers.get("content-type")).toBe("application/json");
273
275
  const body = JSON.parse(String(init?.body)) as Record<string, string>;
274
276
  expect(body.grant_type).toBe("refresh_token");
275
- expect(body.refresh_token).toBe("old-basic-refresh");
277
+ expect(body.refresh_token).toBe("example-old-basic-refresh");
276
278
  // Basic auth carries the client credentials — they must NOT be in the body
277
279
  expect(body.client_id).toBeUndefined();
278
280
  expect(body.client_secret).toBeUndefined();
279
281
  return Promise.resolve(
280
282
  Response.json({
281
- access_token: "new-basic-access",
283
+ access_token: "example-new-basic-access",
282
284
  token_type: "Bearer",
283
285
  expires_in: 3600,
284
- refresh_token: "new-basic-refresh",
286
+ refresh_token: "example-new-basic-refresh",
285
287
  }),
286
288
  );
287
289
  });
@@ -293,7 +295,7 @@ describe("OAuth credential bindings", () => {
293
295
  expect(bindings).toContainEqual(
294
296
  expect.objectContaining({
295
297
  configKey: "PHASE2_BASIC_OAUTH",
296
- value: "new-basic-access",
298
+ value: "example-new-basic-access",
297
299
  }),
298
300
  );
299
301
  });
@@ -323,7 +325,7 @@ describe("OAuth credential bindings", () => {
323
325
  action: "oauth-app-upsert",
324
326
  provider: "jira",
325
327
  clientId: "jira-client",
326
- clientSecret: "jira-secret",
328
+ clientSecret: "example-jira-secret",
327
329
  authorizeUrl: "https://oauth.example.test/authorize",
328
330
  tokenUrl: "https://oauth.example.test/token",
329
331
  scopes: [],
@@ -345,7 +347,7 @@ describe("OAuth credential bindings", () => {
345
347
  action: "oauth-app-upsert",
346
348
  provider: "phase2-tool-unsafe",
347
349
  clientId: "unsafe-client",
348
- clientSecret: "unsafe-secret",
350
+ clientSecret: "example-unsafe-secret",
349
351
  authorizeUrl: "https://oauth.example.test/authorize",
350
352
  tokenUrl: "http://127.0.0.1/token",
351
353
  scopes: [],
@@ -362,7 +364,7 @@ describe("OAuth credential bindings", () => {
362
364
  action: "oauth-app-upsert",
363
365
  provider: "phase2-tool-safe",
364
366
  clientId: "safe-client",
365
- clientSecret: "safe-secret",
367
+ clientSecret: "example-safe-secret",
366
368
  authorizeUrl: "https://oauth.example.test/authorize",
367
369
  tokenUrl: "https://oauth.example.test/token",
368
370
  scopes: ["read"],
@@ -377,8 +379,8 @@ describe("OAuth credential bindings", () => {
377
379
  test("failed OAuth token refresh skips only that binding, others still resolve", async () => {
378
380
  await upsertOAuthApp("phase2-broken", testApp("phase2-broken"));
379
381
  await storeOAuthTokens("phase2-broken", {
380
- accessToken: "stale-access-token",
381
- refreshToken: "stale-refresh-token",
382
+ accessToken: "example-stale-access-token",
383
+ refreshToken: "example-stale-refresh-token",
382
384
  expiresAt: new Date(Date.now() + 60 * 1000).toISOString(),
383
385
  });
384
386
  await upsertCredentialBinding({
@@ -419,7 +421,7 @@ describe("OAuth credential bindings", () => {
419
421
  test("revoked OAuth token skips binding resolution and list reports revoked", async () => {
420
422
  await upsertOAuthApp("phase2-missing", testApp("phase2-missing"));
421
423
  await storeOAuthTokens("phase2-missing", {
422
- accessToken: "soon-deleted",
424
+ accessToken: "example-soon-deleted",
423
425
  expiresAt: new Date(Date.now() + 60 * 60 * 1000).toISOString(),
424
426
  });
425
427
  const authorizationId = (await getOAuthTokens("phase2-missing"))!.id;
@@ -465,10 +467,10 @@ describe("OAuth credential bindings", () => {
465
467
  expect(String(init?.body)).toContain("grant_type=authorization_code");
466
468
  expect(String(init?.body)).toContain("code=callback-code");
467
469
  return Response.json({
468
- access_token: "callback-access-token",
470
+ access_token: "example-callback-access-token",
469
471
  token_type: "Bearer",
470
472
  expires_in: 3600,
471
- refresh_token: "callback-refresh-token",
473
+ refresh_token: "example-callback-refresh-token",
472
474
  scope: "read write",
473
475
  });
474
476
  }) as typeof fetch;
@@ -483,8 +485,8 @@ describe("OAuth credential bindings", () => {
483
485
  expect(res.status).toBe(200);
484
486
  expect(await res.text()).toContain("You can close this tab.");
485
487
  const tokens = await getOAuthTokens(provider);
486
- expect(tokens?.accessToken).toBe("callback-access-token");
487
- expect(tokens?.refreshToken).toBe("callback-refresh-token");
488
+ expect(tokens?.accessToken).toBe("example-callback-access-token");
489
+ expect(tokens?.refreshToken).toBe("example-callback-refresh-token");
488
490
  } finally {
489
491
  server.close();
490
492
  }
@@ -22,7 +22,7 @@ function restoreSlackAlertsChannel(): void {
22
22
 
23
23
  const testApp = {
24
24
  clientId: "test-client-id",
25
- clientSecret: "test-client-secret",
25
+ clientSecret: "example-test-client-secret",
26
26
  authorizeUrl: "https://example.com/oauth/authorize",
27
27
  tokenUrl: "https://example.com/oauth/token",
28
28
  redirectUri: "http://localhost:3013/callback",
@@ -78,13 +78,13 @@ describe("OAuth keepalive", () => {
78
78
 
79
79
  test("stopOAuthKeepalive waits for in-flight Jira refresh persistence", async () => {
80
80
  await storeOAuthTokens("linear", {
81
- accessToken: "linear-access",
82
- refreshToken: "linear-refresh",
81
+ accessToken: "example-linear-access",
82
+ refreshToken: "example-linear-refresh",
83
83
  expiresAt: new Date(Date.now() + 60 * 60 * 1000).toISOString(),
84
84
  });
85
85
  await storeOAuthTokens("jira", {
86
- accessToken: "old-jira-access",
87
- refreshToken: "old-jira-refresh",
86
+ accessToken: "example-old-jira-access",
87
+ refreshToken: "example-old-jira-refresh",
88
88
  expiresAt: new Date(Date.now() + 60 * 1000).toISOString(),
89
89
  });
90
90
 
@@ -102,10 +102,10 @@ describe("OAuth keepalive", () => {
102
102
  await tokenResponseReady;
103
103
  return new Response(
104
104
  JSON.stringify({
105
- access_token: "new-jira-access",
105
+ access_token: "example-new-jira-access",
106
106
  token_type: "Bearer",
107
107
  expires_in: 3600,
108
- refresh_token: "new-jira-refresh",
108
+ refresh_token: "example-new-jira-refresh",
109
109
  }),
110
110
  { status: 200, headers: { "Content-Type": "application/json" } },
111
111
  );
@@ -121,7 +121,7 @@ describe("OAuth keepalive", () => {
121
121
 
122
122
  await Promise.resolve();
123
123
  expect(stopResolved).toBe(false);
124
- expect((await getOAuthTokens("jira"))?.refreshToken).toBe("old-jira-refresh");
124
+ expect((await getOAuthTokens("jira"))?.refreshToken).toBe("example-old-jira-refresh");
125
125
 
126
126
  releaseTokenResponse();
127
127
  await stopPromise;
@@ -129,7 +129,7 @@ describe("OAuth keepalive", () => {
129
129
 
130
130
  expect(stopResolved).toBe(true);
131
131
  const tokens = await getOAuthTokens("jira");
132
- expect(tokens?.accessToken).toBe("new-jira-access");
133
- expect(tokens?.refreshToken).toBe("new-jira-refresh");
132
+ expect(tokens?.accessToken).toBe("example-new-jira-access");
133
+ expect(tokens?.refreshToken).toBe("example-new-jira-refresh");
134
134
  });
135
135
  });