@desplega.ai/agent-swarm 1.164.1 → 1.166.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 +1 -1
- package/dist/acp-adapter-yzfxn8vj.js +23 -0
- package/dist/{actions-hp2h32dx.js → actions-qz3m692w.js} +24 -28
- package/dist/{amp-adapter-zfd7djyx.js → amp-adapter-j1xbmsqz.js} +7 -7
- package/dist/{app-w2d26h4f.js → app-43vrdmv8.js} +9 -10
- package/dist/{assistant-45pc4en7.js → assistant-ertffmka.js} +25 -29
- package/dist/{boot-reembed-k1q2s4fc.js → boot-reembed-998jtpdg.js} +12 -15
- package/dist/{boot-reembed-6rhcpsjf.js → boot-reembed-s7k7c6v2.js} +13 -15
- package/dist/boot-scrub-sweep-nepsk4t1.js +211 -0
- package/dist/{boot-seeds-ex93edx7.js → boot-seeds-vvzs1zhk.js} +12 -12
- package/dist/{claude-adapter-hcxd0szm.js → claude-adapter-2zvmekrp.js} +15 -17
- package/dist/{claude-managed-adapter-fz7xps2r.js → claude-managed-adapter-s49wbk8t.js} +5 -5
- package/dist/{claude-managed-setup-xx6f15h9.js → claude-managed-setup-cvhqq8qn.js} +4 -4
- package/dist/{claude-sdk-session-6nb9raem.js → claude-sdk-session-kkbxtw5q.js} +2624 -2606
- package/dist/{cli-etbrt8x1.js → cli-0nhdwxd5.js} +4 -4
- package/dist/{cli-jeefgppq.js → cli-0qjcsxgz.js} +7 -7
- package/dist/{cli-6behs2bt.js → cli-32bca7nr.js} +1 -1
- package/dist/{cli-gt8v96qx.js → cli-3ddybbbx.js} +4 -4
- package/dist/{acp-adapter-rxvek4ym.js → cli-3qn4r334.js} +317 -35
- package/dist/{cli-1d3w4xm3.js → cli-4r1sjfc4.js} +14 -6
- package/dist/{cli-691f2rxm.js → cli-66zh26sp.js} +68 -16
- package/dist/{cli-et8wdyqh.js → cli-68r1j4sg.js} +9 -9
- package/dist/{cli-xb7kyanp.js → cli-8kgvmkak.js} +3 -3
- package/dist/{cli-fdpkw8vk.js → cli-8t229cmr.js} +8 -8
- package/dist/{cli-gc54qc0p.js → cli-aqcey741.js} +1 -1
- package/dist/{cli-4q4cmr4t.js → cli-cpfmqz3n.js} +8 -8
- package/dist/{cli-a9bw0xxt.js → cli-df56tqdw.js} +997 -408
- package/dist/{cli-n7h1kqpf.js → cli-dmtrxqhg.js} +6 -1
- package/dist/{cli-xfb7333f.js → cli-dw2q9f7g.js} +5 -5
- package/dist/{cli-4drstbb9.js → cli-ecknp7p1.js} +81 -23
- package/dist/{cli-v0pvvhfq.js → cli-efnd2kce.js} +36 -1
- package/dist/{cli-1wetf34q.js → cli-f2n17zhp.js} +1 -1
- package/dist/{cli-2c8eky5y.js → cli-feh3dkah.js} +1 -1
- package/dist/cli-fn697bnt.js +126 -0
- package/dist/{cli-v5pr2fgt.js → cli-gt8azyet.js} +3 -3
- package/dist/{cli-dbszf3rw.js → cli-h3x613ze.js} +4 -4
- package/dist/{cli-nwhb8y2e.js → cli-hf5s9pgf.js} +1 -1
- package/dist/cli-j2jbr8af.js +516 -0
- package/dist/{cli-agjzafns.js → cli-jhm6hzjn.js} +593 -10
- package/dist/{cli-j0tmc908.js → cli-jvj6a0cv.js} +484 -477
- package/dist/{cli-xxz89c2n.js → cli-mb75wpxf.js} +1 -1
- package/dist/{cli-07s39g1n.js → cli-mv2520nm.js} +1 -1
- package/dist/{cli-v90vfwyb.js → cli-mwegs4af.js} +5 -5
- package/dist/{cli-bz1gbac9.js → cli-p4ztb80h.js} +2 -2
- package/dist/{cli-1wd1n2ya.js → cli-rfphkzh5.js} +1 -1
- package/dist/{cli-976r1zqx.js → cli-rggdq8wq.js} +5 -5
- package/dist/{cli-3ajw5v5v.js → cli-rsy933yz.js} +6 -6
- package/dist/{cli-yj790e19.js → cli-tadfgd0t.js} +8 -1
- package/dist/{cli-cn53e7vc.js → cli-ttbsse3f.js} +6 -1
- package/dist/{cli-dyqsrqcf.js → cli-v2a8x45d.js} +4 -4
- package/dist/{cli-wbvnn6tk.js → cli-v6vv7dy8.js} +91 -9
- package/dist/{cli-z2ap2c0c.js → cli-vzc73wet.js} +90 -55
- package/dist/cli-wt7ccy4r.js +2654 -0
- package/dist/{cli-4cn19jvn.js → cli-x7kpr72a.js} +3 -3
- package/dist/{cli-003785v9.js → cli-xvc3q9br.js} +1 -1
- package/dist/{cli-v0e7jpr5.js → cli-xvdgasgy.js} +13 -4
- package/dist/{cli-asqeg4ve.js → cli-y59h2pk9.js} +2 -2
- package/dist/{cli-0wn3ypqv.js → cli-yshaazs1.js} +14121 -3478
- package/dist/{cli-wg8yjqtw.js → cli-ysnyhws9.js} +16 -3
- package/dist/cli-zp67qg5x.js +92 -0
- package/dist/{cli-g3qgrzck.js → cli-zsh093hk.js} +71 -3
- package/dist/{cli-ma3zvh39.js → cli-zy7vwsne.js} +6066 -5829
- package/dist/cli.js +79 -26
- package/dist/{codex-adapter-pcxdn10v.js → codex-adapter-dw1wxqt8.js} +10 -10
- package/dist/{codex-hook-b1fb7c2k.js → codex-hook-d2rkvf39.js} +1 -1
- package/dist/{codex-login-059nm145.js → codex-login-terbdsqq.js} +2 -2
- package/dist/{codex-session-runner-xzwwddp8.js → codex-session-runner-3cgb8y1g.js} +10 -10
- package/dist/{commands-98at8mkn.js → commands-mhxam6z2.js} +9 -9
- package/dist/{cursor-adapter-dkg6qnkp.js → cursor-adapter-2qda3st7.js} +6 -6
- package/dist/{db-01g8wtvw.js → db-sjks418k.js} +11 -9
- package/dist/{devin-adapter-qmttt2fz.js → devin-adapter-bffjj5n4.js} +2 -2
- package/dist/{dispatcher-nn2k1wxd.js → dispatcher-1es759rn.js} +22 -26
- package/dist/{dsh-adapter-w4d4vwdq.js → dsh-adapter-bek4cyw9.js} +6 -6
- package/dist/{e2b-9e4g2hvt.js → e2b-nd50eccg.js} +1 -1
- package/dist/{event-bus-z7v2t26e.js → event-bus-vnfthafg.js} +2 -2
- package/dist/grok-adapter-ar9cw9jg.js +29 -0
- package/dist/{handlers-b0kqsbg8.js → handlers-1gkbhktr.js} +25 -29
- package/dist/{hook-sap7v1aj.js → hook-ds2zxq9v.js} +16 -18
- package/dist/{hook-pz50gqep.js → hook-vxa3tcsy.js} +10 -12
- package/dist/{http-ncr8rmd0.js → http-3h21z9md.js} +679 -227
- package/dist/{index-c4aqcyz1.js → index-9b65j1m5.js} +11 -11
- package/dist/{index-r46s01nq.js → index-bn6cy8ps.js} +22 -26
- package/dist/{index-38kqdt3e.js → index-dkfxpkmm.js} +23 -27
- package/dist/{index-630kj5vd.js → index-f8xnqrye.js} +55 -43
- package/dist/{index-fdk1t4d6.js → index-n0rxa4ca.js} +11962 -9900
- package/dist/{index-9nrj7797.js → index-n99fycq7.js} +22 -26
- package/dist/{keepalive-31613r2h.js → keepalive-3xspa9jw.js} +14 -11
- package/dist/{lead-mx59tr5s.js → lead-6qphc124.js} +43 -43
- package/dist/{maintenance-55ff39ca.js → maintenance-0teem1bb.js} +10 -12
- package/dist/{node-f0ykebbv.js → node-9sg7ajby.js} +25 -7
- package/dist/{oauth-refresh-sweep-anma954w.js → oauth-refresh-sweep-sh9q25xp.js} +13 -10
- package/dist/{onboard-b2fy8ftb.js → onboard-54qmnqxe.js} +4 -3
- package/dist/{opencode-adapter-p1s92tmy.js → opencode-adapter-wjfa2wvd.js} +6 -6
- package/dist/{otel-impl-9brvt7xv.js → otel-impl-ycqzp2a1.js} +2 -2
- package/dist/{pi-mono-adapter-kz4rrwvd.js → pi-mono-adapter-e77e9zst.js} +6 -6
- package/dist/{pricing-refresh-7w8mbmva.js → pricing-refresh-atnkngqs.js} +10 -10
- package/dist/{rbac-roles-ejp7qwvb.js → rbac-roles-9pjphh9q.js} +10 -10
- package/dist/{rbac-roles-nhk4r7bc.js → rbac-roles-j78wdksm.js} +10 -10
- package/dist/{render-v2-2gzt8skq.js → render-v2-pxjs49fx.js} +9 -10
- package/dist/{setup-5et8t412.js → setup-ymej0xtx.js} +2 -2
- package/dist/{work-objects-tb0er7qa.js → work-objects-3nh4ymzb.js} +26 -30
- package/dist/{worker-62cv075d.js → worker-qa9fkz5s.js} +43 -43
- package/dist/{x-vbxb31jr.js → x-ma4gnfgy.js} +2 -2
- package/openapi.json +457 -31
- package/package.json +14 -6
- package/plugin/commands/create-pr.md +7 -1
- package/plugin/pi-skills/create-pr/SKILL.md +7 -1
- package/src/agentmail/app.ts +5 -4
- package/src/be/automation-preflight.ts +11 -9
- package/src/be/boot-scrub-sweep.ts +302 -0
- package/src/be/connector-codes.ts +81 -0
- package/src/be/crypto/key-bootstrap.ts +1 -1
- package/src/be/db/approvals.ts +15 -1
- package/src/be/db/codex-oauth-device-flows.ts +40 -0
- package/src/be/db/config-secrets.ts +31 -0
- package/src/be/db/runtime.ts +4 -0
- package/src/be/db/script-runs.ts +15 -0
- package/src/be/db/tasks/write.ts +1 -1
- package/src/be/db-queries/mcp-oauth.ts +5 -0
- package/src/be/db-queries/oauth.ts +77 -0
- package/src/be/db.ts +162 -59
- package/src/be/events.ts +17 -1
- package/src/be/memory/index-content.ts +2 -2
- package/src/be/memory/providers/sqlite-store.ts +63 -11
- package/src/be/memory/types.ts +14 -0
- package/src/be/migrations/197_connector_codes.sql +23 -0
- package/src/be/migrations/198_permission_audit_guest.sql +33 -0
- package/src/be/migrations/200_backfill_auto_memory_expiry.sql +20 -0
- package/src/be/migrations/201_workflow_replay_columns.sql +10 -0
- package/src/be/migrations/202_codex_oauth_device_flows.sql +24 -0
- package/src/be/model-tier-resolution.ts +2 -1
- package/src/be/model-validation.ts +1 -1
- package/src/be/pricing-normalize.ts +3 -0
- package/src/be/rbac-audit.ts +2 -1
- package/src/be/scripts/db.ts +28 -4
- package/src/be/scripts/source-secrets.ts +37 -0
- package/src/be/scripts/typecheck.ts +23 -2
- package/src/be/scrub-json.ts +32 -0
- package/src/be/sealed-json.ts +59 -0
- package/src/be/secret-registry.ts +131 -0
- package/src/be/seed-pricing.ts +14 -0
- package/src/be/users.ts +7 -1
- package/src/be/workflow-replay.ts +77 -0
- package/src/cli.tsx +7 -0
- package/src/commands/provider-credentials.ts +46 -8
- package/src/commands/runner.ts +2 -10
- package/src/extensions/contract-types.generated.ts +1 -1
- package/src/github/app.ts +4 -4
- package/src/heartbeat/heartbeat.ts +20 -8
- package/src/hooks/pr-body-guard.ts +1 -1
- package/src/http/agents.ts +1 -0
- package/src/http/approval-requests.ts +1 -0
- package/src/http/apps.ts +3 -0
- package/src/http/auth.ts +4 -1
- package/src/http/codex-oauth-device.ts +8 -10
- package/src/http/codex-oauth-keep-warm.ts +2 -2
- package/src/http/config-values.ts +59 -0
- package/src/http/config.ts +5 -0
- package/src/http/db-query-bounded.ts +3 -0
- package/src/http/db-query-shared.ts +107 -15
- package/src/http/db-query.ts +10 -2
- package/src/http/extensions.ts +1 -0
- package/src/http/index.ts +23 -6
- package/src/http/integrations.ts +1 -38
- package/src/http/ip-rate-limit.ts +82 -0
- package/src/http/kv.ts +38 -4
- package/src/http/mcp-servers.ts +1 -0
- package/src/http/memory.ts +9 -0
- package/src/http/models-catalog.ts +2 -0
- package/src/http/operator-actor.ts +4 -0
- package/src/http/page-proxy.ts +22 -0
- package/src/http/pages.ts +4 -2
- package/src/http/realtime.ts +1 -1
- package/src/http/request-principal.ts +14 -1
- package/src/http/script-connections.ts +8 -0
- package/src/http/script-runs.ts +12 -4
- package/src/http/scripts.ts +15 -0
- package/src/http/session-cost-recompute.ts +3 -2
- package/src/http/tasks.ts +9 -0
- package/src/http/users.ts +226 -0
- package/src/http/workflows.ts +3 -2
- package/src/http.ts +1 -0
- package/src/integrations/kapso/client.ts +3 -1
- package/src/jira/app.ts +2 -2
- package/src/kv-view.ts +324 -0
- package/src/linear/app.ts +2 -2
- package/src/oauth/mcp-wrapper.ts +1 -1
- package/src/prompts/memories.ts +42 -1
- package/src/providers/acp-adapter.ts +85 -24
- package/src/providers/acp-target-catalog.ts +54 -1
- package/src/providers/acp-targets.ts +358 -4
- package/src/providers/amp-adapter.ts +1 -1
- package/src/providers/cursor-adapter.ts +1 -1
- package/src/providers/grok-adapter.ts +186 -0
- package/src/providers/index.ts +5 -1
- package/src/providers/pricing-sources.md +6 -0
- package/src/providers/reasoning-effort.ts +17 -1
- package/src/providers/types.ts +2 -1
- package/src/rbac/can.ts +4 -3
- package/src/rbac/legacy-policy.ts +3 -3
- package/src/rbac/types.ts +6 -0
- package/src/script-workflows/supervisor.ts +11 -2
- package/src/scripts-runtime/eval-harness.ts +2 -12
- package/src/scripts-runtime/executors/quickjs-bundle.ts +152 -0
- package/src/scripts-runtime/executors/quickjs-prelude.ts +285 -0
- package/src/scripts-runtime/executors/quickjs-runner.ts +580 -0
- package/src/scripts-runtime/executors/quickjs-worker.ts +81 -0
- package/src/scripts-runtime/executors/quickjs.ts +196 -0
- package/src/scripts-runtime/executors/registry.ts +2 -0
- package/src/scripts-runtime/executors/sourcemap.ts +79 -0
- package/src/scripts-runtime/script-error-hints.ts +14 -0
- package/src/scripts-runtime/swarm-sdk.ts +9 -2
- package/src/scripts-runtime/types/stdlib.d.ts +27 -8
- package/src/scripts-runtime/types/swarm-extension.d.ts +3 -0
- package/src/scripts-runtime/types/swarm-sdk.d.ts +27 -8
- package/src/server-user.ts +2 -20
- package/src/server.ts +3 -1
- package/src/slack/app.ts +4 -0
- package/src/slack/config.ts +3 -1
- package/src/slack/egress-scrub.ts +87 -0
- package/src/tests/acp-adapter.test.ts +191 -2
- package/src/tests/boot-scrub-sweep.test.ts +390 -0
- package/src/tests/budget-user-scope.test.ts +7 -21
- package/src/tests/check-pr-body.test.ts +149 -6
- package/src/tests/check-text-columns.test.ts +145 -0
- package/src/tests/claude-adapter-binary.test.ts +1 -1
- package/src/tests/claude-sdk-process.fixture.ts +13 -2
- package/src/tests/codex-oauth-device.test.ts +23 -37
- package/src/tests/codex-oauth-keep-warm.test.ts +29 -0
- package/src/tests/console-scrub.test.ts +141 -0
- package/src/tests/credential-check.test.ts +90 -0
- package/src/tests/db-query-denylist.test.ts +202 -0
- package/src/tests/db-task-read-contract.test.ts +1 -0
- package/src/tests/db-task-write-contract.test.ts +1 -0
- package/src/tests/docs-index-footprint.test.js +3 -3
- package/src/tests/entrypoint-acp-target-binary.test.ts +44 -1
- package/src/tests/events-scrub.test.ts +88 -0
- package/src/tests/explicit-model-validation.test.ts +81 -0
- package/src/tests/extensions-pre-task.test.ts +33 -1
- package/src/tests/fixtures/grok/acp-updates-recorded.jsonl +53 -0
- package/src/tests/fixtures/grok/prompt-response-meta.json +36 -0
- package/src/tests/fixtures/secret-corpus.ts +320 -0
- package/src/tests/grok-adapter.test.ts +647 -0
- package/src/tests/heartbeat-checklist.test.ts +44 -0
- package/src/tests/integration-disable-flags.test.ts +156 -0
- package/src/tests/kv-http.test.ts +34 -0
- package/src/tests/kv-tool.test.ts +274 -1
- package/src/tests/kv-view.test.ts +147 -0
- package/src/tests/mcp-user-route.test.ts +257 -15
- package/src/tests/memory-injection-outcome.test.ts +143 -0
- package/src/tests/model-tier-resolution.test.ts +76 -3
- package/src/tests/page-guest-session.test.ts +424 -0
- package/src/tests/page-proxy.test.ts +1 -1
- package/src/tests/page-viewer-auth.test.ts +22 -1
- package/src/tests/pr-body-leaks.test.ts +157 -2
- package/src/tests/preload.ts +10 -0
- package/src/tests/provider-registration.test.ts +3 -1
- package/src/tests/rbac-audit.test.ts +32 -0
- package/src/tests/rbac-mcp-admission-e2e.test.ts +4 -62
- package/src/tests/script-connections.test.ts +9 -0
- package/src/tests/script-executor-conformance.test.ts +3 -0
- package/src/tests/script-executor-quickjs.test.ts +442 -0
- package/src/tests/script-executor-registry.test.ts +6 -1
- package/src/tests/script-runs-http.test.ts +126 -1
- package/src/tests/script-runs-scrub.test.ts +275 -0
- package/src/tests/scripts-http.test.ts +82 -1
- package/src/tests/scripts-mcp-e2e.test.ts +42 -6
- package/src/tests/scripts-runtime.test.ts +37 -0
- package/src/tests/scrubbed-text-12e.test.ts +289 -0
- package/src/tests/sealed-key-guard.test.ts +166 -0
- package/src/tests/secret-canary-sweep.test.ts +958 -0
- package/src/tests/secret-registry.test.ts +355 -0
- package/src/tests/secret-rules.test.ts +230 -0
- package/src/tests/secret-scrubber.test.ts +317 -1
- package/src/tests/session-costs-golden.test.ts +17 -0
- package/src/tests/slack-egress-scrub.test.ts +216 -0
- package/src/tests/swarm-tool-result-gate.test.ts +143 -30
- package/src/tests/task-tools-ctx.test.ts +3 -0
- package/src/tests/user-token-routes.test.ts +342 -3
- package/src/tests/workflow-replay.test.ts +518 -0
- package/src/tests/workflow-scrub.test.ts +242 -0
- package/src/tests/workflow-system-one-decision-providers.test.ts +737 -0
- package/src/tools/db-query.ts +1 -1
- package/src/tools/inject-learning.ts +1 -1
- package/src/tools/kv/kv-get.ts +136 -6
- package/src/tools/send-task.ts +61 -17
- package/src/tools/utils.ts +186 -43
- package/src/tools/workflows/get-workflow-run.ts +3 -2
- package/src/types.ts +16 -1
- package/src/utils/console-scrub-install.ts +5 -0
- package/src/utils/console-scrub.ts +57 -0
- package/src/utils/credentials.ts +8 -0
- package/src/utils/page-session.ts +6 -2
- package/src/utils/pr-body-leaks.ts +149 -10
- package/src/utils/request-auth-context.ts +2 -0
- package/src/utils/secret-rules.generated.ts +2055 -0
- package/src/utils/secret-scrubber.ts +662 -36
- package/src/workflows/engine.ts +39 -4
- package/src/workflows/executors/notify.ts +6 -1
- package/src/workflows/executors/system-one-decision.ts +31 -12
- package/src/workflows/executors/system-one-openai-wire.ts +168 -0
- package/src/workflows/executors/system-one-providers.ts +112 -11
- package/src/workflows/executors/system-one-wire.ts +79 -0
- package/src/workflows/recovery.ts +10 -1
- package/src/workflows/resume.ts +62 -3
- package/src/workflows/retry-poller.ts +3 -0
- package/templates/ai-toolbox.manifest.json +2 -2
- package/templates/skills/agent-browser/SKILL.md +5 -5
- package/templates/skills/agent-browser/config.json +1 -1
- package/templates/skills/agent-browser/content.md +4 -4
- package/templates/skills/artifacts/content.md +17 -7
- package/templates/skills/jira-interaction/config.json +1 -1
- package/templates/skills/jira-interaction/content.md +56 -205
- package/templates/skills/linear-interaction/config.json +1 -1
- package/templates/skills/linear-interaction/content.md +31 -50
- package/templates/skills/pages/content.md +8 -4
- package/templates/skills/qa/content.md +2 -2
- package/templates/skills/workflow-iterate/content.md +4 -4
- package/tsconfig.json +3 -3
- package/dist/boot-scrub-logs-t8xg7wd7.js +0 -99
- package/dist/cli-0a7r5331.js +0 -168
- package/dist/cli-93rxw9yd.js +0 -951
- package/dist/cli-cvk6yzw5.js +0 -40
- package/dist/cli-dgnj0zcc.js +0 -40
- package/dist/cli-qt5wzq6v.js +0 -256
- package/dist/cli-v7fqehqd.js +0 -9281
- package/dist/cli-vbr859rz.js +0 -572
- package/src/be/boot-scrub-logs.ts +0 -132
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API-side registry of every stored secret value.
|
|
3
|
+
*
|
|
4
|
+
* The scrubber's exact-match pass only knows sensitive env values and values
|
|
5
|
+
* registered at runtime. Without this registry, a secret stored before the
|
|
6
|
+
* last restart (an agent-scoped config secret, an OAuth or MCP OAuth token, a
|
|
7
|
+
* script API bearer token) stays unknown until something reads it again, and
|
|
8
|
+
* the boot retro-sweep cannot redact a value it does not know.
|
|
9
|
+
*
|
|
10
|
+
* At boot, `loadSecretRegistry()` decrypts every stored secret and registers
|
|
11
|
+
* it. Each encrypt site calls `registerStoredSecret()` with the new plaintext,
|
|
12
|
+
* so a write after boot is covered without a reload.
|
|
13
|
+
*
|
|
14
|
+
* Feeds the scrubber only through `registerVolatileSecret`, so worker-side
|
|
15
|
+
* code is untouched. Append-only: a deleted or rotated secret stays
|
|
16
|
+
* registered, since redacting a revoked value is still correct. Never logs a
|
|
17
|
+
* value: names are source markers (`config:<KEY>`, `oauth:<provider>:…`,
|
|
18
|
+
* `script-api:<id>`), and load results are counts.
|
|
19
|
+
*/
|
|
20
|
+
import { registerVolatileSecret } from "../utils/secret-scrubber";
|
|
21
|
+
import { listStoredConfigSecrets } from "./db/config-secrets";
|
|
22
|
+
import { listStoredOAuthSecrets, type StoredOAuthSecretKind } from "./db-queries/oauth";
|
|
23
|
+
import { listStoredScriptApiSecrets } from "./scripts/db";
|
|
24
|
+
|
|
25
|
+
export function configSecretName(key: string): string {
|
|
26
|
+
return `config:${key}`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function oauthSecretName(provider: string, kind: StoredOAuthSecretKind): string {
|
|
30
|
+
return `oauth:${provider}:${kind}`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function scriptApiSecretName(id: string): string {
|
|
34
|
+
return `script-api:${id}`;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Base64 text that encodes `value` wherever it sits in a larger byte string.
|
|
39
|
+
* Base64 maps 3 bytes to 4 chars, so the chars depend on the value's byte
|
|
40
|
+
* offset mod 3. For each offset, keep only the chars computed from the value's
|
|
41
|
+
* bytes alone: drop the leading chars that mix in preceding bytes and the
|
|
42
|
+
* trailing chars that depend on following bytes. Offset 0 also keeps the whole
|
|
43
|
+
* padded encoding (the value encoded on its own). This catches
|
|
44
|
+
* `Basic base64(user:secret)` and a secret inside an encoded JSON blob.
|
|
45
|
+
*/
|
|
46
|
+
function base64Forms(value: string): string[] {
|
|
47
|
+
const bytes = Buffer.from(value, "utf8");
|
|
48
|
+
const forms = [bytes.toString("base64")];
|
|
49
|
+
for (const offset of [0, 1, 2]) {
|
|
50
|
+
const shifted = Buffer.concat([Buffer.alloc(offset), bytes]);
|
|
51
|
+
// Offset 1 mixes the prefix into the first 2 chars, offset 2 into the first 3.
|
|
52
|
+
const skip = offset === 0 ? 0 : offset + 1;
|
|
53
|
+
const end = Math.floor(shifted.length / 3) * 4;
|
|
54
|
+
forms.push(shifted.toString("base64").slice(skip, end));
|
|
55
|
+
}
|
|
56
|
+
const urlSafe = forms.map((form) =>
|
|
57
|
+
form.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, ""),
|
|
58
|
+
);
|
|
59
|
+
return [...forms, ...urlSafe];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Encoded forms of a known value: base64 (std and url-safe, see
|
|
64
|
+
* `base64Forms`) and URL percent-encoding. Shell and JSON escaping are not
|
|
65
|
+
* repeated here: `registerVolatileSecret` already adds those forms (and
|
|
66
|
+
* drops any form shorter than the scrubber's minimum length).
|
|
67
|
+
*/
|
|
68
|
+
export function encodedForms(value: string): string[] {
|
|
69
|
+
const forms = new Set(base64Forms(value));
|
|
70
|
+
const uriEncoded = encodeURIComponent(value);
|
|
71
|
+
if (uriEncoded !== value) forms.add(uriEncoded);
|
|
72
|
+
forms.delete(value);
|
|
73
|
+
forms.delete("");
|
|
74
|
+
return [...forms];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Register a stored secret value, plus its encoded forms, with the scrubber. */
|
|
78
|
+
export function registerStoredSecret(value: string | null | undefined, name: string): void {
|
|
79
|
+
if (!value) return;
|
|
80
|
+
registerVolatileSecret(value, name);
|
|
81
|
+
for (const form of encodedForms(value)) registerVolatileSecret(form, name);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface SecretRegistryLoadResult {
|
|
85
|
+
config: number;
|
|
86
|
+
oauth: number;
|
|
87
|
+
scriptApi: number;
|
|
88
|
+
/** Rows that could not be read or decrypted (wrong or missing key). */
|
|
89
|
+
failed: number;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Register every stored secret. Called once at API boot, before the boot
|
|
94
|
+
* retro-sweep. A row that fails to decrypt is counted and skipped; a source
|
|
95
|
+
* that fails as a whole (e.g. no encryption key resolved) is counted as one
|
|
96
|
+
* failure and the other sources still load.
|
|
97
|
+
*/
|
|
98
|
+
export async function loadSecretRegistry(): Promise<SecretRegistryLoadResult> {
|
|
99
|
+
const result: SecretRegistryLoadResult = { config: 0, oauth: 0, scriptApi: 0, failed: 0 };
|
|
100
|
+
|
|
101
|
+
try {
|
|
102
|
+
const { secrets, failed } = await listStoredConfigSecrets();
|
|
103
|
+
for (const { key, value } of secrets) registerStoredSecret(value, configSecretName(key));
|
|
104
|
+
result.config = secrets.length;
|
|
105
|
+
result.failed += failed;
|
|
106
|
+
} catch {
|
|
107
|
+
result.failed += 1;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
try {
|
|
111
|
+
const { secrets, failed } = await listStoredOAuthSecrets();
|
|
112
|
+
for (const { provider, kind, value } of secrets) {
|
|
113
|
+
registerStoredSecret(value, oauthSecretName(provider, kind));
|
|
114
|
+
}
|
|
115
|
+
result.oauth = secrets.length;
|
|
116
|
+
result.failed += failed;
|
|
117
|
+
} catch {
|
|
118
|
+
result.failed += 1;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
try {
|
|
122
|
+
const { secrets, failed } = await listStoredScriptApiSecrets();
|
|
123
|
+
for (const { id, token } of secrets) registerStoredSecret(token, scriptApiSecretName(id));
|
|
124
|
+
result.scriptApi = secrets.length;
|
|
125
|
+
result.failed += failed;
|
|
126
|
+
} catch {
|
|
127
|
+
result.failed += 1;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return result;
|
|
131
|
+
}
|
package/src/be/seed-pricing.ts
CHANGED
|
@@ -273,6 +273,14 @@ export function buildModelsDevSeedRows(cache: ModelsDevCache): PricingSeedRow[]
|
|
|
273
273
|
}
|
|
274
274
|
}
|
|
275
275
|
|
|
276
|
+
// ---- Grok CLI (bare xAI ids, billed at xAI's API rates via XAI_API_KEY) --
|
|
277
|
+
for (const [id, model] of Object.entries(cache.xai?.models ?? {})) {
|
|
278
|
+
if (!model?.cost) continue;
|
|
279
|
+
for (const row of projectCostBlock("grok", id, model.cost, { anthropicBilled: false })) {
|
|
280
|
+
rows.push(row);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
276
284
|
// ---- DeepSeek direct API (dsh with DEEPSEEK_API_KEY, bare ids) ---------
|
|
277
285
|
const deepseek = cache.deepseek?.models ?? {};
|
|
278
286
|
for (const [id, model] of Object.entries(deepseek)) {
|
|
@@ -307,6 +315,12 @@ export function buildModelsDevSeedRows(cache: ModelsDevCache): PricingSeedRow[]
|
|
|
307
315
|
})) {
|
|
308
316
|
rows.push(row);
|
|
309
317
|
}
|
|
318
|
+
// grok runs `openrouter/<id>` models as OpenAI-compatible BYOK models.
|
|
319
|
+
for (const row of projectCostBlock("grok", id, model.cost, {
|
|
320
|
+
anthropicBilled: id.startsWith("anthropic/"),
|
|
321
|
+
})) {
|
|
322
|
+
rows.push(row);
|
|
323
|
+
}
|
|
310
324
|
// Gemini specifically: also project under the 'gemini' provider so
|
|
311
325
|
// internal-ai callers that tag with provider='gemini' find a hit.
|
|
312
326
|
if (id.startsWith("google/")) {
|
package/src/be/users.ts
CHANGED
|
@@ -456,6 +456,7 @@ export async function mintToken(
|
|
|
456
456
|
userId: string,
|
|
457
457
|
label: string | null,
|
|
458
458
|
actor: IdentityActor,
|
|
459
|
+
options: { source?: string } = {},
|
|
459
460
|
): Promise<{ tokenId: string; plaintext: string }> {
|
|
460
461
|
// 24 base62 chars from 24 random bytes (~143 bits of entropy).
|
|
461
462
|
const plaintext = `${TOKEN_PREFIX}${base62(randomBytes(24))}`;
|
|
@@ -470,7 +471,12 @@ export async function mintToken(
|
|
|
470
471
|
VALUES (?, ?, ?, ?, ?, ?)`,
|
|
471
472
|
[tokenId, userId, label, hash, preview, now],
|
|
472
473
|
);
|
|
473
|
-
await recordIdentityEvent(userId, "token_minted", actor, null, {
|
|
474
|
+
await recordIdentityEvent(userId, "token_minted", actor, null, {
|
|
475
|
+
tokenId,
|
|
476
|
+
label,
|
|
477
|
+
preview,
|
|
478
|
+
...(options.source ? { source: options.source } : {}),
|
|
479
|
+
});
|
|
474
480
|
});
|
|
475
481
|
|
|
476
482
|
return { tokenId, plaintext };
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { openSealedJson } from "./sealed-json";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Which copy of a workflow payload a reader gets.
|
|
5
|
+
*
|
|
6
|
+
* - `replay`: the exact value from the sealed `*_replay` column. Resume, retry,
|
|
7
|
+
* dedup and recovery rebuild the live ctx from it, so a downstream consumer
|
|
8
|
+
* sees the same bytes after a restart as in the uninterrupted run.
|
|
9
|
+
* - `display`: the scrubbed column, for API responses, MCP tools and the UI.
|
|
10
|
+
*/
|
|
11
|
+
export type WorkflowPayloadView = "replay" | "display";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A sealed replay copy exists but cannot be opened (missing or rotated
|
|
15
|
+
* encryption key, corrupt ciphertext). The scrubbed copy holds redaction
|
|
16
|
+
* markers, so replaying it would silently feed them to downstream nodes: the
|
|
17
|
+
* run fails with this error instead.
|
|
18
|
+
*/
|
|
19
|
+
export class WorkflowReplayStateError extends Error {
|
|
20
|
+
constructor(
|
|
21
|
+
readonly runId: string,
|
|
22
|
+
readonly target: string,
|
|
23
|
+
cause: unknown,
|
|
24
|
+
) {
|
|
25
|
+
super(
|
|
26
|
+
`Workflow run ${runId} cannot replay ${target}: its sealed replay copy could not be opened (${
|
|
27
|
+
cause instanceof Error ? cause.message : String(cause)
|
|
28
|
+
}). The redacted copy is never replayed. Restore the SECRETS_ENCRYPTION_KEY that sealed it, then retry the run.`,
|
|
29
|
+
);
|
|
30
|
+
this.name = "WorkflowReplayStateError";
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Set `target[key]` from a workflow payload pair.
|
|
36
|
+
*
|
|
37
|
+
* `display` parses the scrubbed column. `replay` opens the sealed column
|
|
38
|
+
* lazily, on first read of the property: status-only readers (cancel, polls,
|
|
39
|
+
* cooldown) never decrypt and keep working without the key. Rows written before
|
|
40
|
+
* the replay columns existed have no sealed copy and fall back to the plain
|
|
41
|
+
* column.
|
|
42
|
+
*/
|
|
43
|
+
export function defineWorkflowPayload<T extends object>(
|
|
44
|
+
target: T,
|
|
45
|
+
key: keyof T & string,
|
|
46
|
+
plain: string | null | undefined,
|
|
47
|
+
sealed: string | null | undefined,
|
|
48
|
+
view: WorkflowPayloadView,
|
|
49
|
+
where: { runId: string; target: string },
|
|
50
|
+
): T {
|
|
51
|
+
if (view === "display" || !sealed) {
|
|
52
|
+
(target as Record<string, unknown>)[key] = plain ? JSON.parse(plain) : undefined;
|
|
53
|
+
return target;
|
|
54
|
+
}
|
|
55
|
+
let opened = false;
|
|
56
|
+
let value: unknown;
|
|
57
|
+
Object.defineProperty(target, key, {
|
|
58
|
+
enumerable: true,
|
|
59
|
+
configurable: true,
|
|
60
|
+
get() {
|
|
61
|
+
if (!opened) {
|
|
62
|
+
try {
|
|
63
|
+
value = openSealedJson(sealed);
|
|
64
|
+
} catch (err) {
|
|
65
|
+
throw new WorkflowReplayStateError(where.runId, where.target, err);
|
|
66
|
+
}
|
|
67
|
+
opened = true;
|
|
68
|
+
}
|
|
69
|
+
return value;
|
|
70
|
+
},
|
|
71
|
+
set(next: unknown) {
|
|
72
|
+
value = next;
|
|
73
|
+
opened = true;
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
return target;
|
|
77
|
+
}
|
package/src/cli.tsx
CHANGED
|
@@ -7,6 +7,7 @@ import type { ComponentType } from "react";
|
|
|
7
7
|
import { createElement, useEffect, useState } from "react";
|
|
8
8
|
import pkg from "../package.json";
|
|
9
9
|
import { getApiKey, setApiKey } from "./utils/api-key.ts";
|
|
10
|
+
import { installConsoleScrub } from "./utils/console-scrub.ts";
|
|
10
11
|
|
|
11
12
|
// Get CLI name from bin field (assumes single key)
|
|
12
13
|
const binName = Object.keys(pkg.bin)[0];
|
|
@@ -543,6 +544,9 @@ function WorkerRunner({
|
|
|
543
544
|
const { exit } = useApp();
|
|
544
545
|
|
|
545
546
|
useEffect(() => {
|
|
547
|
+
// Inside the effect, not before render(): Ink's console patch would
|
|
548
|
+
// replace a wrap installed earlier.
|
|
549
|
+
installConsoleScrub();
|
|
546
550
|
import("./commands/worker.ts")
|
|
547
551
|
.then(({ runWorker }) =>
|
|
548
552
|
runWorker({
|
|
@@ -568,6 +572,9 @@ function LeadRunner({ prompt, yolo, systemPrompt, systemPromptFile, additionalAr
|
|
|
568
572
|
const { exit } = useApp();
|
|
569
573
|
|
|
570
574
|
useEffect(() => {
|
|
575
|
+
// Inside the effect, not before render(): Ink's console patch would
|
|
576
|
+
// replace a wrap installed earlier.
|
|
577
|
+
installConsoleScrub();
|
|
571
578
|
import("./commands/lead.ts")
|
|
572
579
|
.then(({ runLead }) =>
|
|
573
580
|
runLead({
|
|
@@ -27,6 +27,7 @@ import { hasCodexOAuthPoolSlots } from "../providers/codex-oauth/env-keys";
|
|
|
27
27
|
import { checkCursorCredentials } from "../providers/cursor-adapter";
|
|
28
28
|
import { checkDevinCredentials } from "../providers/devin-adapter";
|
|
29
29
|
import { checkDshCredentials } from "../providers/dsh-adapter";
|
|
30
|
+
import { checkGrokCredentials } from "../providers/grok-adapter";
|
|
30
31
|
import { checkOpencodeCredentials } from "../providers/opencode-adapter";
|
|
31
32
|
import type { CredCheckOptions, CredStatus } from "../providers/types";
|
|
32
33
|
import type {
|
|
@@ -50,7 +51,8 @@ export type SupportedProvider =
|
|
|
50
51
|
| "acp"
|
|
51
52
|
| "dsh"
|
|
52
53
|
| "cursor"
|
|
53
|
-
| "amp"
|
|
54
|
+
| "amp"
|
|
55
|
+
| "grok";
|
|
54
56
|
|
|
55
57
|
/**
|
|
56
58
|
* True when the pi harness authenticates against Bedrock rather than a provider
|
|
@@ -117,6 +119,7 @@ export const REQUIRED_CRED_VARS_BY_PROVIDER: Record<SupportedProvider, readonly
|
|
|
117
119
|
dsh: ["DEEPSEEK_API_KEY", "OPENROUTER_API_KEY"],
|
|
118
120
|
amp: ["AMP_API_KEY"],
|
|
119
121
|
cursor: ["CURSOR_API_KEY"],
|
|
122
|
+
grok: ["XAI_API_KEY", "OPENROUTER_API_KEY"],
|
|
120
123
|
};
|
|
121
124
|
|
|
122
125
|
type CredentialChecker = (
|
|
@@ -129,6 +132,7 @@ export const CREDENTIAL_PROVIDER_CHECKERS: Record<SupportedProvider, CredentialC
|
|
|
129
132
|
dsh: (env) => checkDshCredentials(env),
|
|
130
133
|
amp: (env) => checkAmpCredentials(env),
|
|
131
134
|
cursor: (env) => checkCursorCredentials(env),
|
|
135
|
+
grok: (env) => checkGrokCredentials(env),
|
|
132
136
|
claude: (env) => checkClaudeCredentials(env),
|
|
133
137
|
"claude-managed": (env) => checkClaudeManagedCredentials(env),
|
|
134
138
|
codex: (env, opts) => checkCodexCredentials(env, opts),
|
|
@@ -269,6 +273,20 @@ async function checkOpenAiApiKey(apiKey: string): Promise<LiveValidationResult>
|
|
|
269
273
|
};
|
|
270
274
|
}
|
|
271
275
|
|
|
276
|
+
/** `GET /v1/models` is the call the Grok CLI makes first; it runs no inference. */
|
|
277
|
+
async function checkXaiApiKey(apiKey: string): Promise<LiveValidationResult> {
|
|
278
|
+
const r = await timedFetch("https://api.x.ai/v1/models", {
|
|
279
|
+
method: "GET",
|
|
280
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
281
|
+
});
|
|
282
|
+
if (r.ok) return { ok: true, latency_ms: r.latency_ms };
|
|
283
|
+
return {
|
|
284
|
+
ok: false,
|
|
285
|
+
error: scrubSecrets(`HTTP ${r.status}: ${r.bodyText.slice(0, 200)}`),
|
|
286
|
+
latency_ms: r.latency_ms,
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
|
|
272
290
|
async function checkOpenRouter(apiKey: string): Promise<LiveValidationResult> {
|
|
273
291
|
const r = await timedFetch(`${getOpenRouterBaseUrl()}/models`, {
|
|
274
292
|
method: "GET",
|
|
@@ -324,8 +342,8 @@ function parseCodexOAuthAccess(blob: string | undefined): string | null {
|
|
|
324
342
|
* | `claude` | default route: Foundry / Bedrock / Vertex → gateway (`ANTHROPIC_BASE_URL` + `ANTHROPIC_AUTH_TOKEN` or `ANTHROPIC_API_KEY`) → `CLAUDE_CODE_OAUTH_TOKEN` → `ANTHROPIC_API_KEY` | the route's own `/v1/models`; OAuth presence-only; cloud routes skipped |
|
|
325
343
|
* | `claude-managed` | `ANTHROPIC_API_KEY` (managed agents always use API key + managed envs) | Anthropic `/v1/models` |
|
|
326
344
|
* | `codex` | `~/.codex/auth.json` (file) → `CODEX_OAUTH` (env OAuth) → `OPENAI_API_KEY` | OpenAI `/v1/models` (api-key path only) |
|
|
327
|
-
* | `opencode` | `OPENROUTER_API_KEY` → `ANTHROPIC_API_KEY` → `OPENAI_API_KEY`
|
|
328
|
-
* | `pi` |
|
|
345
|
+
* | `opencode` | auth.json (file) → `OPENROUTER_API_KEY` → `ANTHROPIC_API_KEY` → `OPENAI_API_KEY` | file presence-only, otherwise provider's `/v1/models` |
|
|
346
|
+
* | `pi` | auth.json (file) → provider API keys, including model-specific keys | file/model-specific key presence-only, otherwise provider's `/v1/models` |
|
|
329
347
|
* | `acp` | target-specific (the ACP target process owns its own auth) | presence-only (validated by the target process) |
|
|
330
348
|
* | `pi` (bedrock) | `MODEL_OVERRIDE=amazon-bedrock/*` → AWS SDK default credential chain | presence-only (real check is the worker-side Bedrock enumeration) |
|
|
331
349
|
* | `devin` | `DEVIN_API_KEY` (+ `DEVIN_API_BASE_URL` override) | `${baseUrl}/v3/self` |
|
|
@@ -333,10 +351,13 @@ function parseCodexOAuthAccess(blob: string | undefined): string | null {
|
|
|
333
351
|
*
|
|
334
352
|
* Returns `{ok: true, latency_ms}` on 2xx, `{ok: false, error, latency_ms}`
|
|
335
353
|
* otherwise. Errors are scrubbed via `scrubSecrets` before being returned.
|
|
354
|
+
* Reports pass their existing presence result so pi/opencode do not repeat
|
|
355
|
+
* that check.
|
|
336
356
|
*/
|
|
337
357
|
export async function validateProviderCredentials(
|
|
338
358
|
provider: string,
|
|
339
359
|
env: Record<string, string | undefined> = process.env,
|
|
360
|
+
presence?: CredStatus,
|
|
340
361
|
): Promise<LiveValidationResult> {
|
|
341
362
|
const startedAt = Date.now();
|
|
342
363
|
|
|
@@ -410,12 +431,18 @@ export async function validateProviderCredentials(
|
|
|
410
431
|
if (provider === "pi" && isBedrockMode(env)) {
|
|
411
432
|
return presenceCheckOk();
|
|
412
433
|
}
|
|
413
|
-
|
|
414
|
-
//
|
|
415
|
-
//
|
|
434
|
+
const status = presence ?? (await checkProviderCredentials(provider, env));
|
|
435
|
+
// The adapters prefer their auth.json over env keys. Reuse that
|
|
436
|
+
// decision, including any injected filesystem probe used by reports.
|
|
437
|
+
if (status.ready && status.satisfiedBy === "file") return presenceCheckOk();
|
|
438
|
+
// Preserve the live-probe order for supported env keys:
|
|
439
|
+
// OPENROUTER → ANTHROPIC → OPENAI.
|
|
416
440
|
if (env.OPENROUTER_API_KEY) return checkOpenRouter(env.OPENROUTER_API_KEY);
|
|
417
441
|
if (env.ANTHROPIC_API_KEY) return checkAnthropicApiKey(env.ANTHROPIC_API_KEY);
|
|
418
442
|
if (env.OPENAI_API_KEY) return checkOpenAiApiKey(env.OPENAI_API_KEY);
|
|
443
|
+
// Model-specific keys (e.g. GEMINI_API_KEY) can satisfy readiness
|
|
444
|
+
// without a probeable endpoint. The harness validates them at inference.
|
|
445
|
+
if (status.ready) return presenceCheckOk();
|
|
419
446
|
return {
|
|
420
447
|
ok: false,
|
|
421
448
|
error:
|
|
@@ -488,12 +515,23 @@ export async function validateProviderCredentials(
|
|
|
488
515
|
? { ok: true, latency_ms: Date.now() - startedAt }
|
|
489
516
|
: { ok: false, error: result.error, latency_ms: Date.now() - startedAt };
|
|
490
517
|
}
|
|
518
|
+
case "grok": {
|
|
519
|
+
const apiKey = env.XAI_API_KEY?.trim();
|
|
520
|
+
if (apiKey) return checkXaiApiKey(apiKey);
|
|
521
|
+
const openRouterKey = env.OPENROUTER_API_KEY?.trim();
|
|
522
|
+
if (openRouterKey) return checkOpenRouter(openRouterKey);
|
|
523
|
+
return {
|
|
524
|
+
ok: false,
|
|
525
|
+
error: "Set XAI_API_KEY or OPENROUTER_API_KEY for grok.",
|
|
526
|
+
latency_ms: Date.now() - startedAt,
|
|
527
|
+
};
|
|
528
|
+
}
|
|
491
529
|
case "acp":
|
|
492
530
|
return presenceCheckOk();
|
|
493
531
|
default:
|
|
494
532
|
return {
|
|
495
533
|
ok: false,
|
|
496
|
-
error: `Unknown provider "${provider}". Supported: claude, claude-managed, codex, devin, opencode, pi, acp, dsh, cursor, amp.`,
|
|
534
|
+
error: `Unknown provider "${provider}". Supported: claude, claude-managed, codex, devin, opencode, pi, acp, dsh, cursor, amp, grok.`,
|
|
497
535
|
latency_ms: Date.now() - startedAt,
|
|
498
536
|
};
|
|
499
537
|
}
|
|
@@ -534,7 +572,7 @@ export async function buildCredStatusReport(
|
|
|
534
572
|
): Promise<AgentCredStatus> {
|
|
535
573
|
const presence = await checkProviderCredentials(provider, env, opts);
|
|
536
574
|
let liveTest: AgentCredStatus["liveTest"] = null;
|
|
537
|
-
const live = presence.ready ? await validateProviderCredentials(provider, env) : null;
|
|
575
|
+
const live = presence.ready ? await validateProviderCredentials(provider, env, presence) : null;
|
|
538
576
|
if (live && !live.skipped) {
|
|
539
577
|
liveTest = {
|
|
540
578
|
ok: live.ok,
|
package/src/commands/runner.ts
CHANGED
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
generateDefaultSoulMd,
|
|
19
19
|
generateDefaultToolsMd,
|
|
20
20
|
} from "../prompts/defaults.ts";
|
|
21
|
-
import { renderMemoriesPrompt } from "../prompts/memories.ts";
|
|
21
|
+
import { type RelevantMemory, renderMemoriesPrompt } from "../prompts/memories.ts";
|
|
22
22
|
import { configureHttpResolver, resolveTemplateAsync } from "../prompts/resolver.ts";
|
|
23
23
|
import { renderSteeringDelivery } from "../prompts/steering-delivery.ts";
|
|
24
24
|
import { authJsonToCredentialSelection } from "../providers/codex-oauth/auth-json.js";
|
|
@@ -3564,15 +3564,7 @@ async function fetchRelevantMemories(
|
|
|
3564
3564
|
|
|
3565
3565
|
if (!response.ok) return null;
|
|
3566
3566
|
|
|
3567
|
-
const data = (await response.json()) as {
|
|
3568
|
-
results: Array<{
|
|
3569
|
-
id: string;
|
|
3570
|
-
name: string;
|
|
3571
|
-
content: string;
|
|
3572
|
-
similarity: number;
|
|
3573
|
-
rawSimilarity?: number;
|
|
3574
|
-
}>;
|
|
3575
|
-
};
|
|
3567
|
+
const data = (await response.json()) as { results: RelevantMemory[] };
|
|
3576
3568
|
|
|
3577
3569
|
return renderMemoriesPrompt(data.results || []);
|
|
3578
3570
|
} catch {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// Generated by scripts/bundle-extension-types.ts. Do not edit.
|
|
2
2
|
// biome-ignore-all lint/suspicious/noTemplateCurlyInString: Type declarations contain literal template placeholders.
|
|
3
3
|
export const EXTENSION_TYPE_DEFINITIONS =
|
|
4
|
-
'// biome-ignore-all lint/suspicious/noConfusingVoidType: Extension handlers may explicitly return no result.\ndeclare module "swarm-extension" {\n export type CreateTaskOptions = {\n key?: string | undefined;\n agentId?: string | null | undefined;\n creatorAgentId?: string | undefined;\n source?:\n | "workflow"\n | "schedule"\n | "slack"\n | "agentmail"\n | "mcp"\n | "api"\n | "ui"\n | "github"\n | "gitlab"\n | "azure-devops"\n | "system"\n | "linear"\n | "jira"\n | "comb"\n | undefined;\n routingReason?:\n | "skill"\n | "continuity"\n | "overflow"\n | "human_pinned"\n | "reroute_fault"\n | undefined;\n routingSource?: "declared" | "engine_default" | undefined;\n routingNote?: string | undefined;\n taskType?: string | undefined;\n tags?: string[] | undefined;\n priority?: number | undefined;\n dependsOn?: string[] | undefined;\n offeredTo?: string | undefined;\n status?: "draft" | "backlog" | "unassigned" | undefined;\n slackChannelId?: string | undefined;\n slackThreadTs?: string | undefined;\n slackTriggerMessageTs?: string | undefined;\n slackUserId?: string | undefined;\n overrideSlackContext?: boolean | undefined;\n vcsProvider?: "github" | "gitlab" | "azure-devops" | undefined;\n vcsRepo?: string | undefined;\n vcsEventType?: string | undefined;\n vcsNumber?: number | undefined;\n vcsCommentId?: number | undefined;\n vcsAuthor?: string | undefined;\n vcsUrl?: string | undefined;\n vcsInstallationId?: number | undefined;\n vcsNodeId?: string | undefined;\n agentmailInboxId?: string | undefined;\n agentmailMessageId?: string | undefined;\n agentmailThreadId?: string | undefined;\n mentionMessageId?: string | undefined;\n mentionChannelId?: string | undefined;\n dir?: string | undefined;\n parentTaskId?: string | undefined;\n model?: string | undefined;\n modelTier?: "smol" | "regular" | "smart" | "ultra" | undefined;\n effort?: "off" | "low" | "medium" | "high" | "xhigh" | "max" | undefined;\n scheduleId?: string | undefined;\n workflowRunId?: string | undefined;\n workflowRunStepId?: string | undefined;\n sourceTaskId?: string | undefined;\n outputSchema?: Record<string, unknown> | undefined;\n inheritParentOutputSchema?: boolean | undefined;\n inheritParentRoutingAffinity?: boolean | undefined;\n inheritParentFollowUpConfig?: boolean | undefined;\n followUpConfig?:\n | {\n disabled?: boolean | undefined;\n onCompleted?: string | undefined;\n onFailed?: string | undefined;\n }\n | undefined;\n requestedByUserId?: string | undefined;\n contextKey?: string | undefined;\n bypassTrackerContextDedup?: boolean | undefined;\n routingAffinity?:\n | {\n capabilities: string[];\n sourceAgentId?: string | undefined;\n role?: string | undefined;\n harnessProvider?:\n | "claude"\n | "codex"\n | "pi"\n | "devin"\n | "claude-managed"\n | "opencode"\n | "acp"\n | "dsh"\n | "amp"\n | "cursor"\n | undefined;\n leadOnly?: boolean | undefined;\n }\n | undefined;\n };\n\n export type AgentTask = {\n id: string;\n key: string;\n agentId: string | null;\n task: string;\n status:\n | "draft"\n | "backlog"\n | "unassigned"\n | "offered"\n | "reviewing"\n | "pending"\n | "in_progress"\n | "paused"\n | "completed"\n | "failed"\n | "cancelled"\n | "superseded";\n source:\n | "workflow"\n | "schedule"\n | "slack"\n | "agentmail"\n | "mcp"\n | "api"\n | "ui"\n | "github"\n | "gitlab"\n | "azure-devops"\n | "system"\n | "linear"\n | "jira"\n | "comb";\n tags: string[];\n priority: number;\n dependsOn: string[];\n createdAt: string;\n lastUpdatedAt: string;\n slackReplySent: boolean;\n wasPaused: boolean;\n creatorAgentId?: string | undefined;\n title?: string | undefined;\n routingReason?:\n | "skill"\n | "continuity"\n | "overflow"\n | "human_pinned"\n | "reroute_fault"\n | undefined;\n routingSource?: "declared" | "engine_default" | undefined;\n routingNote?: string | undefined;\n taskType?: string | undefined;\n offeredTo?: string | undefined;\n offeredAt?: string | undefined;\n acceptedAt?: string | undefined;\n rejectionReason?: string | undefined;\n finishedAt?: string | undefined;\n notifiedAt?: string | undefined;\n failureReason?: string | undefined;\n output?: string | undefined;\n progress?: string | undefined;\n slackChannelId?: string | undefined;\n slackThreadTs?: string | undefined;\n slackTriggerMessageTs?: string | undefined;\n slackUserId?: string | undefined;\n slackProgressMessageTs?: string | undefined;\n slackTreeRootMessageTs?: string | undefined;\n vcsProvider?: "github" | "gitlab" | "azure-devops" | undefined;\n vcsRepo?: string | undefined;\n vcsEventType?: string | undefined;\n vcsNumber?: number | undefined;\n vcsCommentId?: number | undefined;\n vcsAuthor?: string | undefined;\n vcsUrl?: string | undefined;\n vcsInstallationId?: number | undefined;\n vcsNodeId?: string | undefined;\n agentmailInboxId?: string | undefined;\n agentmailMessageId?: string | undefined;\n agentmailThreadId?: string | undefined;\n mentionMessageId?: string | undefined;\n mentionChannelId?: string | undefined;\n dir?: string | undefined;\n parentTaskId?: string | undefined;\n claudeSessionId?: string | undefined;\n model?: string | undefined;\n modelTier?: "smol" | "regular" | "smart" | "ultra" | undefined;\n effort?: "off" | "low" | "medium" | "high" | "xhigh" | "max" | undefined;\n resolvedModel?: string | undefined;\n modelSource?: string | undefined;\n modelAlias?: string | undefined;\n scheduleId?: string | undefined;\n workflowRunId?: string | null | undefined;\n workflowRunStepId?: string | null | undefined;\n contextKey?: string | undefined;\n outputSchema?: Record<string, unknown> | undefined;\n followUpConfig?:\n | {\n disabled?: boolean | undefined;\n onCompleted?: string | undefined;\n onFailed?: string | undefined;\n }\n | undefined;\n deferredAt?: string | undefined;\n compactionCount?: number | undefined;\n peakContextPercent?: number | undefined;\n peakContextTokens?: number | undefined;\n contextWindowSize?: number | undefined;\n credentialKeySuffix?: string | undefined;\n credentialKeyType?: string | undefined;\n requestedByUserId?: string | undefined;\n swarmVersion?: string | undefined;\n provider?:\n | "claude"\n | "codex"\n | "pi"\n | "devin"\n | "claude-managed"\n | "opencode"\n | "acp"\n | "dsh"\n | "amp"\n | "cursor"\n | undefined;\n providerMeta?: Record<string, unknown> | undefined;\n harnessVariant?: string | undefined;\n harnessVariantMeta?: Record<string, unknown> | undefined;\n totalCostUsd?: number | undefined;\n routingAffinity?:\n | {\n capabilities: string[];\n sourceAgentId?: string | undefined;\n role?: string | undefined;\n harnessProvider?:\n | "claude"\n | "codex"\n | "pi"\n | "devin"\n | "claude-managed"\n | "opencode"\n | "acp"\n | "dsh"\n | "amp"\n | "cursor"\n | undefined;\n leadOnly?: boolean | undefined;\n }\n | undefined;\n routingAffinityInvalid?: boolean | undefined;\n };\n\n export type ActiveSession = {\n id: string;\n agentId: string;\n taskId: string | null;\n triggerType: string;\n inboxMessageId: string | null;\n taskDescription: string | null;\n runnerSessionId: string | null;\n providerSessionId: string | null;\n startedAt: string;\n lastHeartbeatAt: string;\n runtimeInstanceId?: string | null | undefined;\n };\n\n export type RequestInfo = {\n sessionId: string | undefined;\n agentId: string | undefined;\n runtimeInstanceId: string | undefined;\n sourceTaskId: string | undefined;\n contextKey: string | undefined;\n callOrigin: "mcp" | "extension" | "script-sdk";\n };\n\n import type { SwarmSdk } from "swarm-sdk";\n import type { z } from "zod";\n export type Runtime = "api" | "worker";\n export interface ExtensionScriptAsset {\n name: string;\n file: string;\n description: string;\n intent?: string;\n }\n export interface ExtensionScheduleAsset {\n name: string;\n description?: string;\n script: string;\n cronExpression?: string;\n intervalMs?: number;\n timezone?: string;\n args?: Record<string, unknown>;\n }\n export interface ExtensionWorkflowAsset {\n file: string;\n }\n export interface ExtensionSkillAsset {\n dir: string;\n }\n export interface ExtensionManifest {\n $schema?: string;\n name: string;\n description: string;\n version: string;\n runtime: Runtime;\n assets: {\n hooks: string;\n scripts?: readonly ExtensionScriptAsset[];\n schedules?: readonly ExtensionScheduleAsset[];\n workflows?: readonly ExtensionWorkflowAsset[];\n skills?: readonly ExtensionSkillAsset[];\n };\n homepage?: string;\n author?: string;\n }\n export interface HooksModule {\n default: SwarmExtension;\n config?: z.ZodTypeAny;\n }\n export interface ExtensionState {\n get<T = unknown>(key: string): Promise<T | null>;\n set<T>(key: string, value: T): Promise<void>;\n incr(key: string, by?: number): Promise<number>;\n del(key: string): Promise<void>;\n }\n export interface ExtensionLogger {\n debug(message: string, data?: unknown): void;\n info(message: string, data?: unknown): void;\n warn(message: string, data?: unknown): void;\n error(message: string, data?: unknown): void;\n }\n type ConfigFor<M extends ExtensionManifest> = M extends {\n config: infer C extends z.ZodTypeAny;\n }\n ? z.infer<C>\n : Record<string, unknown>;\n export interface ApiCtx<Config = Record<string, unknown>> {\n swarm: SwarmSdk;\n state: ExtensionState;\n config: Config;\n log: ExtensionLogger;\n signal: AbortSignal;\n event: {\n name: keyof SwarmEventMap;\n at: string;\n extension: {\n id: string;\n version: number;\n };\n };\n }\n export interface WorkerCtx<Config = Record<string, unknown>>\n extends Omit<ApiCtx<Config>, "swarm"> {\n swarm: SwarmSdk;\n worker: {\n agentId: string;\n taskId: string;\n harness: string;\n };\n }\n export type CtxFor<M extends ExtensionManifest> = M["runtime"] extends "api"\n ? ApiCtx<ConfigFor<M>>\n : WorkerCtx<ConfigFor<M>>;\n export type PreResult<Modify> =\n | void\n | {\n action: "continue";\n }\n | {\n action: "modify";\n data: Modify;\n }\n | {\n action: "block";\n reason: string;\n };\n export type TaskCreateOrigin =\n | "rest"\n | "app"\n | "mcp"\n | "slack"\n | "schedule"\n | "workflow"\n | "webhook"\n | "followUp"\n | `extension:${string}`;\n export interface TaskCreateEvent {\n options: CreateTaskOptions;\n description: string;\n origin: TaskCreateOrigin;\n requestInfo?: RequestInfo;\n }\n export type TaskCreateModify = Partial<\n Pick<\n CreateTaskOptions,\n | "agentId"\n | "creatorAgentId"\n | "source"\n | "taskType"\n | "tags"\n | "priority"\n | "dependsOn"\n | "offeredTo"\n | "vcsProvider"\n | "vcsRepo"\n | "vcsEventType"\n | "vcsNumber"\n | "vcsCommentId"\n | "vcsAuthor"\n | "vcsUrl"\n | "vcsInstallationId"\n | "vcsNodeId"\n | "agentmailInboxId"\n | "agentmailMessageId"\n | "agentmailThreadId"\n | "mentionMessageId"\n | "mentionChannelId"\n | "dir"\n | "model"\n | "modelTier"\n | "effort"\n | "outputSchema"\n | "followUpConfig"\n | "bypassTrackerContextDedup"\n >\n > & {\n description?: string;\n };\n export interface TaskFollowUpEvent {\n completedTask: AgentTask;\n status: "completed" | "failed";\n output?: string;\n failureReason?: string;\n workerAgentId: string;\n leadAgentId: string;\n summary: string;\n }\n export type TaskFollowUpModify = Partial<\n Pick<CreateTaskOptions, "agentId" | "priority" | "followUpConfig">\n > & {\n description?: string;\n };\n export interface SlackRouteEvent {\n channelId: string;\n userId: string;\n text: string;\n threadTs?: string;\n botMentioned: boolean;\n threadContext?: {\n channelId: string;\n threadTs: string;\n };\n }\n export interface SlackRouteModify {\n target:\n | {\n kind: "agent";\n agentId: string;\n }\n | {\n kind: "lead";\n }\n | {\n kind: "broadcast";\n };\n }\n export type HeartbeatClassification = "no-session" | "stale-session" | "fresh-stalled";\n export type HeartbeatAction = "supersede-resume" | "fail" | "record";\n export interface HeartbeatRemediateEvent {\n task: AgentTask;\n session?: ActiveSession;\n classification: HeartbeatClassification;\n proposedAction: HeartbeatAction;\n reason: string;\n taskAgeMs: number;\n sessionHeartbeatAgeMs?: number;\n }\n export interface HeartbeatRemediateModify {\n proposedAction: HeartbeatAction;\n }\n export interface ToolCallEvent {\n tool: string;\n args: unknown;\n requestInfo: RequestInfo;\n }\n export interface ToolCallModify {\n args: unknown;\n }\n export interface TaskEvent {\n task: AgentTask;\n }\n export interface TaskCompletedEvent extends TaskEvent {\n output: string;\n }\n export interface TaskFailedEvent extends TaskEvent {\n failureReason: string;\n }\n export interface TaskSupersededEvent extends TaskEvent {\n supersededBy: string;\n }\n export interface TaskProgressEvent extends TaskEvent {\n progress: string;\n }\n export interface SlackMessageEvent {\n channelId: string;\n userId: string;\n text: string;\n threadTs?: string;\n taskId?: string;\n }\n /**\n * A person answered an approval request. Fires for workflow and standalone\n * requests. Timeouts and cancellations do not emit it today.\n */\n export interface ApprovalResolvedEvent {\n requestId: string;\n status: "approved" | "rejected" | "timeout" | "cancelled";\n responses: Record<string, unknown> | null;\n /** Set when a workflow human-in-the-loop step asked. Absent for a standalone request. */\n workflowRunId?: string;\n workflowRunStepId?: string;\n /** The task whose agent asked, for a standalone request. */\n sourceTaskId?: string;\n }\n /** A task was refused because a daily spend budget is used up. */\n export interface TaskBudgetRefusedEvent extends TaskEvent {\n /** The agent the task was refused for. */\n agentId: string;\n /** Which budget refused it. The matching spend and budget fields are set. */\n cause: "agent" | "global" | "user";\n agentSpendUsd?: number;\n agentBudgetUsd?: number;\n globalSpendUsd?: number;\n globalBudgetUsd?: number;\n userSpendUsd?: number;\n userBudgetUsd?: number;\n /** ISO 8601 time the daily budget resets. */\n resetAt: string;\n }\n /** An inbound AgentMail message. */\n export interface EmailReceivedEvent {\n inboxId: string;\n /** The From header as sent. */\n from: string;\n subject: string;\n /** The text body, or the HTML when there is no text, cut to 500 characters with `...` appended. */\n body: string;\n threadId: string;\n messageId: string;\n }\n /** An inbound Kapso (WhatsApp) message. */\n export interface KapsoMessageEvent {\n phoneNumberId: string;\n conversationId?: string;\n messageId: string;\n from?: string;\n /** Kapso message type, such as `text` or `image`. */\n type?: string;\n /** The text, or a placeholder naming the type for a non-text message. */\n text: string;\n }\n export type VcsProvider = "github" | "gitlab" | "azure-devops";\n /**\n * The provider object the event is about, as the provider names it. GitLab\n * calls a pull request a merge request, and a comment a `note`.\n */\n export type VcsEventKind =\n | "pull_request"\n | "merge_request"\n | "issue"\n | "issue_comment"\n | "note"\n | "pull_request_review"\n | "pipeline";\n /**\n * A webhook event from a connected code host. `action` is the provider\'s own\n * value: `opened`, `closed`, `synchronize`, `merge`, `created`, `commented`, or,\n * for a pipeline, its status such as `success` or `failed`. Fields a kind does\n * not carry are absent.\n */\n export interface VcsEvent {\n provider: VcsProvider;\n kind: VcsEventKind;\n action: string;\n /** `owner/name` on GitHub and GitLab, the repository URL on Azure DevOps. */\n repo: string;\n /** The PR, merge request, or issue number. Absent for a pipeline outside a merge request. */\n number?: number;\n title?: string;\n body?: string | null;\n /** Login of the user behind the event. Set for pull requests, merge requests, and Azure DevOps comments. */\n author?: string;\n url?: string;\n merged?: boolean;\n changedFiles?: number;\n /** The review verdict, on a pull request review. */\n reviewState?: string;\n }\n export interface ToolCallCompletedEvent extends ToolCallEvent {\n result: unknown;\n durationMs: number;\n }\n export interface SwarmEventMap {\n "pre.task.create": {\n event: TaskCreateEvent;\n modify: TaskCreateModify;\n result: PreResult<TaskCreateModify>;\n };\n "pre.task.followUp": {\n event: TaskFollowUpEvent;\n modify: TaskFollowUpModify;\n result: PreResult<TaskFollowUpModify>;\n };\n "pre.slack.route": {\n event: SlackRouteEvent;\n modify: SlackRouteModify;\n result: PreResult<SlackRouteModify>;\n };\n "pre.heartbeat.remediate": {\n event: HeartbeatRemediateEvent;\n modify: HeartbeatRemediateModify;\n result: PreResult<HeartbeatRemediateModify>;\n };\n "pre.tool.call": {\n event: ToolCallEvent;\n modify: ToolCallModify;\n result: PreResult<ToolCallModify>;\n };\n "post.task.created": {\n event: TaskEvent;\n modify: never;\n result: void;\n };\n "post.task.completed": {\n event: TaskCompletedEvent;\n modify: never;\n result: void;\n };\n "post.task.failed": {\n event: TaskFailedEvent;\n modify: never;\n result: void;\n };\n "post.task.cancelled": {\n event: TaskEvent;\n modify: never;\n result: void;\n };\n "post.task.superseded": {\n event: TaskSupersededEvent;\n modify: never;\n result: void;\n };\n "post.task.progress": {\n event: TaskProgressEvent;\n modify: never;\n result: void;\n };\n "post.slack.message": {\n event: SlackMessageEvent;\n modify: never;\n result: void;\n };\n "post.approval.resolved": {\n event: ApprovalResolvedEvent;\n modify: never;\n result: void;\n };\n "post.task.budgetRefused": {\n event: TaskBudgetRefusedEvent;\n modify: never;\n result: void;\n };\n "post.email.received": {\n event: EmailReceivedEvent;\n modify: never;\n result: void;\n };\n "post.kapso.message": {\n event: KapsoMessageEvent;\n modify: never;\n result: void;\n };\n "post.vcs.event": {\n event: VcsEvent;\n modify: never;\n result: void;\n };\n "post.tool.call": {\n event: ToolCallCompletedEvent;\n modify: never;\n result: void;\n };\n }\n export interface ExtensionApi<\n M extends ExtensionManifest = ExtensionManifest & {\n runtime: "api";\n },\n > {\n on<E extends keyof SwarmEventMap>(\n event: E,\n handler: (\n event: SwarmEventMap[E]["event"],\n ctx: CtxFor<M>,\n ) => Promise<SwarmEventMap[E]["result"]> | SwarmEventMap[E]["result"],\n opts?: {\n priority?: number;\n },\n ): void;\n }\n export type SwarmExtension<\n M extends ExtensionManifest = ExtensionManifest & {\n runtime: "api";\n },\n > = (api: ExtensionApi<M>) => void;\n export { block, modify } from "./contract-runtime";\n}\n';
|
|
4
|
+
'// biome-ignore-all lint/suspicious/noConfusingVoidType: Extension handlers may explicitly return no result.\ndeclare module "swarm-extension" {\n export type CreateTaskOptions = {\n key?: string | undefined;\n agentId?: string | null | undefined;\n creatorAgentId?: string | undefined;\n source?:\n | "workflow"\n | "schedule"\n | "slack"\n | "agentmail"\n | "mcp"\n | "api"\n | "ui"\n | "github"\n | "gitlab"\n | "azure-devops"\n | "system"\n | "linear"\n | "jira"\n | "comb"\n | undefined;\n routingReason?:\n | "skill"\n | "continuity"\n | "overflow"\n | "human_pinned"\n | "reroute_fault"\n | undefined;\n routingSource?: "declared" | "engine_default" | undefined;\n routingNote?: string | undefined;\n taskType?: string | undefined;\n tags?: string[] | undefined;\n priority?: number | undefined;\n dependsOn?: string[] | undefined;\n offeredTo?: string | undefined;\n status?: "draft" | "backlog" | "unassigned" | undefined;\n slackChannelId?: string | undefined;\n slackThreadTs?: string | undefined;\n slackTriggerMessageTs?: string | undefined;\n slackUserId?: string | undefined;\n overrideSlackContext?: boolean | undefined;\n vcsProvider?: "github" | "gitlab" | "azure-devops" | undefined;\n vcsRepo?: string | undefined;\n vcsEventType?: string | undefined;\n vcsNumber?: number | undefined;\n vcsCommentId?: number | undefined;\n vcsAuthor?: string | undefined;\n vcsUrl?: string | undefined;\n vcsInstallationId?: number | undefined;\n vcsNodeId?: string | undefined;\n agentmailInboxId?: string | undefined;\n agentmailMessageId?: string | undefined;\n agentmailThreadId?: string | undefined;\n mentionMessageId?: string | undefined;\n mentionChannelId?: string | undefined;\n dir?: string | undefined;\n parentTaskId?: string | undefined;\n model?: string | undefined;\n modelTier?: "smol" | "regular" | "smart" | "ultra" | undefined;\n effort?: "off" | "low" | "medium" | "high" | "xhigh" | "max" | undefined;\n scheduleId?: string | undefined;\n workflowRunId?: string | undefined;\n workflowRunStepId?: string | undefined;\n sourceTaskId?: string | undefined;\n outputSchema?: Record<string, unknown> | undefined;\n inheritParentOutputSchema?: boolean | undefined;\n inheritParentRoutingAffinity?: boolean | undefined;\n inheritParentFollowUpConfig?: boolean | undefined;\n followUpConfig?:\n | {\n disabled?: boolean | undefined;\n onCompleted?: string | undefined;\n onFailed?: string | undefined;\n }\n | undefined;\n requestedByUserId?: string | undefined;\n contextKey?: string | undefined;\n bypassTrackerContextDedup?: boolean | undefined;\n routingAffinity?:\n | {\n capabilities: string[];\n sourceAgentId?: string | undefined;\n role?: string | undefined;\n harnessProvider?:\n | "claude"\n | "codex"\n | "pi"\n | "devin"\n | "claude-managed"\n | "opencode"\n | "acp"\n | "dsh"\n | "amp"\n | "cursor"\n | "grok"\n | undefined;\n leadOnly?: boolean | undefined;\n }\n | undefined;\n };\n\n export type AgentTask = {\n id: string;\n key: string;\n agentId: string | null;\n task: string;\n status:\n | "draft"\n | "backlog"\n | "unassigned"\n | "offered"\n | "reviewing"\n | "pending"\n | "in_progress"\n | "paused"\n | "completed"\n | "failed"\n | "cancelled"\n | "superseded";\n source:\n | "workflow"\n | "schedule"\n | "slack"\n | "agentmail"\n | "mcp"\n | "api"\n | "ui"\n | "github"\n | "gitlab"\n | "azure-devops"\n | "system"\n | "linear"\n | "jira"\n | "comb";\n tags: string[];\n priority: number;\n dependsOn: string[];\n createdAt: string;\n lastUpdatedAt: string;\n slackReplySent: boolean;\n wasPaused: boolean;\n creatorAgentId?: string | undefined;\n title?: string | undefined;\n routingReason?:\n | "skill"\n | "continuity"\n | "overflow"\n | "human_pinned"\n | "reroute_fault"\n | undefined;\n routingSource?: "declared" | "engine_default" | undefined;\n routingNote?: string | undefined;\n taskType?: string | undefined;\n offeredTo?: string | undefined;\n offeredAt?: string | undefined;\n acceptedAt?: string | undefined;\n rejectionReason?: string | undefined;\n finishedAt?: string | undefined;\n notifiedAt?: string | undefined;\n failureReason?: string | undefined;\n output?: string | undefined;\n progress?: string | undefined;\n slackChannelId?: string | undefined;\n slackThreadTs?: string | undefined;\n slackTriggerMessageTs?: string | undefined;\n slackUserId?: string | undefined;\n slackProgressMessageTs?: string | undefined;\n slackTreeRootMessageTs?: string | undefined;\n vcsProvider?: "github" | "gitlab" | "azure-devops" | undefined;\n vcsRepo?: string | undefined;\n vcsEventType?: string | undefined;\n vcsNumber?: number | undefined;\n vcsCommentId?: number | undefined;\n vcsAuthor?: string | undefined;\n vcsUrl?: string | undefined;\n vcsInstallationId?: number | undefined;\n vcsNodeId?: string | undefined;\n agentmailInboxId?: string | undefined;\n agentmailMessageId?: string | undefined;\n agentmailThreadId?: string | undefined;\n mentionMessageId?: string | undefined;\n mentionChannelId?: string | undefined;\n dir?: string | undefined;\n parentTaskId?: string | undefined;\n claudeSessionId?: string | undefined;\n model?: string | undefined;\n modelTier?: "smol" | "regular" | "smart" | "ultra" | undefined;\n effort?: "off" | "low" | "medium" | "high" | "xhigh" | "max" | undefined;\n resolvedModel?: string | undefined;\n modelSource?: string | undefined;\n modelAlias?: string | undefined;\n scheduleId?: string | undefined;\n workflowRunId?: string | null | undefined;\n workflowRunStepId?: string | null | undefined;\n contextKey?: string | undefined;\n outputSchema?: Record<string, unknown> | undefined;\n followUpConfig?:\n | {\n disabled?: boolean | undefined;\n onCompleted?: string | undefined;\n onFailed?: string | undefined;\n }\n | undefined;\n deferredAt?: string | undefined;\n compactionCount?: number | undefined;\n peakContextPercent?: number | undefined;\n peakContextTokens?: number | undefined;\n contextWindowSize?: number | undefined;\n credentialKeySuffix?: string | undefined;\n credentialKeyType?: string | undefined;\n requestedByUserId?: string | undefined;\n swarmVersion?: string | undefined;\n provider?:\n | "claude"\n | "codex"\n | "pi"\n | "devin"\n | "claude-managed"\n | "opencode"\n | "acp"\n | "dsh"\n | "amp"\n | "cursor"\n | "grok"\n | undefined;\n providerMeta?: Record<string, unknown> | undefined;\n harnessVariant?: string | undefined;\n harnessVariantMeta?: Record<string, unknown> | undefined;\n totalCostUsd?: number | undefined;\n routingAffinity?:\n | {\n capabilities: string[];\n sourceAgentId?: string | undefined;\n role?: string | undefined;\n harnessProvider?:\n | "claude"\n | "codex"\n | "pi"\n | "devin"\n | "claude-managed"\n | "opencode"\n | "acp"\n | "dsh"\n | "amp"\n | "cursor"\n | "grok"\n | undefined;\n leadOnly?: boolean | undefined;\n }\n | undefined;\n routingAffinityInvalid?: boolean | undefined;\n };\n\n export type ActiveSession = {\n id: string;\n agentId: string;\n taskId: string | null;\n triggerType: string;\n inboxMessageId: string | null;\n taskDescription: string | null;\n runnerSessionId: string | null;\n providerSessionId: string | null;\n startedAt: string;\n lastHeartbeatAt: string;\n runtimeInstanceId?: string | null | undefined;\n };\n\n export type RequestInfo = {\n sessionId: string | undefined;\n agentId: string | undefined;\n runtimeInstanceId: string | undefined;\n sourceTaskId: string | undefined;\n contextKey: string | undefined;\n callOrigin: "mcp" | "extension" | "script-sdk";\n };\n\n import type { SwarmSdk } from "swarm-sdk";\n import type { z } from "zod";\n export type Runtime = "api" | "worker";\n export interface ExtensionScriptAsset {\n name: string;\n file: string;\n description: string;\n intent?: string;\n }\n export interface ExtensionScheduleAsset {\n name: string;\n description?: string;\n script: string;\n cronExpression?: string;\n intervalMs?: number;\n timezone?: string;\n args?: Record<string, unknown>;\n }\n export interface ExtensionWorkflowAsset {\n file: string;\n }\n export interface ExtensionSkillAsset {\n dir: string;\n }\n export interface ExtensionManifest {\n $schema?: string;\n name: string;\n description: string;\n version: string;\n runtime: Runtime;\n assets: {\n hooks: string;\n scripts?: readonly ExtensionScriptAsset[];\n schedules?: readonly ExtensionScheduleAsset[];\n workflows?: readonly ExtensionWorkflowAsset[];\n skills?: readonly ExtensionSkillAsset[];\n };\n homepage?: string;\n author?: string;\n }\n export interface HooksModule {\n default: SwarmExtension;\n config?: z.ZodTypeAny;\n }\n export interface ExtensionState {\n get<T = unknown>(key: string): Promise<T | null>;\n set<T>(key: string, value: T): Promise<void>;\n incr(key: string, by?: number): Promise<number>;\n del(key: string): Promise<void>;\n }\n export interface ExtensionLogger {\n debug(message: string, data?: unknown): void;\n info(message: string, data?: unknown): void;\n warn(message: string, data?: unknown): void;\n error(message: string, data?: unknown): void;\n }\n type ConfigFor<M extends ExtensionManifest> = M extends {\n config: infer C extends z.ZodTypeAny;\n }\n ? z.infer<C>\n : Record<string, unknown>;\n export interface ApiCtx<Config = Record<string, unknown>> {\n swarm: SwarmSdk;\n state: ExtensionState;\n config: Config;\n log: ExtensionLogger;\n signal: AbortSignal;\n event: {\n name: keyof SwarmEventMap;\n at: string;\n extension: {\n id: string;\n version: number;\n };\n };\n }\n export interface WorkerCtx<Config = Record<string, unknown>>\n extends Omit<ApiCtx<Config>, "swarm"> {\n swarm: SwarmSdk;\n worker: {\n agentId: string;\n taskId: string;\n harness: string;\n };\n }\n export type CtxFor<M extends ExtensionManifest> = M["runtime"] extends "api"\n ? ApiCtx<ConfigFor<M>>\n : WorkerCtx<ConfigFor<M>>;\n export type PreResult<Modify> =\n | void\n | {\n action: "continue";\n }\n | {\n action: "modify";\n data: Modify;\n }\n | {\n action: "block";\n reason: string;\n };\n export type TaskCreateOrigin =\n | "rest"\n | "app"\n | "mcp"\n | "slack"\n | "schedule"\n | "workflow"\n | "webhook"\n | "followUp"\n | `extension:${string}`;\n export interface TaskCreateEvent {\n options: CreateTaskOptions;\n description: string;\n origin: TaskCreateOrigin;\n requestInfo?: RequestInfo;\n }\n export type TaskCreateModify = Partial<\n Pick<\n CreateTaskOptions,\n | "agentId"\n | "creatorAgentId"\n | "source"\n | "taskType"\n | "tags"\n | "priority"\n | "dependsOn"\n | "offeredTo"\n | "vcsProvider"\n | "vcsRepo"\n | "vcsEventType"\n | "vcsNumber"\n | "vcsCommentId"\n | "vcsAuthor"\n | "vcsUrl"\n | "vcsInstallationId"\n | "vcsNodeId"\n | "agentmailInboxId"\n | "agentmailMessageId"\n | "agentmailThreadId"\n | "mentionMessageId"\n | "mentionChannelId"\n | "dir"\n | "model"\n | "modelTier"\n | "effort"\n | "outputSchema"\n | "followUpConfig"\n | "bypassTrackerContextDedup"\n >\n > & {\n description?: string;\n };\n export interface TaskFollowUpEvent {\n completedTask: AgentTask;\n status: "completed" | "failed";\n output?: string;\n failureReason?: string;\n workerAgentId: string;\n leadAgentId: string;\n summary: string;\n }\n export type TaskFollowUpModify = Partial<\n Pick<CreateTaskOptions, "agentId" | "priority" | "followUpConfig">\n > & {\n description?: string;\n };\n export interface SlackRouteEvent {\n channelId: string;\n userId: string;\n text: string;\n threadTs?: string;\n botMentioned: boolean;\n threadContext?: {\n channelId: string;\n threadTs: string;\n };\n }\n export interface SlackRouteModify {\n target:\n | {\n kind: "agent";\n agentId: string;\n }\n | {\n kind: "lead";\n }\n | {\n kind: "broadcast";\n };\n }\n export type HeartbeatClassification = "no-session" | "stale-session" | "fresh-stalled";\n export type HeartbeatAction = "supersede-resume" | "fail" | "record";\n export interface HeartbeatRemediateEvent {\n task: AgentTask;\n session?: ActiveSession;\n classification: HeartbeatClassification;\n proposedAction: HeartbeatAction;\n reason: string;\n taskAgeMs: number;\n sessionHeartbeatAgeMs?: number;\n }\n export interface HeartbeatRemediateModify {\n proposedAction: HeartbeatAction;\n }\n export interface ToolCallEvent {\n tool: string;\n args: unknown;\n requestInfo: RequestInfo;\n }\n export interface ToolCallModify {\n args: unknown;\n }\n export interface TaskEvent {\n task: AgentTask;\n }\n export interface TaskCompletedEvent extends TaskEvent {\n output: string;\n }\n export interface TaskFailedEvent extends TaskEvent {\n failureReason: string;\n }\n export interface TaskSupersededEvent extends TaskEvent {\n supersededBy: string;\n }\n export interface TaskProgressEvent extends TaskEvent {\n progress: string;\n }\n export interface SlackMessageEvent {\n channelId: string;\n userId: string;\n text: string;\n threadTs?: string;\n taskId?: string;\n }\n /**\n * A person answered an approval request. Fires for workflow and standalone\n * requests. Timeouts and cancellations do not emit it today.\n */\n export interface ApprovalResolvedEvent {\n requestId: string;\n status: "approved" | "rejected" | "timeout" | "cancelled";\n responses: Record<string, unknown> | null;\n /** Set when a workflow human-in-the-loop step asked. Absent for a standalone request. */\n workflowRunId?: string;\n workflowRunStepId?: string;\n /** The task whose agent asked, for a standalone request. */\n sourceTaskId?: string;\n }\n /** A task was refused because a daily spend budget is used up. */\n export interface TaskBudgetRefusedEvent extends TaskEvent {\n /** The agent the task was refused for. */\n agentId: string;\n /** Which budget refused it. The matching spend and budget fields are set. */\n cause: "agent" | "global" | "user";\n agentSpendUsd?: number;\n agentBudgetUsd?: number;\n globalSpendUsd?: number;\n globalBudgetUsd?: number;\n userSpendUsd?: number;\n userBudgetUsd?: number;\n /** ISO 8601 time the daily budget resets. */\n resetAt: string;\n }\n /** An inbound AgentMail message. */\n export interface EmailReceivedEvent {\n inboxId: string;\n /** The From header as sent. */\n from: string;\n subject: string;\n /** The text body, or the HTML when there is no text, cut to 500 characters with `...` appended. */\n body: string;\n threadId: string;\n messageId: string;\n }\n /** An inbound Kapso (WhatsApp) message. */\n export interface KapsoMessageEvent {\n phoneNumberId: string;\n conversationId?: string;\n messageId: string;\n from?: string;\n /** Kapso message type, such as `text` or `image`. */\n type?: string;\n /** The text, or a placeholder naming the type for a non-text message. */\n text: string;\n }\n export type VcsProvider = "github" | "gitlab" | "azure-devops";\n /**\n * The provider object the event is about, as the provider names it. GitLab\n * calls a pull request a merge request, and a comment a `note`.\n */\n export type VcsEventKind =\n | "pull_request"\n | "merge_request"\n | "issue"\n | "issue_comment"\n | "note"\n | "pull_request_review"\n | "pipeline";\n /**\n * A webhook event from a connected code host. `action` is the provider\'s own\n * value: `opened`, `closed`, `synchronize`, `merge`, `created`, `commented`, or,\n * for a pipeline, its status such as `success` or `failed`. Fields a kind does\n * not carry are absent.\n */\n export interface VcsEvent {\n provider: VcsProvider;\n kind: VcsEventKind;\n action: string;\n /** `owner/name` on GitHub and GitLab, the repository URL on Azure DevOps. */\n repo: string;\n /** The PR, merge request, or issue number. Absent for a pipeline outside a merge request. */\n number?: number;\n title?: string;\n body?: string | null;\n /** Login of the user behind the event. Set for pull requests, merge requests, and Azure DevOps comments. */\n author?: string;\n url?: string;\n merged?: boolean;\n changedFiles?: number;\n /** The review verdict, on a pull request review. */\n reviewState?: string;\n }\n export interface ToolCallCompletedEvent extends ToolCallEvent {\n result: unknown;\n durationMs: number;\n }\n export interface SwarmEventMap {\n "pre.task.create": {\n event: TaskCreateEvent;\n modify: TaskCreateModify;\n result: PreResult<TaskCreateModify>;\n };\n "pre.task.followUp": {\n event: TaskFollowUpEvent;\n modify: TaskFollowUpModify;\n result: PreResult<TaskFollowUpModify>;\n };\n "pre.slack.route": {\n event: SlackRouteEvent;\n modify: SlackRouteModify;\n result: PreResult<SlackRouteModify>;\n };\n "pre.heartbeat.remediate": {\n event: HeartbeatRemediateEvent;\n modify: HeartbeatRemediateModify;\n result: PreResult<HeartbeatRemediateModify>;\n };\n "pre.tool.call": {\n event: ToolCallEvent;\n modify: ToolCallModify;\n result: PreResult<ToolCallModify>;\n };\n "post.task.created": {\n event: TaskEvent;\n modify: never;\n result: void;\n };\n "post.task.completed": {\n event: TaskCompletedEvent;\n modify: never;\n result: void;\n };\n "post.task.failed": {\n event: TaskFailedEvent;\n modify: never;\n result: void;\n };\n "post.task.cancelled": {\n event: TaskEvent;\n modify: never;\n result: void;\n };\n "post.task.superseded": {\n event: TaskSupersededEvent;\n modify: never;\n result: void;\n };\n "post.task.progress": {\n event: TaskProgressEvent;\n modify: never;\n result: void;\n };\n "post.slack.message": {\n event: SlackMessageEvent;\n modify: never;\n result: void;\n };\n "post.approval.resolved": {\n event: ApprovalResolvedEvent;\n modify: never;\n result: void;\n };\n "post.task.budgetRefused": {\n event: TaskBudgetRefusedEvent;\n modify: never;\n result: void;\n };\n "post.email.received": {\n event: EmailReceivedEvent;\n modify: never;\n result: void;\n };\n "post.kapso.message": {\n event: KapsoMessageEvent;\n modify: never;\n result: void;\n };\n "post.vcs.event": {\n event: VcsEvent;\n modify: never;\n result: void;\n };\n "post.tool.call": {\n event: ToolCallCompletedEvent;\n modify: never;\n result: void;\n };\n }\n export interface ExtensionApi<\n M extends ExtensionManifest = ExtensionManifest & {\n runtime: "api";\n },\n > {\n on<E extends keyof SwarmEventMap>(\n event: E,\n handler: (\n event: SwarmEventMap[E]["event"],\n ctx: CtxFor<M>,\n ) => Promise<SwarmEventMap[E]["result"]> | SwarmEventMap[E]["result"],\n opts?: {\n priority?: number;\n },\n ): void;\n }\n export type SwarmExtension<\n M extends ExtensionManifest = ExtensionManifest & {\n runtime: "api";\n },\n > = (api: ExtensionApi<M>) => void;\n export { block, modify } from "./contract-runtime";\n}\n';
|
package/src/github/app.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { isEnvFlagEnabled } from "../utils/env-flag";
|
|
2
|
+
|
|
1
3
|
let initialized = false;
|
|
2
4
|
let webhookSecret: string | null = null;
|
|
3
5
|
let appId: string | null = null;
|
|
@@ -8,8 +10,7 @@ const tokenCache = new Map<number, { token: string; expiresAt: number }>();
|
|
|
8
10
|
|
|
9
11
|
export function isGitHubEnabled(): boolean {
|
|
10
12
|
// Check if GitHub is explicitly disabled
|
|
11
|
-
|
|
12
|
-
if (githubDisable === "true" || githubDisable === "1") {
|
|
13
|
+
if (isEnvFlagEnabled("GITHUB_DISABLE", false)) {
|
|
13
14
|
return false;
|
|
14
15
|
}
|
|
15
16
|
|
|
@@ -33,8 +34,7 @@ export function initGitHub(): boolean {
|
|
|
33
34
|
initialized = true;
|
|
34
35
|
|
|
35
36
|
// Check if GitHub is explicitly disabled
|
|
36
|
-
|
|
37
|
-
if (githubDisable === "true" || githubDisable === "1") {
|
|
37
|
+
if (isEnvFlagEnabled("GITHUB_DISABLE", false)) {
|
|
38
38
|
console.log("[GitHub] Disabled via GITHUB_DISABLE");
|
|
39
39
|
return false;
|
|
40
40
|
}
|