cartethyia 2.7.9 → 2.8.1
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/.env.example +6 -5
- package/dist/dashboard/assets/{BannedPage-BxoG1MrL.js → BannedPage-Dq530awD.js} +1 -1
- package/dist/dashboard/assets/BannedPage-Dq530awD.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolDetailPage-ixwgKk53.js → CliToolDetailPage-DZzaS-7S.js} +1 -1
- package/dist/dashboard/assets/CliToolDetailPage-DZzaS-7S.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolsPage-BmttNV3U.js → CliToolsPage-DaZZ3cqP.js} +1 -1
- package/dist/dashboard/assets/CliToolsPage-DaZZ3cqP.js.gz +0 -0
- package/dist/dashboard/assets/{CombosPage-BE3qwwfC.js → CombosPage-BlC_xdkX.js} +1 -1
- package/dist/dashboard/assets/CombosPage-BlC_xdkX.js.gz +0 -0
- package/dist/dashboard/assets/{ConsoleLogPage-CRZdmMIX.js → ConsoleLogPage-D-rqeVtG.js} +1 -1
- package/dist/dashboard/assets/ConsoleLogPage-D-rqeVtG.js.gz +0 -0
- package/dist/dashboard/assets/{CustomizationPage-Dv_FJ6Er.js → CustomizationPage-7xT5yg2E.js} +1 -1
- package/dist/dashboard/assets/CustomizationPage-7xT5yg2E.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-Clq8E9cW.js +1 -0
- package/dist/dashboard/assets/HealthEventsModal-Clq8E9cW.js.gz +0 -0
- package/dist/dashboard/assets/{InjectSystemPromptPanel-BOoO8rpz.js → InjectSystemPromptPanel-6Teoq9Se.js} +2 -2
- package/dist/dashboard/assets/InjectSystemPromptPanel-6Teoq9Se.js.gz +0 -0
- package/dist/dashboard/assets/{LoginPage-ChJuNNVN.js → LoginPage-CZuI0MAR.js} +1 -1
- package/dist/dashboard/assets/LoginPage-CZuI0MAR.js.gz +0 -0
- package/dist/dashboard/assets/{ModelPicker-BZAJtPg1.js → ModelPicker-C1hNTlkr.js} +1 -1
- package/dist/dashboard/assets/ModelPicker-C1hNTlkr.js.gz +0 -0
- package/dist/dashboard/assets/{OverviewPage-BE40s3u5.js → OverviewPage-0yfhSI1C.js} +1 -1
- package/dist/dashboard/assets/OverviewPage-0yfhSI1C.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-xqTxdQ4c.js +8 -0
- package/dist/dashboard/assets/ProviderDetailPage-xqTxdQ4c.js.gz +0 -0
- package/dist/dashboard/assets/{ProviderIcon-CQ6bPUf_.js → ProviderIcon-Ddhm1InL.js} +1 -1
- package/dist/dashboard/assets/ProviderIcon-Ddhm1InL.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-C3fYuu6i.js +1 -0
- package/dist/dashboard/assets/ProvidersPage-C3fYuu6i.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-CHtJtZ3u.js +9 -0
- package/dist/dashboard/assets/ProxyPage-CHtJtZ3u.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-D1RV_2BX.js +1 -0
- package/dist/dashboard/assets/QuotaPage-D1RV_2BX.js.gz +0 -0
- package/dist/dashboard/assets/{SettingsPage-C5HPWqEv.js → SettingsPage-BzZAvYSX.js} +1 -1
- package/dist/dashboard/assets/SettingsPage-BzZAvYSX.js.gz +0 -0
- package/dist/dashboard/assets/{SetupPage-CFNcATJJ.js → SetupPage--s-EfEIL.js} +1 -1
- package/dist/dashboard/assets/SetupPage--s-EfEIL.js.gz +0 -0
- package/dist/dashboard/assets/{StudioPage-YoD4tY5l.js → StudioPage-BjXFGSK4.js} +1 -1
- package/dist/dashboard/assets/StudioPage-BjXFGSK4.js.gz +0 -0
- package/dist/dashboard/assets/{UsagePage-DxjaAhb_.js → UsagePage-CP8F8BN7.js} +1 -1
- package/dist/dashboard/assets/UsagePage-CP8F8BN7.js.gz +0 -0
- package/dist/dashboard/assets/{api-keys-BTlkq_Uk.js → api-keys-2hc12Uz2.js} +1 -1
- package/dist/dashboard/assets/api-keys-2hc12Uz2.js.gz +0 -0
- package/dist/dashboard/assets/app-DGXbNfAR.css +2 -0
- package/dist/dashboard/assets/app-DGXbNfAR.css.gz +0 -0
- package/dist/dashboard/assets/assert-BMcj1xZE.js +1 -0
- package/dist/dashboard/assets/assert-BMcj1xZE.js.gz +0 -0
- package/dist/dashboard/assets/{badge-DdbT_7Am.js → badge-DkRUuVfz.js} +1 -1
- package/dist/dashboard/assets/badge-DkRUuVfz.js.gz +0 -0
- package/dist/dashboard/assets/{banner-CsGN-nbm.js → banner-CDjW841Q.js} +1 -1
- package/dist/dashboard/assets/banner-CDjW841Q.js.gz +0 -0
- package/dist/dashboard/assets/{card-mgZ_TLLZ.js → card-Bto5UlL9.js} +1 -1
- package/dist/dashboard/assets/card-Bto5UlL9.js.gz +0 -0
- package/dist/dashboard/assets/{cli-tools-A1-v8-03.js → cli-tools-DaH6g9hL.js} +1 -1
- package/dist/dashboard/assets/cli-tools-DaH6g9hL.js.gz +0 -0
- package/dist/dashboard/assets/{clipboard-button-CJ4Zty89.js → clipboard-button-BYKBCzjk.js} +1 -1
- package/dist/dashboard/assets/clipboard-button-BYKBCzjk.js.gz +0 -0
- package/dist/dashboard/assets/{dialog-B5L2jPQ_.js → dialog-DL0Zftwv.js} +1 -1
- package/dist/dashboard/assets/dialog-DL0Zftwv.js.gz +0 -0
- package/dist/dashboard/assets/{drawer-DkjUouAj.js → drawer-Dpx_UXaS.js} +1 -1
- package/dist/dashboard/assets/drawer-Dpx_UXaS.js.gz +0 -0
- package/dist/dashboard/assets/{entry-B-LVLV6o.js → entry-BV7-1NoM.js} +1 -1
- package/dist/dashboard/assets/entry-BV7-1NoM.js.gz +0 -0
- package/dist/dashboard/assets/{entry-CAhdYl3B.js → entry-CGvdNU6r.js} +1 -1
- package/dist/dashboard/assets/entry-CGvdNU6r.js.gz +0 -0
- package/dist/dashboard/assets/entry-DScKYvZj.js +4 -0
- package/dist/dashboard/assets/entry-DScKYvZj.js.gz +0 -0
- package/dist/dashboard/assets/{formatters-CrsdLVsn.js → formatters-BS3DZlZj.js} +1 -1
- package/dist/dashboard/assets/formatters-BS3DZlZj.js.gz +0 -0
- package/dist/dashboard/assets/{index-BU64Lqvp.js → index-SQnvvTWX.js} +2 -2
- package/dist/dashboard/assets/index-SQnvvTWX.js.gz +0 -0
- package/dist/dashboard/assets/{inline-B2aDLyyg.js → inline-Dl-cuLK0.js} +1 -1
- package/dist/dashboard/assets/inline-Dl-cuLK0.js.gz +0 -0
- package/dist/dashboard/assets/{input-BCVkdR9d.js → input-Bfx0EzRc.js} +1 -1
- package/dist/dashboard/assets/input-Bfx0EzRc.js.gz +0 -0
- package/dist/dashboard/assets/{layout-DNcAdMK-.js → layout-BxhbQ_JS.js} +1 -1
- package/dist/dashboard/assets/layout-BxhbQ_JS.js.gz +0 -0
- package/dist/dashboard/assets/{list-row-DgrIH0hw.js → list-row-D49Y4ptn.js} +1 -1
- package/dist/dashboard/assets/list-row-D49Y4ptn.js.gz +0 -0
- package/dist/dashboard/assets/{live-Cae01iu8.js → live-CbVTdX9V.js} +1 -1
- package/dist/dashboard/assets/live-CbVTdX9V.js.gz +0 -0
- package/dist/dashboard/assets/{network-CRib7H_2.js → network-JGvDveof.js} +1 -1
- package/dist/dashboard/assets/network-JGvDveof.js.gz +0 -0
- package/dist/dashboard/assets/{numbers-BKQE8Xpz.js → numbers-Dw6kiew-.js} +1 -1
- package/dist/dashboard/assets/numbers-Dw6kiew-.js.gz +0 -0
- package/dist/dashboard/assets/{pagination-ecPvG_8g.js → pagination-iUoI8GeE.js} +1 -1
- package/dist/dashboard/assets/pagination-iUoI8GeE.js.gz +0 -0
- package/dist/dashboard/assets/providers/sensenova-intl.png +0 -0
- package/dist/dashboard/assets/providers/sensenova.png +0 -0
- package/dist/dashboard/assets/providers/zro.svg +3 -0
- package/dist/dashboard/assets/providers/zro.svg.gz +0 -0
- package/dist/dashboard/assets/quota-DiPD6UKH.js +1 -0
- package/dist/dashboard/assets/quota-DiPD6UKH.js.gz +0 -0
- package/dist/dashboard/assets/{routing-Ckm1UXuC.js → routing-8jZr-3WE.js} +1 -1
- package/dist/dashboard/assets/routing-8jZr-3WE.js.gz +0 -0
- package/dist/dashboard/assets/{select-ChoFWyKz.js → select-oO1FxMVb.js} +2 -2
- package/dist/dashboard/assets/select-oO1FxMVb.js.gz +0 -0
- package/dist/dashboard/assets/{settings-CKjFPlKW.js → settings-CLr3kdIx.js} +1 -1
- package/dist/dashboard/assets/settings-CLr3kdIx.js.gz +0 -0
- package/dist/dashboard/assets/{stack-DWCwU3fh.js → stack-Y3pDteZr.js} +1 -1
- package/dist/dashboard/assets/stack-Y3pDteZr.js.gz +0 -0
- package/dist/dashboard/assets/{state-Cg3VL5J_.js → state-CArX_Iak.js} +1 -1
- package/dist/dashboard/assets/state-CArX_Iak.js.gz +0 -0
- package/dist/dashboard/assets/{switch-Db70BMix.js → switch-DwlwmDO-.js} +1 -1
- package/dist/dashboard/assets/switch-DwlwmDO-.js.gz +0 -0
- package/dist/dashboard/assets/{useMutation-BqdE0LuM.js → useMutation-DJ9GYEgf.js} +1 -1
- package/dist/dashboard/assets/useMutation-DJ9GYEgf.js.gz +0 -0
- package/dist/dashboard/index.html +2 -2
- package/dist/dashboard/index.html.gz +0 -0
- package/dist/dashboard/precompressed-assets.json +54 -53
- package/migrations/full-postgres/0046_add_accounts_quota_plan_fetched_at.sql +7 -0
- package/migrations/full-postgres/0047_add_provider_device_flow_proxy.sql +17 -0
- package/migrations/lite-sqlite3/0046_add_accounts_quota_plan_fetched_at.sql +4 -0
- package/migrations/lite-sqlite3/0047_add_provider_device_flow_proxy.sql +19 -0
- package/package.json +1 -1
- package/src/boot/app.ts +11 -14
- package/src/boot/dependencies.ts +5 -7
- package/src/boot/flush.ts +20 -0
- package/src/boot/lifecycle.ts +7 -5
- package/src/config/providers.ts +6 -5
- package/src/config/routing.ts +26 -0
- package/src/config/spec-metadata.ts +72 -0
- package/src/config/spec.ts +28 -8
- package/src/console/api-keys/contracts.ts +12 -1
- package/src/console/api-keys/routes.ts +40 -28
- package/src/console/auth/account-reset.ts +7 -9
- package/src/console/backup/contracts.ts +4 -0
- package/src/console/backup/export-endpoint.ts +7 -5
- package/src/console/backup/nine-router.ts +71 -10
- package/src/console/backup/service.ts +8 -1
- package/src/console/cli-tools/service.ts +6 -12
- package/src/console/console-router-guards.ts +23 -16
- package/src/console/console-router.ts +1 -1
- package/src/console/domain-registration.ts +7 -4
- package/src/console/inferhub/client.ts +1 -1
- package/src/console/inferhub/normalize.ts +24 -28
- package/src/console/inferhub/types.ts +3 -0
- package/src/console/ip-bans/routes.ts +7 -13
- package/src/console/observability/live.ts +2 -2
- package/src/console/observability/store.ts +0 -53
- package/src/console/providers/catalog/contracts.ts +9 -3
- package/src/console/providers/catalog/model-operations.ts +2 -3
- package/src/console/providers/catalog/provider-operations.ts +1 -1
- package/src/console/providers/catalog/routes.ts +3 -2
- package/src/console/providers/catalog/store.ts +1914 -1902
- package/src/console/providers/detail/routes.ts +1 -0
- package/src/console/providers/detail/store.ts +4 -0
- package/src/console/providers/oauth/callback-listener.ts +30 -11
- package/src/console/providers/oauth/device-egress.ts +123 -0
- package/src/console/providers/oauth/routes.ts +123 -16
- package/src/console/quota/account-quota-global.ts +14 -24
- package/src/console/quota/account-quota-shared.ts +49 -0
- package/src/console/quota/account-quota-tenant.ts +11 -23
- package/src/console/quota/account-test-egress.ts +2 -2
- package/src/console/quota/daily-growth-job.ts +1 -1
- package/src/console/quota/quota-view.ts +19 -3
- package/src/console/routing/pools/contracts.ts +1 -1
- package/src/console/routing/pools/operations.ts +32 -47
- package/src/console/routing/pools/probe-verdict.ts +2 -2
- package/src/console/routing/pools/relay-deploy.ts +1 -1
- package/src/console/routing/pools/store.ts +4 -4
- package/src/console/shared/errors.ts +33 -6
- package/src/main.ts +2 -3
- package/src/network/client.ts +67 -0
- package/src/network/egress/bidi-session.ts +322 -0
- package/src/network/egress/dial.ts +201 -0
- package/src/network/egress/factory.ts +191 -0
- package/src/network/{outbound-fetch.ts → egress/fetch.ts} +195 -29
- package/src/network/egress/tls-profile.ts +123 -0
- package/src/network/egress/ws.ts +175 -0
- package/src/network/pool/{byte-accounting.ts → accounting.ts} +3 -2
- package/src/network/{types.ts → pool/agent-config.ts} +1 -1
- package/src/network/pool/agent.ts +2 -2
- package/src/network/{pool-cooldown-store.ts → pool/cooldown-store.ts} +95 -20
- package/src/network/{pool-health-machine.ts → pool/health.ts} +205 -6
- package/src/network/pool/resolver.ts +10 -849
- package/src/network/pool/selector.ts +184 -41
- package/src/network/ssrf.ts +7 -7
- package/src/network/{retry.ts → util/retry.ts} +1 -1
- package/src/network/{rate-limit-verdict.ts → verdict.ts} +1 -1
- package/src/observability/event-log.ts +7 -361
- package/src/observability/performance-metrics.ts +9 -0
- package/src/observability/runtime-metrics.ts +14 -9
- package/src/observability/telemetry-buffer.ts +16 -26
- package/src/observability/telemetry-reconciliation.ts +9 -37
- package/src/observability/telemetry-row.ts +125 -0
- package/src/persistence/db-mode.ts +4 -1
- package/src/persistence/dialect.ts +18 -0
- package/src/persistence/migrate.ts +6 -3
- package/src/persistence/schema.ts +17 -0
- package/src/persistence/ttl-cache.ts +21 -3
- package/src/protocol/codecs.ts +59 -2
- package/src/protocol/dsml.ts +34 -86
- package/src/protocol/markup-stream-parser.ts +195 -0
- package/src/protocol/reasoning-text.ts +19 -0
- package/src/protocol/request/chat.ts +10 -10
- package/src/protocol/request/gemini.ts +8 -2
- package/src/protocol/request/messages.ts +34 -22
- package/src/protocol/response/chat.ts +12 -20
- package/src/protocol/response/messages.ts +34 -7
- package/src/protocol/response/omp-tool-call-markup.ts +43 -86
- package/src/protocol/response/responses.ts +18 -2
- package/src/protocol/stop-reason.ts +23 -1
- package/src/protocol/think-split.ts +112 -0
- package/src/protocol/translation/dialect/qwen.ts +26 -58
- package/src/protocol/translation/quirks.ts +15 -0
- package/src/protocol/upstream/send-claude-messages.ts +2 -2
- package/src/providers/adapters/compatible-adapter.ts +76 -12
- package/src/providers/authentication/oauth-client.ts +40 -6
- package/src/providers/authentication/oauth-device-flow.ts +105 -11
- package/src/providers/authentication/oauth-flow-store.ts +82 -1
- package/src/providers/authentication/oauth-refresh-service.ts +766 -758
- package/src/providers/configured-provider.ts +148 -0
- package/src/providers/default-registry.ts +137 -36
- package/src/providers/discovery/discovery-types.ts +7 -0
- package/src/providers/discovery/probe-phases.ts +20 -6
- package/src/providers/discovery/probing-service.ts +22 -2
- package/src/providers/integrations/alibabacp/alibabacp-models.ts +1 -2
- package/src/providers/integrations/{dashscope-models.ts → alibabacp/dashscope-models.ts} +2 -2
- package/src/providers/integrations/antigravity/antigravity-protocol.ts +16 -1
- package/src/providers/integrations/buddy/account.ts +969 -0
- package/src/providers/integrations/buddy/capabilities.ts +12 -12
- package/src/providers/integrations/buddy/{buddy-catalog-shared.ts → catalog.ts} +198 -136
- package/src/providers/integrations/buddy/{buddy-chat-shared.ts → chat.ts} +176 -20
- package/src/providers/integrations/buddy/codebuddy/index.ts +429 -0
- package/src/providers/integrations/buddy/codebuddy/shared.ts +41 -26
- package/src/providers/integrations/buddy/headers.ts +311 -0
- package/src/providers/integrations/buddy/lifecycle.ts +1018 -0
- package/src/providers/integrations/buddy/{buddy-media.ts → media.ts} +1 -1
- package/src/providers/integrations/claude/claude-quota.ts +14 -17
- package/src/providers/integrations/cline/cline-oauth.ts +10 -5
- package/src/providers/integrations/cline/cline.ts +5 -6
- package/src/providers/integrations/clixad/clixad-oauth.ts +98 -0
- package/src/providers/integrations/clixad/clixad-quota.ts +132 -0
- package/src/providers/integrations/clixad/provider.ts +145 -0
- package/src/providers/integrations/codex/codex-oauth.ts +8 -5
- package/src/providers/integrations/commandcode/quota.ts +22 -28
- package/src/providers/integrations/cursor/cursor-auth.ts +1 -9
- package/src/providers/integrations/cursor/cursor-exec.ts +9 -2
- package/src/providers/integrations/cursor/cursor-hardening.ts +279 -0
- package/src/providers/integrations/cursor/cursor-http2.ts +605 -6
- package/src/providers/integrations/cursor/cursor-request.ts +26 -12
- package/src/providers/integrations/cursor/cursor-shared.ts +8 -5
- package/src/providers/integrations/cursor/cursor.ts +574 -110
- package/src/providers/integrations/cursor/protocol/messages.ts +22 -29
- package/src/providers/integrations/cursor/protocol/protobuf-schema.ts +37 -0
- package/src/providers/integrations/deepai/deepai-catalog.ts +149 -0
- package/src/providers/integrations/deepai/deepai-common.ts +145 -0
- package/src/providers/integrations/deepai/deepai-oauth.ts +129 -0
- package/src/providers/integrations/deepai/deepai-quota.ts +97 -0
- package/src/providers/integrations/deepai/provider.ts +42 -0
- package/src/providers/integrations/devin/devin-auth.ts +7 -0
- package/src/providers/integrations/devin/protocol/devin-proto.ts +1 -27
- package/src/providers/integrations/factory/factory-oauth.ts +33 -51
- package/src/providers/integrations/freebuff/assets/official-system-manager.txt +88 -0
- package/src/providers/integrations/freebuff/assets/official-system-worker.txt +57 -0
- package/src/providers/integrations/freebuff/assets/official-tools.json +1070 -0
- package/src/providers/integrations/freebuff/freebuff-catalog.ts +120 -0
- package/src/providers/integrations/freebuff/freebuff-constants.ts +1233 -0
- package/src/providers/integrations/freebuff/freebuff-discovery.ts +108 -0
- package/src/providers/integrations/freebuff/freebuff-oauth.ts +240 -0
- package/src/providers/integrations/freebuff/freebuff-quota.ts +260 -0
- package/src/providers/integrations/freebuff/freebuff-virtual.ts +89 -0
- package/src/providers/integrations/freebuff/freebuff.ts +682 -0
- package/src/providers/integrations/freepi/freepi-catalog.ts +5 -0
- package/src/providers/integrations/freepi/freepi-discovery.ts +2 -2
- package/src/providers/integrations/freepi/freepi-headers.ts +2 -2
- package/src/providers/integrations/freepi/freepi-protocol.ts +11 -2
- package/src/providers/integrations/freepi/freepi-realm.ts +0 -3
- package/src/providers/integrations/freepi/freepi-session.ts +158 -0
- package/src/providers/integrations/freepi/freepi.ts +80 -54
- package/src/providers/integrations/github/github-discovery.ts +30 -13
- package/src/providers/integrations/github/github-oauth.ts +217 -44
- package/src/providers/integrations/github/github-quota.ts +22 -5
- package/src/providers/integrations/github/github.ts +40 -32
- package/src/providers/integrations/grok/grok-oauth.ts +52 -49
- package/src/providers/integrations/grok/grok-ratelimit-store.ts +10 -17
- package/src/providers/integrations/grok/grok-turn-index.ts +11 -16
- package/src/providers/integrations/hermes/hermes-oauth.ts +3 -3
- package/src/providers/integrations/{hermes.ts → hermes/hermes.ts} +42 -13
- package/src/providers/integrations/hermes/index.ts +2 -0
- package/src/providers/integrations/kilo/kilo-oauth.ts +4 -4
- package/src/providers/integrations/kilo/kilo.ts +1 -1
- package/src/providers/integrations/kimi/kimi-oauth.ts +3 -3
- package/src/providers/integrations/kiro/kiro-catalog.ts +17 -1
- package/src/providers/integrations/kiro/kiro-discovery.ts +10 -12
- package/src/providers/integrations/kiro/kiro-oauth.ts +2 -2
- package/src/providers/integrations/kiro/kiro-quota.ts +8 -4
- package/src/providers/integrations/kiro/kiro.ts +15 -19
- package/src/providers/integrations/muse/muse-oauth.ts +5 -5
- package/src/providers/integrations/ollamacloud/index.ts +2 -0
- package/src/providers/integrations/{ollamacloud-models.ts → ollamacloud/models.ts} +2 -2
- package/src/providers/integrations/{ollamacloud-quota.ts → ollamacloud/quota.ts} +3 -3
- package/src/providers/integrations/opencode/fingerprint.ts +1 -1
- package/src/providers/integrations/opencode/opencode-go-quota.ts +2 -8
- package/src/providers/integrations/openrouter/provider.ts +1 -1
- package/src/providers/integrations/perch/perch-credential.ts +25 -0
- package/src/providers/integrations/perch/perch-protocol.ts +0 -6
- package/src/providers/integrations/perch/perch-quota.ts +2 -16
- package/src/providers/integrations/perch/perch.ts +6 -16
- package/src/providers/integrations/qoder/claim-qoder-credits.ts +19 -60
- package/src/providers/integrations/qoder/qoder-adapter.ts +20 -125
- package/src/providers/integrations/qoder/qoder-auth.ts +109 -30
- package/src/providers/integrations/qoder/qoder-catalog.ts +21 -6
- package/src/providers/integrations/qoder/qoder-chat.ts +32 -29
- package/src/providers/integrations/qoder/qoder-checkin.ts +5 -5
- package/src/providers/integrations/qoder/qoder-cosy.ts +37 -9
- package/src/providers/integrations/qoder/qoder-oauth.ts +9 -2
- package/src/providers/integrations/qoder/qoder-realm.ts +13 -36
- package/src/providers/integrations/qoder/qoder-sse.ts +447 -68
- package/src/providers/integrations/qoder/qoder-types.ts +9 -0
- package/src/providers/integrations/qoder/qoder.ts +3 -26
- package/src/providers/integrations/sensenova/provider.ts +144 -0
- package/src/providers/integrations/trae/trae-protocol.ts +9 -5
- package/src/providers/integrations/trae/trae-quota.ts +21 -29
- package/src/providers/integrations/trae/trae-realm.ts +38 -0
- package/src/providers/integrations/trae/trae.ts +7 -24
- package/src/providers/integrations/vercel/provider.ts +117 -0
- package/src/providers/integrations/vercel/vercel-quota.ts +96 -0
- package/src/providers/integrations/xai/xai-oauth.ts +5 -5
- package/src/providers/integrations/zcode-start-plan/gifts.ts +1 -1
- package/src/providers/integrations/zcode-start-plan/oauth.ts +3 -3
- package/src/providers/integrations/zcode-start-plan/provider.ts +226 -23
- package/src/providers/integrations/zcode-start-plan/quota.ts +19 -2
- package/src/providers/integrations/zro/zro.ts +205 -0
- package/src/providers/operations/account-error-classification.ts +199 -307
- package/src/providers/operations/account-health-service.ts +82 -1
- package/src/providers/operations/account-refresh-status.ts +36 -37
- package/src/providers/operations/account-tier.ts +15 -16
- package/src/providers/operations/client-version-resolver.ts +1 -1
- package/src/providers/operations/client-versions.ts +100 -81
- package/src/providers/operations/cooldown-rules.ts +11 -16
- package/src/providers/operations/oauth-refresh-lead.ts +46 -22
- package/src/providers/operations/{model-catalog-cache.ts → provider-caches.ts} +68 -16
- package/src/providers/operations/provider-catalog-service.ts +1 -1
- package/src/providers/operations/provider-credential-service.ts +118 -51
- package/src/providers/operations/provider-rules/github.ts +48 -0
- package/src/providers/operations/provider-rules/grok.ts +33 -0
- package/src/providers/operations/provider-rules/inception.ts +49 -0
- package/src/providers/operations/provider-rules/index.ts +32 -0
- package/src/providers/operations/provider-rules/perch.ts +37 -0
- package/src/providers/operations/provider-rules/qoder.ts +70 -0
- package/src/providers/operations/provider-rules/trae.ts +81 -0
- package/src/providers/operations/session-resolution.ts +17 -1
- package/src/providers/provider-contracts.ts +6 -4
- package/src/providers/{provider-credential-resolver.ts → provider-credentials.ts} +40 -3
- package/src/providers/provider-metadata.ts +70 -10
- package/src/providers/provider-probe.ts +15 -1
- package/src/providers/provider-registry.ts +42 -33
- package/src/providers/quota/quota-contracts.ts +2 -0
- package/src/providers/quota/quota-limit-windows.ts +16 -5
- package/src/providers/quota/quota-support.ts +1 -1
- package/src/providers/quota/quota-window-parser.ts +90 -18
- package/src/providers/quota/refresh.ts +100 -21
- package/src/security/api-key-auth-cache.ts +1 -1
- package/src/security/api-key-auth.ts +6 -2
- package/src/security/ip-boundary.ts +1 -1
- package/src/transport/dispatch/attempt-finalize.ts +15 -14
- package/src/transport/dispatch/attempt-loop.ts +73 -19
- package/src/transport/dispatch/generation.ts +2 -8
- package/src/transport/dispatch/handler-deps.ts +1 -1
- package/src/transport/dispatch/leases.ts +1 -1
- package/src/transport/dispatch/native-shared.ts +25 -0
- package/src/transport/dispatch/proxy-request.ts +8 -46
- package/src/transport/dispatch/responses-compact.ts +2 -8
- package/src/transport/dispatch/retry-policy.ts +1 -1
- package/src/transport/dispatch/streaming/finalize.ts +10 -7
- package/src/transport/dispatch/streaming/stream.ts +9 -37
- package/src/transport/dispatch/systemone.ts +2 -8
- package/src/transport/dispatch/token-count.ts +2 -6
- package/src/transport/dispatch/upstream.ts +63 -0
- package/src/transport/drain-endpoint.ts +31 -4
- package/src/transport/failure-policy.ts +16 -30
- package/src/transport/guards/body-policy.ts +7 -1
- package/src/transport/guards/error-lifecycle.ts +13 -1
- package/src/transport/guards/request-context.ts +22 -14
- package/src/transport/request/preparer.ts +81 -71
- package/src/transport/routing/bounded-lru.ts +14 -0
- package/src/transport/routing/drain-reserve.ts +129 -0
- package/src/transport/routing/plan-gate.ts +7 -1
- package/src/transport/routing/round-robin.ts +60 -0
- package/src/transport/routing/route-catalog.ts +123 -111
- package/src/transport/routing/route-model.ts +51 -9
- package/src/transport/routing/router.ts +393 -32
- package/src/transport/shutdown-notice.ts +1 -1
- package/src/transport/surface/adapters.ts +11 -2
- package/src/transport/surface/chat/adapter.ts +2 -2
- package/src/transport/surface/chat/encode.ts +47 -4
- package/src/transport/surface/chat/parse.ts +2 -12
- package/src/transport/surface/completion.ts +44 -33
- package/src/transport/surface/content-parts.ts +21 -0
- package/src/transport/surface/messages/adapter.ts +7 -1
- package/src/transport/surface/messages/encode.ts +11 -3
- package/src/transport/surface/messages/parse.ts +2 -1
- package/src/transport/surface/messages/stream.ts +33 -17
- package/src/transport/surface/responses/encode.ts +22 -5
- package/src/transport/surface/responses/parse.ts +3 -11
- package/src/workers/buddy-growth-tasks.ts +8 -8
- package/src/workers/daily-checkin.ts +4 -4
- package/src/workers/quota-refresh-sweep.ts +1 -1
- package/src/workers/zcode-gift-claim.ts +1 -1
- package/dist/dashboard/assets/BannedPage-BxoG1MrL.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-ixwgKk53.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-BmttNV3U.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-BE3qwwfC.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-CRZdmMIX.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-Dv_FJ6Er.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-CoVrw2sM.js +0 -1
- package/dist/dashboard/assets/HealthEventsModal-CoVrw2sM.js.gz +0 -0
- package/dist/dashboard/assets/InjectSystemPromptPanel-BOoO8rpz.js.gz +0 -0
- package/dist/dashboard/assets/LoginPage-ChJuNNVN.js.gz +0 -0
- package/dist/dashboard/assets/ModelPicker-BZAJtPg1.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-BE40s3u5.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-sfLoQtPV.js +0 -8
- package/dist/dashboard/assets/ProviderDetailPage-sfLoQtPV.js.gz +0 -0
- package/dist/dashboard/assets/ProviderIcon-CQ6bPUf_.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-DcepmPWo.js +0 -1
- package/dist/dashboard/assets/ProvidersPage-DcepmPWo.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-BJ87Pp0U.js +0 -9
- package/dist/dashboard/assets/ProxyPage-BJ87Pp0U.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-gkSyRAKa.js +0 -1
- package/dist/dashboard/assets/QuotaPage-gkSyRAKa.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-C5HPWqEv.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-CFNcATJJ.js.gz +0 -0
- package/dist/dashboard/assets/StudioPage-YoD4tY5l.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-DxjaAhb_.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-BTlkq_Uk.js.gz +0 -0
- package/dist/dashboard/assets/app-BX2nnKqs.css +0 -2
- package/dist/dashboard/assets/app-BX2nnKqs.css.gz +0 -0
- package/dist/dashboard/assets/assert-CndthXFQ.js +0 -1
- package/dist/dashboard/assets/assert-CndthXFQ.js.gz +0 -0
- package/dist/dashboard/assets/badge-DdbT_7Am.js.gz +0 -0
- package/dist/dashboard/assets/banner-CsGN-nbm.js.gz +0 -0
- package/dist/dashboard/assets/card-mgZ_TLLZ.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-A1-v8-03.js.gz +0 -0
- package/dist/dashboard/assets/clipboard-button-CJ4Zty89.js.gz +0 -0
- package/dist/dashboard/assets/dialog-B5L2jPQ_.js.gz +0 -0
- package/dist/dashboard/assets/drawer-DkjUouAj.js.gz +0 -0
- package/dist/dashboard/assets/entry-B-LVLV6o.js.gz +0 -0
- package/dist/dashboard/assets/entry-CAhdYl3B.js.gz +0 -0
- package/dist/dashboard/assets/entry-D2xD0Tmd.js +0 -4
- package/dist/dashboard/assets/entry-D2xD0Tmd.js.gz +0 -0
- package/dist/dashboard/assets/formatters-CrsdLVsn.js.gz +0 -0
- package/dist/dashboard/assets/index-BU64Lqvp.js.gz +0 -0
- package/dist/dashboard/assets/inline-B2aDLyyg.js.gz +0 -0
- package/dist/dashboard/assets/input-BCVkdR9d.js.gz +0 -0
- package/dist/dashboard/assets/layout-DNcAdMK-.js.gz +0 -0
- package/dist/dashboard/assets/list-row-DgrIH0hw.js.gz +0 -0
- package/dist/dashboard/assets/live-Cae01iu8.js.gz +0 -0
- package/dist/dashboard/assets/network-CRib7H_2.js.gz +0 -0
- package/dist/dashboard/assets/numbers-BKQE8Xpz.js.gz +0 -0
- package/dist/dashboard/assets/pagination-ecPvG_8g.js.gz +0 -0
- package/dist/dashboard/assets/quota-DJ1QlAOq.js +0 -1
- package/dist/dashboard/assets/quota-DJ1QlAOq.js.gz +0 -0
- package/dist/dashboard/assets/routing-Ckm1UXuC.js.gz +0 -0
- package/dist/dashboard/assets/select-ChoFWyKz.js.gz +0 -0
- package/dist/dashboard/assets/settings-CKjFPlKW.js.gz +0 -0
- package/dist/dashboard/assets/stack-DWCwU3fh.js.gz +0 -0
- package/dist/dashboard/assets/state-Cg3VL5J_.js.gz +0 -0
- package/dist/dashboard/assets/switch-Db70BMix.js.gz +0 -0
- package/dist/dashboard/assets/useMutation-BqdE0LuM.js.gz +0 -0
- package/src/network/pool-health.ts +0 -210
- package/src/providers/bundled-discovery-providers.ts +0 -98
- package/src/providers/configured-openai-providers.ts +0 -120
- package/src/providers/integrations/buddy/buddy-checkin.ts +0 -521
- package/src/providers/integrations/buddy/buddy-cli-headers.ts +0 -76
- package/src/providers/integrations/buddy/buddy-conversation-headers.ts +0 -130
- package/src/providers/integrations/buddy/buddy-discovery-shared.ts +0 -234
- package/src/providers/integrations/buddy/buddy-growth-shared.ts +0 -496
- package/src/providers/integrations/buddy/buddy-identity.ts +0 -300
- package/src/providers/integrations/buddy/buddy-oauth-shared.ts +0 -341
- package/src/providers/integrations/buddy/buddy-quota-shared.ts +0 -417
- package/src/providers/integrations/buddy/buddy-server-tools.ts +0 -240
- package/src/providers/integrations/buddy/buddy-usage-shared.ts +0 -221
- package/src/providers/integrations/buddy/buddy-usage-store.ts +0 -181
- package/src/providers/integrations/buddy/codebuddy/cn-catalog.ts +0 -37
- package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +0 -185
- package/src/providers/integrations/buddy/codebuddy/oauth.ts +0 -47
- package/src/providers/integrations/buddy/codebuddy/provider.ts +0 -175
- package/src/providers/integrations/buddy/codebuddy/quota.ts +0 -154
- package/src/providers/integrations/qoder/chat-proto.ts +0 -328
- package/src/providers/integrations/qoder/qoder-grpc.ts +0 -871
- package/src/providers/integrations/qoder/qoder-ide.ts +0 -588
- package/src/providers/operations/model-discovery-cache.ts +0 -34
- package/src/providers/operations/probe-fetch.ts +0 -15
- package/src/providers/operations/provider-version-cache.ts +0 -30
- package/src/providers/provider-capabilities.ts +0 -33
- package/src/providers/provider-credential-envelope.ts +0 -43
- /package/dist/dashboard/assets/{app-B7kIWFm5.js → app-C0gTXEoN.js} +0 -0
- /package/dist/dashboard/assets/{app-B7kIWFm5.js.gz → app-C0gTXEoN.js.gz} +0 -0
- /package/src/network/{http2-bidi.ts → bidi.ts} +0 -0
- /package/src/network/pool/{pool-scripts.ts → scripts.ts} +0 -0
- /package/src/network/pool/{pool-state.ts → state.ts} +0 -0
- /package/src/network/{backoff.ts → util/backoff.ts} +0 -0
- /package/src/network/{deduplication.ts → util/dedupe.ts} +0 -0
- /package/src/network/{ip-utils.ts → util/ip.ts} +0 -0
|
@@ -27,7 +27,7 @@ import { mapUpstreamHttpError } from "../../../transport/failure-policy";
|
|
|
27
27
|
import type { ImageGenerationOutcome, ProviderDispatchContext, ProviderDispatchTarget, ValidatedOutboundFetch } from "../../provider-contracts";
|
|
28
28
|
import type { CanonicalRequest } from "../../../protocol/canonical-model";
|
|
29
29
|
import { codebuddyHeaders, type CodeBuddyVariant } from "./codebuddy/shared";
|
|
30
|
-
import { applyBuddySystemPrompt, buddyPrePayloadCommon } from "./
|
|
30
|
+
import { applyBuddySystemPrompt, buddyPrePayloadCommon } from "./chat";
|
|
31
31
|
|
|
32
32
|
/** Media adapter identity: the variant's headers, its leading system turn, and base URL. */
|
|
33
33
|
export interface BuddyMediaConfig {
|
|
@@ -102,9 +102,13 @@ export async function fetchClaudeQuota(
|
|
|
102
102
|
credential: string,
|
|
103
103
|
fetcher: FetchLike,
|
|
104
104
|
): Promise<ProviderQuotaResult> {
|
|
105
|
+
// No module-local quota cache: the shared two-tier quota cache owns
|
|
106
|
+
// cross-call dedup, and a local tier keyed by credential only is never
|
|
107
|
+
// invalidated by `debitCachedQuota`, so a sweep within its TTL could
|
|
108
|
+
// resurrect a spent balance over the shared cache. Every call here is a
|
|
109
|
+
// fresh upstream read; the shared cache's in-flight dedup prevents
|
|
110
|
+
// duplicate traffic.
|
|
105
111
|
const key = sha256Hex(credential);
|
|
106
|
-
const cached = quotaCache.get(key);
|
|
107
|
-
if (cached !== undefined) return cached;
|
|
108
112
|
if (quotaCooldown.get(key) !== undefined) {
|
|
109
113
|
throw new Error("Quota endpoint rejected request: rate limited (cooled down)");
|
|
110
114
|
}
|
|
@@ -131,9 +135,7 @@ export async function fetchClaudeQuota(
|
|
|
131
135
|
},
|
|
132
136
|
observing,
|
|
133
137
|
);
|
|
134
|
-
|
|
135
|
-
quotaCache.set(key, result);
|
|
136
|
-
return result;
|
|
138
|
+
return parseClaudeQuota(body);
|
|
137
139
|
} catch (error: unknown) {
|
|
138
140
|
// Hammering the usage endpoint on every call is its own rate-limit
|
|
139
141
|
// risk: back off briefly after a 429 instead of retrying into it.
|
|
@@ -143,21 +145,16 @@ export async function fetchClaudeQuota(
|
|
|
143
145
|
}
|
|
144
146
|
|
|
145
147
|
/**
|
|
146
|
-
*
|
|
147
|
-
* (3 min). Keys are credential hashes, never raw secrets; both caches are
|
|
148
|
+
* Short 429 cooldown (3 min). Keys are credential hashes, never raw secrets;
|
|
148
149
|
* capped so credential fan-out cannot pin memory.
|
|
150
|
+
*
|
|
151
|
+
* The cooldown is an absolute window (`until = now + QUOTA_COOLDOWN_MS`), not a
|
|
152
|
+
* TTL from read time, so it is a sentinel whose own TTL *is* that window: the
|
|
153
|
+
* entry lives for exactly the cooldown and is gone the moment it closes.
|
|
149
154
|
*/
|
|
150
|
-
const QUOTA_CACHE_TTL_MS = 5 * 60_000;
|
|
151
155
|
const QUOTA_COOLDOWN_MS = 3 * 60_000;
|
|
152
|
-
const
|
|
153
|
-
const quotaCache = new TtlCache<ProviderQuotaResult>({
|
|
154
|
-
ttlMs: QUOTA_CACHE_TTL_MS,
|
|
155
|
-
maxEntries: QUOTA_CACHE_MAX_ENTRIES,
|
|
156
|
-
});
|
|
157
|
-
// The cooldown is an absolute window (`until = now + QUOTA_COOLDOWN_MS`), not a
|
|
158
|
-
// TTL from read time, so it is a sentinel whose own TTL *is* that window: the
|
|
159
|
-
// entry lives for exactly the cooldown and is gone the moment it closes.
|
|
156
|
+
const QUOTA_COOLDOWN_MAX_ENTRIES = 256;
|
|
160
157
|
const quotaCooldown = new TtlCache<true>({
|
|
161
158
|
ttlMs: QUOTA_COOLDOWN_MS,
|
|
162
|
-
maxEntries:
|
|
159
|
+
maxEntries: QUOTA_COOLDOWN_MAX_ENTRIES,
|
|
163
160
|
});
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
record,
|
|
9
9
|
} from "../../authentication/oauth-flow-store";
|
|
10
10
|
import type { OAuthDeviceFlowContext, OAuthDevicePollResult, OAuthDeviceStartResult, OAuthExchangeResult } from "../../authentication/oauth-flow-store";
|
|
11
|
+
import { oauthAccountIdentity } from "../../authentication/oauth-flow-store";
|
|
11
12
|
import type { OAuthTokenRefreshResult } from "../../authentication/oauth-refresh-service";
|
|
12
13
|
import { OAuthDeviceFlow } from "../../authentication/oauth-device-flow";
|
|
13
14
|
|
|
@@ -45,14 +46,18 @@ function tokenResult(value: unknown, fallbackRefresh?: string): OAuthExchangeRes
|
|
|
45
46
|
const refresh =
|
|
46
47
|
nonEmptyTrimmedString(payload.refresh_token) ?? nonEmptyTrimmedString(payload.refreshToken) ?? fallbackRefresh;
|
|
47
48
|
if (!access || !refresh) throw new Error("Cline OAuth response omitted access or refresh token");
|
|
49
|
+
const identity = oauthAccountIdentity(value);
|
|
48
50
|
const accountLabel =
|
|
49
51
|
nonEmptyTrimmedString(payload.email) ??
|
|
50
52
|
nonEmptyTrimmedString(record(payload.userInfo)?.email) ??
|
|
51
|
-
nonEmptyTrimmedString(record(payload.user)?.email)
|
|
53
|
+
nonEmptyTrimmedString(record(payload.user)?.email) ??
|
|
54
|
+
identity.accountEmail ??
|
|
55
|
+
identity.accountName;
|
|
52
56
|
return {
|
|
53
57
|
access,
|
|
54
58
|
refresh,
|
|
55
59
|
expiresAt: tokenExpiry(payload),
|
|
60
|
+
...identity,
|
|
56
61
|
...(accountLabel === undefined ? {} : { accountLabel }),
|
|
57
62
|
};
|
|
58
63
|
}
|
|
@@ -107,8 +112,8 @@ export class ClineOAuthClient extends OAuthDeviceFlow {
|
|
|
107
112
|
}
|
|
108
113
|
}
|
|
109
114
|
|
|
110
|
-
override async startDeviceAuth(
|
|
111
|
-
const response = await this.
|
|
115
|
+
override async startDeviceAuth(context?: OAuthDeviceFlowContext): Promise<OAuthDeviceStartResult> {
|
|
116
|
+
const response = await this.fetchFor(context)(WORKOS_DEVICE_AUTHORIZATION_URL, {
|
|
112
117
|
method: "POST",
|
|
113
118
|
headers: { "content-type": "application/x-www-form-urlencoded", accept: "application/json" },
|
|
114
119
|
body: new URLSearchParams({ client_id: CLINE_WORKOS_CLIENT_ID }),
|
|
@@ -145,7 +150,7 @@ export class ClineOAuthClient extends OAuthDeviceFlow {
|
|
|
145
150
|
this.#sessions.delete(deviceAuthId);
|
|
146
151
|
return { status: "failed", reason: "Cline device authorization expired" };
|
|
147
152
|
}
|
|
148
|
-
const response = await this.
|
|
153
|
+
const response = await this.fetchFor(context)(WORKOS_AUTHENTICATE_URL, {
|
|
149
154
|
method: "POST",
|
|
150
155
|
headers: { "content-type": "application/x-www-form-urlencoded", accept: "application/json" },
|
|
151
156
|
body: new URLSearchParams({
|
|
@@ -185,7 +190,7 @@ export class ClineOAuthClient extends OAuthDeviceFlow {
|
|
|
185
190
|
// exception that escapes the poll.
|
|
186
191
|
let registered: Record<string, unknown>;
|
|
187
192
|
try {
|
|
188
|
-
const registerResponse = await this.
|
|
193
|
+
const registerResponse = await this.fetchFor(context)(CLINE_REGISTER_URL, {
|
|
189
194
|
method: "POST",
|
|
190
195
|
headers: { "content-type": "application/json", accept: "application/json" },
|
|
191
196
|
body: JSON.stringify({ accessToken, refreshToken }),
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { createApiKeyAdapter } from "../../configured-provider";
|
|
2
2
|
import type { ProviderDispatchTarget, ProviderAdapter, ProviderDispatchContext } from "../../provider-contracts";
|
|
3
3
|
import type { ModelDefinition } from "../../provider-model-definition";
|
|
4
|
-
import { unwrapProviderToken } from "../../provider-
|
|
4
|
+
import { unwrapProviderToken } from "../../provider-credentials";
|
|
5
5
|
import { GatewayError } from "../../../protocol/gateway-error";
|
|
6
6
|
import type { CanonicalRequest } from "../../../protocol/canonical-model";
|
|
7
7
|
import { completeRequiredSchema, isRecord } from "../../../protocol/codecs";
|
|
8
8
|
import { providerBaseUrl } from "../../provider-metadata";
|
|
9
|
-
import { getCachedModelDiscovery } from "../../operations/
|
|
9
|
+
import { getCachedModelDiscovery } from "../../operations/provider-caches";
|
|
10
10
|
import { defineModel } from "../../provider-model-definition";
|
|
11
|
-
import { clineReasoningReplayPrepares } from "../buddy/
|
|
11
|
+
import { clineReasoningReplayPrepares } from "../buddy/chat";
|
|
12
12
|
import { clinePlatform, clinePlatformVersion } from "../../operations/cli-platform";
|
|
13
13
|
import {
|
|
14
14
|
getClineCliVersion,
|
|
@@ -105,7 +105,7 @@ function completeClineToolSchemas(payload: Record<string, unknown>): void {
|
|
|
105
105
|
});
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
function clinePrePayload(
|
|
108
|
+
export function clinePrePayload(
|
|
109
109
|
payload: Record<string, unknown>,
|
|
110
110
|
request: CanonicalRequest,
|
|
111
111
|
candidate: ProviderDispatchTarget,
|
|
@@ -576,11 +576,10 @@ function clineRow(
|
|
|
576
576
|
* not a tier marker — membership of the bucket is what makes a row free.
|
|
577
577
|
*/
|
|
578
578
|
const CLINE_FREE_ROWS: readonly ClineSeedRow[] = [
|
|
579
|
-
{ id: "reflection/beam-free", ctx: 128_000, out: 32_000 },
|
|
580
579
|
{ id: "cline-free/nemotron-3.5-super-vl", ctx: 1_000_000, out: 131_072, vision: true },
|
|
581
580
|
{ id: "nvidia/nemotron-3.5-lightning-free", ctx: 1_000_000, out: 65_536 },
|
|
582
|
-
{ id: "poolside/laguna-s-2.1-free", ctx: 262_144, out: 32_768 },
|
|
583
581
|
{ id: "cline-free/solar-mini4", ctx: 524_288, out: 131_072 },
|
|
582
|
+
{ id: "baidu/ernie-5.5-flash-preview:free", ctx: 1_000_000, out: 921_600 },
|
|
584
583
|
];
|
|
585
584
|
|
|
586
585
|
/**
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// Clixad credential login (GitHub device flow).
|
|
2
|
+
//
|
|
3
|
+
// Clixad's only production login is a GitHub device flow served by the
|
|
4
|
+
// gateway: `POST /v1/auth/device/start` returns a GitHub verification URL +
|
|
5
|
+
// user code; the gateway polls `POST /v1/auth/device/poll` with the session
|
|
6
|
+
// until the operator approves in the browser, then mints the CLI's bearer
|
|
7
|
+
// token (`adg_...`). There is no refresh token — the token is long-lived and
|
|
8
|
+
// the flow is re-run when needed.
|
|
9
|
+
|
|
10
|
+
import { OAuthClient } from "../../authentication/oauth-client";
|
|
11
|
+
import type {
|
|
12
|
+
OAuthDeviceStartResult,
|
|
13
|
+
OAuthDevicePollResult,
|
|
14
|
+
OAuthDeviceFlowContext,
|
|
15
|
+
} from "../../authentication/oauth-flow-store";
|
|
16
|
+
|
|
17
|
+
const CLIXAD_HANDOFF_PATH = "/v1/auth/device/start";
|
|
18
|
+
const CLIXAD_POLL_PATH = "/v1/auth/device/poll";
|
|
19
|
+
const CLIXAD_BASE_URL = "https://clixad.onrender.com";
|
|
20
|
+
|
|
21
|
+
export class ClixadOAuthClient extends OAuthClient {
|
|
22
|
+
readonly supportsDeviceCode = true;
|
|
23
|
+
readonly supportsBrowserCode = false;
|
|
24
|
+
protected readonly providerLabel = "clixad";
|
|
25
|
+
protected readonly clientId = "";
|
|
26
|
+
protected readonly tokenUrl = "";
|
|
27
|
+
protected readonly scopes = "";
|
|
28
|
+
|
|
29
|
+
async startDeviceAuth(): Promise<OAuthDeviceStartResult> {
|
|
30
|
+
const res = await this.fetchFn(new URL(CLIXAD_HANDOFF_PATH, CLIXAD_BASE_URL), {
|
|
31
|
+
method: "POST",
|
|
32
|
+
headers: { "content-type": "application/json", accept: "application/json" },
|
|
33
|
+
});
|
|
34
|
+
if (!res.ok) {
|
|
35
|
+
const text = await res.text().catch(() => "");
|
|
36
|
+
throw new Error(`clixad device flow start failed: HTTP ${res.status} ${text.slice(0, 300)}`);
|
|
37
|
+
}
|
|
38
|
+
const body = (await res.json()) as Record<string, unknown>;
|
|
39
|
+
return {
|
|
40
|
+
verificationUri: String(body["verification_uri"] ?? ""),
|
|
41
|
+
userCode: String(body["user_code"] ?? ""),
|
|
42
|
+
deviceAuthId: String(body["session"] ?? ""),
|
|
43
|
+
intervalSeconds: Number(body["interval"] ?? 5),
|
|
44
|
+
expiresInSeconds: Number(body["expires_in"] ?? 900),
|
|
45
|
+
providerState: JSON.stringify({ session: body["session"] }),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async pollDeviceAuth(deviceAuthId: string, context?: OAuthDeviceFlowContext): Promise<OAuthDevicePollResult> {
|
|
50
|
+
let providerState: Record<string, unknown> = {};
|
|
51
|
+
try {
|
|
52
|
+
providerState = JSON.parse(context?.providerState ?? "{}") as Record<string, unknown>;
|
|
53
|
+
} catch {
|
|
54
|
+
/* ignore */
|
|
55
|
+
}
|
|
56
|
+
const session = String(providerState["session"] ?? deviceAuthId);
|
|
57
|
+
const res = await this.fetchFn(new URL(CLIXAD_POLL_PATH, CLIXAD_BASE_URL), {
|
|
58
|
+
method: "POST",
|
|
59
|
+
headers: { "content-type": "application/json", accept: "application/json" },
|
|
60
|
+
body: JSON.stringify({ session }),
|
|
61
|
+
});
|
|
62
|
+
const body = (await res.json().catch(() => ({}))) as Record<string, unknown>;
|
|
63
|
+
const status = String(body["status"] ?? "");
|
|
64
|
+
if (status === "complete") {
|
|
65
|
+
const token = String(body["token"] ?? "");
|
|
66
|
+
return {
|
|
67
|
+
status: "complete",
|
|
68
|
+
result: {
|
|
69
|
+
access: token,
|
|
70
|
+
// Clixad issues no refresh token — the bearer is long-lived and the
|
|
71
|
+
// flow is re-run when needed. Mirror the access token so the console
|
|
72
|
+
// store always has a non-empty refresh field.
|
|
73
|
+
refresh: token,
|
|
74
|
+
expiresAt: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000),
|
|
75
|
+
accountLabel: String(body["email"] ?? body["login"] ?? ""),
|
|
76
|
+
auth_state: {
|
|
77
|
+
userId: body["userId"],
|
|
78
|
+
email: body["email"],
|
|
79
|
+
login: body["login"],
|
|
80
|
+
defaultModel: body["default_model"],
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
if (status === "closed") {
|
|
86
|
+
return {
|
|
87
|
+
status: "failed",
|
|
88
|
+
reason: `signup closed: ${String(body["message"] ?? "")} (${String(body["waitlist_url"] ?? "")})`,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
if (status === "pending") return { status: "pending" };
|
|
92
|
+
if (status === "unavailable") return { status: "failed", reason: `unavailable: ${String(body["error"] ?? "")}` };
|
|
93
|
+
return { status: "failed", reason: `device poll failed: ${String(body["error"] ?? body["status"] ?? res.status)}` };
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Shared Clixad device-login client instance (registry-facing). */
|
|
98
|
+
export const clixadOAuthClient = new ClixadOAuthClient();
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
// Clixad quota collector.
|
|
2
|
+
//
|
|
3
|
+
// Reads the account's credit surface from the gateway's wallet endpoint
|
|
4
|
+
// (`GET /v1/wallet` with the stored bearer token). The wallet reports the
|
|
5
|
+
// billed balance, the daily free-tier allowance (`free_tier.daily_credits` /
|
|
6
|
+
// `credits_left` — resets at midnight UTC), turns left per free model, and
|
|
7
|
+
// the ad-reward earnings cap (`max_reward_usd_per_day`). Reads are
|
|
8
|
+
// Bearer-authenticated; never throws — a failed read returns a null result so
|
|
9
|
+
// the router treats it as unknown rather than dead.
|
|
10
|
+
|
|
11
|
+
import type { FetchLike, ProviderQuotaResult, ProviderQuotaWindow } from "../../quota/quota-contracts";
|
|
12
|
+
import { cleanError, number, percentWindow, text } from "../../quota/quota-contracts";
|
|
13
|
+
import type { QuotaCollectionContext } from "../../quota/quota-support";
|
|
14
|
+
|
|
15
|
+
async function readWallet(
|
|
16
|
+
baseUrl: string,
|
|
17
|
+
token: string,
|
|
18
|
+
fetcher: FetchLike,
|
|
19
|
+
): Promise<Record<string, unknown> | null> {
|
|
20
|
+
if (!token) return null;
|
|
21
|
+
return fetcher(`${baseUrl}/v1/wallet`, {
|
|
22
|
+
method: "GET",
|
|
23
|
+
headers: {
|
|
24
|
+
accept: "application/json",
|
|
25
|
+
authorization: `Bearer ${token}`,
|
|
26
|
+
},
|
|
27
|
+
signal: AbortSignal.timeout(15_000),
|
|
28
|
+
})
|
|
29
|
+
.then(async (res) => {
|
|
30
|
+
if (!res.ok) return null;
|
|
31
|
+
try {
|
|
32
|
+
return (await res.json()) as Record<string, unknown>;
|
|
33
|
+
} catch {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
})
|
|
37
|
+
.catch(() => null);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Next midnight UTC, for the free-tier reset window. */
|
|
41
|
+
function nextMidnightUtc(): string {
|
|
42
|
+
const now = new Date();
|
|
43
|
+
const next = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate() + 1));
|
|
44
|
+
return next.toISOString();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Reads the account quota and returns a normalized result.
|
|
49
|
+
*
|
|
50
|
+
* Pooled windows: the billed balance (no ceiling — absolute remaining only)
|
|
51
|
+
* and the daily free-tier allowance (120k credits/day, resets at midnight
|
|
52
|
+
* UTC). Independent window: the ad-reward earnings cap ($5/day).
|
|
53
|
+
*/
|
|
54
|
+
export async function fetchClixadQuota(
|
|
55
|
+
credential: string,
|
|
56
|
+
fetcher: FetchLike,
|
|
57
|
+
_context?: QuotaCollectionContext,
|
|
58
|
+
): Promise<ProviderQuotaResult> {
|
|
59
|
+
try {
|
|
60
|
+
const token = text(credential) ?? "";
|
|
61
|
+
const wallet = await readWallet("https://clixad.onrender.com", token, fetcher);
|
|
62
|
+
if (!wallet) {
|
|
63
|
+
return { source: "clixad", plan: null, windows: [], error: "Clixad wallet endpoint unavailable" };
|
|
64
|
+
}
|
|
65
|
+
const windows: ProviderQuotaWindow[] = [];
|
|
66
|
+
|
|
67
|
+
const balance = number(wallet["balance"]);
|
|
68
|
+
if (balance !== null) {
|
|
69
|
+
// Billed balance: pooled, absolute remaining, no ceiling (a bonus pack
|
|
70
|
+
// has no declared limit — it simply is what it is).
|
|
71
|
+
windows.push({
|
|
72
|
+
kind: "credits",
|
|
73
|
+
label: "Account credits",
|
|
74
|
+
accounting: "pooled",
|
|
75
|
+
usedPercent: null,
|
|
76
|
+
remainingPercent: null,
|
|
77
|
+
resetsAt: null,
|
|
78
|
+
remaining: Math.max(0, balance),
|
|
79
|
+
recurring: false,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const freeTier = wallet["free_tier"] as Record<string, unknown> | undefined;
|
|
84
|
+
const dailyCredits = freeTier === undefined ? null : number(freeTier["daily_credits"]);
|
|
85
|
+
if (dailyCredits !== null && dailyCredits > 0) {
|
|
86
|
+
const creditsLeft = freeTier === undefined ? null : number(freeTier["credits_left"]);
|
|
87
|
+
const used = creditsLeft === null ? null : Math.max(0, dailyCredits - creditsLeft);
|
|
88
|
+
// Daily free tier: pooled (it is credit the account can spend), ceiling
|
|
89
|
+
// = the daily allowance, resets at midnight UTC.
|
|
90
|
+
windows.push(
|
|
91
|
+
percentWindow(
|
|
92
|
+
"free_daily",
|
|
93
|
+
"Daily free tier",
|
|
94
|
+
used === null ? null : (used / dailyCredits) * 100,
|
|
95
|
+
nextMidnightUtc(),
|
|
96
|
+
used,
|
|
97
|
+
dailyCredits,
|
|
98
|
+
"pooled",
|
|
99
|
+
),
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const maxRewardUsd = number(wallet["max_reward_usd_per_day"]);
|
|
104
|
+
if (maxRewardUsd !== null && maxRewardUsd > 0) {
|
|
105
|
+
const earnedUsd = number(wallet["earned_usd_today"]) ?? 0;
|
|
106
|
+
const usedUsd = Math.min(maxRewardUsd, Math.max(0, earnedUsd));
|
|
107
|
+
// Ad-reward earnings cap: independent (it does not fund model calls
|
|
108
|
+
// directly — it caps how much *earning* can happen per day).
|
|
109
|
+
windows.push(
|
|
110
|
+
percentWindow(
|
|
111
|
+
"earn_usd_daily",
|
|
112
|
+
"Daily reward cap",
|
|
113
|
+
(usedUsd / maxRewardUsd) * 100,
|
|
114
|
+
nextMidnightUtc(),
|
|
115
|
+
usedUsd,
|
|
116
|
+
maxRewardUsd,
|
|
117
|
+
"independent",
|
|
118
|
+
),
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const plan = number(wallet["balance"]) !== null ? "metered" : null;
|
|
123
|
+
return {
|
|
124
|
+
source: "clixad",
|
|
125
|
+
plan,
|
|
126
|
+
windows,
|
|
127
|
+
error: null,
|
|
128
|
+
};
|
|
129
|
+
} catch (error) {
|
|
130
|
+
return { source: "clixad", plan: null, windows: [], error: cleanError(error) };
|
|
131
|
+
}
|
|
132
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
// Clixad provider — TypeScript, Clixad gateway, Bun gateway.
|
|
2
|
+
//
|
|
3
|
+
// Clixad is an ad-funded terminal coding agent whose gateway
|
|
4
|
+
// (`https://clixad.onrender.com`) meters model calls and keeps the account
|
|
5
|
+
// balance, free-tier allowance, and ad-reward network server-side. The chat
|
|
6
|
+
// surface is OpenAI-compatible (`/v1/chat/completions`) with a bearer token
|
|
7
|
+
// (`adg_...`) minted by the GitHub device flow at login; model calls report
|
|
8
|
+
// credit accounting in an extra `clixad` envelope.
|
|
9
|
+
//
|
|
10
|
+
// Verified live 2026-11-11 (evidence ledger:
|
|
11
|
+
// `documentation/research/clixad/2026-11-11-clixad-wire.md`):
|
|
12
|
+
// - GET /v1/models → 200, 14 rows; the five `free: true` rows are
|
|
13
|
+
// served on the daily free tier (120k credits/day) and are the ones seeded
|
|
14
|
+
// below. The remaining rows are billed against the account balance.
|
|
15
|
+
// - POST /v1/chat/completions → 200 stream for all five free models, with
|
|
16
|
+
// `clixad.credits_waived` accounting the free-tier draw.
|
|
17
|
+
// - GET /v1/wallet → balance + free_tier (daily allowance, turns
|
|
18
|
+
// left per model), the quota source.
|
|
19
|
+
//
|
|
20
|
+
// The static roster carries the five live-verified free rows so the Free
|
|
21
|
+
// Limited section is populated before any fetch. Live discovery keeps the list
|
|
22
|
+
// current; the roster rows are preserved when the upstream listing reports the
|
|
23
|
+
// same id (the shared reader would otherwise overwrite freeTier/reasoning/tool
|
|
24
|
+
// flags with its conservative defaults).
|
|
25
|
+
|
|
26
|
+
import type { ApiKeyProviderSpec } from "../../configured-provider";
|
|
27
|
+
import { fetchOpenAICompatibleModels } from "../../discovery/openai-model-discovery";
|
|
28
|
+
import {
|
|
29
|
+
defineModel,
|
|
30
|
+
type ModelDefinition,
|
|
31
|
+
} from "../../provider-model-definition";
|
|
32
|
+
|
|
33
|
+
const CLIXAD_PROVIDER_ID = "clixad" as const;
|
|
34
|
+
|
|
35
|
+
/** Chat path below the `/v1` base root. */
|
|
36
|
+
const CLIXAD_CHAT_PATH = "/chat/completions";
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Clixad adapter spec: plain bearer, OpenAI-compatible chat.
|
|
40
|
+
*
|
|
41
|
+
* The model call endpoint accepts standard OpenAI fields and streams normally,
|
|
42
|
+
* so the generic API-key adapter serves it. No bespoke headers are required
|
|
43
|
+
* beyond the bearer. (The upstream's gzipped-body fallback is a *client-side*
|
|
44
|
+
* workaround for an edge WAF; the gateway itself answers plain JSON.)
|
|
45
|
+
*/
|
|
46
|
+
export const CLIXAD_SPEC: ApiKeyProviderSpec = {
|
|
47
|
+
provider_id: CLIXAD_PROVIDER_ID,
|
|
48
|
+
endpoint_paths_by_wire_family: { chat: CLIXAD_CHAT_PATH },
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Default rows for the Clixad provider (2026-11-11).
|
|
53
|
+
*
|
|
54
|
+
* Every row below was verified live on a fresh account: it streams a reply and
|
|
55
|
+
* draws from the daily free tier (`credits_waived` per call). Context windows
|
|
56
|
+
* and effort ladders come from the upstream's own `/v1/models` listing; token
|
|
57
|
+
* prices are the credits-per-1M figures the upstream publishes, kept here as
|
|
58
|
+
* `cost` for the operator (the tier itself bills zero — `FREE_TIER_COST`).
|
|
59
|
+
*/
|
|
60
|
+
export const CLIXAD_DEFAULT_MODELS: readonly ModelDefinition[] = [
|
|
61
|
+
defineModel({
|
|
62
|
+
id: "gpt-5-nano",
|
|
63
|
+
wireFamily: "chat",
|
|
64
|
+
endpoint: CLIXAD_CHAT_PATH,
|
|
65
|
+
ctx: 400_000,
|
|
66
|
+
out: 60_000,
|
|
67
|
+
reasoning: true,
|
|
68
|
+
toolCall: true,
|
|
69
|
+
free: true,
|
|
70
|
+
freeTier: true,
|
|
71
|
+
reasoningEfforts: ["minimal", "low", "medium", "high"]
|
|
72
|
+
}),
|
|
73
|
+
defineModel({
|
|
74
|
+
id: "gemini-2.5-flash-lite",
|
|
75
|
+
wireFamily: "chat",
|
|
76
|
+
endpoint: CLIXAD_CHAT_PATH,
|
|
77
|
+
ctx: 1_048_576,
|
|
78
|
+
out: 60_000,
|
|
79
|
+
reasoning: true,
|
|
80
|
+
toolCall: true,
|
|
81
|
+
free: true,
|
|
82
|
+
freeTier: true,
|
|
83
|
+
reasoningEfforts: ["off", "low", "medium", "high"]
|
|
84
|
+
}),
|
|
85
|
+
defineModel({
|
|
86
|
+
id: "claude-haiku-5.5",
|
|
87
|
+
wireFamily: "chat",
|
|
88
|
+
endpoint: CLIXAD_CHAT_PATH,
|
|
89
|
+
ctx: 24_000,
|
|
90
|
+
// The gateway publishes no output cap; clamp under the 24k context so a
|
|
91
|
+
// request can never exceed the endpoint (input + output budget).
|
|
92
|
+
out: 16_000,
|
|
93
|
+
reasoning: true,
|
|
94
|
+
toolCall: true,
|
|
95
|
+
free: true,
|
|
96
|
+
freeTier: true,
|
|
97
|
+
reasoningEfforts: ["off", "low", "medium", "high", "xhigh", "max"]
|
|
98
|
+
}),
|
|
99
|
+
defineModel({
|
|
100
|
+
id: "deepseek-v4-flash",
|
|
101
|
+
wireFamily: "chat",
|
|
102
|
+
endpoint: CLIXAD_CHAT_PATH,
|
|
103
|
+
ctx: 1_048_576,
|
|
104
|
+
out: 42_000,
|
|
105
|
+
reasoning: true,
|
|
106
|
+
toolCall: true,
|
|
107
|
+
free: true,
|
|
108
|
+
freeTier: true,
|
|
109
|
+
reasoningEfforts: ["off", "low", "medium", "high", "xhigh", "max"]
|
|
110
|
+
}),
|
|
111
|
+
defineModel({
|
|
112
|
+
id: "gemini-3.5-flash-lite",
|
|
113
|
+
wireFamily: "chat",
|
|
114
|
+
endpoint: CLIXAD_CHAT_PATH,
|
|
115
|
+
ctx: 1_048_576,
|
|
116
|
+
out: 375_000,
|
|
117
|
+
reasoning: true,
|
|
118
|
+
toolCall: true,
|
|
119
|
+
free: true,
|
|
120
|
+
freeTier: true,
|
|
121
|
+
reasoningEfforts: ["off", "low", "medium", "high", "xhigh", "max"]
|
|
122
|
+
}),
|
|
123
|
+
];
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Live `/v1/models` listing.
|
|
127
|
+
*
|
|
128
|
+
* The listing is unauthenticated (verified live). Every fetched row is kept
|
|
129
|
+
* as the shared reader resolved it, except ids the static roster already knows
|
|
130
|
+
* — those keep the roster row whole so the freeTier/reasoning/tool flags are
|
|
131
|
+
* not overwritten by the listing's conservative defaults.
|
|
132
|
+
*/
|
|
133
|
+
export async function discoverClixadModels(options: {
|
|
134
|
+
readonly baseUrl: string;
|
|
135
|
+
readonly fetcher?: typeof fetch;
|
|
136
|
+
}): Promise<readonly ModelDefinition[] | null> {
|
|
137
|
+
const listed = await fetchOpenAICompatibleModels({
|
|
138
|
+
baseUrl: options.baseUrl,
|
|
139
|
+
providerId: "clixad",
|
|
140
|
+
...(options.fetcher === undefined ? {} : { fetcher: options.fetcher }),
|
|
141
|
+
});
|
|
142
|
+
if (listed === null) return null;
|
|
143
|
+
const known = new Map(CLIXAD_DEFAULT_MODELS.map((model) => [model.modelId, model]));
|
|
144
|
+
return listed.map((model) => known.get(model.modelId) ?? model);
|
|
145
|
+
}
|
|
@@ -3,6 +3,8 @@ import {
|
|
|
3
3
|
postFormTokenRequest,
|
|
4
4
|
InMemoryOAuthFlowStore,
|
|
5
5
|
OAuthFlowStore,
|
|
6
|
+
type OAuthCodeExchangeContext,
|
|
7
|
+
type OAuthDeviceFlowContext,
|
|
6
8
|
type OAuthDevicePollResult,
|
|
7
9
|
type OAuthDeviceStartResult,
|
|
8
10
|
type OAuthExchangeResult,
|
|
@@ -200,12 +202,13 @@ export class CodexOAuthClient extends OAuthDeviceFlow {
|
|
|
200
202
|
codeVerifier: string,
|
|
201
203
|
redirectUri: string,
|
|
202
204
|
_state?: string,
|
|
205
|
+
_context?: OAuthCodeExchangeContext,
|
|
203
206
|
): Promise<OAuthExchangeResult> {
|
|
204
207
|
return exchangeCodeForToken(code, codeVerifier, redirectUri, this.fetchFn);
|
|
205
208
|
}
|
|
206
209
|
|
|
207
|
-
override async startDeviceAuth(): Promise<OAuthDeviceStartResult> {
|
|
208
|
-
const started = await startCodexDeviceAuth(CODEX_CLIENT_ID, this.
|
|
210
|
+
override async startDeviceAuth(context?: OAuthDeviceFlowContext): Promise<OAuthDeviceStartResult> {
|
|
211
|
+
const started = await startCodexDeviceAuth(CODEX_CLIENT_ID, this.fetchFor(context));
|
|
209
212
|
await this.#requireStore().saveDeviceState(started.deviceAuthId, { ...started });
|
|
210
213
|
return {
|
|
211
214
|
verificationUri: "https://auth.openai.com/codex/device",
|
|
@@ -216,7 +219,7 @@ export class CodexOAuthClient extends OAuthDeviceFlow {
|
|
|
216
219
|
};
|
|
217
220
|
}
|
|
218
221
|
|
|
219
|
-
override async pollDeviceAuth(deviceAuthId: string): Promise<OAuthDevicePollResult> {
|
|
222
|
+
override async pollDeviceAuth(deviceAuthId: string, context?: OAuthDeviceFlowContext): Promise<OAuthDevicePollResult> {
|
|
220
223
|
const store = this.#requireStore();
|
|
221
224
|
const stored = await store.getDeviceState(deviceAuthId);
|
|
222
225
|
const device = stored === undefined ? undefined : parseCodexDeviceStart(stored);
|
|
@@ -227,7 +230,7 @@ export class CodexOAuthClient extends OAuthDeviceFlow {
|
|
|
227
230
|
// never an exception that escapes the dashboard's poll request.
|
|
228
231
|
let authorization;
|
|
229
232
|
try {
|
|
230
|
-
authorization = await pollCodexDeviceAuth(device, this.
|
|
233
|
+
authorization = await pollCodexDeviceAuth(device, this.fetchFor(context));
|
|
231
234
|
} catch (error) {
|
|
232
235
|
return { status: "failed", reason: error instanceof Error ? error.message : "Codex device polling failed" };
|
|
233
236
|
}
|
|
@@ -238,7 +241,7 @@ export class CodexOAuthClient extends OAuthDeviceFlow {
|
|
|
238
241
|
authorization.authorizationCode,
|
|
239
242
|
authorization.codeVerifier,
|
|
240
243
|
CODEX_DEVICE_REDIRECT_URI,
|
|
241
|
-
this.
|
|
244
|
+
this.fetchFor(context),
|
|
242
245
|
);
|
|
243
246
|
} catch (error) {
|
|
244
247
|
return { status: "failed", reason: error instanceof Error ? error.message : "Codex token exchange failed" };
|