@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,56 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { getApiKey } from "../utils/api-key.ts";
|
|
4
|
+
import { getMcpBaseUrl } from "../utils/constants.ts";
|
|
5
|
+
import { scrubSecrets } from "../utils/secret-scrubber.ts";
|
|
6
|
+
import {
|
|
7
|
+
auditProfileDivergences,
|
|
8
|
+
type FileReader,
|
|
9
|
+
type ProfileDivergence,
|
|
10
|
+
} from "./profile-sync.ts";
|
|
11
|
+
|
|
12
|
+
export interface ProfileSyncAuditConfig {
|
|
13
|
+
agentId: string;
|
|
14
|
+
apiUrl: string;
|
|
15
|
+
apiKey: string;
|
|
16
|
+
claudeMdPath?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function runProfileSyncAudit(
|
|
20
|
+
config: ProfileSyncAuditConfig,
|
|
21
|
+
deps: { fetchImpl?: typeof fetch; readFile?: FileReader } = {},
|
|
22
|
+
): Promise<{ agentId: string; divergences: ProfileDivergence[] }> {
|
|
23
|
+
const divergences = await auditProfileDivergences(
|
|
24
|
+
{ ...config, fetchImpl: deps.fetchImpl },
|
|
25
|
+
deps.readFile,
|
|
26
|
+
);
|
|
27
|
+
return { agentId: config.agentId, divergences };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function profileSyncAuditExitCode(divergences: ProfileDivergence[]): 0 | 2 {
|
|
31
|
+
return divergences.length > 0 ? 2 : 0;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (import.meta.main) {
|
|
35
|
+
const agentId = process.env.AGENT_ID;
|
|
36
|
+
const apiUrl = getMcpBaseUrl();
|
|
37
|
+
const apiKey = getApiKey();
|
|
38
|
+
if (!agentId || !apiUrl || !apiKey) {
|
|
39
|
+
console.error("profile-sync-audit requires AGENT_ID, MCP_BASE_URL, and an API key");
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
const result = await runProfileSyncAudit({
|
|
45
|
+
agentId,
|
|
46
|
+
apiUrl,
|
|
47
|
+
apiKey,
|
|
48
|
+
});
|
|
49
|
+
console.log(JSON.stringify(result, null, 2));
|
|
50
|
+
process.exit(profileSyncAuditExitCode(result.divergences));
|
|
51
|
+
} catch (error) {
|
|
52
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
53
|
+
console.error(scrubSecrets(`profile-sync-audit failed: ${message}`));
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Harness-agnostic FS → DB profile sync (worker-side, HTTP-only).
|
|
3
3
|
*
|
|
4
4
|
* Persists an agent's self-editable identity / config files back to the API:
|
|
5
|
-
* - SOUL.md / IDENTITY.md / TOOLS.md / HEARTBEAT.md (
|
|
5
|
+
* - SOUL.md / IDENTITY.md / TOOLS.md / HEARTBEAT.md (independent POSTs)
|
|
6
6
|
* - ~/.claude/CLAUDE.md (claude POST)
|
|
7
7
|
* - /workspace/start-up.sh (agent-managed section) (setup POST)
|
|
8
8
|
*
|
|
@@ -27,8 +27,15 @@
|
|
|
27
27
|
* but it must be VISIBLE.
|
|
28
28
|
*/
|
|
29
29
|
|
|
30
|
+
import { resolveTemplateAsync } from "../prompts/resolver.ts";
|
|
31
|
+
import type { Agent, SwarmEvent } from "../types.ts";
|
|
30
32
|
import { MAX_PROFILE_FILE_LENGTH } from "../utils/constants.ts";
|
|
33
|
+
import {
|
|
34
|
+
type BudgetedIdentityField,
|
|
35
|
+
IDENTITY_FIELD_BUDGETS,
|
|
36
|
+
} from "../utils/identity-field-budget.ts";
|
|
31
37
|
import { scrubSecrets } from "../utils/secret-scrubber.ts";
|
|
38
|
+
import "./templates.ts";
|
|
32
39
|
|
|
33
40
|
export const SOUL_MD_PATH = "/workspace/SOUL.md";
|
|
34
41
|
export const IDENTITY_MD_PATH = "/workspace/IDENTITY.md";
|
|
@@ -56,6 +63,223 @@ export function contentSha256(content: string): string {
|
|
|
56
63
|
return new Bun.CryptoHasher("sha256").update(content).digest("hex");
|
|
57
64
|
}
|
|
58
65
|
|
|
66
|
+
export const PROFILE_MARKDOWN_FIELDS = [
|
|
67
|
+
"soulMd",
|
|
68
|
+
"identityMd",
|
|
69
|
+
"claudeMd",
|
|
70
|
+
"toolsMd",
|
|
71
|
+
"heartbeatMd",
|
|
72
|
+
] as const;
|
|
73
|
+
|
|
74
|
+
export type ProfileMarkdownField = (typeof PROFILE_MARKDOWN_FIELDS)[number];
|
|
75
|
+
export type ProfileMarkdownSnapshot = Partial<
|
|
76
|
+
Record<ProfileMarkdownField, string | null | undefined>
|
|
77
|
+
>;
|
|
78
|
+
|
|
79
|
+
export interface ProfileDivergence {
|
|
80
|
+
field: ProfileMarkdownField;
|
|
81
|
+
diskSize: number | null;
|
|
82
|
+
dbSize: number;
|
|
83
|
+
budget: number | null;
|
|
84
|
+
delta: number | null;
|
|
85
|
+
diskHash: string | null;
|
|
86
|
+
dbHash: string;
|
|
87
|
+
diskMissing: boolean;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** Pure disk-vs-DB comparison used by local profile-sync audits. */
|
|
91
|
+
export function findProfileDivergences(
|
|
92
|
+
disk: ProfileMarkdownSnapshot,
|
|
93
|
+
db: ProfileMarkdownSnapshot,
|
|
94
|
+
): ProfileDivergence[] {
|
|
95
|
+
const divergences: ProfileDivergence[] = [];
|
|
96
|
+
|
|
97
|
+
for (const field of PROFILE_MARKDOWN_FIELDS) {
|
|
98
|
+
const diskValue = disk[field];
|
|
99
|
+
const dbValue = db[field] ?? "";
|
|
100
|
+
const budget =
|
|
101
|
+
field === "heartbeatMd" ? null : IDENTITY_FIELD_BUDGETS[field as BudgetedIdentityField];
|
|
102
|
+
if (diskValue === undefined || diskValue === null) {
|
|
103
|
+
if (dbValue.length === 0) continue;
|
|
104
|
+
divergences.push({
|
|
105
|
+
field,
|
|
106
|
+
diskSize: null,
|
|
107
|
+
dbSize: dbValue.length,
|
|
108
|
+
budget,
|
|
109
|
+
delta: null,
|
|
110
|
+
diskHash: null,
|
|
111
|
+
dbHash: contentSha256(dbValue),
|
|
112
|
+
diskMissing: true,
|
|
113
|
+
});
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
if (diskValue === dbValue) continue;
|
|
117
|
+
|
|
118
|
+
divergences.push({
|
|
119
|
+
field,
|
|
120
|
+
diskSize: diskValue.length,
|
|
121
|
+
dbSize: dbValue.length,
|
|
122
|
+
budget,
|
|
123
|
+
delta: diskValue.length - dbValue.length,
|
|
124
|
+
diskHash: contentSha256(diskValue),
|
|
125
|
+
dbHash: contentSha256(dbValue),
|
|
126
|
+
diskMissing: false,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return divergences;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const PROFILE_FIELD_DETAILS: Record<
|
|
134
|
+
BudgetedIdentityField,
|
|
135
|
+
{ label: string; recoveryGuidance: string }
|
|
136
|
+
> = {
|
|
137
|
+
soulMd: {
|
|
138
|
+
label: `soulMd (${SOUL_MD_PATH})`,
|
|
139
|
+
recoveryGuidance: `Inspect and shrink the live ${SOUL_MD_PATH} first, moving durable tail content into memory. After a worker restart, use ${SOUL_MD_PATH}.pre-boot-<timestamp>.bak as the fallback copy of the rejected content.`,
|
|
140
|
+
},
|
|
141
|
+
identityMd: {
|
|
142
|
+
label: `identityMd (${IDENTITY_MD_PATH})`,
|
|
143
|
+
recoveryGuidance: `Inspect and shrink the live ${IDENTITY_MD_PATH} first, moving durable tail content into memory. After a worker restart, use ${IDENTITY_MD_PATH}.pre-boot-<timestamp>.bak as the fallback copy of the rejected content.`,
|
|
144
|
+
},
|
|
145
|
+
claudeMd: {
|
|
146
|
+
label:
|
|
147
|
+
"claudeMd (/workspace/CLAUDE.md for non-Claude harnesses; ~/.claude/CLAUDE.md for Claude)",
|
|
148
|
+
recoveryGuidance:
|
|
149
|
+
"Inspect and shrink the live CLAUDE.md source first, moving durable tail content into memory. After a worker restart, non-Claude harnesses can use /workspace/CLAUDE.md.pre-boot-<timestamp>.bak as the fallback copy; Claude's native ~/.claude/CLAUDE.md source is not archived by that boot step.",
|
|
150
|
+
},
|
|
151
|
+
toolsMd: {
|
|
152
|
+
label: `toolsMd (${TOOLS_MD_PATH})`,
|
|
153
|
+
recoveryGuidance: `Inspect and shrink the live ${TOOLS_MD_PATH} first, moving durable tail content into memory. After a worker restart, use ${TOOLS_MD_PATH}.pre-boot-<timestamp>.bak as the fallback copy of the rejected content.`,
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
/** Render one persisted sync rejection through the prompt-template registry. */
|
|
158
|
+
export async function renderProfileSyncRejectionBanner(event: SwarmEvent): Promise<string | null> {
|
|
159
|
+
const data = event.data;
|
|
160
|
+
const field = data?.field;
|
|
161
|
+
const diskSize = data?.diskSize;
|
|
162
|
+
const dbSize = data?.dbSize;
|
|
163
|
+
const budget = data?.budget;
|
|
164
|
+
const delta = data?.delta;
|
|
165
|
+
if (
|
|
166
|
+
typeof field !== "string" ||
|
|
167
|
+
!(field in PROFILE_FIELD_DETAILS) ||
|
|
168
|
+
typeof diskSize !== "number" ||
|
|
169
|
+
typeof dbSize !== "number" ||
|
|
170
|
+
typeof budget !== "number" ||
|
|
171
|
+
typeof delta !== "number"
|
|
172
|
+
) {
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const details = PROFILE_FIELD_DETAILS[field as BudgetedIdentityField];
|
|
177
|
+
const result = await resolveTemplateAsync("task.profile_sync_rejection", {
|
|
178
|
+
timestamp: event.createdAt,
|
|
179
|
+
field_label: details.label,
|
|
180
|
+
disk_size: diskSize,
|
|
181
|
+
db_size: dbSize,
|
|
182
|
+
budget,
|
|
183
|
+
delta: delta >= 0 ? `+${delta}` : String(delta),
|
|
184
|
+
event_id: event.id,
|
|
185
|
+
recovery_guidance: details.recoveryGuidance,
|
|
186
|
+
});
|
|
187
|
+
return result.skipped ? null : result.text;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/** Fetch every field's latest unresolved rejection before a provider session. */
|
|
191
|
+
export async function fetchProfileSyncRejectionBanner(
|
|
192
|
+
config: Pick<ProfileSyncOptions, "agentId" | "apiUrl" | "apiKey" | "claudeMdPath">,
|
|
193
|
+
fetchImpl: typeof fetch = fetch,
|
|
194
|
+
readFile: FileReader = readFileIfExists,
|
|
195
|
+
): Promise<string> {
|
|
196
|
+
try {
|
|
197
|
+
const responses = await Promise.all(
|
|
198
|
+
(Object.keys(IDENTITY_FIELD_BUDGETS) as BudgetedIdentityField[]).map(async (field) => {
|
|
199
|
+
const fetchLatestEvent = async (event: SwarmEvent["event"]): Promise<SwarmEvent | null> => {
|
|
200
|
+
const query = new URLSearchParams({
|
|
201
|
+
event,
|
|
202
|
+
agentId: config.agentId,
|
|
203
|
+
dataField: field,
|
|
204
|
+
limit: "1",
|
|
205
|
+
});
|
|
206
|
+
const response = await fetchImpl(`${config.apiUrl}/api/events?${query}`, {
|
|
207
|
+
headers: {
|
|
208
|
+
Authorization: `Bearer ${config.apiKey}`,
|
|
209
|
+
"X-Agent-ID": config.agentId,
|
|
210
|
+
},
|
|
211
|
+
});
|
|
212
|
+
if (!response.ok) return null;
|
|
213
|
+
const payload = (await response.json()) as { events?: SwarmEvent[] };
|
|
214
|
+
return payload.events?.[0] ?? null;
|
|
215
|
+
};
|
|
216
|
+
const [rejection, reconciliation] = await Promise.all([
|
|
217
|
+
fetchLatestEvent("system.profile_sync_rejected"),
|
|
218
|
+
fetchLatestEvent("system.profile_sync_reconciled"),
|
|
219
|
+
]);
|
|
220
|
+
return { rejection, reconciliation };
|
|
221
|
+
}),
|
|
222
|
+
);
|
|
223
|
+
const latestEvents = responses.flatMap(({ rejection, reconciliation }) =>
|
|
224
|
+
rejection ? [{ rejection, reconciliation }] : [],
|
|
225
|
+
);
|
|
226
|
+
if (latestEvents.length === 0) return "";
|
|
227
|
+
|
|
228
|
+
let profile: Record<string, unknown> | null = null;
|
|
229
|
+
const profileResponse = await fetchImpl(`${config.apiUrl}/me`, {
|
|
230
|
+
headers: {
|
|
231
|
+
Authorization: `Bearer ${config.apiKey}`,
|
|
232
|
+
"X-Agent-ID": config.agentId,
|
|
233
|
+
},
|
|
234
|
+
});
|
|
235
|
+
if (profileResponse.ok) {
|
|
236
|
+
profile = (await profileResponse.json()) as Record<string, unknown>;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
let disk: Partial<Record<BudgetedIdentityField, string | undefined>> | null = null;
|
|
240
|
+
if (config.claudeMdPath) {
|
|
241
|
+
disk = {
|
|
242
|
+
soulMd: await readFile(SOUL_MD_PATH),
|
|
243
|
+
identityMd: await readFile(IDENTITY_MD_PATH),
|
|
244
|
+
claudeMd: await readFile(config.claudeMdPath),
|
|
245
|
+
toolsMd: await readFile(TOOLS_MD_PATH),
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const unresolved = latestEvents.flatMap(({ rejection, reconciliation }) => {
|
|
250
|
+
if (reconciliation && reconciliation.createdAt > rejection.createdAt) return [];
|
|
251
|
+
const event = rejection;
|
|
252
|
+
const field = event.data?.field;
|
|
253
|
+
const rejectedDbHash = event.data?.dbHash;
|
|
254
|
+
const currentValue = typeof field === "string" ? profile?.[field] : undefined;
|
|
255
|
+
const diskValue =
|
|
256
|
+
typeof field === "string" ? disk?.[field as BudgetedIdentityField] : undefined;
|
|
257
|
+
if (typeof currentValue === "string" && diskValue === currentValue) return [];
|
|
258
|
+
return !(
|
|
259
|
+
typeof rejectedDbHash === "string" &&
|
|
260
|
+
typeof currentValue === "string" &&
|
|
261
|
+
contentSha256(currentValue) !== rejectedDbHash
|
|
262
|
+
)
|
|
263
|
+
? [event]
|
|
264
|
+
: [];
|
|
265
|
+
});
|
|
266
|
+
const banners = await Promise.all(unresolved.map(renderProfileSyncRejectionBanner));
|
|
267
|
+
return banners.filter((banner): banner is string => banner !== null).join("");
|
|
268
|
+
} catch {
|
|
269
|
+
return "";
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
export async function prependProfileSyncRejectionBanner(
|
|
274
|
+
prompt: string,
|
|
275
|
+
config: Pick<ProfileSyncOptions, "agentId" | "apiUrl" | "apiKey" | "claudeMdPath">,
|
|
276
|
+
fetchImpl: typeof fetch = fetch,
|
|
277
|
+
readFile: FileReader = readFileIfExists,
|
|
278
|
+
): Promise<{ prompt: string; injected: boolean }> {
|
|
279
|
+
const banner = await fetchProfileSyncRejectionBanner(config, fetchImpl, readFile);
|
|
280
|
+
return banner ? { prompt: banner + prompt, injected: true } : { prompt, injected: false };
|
|
281
|
+
}
|
|
282
|
+
|
|
59
283
|
export async function writeIdentityBaselines(baselines: IdentityBaselines): Promise<void> {
|
|
60
284
|
await Bun.write(IDENTITY_BASELINES_PATH, JSON.stringify(baselines));
|
|
61
285
|
}
|
|
@@ -168,9 +392,23 @@ export function resolveClaudeMdPath(completedProviders: readonly string[]): stri
|
|
|
168
392
|
}
|
|
169
393
|
|
|
170
394
|
/** A single profile-update POST body, tagged with a label for logging. */
|
|
171
|
-
interface ProfilePayload {
|
|
395
|
+
export interface ProfilePayload {
|
|
172
396
|
label: string;
|
|
173
|
-
body: Record<string,
|
|
397
|
+
body: Record<string, string>;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Keep identity-file sync independent: one rejected ratcheting-budget write
|
|
402
|
+
* must not discard valid edits to other files from the same session.
|
|
403
|
+
*/
|
|
404
|
+
export function buildIndependentIdentityPayloads(
|
|
405
|
+
updates: Record<string, string>,
|
|
406
|
+
changeSource: ProfileChangeSource,
|
|
407
|
+
): ProfilePayload[] {
|
|
408
|
+
return Object.entries(updates).map(([field, value]) => ({
|
|
409
|
+
label: `identity.${field}`,
|
|
410
|
+
body: { [field]: value, changeSource },
|
|
411
|
+
}));
|
|
174
412
|
}
|
|
175
413
|
|
|
176
414
|
/**
|
|
@@ -229,8 +467,6 @@ export function buildIdentityPayload(
|
|
|
229
467
|
const content = files.soulMd;
|
|
230
468
|
if (baselines?.soulMd && contentSha256(content) === baselines.soulMd) {
|
|
231
469
|
// File unchanged during session — skip to preserve Lead's DB edits
|
|
232
|
-
} else if (content.length > MAX_PROFILE_FILE_LENGTH) {
|
|
233
|
-
warnProfileFileTooLarge(agentId, "soulMd", content.length);
|
|
234
470
|
} else if (content.trim()) {
|
|
235
471
|
if (content.length < IDENTITY_FILE_MIN_LENGTH) {
|
|
236
472
|
console.error(
|
|
@@ -246,8 +482,6 @@ export function buildIdentityPayload(
|
|
|
246
482
|
const content = files.identityMd;
|
|
247
483
|
if (baselines?.identityMd && contentSha256(content) === baselines.identityMd) {
|
|
248
484
|
// File unchanged during session — skip to preserve Lead's DB edits
|
|
249
|
-
} else if (content.length > MAX_PROFILE_FILE_LENGTH) {
|
|
250
|
-
warnProfileFileTooLarge(agentId, "identityMd", content.length);
|
|
251
485
|
} else if (content.trim()) {
|
|
252
486
|
if (content.length < IDENTITY_FILE_MIN_LENGTH) {
|
|
253
487
|
console.error(
|
|
@@ -263,8 +497,6 @@ export function buildIdentityPayload(
|
|
|
263
497
|
const content = files.toolsMd;
|
|
264
498
|
if (baselines?.toolsMd && contentSha256(content) === baselines.toolsMd) {
|
|
265
499
|
// File unchanged during session — skip
|
|
266
|
-
} else if (content.length > MAX_PROFILE_FILE_LENGTH) {
|
|
267
|
-
warnProfileFileTooLarge(agentId, "toolsMd", content.length);
|
|
268
500
|
} else if (content.trim()) {
|
|
269
501
|
updates.toolsMd = content;
|
|
270
502
|
}
|
|
@@ -298,6 +530,50 @@ async function readFileIfExists(path: string): Promise<string | undefined> {
|
|
|
298
530
|
}
|
|
299
531
|
}
|
|
300
532
|
|
|
533
|
+
/**
|
|
534
|
+
* Compare the five local profile markdown files with the authenticated agent's
|
|
535
|
+
* stored DB values. This must run inside the agent's local environment; a
|
|
536
|
+
* central script cannot read another worker container's `/workspace` files.
|
|
537
|
+
*/
|
|
538
|
+
export async function auditProfileDivergences(
|
|
539
|
+
opts: Pick<ProfileSyncOptions, "agentId" | "apiUrl" | "apiKey" | "claudeMdPath" | "fetchImpl">,
|
|
540
|
+
readFile: FileReader = readFileIfExists,
|
|
541
|
+
): Promise<ProfileDivergence[]> {
|
|
542
|
+
const doFetch = opts.fetchImpl ?? fetch;
|
|
543
|
+
const response = await doFetch(`${opts.apiUrl}/me`, {
|
|
544
|
+
headers: {
|
|
545
|
+
Authorization: `Bearer ${opts.apiKey}`,
|
|
546
|
+
"X-Agent-ID": opts.agentId,
|
|
547
|
+
},
|
|
548
|
+
});
|
|
549
|
+
if (!response.ok) {
|
|
550
|
+
throw new Error(`Profile divergence audit failed: HTTP ${response.status}`);
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
const stored = (await response.json()) as Agent;
|
|
554
|
+
const claudeMdPath =
|
|
555
|
+
opts.claudeMdPath ??
|
|
556
|
+
(stored.harnessProvider
|
|
557
|
+
? stored.harnessProvider === "claude"
|
|
558
|
+
? CLAUDE_MD_PATH
|
|
559
|
+
: WORKSPACE_CLAUDE_MD_PATH
|
|
560
|
+
: null);
|
|
561
|
+
if (!claudeMdPath) {
|
|
562
|
+
throw new Error(
|
|
563
|
+
"Profile divergence audit requires a registered harness provider or an explicit claudeMdPath",
|
|
564
|
+
);
|
|
565
|
+
}
|
|
566
|
+
const disk: ProfileMarkdownSnapshot = {
|
|
567
|
+
soulMd: await readFile(SOUL_MD_PATH),
|
|
568
|
+
identityMd: await readFile(IDENTITY_MD_PATH),
|
|
569
|
+
claudeMd: await readFile(claudeMdPath),
|
|
570
|
+
toolsMd: await readFile(TOOLS_MD_PATH),
|
|
571
|
+
heartbeatMd: await readFile(HEARTBEAT_MD_PATH),
|
|
572
|
+
};
|
|
573
|
+
|
|
574
|
+
return findProfileDivergences(disk, stored);
|
|
575
|
+
}
|
|
576
|
+
|
|
301
577
|
/**
|
|
302
578
|
* Collect the profile-update POST bodies to send. Each entry is one POST.
|
|
303
579
|
* `fields` selects which groups to include. The file reader is injectable so
|
|
@@ -331,16 +607,12 @@ export async function collectProfilePayloads(
|
|
|
331
607
|
baselines,
|
|
332
608
|
agentId,
|
|
333
609
|
);
|
|
334
|
-
|
|
335
|
-
payloads.push({ label: "identity", body: { ...updates, changeSource } });
|
|
336
|
-
}
|
|
610
|
+
payloads.push(...buildIndependentIdentityPayloads(updates, changeSource));
|
|
337
611
|
}
|
|
338
612
|
|
|
339
613
|
if (fields.includes("claude")) {
|
|
340
614
|
const raw = await readFile(claudeMdPath);
|
|
341
|
-
if (raw
|
|
342
|
-
warnProfileFileTooLarge(agentId, "claudeMd", raw.length);
|
|
343
|
-
} else if (raw?.trim()) {
|
|
615
|
+
if (raw?.trim()) {
|
|
344
616
|
if (baselines?.claudeMd && contentSha256(raw) === baselines.claudeMd) {
|
|
345
617
|
// CLAUDE.md unchanged during session — skip to preserve Lead's DB edits
|
|
346
618
|
} else {
|
|
@@ -444,35 +444,62 @@ export async function buildCredStatusReport(
|
|
|
444
444
|
}
|
|
445
445
|
|
|
446
446
|
/**
|
|
447
|
-
*
|
|
448
|
-
*
|
|
449
|
-
*
|
|
450
|
-
*
|
|
447
|
+
* Strict PUT of credential readiness to the API: propagates network errors
|
|
448
|
+
* and non-2xx responses. The post-credential-wait boot path uses this — after
|
|
449
|
+
* a stale-runtime revival this write is the only transition out of
|
|
450
|
+
* `waiting_for_credentials`, so the caller must be able to observe (and
|
|
451
|
+
* retry) a failure instead of proceeding as though it landed.
|
|
451
452
|
*
|
|
452
453
|
* Posts to the existing `PUT /api/agents/:id/credential-status` endpoint
|
|
453
|
-
* which (per migration 055)
|
|
454
|
-
*
|
|
455
|
-
*
|
|
454
|
+
* which (per migration 055) accepts an optional `cred_status` field. `ready`
|
|
455
|
+
* and `missing` are always included so legacy `agents.credentialMissing` and
|
|
456
|
+
* `agents.status='waiting_for_credentials'` keep tracking; the snapshot is
|
|
457
|
+
* optional so a hiccup while building it cannot lose the transition.
|
|
458
|
+
*/
|
|
459
|
+
export async function sendCredStatusReport(
|
|
460
|
+
apiUrl: string,
|
|
461
|
+
apiKey: string,
|
|
462
|
+
agentId: string,
|
|
463
|
+
runtimeInstanceId: string | undefined,
|
|
464
|
+
report: { ready: boolean; missing: string[]; credStatus?: AgentCredStatus },
|
|
465
|
+
): Promise<void> {
|
|
466
|
+
const res = await fetch(`${apiUrl}/api/agents/${encodeURIComponent(agentId)}/credential-status`, {
|
|
467
|
+
method: "PUT",
|
|
468
|
+
headers: {
|
|
469
|
+
Authorization: `Bearer ${apiKey}`,
|
|
470
|
+
"X-Agent-ID": agentId,
|
|
471
|
+
...(runtimeInstanceId ? { "X-Runtime-Instance-ID": runtimeInstanceId } : {}),
|
|
472
|
+
"Content-Type": "application/json",
|
|
473
|
+
},
|
|
474
|
+
body: JSON.stringify({
|
|
475
|
+
ready: report.ready,
|
|
476
|
+
missing: report.missing,
|
|
477
|
+
...(report.credStatus ? { cred_status: report.credStatus } : {}),
|
|
478
|
+
}),
|
|
479
|
+
});
|
|
480
|
+
if (!res.ok) {
|
|
481
|
+
const body = await res.text().catch(() => "");
|
|
482
|
+
throw new Error(`credential-status report failed: ${res.status} ${body}`.trim());
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* Fire-and-forget wrapper around {@link sendCredStatusReport}. Used by the
|
|
488
|
+
* post-task cache-miss path (`runner.ts`), where a stale dashboard is
|
|
489
|
+
* acceptable and blocking the worker is not.
|
|
456
490
|
*/
|
|
457
491
|
export async function reportCredStatus(
|
|
458
492
|
apiUrl: string,
|
|
459
493
|
apiKey: string,
|
|
460
494
|
agentId: string,
|
|
495
|
+
runtimeInstanceId: string | undefined,
|
|
461
496
|
credStatus: AgentCredStatus,
|
|
462
497
|
): Promise<void> {
|
|
463
498
|
try {
|
|
464
|
-
await
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
"X-Agent-ID": agentId,
|
|
469
|
-
"Content-Type": "application/json",
|
|
470
|
-
},
|
|
471
|
-
body: JSON.stringify({
|
|
472
|
-
ready: credStatus.ready,
|
|
473
|
-
missing: credStatus.missing,
|
|
474
|
-
cred_status: credStatus,
|
|
475
|
-
}),
|
|
499
|
+
await sendCredStatusReport(apiUrl, apiKey, agentId, runtimeInstanceId, {
|
|
500
|
+
ready: credStatus.ready,
|
|
501
|
+
missing: credStatus.missing,
|
|
502
|
+
credStatus,
|
|
476
503
|
});
|
|
477
504
|
} catch (err) {
|
|
478
505
|
console.warn(`[cred-status] POST failed (non-fatal): ${err}`);
|