@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
@@ -6,6 +6,7 @@ import {
6
6
  completeTask,
7
7
  createAgent,
8
8
  createLogEntry,
9
+ createScheduledTask,
9
10
  createTaskExtended,
10
11
  ensureSlackDelegationActivation,
11
12
  ensureSlackRenderV2Activation,
@@ -19,12 +20,14 @@ import {
19
20
  getSlackTreeMessages,
20
21
  getTaskById,
21
22
  initDb,
23
+ insertTaskAttachment,
22
24
  isPendingSlackMessage,
23
25
  markTaskSlackReplySent,
24
26
  startTask,
25
27
  supersedeTask,
26
28
  upsertSwarmConfig,
27
29
  } from "../be/db";
30
+ import { createStandaloneScheduleTask } from "../scheduler/schedule-task";
28
31
  import { getTaskLink, MAX_SECTION_LENGTH } from "../slack/blocks";
29
32
  import {
30
33
  _resetSlackRenderV2ForTests,
@@ -39,7 +42,7 @@ import {
39
42
  } from "../slack/render-v2";
40
43
  import { getAgentDisplayName, getAgentEmoji } from "../slack/responses";
41
44
  import { slackContextKey } from "../tasks/context-key";
42
- import type { AgentTask } from "../types";
45
+ import type { AgentTask, TaskAttachment } from "../types";
43
46
  import { clearVolatileSecretsForTesting } from "../utils/secret-scrubber";
44
47
 
45
48
  const TEST_DB_PATH = "./test-slack-render-v2.sqlite";
@@ -299,12 +302,83 @@ describe("Slack renderer v2", () => {
299
302
  });
300
303
  });
301
304
 
