@desplega.ai/agent-swarm 1.131.1 → 1.134.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.
- package/README.md +3 -3
- package/dist/{actions-jgcy477k.js → actions-7kast243.js} +20 -18
- package/dist/{anthropic-messages-rjmd2e7n.js → anthropic-messages-706yad38.js} +33 -17
- package/dist/app-0g84t8wf.js +28 -0
- package/dist/{artifact-jysj3wrg.js → artifact-dje5ke4h.js} +37 -131
- package/dist/{assistant-f2vkk1hj.js → assistant-ac4htcky.js} +25 -22
- package/dist/{azure-openai-responses-c0yjmbfd.js → azure-openai-responses-be59fbsz.js} +13 -13
- package/dist/{boot-reembed-q7mp8hcr.js → boot-reembed-b1rcqn85.js} +13 -11
- package/dist/{boot-reembed-xmw8wcx6.js → boot-reembed-kw2541c4.js} +14 -12
- package/dist/{boot-scrub-logs-dsqrv79n.js → boot-scrub-logs-ja29t92g.js} +11 -9
- package/dist/{claude-adapter-q6x7yspx.js → claude-adapter-5cg1fv8s.js} +33 -29
- package/dist/{claude-managed-adapter-wsg37bt8.js → claude-managed-adapter-9z9sdytx.js} +9 -9
- package/dist/{claude-managed-setup-52z4mq9w.js → claude-managed-setup-3zqp51cr.js} +5 -5
- package/dist/{claude-1ex232fc.js → claude-wqn3dtca.js} +1 -1
- package/dist/{cli-4wgngmwv.js → cli-00w4hbam.js} +1 -1
- package/dist/{cli-er3a4bb0.js → cli-15429qdw.js} +6 -1
- package/dist/{cli-e5dabkx0.js → cli-1cwhyvta.js} +4 -4
- package/dist/{cli-zsspvvm2.js → cli-1ybr6vw2.js} +237 -237
- package/dist/{cli-xpxde7rm.js → cli-2wv4kj0e.js} +60 -31
- package/dist/cli-34w2584r.js +530 -0
- package/dist/{cli-se2p6rkb.js → cli-38taxznr.js} +6 -6
- package/dist/{cli-9sbhdpvb.js → cli-3cgfyfzm.js} +14 -14
- package/dist/{cli-5n6e5yfn.js → cli-3zmdzfjf.js} +79 -74
- package/dist/{cli-3ty0t082.js → cli-43x36mty.js} +197 -8
- package/dist/{cli-ycrnynpw.js → cli-480nehnh.js} +29 -22
- package/dist/{cli-0258203w.js → cli-492e7ap5.js} +140 -20
- package/dist/{cli-3fj60etf.js → cli-497b685t.js} +3 -3
- package/dist/{cli-pxfxkx5m.js → cli-4bap00k0.js} +1 -1
- package/dist/{cli-w2wxd56v.js → cli-4bc8vmhm.js} +848 -770
- package/dist/{cli-aca5pz9f.js → cli-589599p9.js} +1 -1
- package/dist/{cli-t930g0xh.js → cli-5tnr64pm.js} +1 -1
- package/dist/{cli-jxg3s9ey.js → cli-65d93ves.js} +7 -7
- package/dist/{cli-6dpytdr2.js → cli-6x363v1z.js} +2 -2
- package/dist/{cli-dxak0fqd.js → cli-787ph852.js} +11 -11
- package/dist/{cli-793jvbsh.js → cli-7bv8nckk.js} +16 -11
- package/dist/{cli-zyxs93y9.js → cli-7jcc9y1r.js} +3 -3
- package/dist/{cli-f1am9szv.js → cli-87t2gstf.js} +1 -1
- package/dist/{cli-9aryf9tv.js → cli-95m51ztz.js} +1 -1
- package/dist/{cli-4w4fmq9x.js → cli-9w49enmh.js} +2 -2
- package/dist/{cli-v69vk5h0.js → cli-9y5b02vr.js} +13 -13
- package/dist/{cli-x23me2mg.js → cli-a1rrkrb4.js} +1 -1
- package/dist/{cli-psrqtw2m.js → cli-a3pkfpqs.js} +2 -2
- package/dist/{cli-h0rgxd24.js → cli-a4ajmfvp.js} +6 -6
- package/dist/{cli-ygrbmjja.js → cli-aw8bb6sf.js} +6 -6
- package/dist/{cli-g74vpjp2.js → cli-brm3et47.js} +55 -22
- package/dist/{cli-czkae1fp.js → cli-c5ddbdfj.js} +9 -9
- package/dist/{cli-114fvtmj.js → cli-c79a9zrc.js} +1 -1
- package/dist/{cli-49n9f49x.js → cli-dx3dz0ms.js} +3 -3
- package/dist/{cli-6dp3ydxa.js → cli-e07exmsb.js} +18 -14
- package/dist/cli-et1bbwqf.js +13 -0
- package/dist/{cli-yazx6hap.js → cli-f3s9dry0.js} +14 -14
- package/dist/{cli-t8d349cy.js → cli-f4wj0s3m.js} +3 -3
- package/dist/{cli-d6n0thxw.js → cli-f64gdfxc.js} +1 -1
- package/dist/{cli-pwfsqc2x.js → cli-fyd58xgb.js} +55 -55
- package/dist/{cli-7dm2zqy2.js → cli-g0j14czv.js} +2 -2
- package/dist/{cli-b0p7rfnd.js → cli-g2p9bd1z.js} +14 -14
- package/dist/{cli-z905tvmm.js → cli-g814jbst.js} +2 -2
- package/dist/{cli-5dsbcjjw.js → cli-ghexzd2d.js} +970 -970
- package/dist/{cli-jvv0g8bh.js → cli-gpt9kf01.js} +15 -15
- package/dist/{cli-rgrfzg8z.js → cli-grt6qv91.js} +380 -380
- package/dist/{cli-wz9115x0.js → cli-gtafvdy0.js} +8 -8
- package/dist/{cli-q5dzzak0.js → cli-gy07xk4s.js} +2 -2
- package/dist/{cli-sy7jk3tx.js → cli-h0djenzm.js} +2 -2
- package/dist/{cli-nrkkknat.js → cli-h37gbjbf.js} +2 -281
- package/dist/{cli-jevgrb4w.js → cli-h39xxnq6.js} +1200 -491
- package/dist/{cli-gz9sbyk3.js → cli-jepmgn7r.js} +1 -1
- package/dist/{cli-ccf9vy7q.js → cli-jmvk6et8.js} +7 -7
- package/dist/{cli-2rk0cx7s.js → cli-jxj92gkt.js} +51 -41
- package/dist/{cli-bqw0mt1n.js → cli-k46t4664.js} +18 -3
- package/dist/{cli-50vbt00w.js → cli-m07313tr.js} +1153 -696
- package/dist/{cli-4j2mrzag.js → cli-mkq1rk7b.js} +1 -1
- package/dist/{cli-1z7048dy.js → cli-mnm7w46e.js} +1 -1
- package/dist/{cli-kd1ck4rx.js → cli-mp9sg4cg.js} +14 -8
- package/dist/{cli-jbcva0xj.js → cli-mrammd8c.js} +60 -35
- package/dist/cli-nanaxrz6.js +27 -0
- package/dist/{cli-p9swy5t3.js → cli-pq2ee5ja.js} +8 -6
- package/dist/{cli-2wadx7p2.js → cli-pt43pdp1.js} +2 -2
- package/dist/{cli-7sgrxg9a.js → cli-q6d0vvey.js} +4 -4
- package/dist/{cli-k9qkf1hw.js → cli-qf9kpsve.js} +9 -9
- package/dist/cli-qh4sqfws.js +15 -0
- package/dist/{cli-e15jhafb.js → cli-qntkxysp.js} +14 -14
- package/dist/{cli-sajgpkqg.js → cli-qs9hhsvb.js} +1723 -325
- package/dist/{cli-z2zcxes1.js → cli-qt5bt3vk.js} +1 -1
- package/dist/{cli-wx82tw1k.js → cli-qtekrty1.js} +3 -3
- package/dist/{cli-g1re8r05.js → cli-rh6f3s9n.js} +3 -3
- package/dist/{cli-n0krnc6d.js → cli-rzhcrw2p.js} +2 -2
- package/dist/{cli-gecy3z2s.js → cli-snw62ze5.js} +4 -4
- package/dist/{cli-n6h8qt8n.js → cli-snz3p4yf.js} +15 -10
- package/dist/{cli-r6kqqbj0.js → cli-tkf8n6cw.js} +11 -11
- package/dist/{cli-4rkfg1wx.js → cli-tkrr24mz.js} +14 -9
- package/dist/{cli-9dr5qzc0.js → cli-tv9f1kyb.js} +54 -43
- package/dist/{cli-gm9cbhbq.js → cli-vtz6yj3v.js} +28 -9
- package/dist/{cli-2f07m0xr.js → cli-wf86d5t7.js} +1 -1
- package/dist/{cli-7zd05xb4.js → cli-whrvct19.js} +45 -45
- package/dist/{cli-ap1czx8f.js → cli-wrrea8xm.js} +3 -3
- package/dist/{cli-57khth04.js → cli-xmyqv00z.js} +120 -4
- package/dist/{cli-cwy5hqbq.js → cli-yjmk7tzc.js} +1 -1
- package/dist/{cli-6pcz9h15.js → cli-zykjrwcx.js} +180 -394
- package/dist/cli.js +45 -45
- package/dist/{codex-adapter-htjkn22b.js → codex-adapter-hsq6mz3m.js} +21 -19
- package/dist/{codex-hook-hq54t9ft.js → codex-hook-8c500gq8.js} +8 -7
- package/dist/{codex-login-z6yhbkmk.js → codex-login-x7603481.js} +3 -3
- package/dist/{codex-session-runner-wjfc7smz.js → codex-session-runner-c1x3x143.js} +15 -13
- package/dist/{commands-xhrfwqsk.js → commands-rwtddtst.js} +11 -9
- package/dist/{db-anvwb22f.js → db-j2b355vz.js} +458 -444
- package/dist/{devin-adapter-v1sarqtw.js → devin-adapter-8qmhqpy3.js} +3 -3
- package/dist/{devtools-2y1r7yqk.js → devtools-j2rnj8w7.js} +4 -4
- package/dist/{e2b-jdkwemv2.js → e2b-znpx78eg.js} +16 -16
- package/dist/{es5-vjgtkgp6.js → es5-fmqrjzy3.js} +2 -2
- package/dist/{event-bus-axn823e9.js → event-bus-n8sb35pw.js} +4 -4
- package/dist/{getMachineId-bsd-6tc9wxdj.js → getMachineId-bsd-wpzbhkm6.js} +4 -4
- package/dist/{getMachineId-darwin-sjt9sgnc.js → getMachineId-darwin-45zabjy0.js} +4 -4
- package/dist/{getMachineId-linux-v5n18y9p.js → getMachineId-linux-warnp5pd.js} +3 -3
- package/dist/{getMachineId-unsupported-yrjyqw3d.js → getMachineId-unsupported-5spent2a.js} +3 -3
- package/dist/{getMachineId-win-w3r8063c.js → getMachineId-win-v4bvcw7a.js} +4 -4
- package/dist/{google-generative-ai-hysrd8qx.js → google-generative-ai-b0wzss55.js} +17 -14
- package/dist/{google-vertex-p5arrga0.js → google-vertex-e8q4dpya.js} +18 -15
- package/dist/{handlers-b9kbc621.js → handlers-hchgrxkh.js} +32 -29
- package/dist/{hook-xkvn6c5h.js → hook-p49egqc0.js} +66 -52
- package/dist/hook-spb00w76.js +34 -0
- package/dist/{http-9xh6ta4r.js → http-nh14kkms.js} +663 -181
- package/dist/index-1qthq7vc.js +6 -0
- package/dist/{index-0g68f0p6.js → index-20xqmn3v.js} +3 -3
- package/dist/{index-vdkr5z2w.js → index-3e03k6e4.js} +114 -114
- package/dist/{index-ywds4812.js → index-4cbyhq2g.js} +43 -41
- package/dist/index-67pzqfrb.js +36 -0
- package/dist/{index-bccrkdkn.js → index-7m8yxkw5.js} +16 -16
- package/dist/{index-eaxyqcmj.js → index-dvsk64sm.js} +163 -83
- package/dist/{index-dqkpnmqm.js → index-e19s2m8k.js} +18 -18
- package/dist/{index-j30k5zxn.js → index-emvxcy98.js} +16 -16
- package/dist/{index-7ndw6ecy.js → index-gqnmr60d.js} +9 -9
- package/dist/{index-9znhar3x.js → index-j02xvjtd.js} +184 -185
- package/dist/{index-1s2442yw.js → index-ns5kksc1.js} +7 -7
- package/dist/{index-dpy2hth8.js → index-pdxc8kfh.js} +71 -71
- package/dist/{index-z1m7pw0v.js → index-ptcqm8bc.js} +107 -107
- package/dist/{index-070v4eyb.js → index-pyp7rexm.js} +5 -6
- package/dist/{index-86znjz1p.js → index-shne41sd.js} +13 -13
- package/dist/{index-2qn2qndv.js → index-t36q2v4t.js} +183 -183
- package/dist/index-tcnvv8w6.js +7 -0
- package/dist/index-w91qbfv1.js +7 -0
- package/dist/{index-fzc0mwvj.js → index-yqweff5n.js} +32 -32
- package/dist/index-yrfphye1.js +39 -0
- package/dist/{keepalive-vc7s2aa6.js → keepalive-9k51nqhc.js} +21 -15
- package/dist/lead-2xq3dxbz.js +88 -0
- package/dist/maintenance-0c0g6nym.js +28 -0
- package/dist/mistral-conversations-2njwdwhj.js +717 -0
- package/dist/{multipart-parser-qaktc7p8.js → multipart-parser-6gftesw0.js} +2 -2
- package/dist/{oauth-refresh-sweep-yecgjpk4.js → oauth-refresh-sweep-273a64r2.js} +14 -12
- package/dist/{onboard-xj0f73f9.js → onboard-tsv9wwhz.js} +12 -12
- package/dist/{openai-codex-responses-5g27pd6f.js → openai-codex-responses-kt84eq86.js} +26 -26
- package/dist/{openai-completions-3vkmfz2a.js → openai-completions-mrypq7qp.js} +17 -16
- package/dist/{openai-responses-dg4t7j7a.js → openai-responses-qhrk21ez.js} +20 -17
- package/dist/{opencode-adapter-1gm38aba.js → opencode-adapter-rar9676j.js} +13 -11
- package/dist/{openrouter-images-g3gm8931.js → openrouter-images-684fysx9.js} +5 -5
- package/dist/{otel-impl-nxg0n0b3.js → otel-impl-wp1mfzd2.js} +752 -537
- package/dist/{photon_rs-ky7dj5qw.js → photon_rs-8dwt2pzy.js} +581 -581
- package/dist/{pi-messages-tqj8q6b9.js → pi-messages-txp9f97r.js} +7 -7
- package/dist/{pi-mono-adapter-4g5kby31.js → pi-mono-adapter-yz47kk8e.js} +1910 -1180
- package/dist/pricing-refresh-jw1yw2fn.js +22 -0
- package/dist/rbac-roles-dg964c8p.js +32 -0
- package/dist/{rbac-roles-1hcxdtg7.js → rbac-roles-p53cg5cv.js} +19 -17
- package/dist/{registry-02cy9z5z.js → registry-mh12y17v.js} +4 -4
- package/dist/render-v2-56vn2rk9.js +36 -0
- package/dist/seed-pricing-52xx6z63.js +19 -0
- package/dist/{setup-46xtgq3c.js → setup-e8gp79sy.js} +7 -7
- package/dist/token-util-zy908s1a.js +6 -0
- package/dist/{token-fxkn2zf2.js → token-xg5711x5.js} +4 -4
- package/dist/worker-s17f1g46.js +88 -0
- package/dist/{x-6mg4kfpe.js → x-xkfh0w0v.js} +5 -5
- package/openapi.json +566 -22
- package/package.json +6 -6
- package/src/be/budget-refusal-notify.ts +14 -7
- package/src/be/db-queries/task-artifacts.ts +182 -0
- package/src/be/db.ts +834 -171
- package/src/be/events.ts +5 -0
- package/src/be/migrations/131_session_logs_created_at_index.sql +2 -0
- package/src/be/migrations/132_multi_runtime_instances.sql +44 -0
- package/src/be/migrations/133_workflow_run_trigger_type.sql +12 -0
- package/src/be/migrations/135_backfill_task_pull_request_attachments.sql +228 -0
- package/src/be/migrations/136_task_requester_provenance.sql +37 -0
- package/src/be/migrations/137_memory_retrieval_composite_index.sql +1 -0
- package/src/be/migrations/runner.ts +17 -11
- package/src/be/multi-runtime.ts +430 -0
- package/src/be/scripts/extract-schema.ts +3 -1
- package/src/be/scripts/typecheck.ts +6 -2
- package/src/be/seed-prompt-templates.ts +25 -2
- package/src/be/seed-skills/index.ts +7 -0
- package/src/be/steering.ts +1 -1
- package/src/be/swarm-config-guard.ts +18 -0
- package/src/commands/credential-wait.ts +54 -0
- package/src/commands/onboard/steps/core-credentials.tsx +1 -1
- package/src/commands/onboard/steps/custom-templates.tsx +1 -1
- package/src/commands/onboard/steps/harness-credentials.tsx +1 -1
- package/src/commands/onboard/steps/health-check.tsx +1 -1
- package/src/commands/onboard/steps/start.tsx +1 -1
- package/src/commands/profile-sync-audit.ts +56 -0
- package/src/commands/profile-sync.ts +287 -15
- package/src/commands/provider-credentials.ts +46 -19
- package/src/commands/runner.ts +199 -33
- package/src/commands/templates.ts +22 -0
- package/src/github/handlers.ts +55 -9
- package/src/heartbeat/heartbeat.ts +109 -17
- package/src/hooks/hook.ts +49 -33
- package/src/http/active-sessions.ts +11 -1
- package/src/http/agents.ts +261 -30
- package/src/http/all-routes.ts +1 -0
- package/src/http/config.ts +13 -2
- package/src/http/core.ts +102 -4
- package/src/http/db-query-bounded.ts +313 -0
- package/src/http/db-query-shared.ts +249 -0
- package/src/http/db-query.ts +54 -42
- package/src/http/events.ts +2 -0
- package/src/http/index.ts +23 -2
- package/src/http/mcp-bridge.ts +37 -3
- package/src/http/mcp.ts +12 -0
- package/src/http/memory.ts +13 -2
- package/src/http/openapi.ts +1 -0
- package/src/http/poll.ts +70 -27
- package/src/http/prompt-templates.ts +36 -13
- package/src/http/route-def.ts +43 -9
- package/src/http/schedules.ts +2 -2
- package/src/http/scripts.ts +10 -1
- package/src/http/session-data.ts +44 -0
- package/src/http/tasks.ts +2 -2
- package/src/http/users.ts +74 -52
- package/src/http/webhooks.ts +5 -2
- package/src/http/workflows.ts +1 -4
- package/src/integrations/kapso/inbound.ts +1 -1
- package/src/jira/outbound.ts +39 -8
- package/src/jira/webhook-lifecycle.ts +13 -2
- package/src/linear/outbound.ts +43 -10
- package/src/oauth/keepalive.ts +13 -2
- package/src/prompts/base-prompt.ts +1 -1
- package/src/prompts/default-drift.ts +21 -0
- package/src/prompts/session-templates.ts +56 -7
- package/src/providers/claude-adapter.ts +6 -0
- package/src/providers/codex-adapter.ts +6 -0
- package/src/providers/opencode-adapter.ts +6 -0
- package/src/providers/pi-mono-adapter.ts +8 -0
- package/src/providers/pricing-sources.md +24 -0
- package/src/queue-stall-alarm.ts +216 -0
- package/src/rbac/legacy-policy.ts +3 -0
- package/src/rbac/permissions.ts +12 -0
- package/src/scheduler/scheduler.ts +7 -0
- package/src/script-workflows/executor.ts +2 -1
- package/src/scripts-runtime/executors/native.ts +2 -1
- package/src/scripts-runtime/executors/types.ts +5 -0
- package/src/scripts-runtime/loader.ts +5 -0
- package/src/scripts-runtime/sdk-allowlist.ts +3 -0
- package/src/scripts-runtime/swarm-config.ts +8 -0
- package/src/scripts-runtime/swarm-sdk.ts +7 -0
- package/src/scripts-runtime/types/stdlib.d.ts +4 -0
- package/src/scripts-runtime/types/swarm-sdk.d.ts +4 -0
- package/src/server.ts +6 -0
- package/src/slack/channel-join.ts +22 -3
- package/src/slack/channel-lifecycle.ts +114 -0
- package/src/tests/budget-claim-gate.test.ts +20 -0
- package/src/tests/claude-adapter.test.ts +32 -0
- package/src/tests/codex-adapter.test.ts +30 -0
- package/src/tests/create-task-validation.test.ts +128 -0
- package/src/tests/credential-wait.test.ts +67 -1
- package/src/tests/db-query.test.ts +711 -2
- package/src/tests/heartbeat-checklist.test.ts +28 -0
- package/src/tests/http-api-integration.test.ts +81 -0
- package/src/tests/http-users.test.ts +166 -1
- package/src/tests/identity-field-budget.test.ts +176 -0
- package/src/tests/mcp-tools-user.test.ts +34 -0
- package/src/tests/mcp-user-route.test.ts +17 -0
- package/src/tests/metrics-http.test.ts +44 -0
- package/src/tests/migration-failure.test.ts +86 -0
- package/src/tests/multi-runtime-registration.test.ts +2810 -0
- package/src/tests/openapi-response-contract.test.ts +24 -0
- package/src/tests/openapi-route-headers.test.ts +83 -0
- package/src/tests/opencode-adapter.test.ts +40 -0
- package/src/tests/outbound-listener-rejection.test.ts +138 -0
- package/src/tests/pi-mono-adapter.test.ts +98 -0
- package/src/tests/preload.ts +2 -0
- package/src/tests/profile-sync-warning.test.ts +277 -0
- package/src/tests/profile-sync.test.ts +232 -6
- package/src/tests/prompt-template-resolver.test.ts +177 -6
- package/src/tests/prompt-template-session.test.ts +39 -3
- package/src/tests/queue-stall-alarm.test.ts +226 -0
- package/src/tests/rbac-charact-slack.test.ts +29 -0
- package/src/tests/rbac-engine.test.ts +3 -0
- package/src/tests/requester-comms.test.ts +32 -0
- package/src/tests/runner-requester-profile.test.ts +38 -0
- package/src/tests/schedule-target-type.test.ts +38 -0
- package/src/tests/script-connections.test.ts +13 -1
- package/src/tests/scripts-runtime-identity.test.ts +375 -0
- package/src/tests/scripts-runtime.test.ts +4 -3
- package/src/tests/sdk-allowlist.test.ts +47 -0
- package/src/tests/send-task-requested-by.test.ts +9 -0
- package/src/tests/session-costs.test.ts +506 -1
- package/src/tests/shutdown-error-scrubbing.test.ts +92 -0
- package/src/tests/slack-channel-lifecycle.test.ts +241 -0
- package/src/tests/slack-render-v2.test.ts +43 -0
- package/src/tests/steering-core.test.ts +28 -0
- package/src/tests/swarm-config-reserved-keys.test.ts +22 -0
- package/src/tests/task-artifacts.test.ts +386 -0
- package/src/tests/task-attachments-schema.test.ts +17 -1
- package/src/tests/task-completion-idempotency.test.ts +57 -0
- package/src/tests/task-pull-request-backfill-migration.test.ts +321 -0
- package/src/tests/tool-annotations.test.ts +4 -0
- package/src/tests/update-profile-api.test.ts +67 -39
- package/src/tests/update-profile-auth.test.ts +48 -4
- package/src/tests/user-attribution-migration.test.ts +54 -0
- package/src/tests/user-identity.test.ts +72 -0
- package/src/tests/workflow-async-v2.test.ts +39 -1
- package/src/tests/workflow-http-v2.test.ts +3 -2
- package/src/tests/workflow-mcp-trigger-schema.test.ts +52 -3
- package/src/tests/workflow-retry-v2.test.ts +45 -1
- package/src/tools/db-query.ts +18 -8
- package/src/tools/get-task-details.ts +24 -3
- package/src/tools/manage-user.ts +36 -3
- package/src/tools/poll-task.ts +93 -14
- package/src/tools/script-common.ts +5 -0
- package/src/tools/send-task.ts +1 -4
- package/src/tools/slack-archive-channel.ts +70 -0
- package/src/tools/slack-create-channel.ts +74 -0
- package/src/tools/slack-invite-to-channel.ts +78 -0
- package/src/tools/store-progress.ts +13 -2
- package/src/tools/swarm-config/delete-config.ts +9 -0
- package/src/tools/swarm-config/set-config.ts +3 -2
- package/src/tools/task-action.ts +30 -0
- package/src/tools/task-tool-ctx.ts +8 -1
- package/src/tools/tool-config.ts +4 -1
- package/src/tools/update-profile.ts +16 -21
- package/src/tools/utils.ts +5 -0
- package/src/tools/workflows/trigger-workflow.ts +7 -1
- package/src/types.ts +165 -1
- package/src/utils/github-pull-request.ts +76 -0
- package/src/utils/identity-field-budget.ts +73 -0
- package/src/utils/multi-runtime.ts +20 -0
- package/src/utils/requester-comms.ts +24 -0
- package/src/workflows/engine.ts +22 -2
- package/src/workflows/resume.ts +19 -11
- package/src/workflows/retry-poller.ts +1 -0
- package/src/workflows/triggers.ts +4 -0
- package/templates/skills/db-query-guidance/config.json +14 -0
- package/templates/skills/db-query-guidance/content.md +57 -0
- package/dist/app-5da78bd4.js +0 -26
- package/dist/cli-3te4jdkm.js +0 -225
- package/dist/cli-bmze986d.js +0 -7
- package/dist/cli-kh3ba2zf.js +0 -607
- package/dist/hook-cgk4wxmx.js +0 -31
- package/dist/index-25wjsdv2.js +0 -34
- package/dist/index-76at2ymp.js +0 -7
- package/dist/index-hase6zbe.js +0 -6
- package/dist/index-vg4snay4.js +0 -36
- package/dist/index-vy8edt27.js +0 -7
- package/dist/lead-r2yqfmx7.js +0 -85
- package/dist/maintenance-mw70k468.js +0 -26
- package/dist/mistral-conversations-81fwav0j.js +0 -30578
- package/dist/otel-nqa12wf3.js +0 -3149
- package/dist/pricing-refresh-2cn6effr.js +0 -20
- package/dist/rbac-roles-vynday5g.js +0 -30
- package/dist/render-v2-tc0bh8kk.js +0 -34
- package/dist/seed-pricing-8kceb43f.js +0 -17
- package/dist/token-util-pqyc8kng.js +0 -6
- package/dist/worker-qrbz6hmv.js +0 -85
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import { afterAll, beforeAll, describe, expect, mock, test } from "bun:test";
|
|
2
|
+
import { unlink } from "node:fs/promises";
|
|
3
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4
|
+
import type { WebClient } from "@slack/web-api";
|
|
5
|
+
import { closeDb, createAgent, initDb } from "../be/db";
|
|
6
|
+
import {
|
|
7
|
+
archiveChannel,
|
|
8
|
+
createChannel,
|
|
9
|
+
inviteToChannel,
|
|
10
|
+
normalizeChannelName,
|
|
11
|
+
} from "../slack/channel-lifecycle";
|
|
12
|
+
import { registerSlackArchiveChannelTool } from "../tools/slack-archive-channel";
|
|
13
|
+
import { registerSlackCreateChannelTool } from "../tools/slack-create-channel";
|
|
14
|
+
import { registerSlackInviteToChannelTool } from "../tools/slack-invite-to-channel";
|
|
15
|
+
|
|
16
|
+
const TEST_DB_PATH = "./test-slack-channel-lifecycle.sqlite";
|
|
17
|
+
const LEAD_ID = "aaaaaaaa-0000-4000-8000-000000000121";
|
|
18
|
+
|
|
19
|
+
const mockCreate = mock(() => Promise.resolve({ channel: { id: "C123", name: "project-alpha" } }));
|
|
20
|
+
const mockInvite = mock(() => Promise.resolve({ ok: true }));
|
|
21
|
+
const mockArchive = mock(() => Promise.resolve({ ok: true }));
|
|
22
|
+
|
|
23
|
+
mock.module("../slack/app", () => ({
|
|
24
|
+
getSlackApp: () => ({
|
|
25
|
+
client: {
|
|
26
|
+
conversations: {
|
|
27
|
+
create: mockCreate,
|
|
28
|
+
invite: mockInvite,
|
|
29
|
+
archive: mockArchive,
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
}),
|
|
33
|
+
}));
|
|
34
|
+
|
|
35
|
+
function makePlatformError(code: string, needed?: string): Error {
|
|
36
|
+
const error = new Error(`An API error occurred: ${code}`);
|
|
37
|
+
(error as unknown as { data: { error: string; needed?: string } }).data = { error: code, needed };
|
|
38
|
+
return error;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function makeClient(
|
|
42
|
+
overrides: { create?: () => unknown; invite?: () => unknown; archive?: () => unknown } = {},
|
|
43
|
+
) {
|
|
44
|
+
const create = mock(
|
|
45
|
+
overrides.create ?? (() => Promise.resolve({ channel: { id: "C123", name: "project-alpha" } })),
|
|
46
|
+
);
|
|
47
|
+
const invite = mock(overrides.invite ?? (() => Promise.resolve({ ok: true })));
|
|
48
|
+
const archive = mock(overrides.archive ?? (() => Promise.resolve({ ok: true })));
|
|
49
|
+
const client = { conversations: { create, invite, archive } } as unknown as WebClient;
|
|
50
|
+
|
|
51
|
+
return { client, create, invite, archive };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
type RegisteredTool = {
|
|
55
|
+
handler: (
|
|
56
|
+
args: unknown,
|
|
57
|
+
extra: unknown,
|
|
58
|
+
) => Promise<{ isError?: boolean; structuredContent: { success: boolean; message: string } }>;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
let tools: Record<string, RegisteredTool>;
|
|
62
|
+
|
|
63
|
+
async function removeDbFiles(): Promise<void> {
|
|
64
|
+
for (const suffix of ["", "-wal", "-shm"]) {
|
|
65
|
+
try {
|
|
66
|
+
await unlink(TEST_DB_PATH + suffix);
|
|
67
|
+
} catch (error) {
|
|
68
|
+
if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async function callTool(name: string, args: Record<string, unknown>) {
|
|
74
|
+
const tool = tools[name];
|
|
75
|
+
if (!tool) throw new Error(`Tool not registered: ${name}`);
|
|
76
|
+
|
|
77
|
+
return tool.handler(args, {
|
|
78
|
+
sessionId: "slack-channel-lifecycle-test",
|
|
79
|
+
requestInfo: { headers: { "x-agent-id": LEAD_ID } },
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
beforeAll(async () => {
|
|
84
|
+
await removeDbFiles();
|
|
85
|
+
closeDb();
|
|
86
|
+
initDb(TEST_DB_PATH);
|
|
87
|
+
createAgent({ id: LEAD_ID, name: "Slack Lifecycle Lead", isLead: true, status: "idle" });
|
|
88
|
+
|
|
89
|
+
const server = new McpServer({ name: "slack-channel-lifecycle-test", version: "1.0.0" });
|
|
90
|
+
registerSlackCreateChannelTool(server);
|
|
91
|
+
registerSlackInviteToChannelTool(server);
|
|
92
|
+
registerSlackArchiveChannelTool(server);
|
|
93
|
+
tools = (server as unknown as { _registeredTools: Record<string, RegisteredTool> })
|
|
94
|
+
._registeredTools;
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
afterAll(async () => {
|
|
98
|
+
closeDb();
|
|
99
|
+
await removeDbFiles();
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
describe("Slack channel lifecycle", () => {
|
|
103
|
+
test("normalizes channel names to Slack's naming rules", () => {
|
|
104
|
+
expect(normalizeChannelName(" Project.Alpha / Launch! ")).toBe("project-alpha-launch");
|
|
105
|
+
expect(normalizeChannelName(`A${"B".repeat(100)}`)).toHaveLength(80);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test("rejects a name that normalizes to an empty value", () => {
|
|
109
|
+
expect(() => normalizeChannelName("... !!!")).toThrow("at least one letter or number");
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test("creates a channel with the normalized name and returns it", async () => {
|
|
113
|
+
const { client, create } = makeClient();
|
|
114
|
+
|
|
115
|
+
const result = await createChannel(client, { name: "Project.Alpha", isPrivate: true });
|
|
116
|
+
|
|
117
|
+
expect(result).toEqual({ channelId: "C123", name: "project-alpha" });
|
|
118
|
+
expect(create).toHaveBeenCalledWith({ name: "project-alpha", is_private: true });
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
test("surfaces name_taken with the normalized name", async () => {
|
|
122
|
+
const { client } = makeClient({
|
|
123
|
+
create: () => {
|
|
124
|
+
throw makePlatformError("name_taken");
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
await expect(createChannel(client, { name: "Project.Alpha" })).rejects.toThrow(
|
|
129
|
+
'Slack channel name "project-alpha" is already taken.',
|
|
130
|
+
);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
test("treats already_in_channel as invite success", async () => {
|
|
134
|
+
const { client, invite } = makeClient({
|
|
135
|
+
invite: () => {
|
|
136
|
+
throw makePlatformError("already_in_channel");
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
const result = await inviteToChannel(client, "C123", ["U1", "U2"]);
|
|
141
|
+
|
|
142
|
+
expect(result).toEqual({ alreadyInChannel: true });
|
|
143
|
+
expect(invite).toHaveBeenCalledTimes(3);
|
|
144
|
+
expect(invite).toHaveBeenNthCalledWith(1, { channel: "C123", users: "U1,U2" });
|
|
145
|
+
expect(invite).toHaveBeenNthCalledWith(2, { channel: "C123", users: "U1" });
|
|
146
|
+
expect(invite).toHaveBeenNthCalledWith(3, { channel: "C123", users: "U2" });
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
test("retries a mixed already_in_channel batch so new users are still invited", async () => {
|
|
150
|
+
const inviteResults = [
|
|
151
|
+
() => {
|
|
152
|
+
throw makePlatformError("already_in_channel");
|
|
153
|
+
},
|
|
154
|
+
() => {
|
|
155
|
+
throw makePlatformError("already_in_channel");
|
|
156
|
+
},
|
|
157
|
+
() => Promise.resolve({ ok: true }),
|
|
158
|
+
];
|
|
159
|
+
const { client, invite } = makeClient({
|
|
160
|
+
invite: () => inviteResults.shift()?.(),
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
const result = await inviteToChannel(client, "C123", ["U1", "U2"]);
|
|
164
|
+
|
|
165
|
+
expect(result).toEqual({ alreadyInChannel: false });
|
|
166
|
+
expect(invite).toHaveBeenNthCalledWith(2, { channel: "C123", users: "U1" });
|
|
167
|
+
expect(invite).toHaveBeenNthCalledWith(3, { channel: "C123", users: "U2" });
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
test("treats already_archived as archive success", async () => {
|
|
171
|
+
const { client, archive } = makeClient({
|
|
172
|
+
archive: () => {
|
|
173
|
+
throw makePlatformError("already_archived");
|
|
174
|
+
},
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
const result = await archiveChannel(client, "C123");
|
|
178
|
+
|
|
179
|
+
expect(result).toEqual({ alreadyArchived: true });
|
|
180
|
+
expect(archive).toHaveBeenCalledWith({ channel: "C123" });
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
test("explains that Slack's general channel cannot be archived", async () => {
|
|
184
|
+
const { client } = makeClient({
|
|
185
|
+
archive: () => {
|
|
186
|
+
throw makePlatformError("cant_archive_general");
|
|
187
|
+
},
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
await expect(archiveChannel(client, "CGENERAL")).rejects.toThrow(
|
|
191
|
+
"Slack's general channel cannot be archived.",
|
|
192
|
+
);
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
describe("Slack channel lifecycle tool scope errors", () => {
|
|
197
|
+
test("create names Slack's required scope and the reinstall step", async () => {
|
|
198
|
+
mockCreate.mockImplementationOnce(() =>
|
|
199
|
+
Promise.reject(makePlatformError("missing_scope", "channels:manage")),
|
|
200
|
+
);
|
|
201
|
+
|
|
202
|
+
const result = await callTool("slack-create-channel", { name: "project-alpha" });
|
|
203
|
+
|
|
204
|
+
expect(result.isError).toBe(true);
|
|
205
|
+
expect(result.structuredContent.success).toBe(false);
|
|
206
|
+
expect(result.structuredContent.message).toBe(
|
|
207
|
+
"Failed to create Slack channel: Slack requires the `channels:manage` scope. Add it to slack-manifest.json, apply the updated manifest to the Slack app, then reinstall the app to the workspace for the change to take effect.",
|
|
208
|
+
);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
test("invite names Slack's required scope and the reinstall step", async () => {
|
|
212
|
+
mockInvite.mockImplementationOnce(() =>
|
|
213
|
+
Promise.reject(makePlatformError("missing_scope", "groups:write")),
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
const result = await callTool("slack-invite-to-channel", {
|
|
217
|
+
channelId: "G123",
|
|
218
|
+
userIds: ["U123"],
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
expect(result.isError).toBe(true);
|
|
222
|
+
expect(result.structuredContent.success).toBe(false);
|
|
223
|
+
expect(result.structuredContent.message).toBe(
|
|
224
|
+
"Failed to invite users to Slack channel: Slack requires the `groups:write` scope. Add it to slack-manifest.json, apply the updated manifest to the Slack app, then reinstall the app to the workspace for the change to take effect.",
|
|
225
|
+
);
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
test("archive names Slack's required scope and the reinstall step", async () => {
|
|
229
|
+
mockArchive.mockImplementationOnce(() =>
|
|
230
|
+
Promise.reject(makePlatformError("missing_scope", "channels:manage")),
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
const result = await callTool("slack-archive-channel", { channelId: "C123" });
|
|
234
|
+
|
|
235
|
+
expect(result.isError).toBe(true);
|
|
236
|
+
expect(result.structuredContent.success).toBe(false);
|
|
237
|
+
expect(result.structuredContent.message).toBe(
|
|
238
|
+
"Failed to archive Slack channel: Slack requires the `channels:manage` scope. Add it to slack-manifest.json, apply the updated manifest to the Slack app, then reinstall the app to the workspace for the change to take effect.",
|
|
239
|
+
);
|
|
240
|
+
});
|
|
241
|
+
});
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
isPendingSlackMessage,
|
|
20
20
|
markTaskSlackReplySent,
|
|
21
21
|
startTask,
|
|
22
|
+
upsertSwarmConfig,
|
|
22
23
|
} from "../be/db";
|
|
23
24
|
import { getTaskLink, MAX_SECTION_LENGTH } from "../slack/blocks";
|
|
24
25
|
import {
|
|
@@ -33,6 +34,7 @@ import {
|
|
|
33
34
|
} from "../slack/render-v2";
|
|
34
35
|
import { getAgentDisplayName, getAgentEmoji } from "../slack/responses";
|
|
35
36
|
import { slackContextKey } from "../tasks/context-key";
|
|
37
|
+
import { clearVolatileSecretsForTesting } from "../utils/secret-scrubber";
|
|
36
38
|
|
|
37
39
|
const TEST_DB_PATH = "./test-slack-render-v2.sqlite";
|
|
38
40
|
const calls: Array<{ method: string; payload: Record<string, unknown> }> = [];
|
|
@@ -224,6 +226,7 @@ beforeAll(() => {
|
|
|
224
226
|
});
|
|
225
227
|
|
|
226
228
|
beforeEach(async () => {
|
|
229
|
+
clearVolatileSecretsForTesting();
|
|
227
230
|
closeDb();
|
|
228
231
|
await removeDbFiles();
|
|
229
232
|
initDb(TEST_DB_PATH);
|
|
@@ -1412,6 +1415,46 @@ describe("Slack renderer v2", () => {
|
|
|
1412
1415
|
);
|
|
1413
1416
|
});
|
|
1414
1417
|
|
|
1418
|
+
test("redacts a runtime-rotated config secret from persisted output and its Slack outcome", async () => {
|
|
1419
|
+
const lead = createAgent({ name: "Rotating Secret Lead", isLead: true, status: "idle" });
|
|
1420
|
+
const { channelId, threadTs } = uniqueSlackAddress("C_RENDER_ROTATED_SECRET");
|
|
1421
|
+
const ask = createTaskExtended("rotate a secret before completing", {
|
|
1422
|
+
agentId: lead.id,
|
|
1423
|
+
source: "slack",
|
|
1424
|
+
slackChannelId: channelId,
|
|
1425
|
+
slackThreadTs: threadTs,
|
|
1426
|
+
contextKey: slackContextKey({ channelId, threadTs }),
|
|
1427
|
+
});
|
|
1428
|
+
const secret = `rotated-directory-token-${crypto.randomUUID()}`;
|
|
1429
|
+
const redacted = "[REDACTED:config:AUTOINFRA_DIRECTORY_ACCESS_VALUE]";
|
|
1430
|
+
|
|
1431
|
+
upsertSwarmConfig({
|
|
1432
|
+
scope: "global",
|
|
1433
|
+
key: "AUTOINFRA_DIRECTORY_ACCESS_VALUE",
|
|
1434
|
+
value: secret,
|
|
1435
|
+
isSecret: true,
|
|
1436
|
+
});
|
|
1437
|
+
startTask(ask.id);
|
|
1438
|
+
await ensureSlackThreadTree([ask.id]);
|
|
1439
|
+
completeTask(ask.id, `Artifact: https://example.test/downloads/${secret}/result.json`);
|
|
1440
|
+
|
|
1441
|
+
const persistedOutput = getTaskById(ask.id)?.output;
|
|
1442
|
+
expect(persistedOutput).toBe(
|
|
1443
|
+
`Artifact: https://example.test/downloads/${redacted}/result.json`,
|
|
1444
|
+
);
|
|
1445
|
+
expect(persistedOutput).not.toContain(secret);
|
|
1446
|
+
|
|
1447
|
+
calls.length = 0;
|
|
1448
|
+
_resetSlackRenderV2ForTests();
|
|
1449
|
+
await processSlackRenderV2();
|
|
1450
|
+
|
|
1451
|
+
const started = calls.find((call) => call.method === "chat.startStream");
|
|
1452
|
+
expect(started?.payload.markdown_text).toBe(
|
|
1453
|
+
`✅\n\nArtifact: https://example.test/downloads/${redacted}/result.json`,
|
|
1454
|
+
);
|
|
1455
|
+
expect(started?.payload.markdown_text).not.toContain(secret);
|
|
1456
|
+
});
|
|
1457
|
+
|
|
1415
1458
|
test("re-reads slackReplySent inside streamOutcomeCard to avoid a stale caller snapshot", async () => {
|
|
1416
1459
|
const lead = createAgent({ name: "Stale Snapshot Lead", isLead: true, status: "idle" });
|
|
1417
1460
|
const { channelId, threadTs } = uniqueSlackAddress("C_RENDER_STALE_SNAPSHOT");
|
|
@@ -12,7 +12,9 @@ import {
|
|
|
12
12
|
createAgent,
|
|
13
13
|
createSteeringMessage,
|
|
14
14
|
createTaskExtended,
|
|
15
|
+
createUser,
|
|
15
16
|
getChildTasks,
|
|
17
|
+
getDb,
|
|
16
18
|
getLatestLeadTaskInThread,
|
|
17
19
|
getPendingSteeringForAgent,
|
|
18
20
|
getSteeringMessageById,
|
|
@@ -246,6 +248,32 @@ describe("task steering core", () => {
|
|
|
246
248
|
});
|
|
247
249
|
});
|
|
248
250
|
|
|
251
|
+
test("automatic promotion preserves inherited requester provenance", () => {
|
|
252
|
+
const user = createUser({ name: "Steering provenance requester" });
|
|
253
|
+
const parent = createTaskExtended("heartbeat steering parent", {
|
|
254
|
+
agentId: agentIds.get("codex"),
|
|
255
|
+
taskType: "heartbeat-checklist",
|
|
256
|
+
requestedByUserId: user.id,
|
|
257
|
+
});
|
|
258
|
+
expect(startTask(parent.id)?.status).toBe("in_progress");
|
|
259
|
+
|
|
260
|
+
const result = requestSteering({
|
|
261
|
+
taskId: parent.id,
|
|
262
|
+
message: "promote autonomous steering",
|
|
263
|
+
source: "api",
|
|
264
|
+
createdByKind: "agent",
|
|
265
|
+
createdByAgentId: agentIds.get("lead"),
|
|
266
|
+
});
|
|
267
|
+
const promoted = markSteeringUndeliverable(result.steeringMessageId, "session died");
|
|
268
|
+
expect(getTaskById(promoted.promotedTaskId!)?.requestedByUserId).toBe(user.id);
|
|
269
|
+
const provenance = getDb()
|
|
270
|
+
.query<{ inherited: number }, [string]>(
|
|
271
|
+
"SELECT requestedByUserIdInherited AS inherited FROM agent_tasks WHERE id = ?",
|
|
272
|
+
)
|
|
273
|
+
.get(promoted.promotedTaskId!);
|
|
274
|
+
expect(provenance?.inherited).toBe(1);
|
|
275
|
+
});
|
|
276
|
+
|
|
249
277
|
test("claude steer requests degrade to queue while preserving requested mode", () => {
|
|
250
278
|
const task = runningTask("claude", "claude degrade");
|
|
251
279
|
const result = requestSteering({
|
|
@@ -19,6 +19,7 @@ import { registerDeleteConfigTool } from "../tools/swarm-config/delete-config";
|
|
|
19
19
|
import { registerListConfigTool } from "../tools/swarm-config/list-config";
|
|
20
20
|
import { registerSetConfigTool } from "../tools/swarm-config/set-config";
|
|
21
21
|
import { setRequestAuth } from "../utils/request-auth-context";
|
|
22
|
+
import { clearVolatileSecretsForTesting, scrubSecrets } from "../utils/secret-scrubber";
|
|
22
23
|
|
|
23
24
|
const TEST_DB_PATH = "./test-swarm-config-reserved-keys.sqlite";
|
|
24
25
|
const TEST_PORT = 13047;
|
|
@@ -126,6 +127,7 @@ describe("swarm-config reserved keys guard", () => {
|
|
|
126
127
|
});
|
|
127
128
|
|
|
128
129
|
afterAll(async () => {
|
|
130
|
+
clearVolatileSecretsForTesting();
|
|
129
131
|
server.close();
|
|
130
132
|
closeDb();
|
|
131
133
|
await unlink(TEST_DB_PATH).catch(() => {});
|
|
@@ -282,6 +284,26 @@ describe("swarm-config reserved keys guard", () => {
|
|
|
282
284
|
expect(result.structuredContent.success).toBe(true);
|
|
283
285
|
});
|
|
284
286
|
|
|
287
|
+
test("immediately redacts a newly set secret config value", async () => {
|
|
288
|
+
clearVolatileSecretsForTesting();
|
|
289
|
+
const handler = mcpServer.handlers.get("set-config");
|
|
290
|
+
const value = `rotated-directory-token-${crypto.randomUUID()}`;
|
|
291
|
+
const result = (await handler!(
|
|
292
|
+
{
|
|
293
|
+
scope: "global",
|
|
294
|
+
key: "AUTOINFRA_DIRECTORY_ACCESS_VALUE",
|
|
295
|
+
value,
|
|
296
|
+
isSecret: true,
|
|
297
|
+
},
|
|
298
|
+
makeRequestInfo(),
|
|
299
|
+
)) as { structuredContent: { success: boolean } };
|
|
300
|
+
|
|
301
|
+
expect(result.structuredContent.success).toBe(true);
|
|
302
|
+
expect(scrubSecrets(`https://example.test/downloads/${value}/artifact`)).toBe(
|
|
303
|
+
"https://example.test/downloads/[REDACTED:config:AUTOINFRA_DIRECTORY_ACCESS_VALUE]/artifact",
|
|
304
|
+
);
|
|
305
|
+
});
|
|
306
|
+
|
|
285
307
|
test("rejects arbitrary config writes from non-lead set-config callers", async () => {
|
|
286
308
|
const worker = createAgent({
|
|
287
309
|
name: "config-worker",
|