@desplega.ai/agent-swarm 1.158.0 → 1.160.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-xaq4n6pc.js → acp-adapter-2mjwcsfh.js} +124 -27
- package/dist/{actions-p9hz5yat.js → actions-e43rxskr.js} +35 -30
- package/dist/{anthropic-messages-51pz26qe.js → anthropic-messages-5qx80j9k.js} +106 -16
- package/dist/{app-g26wdcz6.js → app-mc7xfagn.js} +12 -10
- package/dist/{assistant-wydfqkb3.js → assistant-sedkzv3b.js} +42 -31
- package/dist/{azure-openai-responses-8gksqtmz.js → azure-openai-responses-nfb21z9a.js} +13 -14
- package/dist/{boot-reembed-se8zmdcp.js → boot-reembed-cqz9swn5.js} +13 -12
- package/dist/{boot-reembed-g5ckg9yb.js → boot-reembed-m3656j2n.js} +14 -13
- package/dist/{boot-scrub-logs-wfxqan61.js → boot-scrub-logs-xbxf5d7w.js} +11 -9
- package/dist/boot-seeds-gsetbs5y.js +28 -0
- package/dist/{claude-adapter-tv2x4f36.js → claude-adapter-dc6289mc.js} +28 -23
- package/dist/{claude-managed-adapter-41b2s7fd.js → claude-managed-adapter-naaw51me.js} +4 -3
- package/dist/{claude-managed-setup-60g8aazx.js → claude-managed-setup-eacvchx0.js} +12 -3
- package/dist/claude-sdk-session-bqp2xvym.js +29722 -0
- package/dist/{cli-987hg0aa.js → cli-0jwe9034.js} +2 -2
- package/dist/{cli-vj6h9kc2.js → cli-0m7wct0d.js} +59 -1
- package/dist/{cli-c07r9a2m.js → cli-0q3avq3s.js} +12 -11
- package/dist/{cli-19jenss3.js → cli-0wgxmwf6.js} +31 -10
- package/dist/cli-0x01kwrd.js +491 -0
- package/dist/cli-0xqde53b.js +176 -0
- package/dist/cli-10nhj6xq.js +8355 -0
- package/dist/{cli-tt9k8r35.js → cli-12tszpk9.js} +479 -910
- package/dist/{cli-5b6b62tz.js → cli-13hw4z91.js} +1 -1
- package/dist/{cli-cqt19wg6.js → cli-1a2j50m0.js} +11 -2
- package/dist/{cli-xberxa1r.js → cli-25fcq4b4.js} +2 -2
- package/dist/{cli-npssxgaz.js → cli-2pdaysab.js} +52 -2
- package/dist/cli-3qhyh31j.js +166 -0
- package/dist/cli-447dt1h3.js +3828 -0
- package/dist/cli-4derpgyk.js +115 -0
- package/dist/{cli-00w2c66p.js → cli-523679eh.js} +13 -2
- package/dist/{cli-y95wp3tg.js → cli-58e8yr0d.js} +1 -1
- package/dist/{cli-24k806sc.js → cli-5nbmpy8w.js} +3 -3
- package/dist/{cli-53sz8gkz.js → cli-6cs6wzxt.js} +1 -1
- package/dist/cli-741yb0xx.js +1027 -0
- package/dist/cli-74h9hscv.js +69 -0
- package/dist/cli-7cxw8b60.js +14910 -0
- package/dist/{cli-xhaeg2nc.js → cli-7e398j1h.js} +1 -1
- package/dist/cli-7kyk9jr3.js +22 -0
- package/dist/cli-89s4ngw3.js +183 -0
- package/dist/{cli-9b13ggd1.js → cli-89v6kyq7.js} +1 -0
- package/dist/{cli-ftfvggzx.js → cli-9hsgwz4w.js} +1045 -581
- package/dist/{cli-rqz8qbw7.js → cli-a8dvhzrt.js} +59 -20
- package/dist/{cli-j57qkrpq.js → cli-azhgzetg.js} +395 -56
- package/dist/cli-br0qdrnp.js +2150 -0
- package/dist/{cli-rj19hc34.js → cli-btfv8y88.js} +1 -1
- package/dist/{cli-8qmme6vd.js → cli-c8a36vcc.js} +2 -2
- package/dist/cli-cpvsaqsw.js +333 -0
- package/dist/cli-d5czme6m.js +17805 -0
- package/dist/{cli-h38x0qhg.js → cli-et8m9xsv.js} +4 -3
- package/dist/{cli-x24pshtq.js → cli-evvtk35y.js} +6 -6
- package/dist/{cli-7s3syk22.js → cli-f8gy6r2r.js} +5 -5
- package/dist/{cli-zt1227k1.js → cli-fkqhbg8g.js} +5 -3
- package/dist/{cli-9httdpyq.js → cli-g2whhdrf.js} +1 -1
- package/dist/cli-gt4hxb8p.js +99 -0
- package/dist/{cli-s8eet254.js → cli-jajnsm8q.js} +37184 -53838
- package/dist/{cli-7gtvvpbh.js → cli-jayjpjmb.js} +21 -12
- package/dist/{cli-68w09sjw.js → cli-jyk0ynw2.js} +27 -89
- package/dist/{cli-aehm1rbq.js → cli-jz4w45qt.js} +1152 -61
- package/dist/cli-kmcpfwn2.js +333856 -0
- package/dist/{cli-4198qc9v.js → cli-ktmyrtpn.js} +19 -3
- package/dist/{cli-j55n64b6.js → cli-mfe5btp9.js} +505 -189
- package/dist/{cli-q67y4wzm.js → cli-phsaj4xq.js} +24 -2
- package/dist/{cli-1hkrch3k.js → cli-pm1rst0h.js} +46 -7
- package/dist/{cli-pw9rj5t9.js → cli-pqetb83f.js} +1 -176
- package/dist/{cli-ggm92wcn.js → cli-ptr8h7kp.js} +20 -1
- package/dist/{cli-s8s499xy.js → cli-qbksc292.js} +3 -2
- package/dist/{cli-47m6dkd3.js → cli-qydf22qq.js} +597 -346
- package/dist/{cli-3gmcwfyx.js → cli-r1mxd1xh.js} +13 -6
- package/dist/cli-rb9m6rpe.js +4980 -0
- package/dist/cli-rykfmgwg.js +102 -0
- package/dist/{cli-5d10vd2m.js → cli-shkxm1vn.js} +6 -5
- package/dist/{cli-eetrvv91.js → cli-t3p77qk1.js} +1 -1
- package/dist/cli-tfky2838.js +756 -0
- package/dist/{cli-g8djp6qe.js → cli-tmqt7dpj.js} +40 -0
- package/dist/{cli-fgqxwrpv.js → cli-tpq83z89.js} +1631 -127
- package/dist/cli-trc24wk2.js +143 -0
- package/dist/{cli-aky8tctm.js → cli-tzx2ke1v.js} +3 -3
- package/dist/cli-v7fn5gms.js +1425 -0
- package/dist/{cli-wscdvcqz.js → cli-vctdqs5h.js} +1 -1
- package/dist/{cli-cw9zck8j.js → cli-xjcywfsf.js} +8 -4
- package/dist/{cli-k0g1sjzm.js → cli-ybgv4kw2.js} +18 -11
- package/dist/{cli-rjehvrts.js → cli-ydmcgve1.js} +8 -8
- package/dist/{cli-vhjwh6cz.js → cli-ygwm91nt.js} +1 -1
- package/dist/{cli-mcnhgnn1.js → cli-ykk5jaax.js} +184 -26
- package/dist/{cli-de1396j2.js → cli-ywybs5as.js} +7 -1
- package/dist/cli-zpep9q5e.js +491 -0
- package/dist/cli.js +41 -32
- package/dist/cloudflare-workers-ai-system-one-k6fbxw9d.js +46 -0
- package/dist/{codex-adapter-cnm8wk11.js → codex-adapter-nmxcatww.js} +26 -17
- package/dist/{codex-hook-9hptmdhj.js → codex-hook-20me6byw.js} +2 -2
- package/dist/{codex-login-x3jk4etn.js → codex-login-w6fz4xbz.js} +50 -5
- package/dist/{codex-session-runner-gfg547zj.js → codex-session-runner-90aa80ev.js} +24 -17
- package/dist/{commands-e3bn0p75.js → commands-8wcq1kn7.js} +11 -9
- package/dist/{db-03v9kzr2.js → db-j40kc4se.js} +25 -11
- package/dist/{devin-adapter-8vgkwh29.js → devin-adapter-dpsv6hd9.js} +1 -1
- package/dist/{dispatcher-nrmg8yht.js → dispatcher-4zqy768d.js} +34 -29
- package/dist/{dsh-adapter-k03nfqa6.js → dsh-adapter-mpnzgztj.js} +3 -3
- package/dist/{e2b-93x1k0j5.js → e2b-ez07znam.js} +4 -3
- package/dist/execute-6e7qeyk4.js +1017 -0
- package/dist/{google-generative-ai-bxmv50nc.js → google-generative-ai-k6n5nbpp.js} +6 -5
- package/dist/{google-vertex-809af514.js → google-vertex-44xxtcvp.js} +6 -5
- package/dist/{handlers-aqcedbyb.js → handlers-kjdce1w5.js} +37 -32
- package/dist/{hook-ybvmrmhq.js → hook-czx13n12.js} +19 -15
- package/dist/{hook-7vkskkre.js → hook-r2t4bqfg.js} +18 -14
- package/dist/{http-2eqa8t24.js → http-3bbb19be.js} +900 -145
- package/dist/{index-f6cryxwe.js → index-4a5njnm1.js} +2 -59
- package/dist/{index-x71bvq0p.js → index-668me3f0.js} +35 -30
- package/dist/{index-c6zsv1bd.js → index-7aj368tw.js} +13 -12
- package/dist/{index-1yks3qcr.js → index-fg0dsp6c.js} +34 -29
- package/dist/{index-chgdkq36.js → index-kkv84jq9.js} +34 -29
- package/dist/{index-a3vn96n8.js → index-zg7vp46x.js} +198 -54
- package/dist/{keepalive-vtkf5n99.js → keepalive-yra8dy57.js} +13 -11
- package/dist/{lead-h3sp357x.js → lead-va0pad2c.js} +54 -49
- package/dist/llama-cpp-classify-tgj35k8d.js +335 -0
- package/dist/{maintenance-jzeqtk3q.js → maintenance-hqewtmyg.js} +14 -13
- package/dist/{mistral-conversations-zx0kn554.js → mistral-conversations-pc3ntnxt.js} +14 -17
- package/dist/{oauth-refresh-sweep-qp3dzmdp.js → oauth-refresh-sweep-7rdt1m9n.js} +12 -10
- package/dist/{onboard-tmsp0qbz.js → onboard-j6ms6d0x.js} +6 -5
- package/dist/{openai-codex-responses-4vjqzvjp.js → openai-codex-responses-bbancrr0.js} +21 -8
- package/dist/{openai-completions-9hjrqbw8.js → openai-completions-jpaj5g2b.js} +9 -12
- package/dist/{openai-responses-7b1pn0xt.js → openai-responses-200k1wx4.js} +23 -18
- package/dist/{opencode-adapter-x6x2da1z.js → opencode-adapter-89rabkw2.js} +8 -7
- package/dist/{openrouter-images-9f9ek4rw.js → openrouter-images-8yx3487g.js} +5 -7
- package/dist/{otel-impl-9mz73q65.js → otel-impl-a792rjz0.js} +1 -1
- package/dist/{pi-messages-txpjj39q.js → pi-messages-vxdt8v7j.js} +2 -1
- package/dist/{pi-mono-adapter-m6dvv0dz.js → pi-mono-adapter-g7qzvr3v.js} +295 -70
- package/dist/pricing-refresh-wx0tp7cb.js +39 -0
- package/dist/quickjs-r1pq2107.wasm +0 -0
- package/dist/{rbac-roles-c9wqz83x.js → rbac-roles-8tzawacv.js} +12 -10
- package/dist/{render-v2-gryrh9h8.js → render-v2-mm7zswb8.js} +12 -10
- package/dist/runtime-zyssgse0.js +24 -0
- package/dist/{setup-q9720bt6.js → setup-8y70ys6t.js} +6 -5
- package/dist/typesafe-system-one-2ef30pec.js +27 -0
- package/dist/{virtual-modules-3htpgn8x.js → virtual-modules-6nmk7h3n.js} +22 -13
- package/dist/{work-objects-b76x7deb.js → work-objects-fg6xkb0n.js} +37 -32
- package/dist/{worker-6vrxbv41.js → worker-wmwhxsph.js} +54 -49
- package/openapi.json +1314 -91
- package/package.json +12 -11
- package/src/be/db/agents.ts +20 -0
- package/src/be/db/api-keys.ts +70 -0
- package/src/be/db/tasks/human-free.ts +442 -0
- package/src/be/db/tasks/read.ts +56 -1
- package/src/be/db/tasks/write.ts +107 -11
- package/src/be/db.ts +274 -188
- package/src/be/harness-model-support.ts +182 -0
- package/src/be/human-free-drain.ts +67 -0
- package/src/be/memory/providers/sqlite-store.ts +51 -15
- package/src/be/migrations/182_task_human_free_flag.sql +63 -0
- package/src/be/migrations/183_human_free_reclassify_queue.sql +25 -0
- package/src/be/migrations/184_model_catalog.sql +120 -0
- package/src/be/migrations/185_api_key_auth_failures.sql +6 -0
- package/src/be/migrations/186_api_key_seat_mismatch.sql +8 -0
- package/src/be/model-catalog-store.ts +644 -0
- package/src/be/model-tier-keys.ts +46 -0
- package/src/be/model-tier-resolution.ts +534 -0
- package/src/be/model-validation.ts +188 -0
- package/src/be/models-catalog.ts +61 -7
- package/src/be/modelsdev-cache.json +82 -0
- package/src/be/modelsdev-cache.ts +2 -0
- package/src/be/pricing-refresh.ts +154 -12
- package/src/be/scripts/typecheck.ts +15 -0
- package/src/be/seed/runner.ts +18 -12
- package/src/be/seed/types.ts +1 -0
- package/src/be/seed-scripts/catalog/task-failure-audit.ts +61 -9
- package/src/be/swarm-config-guard.ts +8 -0
- package/src/cli.tsx +10 -0
- package/src/commands/claude-managed-setup.ts +3 -1
- package/src/commands/codex-login.ts +67 -0
- package/src/commands/credential-outcome-report.ts +191 -0
- package/src/commands/rate-limit-outcome.ts +34 -4
- package/src/commands/runner.ts +357 -186
- package/src/commands/seat-mismatch-report.ts +46 -0
- package/src/extensions/apply-task-create.ts +27 -1
- package/src/extensions/contract-types.generated.ts +1 -1
- package/src/heartbeat/heartbeat.ts +79 -17
- package/src/heartbeat/templates.ts +2 -2
- package/src/http/agents.ts +62 -1
- package/src/http/api-keys.ts +140 -2
- package/src/http/codex-oauth-keep-warm.ts +3 -5
- package/src/http/index.ts +8 -0
- package/src/http/memory.ts +12 -5
- package/src/http/models-catalog.ts +357 -8
- package/src/http/poll.ts +54 -3
- package/src/http/schedules.ts +51 -6
- package/src/http/script-runs.ts +12 -0
- package/src/http/session-data.ts +2 -5
- package/src/http/stats.ts +6 -8
- package/src/http/status.ts +15 -1
- package/src/http/tasks.ts +90 -7
- package/src/http/usage-cache.ts +56 -15
- package/src/http/workflows.ts +46 -8
- package/src/mcp-client/http-client.ts +5 -0
- package/src/memory/recall-query.ts +74 -0
- package/src/prompts/base-prompt.ts +15 -4
- package/src/prompts/session-templates.ts +23 -1
- package/src/providers/acp-adapter.ts +1 -0
- package/src/providers/claude-adapter.ts +14 -5
- package/src/providers/claude-managed-adapter.ts +1 -0
- package/src/providers/claude-managed-models.ts +47 -161
- package/src/providers/claude-sdk-session.ts +3 -1
- package/src/providers/codex-adapter.ts +14 -14
- package/src/providers/codex-models.ts +65 -198
- package/src/providers/devin-adapter.ts +1 -0
- package/src/providers/dsh-adapter.ts +2 -1
- package/src/providers/harness-version.ts +83 -7
- package/src/providers/opencode-adapter.ts +53 -1
- package/src/providers/pi-binary-root/src/extensions/codemode/worker.ts +11 -0
- package/src/providers/pi-codemode-runtime.ts +17 -0
- package/src/providers/pi-mono-adapter.ts +361 -83
- package/src/providers/pi-mono-extension.ts +16 -1
- package/src/providers/reasoning-effort.ts +44 -140
- package/src/providers/types.ts +8 -0
- package/src/rbac/legacy-policy.ts +43 -0
- package/src/rbac/permissions.ts +15 -0
- package/src/scripts-runtime/sdk-allowlist.ts +4 -0
- package/src/scripts-runtime/types/stdlib.d.ts +15 -0
- package/src/scripts-runtime/types/swarm-extension.d.ts +3 -0
- package/src/scripts-runtime/types/swarm-sdk.d.ts +15 -0
- package/src/server.ts +6 -0
- package/src/slack/assistant.ts +13 -0
- package/src/slack/message-text.ts +56 -2
- package/src/slack/render-v2.ts +87 -37
- package/src/slack/session-status.ts +541 -0
- package/src/slack/thread-buffer.ts +10 -2
- package/src/tasks/sibling-awareness.ts +3 -2
- package/src/telemetry.ts +5 -4
- package/src/templates.d.ts +6 -0
- package/src/tests/agents-list-model-display.test.ts +4 -6
- package/src/tests/api-key-auth-failure-route.test.ts +142 -0
- package/src/tests/api-key-tracking.test.ts +368 -1
- package/src/tests/base-prompt.test.ts +43 -2
- package/src/tests/claude-adapter.test.ts +68 -0
- package/src/tests/claude-managed-adapter.test.ts +12 -18
- package/src/tests/codex-adapter.test.ts +2 -1
- package/src/tests/codex-auth-failure.test.ts +52 -0
- package/src/tests/codex-gpt6-release.test.ts +66 -5
- package/src/tests/codex-login.test.ts +116 -0
- package/src/tests/context-window.test.ts +7 -5
- package/src/tests/credential-exhaustion-policy.test.ts +118 -3
- package/src/tests/credential-outcome-report.test.ts +171 -0
- package/src/tests/credential-status-api.test.ts +103 -2
- package/src/tests/db-extraction-contract.test.ts +1 -0
- package/src/tests/db-task-read-contract.test.ts +10 -1
- package/src/tests/db-task-write-contract.test.ts +535 -2
- package/src/tests/docs-index-footprint.test.js +3 -3
- package/src/tests/dokploy-deploy.test.ts +315 -0
- package/src/tests/dsh-adapter.test.ts +1 -1
- package/src/tests/explicit-model-validation.test.ts +583 -0
- package/src/tests/extensions-pre-task.test.ts +73 -0
- package/src/tests/fetch-resolved-env.test.ts +46 -0
- package/src/tests/hang-watchdog-worker.ts +47 -0
- package/src/tests/hang-watchdog.test.ts +45 -0
- package/src/tests/hang-watchdog.ts +30 -0
- package/src/tests/harness-model-guard.test.ts +123 -0
- package/src/tests/harness-model-support.test.ts +374 -0
- package/src/tests/harness-version.test.ts +70 -3
- package/src/tests/heartbeat-checklist-config.test.ts +71 -0
- package/src/tests/heartbeat-checklist.test.ts +4 -2
- package/src/tests/heartbeat-orphan-resume.test.ts +48 -0
- package/src/tests/http-task-write-ownership.test.ts +172 -0
- package/src/tests/human-free-flag.test.ts +279 -0
- package/src/tests/human-free-oracle.ts +57 -0
- package/src/tests/human-free-reclassify.test.ts +669 -0
- package/src/tests/memory-fts-populate.test.ts +139 -0
- package/src/tests/memory-http-recall-gating.test.ts +125 -1
- package/src/tests/migration-046-budgets.test.ts +3 -3
- package/src/tests/model-catalog-migration.test.ts +134 -0
- package/src/tests/model-catalog-table.test.ts +249 -0
- package/src/tests/model-catalog-write-access.test.ts +387 -0
- package/src/tests/model-rate-limit-windows.test.ts +19 -0
- package/src/tests/model-tier-resolution.test.ts +611 -0
- package/src/tests/models-catalog.test.ts +1 -1
- package/src/tests/multi-runtime-enabled-stats.test.ts +65 -1
- package/src/tests/opencode-adapter.test.ts +157 -2
- package/src/tests/package-publish.test.ts +137 -36
- package/src/tests/pi-codemode.test.ts +246 -0
- package/src/tests/pi-mono-adapter.test.ts +3 -0
- package/src/tests/pi-native-mcp.test.ts +193 -0
- package/src/tests/pi-tool-exposure.test.ts +374 -0
- package/src/tests/preload.ts +3 -0
- package/src/tests/pricing-routes.test.ts +2 -2
- package/src/tests/prompt-template-session.test.ts +5 -3
- package/src/tests/rate-limit-event.test.ts +65 -0
- package/src/tests/rate-limit-outcome.test.ts +90 -0
- package/src/tests/rbac-engine.test.ts +77 -3
- package/src/tests/reasoning-effort.test.ts +109 -0
- package/src/tests/refresh-modelsdev-carryforward.test.ts +5 -5
- package/src/tests/runner-key-completion-outcome.test.ts +112 -0
- package/src/tests/runner-key-outcome-late-reset.test.ts +224 -0
- package/src/tests/runner-registration-retry.test.ts +149 -0
- package/src/tests/runtime-model-catalog.test.ts +86 -0
- package/src/tests/script-connections.test.ts +9 -0
- package/src/tests/seat-mismatch-report.test.ts +85 -0
- package/src/tests/seed-scripts.test.ts +138 -0
- package/src/tests/seed.test.ts +25 -0
- package/src/tests/session-costs.test.ts +14 -11
- package/src/tests/slack-message-text.test.ts +101 -0
- package/src/tests/slack-render-v2.test.ts +96 -0
- package/src/tests/slack-session-status.test.ts +626 -0
- package/src/tests/slack-thread-buffer-context.test.ts +93 -0
- package/src/tests/status.test.ts +29 -0
- package/src/tests/steering-promotion.test.ts +51 -0
- package/src/tests/store-progress-ownership.test.ts +136 -0
- package/src/tests/subscription-plans.test.ts +28 -0
- package/src/tests/task-cascade-fail.test.ts +148 -2
- package/src/tests/task-citations.test.ts +3 -2
- package/src/tests/tool-annotations.test.ts +1 -1
- package/src/tests/usage-cache.test.ts +166 -0
- package/src/tests/workflow-agent-task.test.ts +30 -0
- package/src/tests/workflow-executors.test.ts +5 -2
- package/src/tests/workflow-system-one-decision-review.test.ts +1021 -0
- package/src/tests/workflow-system-one-decision-save-warnings.test.ts +365 -0
- package/src/tests/workflow-system-one-decision.test.ts +2063 -0
- package/src/tests/workflow-triggers-v2.test.ts +320 -0
- package/src/tools/model-catalog/index.ts +137 -0
- package/src/tools/schedules/create-schedule.ts +17 -2
- package/src/tools/schedules/patch-schedule.ts +31 -1
- package/src/tools/schedules/update-schedule.ts +31 -1
- package/src/tools/send-task.ts +18 -1
- package/src/tools/store-progress.ts +49 -4
- package/src/tools/task-action.ts +14 -1
- package/src/tools/tool-config.ts +3 -1
- package/src/tools/workflows/create-workflow.ts +17 -4
- package/src/tools/workflows/patch-workflow-node.ts +17 -7
- package/src/tools/workflows/patch-workflow.ts +9 -2
- package/src/tools/workflows/update-workflow.ts +17 -4
- package/src/types.ts +41 -1
- package/src/utils/codex-auth-failure.ts +34 -0
- package/src/utils/context-window.ts +47 -53
- package/src/utils/credentials.ts +72 -30
- package/src/utils/error-tracker.ts +80 -0
- package/src/utils/harness-cli-version.ts +115 -0
- package/src/utils/harness-model-error.ts +33 -0
- package/src/utils/model-rate-limit-windows.ts +12 -0
- package/src/utils/runtime-model-catalog.ts +152 -0
- package/src/utils/spawn-model-guard.ts +43 -0
- package/src/utils/subscription-plans.ts +22 -0
- package/src/workflows/approval-resolution.ts +39 -0
- package/src/workflows/definition.ts +7 -0
- package/src/workflows/engine.ts +69 -1
- package/src/workflows/executors/agent-task.ts +16 -6
- package/src/workflows/executors/base.ts +53 -0
- package/src/workflows/executors/human-in-the-loop.ts +8 -8
- package/src/workflows/executors/index.ts +1 -0
- package/src/workflows/executors/registry.ts +2 -0
- package/src/workflows/executors/system-one-decision.ts +1232 -0
- package/src/workflows/executors/system-one-providers.ts +301 -0
- package/src/workflows/executors/workflow-llm.ts +13 -1
- package/src/workflows/model-validation.ts +45 -0
- package/src/workflows/patch-definition.ts +5 -0
- package/src/workflows/readiness.ts +86 -0
- package/src/workflows/recovery.ts +12 -12
- package/src/workflows/resume.ts +23 -9
- package/src/workflows/triggers.ts +85 -0
- package/templates/schedules/daily-blocker-digest/content.md +4 -5
- package/templates/skills/agent-browser/SKILL.md +6 -5
- package/templates/skills/agent-browser/content.md +6 -5
- package/templates/skills/heartbeat-runbook/config.json +1 -1
- package/templates/skills/heartbeat-runbook/content.md +2 -2
- package/templates/skills/swarm-scripts/SKILL.md +1 -1
- package/templates/skills/swarm-scripts/content.md +1 -1
- package/templates/skills/workflow-iterate/content.md +82 -1
- package/templates/workflows/claude-code-changelog-watch/content.md +2 -0
- package/templates/workflows/pr-review-status-sweep/content.md +2 -0
- package/dist/boot-seeds-s3q01xj3.js +0 -26
- package/dist/claude-sdk-session-t442qz6f.js +0 -39108
- package/dist/cli-0xjkj1j7.js +0 -61
- package/dist/cli-20cj37vt.js +0 -335561
- package/dist/cli-2djtr51b.js +0 -48
- package/dist/cli-65hjmev5.js +0 -1141
- package/dist/cli-aw1jwp1r.js +0 -14075
- package/dist/cli-h967nb6r.js +0 -6603
- package/dist/cli-vapyk8sw.js +0 -20
- package/dist/cli-ws6rqycm.js +0 -247
- package/dist/pricing-refresh-v1cbr9te.js +0 -27
- package/src/providers/modelsdev-reasoning.json +0 -6453
- package/dist/{index-f24115ge.js → index-2wsdsnmm.js} +3 -3
|
@@ -1,355 +1,30 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getValidCodexOAuth,
|
|
3
3
|
persistCodexOAuth
|
|
4
|
-
} from "./cli-
|
|
4
|
+
} from "./cli-ygwm91nt.js";
|
|
5
5
|
import {
|
|
6
6
|
GITHUB_COPILOT_MODELS,
|
|
7
7
|
builtinModels,
|
|
8
|
-
getEnvApiKey,
|
|
9
8
|
normalizeRadiusGatewayUrl,
|
|
10
9
|
registerBundledOAuthFlowLoaders
|
|
11
|
-
} from "./cli-
|
|
10
|
+
} from "./cli-10nhj6xq.js";
|
|
12
11
|
import {
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
oauthErrorHtml,
|
|
13
|
+
oauthSuccessHtml
|
|
14
|
+
} from "./cli-rykfmgwg.js";
|
|
15
15
|
import {
|
|
16
|
-
|
|
17
|
-
} from "./cli-
|
|
16
|
+
getEnvApiKey
|
|
17
|
+
} from "./cli-trc24wk2.js";
|
|
18
18
|
import {
|
|
19
19
|
getProviderEnvValue
|
|
20
20
|
} from "./cli-btbzvq95.js";
|
|
21
21
|
import {
|
|
22
22
|
InMemoryCredentialStore
|
|
23
|
-
} from "./cli-
|
|
23
|
+
} from "./cli-ykk5jaax.js";
|
|
24
24
|
import {
|
|
25
25
|
__require
|
|
26
26
|
} from "./cli-bc05qbss.js";
|
|
27
27
|
|
|
28
|
-
// plugin/opencode-plugins/lib/memory-raters.ts
|
|
29
|
-
function getMemoryRaterNames() {
|
|
30
|
-
return (process.env.MEMORY_RATERS ?? "implicit-citation,explicit-self").split(",").map((name) => name.trim()).filter(Boolean);
|
|
31
|
-
}
|
|
32
|
-
// src/be/memory/raters/llm.ts
|
|
33
|
-
init_zod();
|
|
34
|
-
|
|
35
|
-
// src/be/memory/raters/llm-client.ts
|
|
36
|
-
var DEFAULT_TIMEOUT_MS = 30000;
|
|
37
|
-
var PROMPT_TEMPLATE = `You are scoring the usefulness of one retrieved memory.
|
|
38
|
-
|
|
39
|
-
Return ONLY a JSON object with these fields (no prose, no markdown):
|
|
40
|
-
{
|
|
41
|
-
"score": number, // 0 = misleading/unhelpful, 1 = highly useful
|
|
42
|
-
"reasoning": string // 1..500 chars, why
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
QUERY:
|
|
46
|
-
\${query}
|
|
47
|
-
|
|
48
|
-
MEMORY:
|
|
49
|
-
id: \${memoryId}
|
|
50
|
-
name: \${memoryName}
|
|
51
|
-
content: \${memoryContent}
|
|
52
|
-
|
|
53
|
-
AGENT RESPONSE / SUMMARY:
|
|
54
|
-
\${response}
|
|
55
|
-
|
|
56
|
-
Score 0..1.`;
|
|
57
|
-
var PLACEHOLDER_PREFIX = "$";
|
|
58
|
-
var QUERY_PLACEHOLDER = `${PLACEHOLDER_PREFIX}{query}`;
|
|
59
|
-
var MEMORY_ID_PLACEHOLDER = `${PLACEHOLDER_PREFIX}{memoryId}`;
|
|
60
|
-
var MEMORY_NAME_PLACEHOLDER = `${PLACEHOLDER_PREFIX}{memoryName}`;
|
|
61
|
-
var MEMORY_CONTENT_PLACEHOLDER = `${PLACEHOLDER_PREFIX}{memoryContent}`;
|
|
62
|
-
var RESPONSE_PLACEHOLDER = `${PLACEHOLDER_PREFIX}{response}`;
|
|
63
|
-
function buildPrompt(input) {
|
|
64
|
-
return PROMPT_TEMPLATE.replace(QUERY_PLACEHOLDER, input.query).replace(MEMORY_ID_PLACEHOLDER, input.memory.id).replace(MEMORY_NAME_PLACEHOLDER, input.memory.name).replace(MEMORY_CONTENT_PLACEHOLDER, input.memory.content).replace(RESPONSE_PLACEHOLDER, input.response);
|
|
65
|
-
}
|
|
66
|
-
function parseScoreAndReasoning(raw) {
|
|
67
|
-
if (typeof raw !== "string")
|
|
68
|
-
return null;
|
|
69
|
-
let parsed;
|
|
70
|
-
try {
|
|
71
|
-
parsed = JSON.parse(raw.trim());
|
|
72
|
-
} catch {
|
|
73
|
-
return null;
|
|
74
|
-
}
|
|
75
|
-
if (!parsed || typeof parsed !== "object")
|
|
76
|
-
return null;
|
|
77
|
-
const obj = parsed;
|
|
78
|
-
const score = typeof obj.score === "number" ? obj.score : null;
|
|
79
|
-
const reasoning = typeof obj.reasoning === "string" ? obj.reasoning : null;
|
|
80
|
-
if (score == null || reasoning == null)
|
|
81
|
-
return null;
|
|
82
|
-
if (!Number.isFinite(score) || score < 0 || score > 1)
|
|
83
|
-
return null;
|
|
84
|
-
if (reasoning.length === 0 || reasoning.length > 500)
|
|
85
|
-
return null;
|
|
86
|
-
return { score, reasoning };
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
class ClaudeCliLlmRaterClient {
|
|
90
|
-
model;
|
|
91
|
-
timeoutMs;
|
|
92
|
-
constructor(opts = {}) {
|
|
93
|
-
this.model = opts.model ?? process.env.MEMORY_LLM_RATER_MODEL ?? "haiku";
|
|
94
|
-
this.timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
95
|
-
}
|
|
96
|
-
async rate(input) {
|
|
97
|
-
const prompt = buildPrompt(input);
|
|
98
|
-
const tmpFile = `/tmp/llm-rater-${Date.now()}-${Math.random().toString(36).slice(2)}.txt`;
|
|
99
|
-
let stdout = "";
|
|
100
|
-
try {
|
|
101
|
-
await Bun.write(tmpFile, prompt);
|
|
102
|
-
const proc = Bun.spawn(["bash", "-c", `cat "${tmpFile}" | claude -p --model ${this.model} --output-format json`], {
|
|
103
|
-
stdout: "pipe",
|
|
104
|
-
stderr: "pipe",
|
|
105
|
-
env: { ...process.env, SKIP_SESSION_SUMMARY: "1" }
|
|
106
|
-
});
|
|
107
|
-
const timeoutId = setTimeout(() => proc.kill(), this.timeoutMs);
|
|
108
|
-
stdout = await new Response(proc.stdout).text();
|
|
109
|
-
clearTimeout(timeoutId);
|
|
110
|
-
} catch (err) {
|
|
111
|
-
console.error("[memory-rater:llm] claude -p shell-out failed:", err.message);
|
|
112
|
-
return null;
|
|
113
|
-
} finally {
|
|
114
|
-
try {
|
|
115
|
-
await Bun.$`rm -f ${tmpFile}`.quiet();
|
|
116
|
-
} catch {}
|
|
117
|
-
}
|
|
118
|
-
let envelope;
|
|
119
|
-
try {
|
|
120
|
-
envelope = JSON.parse(stdout);
|
|
121
|
-
} catch {
|
|
122
|
-
return null;
|
|
123
|
-
}
|
|
124
|
-
return parseScoreAndReasoning(envelope.result);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// src/be/memory/raters/types.ts
|
|
129
|
-
var REFERENCES_SOURCE_MAX_LENGTH = 512;
|
|
130
|
-
var NUL_CHAR_CODE = 0;
|
|
131
|
-
var DEL_CHAR_CODE = 127;
|
|
132
|
-
var FIRST_PRINTABLE_ASCII = 32;
|
|
133
|
-
function sanitizeReferencesSource(input) {
|
|
134
|
-
let stripped = "";
|
|
135
|
-
for (let i = 0;i < input.length; i++) {
|
|
136
|
-
const code = input.charCodeAt(i);
|
|
137
|
-
if (code === NUL_CHAR_CODE)
|
|
138
|
-
return null;
|
|
139
|
-
if (code < FIRST_PRINTABLE_ASCII || code === DEL_CHAR_CODE) {
|
|
140
|
-
continue;
|
|
141
|
-
}
|
|
142
|
-
stripped += input[i];
|
|
143
|
-
}
|
|
144
|
-
if (stripped.length === 0)
|
|
145
|
-
return null;
|
|
146
|
-
return stripped;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// src/be/memory/raters/llm.ts
|
|
150
|
-
var LLM_RATER_WEIGHT = 0.8;
|
|
151
|
-
var RatingSchema = exports_external.object({
|
|
152
|
-
id: exports_external.string().min(1),
|
|
153
|
-
score: exports_external.number().min(0).max(1),
|
|
154
|
-
reasoning: exports_external.string().min(1).max(500),
|
|
155
|
-
referencesSource: exports_external.string().min(1).max(REFERENCES_SOURCE_MAX_LENGTH).optional()
|
|
156
|
-
});
|
|
157
|
-
var SummaryWithRatingsSchema = exports_external.object({
|
|
158
|
-
summary: exports_external.string(),
|
|
159
|
-
ratings: exports_external.array(RatingSchema).default([])
|
|
160
|
-
});
|
|
161
|
-
var BASE_SUMMARIZE_PROMPT = `You are summarizing an AI agent's work session. Extract ONLY high-value learnings.
|
|
162
|
-
|
|
163
|
-
DO NOT include:
|
|
164
|
-
- Generic descriptions of what was done ("worked on task X")
|
|
165
|
-
- Tool calls or file reads
|
|
166
|
-
- Routine progress updates
|
|
167
|
-
|
|
168
|
-
DO include (if present):
|
|
169
|
-
- **Mistakes made and corrections** — what went wrong and what fixed it
|
|
170
|
-
- **Discovered patterns** — reusable approaches, APIs, or codebase conventions
|
|
171
|
-
- **Codebase knowledge** — important file paths, architecture decisions, gotchas
|
|
172
|
-
- **Environment knowledge** — service URLs, config details, tool quirks
|
|
173
|
-
- **Failed approaches** — what was tried and didn't work (and why)
|
|
174
|
-
|
|
175
|
-
Format as a bulleted list of concrete, reusable facts. If the session was routine with no significant learnings, respond with exactly: "No significant learnings."`;
|
|
176
|
-
|
|
177
|
-
class LlmRater {
|
|
178
|
-
client;
|
|
179
|
-
name = "llm";
|
|
180
|
-
constructor(client = new ClaudeCliLlmRaterClient) {
|
|
181
|
-
this.client = client;
|
|
182
|
-
}
|
|
183
|
-
async rate(ctx) {
|
|
184
|
-
const enriched = ctx;
|
|
185
|
-
if (enriched.retrievedMemoryIds.length === 0)
|
|
186
|
-
return [];
|
|
187
|
-
const memories = enriched.retrievedMemories;
|
|
188
|
-
if (!memories || memories.length === 0)
|
|
189
|
-
return [];
|
|
190
|
-
const events = [];
|
|
191
|
-
for (const memoryId of enriched.retrievedMemoryIds) {
|
|
192
|
-
const memory = memories.find((m) => m.id === memoryId);
|
|
193
|
-
if (!memory)
|
|
194
|
-
continue;
|
|
195
|
-
let result;
|
|
196
|
-
try {
|
|
197
|
-
result = await this.client.rate({
|
|
198
|
-
query: enriched.query ?? "",
|
|
199
|
-
memory,
|
|
200
|
-
response: enriched.response ?? enriched.evidence ?? ""
|
|
201
|
-
});
|
|
202
|
-
} catch (err) {
|
|
203
|
-
console.error(`[memory-rater:llm] client.rate threw for memoryId=${memoryId}:`, err.message);
|
|
204
|
-
continue;
|
|
205
|
-
}
|
|
206
|
-
if (!result)
|
|
207
|
-
continue;
|
|
208
|
-
events.push({
|
|
209
|
-
memoryId,
|
|
210
|
-
signal: 2 * result.score - 1,
|
|
211
|
-
weight: LLM_RATER_WEIGHT,
|
|
212
|
-
source: "",
|
|
213
|
-
reasoning: result.reasoning
|
|
214
|
-
});
|
|
215
|
-
}
|
|
216
|
-
return events;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
function buildRatingsFromLlm(ratings, retrievals) {
|
|
220
|
-
const allowed = new Set(retrievals.map((r) => r.id));
|
|
221
|
-
const events = [];
|
|
222
|
-
for (const r of ratings) {
|
|
223
|
-
if (!allowed.has(r.id))
|
|
224
|
-
continue;
|
|
225
|
-
let cleanedReferencesSource;
|
|
226
|
-
if (r.referencesSource !== undefined) {
|
|
227
|
-
const cleaned = sanitizeReferencesSource(r.referencesSource);
|
|
228
|
-
if (cleaned !== null) {
|
|
229
|
-
cleanedReferencesSource = cleaned;
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
events.push({
|
|
233
|
-
memoryId: r.id,
|
|
234
|
-
signal: 2 * r.score - 1,
|
|
235
|
-
weight: LLM_RATER_WEIGHT,
|
|
236
|
-
source: "llm",
|
|
237
|
-
reasoning: r.reasoning,
|
|
238
|
-
...cleanedReferencesSource !== undefined ? { referencesSource: cleanedReferencesSource } : {}
|
|
239
|
-
});
|
|
240
|
-
}
|
|
241
|
-
return events;
|
|
242
|
-
}
|
|
243
|
-
var RETRIEVAL_PROMPT_CONTENT_CAP = 600;
|
|
244
|
-
function buildSummaryWithRatingsPrompt(basePrompt, retrievals) {
|
|
245
|
-
if (retrievals.length === 0)
|
|
246
|
-
return basePrompt;
|
|
247
|
-
const memoryBlock = retrievals.map((m, i) => {
|
|
248
|
-
const content = m.content.length > RETRIEVAL_PROMPT_CONTENT_CAP ? `${m.content.slice(0, RETRIEVAL_PROMPT_CONTENT_CAP)}…` : m.content;
|
|
249
|
-
return `Memory #${i + 1}
|
|
250
|
-
id: ${m.id}
|
|
251
|
-
name: ${m.name}
|
|
252
|
-
content: ${content}`;
|
|
253
|
-
}).join(`
|
|
254
|
-
|
|
255
|
-
`);
|
|
256
|
-
return `${basePrompt}
|
|
257
|
-
|
|
258
|
-
CRITICAL: Your entire response MUST be a single JSON object that conforms to the schema below. Do NOT wrap it in triple-backtick fences (no \`\`\`json or \`\`\`), do NOT add a prose preamble, do NOT add trailing commentary. Just the JSON object, nothing else.
|
|
259
|
-
|
|
260
|
-
Schema:
|
|
261
|
-
{
|
|
262
|
-
"summary": string, // your existing summary text
|
|
263
|
-
"ratings": [ // one entry per memory you can score
|
|
264
|
-
{
|
|
265
|
-
"id": string, // memory id, copied from the list below
|
|
266
|
-
"score": number, // 0 = misleading/unhelpful, 1 = highly useful
|
|
267
|
-
"reasoning": string, // 1..500 chars, why
|
|
268
|
-
"referencesSource": string // OPTIONAL — see note below
|
|
269
|
-
}
|
|
270
|
-
]
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
Score ONLY memories present in the list below. Use the exact ids. Omit any you cannot evaluate.
|
|
274
|
-
|
|
275
|
-
Optionally for each rating, if the memory clearly references a specific external source (a GitHub PR/issue, a Linear issue, a customer, a Slack thread, an AgentMail thread, etc.), include a \`referencesSource\` string using the convention "<source>:<identifier>" (e.g. "github:owner/repo#N", "linear:KEY-N", "customer:<slug>"). Any prefix is fine — pick what matches the source. Omit the field if no clear external source.
|
|
276
|
-
|
|
277
|
-
Memories retrieved during this session:
|
|
278
|
-
|
|
279
|
-
${memoryBlock}`;
|
|
280
|
-
}
|
|
281
|
-
function isLlmRaterEnabled() {
|
|
282
|
-
return getMemoryRaterNames().includes("llm");
|
|
283
|
-
}
|
|
284
|
-
function dedupeRetrievalsForRater(rows) {
|
|
285
|
-
const seenSchedules = new Set;
|
|
286
|
-
const out = [];
|
|
287
|
-
for (const row of rows) {
|
|
288
|
-
const scheduleId = row.scheduleId;
|
|
289
|
-
if (typeof scheduleId === "string" && scheduleId.length > 0) {
|
|
290
|
-
if (seenSchedules.has(scheduleId))
|
|
291
|
-
continue;
|
|
292
|
-
seenSchedules.add(scheduleId);
|
|
293
|
-
}
|
|
294
|
-
out.push(row);
|
|
295
|
-
}
|
|
296
|
-
return out;
|
|
297
|
-
}
|
|
298
|
-
async function fetchRetrievalsForTask(opts) {
|
|
299
|
-
const fetchFn = opts.fetchImpl ?? fetch;
|
|
300
|
-
try {
|
|
301
|
-
const url = `${opts.apiUrl}/api/memory/retrievals?taskId=${encodeURIComponent(opts.taskId)}`;
|
|
302
|
-
const res = await fetchFn(url, {
|
|
303
|
-
headers: {
|
|
304
|
-
"X-Agent-ID": opts.agentId,
|
|
305
|
-
...opts.apiKey ? { Authorization: `Bearer ${opts.apiKey}` } : {}
|
|
306
|
-
}
|
|
307
|
-
});
|
|
308
|
-
if (!res.ok) {
|
|
309
|
-
console.error(`[memory-rater:llm] GET /api/memory/retrievals failed: ${res.status} ${res.statusText}`);
|
|
310
|
-
return [];
|
|
311
|
-
}
|
|
312
|
-
const body = await res.json();
|
|
313
|
-
return body.results ?? [];
|
|
314
|
-
} catch (err) {
|
|
315
|
-
console.error("[memory-rater:llm] fetchRetrievalsForTask threw:", err.message);
|
|
316
|
-
return [];
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
async function postRatings(opts) {
|
|
320
|
-
if (opts.events.length === 0)
|
|
321
|
-
return { ok: true, status: 0 };
|
|
322
|
-
const fetchFn = opts.fetchImpl ?? fetch;
|
|
323
|
-
const events = opts.events.map((e) => ({
|
|
324
|
-
memoryId: e.memoryId,
|
|
325
|
-
signal: e.signal,
|
|
326
|
-
weight: e.weight,
|
|
327
|
-
source: e.source,
|
|
328
|
-
...e.reasoning !== undefined ? { reasoning: e.reasoning } : {},
|
|
329
|
-
...e.referencesSource !== undefined ? { referencesSource: e.referencesSource } : {},
|
|
330
|
-
...opts.taskId ? { taskId: opts.taskId } : {}
|
|
331
|
-
}));
|
|
332
|
-
try {
|
|
333
|
-
const res = await fetchFn(`${opts.apiUrl}/api/memory/rate`, {
|
|
334
|
-
method: "POST",
|
|
335
|
-
headers: {
|
|
336
|
-
"Content-Type": "application/json",
|
|
337
|
-
"X-Agent-ID": opts.agentId,
|
|
338
|
-
...opts.apiKey ? { Authorization: `Bearer ${opts.apiKey}` } : {}
|
|
339
|
-
},
|
|
340
|
-
body: JSON.stringify({ events })
|
|
341
|
-
});
|
|
342
|
-
if (!res.ok) {
|
|
343
|
-
const text = await res.text().catch(() => "");
|
|
344
|
-
console.error(`[memory-rater:llm] POST /api/memory/rate failed: ${res.status} ${res.statusText} ${text.slice(0, 200)}`);
|
|
345
|
-
}
|
|
346
|
-
return { ok: res.ok, status: res.status };
|
|
347
|
-
} catch (err) {
|
|
348
|
-
console.error("[memory-rater:llm] postRatings threw:", err.message);
|
|
349
|
-
return { ok: false, status: 0 };
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
|
|
353
28
|
// src/utils/internal-ai/models.ts
|
|
354
29
|
var DEFAULT_MODEL = {
|
|
355
30
|
openrouter: "openrouter/deepseek/deepseek-v4.1-flash",
|
|
@@ -368,105 +43,135 @@ function parseModelStr(modelStr) {
|
|
|
368
43
|
return [modelStr.slice(0, idx), modelStr.slice(idx + 1)];
|
|
369
44
|
}
|
|
370
45
|
|
|
371
|
-
// node_modules/@earendil-works/pi-ai/dist/auth/oauth/
|
|
372
|
-
|
|
373
|
-
function
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
const
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
${details ? `<div class="details">${details}</div>` : ""}
|
|
452
|
-
</main>
|
|
453
|
-
</body>
|
|
454
|
-
</html>`;
|
|
455
|
-
}
|
|
456
|
-
function oauthSuccessHtml(message) {
|
|
457
|
-
return renderPage({
|
|
458
|
-
title: "Authentication successful",
|
|
459
|
-
heading: "Authentication successful",
|
|
460
|
-
message
|
|
46
|
+
// node_modules/@earendil-works/pi-ai/dist/auth/oauth/callback-server.js
|
|
47
|
+
import { createServer } from "node:http";
|
|
48
|
+
function sendPage(response, status, html) {
|
|
49
|
+
response.writeHead(status, { "content-type": "text/html; charset=utf-8", "cache-control": "no-store" });
|
|
50
|
+
response.end(html);
|
|
51
|
+
}
|
|
52
|
+
async function startOAuthCallbackServer(options) {
|
|
53
|
+
const { providerName, signal } = options;
|
|
54
|
+
if (signal?.aborted)
|
|
55
|
+
throw new Error("Login cancelled");
|
|
56
|
+
let resolveWait = () => {};
|
|
57
|
+
let rejectWait = () => {};
|
|
58
|
+
const waitPromise = new Promise((resolve, reject) => {
|
|
59
|
+
resolveWait = resolve;
|
|
60
|
+
rejectWait = reject;
|
|
61
|
+
});
|
|
62
|
+
waitPromise.catch(() => {
|
|
63
|
+
return;
|
|
64
|
+
});
|
|
65
|
+
let claimed = false;
|
|
66
|
+
let settled = false;
|
|
67
|
+
let timer;
|
|
68
|
+
const onAbort = () => finish({ error: new Error("Login cancelled") });
|
|
69
|
+
const finish = (result) => {
|
|
70
|
+
if (settled)
|
|
71
|
+
return;
|
|
72
|
+
settled = true;
|
|
73
|
+
if (timer)
|
|
74
|
+
clearTimeout(timer);
|
|
75
|
+
signal?.removeEventListener("abort", onAbort);
|
|
76
|
+
if ("error" in result)
|
|
77
|
+
rejectWait(result.error);
|
|
78
|
+
else
|
|
79
|
+
resolveWait(result.value);
|
|
80
|
+
};
|
|
81
|
+
const server = createServer((request, response) => {
|
|
82
|
+
(async () => {
|
|
83
|
+
const url = new URL(request.url ?? "/", "http://localhost");
|
|
84
|
+
if (request.method !== "GET" || url.pathname !== options.path) {
|
|
85
|
+
sendPage(response, 404, oauthErrorHtml("Callback route not found."));
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
if (options.state !== undefined && url.searchParams.get("state") !== options.state) {
|
|
89
|
+
sendPage(response, 400, oauthErrorHtml("State mismatch."));
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (claimed || settled) {
|
|
93
|
+
sendPage(response, 409, oauthErrorHtml("This sign-in has already been handled."));
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const error = url.searchParams.get("error");
|
|
97
|
+
if (error) {
|
|
98
|
+
const description = url.searchParams.get("error_description") ?? error;
|
|
99
|
+
sendPage(response, 400, oauthErrorHtml(`${providerName} authorization failed.`, description));
|
|
100
|
+
finish({ error: new Error(`${providerName} authorization failed: ${description}`) });
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const code = url.searchParams.get("code");
|
|
104
|
+
if (!code) {
|
|
105
|
+
sendPage(response, 400, oauthErrorHtml("Missing authorization code."));
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
claimed = true;
|
|
109
|
+
try {
|
|
110
|
+
const value = await options.complete(code);
|
|
111
|
+
sendPage(response, 200, oauthSuccessHtml(`Signed in to ${providerName}. You may now close this page.`));
|
|
112
|
+
finish({ value });
|
|
113
|
+
} catch (error2) {
|
|
114
|
+
const failure = error2 instanceof Error ? error2 : new Error(String(error2));
|
|
115
|
+
sendPage(response, 502, oauthErrorHtml(`${providerName} sign-in failed.`, failure.message));
|
|
116
|
+
finish({ error: failure });
|
|
117
|
+
}
|
|
118
|
+
})();
|
|
119
|
+
});
|
|
120
|
+
await new Promise((resolve, reject) => {
|
|
121
|
+
server.once("error", reject);
|
|
122
|
+
server.listen(options.port, options.host, () => {
|
|
123
|
+
server.off("error", reject);
|
|
124
|
+
resolve();
|
|
125
|
+
});
|
|
461
126
|
});
|
|
127
|
+
const address = server.address();
|
|
128
|
+
if (!address || typeof address === "string") {
|
|
129
|
+
server.close();
|
|
130
|
+
throw new Error("OAuth callback server did not bind to TCP");
|
|
131
|
+
}
|
|
132
|
+
server.on("error", (error) => finish({ error }));
|
|
133
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
134
|
+
if (options.timeoutMs !== undefined) {
|
|
135
|
+
timer = setTimeout(() => finish({ error: new Error(`${providerName} sign-in timed out`) }), options.timeoutMs);
|
|
136
|
+
}
|
|
137
|
+
const redirectHost = options.redirectHost ?? options.host;
|
|
138
|
+
return {
|
|
139
|
+
redirectUri: `http://${redirectHost.includes(":") ? `[${redirectHost}]` : redirectHost}:${address.port}${options.path}`,
|
|
140
|
+
wait: () => waitPromise,
|
|
141
|
+
cancel: () => {
|
|
142
|
+
if (!claimed)
|
|
143
|
+
finish({ value: undefined });
|
|
144
|
+
},
|
|
145
|
+
close: () => {
|
|
146
|
+
finish({ error: new Error("OAuth callback server closed") });
|
|
147
|
+
server.close();
|
|
148
|
+
}
|
|
149
|
+
};
|
|
462
150
|
}
|
|
463
|
-
function
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
151
|
+
async function waitForCallbackOrManualInput(interaction, callback, prompt) {
|
|
152
|
+
const manualAbort = new AbortController;
|
|
153
|
+
let manualError;
|
|
154
|
+
const manual = interaction.prompt({ type: "manual_code", ...prompt, signal: manualAbort.signal }).then((input) => {
|
|
155
|
+
callback?.cancel();
|
|
156
|
+
return input;
|
|
157
|
+
}).catch((error) => {
|
|
158
|
+
manualError = error instanceof Error ? error : new Error(String(error));
|
|
159
|
+
callback?.cancel();
|
|
160
|
+
return;
|
|
469
161
|
});
|
|
162
|
+
try {
|
|
163
|
+
const value = await callback?.wait();
|
|
164
|
+
if (manualError)
|
|
165
|
+
throw manualError;
|
|
166
|
+
if (value !== undefined)
|
|
167
|
+
return { type: "callback", value };
|
|
168
|
+
const input = await manual;
|
|
169
|
+
if (manualError)
|
|
170
|
+
throw manualError;
|
|
171
|
+
return { type: "manual", input: input ?? "" };
|
|
172
|
+
} finally {
|
|
173
|
+
manualAbort.abort();
|
|
174
|
+
}
|
|
470
175
|
}
|
|
471
176
|
|
|
472
177
|
// node_modules/@earendil-works/pi-ai/dist/auth/oauth/pkce.js
|
|
@@ -489,8 +194,6 @@ async function generatePKCE() {
|
|
|
489
194
|
}
|
|
490
195
|
|
|
491
196
|
// node_modules/@earendil-works/pi-ai/dist/auth/oauth/anthropic.js
|
|
492
|
-
var nodeApis = null;
|
|
493
|
-
var nodeApisPromise = null;
|
|
494
197
|
var decode = (s) => atob(s);
|
|
495
198
|
var CLIENT_ID = decode("OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl");
|
|
496
199
|
var AUTHORIZE_URL = "https://claude.ai/oauth/authorize";
|
|
@@ -500,20 +203,6 @@ var CALLBACK_PORT = 53692;
|
|
|
500
203
|
var CALLBACK_PATH = "/callback";
|
|
501
204
|
var REDIRECT_URI = `http://localhost:${CALLBACK_PORT}${CALLBACK_PATH}`;
|
|
502
205
|
var SCOPES = "org:create_api_key user:profile user:inference user:sessions:claude_code user:mcp_servers user:file_upload";
|
|
503
|
-
async function getNodeApis() {
|
|
504
|
-
if (nodeApis)
|
|
505
|
-
return nodeApis;
|
|
506
|
-
if (!nodeApisPromise) {
|
|
507
|
-
if (typeof process === "undefined" || !process.versions?.node && !process.versions?.bun) {
|
|
508
|
-
throw new Error("Anthropic OAuth is only available in Node.js environments");
|
|
509
|
-
}
|
|
510
|
-
nodeApisPromise = import("node:http").then((httpModule) => ({
|
|
511
|
-
createServer: httpModule.createServer
|
|
512
|
-
}));
|
|
513
|
-
}
|
|
514
|
-
nodeApis = await nodeApisPromise;
|
|
515
|
-
return nodeApis;
|
|
516
|
-
}
|
|
517
206
|
function parseAuthorizationInput(input) {
|
|
518
207
|
const value = input.trim();
|
|
519
208
|
if (!value)
|
|
@@ -556,68 +245,6 @@ function formatErrorDetails(error) {
|
|
|
556
245
|
}
|
|
557
246
|
return String(error);
|
|
558
247
|
}
|
|
559
|
-
async function startCallbackServer(expectedState) {
|
|
560
|
-
const { createServer } = await getNodeApis();
|
|
561
|
-
return new Promise((resolve, reject) => {
|
|
562
|
-
let settleWait;
|
|
563
|
-
const waitForCodePromise = new Promise((resolveWait) => {
|
|
564
|
-
let settled = false;
|
|
565
|
-
settleWait = (value) => {
|
|
566
|
-
if (settled)
|
|
567
|
-
return;
|
|
568
|
-
settled = true;
|
|
569
|
-
resolveWait(value);
|
|
570
|
-
};
|
|
571
|
-
});
|
|
572
|
-
const server = createServer((req, res) => {
|
|
573
|
-
try {
|
|
574
|
-
const url = new URL(req.url || "", "http://localhost");
|
|
575
|
-
if (url.pathname !== CALLBACK_PATH) {
|
|
576
|
-
res.writeHead(404, { "Content-Type": "text/html; charset=utf-8" });
|
|
577
|
-
res.end(oauthErrorHtml("Callback route not found."));
|
|
578
|
-
return;
|
|
579
|
-
}
|
|
580
|
-
const code = url.searchParams.get("code");
|
|
581
|
-
const state = url.searchParams.get("state");
|
|
582
|
-
const error = url.searchParams.get("error");
|
|
583
|
-
if (error) {
|
|
584
|
-
res.writeHead(400, { "Content-Type": "text/html; charset=utf-8" });
|
|
585
|
-
res.end(oauthErrorHtml("Anthropic authentication did not complete.", `Error: ${error}`));
|
|
586
|
-
return;
|
|
587
|
-
}
|
|
588
|
-
if (!code || !state) {
|
|
589
|
-
res.writeHead(400, { "Content-Type": "text/html; charset=utf-8" });
|
|
590
|
-
res.end(oauthErrorHtml("Missing code or state parameter."));
|
|
591
|
-
return;
|
|
592
|
-
}
|
|
593
|
-
if (state !== expectedState) {
|
|
594
|
-
res.writeHead(400, { "Content-Type": "text/html; charset=utf-8" });
|
|
595
|
-
res.end(oauthErrorHtml("State mismatch."));
|
|
596
|
-
return;
|
|
597
|
-
}
|
|
598
|
-
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
599
|
-
res.end(oauthSuccessHtml("Anthropic authentication completed. You can close this window."));
|
|
600
|
-
settleWait?.({ code, state });
|
|
601
|
-
} catch {
|
|
602
|
-
res.writeHead(500, { "Content-Type": "text/plain; charset=utf-8" });
|
|
603
|
-
res.end("Internal error");
|
|
604
|
-
}
|
|
605
|
-
});
|
|
606
|
-
server.on("error", (err) => {
|
|
607
|
-
reject(err);
|
|
608
|
-
});
|
|
609
|
-
server.listen(CALLBACK_PORT, CALLBACK_HOST, () => {
|
|
610
|
-
resolve({
|
|
611
|
-
server,
|
|
612
|
-
redirectUri: REDIRECT_URI,
|
|
613
|
-
cancelWait: () => {
|
|
614
|
-
settleWait?.(null);
|
|
615
|
-
},
|
|
616
|
-
waitForCode: () => waitForCodePromise
|
|
617
|
-
});
|
|
618
|
-
});
|
|
619
|
-
});
|
|
620
|
-
}
|
|
621
248
|
async function postJson(url, body, signal) {
|
|
622
249
|
const response = await fetch(url, {
|
|
623
250
|
method: "POST",
|
|
@@ -658,21 +285,22 @@ async function exchangeAuthorizationCode(code, state, verifier, redirectUri, sig
|
|
|
658
285
|
type: "oauth",
|
|
659
286
|
refresh: tokenData.refresh_token,
|
|
660
287
|
access: tokenData.access_token,
|
|
661
|
-
expires: Date.now() + tokenData.expires_in * 1000 -
|
|
288
|
+
expires: Date.now() + tokenData.expires_in * 1000 - 5 * 60 * 1000
|
|
662
289
|
};
|
|
663
290
|
}
|
|
664
291
|
async function loginAnthropic(interaction) {
|
|
665
292
|
const { verifier, challenge } = await generatePKCE();
|
|
666
|
-
const
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
293
|
+
const callback = await startOAuthCallbackServer({
|
|
294
|
+
providerName: "Anthropic",
|
|
295
|
+
host: CALLBACK_HOST,
|
|
296
|
+
port: CALLBACK_PORT,
|
|
297
|
+
path: CALLBACK_PATH,
|
|
298
|
+
state: verifier,
|
|
299
|
+
complete: async (code) => code,
|
|
300
|
+
signal: interaction.signal
|
|
301
|
+
}).catch(() => {
|
|
302
|
+
return;
|
|
303
|
+
});
|
|
676
304
|
try {
|
|
677
305
|
const authParams = new URLSearchParams({
|
|
678
306
|
code: "true",
|
|
@@ -689,53 +317,27 @@ async function loginAnthropic(interaction) {
|
|
|
689
317
|
url: `${AUTHORIZE_URL}?${authParams.toString()}`,
|
|
690
318
|
instructions: "Complete login in your browser. If the browser is on another machine, paste the final redirect URL here."
|
|
691
319
|
});
|
|
692
|
-
const
|
|
693
|
-
type: "manual_code",
|
|
320
|
+
const result = await waitForCallbackOrManualInput(interaction, callback, {
|
|
694
321
|
message: "Complete login in your browser, or paste the authorization code / redirect URL here:",
|
|
695
|
-
placeholder: REDIRECT_URI
|
|
696
|
-
signal: manualAbort.signal
|
|
697
|
-
}).then((input) => {
|
|
698
|
-
manualInput = input;
|
|
699
|
-
server.cancelWait();
|
|
700
|
-
}).catch((error) => {
|
|
701
|
-
manualError = error instanceof Error ? error : new Error(String(error));
|
|
702
|
-
server.cancelWait();
|
|
322
|
+
placeholder: REDIRECT_URI
|
|
703
323
|
});
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
} else if (manualInput) {
|
|
711
|
-
const parsed = parseAuthorizationInput(manualInput);
|
|
324
|
+
let code;
|
|
325
|
+
let state = verifier;
|
|
326
|
+
if (result.type === "callback") {
|
|
327
|
+
code = result.value;
|
|
328
|
+
} else {
|
|
329
|
+
const parsed = parseAuthorizationInput(result.input);
|
|
712
330
|
if (parsed.state && parsed.state !== verifier)
|
|
713
331
|
throw new Error("OAuth state mismatch");
|
|
714
332
|
code = parsed.code;
|
|
715
333
|
state = parsed.state ?? verifier;
|
|
716
334
|
}
|
|
717
|
-
if (!code) {
|
|
718
|
-
await manualPromise;
|
|
719
|
-
if (manualError)
|
|
720
|
-
throw manualError;
|
|
721
|
-
if (manualInput) {
|
|
722
|
-
const parsed = parseAuthorizationInput(manualInput);
|
|
723
|
-
if (parsed.state && parsed.state !== verifier)
|
|
724
|
-
throw new Error("OAuth state mismatch");
|
|
725
|
-
code = parsed.code;
|
|
726
|
-
state = parsed.state ?? verifier;
|
|
727
|
-
}
|
|
728
|
-
}
|
|
729
335
|
if (!code)
|
|
730
336
|
throw new Error("Missing authorization code");
|
|
731
|
-
if (!state)
|
|
732
|
-
throw new Error("Missing OAuth state");
|
|
733
337
|
interaction.notify({ type: "progress", message: "Exchanging authorization code for tokens..." });
|
|
734
|
-
return exchangeAuthorizationCode(code, state, verifier, REDIRECT_URI, interaction.signal);
|
|
338
|
+
return await exchangeAuthorizationCode(code, state, verifier, REDIRECT_URI, interaction.signal);
|
|
735
339
|
} finally {
|
|
736
|
-
|
|
737
|
-
manualAbort.abort();
|
|
738
|
-
server.server.close();
|
|
340
|
+
callback?.close();
|
|
739
341
|
}
|
|
740
342
|
}
|
|
741
343
|
async function refreshAnthropicToken(refreshToken, signal) {
|
|
@@ -759,7 +361,7 @@ async function refreshAnthropicToken(refreshToken, signal) {
|
|
|
759
361
|
type: "oauth",
|
|
760
362
|
refresh: data.refresh_token,
|
|
761
363
|
access: data.access_token,
|
|
762
|
-
expires: Date.now() + data.expires_in * 1000 -
|
|
364
|
+
expires: Date.now() + data.expires_in * 1000 - 5 * 60 * 1000
|
|
763
365
|
};
|
|
764
366
|
}
|
|
765
367
|
var anthropicOAuth = {
|
|
@@ -1577,22 +1179,258 @@ var metaOAuth = {
|
|
|
1577
1179
|
}
|
|
1578
1180
|
};
|
|
1579
1181
|
|
|
1182
|
+
// node_modules/@earendil-works/pi-ai/dist/auth/oauth/openai-chatgpt.js
|
|
1183
|
+
import { randomBytes } from "node:crypto";
|
|
1184
|
+
import { createServer as createServer2 } from "node:http";
|
|
1185
|
+
var DYNAMIC_CLIENT_ID = "dynamic_agent_client";
|
|
1186
|
+
var AGENT_NAME_HINT = "Pi";
|
|
1187
|
+
var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
1188
|
+
var AUTHORIZE_URL2 = "https://auth.openai.com/api/accounts/authorize";
|
|
1189
|
+
var TOKEN_URL2 = "https://auth.openai.com/api/accounts/oauth/token";
|
|
1190
|
+
var RESOURCE = "https://api.openai.com/v1";
|
|
1191
|
+
var CALLBACK_HOST2 = getProviderEnvValue("PI_OAUTH_CALLBACK_HOST") || "127.0.0.1";
|
|
1192
|
+
var CALLBACK_PORT2 = 1455;
|
|
1193
|
+
var CALLBACK_PATH2 = "/auth/callback";
|
|
1194
|
+
var REDIRECT_URI2 = `http://127.0.0.1:${CALLBACK_PORT2}${CALLBACK_PATH2}`;
|
|
1195
|
+
var DIRECT_TOKEN_SCOPE = "chatgpt.tokens.use.direct";
|
|
1196
|
+
var SCOPE = `openid profile email offline_access resource.invoke ${DIRECT_TOKEN_SCOPE}`;
|
|
1197
|
+
var EXPIRY_MARGIN_MS = 3 * 60 * 1000;
|
|
1198
|
+
function randomValue() {
|
|
1199
|
+
return randomBytes(32).toString("base64url");
|
|
1200
|
+
}
|
|
1201
|
+
function authorizationResultFromCallback(url, expectedState) {
|
|
1202
|
+
const code = url.searchParams.get("code");
|
|
1203
|
+
if (!code)
|
|
1204
|
+
throw new Error("Missing authorization code");
|
|
1205
|
+
const state = url.searchParams.get("state");
|
|
1206
|
+
if (!state)
|
|
1207
|
+
throw new Error("Missing OAuth state");
|
|
1208
|
+
if (state !== expectedState)
|
|
1209
|
+
throw new Error("OAuth state mismatch");
|
|
1210
|
+
const clientId = url.searchParams.get("client_id")?.trim();
|
|
1211
|
+
if (!clientId)
|
|
1212
|
+
throw new Error("OpenAI OAuth registration callback did not contain an issued client ID");
|
|
1213
|
+
return { code, clientId };
|
|
1214
|
+
}
|
|
1215
|
+
function authorizationResultFromManualInput(input, expectedState) {
|
|
1216
|
+
let url;
|
|
1217
|
+
try {
|
|
1218
|
+
url = new URL(input.trim());
|
|
1219
|
+
} catch {
|
|
1220
|
+
throw new Error("Paste the full callback URL from the browser");
|
|
1221
|
+
}
|
|
1222
|
+
const expected = new URL(REDIRECT_URI2);
|
|
1223
|
+
if (url.origin !== expected.origin || url.pathname !== expected.pathname) {
|
|
1224
|
+
throw new Error(`The pasted callback URL must start with ${REDIRECT_URI2}`);
|
|
1225
|
+
}
|
|
1226
|
+
const error = url.searchParams.get("error");
|
|
1227
|
+
if (error)
|
|
1228
|
+
throw new Error(`ChatGPT authorization failed: ${error}`);
|
|
1229
|
+
return authorizationResultFromCallback(url, expectedState);
|
|
1230
|
+
}
|
|
1231
|
+
function sendHtml(response, status, body) {
|
|
1232
|
+
response.writeHead(status, { "Content-Type": "text/html; charset=utf-8" });
|
|
1233
|
+
response.end(body);
|
|
1234
|
+
}
|
|
1235
|
+
function startCallbackServer(expectedState) {
|
|
1236
|
+
return new Promise((resolve, reject) => {
|
|
1237
|
+
let resolveResult;
|
|
1238
|
+
let rejectResult;
|
|
1239
|
+
const result = new Promise((resolveAuthorization, rejectAuthorization) => {
|
|
1240
|
+
resolveResult = resolveAuthorization;
|
|
1241
|
+
rejectResult = rejectAuthorization;
|
|
1242
|
+
});
|
|
1243
|
+
const server = createServer2((request, response) => {
|
|
1244
|
+
try {
|
|
1245
|
+
const url = new URL(request.url || "", REDIRECT_URI2);
|
|
1246
|
+
if (url.pathname !== CALLBACK_PATH2) {
|
|
1247
|
+
sendHtml(response, 404, oauthErrorHtml("Callback route not found."));
|
|
1248
|
+
return;
|
|
1249
|
+
}
|
|
1250
|
+
const error = url.searchParams.get("error");
|
|
1251
|
+
if (error) {
|
|
1252
|
+
sendHtml(response, 400, oauthErrorHtml("ChatGPT was not connected.", `Error: ${error}`));
|
|
1253
|
+
rejectResult(new Error(`ChatGPT authorization failed: ${error}`));
|
|
1254
|
+
return;
|
|
1255
|
+
}
|
|
1256
|
+
let authorizationResult;
|
|
1257
|
+
try {
|
|
1258
|
+
authorizationResult = authorizationResultFromCallback(url, expectedState);
|
|
1259
|
+
} catch (error2) {
|
|
1260
|
+
const message = error2 instanceof Error ? error2.message : "Invalid callback";
|
|
1261
|
+
sendHtml(response, 400, oauthErrorHtml(message));
|
|
1262
|
+
return;
|
|
1263
|
+
}
|
|
1264
|
+
sendHtml(response, 200, oauthSuccessHtml("ChatGPT authentication completed. You can close this window."));
|
|
1265
|
+
resolveResult(authorizationResult);
|
|
1266
|
+
} catch {
|
|
1267
|
+
sendHtml(response, 500, oauthErrorHtml("Internal error while processing the callback."));
|
|
1268
|
+
}
|
|
1269
|
+
});
|
|
1270
|
+
server.once("error", reject);
|
|
1271
|
+
server.listen(CALLBACK_PORT2, CALLBACK_HOST2, () => {
|
|
1272
|
+
server.removeListener("error", reject);
|
|
1273
|
+
server.on("error", rejectResult);
|
|
1274
|
+
resolve({ server, result });
|
|
1275
|
+
});
|
|
1276
|
+
});
|
|
1277
|
+
}
|
|
1278
|
+
async function requestToken(body, signal) {
|
|
1279
|
+
const response = await fetch(TOKEN_URL2, {
|
|
1280
|
+
method: "POST",
|
|
1281
|
+
headers: {
|
|
1282
|
+
accept: "application/json",
|
|
1283
|
+
"content-type": "application/x-www-form-urlencoded"
|
|
1284
|
+
},
|
|
1285
|
+
body,
|
|
1286
|
+
signal
|
|
1287
|
+
});
|
|
1288
|
+
if (!response.ok) {
|
|
1289
|
+
const responseBody = await response.text().catch(() => "");
|
|
1290
|
+
throw new Error(`OpenAI OAuth token request failed (${response.status}): ${responseBody || response.statusText}`);
|
|
1291
|
+
}
|
|
1292
|
+
const data = await response.json();
|
|
1293
|
+
if (typeof data !== "object" || data === null || Array.isArray(data)) {
|
|
1294
|
+
throw new Error("OpenAI OAuth token response must be an object");
|
|
1295
|
+
}
|
|
1296
|
+
return data;
|
|
1297
|
+
}
|
|
1298
|
+
function requireTokenString(value, field) {
|
|
1299
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
1300
|
+
throw new Error(`OpenAI OAuth token response has invalid ${field}`);
|
|
1301
|
+
}
|
|
1302
|
+
return value;
|
|
1303
|
+
}
|
|
1304
|
+
function credentialFromTokenResponse(token, clientId) {
|
|
1305
|
+
const access = requireTokenString(token.access_token, "access_token");
|
|
1306
|
+
const refresh = requireTokenString(token.refresh_token, "refresh_token");
|
|
1307
|
+
const scope = requireTokenString(token.scope, "scope");
|
|
1308
|
+
if (typeof token.expires_in !== "number" || !Number.isFinite(token.expires_in) || token.expires_in <= 0) {
|
|
1309
|
+
throw new Error("OpenAI OAuth token response has invalid expires_in");
|
|
1310
|
+
}
|
|
1311
|
+
const scopes = scope.trim().split(/\s+/).filter(Boolean);
|
|
1312
|
+
if (!scopes.includes(DIRECT_TOKEN_SCOPE)) {
|
|
1313
|
+
throw new Error(`OpenAI OAuth grant did not include ${DIRECT_TOKEN_SCOPE}`);
|
|
1314
|
+
}
|
|
1315
|
+
return {
|
|
1316
|
+
type: "oauth",
|
|
1317
|
+
access,
|
|
1318
|
+
refresh,
|
|
1319
|
+
expires: Date.now() + token.expires_in * 1000 - EXPIRY_MARGIN_MS,
|
|
1320
|
+
clientId,
|
|
1321
|
+
scopes
|
|
1322
|
+
};
|
|
1323
|
+
}
|
|
1324
|
+
async function exchangeAuthorizationCode2(code, verifier, clientId, signal) {
|
|
1325
|
+
const token = await requestToken(new URLSearchParams({
|
|
1326
|
+
grant_type: "authorization_code",
|
|
1327
|
+
client_id: clientId,
|
|
1328
|
+
code,
|
|
1329
|
+
code_verifier: verifier,
|
|
1330
|
+
redirect_uri: REDIRECT_URI2,
|
|
1331
|
+
resource: RESOURCE
|
|
1332
|
+
}), signal);
|
|
1333
|
+
if (typeof token.id_token !== "string" || token.id_token.trim().length === 0) {
|
|
1334
|
+
throw new Error("OpenAI OAuth token response did not contain an ID token");
|
|
1335
|
+
}
|
|
1336
|
+
return credentialFromTokenResponse(token, clientId);
|
|
1337
|
+
}
|
|
1338
|
+
async function refreshAccessToken(credential, signal) {
|
|
1339
|
+
const clientId = credential.clientId;
|
|
1340
|
+
if (typeof clientId !== "string" || clientId.trim().length === 0) {
|
|
1341
|
+
throw new Error("Stored OpenAI OAuth credential does not contain an issued client ID; reconnect ChatGPT");
|
|
1342
|
+
}
|
|
1343
|
+
const token = await requestToken(new URLSearchParams({
|
|
1344
|
+
grant_type: "refresh_token",
|
|
1345
|
+
client_id: clientId,
|
|
1346
|
+
refresh_token: credential.refresh,
|
|
1347
|
+
resource: RESOURCE
|
|
1348
|
+
}), signal);
|
|
1349
|
+
return credentialFromTokenResponse(token, clientId);
|
|
1350
|
+
}
|
|
1351
|
+
function agentHostId(deviceId) {
|
|
1352
|
+
if (!deviceId || !UUID_PATTERN.test(deviceId)) {
|
|
1353
|
+
throw new Error("Sign in with ChatGPT requires a device ID (UUID) for this installation");
|
|
1354
|
+
}
|
|
1355
|
+
return `urn:uuid:${deviceId.toLowerCase()}`;
|
|
1356
|
+
}
|
|
1357
|
+
async function loginOpenAIChatGPT(interaction, options) {
|
|
1358
|
+
const hostId = agentHostId(options?.getDeviceId?.());
|
|
1359
|
+
const { verifier, challenge } = await generatePKCE();
|
|
1360
|
+
const state = randomValue();
|
|
1361
|
+
const nonce = randomValue();
|
|
1362
|
+
let callback;
|
|
1363
|
+
try {
|
|
1364
|
+
callback = await startCallbackServer(state);
|
|
1365
|
+
} catch (error) {
|
|
1366
|
+
interaction.notify({
|
|
1367
|
+
type: "info",
|
|
1368
|
+
message: `Could not listen on ${REDIRECT_URI2}; paste the final redirect URL to continue. ${error instanceof Error ? error.message : String(error)}`
|
|
1369
|
+
});
|
|
1370
|
+
}
|
|
1371
|
+
const authorizationUrl = new URL(AUTHORIZE_URL2);
|
|
1372
|
+
authorizationUrl.search = new URLSearchParams({
|
|
1373
|
+
client_id: DYNAMIC_CLIENT_ID,
|
|
1374
|
+
agent_name_hint: AGENT_NAME_HINT,
|
|
1375
|
+
ext_agent_host_id: hostId,
|
|
1376
|
+
response_type: "code",
|
|
1377
|
+
redirect_uri: REDIRECT_URI2,
|
|
1378
|
+
resource: RESOURCE,
|
|
1379
|
+
scope: SCOPE,
|
|
1380
|
+
state,
|
|
1381
|
+
code_challenge: challenge,
|
|
1382
|
+
code_challenge_method: "S256",
|
|
1383
|
+
nonce
|
|
1384
|
+
}).toString();
|
|
1385
|
+
interaction.notify({
|
|
1386
|
+
type: "auth_url",
|
|
1387
|
+
url: authorizationUrl.toString(),
|
|
1388
|
+
instructions: "Complete sign-in in your browser. If the callback does not complete, paste the final redirect URL here."
|
|
1389
|
+
});
|
|
1390
|
+
const manualAbort = new AbortController;
|
|
1391
|
+
const manualCode = interaction.prompt({
|
|
1392
|
+
type: "manual_code",
|
|
1393
|
+
message: "Complete login in your browser, or paste the final redirect URL here:",
|
|
1394
|
+
placeholder: REDIRECT_URI2,
|
|
1395
|
+
signal: AbortSignal.any([manualAbort.signal, interaction.signal])
|
|
1396
|
+
}).then((input) => authorizationResultFromManualInput(input, state));
|
|
1397
|
+
try {
|
|
1398
|
+
const result = await (callback ? Promise.race([callback.result, manualCode]) : manualCode);
|
|
1399
|
+
interaction.notify({ type: "progress", message: "Exchanging authorization code for tokens..." });
|
|
1400
|
+
return await exchangeAuthorizationCode2(result.code, verifier, result.clientId, interaction.signal);
|
|
1401
|
+
} catch (error) {
|
|
1402
|
+
if (interaction.signal.aborted)
|
|
1403
|
+
throw new Error("Login cancelled");
|
|
1404
|
+
throw error;
|
|
1405
|
+
} finally {
|
|
1406
|
+
manualAbort.abort();
|
|
1407
|
+
callback?.server.close();
|
|
1408
|
+
callback?.server.closeAllConnections();
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
var openaiChatGPTOAuth = {
|
|
1412
|
+
name: "OpenAI (ChatGPT subscription)",
|
|
1413
|
+
isSubscription: true,
|
|
1414
|
+
loginLabel: "Sign in with ChatGPT",
|
|
1415
|
+
login: loginOpenAIChatGPT,
|
|
1416
|
+
refresh: refreshAccessToken,
|
|
1417
|
+
async toAuth(credential) {
|
|
1418
|
+
return { apiKey: credential.access };
|
|
1419
|
+
}
|
|
1420
|
+
};
|
|
1421
|
+
|
|
1580
1422
|
// node_modules/@earendil-works/pi-ai/dist/auth/oauth/openai-codex.js
|
|
1581
1423
|
var _randomBytes = null;
|
|
1582
|
-
var _http = null;
|
|
1583
1424
|
if (typeof process !== "undefined" && (process.versions?.node || process.versions?.bun)) {
|
|
1584
1425
|
import("node:crypto").then((m) => {
|
|
1585
1426
|
_randomBytes = m.randomBytes;
|
|
1586
1427
|
});
|
|
1587
|
-
import("node:http").then((m) => {
|
|
1588
|
-
_http = m;
|
|
1589
|
-
});
|
|
1590
1428
|
}
|
|
1591
1429
|
var CLIENT_ID5 = "app_EMoamEEZ73f0CkXaXp7hrann";
|
|
1592
1430
|
var AUTH_BASE_URL = "https://auth.openai.com";
|
|
1593
|
-
var
|
|
1594
|
-
var
|
|
1595
|
-
var
|
|
1431
|
+
var AUTHORIZE_URL3 = `${AUTH_BASE_URL}/oauth/authorize`;
|
|
1432
|
+
var TOKEN_URL3 = `${AUTH_BASE_URL}/oauth/token`;
|
|
1433
|
+
var REDIRECT_URI3 = "http://localhost:1455/auth/callback";
|
|
1596
1434
|
var DEVICE_USER_CODE_URL = `${AUTH_BASE_URL}/api/accounts/deviceauth/usercode`;
|
|
1597
1435
|
var DEVICE_TOKEN_URL2 = `${AUTH_BASE_URL}/api/accounts/deviceauth/token`;
|
|
1598
1436
|
var DEVICE_VERIFICATION_URI = `${AUTH_BASE_URL}/codex/device`;
|
|
@@ -1600,7 +1438,7 @@ var DEVICE_REDIRECT_URI = `${AUTH_BASE_URL}/deviceauth/callback`;
|
|
|
1600
1438
|
var DEVICE_CODE_TIMEOUT_SECONDS2 = 900;
|
|
1601
1439
|
var OPENAI_CODEX_BROWSER_LOGIN_METHOD = "browser";
|
|
1602
1440
|
var OPENAI_CODEX_DEVICE_CODE_LOGIN_METHOD = "device_code";
|
|
1603
|
-
var
|
|
1441
|
+
var SCOPE2 = "openid profile email offline_access";
|
|
1604
1442
|
var JWT_CLAIM_PATH = "https://api.openai.com/auth";
|
|
1605
1443
|
function getCallbackHost() {
|
|
1606
1444
|
return getProviderEnvValue("PI_OAUTH_CALLBACK_HOST") || "127.0.0.1";
|
|
@@ -1673,8 +1511,8 @@ async function readTokenResponse(response, operation) {
|
|
|
1673
1511
|
expires: Date.now() + json.expires_in * 1000
|
|
1674
1512
|
};
|
|
1675
1513
|
}
|
|
1676
|
-
async function
|
|
1677
|
-
const response = await fetchWithLoginCancellation(
|
|
1514
|
+
async function exchangeAuthorizationCode3(code, verifier, redirectUri, signal) {
|
|
1515
|
+
const response = await fetchWithLoginCancellation(TOKEN_URL3, {
|
|
1678
1516
|
method: "POST",
|
|
1679
1517
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
1680
1518
|
body: new URLSearchParams({
|
|
@@ -1688,10 +1526,10 @@ async function exchangeAuthorizationCode2(code, verifier, redirectUri, signal) {
|
|
|
1688
1526
|
});
|
|
1689
1527
|
return readTokenResponse(response, "exchange");
|
|
1690
1528
|
}
|
|
1691
|
-
async function
|
|
1529
|
+
async function refreshAccessToken2(refreshToken2, signal) {
|
|
1692
1530
|
let response;
|
|
1693
1531
|
try {
|
|
1694
|
-
response = await fetch(
|
|
1532
|
+
response = await fetch(TOKEN_URL3, {
|
|
1695
1533
|
method: "POST",
|
|
1696
1534
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
1697
1535
|
body: new URLSearchParams({
|
|
@@ -1787,11 +1625,11 @@ async function pollOpenAICodexDeviceAuth(device, signal) {
|
|
|
1787
1625
|
async function createAuthorizationFlow(originator = "pi") {
|
|
1788
1626
|
const { verifier, challenge } = await generatePKCE();
|
|
1789
1627
|
const state = createState();
|
|
1790
|
-
const url = new URL(
|
|
1628
|
+
const url = new URL(AUTHORIZE_URL3);
|
|
1791
1629
|
url.searchParams.set("response_type", "code");
|
|
1792
1630
|
url.searchParams.set("client_id", CLIENT_ID5);
|
|
1793
|
-
url.searchParams.set("redirect_uri",
|
|
1794
|
-
url.searchParams.set("scope",
|
|
1631
|
+
url.searchParams.set("redirect_uri", REDIRECT_URI3);
|
|
1632
|
+
url.searchParams.set("scope", SCOPE2);
|
|
1795
1633
|
url.searchParams.set("code_challenge", challenge);
|
|
1796
1634
|
url.searchParams.set("code_challenge_method", "S256");
|
|
1797
1635
|
url.searchParams.set("state", state);
|
|
@@ -1800,75 +1638,6 @@ async function createAuthorizationFlow(originator = "pi") {
|
|
|
1800
1638
|
url.searchParams.set("originator", originator);
|
|
1801
1639
|
return { verifier, state, url: url.toString() };
|
|
1802
1640
|
}
|
|
1803
|
-
function startLocalOAuthServer(state) {
|
|
1804
|
-
if (!_http) {
|
|
1805
|
-
throw new Error("OpenAI Codex OAuth is only available in Node.js environments");
|
|
1806
|
-
}
|
|
1807
|
-
let settleWait;
|
|
1808
|
-
const waitForCodePromise = new Promise((resolve) => {
|
|
1809
|
-
let settled = false;
|
|
1810
|
-
settleWait = (value) => {
|
|
1811
|
-
if (settled)
|
|
1812
|
-
return;
|
|
1813
|
-
settled = true;
|
|
1814
|
-
resolve(value);
|
|
1815
|
-
};
|
|
1816
|
-
});
|
|
1817
|
-
const server = _http.createServer((req, res) => {
|
|
1818
|
-
try {
|
|
1819
|
-
const url = new URL(req.url || "", "http://localhost");
|
|
1820
|
-
if (url.pathname !== "/auth/callback") {
|
|
1821
|
-
res.statusCode = 404;
|
|
1822
|
-
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
1823
|
-
res.end(oauthErrorHtml("Callback route not found."));
|
|
1824
|
-
return;
|
|
1825
|
-
}
|
|
1826
|
-
if (url.searchParams.get("state") !== state) {
|
|
1827
|
-
res.statusCode = 400;
|
|
1828
|
-
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
1829
|
-
res.end(oauthErrorHtml("State mismatch."));
|
|
1830
|
-
return;
|
|
1831
|
-
}
|
|
1832
|
-
const code = url.searchParams.get("code");
|
|
1833
|
-
if (!code) {
|
|
1834
|
-
res.statusCode = 400;
|
|
1835
|
-
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
1836
|
-
res.end(oauthErrorHtml("Missing authorization code."));
|
|
1837
|
-
return;
|
|
1838
|
-
}
|
|
1839
|
-
res.statusCode = 200;
|
|
1840
|
-
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
1841
|
-
res.end(oauthSuccessHtml("OpenAI authentication completed. You can close this window."));
|
|
1842
|
-
settleWait?.({ code });
|
|
1843
|
-
} catch {
|
|
1844
|
-
res.statusCode = 500;
|
|
1845
|
-
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
1846
|
-
res.end(oauthErrorHtml("Internal error while processing OAuth callback."));
|
|
1847
|
-
}
|
|
1848
|
-
});
|
|
1849
|
-
return new Promise((resolve) => {
|
|
1850
|
-
server.listen(1455, getCallbackHost(), () => {
|
|
1851
|
-
resolve({
|
|
1852
|
-
close: () => server.close(),
|
|
1853
|
-
cancelWait: () => {
|
|
1854
|
-
settleWait?.(null);
|
|
1855
|
-
},
|
|
1856
|
-
waitForCode: () => waitForCodePromise
|
|
1857
|
-
});
|
|
1858
|
-
}).on("error", (_err) => {
|
|
1859
|
-
settleWait?.(null);
|
|
1860
|
-
resolve({
|
|
1861
|
-
close: () => {
|
|
1862
|
-
try {
|
|
1863
|
-
server.close();
|
|
1864
|
-
} catch {}
|
|
1865
|
-
},
|
|
1866
|
-
cancelWait: () => {},
|
|
1867
|
-
waitForCode: async () => null
|
|
1868
|
-
});
|
|
1869
|
-
});
|
|
1870
|
-
});
|
|
1871
|
-
}
|
|
1872
1641
|
function getAccountId(accessToken) {
|
|
1873
1642
|
const payload = decodeJwt(accessToken);
|
|
1874
1643
|
const auth = payload?.[JWT_CLAIM_PATH];
|
|
@@ -1889,7 +1658,7 @@ function credentialsFromToken(token) {
|
|
|
1889
1658
|
};
|
|
1890
1659
|
}
|
|
1891
1660
|
async function exchangeAuthorizationCodeForCredentials(code, verifier, redirectUri, signal) {
|
|
1892
|
-
return credentialsFromToken(await
|
|
1661
|
+
return credentialsFromToken(await exchangeAuthorizationCode3(code, verifier, redirectUri, signal));
|
|
1893
1662
|
}
|
|
1894
1663
|
async function loginOpenAICodexDeviceCode(interaction) {
|
|
1895
1664
|
const device = await startOpenAICodexDeviceAuth(interaction.signal);
|
|
@@ -1905,66 +1674,45 @@ async function loginOpenAICodexDeviceCode(interaction) {
|
|
|
1905
1674
|
}
|
|
1906
1675
|
async function loginOpenAICodex(interaction) {
|
|
1907
1676
|
const { verifier, state, url } = await createAuthorizationFlow();
|
|
1908
|
-
const
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1677
|
+
const callback = await startOAuthCallbackServer({
|
|
1678
|
+
providerName: "OpenAI",
|
|
1679
|
+
host: getCallbackHost(),
|
|
1680
|
+
port: 1455,
|
|
1681
|
+
path: "/auth/callback",
|
|
1682
|
+
state,
|
|
1683
|
+
complete: async (code) => code,
|
|
1684
|
+
signal: interaction.signal
|
|
1685
|
+
}).catch(() => {
|
|
1686
|
+
return;
|
|
1687
|
+
});
|
|
1917
1688
|
interaction.notify({
|
|
1918
1689
|
type: "auth_url",
|
|
1919
1690
|
url,
|
|
1920
1691
|
instructions: "A browser window should open. Complete login to finish."
|
|
1921
1692
|
});
|
|
1922
1693
|
try {
|
|
1923
|
-
const
|
|
1924
|
-
type: "manual_code",
|
|
1694
|
+
const result = await waitForCallbackOrManualInput(interaction, callback, {
|
|
1925
1695
|
message: "Complete login in your browser, or paste the authorization code / redirect URL here:",
|
|
1926
|
-
placeholder:
|
|
1927
|
-
signal: manualAbort.signal
|
|
1928
|
-
}).then((input) => {
|
|
1929
|
-
manualCode = input;
|
|
1930
|
-
server.cancelWait();
|
|
1931
|
-
}).catch((error) => {
|
|
1932
|
-
manualError = error instanceof Error ? error : new Error(String(error));
|
|
1933
|
-
server.cancelWait();
|
|
1696
|
+
placeholder: REDIRECT_URI3
|
|
1934
1697
|
});
|
|
1935
|
-
|
|
1936
|
-
if (
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
} else if (manualCode) {
|
|
1941
|
-
const parsed = parseAuthorizationInput2(manualCode);
|
|
1698
|
+
let code;
|
|
1699
|
+
if (result.type === "callback") {
|
|
1700
|
+
code = result.value;
|
|
1701
|
+
} else {
|
|
1702
|
+
const parsed = parseAuthorizationInput2(result.input);
|
|
1942
1703
|
if (parsed.state && parsed.state !== state)
|
|
1943
1704
|
throw new Error("State mismatch");
|
|
1944
1705
|
code = parsed.code;
|
|
1945
1706
|
}
|
|
1946
|
-
if (!code) {
|
|
1947
|
-
await manualPromise;
|
|
1948
|
-
if (manualError)
|
|
1949
|
-
throw manualError;
|
|
1950
|
-
if (manualCode) {
|
|
1951
|
-
const parsed = parseAuthorizationInput2(manualCode);
|
|
1952
|
-
if (parsed.state && parsed.state !== state)
|
|
1953
|
-
throw new Error("State mismatch");
|
|
1954
|
-
code = parsed.code;
|
|
1955
|
-
}
|
|
1956
|
-
}
|
|
1957
1707
|
if (!code)
|
|
1958
1708
|
throw new Error("Missing authorization code");
|
|
1959
|
-
return exchangeAuthorizationCodeForCredentials(code, verifier,
|
|
1709
|
+
return await exchangeAuthorizationCodeForCredentials(code, verifier, REDIRECT_URI3, interaction.signal);
|
|
1960
1710
|
} finally {
|
|
1961
|
-
|
|
1962
|
-
manualAbort.abort();
|
|
1963
|
-
server.close();
|
|
1711
|
+
callback?.close();
|
|
1964
1712
|
}
|
|
1965
1713
|
}
|
|
1966
1714
|
async function refreshOpenAICodexToken(refreshToken2, signal) {
|
|
1967
|
-
return credentialsFromToken(await
|
|
1715
|
+
return credentialsFromToken(await refreshAccessToken2(refreshToken2, signal));
|
|
1968
1716
|
}
|
|
1969
1717
|
var openaiCodexOAuth = {
|
|
1970
1718
|
name: "OpenAI (ChatGPT Plus/Pro)",
|
|
@@ -1993,20 +1741,13 @@ var openaiCodexOAuth = {
|
|
|
1993
1741
|
};
|
|
1994
1742
|
|
|
1995
1743
|
// node_modules/@earendil-works/pi-ai/dist/auth/oauth/openrouter.js
|
|
1996
|
-
|
|
1997
|
-
var
|
|
1998
|
-
var TOKEN_URL3 = "https://openrouter.ai/api/v1/auth/keys";
|
|
1744
|
+
var AUTHORIZE_URL4 = "https://openrouter.ai/auth";
|
|
1745
|
+
var TOKEN_URL4 = "https://openrouter.ai/api/v1/auth/keys";
|
|
1999
1746
|
var LOGIN_TIMEOUT_MS = 5 * 60 * 1000;
|
|
2000
1747
|
var TOKEN_EXCHANGE_TIMEOUT_MS = 30000;
|
|
2001
1748
|
function getCallbackHost2() {
|
|
2002
1749
|
return getProviderEnvValue("PI_OAUTH_CALLBACK_HOST") || "127.0.0.1";
|
|
2003
1750
|
}
|
|
2004
|
-
function sendHtml(response, status, html) {
|
|
2005
|
-
response.statusCode = status;
|
|
2006
|
-
response.setHeader("content-type", "text/html; charset=utf-8");
|
|
2007
|
-
response.setHeader("cache-control", "no-store");
|
|
2008
|
-
response.end(html);
|
|
2009
|
-
}
|
|
2010
1751
|
function parseAuthorizationInput3(input) {
|
|
2011
1752
|
const value = input.trim();
|
|
2012
1753
|
if (!value)
|
|
@@ -2033,7 +1774,7 @@ function errorDetail2(body) {
|
|
|
2033
1774
|
}
|
|
2034
1775
|
return;
|
|
2035
1776
|
}
|
|
2036
|
-
async function
|
|
1777
|
+
async function exchangeAuthorizationCode4(code, verifier, signal) {
|
|
2037
1778
|
if (signal.aborted)
|
|
2038
1779
|
throw new Error("Login cancelled");
|
|
2039
1780
|
const controller = new AbortController;
|
|
@@ -2043,7 +1784,7 @@ async function exchangeAuthorizationCode3(code, verifier, signal) {
|
|
|
2043
1784
|
let response;
|
|
2044
1785
|
let body = {};
|
|
2045
1786
|
try {
|
|
2046
|
-
response = await fetch(
|
|
1787
|
+
response = await fetch(TOKEN_URL4, {
|
|
2047
1788
|
method: "POST",
|
|
2048
1789
|
headers: { accept: "application/json", "content-type": "application/json" },
|
|
2049
1790
|
body: JSON.stringify({ code, code_verifier: verifier, code_challenge_method: "S256" }),
|
|
@@ -2081,153 +1822,45 @@ async function exchangeAuthorizationCode3(code, verifier, signal) {
|
|
|
2081
1822
|
expires: Number.MAX_SAFE_INTEGER
|
|
2082
1823
|
};
|
|
2083
1824
|
}
|
|
2084
|
-
async function startCallbackServer2(callbackPath, verifier, signal) {
|
|
2085
|
-
if (signal.aborted)
|
|
2086
|
-
throw new Error("Login cancelled");
|
|
2087
|
-
const callbackHost = getCallbackHost2();
|
|
2088
|
-
let resolveCredential = () => {};
|
|
2089
|
-
let rejectCredential = () => {};
|
|
2090
|
-
const credential = new Promise((resolve, reject) => {
|
|
2091
|
-
resolveCredential = resolve;
|
|
2092
|
-
rejectCredential = reject;
|
|
2093
|
-
});
|
|
2094
|
-
let server;
|
|
2095
|
-
let claimed = false;
|
|
2096
|
-
let settled = false;
|
|
2097
|
-
let timeout;
|
|
2098
|
-
let onAbort;
|
|
2099
|
-
const close = () => {
|
|
2100
|
-
if (timeout)
|
|
2101
|
-
clearTimeout(timeout);
|
|
2102
|
-
if (onAbort)
|
|
2103
|
-
signal.removeEventListener("abort", onAbort);
|
|
2104
|
-
server.close();
|
|
2105
|
-
};
|
|
2106
|
-
const finish = (result) => {
|
|
2107
|
-
if (settled)
|
|
2108
|
-
return;
|
|
2109
|
-
settled = true;
|
|
2110
|
-
close();
|
|
2111
|
-
if ("credential" in result)
|
|
2112
|
-
resolveCredential(result.credential);
|
|
2113
|
-
else
|
|
2114
|
-
rejectCredential(result.error);
|
|
2115
|
-
};
|
|
2116
|
-
server = createServer((request, response) => {
|
|
2117
|
-
(async () => {
|
|
2118
|
-
const requestUrl = new URL(request.url ?? "/", `http://${callbackHost}`);
|
|
2119
|
-
if (request.method !== "GET" || requestUrl.pathname !== callbackPath) {
|
|
2120
|
-
sendHtml(response, 404, oauthErrorHtml("OAuth callback route not found."));
|
|
2121
|
-
return;
|
|
2122
|
-
}
|
|
2123
|
-
if (claimed || settled) {
|
|
2124
|
-
sendHtml(response, 409, oauthErrorHtml("This OAuth callback has already been used."));
|
|
2125
|
-
return;
|
|
2126
|
-
}
|
|
2127
|
-
const oauthError = requestUrl.searchParams.get("error");
|
|
2128
|
-
if (oauthError) {
|
|
2129
|
-
const description = requestUrl.searchParams.get("error_description") ?? oauthError;
|
|
2130
|
-
sendHtml(response, 400, oauthErrorHtml("OpenRouter authorization was denied.", description));
|
|
2131
|
-
finish({ error: new Error(`OpenRouter authorization failed: ${description}`) });
|
|
2132
|
-
return;
|
|
2133
|
-
}
|
|
2134
|
-
const code = requestUrl.searchParams.get("code");
|
|
2135
|
-
if (!code) {
|
|
2136
|
-
sendHtml(response, 400, oauthErrorHtml("OpenRouter returned no authorization code."));
|
|
2137
|
-
return;
|
|
2138
|
-
}
|
|
2139
|
-
claimed = true;
|
|
2140
|
-
try {
|
|
2141
|
-
const result = await exchangeAuthorizationCode3(code, verifier, signal);
|
|
2142
|
-
sendHtml(response, 200, oauthSuccessHtml("Signed in to OpenRouter. You may now close this page."));
|
|
2143
|
-
finish({ credential: result });
|
|
2144
|
-
} catch (error) {
|
|
2145
|
-
const message = error instanceof Error ? error.message : "Unknown token exchange error";
|
|
2146
|
-
sendHtml(response, 502, oauthErrorHtml("OpenRouter key exchange failed.", message));
|
|
2147
|
-
finish({ error: error instanceof Error ? error : new Error(message) });
|
|
2148
|
-
}
|
|
2149
|
-
})();
|
|
2150
|
-
});
|
|
2151
|
-
await new Promise((resolve, reject) => {
|
|
2152
|
-
server.once("error", reject);
|
|
2153
|
-
server.listen(0, callbackHost, () => {
|
|
2154
|
-
server.removeListener("error", reject);
|
|
2155
|
-
resolve();
|
|
2156
|
-
});
|
|
2157
|
-
});
|
|
2158
|
-
server.on("error", (error) => finish({ error }));
|
|
2159
|
-
onAbort = () => finish({ error: new Error("Login cancelled") });
|
|
2160
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
2161
|
-
if (signal.aborted) {
|
|
2162
|
-
close();
|
|
2163
|
-
throw new Error("Login cancelled");
|
|
2164
|
-
}
|
|
2165
|
-
timeout = setTimeout(() => finish({ error: new Error("OpenRouter OAuth login timed out") }), LOGIN_TIMEOUT_MS);
|
|
2166
|
-
const address = server.address();
|
|
2167
|
-
if (!address || typeof address === "string") {
|
|
2168
|
-
close();
|
|
2169
|
-
throw new Error("Could not determine the OpenRouter OAuth callback port");
|
|
2170
|
-
}
|
|
2171
|
-
return {
|
|
2172
|
-
callbackUrl: `http://${callbackHost}:${address.port}${callbackPath}`,
|
|
2173
|
-
close,
|
|
2174
|
-
cancelWait: () => {
|
|
2175
|
-
if (!claimed)
|
|
2176
|
-
finish({ credential: null });
|
|
2177
|
-
},
|
|
2178
|
-
waitForCredential: () => credential
|
|
2179
|
-
};
|
|
2180
|
-
}
|
|
2181
1825
|
async function loginOpenRouter(interaction) {
|
|
2182
1826
|
const { verifier, challenge } = await generatePKCE();
|
|
2183
|
-
const
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
1827
|
+
const callback = await startOAuthCallbackServer({
|
|
1828
|
+
providerName: "OpenRouter",
|
|
1829
|
+
host: getCallbackHost2(),
|
|
1830
|
+
port: 0,
|
|
1831
|
+
path: `/oauth/callback/${crypto.randomUUID()}`,
|
|
1832
|
+
complete: (code) => exchangeAuthorizationCode4(code, verifier, interaction.signal),
|
|
1833
|
+
signal: interaction.signal,
|
|
1834
|
+
timeoutMs: LOGIN_TIMEOUT_MS
|
|
1835
|
+
});
|
|
2188
1836
|
try {
|
|
2189
|
-
const authorizeUrl = new URL(
|
|
1837
|
+
const authorizeUrl = new URL(AUTHORIZE_URL4);
|
|
2190
1838
|
authorizeUrl.search = new URLSearchParams({
|
|
2191
|
-
callback_url: callback.
|
|
1839
|
+
callback_url: callback.redirectUri,
|
|
2192
1840
|
code_challenge: challenge,
|
|
2193
1841
|
code_challenge_method: "S256"
|
|
2194
1842
|
}).toString();
|
|
2195
1843
|
interaction.notify({
|
|
2196
1844
|
type: "progress",
|
|
2197
|
-
message: `Listening for OpenRouter OAuth callback on ${callback.
|
|
1845
|
+
message: `Listening for OpenRouter OAuth callback on ${callback.redirectUri}`
|
|
2198
1846
|
});
|
|
2199
1847
|
interaction.notify({
|
|
2200
1848
|
type: "auth_url",
|
|
2201
1849
|
url: authorizeUrl.toString(),
|
|
2202
1850
|
instructions: "Complete sign-in in your browser. If the browser is on another machine, paste the final redirect URL here."
|
|
2203
1851
|
});
|
|
2204
|
-
const
|
|
2205
|
-
type: "manual_code",
|
|
1852
|
+
const result = await waitForCallbackOrManualInput(interaction, callback, {
|
|
2206
1853
|
message: "Complete sign-in in your browser, or paste the authorization code / redirect URL here:",
|
|
2207
|
-
placeholder: callback.
|
|
2208
|
-
signal: manualAbort.signal
|
|
2209
|
-
}).then((input) => {
|
|
2210
|
-
manualInput = input;
|
|
2211
|
-
callback.cancelWait();
|
|
2212
|
-
}).catch((error) => {
|
|
2213
|
-
manualError = error instanceof Error ? error : new Error(String(error));
|
|
2214
|
-
callback.cancelWait();
|
|
1854
|
+
placeholder: callback.redirectUri
|
|
2215
1855
|
});
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
if (credential)
|
|
2220
|
-
return credential;
|
|
2221
|
-
await manualPromise;
|
|
2222
|
-
if (manualError)
|
|
2223
|
-
throw manualError;
|
|
2224
|
-
const code = manualInput ? parseAuthorizationInput3(manualInput) : undefined;
|
|
1856
|
+
if (result.type === "callback")
|
|
1857
|
+
return result.value;
|
|
1858
|
+
const code = parseAuthorizationInput3(result.input);
|
|
2225
1859
|
if (!code)
|
|
2226
1860
|
throw new Error("Missing authorization code");
|
|
2227
1861
|
interaction.notify({ type: "progress", message: "Exchanging authorization code for an API key..." });
|
|
2228
|
-
return await
|
|
1862
|
+
return await exchangeAuthorizationCode4(code, verifier, interaction.signal);
|
|
2229
1863
|
} finally {
|
|
2230
|
-
manualAbort.abort();
|
|
2231
1864
|
callback.close();
|
|
2232
1865
|
}
|
|
2233
1866
|
}
|
|
@@ -2244,16 +1877,10 @@ var openRouterOAuth = {
|
|
|
2244
1877
|
};
|
|
2245
1878
|
|
|
2246
1879
|
// node_modules/@earendil-works/pi-ai/dist/auth/oauth/radius.js
|
|
2247
|
-
var
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
});
|
|
2252
|
-
}
|
|
2253
|
-
var CALLBACK_HOST2 = "127.0.0.1";
|
|
2254
|
-
var CALLBACK_PORT2 = 1456;
|
|
2255
|
-
var CALLBACK_PATH2 = "/oauth/callback";
|
|
2256
|
-
var REDIRECT_URI3 = `http://${CALLBACK_HOST2}:${CALLBACK_PORT2}${CALLBACK_PATH2}`;
|
|
1880
|
+
var CALLBACK_HOST3 = "127.0.0.1";
|
|
1881
|
+
var CALLBACK_PORT3 = 1456;
|
|
1882
|
+
var CALLBACK_PATH3 = "/oauth/callback";
|
|
1883
|
+
var REDIRECT_URI4 = `http://${CALLBACK_HOST3}:${CALLBACK_PORT3}${CALLBACK_PATH3}`;
|
|
2257
1884
|
var TOKEN_EXPIRY_SKEW_MS = 60000;
|
|
2258
1885
|
var LOGIN_METHOD_BROWSER = "browser";
|
|
2259
1886
|
var LOGIN_METHOD_DEVICE_CODE = "device-code";
|
|
@@ -2327,69 +1954,6 @@ async function requestOAuthToken(gateway, body, signal) {
|
|
|
2327
1954
|
scope: data.scope
|
|
2328
1955
|
};
|
|
2329
1956
|
}
|
|
2330
|
-
function startOAuthCallbackServer(expectedState, signal) {
|
|
2331
|
-
if (!_http2) {
|
|
2332
|
-
throw new Error("Radius OAuth is only available in Node.js environments");
|
|
2333
|
-
}
|
|
2334
|
-
let settle = () => {};
|
|
2335
|
-
let settled = false;
|
|
2336
|
-
const wait = new Promise((resolve) => {
|
|
2337
|
-
settle = resolve;
|
|
2338
|
-
});
|
|
2339
|
-
const finish = (code) => {
|
|
2340
|
-
if (settled) {
|
|
2341
|
-
return;
|
|
2342
|
-
}
|
|
2343
|
-
settled = true;
|
|
2344
|
-
signal.removeEventListener("abort", onAbort);
|
|
2345
|
-
settle(code);
|
|
2346
|
-
};
|
|
2347
|
-
const onAbort = () => finish(null);
|
|
2348
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
2349
|
-
const sendPage = (response, status, html) => {
|
|
2350
|
-
response.statusCode = status;
|
|
2351
|
-
response.setHeader("content-type", "text/html; charset=utf-8");
|
|
2352
|
-
response.end(html);
|
|
2353
|
-
};
|
|
2354
|
-
const server = _http2.createServer((request, response) => {
|
|
2355
|
-
const url = new URL(request.url ?? "/", REDIRECT_URI3);
|
|
2356
|
-
if (url.pathname !== CALLBACK_PATH2) {
|
|
2357
|
-
sendPage(response, 404, oauthErrorHtml("Callback route not found."));
|
|
2358
|
-
return;
|
|
2359
|
-
}
|
|
2360
|
-
if (url.searchParams.get("state") !== expectedState) {
|
|
2361
|
-
sendPage(response, 400, oauthErrorHtml("OAuth state mismatch."));
|
|
2362
|
-
return;
|
|
2363
|
-
}
|
|
2364
|
-
const error = url.searchParams.get("error");
|
|
2365
|
-
if (error) {
|
|
2366
|
-
sendPage(response, 400, oauthErrorHtml(url.searchParams.get("error_description") ?? error));
|
|
2367
|
-
finish(null);
|
|
2368
|
-
return;
|
|
2369
|
-
}
|
|
2370
|
-
const code = url.searchParams.get("code");
|
|
2371
|
-
if (!code) {
|
|
2372
|
-
sendPage(response, 400, oauthErrorHtml("Missing authorization code."));
|
|
2373
|
-
return;
|
|
2374
|
-
}
|
|
2375
|
-
sendPage(response, 200, oauthSuccessHtml("Signed in to Radius. You may now close this page."));
|
|
2376
|
-
finish(code);
|
|
2377
|
-
});
|
|
2378
|
-
return new Promise((resolve) => {
|
|
2379
|
-
server.listen(CALLBACK_PORT2, CALLBACK_HOST2, () => {
|
|
2380
|
-
resolve({
|
|
2381
|
-
waitForCode: () => wait,
|
|
2382
|
-
close: () => {
|
|
2383
|
-
finish(null);
|
|
2384
|
-
server.close();
|
|
2385
|
-
}
|
|
2386
|
-
});
|
|
2387
|
-
}).once("error", () => {
|
|
2388
|
-
finish(null);
|
|
2389
|
-
resolve({ waitForCode: async () => null, close: () => {} });
|
|
2390
|
-
});
|
|
2391
|
-
});
|
|
2392
|
-
}
|
|
2393
1957
|
async function loginWithBrowser(gateway, authorizationEndpoint, interaction) {
|
|
2394
1958
|
const { verifier, challenge } = await generatePKCE();
|
|
2395
1959
|
const state = crypto.randomUUID();
|
|
@@ -2397,37 +1961,41 @@ async function loginWithBrowser(gateway, authorizationEndpoint, interaction) {
|
|
|
2397
1961
|
authorizeUrl.search = new URLSearchParams({
|
|
2398
1962
|
response_type: "code",
|
|
2399
1963
|
client_id: OAUTH_CLIENT_ID,
|
|
2400
|
-
redirect_uri:
|
|
1964
|
+
redirect_uri: REDIRECT_URI4,
|
|
2401
1965
|
scope: OAUTH_SCOPE,
|
|
2402
1966
|
code_challenge: challenge,
|
|
2403
1967
|
code_challenge_method: "S256",
|
|
2404
1968
|
handoff: "url",
|
|
2405
1969
|
state
|
|
2406
1970
|
}).toString();
|
|
2407
|
-
const
|
|
2408
|
-
|
|
1971
|
+
const callback = await startOAuthCallbackServer({
|
|
1972
|
+
providerName: "Radius",
|
|
1973
|
+
host: CALLBACK_HOST3,
|
|
1974
|
+
port: CALLBACK_PORT3,
|
|
1975
|
+
path: CALLBACK_PATH3,
|
|
1976
|
+
state,
|
|
1977
|
+
complete: (code) => requestOAuthToken(gateway, new URLSearchParams({
|
|
1978
|
+
grant_type: "authorization_code",
|
|
1979
|
+
client_id: OAUTH_CLIENT_ID,
|
|
1980
|
+
redirect_uri: REDIRECT_URI4,
|
|
1981
|
+
code,
|
|
1982
|
+
code_verifier: verifier
|
|
1983
|
+
}), interaction.signal),
|
|
1984
|
+
signal: interaction.signal
|
|
1985
|
+
});
|
|
1986
|
+
interaction.notify({ type: "progress", message: `Listening for OAuth callback on ${REDIRECT_URI4}` });
|
|
2409
1987
|
interaction.notify({
|
|
2410
1988
|
type: "auth_url",
|
|
2411
1989
|
url: authorizeUrl.toString(),
|
|
2412
1990
|
instructions: "Continue in your browser."
|
|
2413
1991
|
});
|
|
2414
1992
|
try {
|
|
2415
|
-
const
|
|
2416
|
-
if (!
|
|
2417
|
-
if (interaction.signal.aborted) {
|
|
2418
|
-
throw new Error("Login cancelled");
|
|
2419
|
-
}
|
|
1993
|
+
const credential = await callback.wait();
|
|
1994
|
+
if (!credential)
|
|
2420
1995
|
throw new Error("OAuth callback did not complete.");
|
|
2421
|
-
|
|
2422
|
-
return await requestOAuthToken(gateway, new URLSearchParams({
|
|
2423
|
-
grant_type: "authorization_code",
|
|
2424
|
-
client_id: OAUTH_CLIENT_ID,
|
|
2425
|
-
redirect_uri: REDIRECT_URI3,
|
|
2426
|
-
code,
|
|
2427
|
-
code_verifier: verifier
|
|
2428
|
-
}), interaction.signal);
|
|
1996
|
+
return credential;
|
|
2429
1997
|
} finally {
|
|
2430
|
-
|
|
1998
|
+
callback.close();
|
|
2431
1999
|
}
|
|
2432
2000
|
}
|
|
2433
2001
|
async function requestDeviceAuthorization(gateway, signal) {
|
|
@@ -2719,6 +2287,7 @@ function registerBunOAuthFlows() {
|
|
|
2719
2287
|
registerBundledOAuthFlowLoaders({
|
|
2720
2288
|
anthropic: () => anthropicOAuth,
|
|
2721
2289
|
openaiCodex: () => openaiCodexOAuth,
|
|
2290
|
+
openaiChatGPT: () => openaiChatGPTOAuth,
|
|
2722
2291
|
githubCopilot: () => githubCopilotOAuth,
|
|
2723
2292
|
openrouter: () => openRouterOAuth,
|
|
2724
2293
|
kimiCoding: () => kimiCodingOAuth,
|
|
@@ -2825,4 +2394,4 @@ async function resolveCredential(opts = {}) {
|
|
|
2825
2394
|
return null;
|
|
2826
2395
|
}
|
|
2827
2396
|
|
|
2828
|
-
export { DEFAULT_MODEL, parseModelStr, resolveCredential
|
|
2397
|
+
export { DEFAULT_MODEL, parseModelStr, resolveCredential };
|