302
- test("defaults off and accepts an explicit opt-in", () => {
305
+ for (const delegationEnabled of [false, true]) {
306
+ test(`relays a deferred schedule continuation with delegation=${delegationEnabled}`, async () => {
307
+ process.env.SLACK_RENDER_V2_DELEGATION = String(delegationEnabled);
308
+ if (delegationEnabled) await ensureSlackDelegationActivation();
309
+ const lead = await createAgent({ name: "Continuation Lead", isLead: true, status: "idle" });
310
+ const { channelId, threadTs } = uniqueSlackAddress("C_CONTINUATION");
311
+ const ask = await createTaskExtended("answer when ready", {
312
+ agentId: lead.id,
313
+ source: "slack",
314
+ slackChannelId: channelId,
315
+ slackThreadTs: threadTs,
316
+ contextKey: slackContextKey({ channelId, threadTs }),
317
+ });
318
+ await startTask(ask.id);
319
+ await completeTask(ask.id, "Waiting for the result.", { addTags: ["deferred"] });
320
+ await backdateLastUpdated([ask.id], 20);
321
+ await processSlackRenderV2();
322
+ expect((await getSlackOutcomeMessage(ask.id))?.finalizedAt).toBeTruthy();
323
+
324
+ const schedule = await createScheduledTask({
325
+ name: "deferred-answer",
326
+ scheduleType: "one_time",
327
+ taskTemplate: "Deliver the result",
328
+ taskType: "deferred",
329
+ tags: ["deferred"],
330
+ parentTaskId: ask.id,
331
+ targetAgentId: lead.id,
332
+ createdByAgentId: lead.id,
333
+ nextRunAt: new Date().toISOString(),
334
+ });
335
+ const continuation = await createStandaloneScheduleTask(schedule);
336
+ expect(continuation.source).toBe("schedule");
337
+ expect(continuation.scheduleId).toBe(schedule.id);
338
+ expect(continuation.slackChannelId).toBe(channelId);
339
+ expect(continuation.slackThreadTs).toBe(threadTs);
340
+ await startTask(continuation.id);
341
+ await processSlackRenderV2();
342
+ expect(await getSlackOutcomeMessage(continuation.id)).toBeNull();
343
+ await completeTask(continuation.id, "Here is the complete answer.");
344
+ calls.length = 0;
345
+
346
+ await processSlackRenderV2();
347
+ await processSlackRenderV2();
348
+
349
+ expect((await getSlackOutcomeMessage(continuation.id))?.finalizedAt).toBeTruthy();
350
+ const streams = calls.filter((call) => call.method === "chat.startStream");
351
+ expect(streams).toHaveLength(1);
352
+ expect(streams[0]?.payload).toMatchObject({
353
+ channel: channelId,
354
+ thread_ts: threadTs,
355
+ markdown_text: "✅\n\nHere is the complete answer.",
356
+ });
357
+ });
358
+ }
359
+
360
+ test("does not relay an ordinary scheduled task without Slack context", async () => {
361
+ const schedule = await createScheduledTask({
362
+ name: "ordinary-maintenance",
363
+ scheduleType: "one_time",
364
+ taskTemplate: "Run maintenance",
365
+ taskType: "maintenance",
366
+ nextRunAt: new Date().toISOString(),
367
+ });
368
+ const task = await createStandaloneScheduleTask(schedule);
369
+ await startTask(task.id);
370
+ await completeTask(task.id, "Maintenance completed.");
371
+ await processSlackRenderV2();
372
+ expect(await getSlackOutcomeMessage(task.id)).toBeNull();
373
+ expect(calls).toHaveLength(0);
374
+ });
375
+
376
+ test("defaults on and accepts an explicit opt-out", () => {
303
377
  const previous = process.env.SLACK_RENDER_V2;
304
378
  delete process.env.SLACK_RENDER_V2;
305
- expect(isSlackRenderV2Enabled()).toBe(false);
306
- process.env.SLACK_RENDER_V2 = "true";
307
379
  expect(isSlackRenderV2Enabled()).toBe(true);
380
+ process.env.SLACK_RENDER_V2 = "false";
381
+ expect(isSlackRenderV2Enabled()).toBe(false);
308
382
  if (previous === undefined) delete process.env.SLACK_RENDER_V2;
309
383
  else process.env.SLACK_RENDER_V2 = previous;
310
384
  });
@@ -1183,6 +1257,95 @@ describe("Slack renderer v2", () => {
1183
1257
  expect(calls.some((call) => call.method === "chat.appendStream")).toBe(false);
1184
1258
  });
1185
1259
 
1260
+ test.each<{
1261
+ label: string;
1262
+ attachment: Partial<TaskAttachment> & Pick<TaskAttachment, "kind" | "name">;
1263
+ expected: string;
1264
+ }>([
1265
+ {
1266
+ label: "plain ASCII positive control",
1267
+ attachment: { kind: "agent-fs", name: "report.txt", path: "/reports/report.txt" },
1268
+ expected:
1269
+ "📎 [report.txt](https://files.example.test/file/~/org-1/drive-1/reports/report.txt)",
1270
+ },
1271
+ {
1272
+ label: "raw path spaces and parentheses",
1273
+ attachment: { kind: "agent-fs", name: "final report", path: "/shared reports/final (v1).md" },
1274
+ expected:
1275
+ "📎 [final report](https://files.example.test/file/~/org-1/drive-1/shared%20reports/final%20%28v1%29.md)",
1276
+ },
1277
+ {
1278
+ label: "already encoded positive control",
1279
+ attachment: { kind: "agent-fs", name: "report", path: "/reports/final%20%28v1%29.md" },
1280
+ expected:
1281
+ "📎 [report](https://files.example.test/file/~/org-1/drive-1/reports/final%20%28v1%29.md)",
1282
+ },
1283
+ {
1284
+ label: "label delimiters, backslashes, and whitespace",
1285
+ attachment: {
1286
+ kind: "url",
1287
+ name: " \t[report] (final)\\\r\n\t copy ",
1288
+ url: "https://example.test/report",
1289
+ },
1290
+ expected: "📎 [\\[report\\] \\(final\\)\\\\ copy](https://example.test/report)",
1291
+ },
1292
+ {
1293
+ label: "URL positive control with an IPv6 host",
1294
+ attachment: { kind: "url", name: "report", url: "http://[::1]/report.txt?q=a%20b&x=1#part" },
1295
+ expected: "📎 [report](http://[::1]/report.txt?q=a%20b&x=1#part)",
1296
+ },
1297
+ {
1298
+ label: "URL delimiters with existing escapes and query parameters",
1299
+ attachment: {
1300
+ kind: "url",
1301
+ name: "report",
1302
+ url: "https://example.test/a%20b) [c]<(d)>\\file?q=one two&x=1#part",
1303
+ },
1304
+ expected:
1305
+ "📎 [report](https://example.test/a%20b%29%20[c]%3C%28d%29%3E%5Cfile?q=one%20two&x=1#part)",
1306
+ },
1307
+ {
1308
+ label: "non-HTTP fallback stays omitted",
1309
+ attachment: { kind: "url", name: "report", url: "agent-fs:/reports/report.md" },
1310
+ expected: "",
1311
+ },
1312
+ ])("streams safe attachment Markdown: $label", async ({ attachment, expected }) => {
1313
+ const originalHost = process.env.AGENT_FS_LIVE_URL;
1314
+ process.env.AGENT_FS_LIVE_URL = "https://files.example.test";
1315
+ try {
1316
+ const lead = await createAgent({ name: "Attachment Lead", isLead: true, status: "idle" });
1317
+ const { channelId, threadTs } = uniqueSlackAddress("C_OUTCOME_ATTACHMENT");
1318
+ const ask = await createTaskExtended("render attachment link", {
1319
+ agentId: lead.id,
1320
+ source: "slack",
1321
+ slackChannelId: channelId,
1322
+ slackThreadTs: threadTs,
1323
+ contextKey: slackContextKey({ channelId, threadTs }),
1324
+ });
1325
+ await insertTaskAttachment({
1326
+ ...attachment,
1327
+ taskId: ask.id,
1328
+ agentId: lead.id,
1329
+ orgId: "org-1",
1330
+ driveId: "drive-1",
1331
+ isPrimary: true,
1332
+ });
1333
+ await startTask(ask.id);
1334
+ await ensureSlackThreadTree([ask.id]);
1335
+ await completeTask(ask.id, "Done");
1336
+ calls.length = 0;
1337
+ _resetSlackRenderV2ForTests();
1338
+
1339
+ await processSlackRenderV2();
1340
+
1341
+ const started = calls.find((call) => call.method === "chat.startStream");
1342
+ expect(started?.payload.markdown_text).toBe(`✅\n\nDone${expected ? `\n\n${expected}` : ""}`);
1343
+ } finally {
1344
+ if (originalHost === undefined) delete process.env.AGENT_FS_LIVE_URL;
1345
+ else process.env.AGENT_FS_LIVE_URL = originalHost;
1346
+ }
1347
+ });
1348
+
1186
1349
  test("truncates oversized Markdown before a code fence and links the full task", async () => {
1187
1350
  const lead = await createAgent({ name: "Overflow Lead", isLead: true, status: "idle" });
1188
1351
  const { channelId, threadTs } = uniqueSlackAddress("C_OUTCOME_OVERFLOW");
@@ -1626,6 +1789,35 @@ describe("Slack renderer v2", () => {
1626
1789
  expect(outcome?.finalizedAt).toBeDefined();
1627
1790
  });
1628
1791
 
1792
+ test("keeps a deferral's human-facing line even when the agent already sent a slack-reply", async () => {
1793
+ const lead = await createAgent({ name: "Deferring Lead", isLead: true, status: "idle" });
1794
+ const { channelId, threadTs } = uniqueSlackAddress("C_RENDER_DEFER_AFTER_REPLY");
1795
+ const ask = await createTaskExtended("defer after replying by hand", {
1796
+ agentId: lead.id,
1797
+ source: "slack",
1798
+ slackChannelId: channelId,
1799
+ slackThreadTs: threadTs,
1800
+ contextKey: slackContextKey({ channelId, threadTs }),
1801
+ });
1802
+ await startTask(ask.id);
1803
+ await ensureSlackThreadTree([ask.id]);
1804
+ // Agent posts a hand-written slack-reply first (e.g. a transcription),
1805
+ // then defer-task completes the task with the engine-authored deferral
1806
+ // line and tags it "deferred" (mirrors defer-task.ts's completeTask call).
1807
+ await markTaskSlackReplySent(ask.id);
1808
+ const deferralLine =
1809
+ "Deferred until today 17:30:19 UTC ([715bf847](https://app.agent-swarm.dev/schedules/715bf847-fe3e-40e9-9fef-3297a62d9afd)) -> checking the new defer card";
1810
+ await completeTask(ask.id, deferralLine, { addTags: ["deferred"] });
1811
+ calls.length = 0;
1812
+ _resetSlackRenderV2ForTests();
1813
+
1814
+ await processSlackRenderV2();
1815
+
1816
+ const started = calls.find((call) => call.method === "chat.startStream");
1817
+ expect(started?.payload.markdown_text).toBe(`✅\n\n${deferralLine}`);
1818
+ expect(started?.payload.markdown_text).not.toBe(`✅ ${lead.name} completed`);
1819
+ });
1820
+
1629
1821
  test("refreshes a stream started with stale content before finalizing it", async () => {
1630
1822
  const lead = await createAgent({ name: "Refresh Lead", isLead: true, status: "idle" });
1631
1823
  const { channelId, threadTs } = uniqueSlackAddress("C_RENDER_REFRESH_STALE");
@@ -1,7 +1,7 @@
1
1
  import { afterAll, beforeAll, describe, expect, test } from "bun:test";
2
2
  import { unlinkSync } from "node:fs";
3
- import { closeDb, createAgent, createTaskExtended, initDb } from "../be/db";
4
- import { routeMessage } from "../slack/router";
3
+ import { closeDb, createAgent, createTaskExtended, getAllAgents, initDb } from "../be/db";
4
+ import { broadcastMatches, routeMessage } from "../slack/router";
5
5
  import type { Agent } from "../types";
6
6
 
7
7
  const TEST_DB_PATH = "./test-slack-router.sqlite";
@@ -169,6 +169,21 @@ describe("Slack router — thread follow-up routing", () => {
169
169
  // Lead should not be in the matches
170
170
  expect(matches.every((m) => !m.agent.isLead)).toBe(true);
171
171
  });
172
+
173
+ test("swarm#all includes offline non-lead agents", async () => {
174
+ const offlineWorker = await createAgent({
175
+ name: "offline-broadcast-worker",
176
+ isLead: false,
177
+ status: "offline",
178
+ capabilities: [],
179
+ });
180
+
181
+ const matches = broadcastMatches(await getAllAgents());
182
+
183
+ expect(matches.map((match) => match.agent.id)).toContain(offlineWorker.id);
184
+ expect(matches.every((match) => !match.agent.isLead)).toBe(true);
185
+ expect(matches.every((match) => match.matchedText === "swarm#all")).toBe(true);
186
+ });
172
187
  });
173
188
 
174
189
  describe("no thread context behaves normally", () => {
@@ -105,6 +105,25 @@ describe("Slack thread steering", () => {
105
105
  expect(await getChildTasks(leadTask.id)).toHaveLength(1);
106
106
  });
107
107
 
108
+ test("unset configuration steers the lead with queued delivery", async () => {
109
+ delete process.env.SLACK_THREAD_STEERING;
110
+ delete process.env.SLACK_THREAD_STEERING_MODE;
111
+ const channelId = "C_DEFAULT_STEER";
112
+ const threadTs = "1500.0001";
113
+ const task = await createRunningSlackTask(leadId, channelId, threadTs);
114
+ const result = await requestSlackThreadSteering({
115
+ channelId,
116
+ threadTs,
117
+ message: "new context",
118
+ });
119
+ expect(result).toMatchObject({
120
+ task: { id: task.id },
121
+ result: { outcome: "queued", effectiveMode: "queue" },
122
+ });
123
+ expect(await getSteeringMessagesForTask(task.id)).toHaveLength(1);
124
+ expect(await getChildTasks(task.id)).toEqual([]);
125
+ });
126
+
108
127
  test("lead mode sends one steering message to an in-progress lead and creates no task", async () => {
109
128
  process.env.SLACK_THREAD_STEERING = "lead";
110
129
  process.env.SLACK_THREAD_STEERING_MODE = "steer";
@@ -31,6 +31,7 @@ import {
31
31
  updateAgentCredStatus,
32
32
  } from "../be/db";
33
33
  import { storeOAuthTokens, upsertOAuthApp } from "../be/db-queries/oauth";
34
+ import { resetEmbeddingProvider } from "../be/memory";
34
35
  import { validateProviderCredentials } from "../commands/provider-credentials";
35
36
  import {
36
37
  _resetTestConnectionCache,
@@ -123,6 +124,11 @@ function clearEnv() {
123
124
  for (const k of ENV_KEYS_TO_RESET) {
124
125
  delete process.env[k];
125
126
  }
127
+ // The embedding provider memoizes its API key at construction (see
128
+ // OpenAIEmbeddingProvider); reset the singleton so embeddingsMilestone()
129
+ // (which now reads the live provider, not process.env directly) reflects
130
+ // whatever this test just set/cleared instead of a stale prior test's key.
131
+ resetEmbeddingProvider();
126
132
  }
127
133
 
128
134
  function restoreEnv() {
@@ -245,14 +251,20 @@ describe("setup milestones", () => {
245
251
  hint: "Memory search is off. Set OPENAI_API_KEY (or EMBEDDING_API_KEY) on the API server to enable it; it is cheap.",
246
252
  });
247
253
 
248
- process.env.OPENAI_API_KEY = "openai-embedding-key";
254
+ // The provider memoizes its API key at construction; in production a
255
+ // config reload resets it (see resetEmbeddingProvider in src/http/core.ts).
256
+ // Mirror that here after each direct env mutation.
257
+ process.env.OPENAI_API_KEY = "example-openai-embedding-key";
258
+ resetEmbeddingProvider();
249
259
  expect(getMilestone(await buildStatusPayload(), "embeddings").state).toBe("configured");
250
260
 
251
261
  process.env.EMBEDDING_API_KEY = "";
262
+ resetEmbeddingProvider();
252
263
  expect(getMilestone(await buildStatusPayload(), "embeddings").state).toBe("unverified");
253
264
 
254
- process.env.EMBEDDING_API_KEY = "dedicated-embedding-key";
265
+ process.env.EMBEDDING_API_KEY = "example-dedicated-embedding-key";
255
266
  delete process.env.OPENAI_API_KEY;
267
+ resetEmbeddingProvider();
256
268
  expect(getMilestone(await buildStatusPayload(), "embeddings").state).toBe("configured");
257
269
  });
258
270
 
@@ -417,7 +429,7 @@ describe("setup milestones", () => {
417
429
  const a = await buildStatusPayload();
418
430
  expect(getMilestone(a, "github").state).toBe("unverified");
419
431
 
420
- process.env.GITHUB_APP_PRIVATE_KEY = "-----BEGIN PRIVATE KEY-----\n...";
432
+ process.env.GITHUB_APP_PRIVATE_KEY = "[REDACTED:github_app_private_key]";
421
433
  const b = await buildStatusPayload();
422
434
  expect(getMilestone(b, "github").state).toBe("verified");
423
435
  });
@@ -456,7 +468,7 @@ describe("setup milestones", () => {
456
468
  scopes: "read",
457
469
  });
458
470
  await storeOAuthTokens("linear", {
459
- accessToken: "lin-tok-xyz",
471
+ accessToken: "example-lin-tok-xyz",
460
472
  refreshToken: "ref",
461
473
  expiresAt: new Date(Date.now() + 3600_000).toISOString(),
462
474
  scope: "read",
@@ -475,7 +487,7 @@ describe("setup milestones", () => {
475
487
  // metadata intentionally omitted on first upsert
476
488
  });
477
489
  await storeOAuthTokens("jira", {
478
- accessToken: "jira-tok",
490
+ accessToken: "example-jira-tok",
479
491
  refreshToken: null,
480
492
  expiresAt: new Date(Date.now() + 3600_000).toISOString(),
481
493
  scope: null,
@@ -831,7 +843,7 @@ describe("validateProviderCredentials — error scrubbing", () => {
831
843
  });
832
844
 
833
845
  test("devin hits v3/self (not the deprecated v1 endpoint) and passes on 2xx", async () => {
834
- process.env.DEVIN_API_KEY = "cog_fake-devin-key-1234";
846
+ process.env.DEVIN_API_KEY = "example-cog_fake-devin-key-1234";
835
847
  let capturedUrl = "";
836
848
  globalThis.fetch = (async (url) => {
837
849
  capturedUrl = String(url);
@@ -851,7 +863,7 @@ describe("validateProviderCredentials — error scrubbing", () => {
851
863
  });
852
864
 
853
865
  test("scrubs api key from error message on 401 response", async () => {
854
- const fakeKey = "sk-ant-fakekey-DO-NOT-LEAK-1234567890abcdef";
866
+ const fakeKey = "example-anthropic-key-do-not-leak";
855
867
  process.env.ANTHROPIC_API_KEY = fakeKey;
856
868
  globalThis.fetch = (async () =>
857
869
  new Response(`Unauthorized: invalid key ${fakeKey}`, {
@@ -413,7 +413,7 @@ describe("task steering core", () => {
413
413
 
414
414
  test("scrubs secrets before persisting the steering body", async () => {
415
415
  const previous = process.env.OPENAI_API_KEY;
416
- const secret = "sk-proj-steering-secret-value-1234567890";
416
+ const secret = "example-steering-secret-value";
417
417
  process.env.OPENAI_API_KEY = secret;
418
418
  try {
419
419
  const task = await runningTask("pi", "secret scrubbing");
@@ -48,12 +48,11 @@ function restoreEnv(name: string, value: string | undefined): void {
48
48
  }
49
49
 
50
50
  /**
51
- * Steering is opt-in (disabled unless STEERING_ENABLED=true|1), so "disabled"
52
- * is simply the default: unset the flag for the duration of the callback.
51
+ * Exercise an explicit opt-out without depending on the deployment default.
53
52
  */
54
53
  async function withSteeringDisabled<T>(run: () => Promise<T> | T): Promise<T> {
55
54
  const previous = process.env.STEERING_ENABLED;
56
- delete process.env.STEERING_ENABLED;
55
+ process.env.STEERING_ENABLED = "false";
57
56
  try {
58
57
  return await run();
59
58
  } finally {
@@ -116,8 +115,7 @@ async function api(
116
115
  const originalSteeringEnabled = process.env.STEERING_ENABLED;
117
116
 
118
117
  beforeAll(async () => {
119
- // The "enabled" halves of these tests opt in explicitly (steering is off by
120
- // default); withSteeringDisabled() drops the flag to exercise the default.
118
+ // Pin both branches explicitly so inherited configuration cannot affect them.
121
119
  process.env.STEERING_ENABLED = "true";
122
120
  await removeTestDb();
123
121
  process.env.DATABASE_PATH = TEST_DB_PATH;
@@ -147,9 +145,9 @@ afterAll(async () => {
147
145
  await removeTestDb();
148
146
  });
149
147
 
150
- describe("STEERING_ENABLED opt-in", () => {
151
- test("steering is disabled by default (flag unset) and on falsy values", () => {
152
- expect(isSteeringEnabled({})).toBe(false);
148
+ describe("STEERING_ENABLED defaults and overrides", () => {
149
+ test("steering defaults on and accepts explicit opt-outs", () => {
150
+ expect(isSteeringEnabled({})).toBe(true);
153
151
  expect(isSteeringEnabled({ STEERING_ENABLED: "false" })).toBe(false);
154
152
  expect(isSteeringEnabled({ STEERING_ENABLED: "0" })).toBe(false);
155
153
  expect(isSteeringEnabled({ STEERING_ENABLED: "true" })).toBe(true);
@@ -233,7 +233,7 @@ describe("steering worker transport", () => {
233
233
 
234
234
  test("scrubs provider errors before reporting an undeliverable reason", async () => {
235
235
  const pending = pendingMessage();
236
- const secret = "sk-proj-steering-transport-secret-1234567890";
236
+ const secret = `sk-proj-${"steering".repeat(4)}`;
237
237
  let reportedBody = "";
238
238
  const fetchImpl = (async (input: string | URL | Request, init?: RequestInit) => {
239
239
  if (String(input).includes("/api/steering-messages?")) {
@@ -280,7 +280,7 @@ describe("steering worker transport", () => {
280
280
  expect(requested.outcome).toBe("queued");
281
281
 
282
282
  await pollAndDispatchSteering(
283
- { apiUrl: baseUrl, apiKey: "test-key", agentId: agent.id },
283
+ { apiUrl: baseUrl, apiKey: "example-test-key", agentId: agent.id },
284
284
  task.id,
285
285
  session(),
286
286
  createSteeringDispatchState(),
@@ -327,7 +327,7 @@ describe("steering worker transport", () => {
327
327
  // undeliverable — but the external-delivery flag short-circuits the poll.
328
328
  const codexLikeSession = { ...session(), steeringDeliveredExternally: true };
329
329
  await pollAndDispatchSteering(
330
- { apiUrl: baseUrl, apiKey: "test-key", agentId: agent.id },
330
+ { apiUrl: baseUrl, apiKey: "example-test-key", agentId: agent.id },
331
331
  task.id,
332
332
  codexLikeSession,
333
333
  createSteeringDispatchState(),
@@ -343,7 +343,7 @@ describe("steering worker transport", () => {
343
343
  const previousBaseUrl = process.env.MCP_BASE_URL;
344
344
  const previousApiKey = process.env.AGENT_SWARM_API_KEY;
345
345
  process.env.MCP_BASE_URL = baseUrl;
346
- process.env.AGENT_SWARM_API_KEY = "test-key";
346
+ process.env.AGENT_SWARM_API_KEY = "example-test-key";
347
347
  try {
348
348
  const agent = await createAgent({
349
349
  name: "accept steering worker",
@@ -0,0 +1,34 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import type * as z from "zod";
4
+ import { registerStoreProgressTool } from "../tools/store-progress";
5
+
6
+ describe("store-progress output guidance", () => {
7
+ const server = new McpServer({ name: "output-guidance-test", version: "1.0.0" });
8
+ registerStoreProgressTool(server);
9
+ const tools = (
10
+ server as unknown as {
11
+ _registeredTools: Record<string, { inputSchema: z.ZodObject }>;
12
+ }
13
+ )._registeredTools;
14
+ const outputSchema = tools["store-progress"].inputSchema.shape.output;
15
+
16
+ test("the exposed output field carries the same budget and exceptions as the prompts", () => {
17
+ expect(outputSchema.description).toContain("Keep free-text output under 120 words by default");
18
+ expect(outputSchema.description).toContain("published verbatim in the thread's outcome card");
19
+ expect(outputSchema.description).toContain("every artifact link");
20
+ expect(outputSchema.description).toContain("Link documents instead of inlining them");
21
+ expect(outputSchema.description).toContain(
22
+ "requested depth, enumerated results, essential evidence",
23
+ );
24
+ expect(outputSchema.description).toContain("the task's outputSchema requires longer output");
25
+ expect(outputSchema.description).toContain("output must be JSON matching it");
26
+ });
27
+
28
+ test("the style target does not reject longer requested or schema-constrained output", () => {
29
+ const longResult = "Required result. ".repeat(150);
30
+ for (const output of [longResult, JSON.stringify({ results: [longResult] })]) {
31
+ expect(outputSchema.parse(output)).toBe(output);
32
+ }
33
+ });
34
+ });
@@ -111,38 +111,38 @@ describe("finalizeSwarmToolResult", () => {
111
111
  });
112
112
 
113
113
  test("secrets are scrubbed from message, details, and data at the egress point", async () => {
114
- registerVolatileSecret("sk-super-secret-token-123", "TEST_TOKEN");
114
+ registerVolatileSecret("example-sk-super-secret-token-123", "TEST_TOKEN");
115
115
  try {
116
116
  const result = await finalizeSwarmToolResult("some-tool", {
117
117
  ok: false,
118
- message: "Auth failed with sk-super-secret-token-123",
119
- details: "header was sk-super-secret-token-123",
120
- data: { token: "sk-super-secret-token-123" },
118
+ message: "Auth failed with example-sk-super-secret-token-123",
119
+ details: "header was example-sk-super-secret-token-123",
120
+ data: { token: "example-sk-super-secret-token-123" },
121
121
  });
122
122
  const serialized = JSON.stringify(result);
123
- expect(serialized).not.toContain("sk-super-secret-token-123");
123
+ expect(serialized).not.toContain("example-sk-super-secret-token-123");
124
124
  } finally {
125
125
  clearVolatileSecretsForTesting();
126
126
  }
127
127
  });
128
128
 
129
129
  test("allowSecretEgress skips scrubbing for deliberate credential reveals only", async () => {
130
- registerVolatileSecret("xsk_reveal_me_once_456", "TEST_REVEAL");
130
+ registerVolatileSecret("example-xsk_reveal_me_once_456", "TEST_REVEAL");
131
131
  try {
132
132
  const revealed = await finalizeSwarmToolResult("script-apis", {
133
133
  ok: true,
134
134
  message: "Endpoint created.",
135
- details: "Bearer token (shown once — save it now): xsk_reveal_me_once_456",
136
- data: { token: "xsk_reveal_me_once_456" },
135
+ details: "Bearer token (shown once — save it now): example-xsk_reveal_me_once_456",
136
+ data: { token: "example-xsk_reveal_me_once_456" },
137
137
  allowSecretEgress: true,
138
138
  });
139
- expect(JSON.stringify(revealed)).toContain("xsk_reveal_me_once_456");
139
+ expect(JSON.stringify(revealed)).toContain("example-xsk_reveal_me_once_456");
140
140
 
141
141
  const scrubbed = await finalizeSwarmToolResult("some-tool", {
142
142
  ok: true,
143
- message: "leaky xsk_reveal_me_once_456",
143
+ message: "leaky example-xsk_reveal_me_once_456",
144
144
  });
145
- expect(JSON.stringify(scrubbed)).not.toContain("xsk_reveal_me_once_456");
145
+ expect(JSON.stringify(scrubbed)).not.toContain("example-xsk_reveal_me_once_456");
146
146
  } finally {
147
147
  clearVolatileSecretsForTesting();
148
148
  }
@@ -36,12 +36,14 @@ afterEach(() => {
36
36
 
37
37
  describe("swarm_x MCP tool", () => {
38
38
  test("routes composio requests with server-side auth and scrubbed output", async () => {
39
- process.env.COMPOSIO_API_KEY = "ck_tool_secret_value";
39
+ process.env.COMPOSIO_API_KEY = "example-ck_tool_secret_value";
40
40
  const fetchMock = mock(async (url: string | URL | Request, init?: RequestInit) => {
41
41
  expect(String(url)).toBe("https://backend.composio.dev/api/v3.1/tools?limit=1");
42
42
  expect(init?.method).toBe("GET");
43
- expect((init?.headers as Record<string, string>)["x-api-key"]).toBe("ck_tool_secret_value");
44
- return jsonResponse({ ok: true, token: "ck_tool_secret_value" });
43
+ expect((init?.headers as Record<string, string>)["x-api-key"]).toBe(
44
+ "example-ck_tool_secret_value",
45
+ );
46
+ return jsonResponse({ ok: true, token: "example-ck_tool_secret_value" });
45
47
  });
46
48
  globalThis.fetch = fetchMock;
47
49
 
@@ -65,11 +67,11 @@ describe("swarm_x MCP tool", () => {
65
67
  expect(JSON.stringify(result.structuredContent.response)).toContain(
66
68
  "[REDACTED:COMPOSIO_API_KEY]",
67
69
  );
68
- expect(result.structuredContent.responseText).not.toContain("ck_tool_secret_value");
70
+ expect(result.structuredContent.responseText).not.toContain("example-ck_tool_secret_value");
69
71
  });
70
72
 
71
73
  test("rejects absolute composio paths", async () => {
72
- process.env.COMPOSIO_API_KEY = "ck_tool_secret_value";
74
+ process.env.COMPOSIO_API_KEY = "example-ck_tool_secret_value";
73
75
  const fetchMock = mock(async () => jsonResponse({ ok: true }));
74
76
  globalThis.fetch = fetchMock;
75
77
 
@@ -10,6 +10,7 @@ import {
10
10
  type Manifest,
11
11
  type PathRewrite,
12
12
  parseSkillMd,
13
+ rewriteBundledFileComments,
13
14
  rewriteSkillReferences,
14
15
  sanitizeSyncedVia,
15
16
  stableJson,
@@ -215,6 +216,24 @@ describe("ai-toolbox skill sync pure transforms", () => {
215
216
  ).toThrow("exceed 10485760 bytes total");
216
217
  });
217
218
 
219
+ test("clarifies only the Codex helper comment and preserves executable sandbox settings", () => {
220
+ const comment =
221
+ "# CODEX_SANDBOX default: workspace-write read-only | workspace-write | danger-full-access";
222
+ const executable = `SANDBOX="\${CODEX_SANDBOX:-workspace-write}"\nargs+=( --dangerously-bypass-approvals-and-sandbox )\n`;
223
+ const source = `${comment}\n${executable}`;
224
+ expect(rewriteBundledFileComments("delegate-work", "scripts/codex-exec.sh", source)).toBe(
225
+ `# CODEX_SANDBOX default: workspace-write (passed to codex's -s option)\n${executable}`,
226
+ );
227
+ expect(rewriteBundledFileComments("other", "scripts/codex-exec.sh", source)).toBe(source);
228
+ expect(rewriteBundledFileComments("delegate-work", "scripts/other.sh", source)).toBe(source);
229
+ expect(() =>
230
+ rewriteBundledFileComments("delegate-work", "scripts/codex-exec.sh", executable),
231
+ ).toThrow("expected one upstream sandbox default comment");
232
+ expect(() =>
233
+ rewriteBundledFileComments("delegate-work", "scripts/codex-exec.sh", `${comment}\n${source}`),
234
+ ).toThrow("expected one upstream sandbox default comment");
235
+ });
236
+
218
237
  test("reports executable text downgrades and rejects binary files", () => {
219
238
  const executable = validateBundledFileBytes(
220
239
  "fixture",
@@ -645,7 +645,7 @@ describe("Task Supersede + Resume", () => {
645
645
  test("scrubs secret-shaped values from session-log summaries", async () => {
646
646
  // GitHub PAT-shaped token — matches a structural pattern in
647
647
  // scrubSecrets (regardless of env state).
648
- const fakeToken = "ghp_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
648
+ const fakeToken = `ghp_${"a".repeat(36)}`;
649
649
  mockSessionLogs = [
650
650
  {
651
651
  createdAt: new Date().toISOString(),
@@ -73,11 +73,14 @@ async function pins(client: Client): Promise<string[]> {
73
73
  .sort();
74
74
  }
75
75
 
76
- test("wire response is default-off, per-task, additive, and fixed for one MCP session", async () => {
76
+ test("wire response is default-on, per-task, additive, and fixed for one MCP session", async () => {
77
77
  const task = await createTaskExtended("review fixture", { agentId, taskType: "review" });
78
78
  const other = await createTaskExtended("other fixture", { agentId, taskType: "other" });
79
79
  const foreign = await createTaskExtended("unowned", { taskType: "review" });
80
80
  await configure("TASK_TOOL_MANIFESTS", '{"taskTypes":{"review":["script-run","get-tasks"]}}');
81
+ const defaultOn = await connect(task.id);
82
+ expect(await pins(defaultOn)).toEqual(["get-tasks", "script-run"]);
83
+ await configure("TASK_TOOL_PRELOAD_ENABLED", "false");
81
84
  const off = await connect(task.id);
82
85
  const baseline = (await off.listTools()).tools;
83
86
  expect(baseline.some((tool) => tool.name === "script-run")).toBe(true);