cartethyia 2.8.0 → 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 +3 -3
- package/dist/dashboard/assets/{BannedPage-Cc0vKpMG.js → BannedPage-Dq530awD.js} +1 -1
- package/dist/dashboard/assets/BannedPage-Dq530awD.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolDetailPage-Bqj2aa1T.js → CliToolDetailPage-DZzaS-7S.js} +1 -1
- package/dist/dashboard/assets/CliToolDetailPage-DZzaS-7S.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolsPage-CXsaOAO2.js → CliToolsPage-DaZZ3cqP.js} +1 -1
- package/dist/dashboard/assets/CliToolsPage-DaZZ3cqP.js.gz +0 -0
- package/dist/dashboard/assets/{CombosPage-BeLpJ4ma.js → CombosPage-BlC_xdkX.js} +1 -1
- package/dist/dashboard/assets/CombosPage-BlC_xdkX.js.gz +0 -0
- package/dist/dashboard/assets/{ConsoleLogPage-DnV0uZ3m.js → ConsoleLogPage-D-rqeVtG.js} +1 -1
- package/dist/dashboard/assets/ConsoleLogPage-D-rqeVtG.js.gz +0 -0
- package/dist/dashboard/assets/{CustomizationPage-CBxAjo63.js → CustomizationPage-7xT5yg2E.js} +1 -1
- package/dist/dashboard/assets/CustomizationPage-7xT5yg2E.js.gz +0 -0
- package/dist/dashboard/assets/{HealthEventsModal-B5yEE0k6.js → HealthEventsModal-Clq8E9cW.js} +1 -1
- package/dist/dashboard/assets/HealthEventsModal-Clq8E9cW.js.gz +0 -0
- package/dist/dashboard/assets/{InjectSystemPromptPanel-BWFLECmz.js → InjectSystemPromptPanel-6Teoq9Se.js} +1 -1
- package/dist/dashboard/assets/InjectSystemPromptPanel-6Teoq9Se.js.gz +0 -0
- package/dist/dashboard/assets/{LoginPage-CgoPc5B9.js → LoginPage-CZuI0MAR.js} +1 -1
- package/dist/dashboard/assets/LoginPage-CZuI0MAR.js.gz +0 -0
- package/dist/dashboard/assets/{ModelPicker-D9bFQern.js → ModelPicker-C1hNTlkr.js} +1 -1
- package/dist/dashboard/assets/ModelPicker-C1hNTlkr.js.gz +0 -0
- package/dist/dashboard/assets/{OverviewPage-B_p4tL8k.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-D_0PiZtg.js → ProviderIcon-Ddhm1InL.js} +1 -1
- package/dist/dashboard/assets/ProviderIcon-Ddhm1InL.js.gz +0 -0
- package/dist/dashboard/assets/{ProvidersPage-CLI2bJTK.js → ProvidersPage-C3fYuu6i.js} +1 -1
- 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-DA-a1iSN.js → QuotaPage-D1RV_2BX.js} +1 -1
- package/dist/dashboard/assets/QuotaPage-D1RV_2BX.js.gz +0 -0
- package/dist/dashboard/assets/{SettingsPage-CctTga2C.js → SettingsPage-BzZAvYSX.js} +1 -1
- package/dist/dashboard/assets/SettingsPage-BzZAvYSX.js.gz +0 -0
- package/dist/dashboard/assets/{SetupPage-febLU4r1.js → SetupPage--s-EfEIL.js} +1 -1
- package/dist/dashboard/assets/SetupPage--s-EfEIL.js.gz +0 -0
- package/dist/dashboard/assets/{StudioPage-M6fvR5Wz.js → StudioPage-BjXFGSK4.js} +1 -1
- package/dist/dashboard/assets/StudioPage-BjXFGSK4.js.gz +0 -0
- package/dist/dashboard/assets/{UsagePage-nyeuRqz9.js → UsagePage-CP8F8BN7.js} +1 -1
- package/dist/dashboard/assets/UsagePage-CP8F8BN7.js.gz +0 -0
- package/dist/dashboard/assets/{api-keys-BFOlvrJC.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-CqTLw5e7.js → assert-BMcj1xZE.js} +1 -1
- package/dist/dashboard/assets/assert-BMcj1xZE.js.gz +0 -0
- package/dist/dashboard/assets/{badge-C83EqLB0.js → badge-DkRUuVfz.js} +1 -1
- package/dist/dashboard/assets/badge-DkRUuVfz.js.gz +0 -0
- package/dist/dashboard/assets/{banner-D1xn7pIe.js → banner-CDjW841Q.js} +1 -1
- package/dist/dashboard/assets/banner-CDjW841Q.js.gz +0 -0
- package/dist/dashboard/assets/{card-DU3Lq5Lm.js → card-Bto5UlL9.js} +1 -1
- package/dist/dashboard/assets/card-Bto5UlL9.js.gz +0 -0
- package/dist/dashboard/assets/{cli-tools-Dw1U_drK.js → cli-tools-DaH6g9hL.js} +1 -1
- package/dist/dashboard/assets/cli-tools-DaH6g9hL.js.gz +0 -0
- package/dist/dashboard/assets/{clipboard-button-CEL5Sg_J.js → clipboard-button-BYKBCzjk.js} +1 -1
- package/dist/dashboard/assets/clipboard-button-BYKBCzjk.js.gz +0 -0
- package/dist/dashboard/assets/{dialog-BjFR5UHy.js → dialog-DL0Zftwv.js} +1 -1
- package/dist/dashboard/assets/dialog-DL0Zftwv.js.gz +0 -0
- package/dist/dashboard/assets/{drawer-HvBW0AjI.js → drawer-Dpx_UXaS.js} +1 -1
- package/dist/dashboard/assets/drawer-Dpx_UXaS.js.gz +0 -0
- package/dist/dashboard/assets/{entry-CECVELyy.js → entry-BV7-1NoM.js} +1 -1
- package/dist/dashboard/assets/entry-BV7-1NoM.js.gz +0 -0
- package/dist/dashboard/assets/{entry-DYYofQ7W.js → entry-CGvdNU6r.js} +1 -1
- package/dist/dashboard/assets/entry-CGvdNU6r.js.gz +0 -0
- package/dist/dashboard/assets/{entry-BSu3gFlt.js → entry-DScKYvZj.js} +3 -3
- package/dist/dashboard/assets/entry-DScKYvZj.js.gz +0 -0
- package/dist/dashboard/assets/{formatters-DLW4i8zK.js → formatters-BS3DZlZj.js} +1 -1
- package/dist/dashboard/assets/formatters-BS3DZlZj.js.gz +0 -0
- package/dist/dashboard/assets/{index-1-fCqe64.js → index-SQnvvTWX.js} +2 -2
- package/dist/dashboard/assets/index-SQnvvTWX.js.gz +0 -0
- package/dist/dashboard/assets/{inline-DGvU2oLK.js → inline-Dl-cuLK0.js} +1 -1
- package/dist/dashboard/assets/inline-Dl-cuLK0.js.gz +0 -0
- package/dist/dashboard/assets/{input-iNnO1X2K.js → input-Bfx0EzRc.js} +1 -1
- package/dist/dashboard/assets/input-Bfx0EzRc.js.gz +0 -0
- package/dist/dashboard/assets/{layout-0q8UGypb.js → layout-BxhbQ_JS.js} +1 -1
- package/dist/dashboard/assets/layout-BxhbQ_JS.js.gz +0 -0
- package/dist/dashboard/assets/{list-row-C0w2bQjJ.js → list-row-D49Y4ptn.js} +1 -1
- package/dist/dashboard/assets/list-row-D49Y4ptn.js.gz +0 -0
- package/dist/dashboard/assets/{live-M5aJ_xCa.js → live-CbVTdX9V.js} +1 -1
- package/dist/dashboard/assets/live-CbVTdX9V.js.gz +0 -0
- package/dist/dashboard/assets/{network-BKeQGT3K.js → network-JGvDveof.js} +1 -1
- package/dist/dashboard/assets/network-JGvDveof.js.gz +0 -0
- package/dist/dashboard/assets/{numbers-CivAk3da.js → numbers-Dw6kiew-.js} +1 -1
- package/dist/dashboard/assets/numbers-Dw6kiew-.js.gz +0 -0
- package/dist/dashboard/assets/{pagination-CpzvI5ep.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/{routing-BFQX2VBc.js → routing-8jZr-3WE.js} +1 -1
- package/dist/dashboard/assets/routing-8jZr-3WE.js.gz +0 -0
- package/dist/dashboard/assets/{select-CXbck0jG.js → select-oO1FxMVb.js} +1 -1
- package/dist/dashboard/assets/select-oO1FxMVb.js.gz +0 -0
- package/dist/dashboard/assets/{settings-C_XvMHh9.js → settings-CLr3kdIx.js} +1 -1
- package/dist/dashboard/assets/settings-CLr3kdIx.js.gz +0 -0
- package/dist/dashboard/assets/{stack-DggRiCxE.js → stack-Y3pDteZr.js} +1 -1
- package/dist/dashboard/assets/stack-Y3pDteZr.js.gz +0 -0
- package/dist/dashboard/assets/{state-ClFzfbYp.js → state-CArX_Iak.js} +1 -1
- package/dist/dashboard/assets/state-CArX_Iak.js.gz +0 -0
- package/dist/dashboard/assets/{switch-CTIFxKqS.js → switch-DwlwmDO-.js} +1 -1
- package/dist/dashboard/assets/switch-DwlwmDO-.js.gz +0 -0
- package/dist/dashboard/assets/{useMutation-BClG3yWj.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 +51 -51
- package/migrations/full-postgres/0047_add_provider_device_flow_proxy.sql +17 -0
- package/migrations/lite-sqlite3/0047_add_provider_device_flow_proxy.sql +19 -0
- package/package.json +1 -1
- package/src/boot/app.ts +1 -1
- package/src/boot/dependencies.ts +4 -6
- package/src/config/providers.ts +6 -5
- package/src/config/spec.ts +8 -8
- package/src/console/backup/nine-router.ts +71 -10
- package/src/console/backup/service.ts +8 -1
- package/src/console/console-router.ts +1 -1
- package/src/console/domain-registration.ts +7 -2
- package/src/console/inferhub/client.ts +1 -1
- package/src/console/observability/live.ts +2 -2
- 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 +2 -2
- package/src/console/providers/catalog/store.ts +1914 -1907
- 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-tenant.ts +5 -5
- package/src/console/quota/account-test-egress.ts +2 -2
- package/src/console/quota/daily-growth-job.ts +1 -1
- package/src/console/routing/pools/contracts.ts +1 -1
- package/src/console/routing/pools/operations.ts +1 -1
- 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/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/{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} +7 -7
- 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 +2 -2
- package/src/network/ssrf.ts +1 -1
- package/src/network/{retry.ts → util/retry.ts} +1 -1
- package/src/observability/telemetry-buffer.ts +1 -1
- package/src/persistence/schema.ts +9 -0
- package/src/persistence/ttl-cache.ts +1 -1
- package/src/protocol/codecs.ts +58 -1
- package/src/protocol/request/messages.ts +31 -18
- package/src/protocol/response/messages.ts +34 -7
- 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 +5 -0
- package/src/providers/authentication/oauth-client.ts +40 -6
- package/src/providers/authentication/oauth-device-flow.ts +7 -3
- package/src/providers/authentication/oauth-flow-store.ts +82 -1
- package/src/providers/authentication/oauth-refresh-service.ts +766 -739
- package/src/providers/default-registry.ts +76 -0
- package/src/providers/discovery/discovery-types.ts +7 -0
- package/src/providers/discovery/probe-phases.ts +6 -2
- package/src/providers/discovery/probing-service.ts +7 -0
- package/src/providers/integrations/antigravity/antigravity-protocol.ts +11 -0
- package/src/providers/integrations/buddy/account.ts +969 -0
- package/src/providers/integrations/buddy/capabilities.ts +10 -10
- package/src/providers/integrations/buddy/{buddy-catalog-shared.ts → catalog.ts} +198 -136
- package/src/providers/integrations/buddy/{buddy-chat-shared.ts → chat.ts} +5 -5
- package/src/providers/integrations/buddy/codebuddy/index.ts +429 -0
- package/src/providers/integrations/buddy/codebuddy/shared.ts +4 -4
- package/src/providers/integrations/buddy/{buddy-identity.ts → headers.ts} +138 -140
- 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/cline/cline-oauth.ts +10 -5
- package/src/providers/integrations/cline/cline.ts +3 -4
- 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/cursor/cursor-auth.ts +1 -1
- 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-shared.ts +1 -1
- package/src/providers/integrations/cursor/cursor.ts +485 -70
- 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/factory/factory-oauth.ts +16 -7
- package/src/providers/integrations/freebuff/freebuff.ts +2 -2
- 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 +4 -4
- package/src/providers/integrations/hermes/hermes-oauth.ts +3 -3
- package/src/providers/integrations/hermes/hermes.ts +34 -5
- 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-oauth.ts +2 -2
- package/src/providers/integrations/muse/muse-oauth.ts +5 -5
- package/src/providers/integrations/opencode/fingerprint.ts +1 -1
- package/src/providers/integrations/openrouter/provider.ts +1 -1
- package/src/providers/integrations/perch/perch-protocol.ts +0 -3
- package/src/providers/integrations/perch/perch.ts +3 -3
- package/src/providers/integrations/qoder/claim-qoder-credits.ts +1 -1
- package/src/providers/integrations/qoder/qoder-adapter.ts +19 -113
- package/src/providers/integrations/qoder/qoder-auth.ts +8 -1
- package/src/providers/integrations/qoder/qoder-catalog.ts +1 -1
- package/src/providers/integrations/qoder/qoder-chat.ts +25 -8
- package/src/providers/integrations/qoder/qoder-checkin.ts +1 -1
- 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 -25
- package/src/providers/integrations/sensenova/provider.ts +144 -0
- package/src/providers/integrations/trae/trae-quota.ts +15 -1
- 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/zro/zro.ts +2 -1
- package/src/providers/operations/account-refresh-status.ts +14 -0
- package/src/providers/operations/client-versions.ts +95 -30
- package/src/providers/operations/oauth-refresh-lead.ts +46 -22
- package/src/providers/operations/provider-caches.ts +1 -1
- package/src/providers/operations/provider-credential-service.ts +22 -25
- package/src/providers/operations/session-resolution.ts +17 -1
- package/src/providers/provider-contracts.ts +2 -2
- package/src/providers/provider-metadata.ts +30 -0
- package/src/providers/quota/quota-contracts.ts +2 -0
- package/src/providers/quota/refresh.ts +25 -3
- package/src/security/ip-boundary.ts +1 -1
- package/src/transport/dispatch/attempt-finalize.ts +1 -1
- package/src/transport/dispatch/attempt-loop.ts +3 -3
- package/src/transport/dispatch/handler-deps.ts +1 -1
- package/src/transport/dispatch/leases.ts +1 -1
- package/src/transport/dispatch/retry-policy.ts +1 -1
- package/src/transport/dispatch/streaming/finalize.ts +2 -2
- package/src/transport/dispatch/streaming/stream.ts +1 -1
- package/src/transport/dispatch/upstream.ts +1 -1
- package/src/transport/shutdown-notice.ts +1 -1
- 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-Cc0vKpMG.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-Bqj2aa1T.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-CXsaOAO2.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-BeLpJ4ma.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-DnV0uZ3m.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-CBxAjo63.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-B5yEE0k6.js.gz +0 -0
- package/dist/dashboard/assets/InjectSystemPromptPanel-BWFLECmz.js.gz +0 -0
- package/dist/dashboard/assets/LoginPage-CgoPc5B9.js.gz +0 -0
- package/dist/dashboard/assets/ModelPicker-D9bFQern.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-B_p4tL8k.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-rs5E2rxv.js +0 -8
- package/dist/dashboard/assets/ProviderDetailPage-rs5E2rxv.js.gz +0 -0
- package/dist/dashboard/assets/ProviderIcon-D_0PiZtg.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-CLI2bJTK.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-BwNC_-Cx.js +0 -9
- package/dist/dashboard/assets/ProxyPage-BwNC_-Cx.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-DA-a1iSN.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-CctTga2C.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-febLU4r1.js.gz +0 -0
- package/dist/dashboard/assets/StudioPage-M6fvR5Wz.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-nyeuRqz9.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-BFOlvrJC.js.gz +0 -0
- package/dist/dashboard/assets/app-Dx2QgsNj.css +0 -2
- package/dist/dashboard/assets/app-Dx2QgsNj.css.gz +0 -0
- package/dist/dashboard/assets/assert-CqTLw5e7.js.gz +0 -0
- package/dist/dashboard/assets/badge-C83EqLB0.js.gz +0 -0
- package/dist/dashboard/assets/banner-D1xn7pIe.js.gz +0 -0
- package/dist/dashboard/assets/card-DU3Lq5Lm.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-Dw1U_drK.js.gz +0 -0
- package/dist/dashboard/assets/clipboard-button-CEL5Sg_J.js.gz +0 -0
- package/dist/dashboard/assets/dialog-BjFR5UHy.js.gz +0 -0
- package/dist/dashboard/assets/drawer-HvBW0AjI.js.gz +0 -0
- package/dist/dashboard/assets/entry-BSu3gFlt.js.gz +0 -0
- package/dist/dashboard/assets/entry-CECVELyy.js.gz +0 -0
- package/dist/dashboard/assets/entry-DYYofQ7W.js.gz +0 -0
- package/dist/dashboard/assets/formatters-DLW4i8zK.js.gz +0 -0
- package/dist/dashboard/assets/index-1-fCqe64.js.gz +0 -0
- package/dist/dashboard/assets/inline-DGvU2oLK.js.gz +0 -0
- package/dist/dashboard/assets/input-iNnO1X2K.js.gz +0 -0
- package/dist/dashboard/assets/layout-0q8UGypb.js.gz +0 -0
- package/dist/dashboard/assets/list-row-C0w2bQjJ.js.gz +0 -0
- package/dist/dashboard/assets/live-M5aJ_xCa.js.gz +0 -0
- package/dist/dashboard/assets/network-BKeQGT3K.js.gz +0 -0
- package/dist/dashboard/assets/numbers-CivAk3da.js.gz +0 -0
- package/dist/dashboard/assets/pagination-CpzvI5ep.js.gz +0 -0
- package/dist/dashboard/assets/routing-BFQX2VBc.js.gz +0 -0
- package/dist/dashboard/assets/select-CXbck0jG.js.gz +0 -0
- package/dist/dashboard/assets/settings-C_XvMHh9.js.gz +0 -0
- package/dist/dashboard/assets/stack-DggRiCxE.js.gz +0 -0
- package/dist/dashboard/assets/state-ClFzfbYp.js.gz +0 -0
- package/dist/dashboard/assets/switch-CTIFxKqS.js.gz +0 -0
- package/dist/dashboard/assets/useMutation-BClG3yWj.js.gz +0 -0
- package/src/console/providers/catalog/discover-constants.ts +0 -6
- package/src/network/pool-health.ts +0 -198
- 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-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 -188
- package/src/providers/integrations/buddy/codebuddy/oauth.ts +0 -47
- package/src/providers/integrations/buddy/codebuddy/provider.ts +0 -179
- 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 -870
- package/src/providers/integrations/qoder/qoder-ide.ts +0 -481
- /package/dist/dashboard/assets/{app-DIXLjojg.js → app-C0gTXEoN.js} +0 -0
- /package/dist/dashboard/assets/{app-DIXLjojg.js.gz → app-C0gTXEoN.js.gz} +0 -0
- /package/src/network/{http2-bidi.ts → bidi.ts} +0 -0
- /package/src/network/pool/{byte-accounting.ts → accounting.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
- /package/src/network/{rate-limit-verdict.ts → verdict.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 {
|
|
@@ -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 }),
|
|
@@ -8,7 +8,7 @@ import { completeRequiredSchema, isRecord } from "../../../protocol/codecs";
|
|
|
8
8
|
import { providerBaseUrl } from "../../provider-metadata";
|
|
9
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" };
|
|
@@ -279,7 +279,7 @@ export class CursorOAuthClient extends OAuthDeviceFlow {
|
|
|
279
279
|
`${CURSOR_API_BASE_URL}/auth/poll?uuid=${encodeURIComponent(deviceAuthId)}` +
|
|
280
280
|
`&verifier=${encodeURIComponent(state.verifier)}`;
|
|
281
281
|
const outcome = await fetchJson(
|
|
282
|
-
asFetchFn(this.
|
|
282
|
+
asFetchFn(this.fetchFor(context)),
|
|
283
283
|
url,
|
|
284
284
|
{ method: "GET", headers: { accept: "application/json" } },
|
|
285
285
|
AUTH_REQUEST_TIMEOUT_MS,
|