@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
|
@@ -10,9 +10,10 @@ import {
|
|
|
10
10
|
resolvePromptTemplate,
|
|
11
11
|
upsertPromptTemplate,
|
|
12
12
|
} from "../be/db";
|
|
13
|
+
import { getPromptTemplateDefaultDrift } from "../prompts/default-drift";
|
|
13
14
|
import { getAllTemplateDefinitions, getTemplateDefinition } from "../prompts/registry";
|
|
14
15
|
import { resolveTemplate } from "../prompts/resolver";
|
|
15
|
-
import { PromptTemplateHistorySchema, PromptTemplateSchema } from "../types";
|
|
16
|
+
import { type PromptTemplate, PromptTemplateHistorySchema, PromptTemplateSchema } from "../types";
|
|
16
17
|
import { interpolate } from "../utils/template";
|
|
17
18
|
import { route } from "./route-def";
|
|
18
19
|
import { jsonError } from "./utils";
|
|
@@ -35,6 +36,19 @@ const EventTemplateDefinitionResponseSchema = z.object({
|
|
|
35
36
|
category: z.enum(["event", "system", "common", "task_lifecycle", "session"]),
|
|
36
37
|
});
|
|
37
38
|
|
|
39
|
+
const PromptTemplateResponseSchema = PromptTemplateSchema.extend({
|
|
40
|
+
defaultDrifted: z.boolean(),
|
|
41
|
+
}).openapi("PromptTemplateResponse");
|
|
42
|
+
|
|
43
|
+
function toPromptTemplateResponse(template: PromptTemplate) {
|
|
44
|
+
const definition = getTemplateDefinition(template.eventType);
|
|
45
|
+
const defaultDrifted = definition
|
|
46
|
+
? getPromptTemplateDefaultDrift(template, definition.defaultBody).defaultDrifted
|
|
47
|
+
: false;
|
|
48
|
+
|
|
49
|
+
return { ...template, defaultDrifted };
|
|
50
|
+
}
|
|
51
|
+
|
|
38
52
|
/** Mirrors `ResolveResult` from src/prompts/resolver.ts */
|
|
39
53
|
const ResolveResultSchema = z.object({
|
|
40
54
|
text: z.string(),
|
|
@@ -46,7 +60,10 @@ const ResolveResultSchema = z.object({
|
|
|
46
60
|
|
|
47
61
|
/** Mirrors the return type of `resolvePromptTemplate` in src/be/db.ts */
|
|
48
62
|
const DbResolveResultSchema = z
|
|
49
|
-
.union([
|
|
63
|
+
.union([
|
|
64
|
+
z.object({ template: PromptTemplateResponseSchema }),
|
|
65
|
+
z.object({ skip: z.literal(true) }),
|
|
66
|
+
])
|
|
50
67
|
.nullable();
|
|
51
68
|
|
|
52
69
|
// ─── Route Definitions ───────────────────────────────────────────────────────
|
|
@@ -142,7 +159,7 @@ const checkoutRoute = route({
|
|
|
142
159
|
responses: {
|
|
143
160
|
200: {
|
|
144
161
|
description: "Checked-out template",
|
|
145
|
-
schema: z.object({ template:
|
|
162
|
+
schema: z.object({ template: PromptTemplateResponseSchema }),
|
|
146
163
|
},
|
|
147
164
|
400: { description: "Validation error" },
|
|
148
165
|
404: { description: "Template or version not found" },
|
|
@@ -158,7 +175,10 @@ const resetRoute = route({
|
|
|
158
175
|
tags: ["PromptTemplates"],
|
|
159
176
|
params: z.object({ id: z.string() }),
|
|
160
177
|
responses: {
|
|
161
|
-
200: {
|
|
178
|
+
200: {
|
|
179
|
+
description: "Reset template",
|
|
180
|
+
schema: z.object({ template: PromptTemplateResponseSchema }),
|
|
181
|
+
},
|
|
162
182
|
404: { description: "Template not found or no code default available" },
|
|
163
183
|
},
|
|
164
184
|
auth: { apiKey: true },
|
|
@@ -175,7 +195,7 @@ const getByIdRoute = route({
|
|
|
175
195
|
200: {
|
|
176
196
|
description: "Template with history",
|
|
177
197
|
schema: z.object({
|
|
178
|
-
template:
|
|
198
|
+
template: PromptTemplateResponseSchema,
|
|
179
199
|
history: z.array(PromptTemplateHistorySchema),
|
|
180
200
|
}),
|
|
181
201
|
},
|
|
@@ -217,7 +237,7 @@ const listRoute = route({
|
|
|
217
237
|
responses: {
|
|
218
238
|
200: {
|
|
219
239
|
description: "List of prompt templates",
|
|
220
|
-
schema: z.object({ templates: z.array(
|
|
240
|
+
schema: z.object({ templates: z.array(PromptTemplateResponseSchema) }),
|
|
221
241
|
},
|
|
222
242
|
},
|
|
223
243
|
auth: { apiKey: true },
|
|
@@ -241,7 +261,7 @@ const upsertRoute = route({
|
|
|
241
261
|
responses: {
|
|
242
262
|
200: {
|
|
243
263
|
description: "Upserted template",
|
|
244
|
-
schema: z.object({ template:
|
|
264
|
+
schema: z.object({ template: PromptTemplateResponseSchema }),
|
|
245
265
|
},
|
|
246
266
|
400: { description: "Validation error" },
|
|
247
267
|
},
|
|
@@ -273,7 +293,10 @@ export async function handlePromptTemplates(
|
|
|
273
293
|
|
|
274
294
|
resolvedRoute.respond(res, 200, {
|
|
275
295
|
resolution: result,
|
|
276
|
-
dbResult
|
|
296
|
+
dbResult:
|
|
297
|
+
dbResult && "template" in dbResult
|
|
298
|
+
? { template: toPromptTemplateResponse(dbResult.template) }
|
|
299
|
+
: dbResult,
|
|
277
300
|
definition: definition
|
|
278
301
|
? {
|
|
279
302
|
eventType: definition.eventType,
|
|
@@ -339,7 +362,7 @@ export async function handlePromptTemplates(
|
|
|
339
362
|
|
|
340
363
|
try {
|
|
341
364
|
const template = checkoutPromptTemplate(parsed.params.id, parsed.body.version);
|
|
342
|
-
checkoutRoute.respond(res, 200, { template });
|
|
365
|
+
checkoutRoute.respond(res, 200, { template: toPromptTemplateResponse(template) });
|
|
343
366
|
} catch (error) {
|
|
344
367
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
345
368
|
if (message.includes("not found")) {
|
|
@@ -370,7 +393,7 @@ export async function handlePromptTemplates(
|
|
|
370
393
|
|
|
371
394
|
try {
|
|
372
395
|
const template = resetPromptTemplateToDefault(parsed.params.id, definition.defaultBody);
|
|
373
|
-
resetRoute.respond(res, 200, { template });
|
|
396
|
+
resetRoute.respond(res, 200, { template: toPromptTemplateResponse(template) });
|
|
374
397
|
} catch (error) {
|
|
375
398
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
376
399
|
jsonError(res, message, 400);
|
|
@@ -390,7 +413,7 @@ export async function handlePromptTemplates(
|
|
|
390
413
|
}
|
|
391
414
|
|
|
392
415
|
const history = getPromptTemplateHistory(parsed.params.id);
|
|
393
|
-
getByIdRoute.respond(res, 200, { template, history });
|
|
416
|
+
getByIdRoute.respond(res, 200, { template: toPromptTemplateResponse(template), history });
|
|
394
417
|
return true;
|
|
395
418
|
}
|
|
396
419
|
|
|
@@ -425,7 +448,7 @@ export async function handlePromptTemplates(
|
|
|
425
448
|
isDefault: parsed.query.isDefault ? parsed.query.isDefault === "true" : undefined,
|
|
426
449
|
});
|
|
427
450
|
|
|
428
|
-
listRoute.respond(res, 200, { templates });
|
|
451
|
+
listRoute.respond(res, 200, { templates: templates.map(toPromptTemplateResponse) });
|
|
429
452
|
return true;
|
|
430
453
|
}
|
|
431
454
|
|
|
@@ -464,7 +487,7 @@ export async function handlePromptTemplates(
|
|
|
464
487
|
changedBy,
|
|
465
488
|
changeReason,
|
|
466
489
|
});
|
|
467
|
-
upsertRoute.respond(res, 200, { template });
|
|
490
|
+
upsertRoute.respond(res, 200, { template: toPromptTemplateResponse(template) });
|
|
468
491
|
} catch (error) {
|
|
469
492
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
470
493
|
jsonError(res, message, 500);
|
package/src/http/route-def.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import type { PermissionVerb } from "../rbac";
|
|
4
|
+
import { scrubSecrets } from "../utils/secret-scrubber";
|
|
4
5
|
import { jsonError, matchRoute, parseBody } from "./utils";
|
|
5
6
|
|
|
6
7
|
// ─── Types ───────────────────────────────────────────────────────────────────
|
|
@@ -25,6 +26,24 @@ type ResponsesDef = Record<number, RouteResponseDef>;
|
|
|
25
26
|
/** Extracts the payload type respond() accepts for one response def. */
|
|
26
27
|
type ResponseData<R> = R extends { schema: infer S extends z.ZodType } ? z.input<S> : never;
|
|
27
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Optional `X-Runtime-Instance-ID` header shared by the lifecycle and poll
|
|
31
|
+
* routes. Optional in the schema because the requirement is conditional:
|
|
32
|
+
* only multi-runtime mode needs it, and legacy deployments must keep working
|
|
33
|
+
* without it.
|
|
34
|
+
*/
|
|
35
|
+
export const runtimeInstanceHeader = (operation: string) =>
|
|
36
|
+
z.object({
|
|
37
|
+
"X-Runtime-Instance-ID": z
|
|
38
|
+
.string()
|
|
39
|
+
.optional()
|
|
40
|
+
.describe(
|
|
41
|
+
"Identifies the concrete runtime instance (worker process) making the call, " +
|
|
42
|
+
`as generated at its boot. Required to ${operation} when multi-runtime mode ` +
|
|
43
|
+
"(MULTI_RUNTIME_ENABLED) is on; ignored otherwise.",
|
|
44
|
+
),
|
|
45
|
+
});
|
|
46
|
+
|
|
28
47
|
export interface RouteDef<
|
|
29
48
|
TParams extends z.ZodType = z.ZodType,
|
|
30
49
|
TQuery extends z.ZodType = z.ZodType,
|
|
@@ -41,6 +60,14 @@ export interface RouteDef<
|
|
|
41
60
|
tags: string[];
|
|
42
61
|
params?: TParams;
|
|
43
62
|
query?: TQuery;
|
|
63
|
+
/**
|
|
64
|
+
* Request headers to publish as OpenAPI parameters, beyond the global
|
|
65
|
+
* `Authorization`/`X-Agent-ID` security schemes. Declaration-only: handlers
|
|
66
|
+
* still read headers off `req`, so adding this to a route changes the
|
|
67
|
+
* generated spec and nothing else. Mark each property `.optional()` unless
|
|
68
|
+
* the header is unconditionally required.
|
|
69
|
+
*/
|
|
70
|
+
headers?: z.ZodObject;
|
|
44
71
|
body?: TBody;
|
|
45
72
|
responses: TResponses;
|
|
46
73
|
auth?: {
|
|
@@ -187,10 +214,14 @@ export function describeRequestRoute(
|
|
|
187
214
|
// ─── Factory ─────────────────────────────────────────────────────────────────
|
|
188
215
|
|
|
189
216
|
/**
|
|
190
|
-
* Runtime response validation gate for `respond()`.
|
|
191
|
-
*
|
|
192
|
-
*
|
|
193
|
-
*
|
|
217
|
+
* Runtime response validation gate for `respond()`. Only `bun test`
|
|
218
|
+
* (NODE_ENV=test) fails hard on a violation: one bad row must never take an
|
|
219
|
+
* endpoint down outside tests (2026-08-18 incident — a single priority='high'
|
|
220
|
+
* row 500'd every task listing). When the gate is on outside tests
|
|
221
|
+
* (NODE_ENV=development, or VALIDATE_HTTP_RESPONSES=true), `respond()` logs
|
|
222
|
+
* the violation and sends the response anyway. Note: the compiled Bun binary
|
|
223
|
+
* defaults NODE_ENV to "development", so deploys must also set
|
|
224
|
+
* NODE_ENV=production explicitly (see the deploy-env change in the fix PR).
|
|
194
225
|
*/
|
|
195
226
|
const VALIDATE_RESPONSES =
|
|
196
227
|
process.env.NODE_ENV === "test" ||
|
|
@@ -216,12 +247,15 @@ export function route<
|
|
|
216
247
|
if (schema) {
|
|
217
248
|
const result = schema.safeParse(data);
|
|
218
249
|
if (!result.success) {
|
|
219
|
-
|
|
250
|
+
const detail =
|
|
220
251
|
`Response schema violation: ${def.method.toUpperCase()} ${def.path} ${code} — ` +
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
)
|
|
252
|
+
result.error.issues
|
|
253
|
+
.map((i) => `${i.path.join(".") || "<root>"}: ${i.message}`)
|
|
254
|
+
.join("; ");
|
|
255
|
+
if (process.env.NODE_ENV === "test") {
|
|
256
|
+
throw new Error(detail);
|
|
257
|
+
}
|
|
258
|
+
console.error(`[route-def] ${scrubSecrets(detail)}`);
|
|
225
259
|
}
|
|
226
260
|
}
|
|
227
261
|
}
|
package/src/http/schedules.ts
CHANGED
|
@@ -40,7 +40,7 @@ const scheduleUpdateBodySchema = z.object({
|
|
|
40
40
|
taskTemplate: z.string().optional(),
|
|
41
41
|
taskType: z.string().optional(),
|
|
42
42
|
tags: z.array(z.string()).optional(),
|
|
43
|
-
priority: z.number().int().optional(),
|
|
43
|
+
priority: z.number().int().min(0).max(100).optional(),
|
|
44
44
|
targetAgentId: z.string().nullable().optional(),
|
|
45
45
|
enabled: z.boolean().optional(),
|
|
46
46
|
timezone: z.string().optional(),
|
|
@@ -96,7 +96,7 @@ const createSchedule = route({
|
|
|
96
96
|
taskTemplate: z.string().min(1).optional(),
|
|
97
97
|
taskType: z.string().optional(),
|
|
98
98
|
tags: z.array(z.string()).optional(),
|
|
99
|
-
priority: z.number().int().optional(),
|
|
99
|
+
priority: z.number().int().min(0).max(100).optional(),
|
|
100
100
|
targetAgentId: z.string().optional(),
|
|
101
101
|
enabled: z.boolean().optional(),
|
|
102
102
|
timezone: z.string().optional(),
|
package/src/http/scripts.ts
CHANGED
|
@@ -53,7 +53,7 @@ import {
|
|
|
53
53
|
ScriptVersionRecordSchema,
|
|
54
54
|
} from "../types";
|
|
55
55
|
import { scrubObject, scrubSecrets } from "../utils/secret-scrubber";
|
|
56
|
-
import { route } from "./route-def";
|
|
56
|
+
import { route, runtimeInstanceHeader } from "./route-def";
|
|
57
57
|
import { json, jsonError } from "./utils";
|
|
58
58
|
|
|
59
59
|
const scriptNameSchema = z.string().min(1).max(200);
|
|
@@ -244,6 +244,7 @@ const runRoute = route({
|
|
|
244
244
|
description:
|
|
245
245
|
"Inline source skips typecheck and is auto-saved as a scratch script only on success.",
|
|
246
246
|
tags: ["Scripts"],
|
|
247
|
+
headers: runtimeInstanceHeader("acquire work through the script SDK"),
|
|
247
248
|
body: runBodySchema,
|
|
248
249
|
responses: {
|
|
249
250
|
200: { description: "Script run completed", schema: scriptRunResponseSchema },
|
|
@@ -695,6 +696,13 @@ export async function handleScripts(
|
|
|
695
696
|
const agent = requireAgent(res, agentId);
|
|
696
697
|
if (!agent) return true;
|
|
697
698
|
|
|
699
|
+
// Per-boot identity of the invoking worker process. Carried into the
|
|
700
|
+
// script runtime as system context so SDK work-acquisition calls present
|
|
701
|
+
// the same runtime the worker itself would — never script input.
|
|
702
|
+
const runtimeInstanceId = ((h) => (Array.isArray(h) ? h[0] : h))(
|
|
703
|
+
req.headers["x-runtime-instance-id"],
|
|
704
|
+
);
|
|
705
|
+
|
|
698
706
|
let source = parsed.body.source;
|
|
699
707
|
let fsMode = parsed.body.fsMode;
|
|
700
708
|
let namedScript: ScriptRecord | null = null;
|
|
@@ -726,6 +734,7 @@ export async function handleScripts(
|
|
|
726
734
|
args: parsed.body.args,
|
|
727
735
|
fsMode,
|
|
728
736
|
agentId: agent.id,
|
|
737
|
+
runtimeInstanceId,
|
|
729
738
|
egressSecrets: credentials.egressSecrets,
|
|
730
739
|
failedBindings: credentials.failedBindings,
|
|
731
740
|
apiConnections: getScriptApiConnectionDescriptors({ agentId: agent.id }),
|
package/src/http/session-data.ts
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
createSessionLogs,
|
|
6
6
|
getActivePricingRow,
|
|
7
7
|
getAllSessionCosts,
|
|
8
|
+
getAttributionByPerson,
|
|
8
9
|
getDashboardCostSummary,
|
|
9
10
|
getSessionCostSummary,
|
|
10
11
|
getSessionCostsByAgentId,
|
|
@@ -34,6 +35,9 @@ const SessionCostSummaryTotalsSchema = z.object({
|
|
|
34
35
|
totalSessions: z.number().int(),
|
|
35
36
|
avgCostPerSession: z.number(),
|
|
36
37
|
attributedCostUsd: z.number(),
|
|
38
|
+
attributableCostUsd: z.number(),
|
|
39
|
+
excludedCostUsd: z.number(),
|
|
40
|
+
excludedTaskCount: z.number().int(),
|
|
37
41
|
});
|
|
38
42
|
|
|
39
43
|
/** Mirrors `SessionCostDailyRow` in src/be/db.ts. */
|
|
@@ -79,6 +83,17 @@ const DashboardCostSummarySchema = z.object({
|
|
|
79
83
|
costMtd: z.number(),
|
|
80
84
|
});
|
|
81
85
|
|
|
86
|
+
/** Mirrors `AttributionByPersonRow` in src/be/db.ts. */
|
|
87
|
+
const AttributionByPersonRowSchema = z.object({
|
|
88
|
+
userId: z.string(),
|
|
89
|
+
problemsInitiated: z.number().int(),
|
|
90
|
+
problemsShipped: z.number().int(),
|
|
91
|
+
agentsReached: z.number().int(),
|
|
92
|
+
reposReached: z.number().int(),
|
|
93
|
+
surfacesReached: z.number().int(),
|
|
94
|
+
firstPassYield: z.null(),
|
|
95
|
+
});
|
|
96
|
+
|
|
82
97
|
// ─── Route Definitions ───────────────────────────────────────────────────────
|
|
83
98
|
|
|
84
99
|
const createSessionLogsRoute = route({
|
|
@@ -203,6 +218,24 @@ const getSessionCostSummaryRoute = route({
|
|
|
203
218
|
},
|
|
204
219
|
});
|
|
205
220
|
|
|
221
|
+
const getAttributionByPersonRoute = route({
|
|
222
|
+
method: "get",
|
|
223
|
+
path: "/api/attribution/by-person",
|
|
224
|
+
pattern: ["api", "attribution", "by-person"],
|
|
225
|
+
summary: "Four-metric per-person attribution (problems initiated/shipped, reach)",
|
|
226
|
+
tags: ["Session Data"],
|
|
227
|
+
query: z.object({
|
|
228
|
+
startDate: z.string().optional(),
|
|
229
|
+
endDate: z.string().optional(),
|
|
230
|
+
}),
|
|
231
|
+
responses: {
|
|
232
|
+
200: {
|
|
233
|
+
description: "Per-person attribution rows",
|
|
234
|
+
schema: z.object({ rows: z.array(AttributionByPersonRowSchema) }),
|
|
235
|
+
},
|
|
236
|
+
},
|
|
237
|
+
});
|
|
238
|
+
|
|
206
239
|
const getDashboardCosts = route({
|
|
207
240
|
method: "get",
|
|
208
241
|
path: "/api/session-costs/dashboard",
|
|
@@ -403,6 +436,17 @@ export async function handleSessionData(
|
|
|
403
436
|
return true;
|
|
404
437
|
}
|
|
405
438
|
|
|
439
|
+
if (getAttributionByPersonRoute.match(req.method, pathSegments)) {
|
|
440
|
+
const parsed = await getAttributionByPersonRoute.parse(req, res, pathSegments, queryParams);
|
|
441
|
+
if (!parsed) return true;
|
|
442
|
+
const rows = getAttributionByPerson({
|
|
443
|
+
startDate: parsed.query.startDate || undefined,
|
|
444
|
+
endDate: parsed.query.endDate || undefined,
|
|
445
|
+
});
|
|
446
|
+
getAttributionByPersonRoute.respond(res, 200, { rows });
|
|
447
|
+
return true;
|
|
448
|
+
}
|
|
449
|
+
|
|
406
450
|
if (listSessionCosts.match(req.method, pathSegments)) {
|
|
407
451
|
const parsed = await listSessionCosts.parse(req, res, pathSegments, queryParams);
|
|
408
452
|
if (!parsed) return true;
|
package/src/http/tasks.ts
CHANGED
|
@@ -220,7 +220,7 @@ const createTask = route({
|
|
|
220
220
|
agentId: z.string().optional(),
|
|
221
221
|
taskType: z.string().optional(),
|
|
222
222
|
tags: z.array(z.string()).optional(),
|
|
223
|
-
priority: z.number().int().optional(),
|
|
223
|
+
priority: z.number().int().min(0).max(100).optional(),
|
|
224
224
|
dependsOn: z.array(z.string()).optional(),
|
|
225
225
|
offeredTo: z.string().optional(),
|
|
226
226
|
dir: z.string().optional(),
|
|
@@ -760,7 +760,7 @@ export async function handleTasks(
|
|
|
760
760
|
creatorAgentId: myAgentId || undefined,
|
|
761
761
|
taskType: parsed.body.taskType || undefined,
|
|
762
762
|
tags: parsed.body.tags || undefined,
|
|
763
|
-
priority: parsed.body.priority
|
|
763
|
+
priority: parsed.body.priority,
|
|
764
764
|
dependsOn: parsed.body.dependsOn || undefined,
|
|
765
765
|
offeredTo: parsed.body.offeredTo || undefined,
|
|
766
766
|
dir: parsed.body.dir || undefined,
|
package/src/http/users.ts
CHANGED
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
deleteKv,
|
|
33
33
|
deleteUser,
|
|
34
34
|
getAllUsers,
|
|
35
|
+
getDb,
|
|
35
36
|
getUserById,
|
|
36
37
|
listKv,
|
|
37
38
|
updateUser,
|
|
@@ -48,7 +49,7 @@ import {
|
|
|
48
49
|
revokeToken,
|
|
49
50
|
unlinkIdentity,
|
|
50
51
|
} from "../be/users";
|
|
51
|
-
import { UserSchema } from "../types";
|
|
52
|
+
import { UserCommsPrefsSchema, UserSchema } from "../types";
|
|
52
53
|
import { getRequestAuth } from "../utils/request-auth-context";
|
|
53
54
|
import { getOperatorActor } from "./operator-actor";
|
|
54
55
|
import { route } from "./route-def";
|
|
@@ -296,6 +297,11 @@ const updateUserRoute = route({
|
|
|
296
297
|
preferredChannel: z.string().optional(),
|
|
297
298
|
timezone: z.string().optional(),
|
|
298
299
|
metadata: z.record(z.string(), z.unknown()).nullable().optional(),
|
|
300
|
+
comms: UserCommsPrefsSchema.nullable()
|
|
301
|
+
.optional()
|
|
302
|
+
.describe(
|
|
303
|
+
"Merges into metadata.comms without touching sibling metadata keys; null removes only the comms key. When metadata is also provided, it is applied first and replaces the whole blob.",
|
|
304
|
+
),
|
|
299
305
|
dailyBudgetUsd: z.number().nullable().optional(),
|
|
300
306
|
status: z.enum(["invited", "active", "suspended"]).optional(),
|
|
301
307
|
// Complete-list diff: passing this replaces the user's identity set,
|
|
@@ -776,60 +782,63 @@ export async function handleUsers(
|
|
|
776
782
|
}
|
|
777
783
|
|
|
778
784
|
try {
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
785
|
+
const mergedUser = getDb().transaction(() => {
|
|
786
|
+
// Move every identity from source → target.
|
|
787
|
+
for (const ident of sourceBefore.identities) {
|
|
788
|
+
unlinkIdentity(sourceId, ident.kind, ident.externalId, actor);
|
|
789
|
+
linkIdentity(targetId, ident.kind, ident.externalId, actor);
|
|
790
|
+
}
|
|
784
791
|
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
792
|
+
// Merge email aliases — append source.email + source.emailAliases into
|
|
793
|
+
// target.emailAliases (de-duped). Emit `email_added` per added alias.
|
|
794
|
+
const targetAliases = new Set(targetBefore.emailAliases ?? []);
|
|
795
|
+
const targetPrimary = (targetBefore.email ?? "").toLowerCase();
|
|
796
|
+
const newAliases: string[] = [];
|
|
797
|
+
const candidates = [
|
|
798
|
+
...(sourceBefore.email ? [sourceBefore.email] : []),
|
|
799
|
+
...(sourceBefore.emailAliases ?? []),
|
|
800
|
+
];
|
|
801
|
+
for (const candidate of candidates) {
|
|
802
|
+
const lower = candidate.toLowerCase();
|
|
803
|
+
if (!lower || lower === targetPrimary) continue;
|
|
804
|
+
if (
|
|
805
|
+
![...targetAliases].some((a) => a.toLowerCase() === lower) &&
|
|
806
|
+
!newAliases.some((a) => a.toLowerCase() === lower)
|
|
807
|
+
) {
|
|
808
|
+
newAliases.push(candidate);
|
|
809
|
+
}
|
|
802
810
|
}
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
811
|
+
if (newAliases.length > 0) {
|
|
812
|
+
const merged = [...(targetBefore.emailAliases ?? []), ...newAliases];
|
|
813
|
+
updateUser(targetId, { emailAliases: merged });
|
|
814
|
+
for (const alias of newAliases) {
|
|
815
|
+
recordIdentityEvent(targetId, "email_added", actor, null, { email: alias });
|
|
816
|
+
}
|
|
809
817
|
}
|
|
810
|
-
}
|
|
811
818
|
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
819
|
+
// Delete source — CASCADE cleans up any leftover external_ids row that
|
|
820
|
+
// we may have missed. Retained user references move to the target.
|
|
821
|
+
deleteUser(sourceId, targetId);
|
|
822
|
+
|
|
823
|
+
// Single manual_merge event on target capturing the before/after rows.
|
|
824
|
+
// The source row is deleted above, so carry a minimal snapshot of the
|
|
825
|
+
// source user ({id, name, email}) inside the `after` payload under
|
|
826
|
+
// `source` — this lets the UI render "Merged manually from X → Y".
|
|
827
|
+
const targetAfter = composeUser(targetId);
|
|
828
|
+
recordIdentityEvent(targetId, "manual_merge", actor, targetBefore, {
|
|
829
|
+
...targetAfter,
|
|
830
|
+
source: {
|
|
831
|
+
id: sourceBefore.id,
|
|
832
|
+
name: sourceBefore.name,
|
|
833
|
+
email: sourceBefore.email,
|
|
834
|
+
},
|
|
835
|
+
});
|
|
829
836
|
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
837
|
+
// Re-compose AFTER the event so the response surfaces the merge event in
|
|
838
|
+
// recentEvents (otherwise the timeline is missing the event we just wrote).
|
|
839
|
+
return composeUser(targetId);
|
|
840
|
+
})();
|
|
841
|
+
mergeUsersRoute.respond(res, 200, { user: mergedUser });
|
|
833
842
|
} catch (err) {
|
|
834
843
|
jsonError(res, err instanceof Error ? err.message : "Failed to merge users", 500);
|
|
835
844
|
}
|
|
@@ -863,10 +872,23 @@ export async function handleUsers(
|
|
|
863
872
|
}
|
|
864
873
|
|
|
865
874
|
try {
|
|
866
|
-
const { identities, metadata, ...rest } = parsed.body;
|
|
875
|
+
const { identities, metadata, comms, ...rest } = parsed.body;
|
|
867
876
|
// updateUser doesn't accept `metadata: null` directly — passthrough via cast.
|
|
868
877
|
const update: Parameters<typeof updateUser>[1] = { ...rest };
|
|
869
|
-
if (
|
|
878
|
+
if (comms !== undefined) {
|
|
879
|
+
// Merge-safe write: metadata (if provided) is applied first and
|
|
880
|
+
// replaces the whole blob, then comms is merged into it so sibling
|
|
881
|
+
// metadata keys survive.
|
|
882
|
+
const base: Record<string, unknown> = {
|
|
883
|
+
...(metadata !== undefined ? (metadata ?? {}) : (before.metadata ?? {})),
|
|
884
|
+
};
|
|
885
|
+
if (comms === null) {
|
|
886
|
+
delete base.comms;
|
|
887
|
+
} else {
|
|
888
|
+
base.comms = comms;
|
|
889
|
+
}
|
|
890
|
+
update.metadata = Object.keys(base).length > 0 ? base : null;
|
|
891
|
+
} else if (metadata !== undefined) {
|
|
870
892
|
update.metadata = metadata as Record<string, unknown> | null;
|
|
871
893
|
}
|
|
872
894
|
const updated = updateUser(parsed.params.id, update);
|
package/src/http/webhooks.ts
CHANGED
|
@@ -50,7 +50,7 @@ import {
|
|
|
50
50
|
import type { KapsoConfig } from "../integrations/kapso/config";
|
|
51
51
|
import { getKapsoConfig } from "../integrations/kapso/config";
|
|
52
52
|
import type { KapsoWebhookPayload } from "../integrations/kapso/inbound";
|
|
53
|
-
import { routeKapsoInbound } from "../integrations/kapso/inbound";
|
|
53
|
+
import { resolveKapsoRequestedByUserId, routeKapsoInbound } from "../integrations/kapso/inbound";
|
|
54
54
|
import { getExecutorRegistry } from "../workflows";
|
|
55
55
|
import { workflowEventBus } from "../workflows/event-bus";
|
|
56
56
|
import { handleWebhookTrigger, verifyHmacSignature, WebhookError } from "../workflows/triggers";
|
|
@@ -600,7 +600,10 @@ export async function handleWebhooks(
|
|
|
600
600
|
rawBody,
|
|
601
601
|
req.headers,
|
|
602
602
|
getExecutorRegistry(),
|
|
603
|
-
{
|
|
603
|
+
{
|
|
604
|
+
alreadyAuthenticated: true,
|
|
605
|
+
requestedByUserId: resolveKapsoRequestedByUserId(payload),
|
|
606
|
+
},
|
|
604
607
|
);
|
|
605
608
|
break;
|
|
606
609
|
case "no_mapping":
|
package/src/http/workflows.ts
CHANGED
|
@@ -31,7 +31,6 @@ import {
|
|
|
31
31
|
WorkflowSchema,
|
|
32
32
|
WorkflowVersionSchema,
|
|
33
33
|
} from "../types";
|
|
34
|
-
import { getRequestAuth } from "../utils/request-auth-context";
|
|
35
34
|
import { getExecutorRegistry, startWorkflowExecution } from "../workflows";
|
|
36
35
|
import {
|
|
37
36
|
applyDefinitionPatch,
|
|
@@ -827,13 +826,11 @@ export async function handleWorkflows(
|
|
|
827
826
|
return true;
|
|
828
827
|
}
|
|
829
828
|
const body = await parseBody<Record<string, unknown>>(req);
|
|
830
|
-
const auth = getRequestAuth(req);
|
|
831
|
-
|
|
832
829
|
let runId: string;
|
|
833
830
|
try {
|
|
834
831
|
runId = await startWorkflowExecution(workflow, body, getExecutorRegistry(), {
|
|
835
832
|
triggerType: "api",
|
|
836
|
-
requestedByUserId:
|
|
833
|
+
requestedByUserId: resolveHttpAuditUserId(req, myAgentId) ?? undefined,
|
|
837
834
|
});
|
|
838
835
|
} catch (err) {
|
|
839
836
|
if (err instanceof TriggerSchemaError) {
|
|
@@ -80,7 +80,7 @@ function resolveKapsoIdentity(externalId: string): IdentityResolution {
|
|
|
80
80
|
return kapsoResolution;
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
function resolveKapsoRequestedByUserId(payload: KapsoWebhookPayload): string | undefined {
|
|
83
|
+
export function resolveKapsoRequestedByUserId(payload: KapsoWebhookPayload): string | undefined {
|
|
84
84
|
const externalId = normalizeKapsoSender(payload);
|
|
85
85
|
if (!externalId) return undefined;
|
|
86
86
|
|