cartethyia 2.7.8 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +3 -3
- package/README.md +29 -59
- package/dist/dashboard/assets/BannedPage-Cc0vKpMG.js +1 -0
- package/dist/dashboard/assets/BannedPage-Cc0vKpMG.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolDetailPage-BRWKPQPf.js → CliToolDetailPage-Bqj2aa1T.js} +1 -1
- package/dist/dashboard/assets/CliToolDetailPage-Bqj2aa1T.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolsPage-BP-Y5iHN.js → CliToolsPage-CXsaOAO2.js} +1 -1
- package/dist/dashboard/assets/CliToolsPage-CXsaOAO2.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-BeLpJ4ma.js +1 -0
- package/dist/dashboard/assets/CombosPage-BeLpJ4ma.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-DnV0uZ3m.js +1 -0
- package/dist/dashboard/assets/ConsoleLogPage-DnV0uZ3m.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-CBxAjo63.js +1 -0
- package/dist/dashboard/assets/CustomizationPage-CBxAjo63.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-B5yEE0k6.js +1 -0
- package/dist/dashboard/assets/HealthEventsModal-B5yEE0k6.js.gz +0 -0
- package/dist/dashboard/assets/{InjectSystemPromptPanel-Cv-2Ol_K.js → InjectSystemPromptPanel-BWFLECmz.js} +2 -2
- package/dist/dashboard/assets/InjectSystemPromptPanel-BWFLECmz.js.gz +0 -0
- package/dist/dashboard/assets/{LoginPage-bKfz_b1K.js → LoginPage-CgoPc5B9.js} +1 -1
- package/dist/dashboard/assets/LoginPage-CgoPc5B9.js.gz +0 -0
- package/dist/dashboard/assets/{ModelPicker-B-WQxx_H.js → ModelPicker-D9bFQern.js} +1 -1
- package/dist/dashboard/assets/ModelPicker-D9bFQern.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-B_p4tL8k.js +1 -0
- package/dist/dashboard/assets/OverviewPage-B_p4tL8k.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-rs5E2rxv.js +8 -0
- package/dist/dashboard/assets/ProviderDetailPage-rs5E2rxv.js.gz +0 -0
- package/dist/dashboard/assets/ProviderIcon-D_0PiZtg.js +1 -0
- package/dist/dashboard/assets/ProviderIcon-D_0PiZtg.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-CLI2bJTK.js +1 -0
- package/dist/dashboard/assets/ProvidersPage-CLI2bJTK.js.gz +0 -0
- package/dist/dashboard/assets/{ProxyPage-emlTuxz6.js → ProxyPage-BwNC_-Cx.js} +1 -1
- package/dist/dashboard/assets/ProxyPage-BwNC_-Cx.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-DA-a1iSN.js +1 -0
- package/dist/dashboard/assets/QuotaPage-DA-a1iSN.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-CctTga2C.js +1 -0
- package/dist/dashboard/assets/SettingsPage-CctTga2C.js.gz +0 -0
- package/dist/dashboard/assets/{SetupPage-CUZrKs9r.js → SetupPage-febLU4r1.js} +1 -1
- package/dist/dashboard/assets/SetupPage-febLU4r1.js.gz +0 -0
- package/dist/dashboard/assets/{StudioPage-jWmUdDpy.js → StudioPage-M6fvR5Wz.js} +1 -1
- package/dist/dashboard/assets/StudioPage-M6fvR5Wz.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-nyeuRqz9.js +56 -0
- package/dist/dashboard/assets/UsagePage-nyeuRqz9.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-BFOlvrJC.js +1 -0
- package/dist/dashboard/assets/api-keys-BFOlvrJC.js.gz +0 -0
- package/dist/dashboard/assets/app-Dx2QgsNj.css +2 -0
- package/dist/dashboard/assets/app-Dx2QgsNj.css.gz +0 -0
- package/dist/dashboard/assets/{assert-CidQVoNo.js → assert-CqTLw5e7.js} +1 -1
- package/dist/dashboard/assets/assert-CqTLw5e7.js.gz +0 -0
- package/dist/dashboard/assets/{badge-DyI_mJfi.js → badge-C83EqLB0.js} +1 -1
- package/dist/dashboard/assets/badge-C83EqLB0.js.gz +0 -0
- package/dist/dashboard/assets/ban-durations-B58FyRxC.js +1 -0
- package/dist/dashboard/assets/ban-durations-B58FyRxC.js.gz +0 -0
- package/dist/dashboard/assets/{banner-B-yXtCqb.js → banner-D1xn7pIe.js} +1 -1
- package/dist/dashboard/assets/banner-D1xn7pIe.js.gz +0 -0
- package/dist/dashboard/assets/brand/bansos_page.webp +0 -0
- package/dist/dashboard/assets/brand/denia_bansos.webp +0 -0
- package/dist/dashboard/assets/brand/favicon.webp +0 -0
- package/dist/dashboard/assets/brand/login_register.webp +0 -0
- package/dist/dashboard/assets/brand/login_register_initial.webp +0 -0
- package/dist/dashboard/assets/brand/og_bansos.webp +0 -0
- package/dist/dashboard/assets/brand/og_image.webp +0 -0
- package/dist/dashboard/assets/brand/sidebar_ico.webp +0 -0
- package/dist/dashboard/assets/{card-_HwAEqFF.js → card-DU3Lq5Lm.js} +1 -1
- package/dist/dashboard/assets/card-DU3Lq5Lm.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-Dw1U_drK.js +1 -0
- package/dist/dashboard/assets/cli-tools-Dw1U_drK.js.gz +0 -0
- package/dist/dashboard/assets/{clipboard-button-ByjCk0o9.js → clipboard-button-CEL5Sg_J.js} +1 -1
- package/dist/dashboard/assets/clipboard-button-CEL5Sg_J.js.gz +0 -0
- package/dist/dashboard/assets/{dialog-BZhOlfz-.js → dialog-BjFR5UHy.js} +1 -1
- package/dist/dashboard/assets/dialog-BjFR5UHy.js.gz +0 -0
- package/dist/dashboard/assets/{drawer-BADqIRYP.js → drawer-HvBW0AjI.js} +1 -1
- package/dist/dashboard/assets/drawer-HvBW0AjI.js.gz +0 -0
- package/dist/dashboard/assets/entry-BSu3gFlt.js +4 -0
- package/dist/dashboard/assets/entry-BSu3gFlt.js.gz +0 -0
- package/dist/dashboard/assets/{entry-COaC-irN.js → entry-CECVELyy.js} +1 -1
- package/dist/dashboard/assets/entry-CECVELyy.js.gz +0 -0
- package/dist/dashboard/assets/entry-DYYofQ7W.js +1 -0
- package/dist/dashboard/assets/entry-DYYofQ7W.js.gz +0 -0
- package/dist/dashboard/assets/{formatters-DcHJyRiu.js → formatters-DLW4i8zK.js} +1 -1
- package/dist/dashboard/assets/formatters-DLW4i8zK.js.gz +0 -0
- package/dist/dashboard/assets/{index-CgKmFngv.js → index-1-fCqe64.js} +2 -2
- package/dist/dashboard/assets/index-1-fCqe64.js.gz +0 -0
- package/dist/dashboard/assets/{inline-B2BirKry.js → inline-DGvU2oLK.js} +1 -1
- package/dist/dashboard/assets/inline-DGvU2oLK.js.gz +0 -0
- package/dist/dashboard/assets/{input-D-qV9dKY.js → input-iNnO1X2K.js} +1 -1
- package/dist/dashboard/assets/input-iNnO1X2K.js.gz +0 -0
- package/dist/dashboard/assets/{layout-B7tVWhtV.js → layout-0q8UGypb.js} +1 -1
- package/dist/dashboard/assets/layout-0q8UGypb.js.gz +0 -0
- package/dist/dashboard/assets/{list-row-CtkGE3bF.js → list-row-C0w2bQjJ.js} +1 -1
- package/dist/dashboard/assets/list-row-C0w2bQjJ.js.gz +0 -0
- package/dist/dashboard/assets/{live-DGizF06-.js → live-M5aJ_xCa.js} +1 -1
- package/dist/dashboard/assets/live-M5aJ_xCa.js.gz +0 -0
- package/dist/dashboard/assets/{mutation-GU7XdEjz.js → mutation-BQ0ccH_A.js} +1 -1
- package/dist/dashboard/assets/mutation-BQ0ccH_A.js.gz +0 -0
- package/dist/dashboard/assets/{network-C9UE-bOr.js → network-BKeQGT3K.js} +1 -1
- package/dist/dashboard/assets/network-BKeQGT3K.js.gz +0 -0
- package/dist/dashboard/assets/{numbers-BnAd22a_.js → numbers-CivAk3da.js} +1 -1
- package/dist/dashboard/assets/numbers-CivAk3da.js.gz +0 -0
- package/dist/dashboard/assets/{pagination-BAywyMzS.js → pagination-CpzvI5ep.js} +1 -1
- package/dist/dashboard/assets/pagination-CpzvI5ep.js.gz +0 -0
- package/dist/dashboard/assets/providers/devin.svg +9 -0
- package/dist/dashboard/assets/providers/devin.svg.gz +0 -0
- package/dist/dashboard/assets/providers/windsurf.svg +10 -0
- package/dist/dashboard/assets/providers/windsurf.svg.gz +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/{query-keys-YSoQOUh6.js → query-keys-IKLh0YFd.js} +1 -1
- package/dist/dashboard/assets/query-keys-IKLh0YFd.js.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-BFQX2VBc.js +1 -0
- package/dist/dashboard/assets/routing-BFQX2VBc.js.gz +0 -0
- package/dist/dashboard/assets/{select-BCOcv8WK.js → select-CXbck0jG.js} +2 -2
- package/dist/dashboard/assets/select-CXbck0jG.js.gz +0 -0
- package/dist/dashboard/assets/settings-C_XvMHh9.js +1 -0
- package/dist/dashboard/assets/settings-C_XvMHh9.js.gz +0 -0
- package/dist/dashboard/assets/{stack-ByKt3Q1g.js → stack-DggRiCxE.js} +1 -1
- package/dist/dashboard/assets/stack-DggRiCxE.js.gz +0 -0
- package/dist/dashboard/assets/{state-DXbGTx7N.js → state-ClFzfbYp.js} +1 -1
- package/dist/dashboard/assets/state-ClFzfbYp.js.gz +0 -0
- package/dist/dashboard/assets/story/25817331.webp +0 -0
- package/dist/dashboard/assets/story/Shorekeeper.webp +0 -0
- package/dist/dashboard/assets/story/cartethyia-god.webp +0 -0
- package/dist/dashboard/assets/story/fleurdelys_plus.webp +0 -0
- package/dist/dashboard/assets/story/jinhsi-blossom.webp +0 -0
- package/dist/dashboard/assets/story/phrolova-a.webp +0 -0
- package/dist/dashboard/assets/story/requestdeniawokkjpg.webp +0 -0
- package/dist/dashboard/assets/story/wuthering-waves-hiyuki-aemeath-hiyuki-rover.webp +0 -0
- package/dist/dashboard/assets/{switch-ZeTsW623.js → switch-CTIFxKqS.js} +1 -1
- package/dist/dashboard/assets/switch-CTIFxKqS.js.gz +0 -0
- package/dist/dashboard/assets/{useMutation-CbCP4w1o.js → useMutation-BClG3yWj.js} +1 -1
- package/dist/dashboard/assets/useMutation-BClG3yWj.js.gz +0 -0
- package/dist/dashboard/console-backgrounds.webp +0 -0
- package/dist/dashboard/console-backgrounds_initial.webp +0 -0
- package/dist/dashboard/donation/qris-risun-marke.webp +0 -0
- package/dist/dashboard/index.html +3 -3
- package/dist/dashboard/index.html.gz +0 -0
- package/dist/dashboard/precompressed-assets.json +59 -56
- package/migrations/full-postgres/0044_add_models_warning_metadata.sql +10 -0
- package/migrations/full-postgres/0045_migrate_workbuddy_to_codebuddy.sql +156 -0
- package/migrations/full-postgres/0046_add_accounts_quota_plan_fetched_at.sql +7 -0
- package/migrations/lite-sqlite3/0044_add_models_warning_metadata.sql +11 -0
- package/migrations/lite-sqlite3/0045_migrate_workbuddy_to_codebuddy.sql +156 -0
- package/migrations/lite-sqlite3/0046_add_accounts_quota_plan_fetched_at.sql +4 -0
- package/package.json +1 -1
- package/src/boot/app.ts +10 -13
- package/src/boot/dependencies.ts +12 -4
- package/src/boot/flush.ts +20 -0
- package/src/boot/lifecycle.ts +7 -5
- package/src/config/cooldowns.ts +1 -1
- package/src/config/routing.ts +26 -0
- package/src/config/spec-metadata.ts +72 -0
- package/src/config/spec.ts +20 -6
- package/src/console/api-keys/contracts.ts +12 -1
- package/src/console/api-keys/routes.ts +50 -31
- 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/cli-tools/service.ts +6 -12
- package/src/console/console-router-guards.ts +23 -16
- package/src/console/console-router.ts +7 -0
- package/src/console/dashboard-assets.ts +5 -5
- package/src/console/domain-registration.ts +27 -2
- package/src/console/inferhub/normalize.ts +24 -28
- package/src/console/inferhub/types.ts +3 -0
- package/src/console/ip-bans/routes.ts +93 -0
- package/src/console/observability/store.ts +0 -53
- package/src/console/providers/catalog/catalog-projections.ts +5 -2
- package/src/console/providers/catalog/contracts.ts +123 -0
- package/src/console/providers/catalog/discover-constants.ts +6 -0
- package/src/console/providers/catalog/model-operations.ts +122 -10
- package/src/console/providers/catalog/provider-operations.ts +116 -8
- package/src/console/providers/catalog/public-model-store.ts +0 -0
- package/src/console/providers/catalog/routes.ts +65 -4
- package/src/console/providers/catalog/store-helpers.ts +30 -1
- package/src/console/providers/catalog/store.ts +249 -4
- package/src/console/quota/account-quota-global.ts +97 -19
- package/src/console/quota/account-quota-shared.ts +49 -0
- package/src/console/quota/account-quota-tenant.ts +6 -18
- package/src/console/quota/native-identity.ts +2 -0
- package/src/console/quota/quota-view.ts +19 -3
- package/src/console/routing/pools/operations.ts +31 -46
- package/src/console/settings/contracts.ts +18 -0
- package/src/console/settings/store.ts +32 -0
- package/src/console/shared/errors.ts +33 -6
- package/src/console/system-prompt/contracts.ts +0 -1
- package/src/main.ts +3 -3
- package/src/network/pool/byte-accounting.ts +3 -2
- package/src/network/pool/selector.ts +182 -39
- package/src/network/pool-cooldown-store.ts +89 -14
- package/src/network/pool-health.ts +49 -61
- package/src/network/rate-limit-verdict.ts +1 -1
- package/src/network/ssrf.ts +6 -6
- package/src/observability/event-log.ts +7 -361
- package/src/observability/event-query.ts +18 -4
- package/src/observability/performance-metrics.ts +9 -0
- package/src/observability/runtime-metrics.ts +14 -9
- package/src/observability/telemetry-buffer.ts +15 -25
- 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 +30 -0
- package/src/persistence/migrate.ts +6 -3
- package/src/persistence/schema.ts +28 -2
- package/src/persistence/ttl-cache.ts +20 -2
- package/src/protocol/codecs.ts +1 -1
- package/src/protocol/dsml.ts +35 -87
- package/src/protocol/gateway-error.ts +1 -0
- package/src/protocol/markup-stream-parser.ts +195 -0
- package/src/protocol/reasoning-text.ts +19 -0
- package/src/protocol/reasoning.ts +1 -1
- package/src/protocol/request/chat.ts +14 -14
- package/src/protocol/request/gemini.ts +8 -2
- package/src/protocol/request/messages.ts +4 -5
- package/src/protocol/response/chat.ts +12 -20
- package/src/protocol/response/gemini.ts +6 -1
- package/src/protocol/response/omp-tool-call-markup.ts +43 -86
- package/src/protocol/response/responses.ts +18 -2
- package/src/protocol/sse-decoder.ts +25 -8
- package/src/protocol/stop-reason.ts +23 -1
- package/src/protocol/stream-error-frames.ts +13 -3
- package/src/protocol/think-split.ts +112 -0
- package/src/protocol/translation/dialect/qwen.ts +26 -58
- package/src/protocol/translation/quirks.ts +1 -1
- package/src/protocol/translation/tool-repair.ts +2 -2
- package/src/protocol/upstream/send-claude-messages.ts +15 -4
- package/src/protocol/upstream-parsing.ts +1 -1
- package/src/providers/adapters/compatible-adapter.ts +78 -17
- package/src/providers/authentication/oauth-client.ts +1 -1
- package/src/providers/authentication/oauth-device-flow.ts +98 -8
- package/src/providers/authentication/oauth-refresh-service.ts +153 -59
- package/src/providers/configured-provider.ts +148 -0
- package/src/providers/default-registry.ts +117 -27
- package/src/providers/discovery/discovery-types.ts +12 -0
- package/src/providers/discovery/probe-phases.ts +74 -33
- package/src/providers/discovery/probing-service.ts +293 -165
- 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 +121 -2
- package/src/providers/integrations/antigravity/antigravity.ts +13 -2
- package/src/providers/integrations/buddy/buddy-catalog-shared.ts +72 -34
- package/src/providers/integrations/buddy/buddy-chat-shared.ts +191 -35
- package/src/providers/integrations/buddy/buddy-checkin.ts +17 -39
- package/src/providers/integrations/buddy/buddy-conversation-headers.ts +2 -2
- package/src/providers/integrations/buddy/buddy-discovery-shared.ts +5 -5
- package/src/providers/integrations/buddy/buddy-identity.ts +89 -6
- package/src/providers/integrations/buddy/buddy-media.ts +4 -5
- package/src/providers/integrations/buddy/buddy-oauth-shared.ts +2 -2
- package/src/providers/integrations/buddy/buddy-quota-shared.ts +1 -1
- package/src/providers/integrations/buddy/buddy-usage-shared.ts +1 -3
- package/src/providers/integrations/buddy/capabilities.ts +6 -43
- package/src/providers/integrations/buddy/codebuddy/cn-catalog.ts +2 -1
- package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +23 -1
- package/src/providers/integrations/buddy/codebuddy/provider.ts +6 -2
- package/src/providers/integrations/buddy/codebuddy/shared.ts +38 -27
- package/src/providers/integrations/claude/claude-quota.ts +14 -17
- package/src/providers/integrations/cline/cline.ts +2 -2
- package/src/providers/integrations/commandcode/quota.ts +22 -28
- package/src/providers/integrations/cursor/cursor-auth.ts +0 -8
- package/src/providers/integrations/cursor/cursor-catalog.ts +2 -0
- package/src/providers/integrations/cursor/cursor-exec.ts +745 -0
- package/src/providers/integrations/cursor/cursor-http2.ts +2 -0
- package/src/providers/integrations/cursor/cursor-request.ts +35 -20
- package/src/providers/integrations/cursor/cursor-shared.ts +26 -5
- package/src/providers/integrations/cursor/cursor.ts +139 -70
- 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/cursor/protocol/tool-canonical.ts +26 -100
- package/src/providers/integrations/devin/devin-auth.ts +353 -0
- package/src/providers/integrations/devin/devin-catalog.ts +207 -0
- package/src/providers/integrations/devin/devin-http.ts +91 -0
- package/src/providers/integrations/devin/devin-quota.ts +214 -0
- package/src/providers/integrations/devin/devin-shared.ts +111 -0
- package/src/providers/integrations/devin/devin.ts +539 -0
- package/src/providers/integrations/devin/protocol/devin-proto.ts +558 -0
- package/src/providers/integrations/devin/protocol/framing.ts +124 -0
- package/src/providers/integrations/factory/factory-oauth.ts +17 -44
- package/src/providers/integrations/factory/factory.ts +2 -2
- 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 +60 -0
- package/src/providers/integrations/freepi/freepi-discovery.ts +82 -0
- package/src/providers/integrations/freepi/freepi-headers.ts +21 -0
- package/src/providers/integrations/freepi/freepi-oauth.ts +142 -0
- package/src/providers/integrations/freepi/freepi-protocol.ts +242 -0
- package/src/providers/integrations/freepi/freepi-quota.ts +126 -0
- package/src/providers/integrations/freepi/freepi-realm.ts +35 -0
- package/src/providers/integrations/freepi/freepi.ts +292 -0
- package/src/providers/integrations/gemini.ts +2 -2
- package/src/providers/integrations/grok/grok-oauth.ts +48 -45
- 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 +94 -0
- package/src/providers/integrations/{hermes.ts → hermes/hermes.ts} +13 -21
- package/src/providers/integrations/hermes/index.ts +2 -0
- 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-quota.ts +8 -4
- package/src/providers/integrations/kiro/kiro.ts +15 -19
- 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/perch/perch-catalog.ts +105 -0
- package/src/providers/integrations/perch/perch-credential.ts +25 -0
- package/src/providers/integrations/perch/perch-oauth.ts +170 -0
- package/src/providers/integrations/perch/perch-protocol.ts +208 -0
- package/src/providers/integrations/perch/perch-quota.ts +123 -0
- package/src/providers/integrations/perch/perch-realm.ts +82 -0
- package/src/providers/integrations/perch/perch-system-prompt.ts +13 -0
- package/src/providers/integrations/perch/perch.ts +305 -0
- package/src/providers/integrations/perch/saffron-system-prompt.txt +8 -0
- package/src/providers/integrations/qoder/chat-proto.ts +328 -328
- package/src/providers/integrations/qoder/claim-qoder-credits.ts +19 -60
- package/src/providers/integrations/qoder/qoder-adapter.ts +90 -40
- package/src/providers/integrations/qoder/qoder-auth.ts +101 -29
- package/src/providers/integrations/qoder/qoder-cache.ts +32 -0
- package/src/providers/integrations/qoder/qoder-catalog.ts +26 -6
- package/src/providers/integrations/qoder/qoder-chat.ts +7 -21
- package/src/providers/integrations/qoder/qoder-checkin.ts +6 -6
- package/src/providers/integrations/qoder/qoder-grpc.ts +210 -7
- package/src/providers/integrations/qoder/qoder-ide.ts +5 -108
- package/src/providers/integrations/qoder/qoder-identity-cache.ts +184 -0
- package/src/providers/integrations/qoder/qoder-native-identity-store.ts +83 -18
- package/src/providers/integrations/qoder/qoder-realm.ts +9 -6
- package/src/providers/integrations/qoder/qoder-umid.ts +109 -342
- package/src/providers/integrations/qoder/qoder-virtual.ts +33 -1
- package/src/providers/integrations/qoder/qoder.ts +3 -7
- package/src/providers/integrations/trae/trae-catalog.ts +9 -14
- package/src/providers/integrations/trae/trae-headers.ts +36 -11
- package/src/providers/integrations/trae/trae-oauth.ts +14 -17
- package/src/providers/integrations/trae/trae-protocol.ts +12 -11
- package/src/providers/integrations/trae/trae-quota.ts +96 -36
- package/src/providers/integrations/trae/trae-realm.ts +74 -15
- package/src/providers/integrations/trae/trae.ts +99 -26
- 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 +204 -0
- package/src/providers/operations/account-error-classification.ts +235 -278
- package/src/providers/operations/account-health-service.ts +273 -26
- package/src/providers/operations/account-refresh-status.ts +269 -0
- package/src/providers/operations/account-tier.ts +66 -0
- package/src/providers/operations/client-version-resolver.ts +1 -1
- package/src/providers/operations/client-versions.ts +42 -150
- package/src/providers/operations/cooldown-rules.ts +56 -0
- package/src/providers/operations/{model-catalog-cache.ts → provider-caches.ts} +68 -16
- package/src/providers/operations/provider-catalog-seeder.ts +4 -0
- package/src/providers/operations/provider-catalog-service.ts +1 -1
- package/src/providers/operations/provider-credential-service.ts +102 -32
- 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/provider-contracts.ts +33 -2
- package/src/providers/{provider-credential-resolver.ts → provider-credentials.ts} +40 -3
- package/src/providers/provider-metadata.ts +99 -14
- package/src/providers/provider-model-definition.ts +36 -0
- package/src/providers/provider-probe.ts +15 -1
- package/src/providers/provider-registry.ts +42 -33
- 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 +96 -18
- package/src/security/abuse.ts +71 -0
- package/src/security/api-key-auth-cache.ts +1 -1
- package/src/security/api-key-auth.ts +6 -2
- package/src/transport/dispatch/attempt-finalize.ts +14 -13
- package/src/transport/dispatch/attempt-loop.ts +71 -17
- package/src/transport/dispatch/generation.ts +2 -8
- package/src/transport/dispatch/native-shared.ts +25 -0
- package/src/transport/dispatch/proxy-request.ts +9 -46
- package/src/transport/dispatch/responses-compact.ts +2 -8
- package/src/transport/dispatch/streaming/finalize.ts +9 -6
- package/src/transport/dispatch/streaming/stream.ts +9 -36
- package/src/transport/dispatch/systemone.ts +2 -8
- package/src/transport/dispatch/token-count.ts +2 -6
- package/src/transport/dispatch/upstream.ts +67 -1
- package/src/transport/drain-endpoint.ts +31 -4
- package/src/transport/failure-policy.ts +129 -37
- 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 +418 -33
- 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 +9 -2
- 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 +34 -6
- package/src/transport/surface/responses/parse.ts +3 -11
- package/src/workers/daily-checkin.ts +1 -1
- package/src/workers/quota-refresh-sweep.ts +1 -1
- package/src/workers/scheduler.ts +22 -4
- package/dist/dashboard/assets/BannedPage-DeIbIiBU.js +0 -1
- package/dist/dashboard/assets/BannedPage-DeIbIiBU.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-BRWKPQPf.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-BP-Y5iHN.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-B7JHozVa.js +0 -1
- package/dist/dashboard/assets/CombosPage-B7JHozVa.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-GX7iGGcu.js +0 -1
- package/dist/dashboard/assets/ConsoleLogPage-GX7iGGcu.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-HVonbGEa.js +0 -1
- package/dist/dashboard/assets/CustomizationPage-HVonbGEa.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-xaut4OJ9.js +0 -1
- package/dist/dashboard/assets/HealthEventsModal-xaut4OJ9.js.gz +0 -0
- package/dist/dashboard/assets/InjectSystemPromptPanel-Cv-2Ol_K.js.gz +0 -0
- package/dist/dashboard/assets/LoginPage-bKfz_b1K.js.gz +0 -0
- package/dist/dashboard/assets/ModelPicker-B-WQxx_H.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-Z9pJZFo8.js +0 -1
- package/dist/dashboard/assets/OverviewPage-Z9pJZFo8.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-CMeDBxR1.js +0 -7
- package/dist/dashboard/assets/ProviderDetailPage-CMeDBxR1.js.gz +0 -0
- package/dist/dashboard/assets/ProviderIcon-jjqXJDA3.js +0 -1
- package/dist/dashboard/assets/ProviderIcon-jjqXJDA3.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-BXPdOpG4.js +0 -1
- package/dist/dashboard/assets/ProvidersPage-BXPdOpG4.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-emlTuxz6.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-CMJKNYWb.js +0 -1
- package/dist/dashboard/assets/QuotaPage-CMJKNYWb.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-BSy7EwGo.js +0 -1
- package/dist/dashboard/assets/SettingsPage-BSy7EwGo.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-CUZrKs9r.js.gz +0 -0
- package/dist/dashboard/assets/StudioPage-jWmUdDpy.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-5F9tGVGG.js +0 -56
- package/dist/dashboard/assets/UsagePage-5F9tGVGG.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-KvX83mRe.js +0 -1
- package/dist/dashboard/assets/api-keys-KvX83mRe.js.gz +0 -0
- package/dist/dashboard/assets/app-BEsU8hKs.css +0 -2
- package/dist/dashboard/assets/app-BEsU8hKs.css.gz +0 -0
- package/dist/dashboard/assets/assert-CidQVoNo.js.gz +0 -0
- package/dist/dashboard/assets/badge-DyI_mJfi.js.gz +0 -0
- package/dist/dashboard/assets/banner-B-yXtCqb.js.gz +0 -0
- package/dist/dashboard/assets/brand/bansos_page.png +0 -0
- package/dist/dashboard/assets/brand/denia_bansos.jpg +0 -0
- package/dist/dashboard/assets/brand/favicon.jpg +0 -0
- package/dist/dashboard/assets/brand/login_register.jpg +0 -0
- package/dist/dashboard/assets/brand/login_register_initial.jpg +0 -0
- package/dist/dashboard/assets/brand/og_bansos.jpg +0 -0
- package/dist/dashboard/assets/brand/og_image.jpg +0 -0
- package/dist/dashboard/assets/brand/sidebar_ico.jpg +0 -0
- package/dist/dashboard/assets/card-_HwAEqFF.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-Bwv5-zGZ.js +0 -1
- package/dist/dashboard/assets/cli-tools-Bwv5-zGZ.js.gz +0 -0
- package/dist/dashboard/assets/clipboard-button-ByjCk0o9.js.gz +0 -0
- package/dist/dashboard/assets/dialog-BZhOlfz-.js.gz +0 -0
- package/dist/dashboard/assets/drawer-BADqIRYP.js.gz +0 -0
- package/dist/dashboard/assets/entry-COaC-irN.js.gz +0 -0
- package/dist/dashboard/assets/entry-Ca7LSCet.js +0 -4
- package/dist/dashboard/assets/entry-Ca7LSCet.js.gz +0 -0
- package/dist/dashboard/assets/entry-PDd27uCd.js +0 -1
- package/dist/dashboard/assets/entry-PDd27uCd.js.gz +0 -0
- package/dist/dashboard/assets/formatters-DcHJyRiu.js.gz +0 -0
- package/dist/dashboard/assets/index-CgKmFngv.js.gz +0 -0
- package/dist/dashboard/assets/inline-B2BirKry.js.gz +0 -0
- package/dist/dashboard/assets/input-D-qV9dKY.js.gz +0 -0
- package/dist/dashboard/assets/layout-B7tVWhtV.js.gz +0 -0
- package/dist/dashboard/assets/list-row-CtkGE3bF.js.gz +0 -0
- package/dist/dashboard/assets/live-DGizF06-.js.gz +0 -0
- package/dist/dashboard/assets/minimize-2-BTmMTK4o.js +0 -1
- package/dist/dashboard/assets/minimize-2-BTmMTK4o.js.gz +0 -0
- package/dist/dashboard/assets/mutation-GU7XdEjz.js.gz +0 -0
- package/dist/dashboard/assets/network-C9UE-bOr.js.gz +0 -0
- package/dist/dashboard/assets/numbers-BnAd22a_.js.gz +0 -0
- package/dist/dashboard/assets/pagination-BAywyMzS.js.gz +0 -0
- package/dist/dashboard/assets/query-keys-YSoQOUh6.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-fnCsxgNO.js +0 -1
- package/dist/dashboard/assets/routing-fnCsxgNO.js.gz +0 -0
- package/dist/dashboard/assets/select-BCOcv8WK.js.gz +0 -0
- package/dist/dashboard/assets/settings-BxslsErn.js +0 -1
- package/dist/dashboard/assets/settings-BxslsErn.js.gz +0 -0
- package/dist/dashboard/assets/stack-ByKt3Q1g.js.gz +0 -0
- package/dist/dashboard/assets/state-DXbGTx7N.js.gz +0 -0
- package/dist/dashboard/assets/switch-ZeTsW623.js.gz +0 -0
- package/dist/dashboard/assets/useMutation-CbCP4w1o.js.gz +0 -0
- package/dist/dashboard/console-backgrounds.jpg +0 -0
- package/dist/dashboard/console-backgrounds_initial.jpg +0 -0
- package/dist/dashboard/donation/qris-risun-marke.png +0 -0
- package/src/providers/bundled-discovery-providers.ts +0 -98
- package/src/providers/configured-openai-providers.ts +0 -120
- package/src/providers/integrations/buddy/turing-device-token.ts +0 -262
- package/src/providers/integrations/buddy/workbuddy/cn-oauth.ts +0 -30
- package/src/providers/integrations/buddy/workbuddy/cn-provider.ts +0 -58
- package/src/providers/integrations/buddy/workbuddy/oauth.ts +0 -31
- package/src/providers/integrations/buddy/workbuddy/provider.ts +0 -209
- package/src/providers/integrations/buddy/workbuddy/quota.ts +0 -161
- package/src/providers/integrations/buddy/workbuddy/shared.ts +0 -285
- 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-CTxoqyYB.js → app-DIXLjojg.js} +0 -0
- /package/dist/dashboard/assets/{app-CTxoqyYB.js.gz → app-DIXLjojg.js.gz} +0 -0
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
// Cursor-native tool calls, unified into one canonical shape.
|
|
2
2
|
//
|
|
3
|
-
// Cursor's `agent.v1.ToolCall` is a oneof of ~30 variants spanning
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
// `PiLsToolCall` 67)
|
|
7
|
-
//
|
|
8
|
-
// them individually meant a decoder and a builder per variant — most of them
|
|
9
|
-
// saying the same thing.
|
|
3
|
+
// Cursor's `agent.v1.ToolCall` is a oneof of ~30 variants spanning several
|
|
4
|
+
// generations: the legacy natives (`ReadToolCall` 8, `ShellToolCall` 1,
|
|
5
|
+
// `EditToolCall` 12, …) and the modern exec family (`PiReadToolCall` 61 …
|
|
6
|
+
// `PiLsToolCall` 67). Each carries its own args message and its own
|
|
7
|
+
// `*ToolResult` oneof of `success`/`error`.
|
|
10
8
|
//
|
|
11
9
|
// This module is the single join point. One table maps a wire variant to a
|
|
12
10
|
// canonical tool identity, and the decode/encode paths below are written once
|
|
13
11
|
// against that table rather than once per variant.
|
|
14
12
|
//
|
|
15
|
-
// **
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
13
|
+
// **Generation aliases collapse to one canonical name.** `ReadToolCall` and
|
|
14
|
+
// `PiReadToolCall` are the *same tool* across two wire generations — the pi_
|
|
15
|
+
// family is the modern executor, the legacy family the older surface. They are
|
|
16
|
+
// folded onto one name (`read`, `shell`, `edit`, `write`, `grep`, `find`,
|
|
17
|
+
// `ls`) so callers reason about tools, not about which wire arm carried them.
|
|
18
|
+
// The `field`/`argsType`/`resultType` still differ per row, so encode/decode
|
|
19
|
+
// round-trips preserve the exact arm that arrived.
|
|
19
20
|
//
|
|
20
21
|
// **Cursor-scoped on purpose.** Nothing here is shared with the other provider
|
|
21
|
-
// integrations. The canonical vocabulary is Cursor's own (`read`, `
|
|
22
|
-
// `
|
|
22
|
+
// integrations. The canonical vocabulary is Cursor's own (`read`, `shell`,
|
|
23
|
+
// `edit`, …), so a tool named `read` on Cursor and a `read` on some other
|
|
23
24
|
// provider are unrelated and cannot collide through a shared registry.
|
|
24
|
-
import type { ToolDefinition } from "../../../../protocol/canonical-model";
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
27
|
* One `ToolCall` oneof arm, as it exists on the wire.
|
|
@@ -41,9 +41,8 @@ export interface CursorToolVariant {
|
|
|
41
41
|
/**
|
|
42
42
|
* Canonical tool name for this variant.
|
|
43
43
|
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
* both; a caller that wants one filters on one.
|
|
44
|
+
* Shared across wire generations: `read` is both `ReadToolCall` and
|
|
45
|
+
* `PiReadToolCall`.
|
|
47
46
|
*/
|
|
48
47
|
readonly name: string;
|
|
49
48
|
}
|
|
@@ -59,14 +58,18 @@ const VARIANT = (
|
|
|
59
58
|
/**
|
|
60
59
|
* Every Cursor-native tool variant this layer speaks, keyed by oneof field.
|
|
61
60
|
*
|
|
62
|
-
* `McpToolCall` is absent
|
|
63
|
-
*
|
|
64
|
-
* `
|
|
65
|
-
* other place tools travel — so those stay on the MCP meta-tool path. This
|
|
66
|
-
* table is for the arms Cursor itself owns.
|
|
61
|
+
* MCP (`McpToolCall`) is intentionally absent: the gateway no longer speaks
|
|
62
|
+
* the MCP meta-tool channel. Client-declared tools have no native slot in
|
|
63
|
+
* `agent.proto`; they are not advertised and any inbound MCP arm is refused.
|
|
67
64
|
*/
|
|
68
65
|
export const CURSOR_TOOL_VARIANTS: ReadonlyMap<number, CursorToolVariant> = new Map([
|
|
69
66
|
VARIANT(1, "ShellToolCall", "ShellArgs", "ShellResult", "shell"),
|
|
67
|
+
// Legacy write has no ToolCall oneof arm — it arrives only as
|
|
68
|
+
// `ExecServerMessage.write_args` (field 3). The variant is registered with
|
|
69
|
+
// a dedicated field number so the executor can resolve it without colliding
|
|
70
|
+
// with `DeleteToolCall` (which also owns field 3); the field is otherwise
|
|
71
|
+
// unused by the ToolCall path.
|
|
72
|
+
VARIANT(0, "WriteToolCall", "WriteArgs", "WriteResult", "write"),
|
|
70
73
|
VARIANT(3, "DeleteToolCall", "DeleteArgs", "DeleteResult", "delete"),
|
|
71
74
|
VARIANT(4, "GlobToolCall", "GlobArgs", "GlobResult", "glob"),
|
|
72
75
|
VARIANT(5, "GrepToolCall", "GrepArgs", "GrepResult", "grep"),
|
|
@@ -93,14 +96,6 @@ export const CURSOR_TOOL_VARIANTS: ReadonlyMap<number, CursorToolVariant> = new
|
|
|
93
96
|
VARIANT(32, "ReflectToolCall", "ReflectArgs", "ReflectResult", "reflect"),
|
|
94
97
|
VARIANT(33, "SetupVmEnvironmentToolCall", "SetupVmEnvironmentArgs", "SetupVmEnvironmentResult", "setup_vm_environment"),
|
|
95
98
|
VARIANT(34, "TruncatedToolCall", "TruncatedArgs", "TruncatedResult", "truncated"),
|
|
96
|
-
// The modern exec family. Same join point, separate identities.
|
|
97
|
-
VARIANT(61, "PiReadToolCall", "PiReadToolArgs", "PiReadExecResult", "pi_read"),
|
|
98
|
-
VARIANT(62, "PiBashToolCall", "PiBashToolArgs", "PiBashExecResult", "pi_bash"),
|
|
99
|
-
VARIANT(63, "PiEditToolCall", "PiEditToolArgs", "PiEditExecResult", "pi_edit"),
|
|
100
|
-
VARIANT(64, "PiWriteToolCall", "PiWriteToolArgs", "PiWriteExecResult", "pi_write"),
|
|
101
|
-
VARIANT(65, "PiGrepToolCall", "PiGrepToolArgs", "PiGrepExecResult", "pi_grep"),
|
|
102
|
-
VARIANT(66, "PiFindToolCall", "PiFindToolArgs", "PiFindExecResult", "pi_find"),
|
|
103
|
-
VARIANT(67, "PiLsToolCall", "PiLsToolArgs", "PiLsExecResult", "pi_ls"),
|
|
104
99
|
].map((entry) => [entry.field, entry]));
|
|
105
100
|
|
|
106
101
|
/**
|
|
@@ -126,8 +121,7 @@ type OneofArm = { readonly field: number; readonly payload: Record<string, unkno
|
|
|
126
121
|
*
|
|
127
122
|
* A oneof has exactly one populated field; a message with none is not a tool
|
|
128
123
|
* call at all and is reported as `undefined` rather than guessed at. An arm
|
|
129
|
-
* this layer does not know is also `undefined
|
|
130
|
-
* MCP to claim it.
|
|
124
|
+
* this layer does not know is also `undefined`.
|
|
131
125
|
*/
|
|
132
126
|
export function cursorToolArm(
|
|
133
127
|
toolCall: Record<string, unknown>,
|
|
@@ -205,71 +199,3 @@ function snakeCaseKey(key: string): string {
|
|
|
205
199
|
.replace(/[\s-]+/g, "_")
|
|
206
200
|
.toLowerCase();
|
|
207
201
|
}
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* The variant whose args a host-exec frame is carrying.
|
|
211
|
-
*
|
|
212
|
-
* Exec frames name their payload after the args message — `read_args`,
|
|
213
|
-
* `shell_args`, `pi_read_args` — not after the `ToolCall` arm, so the lookup
|
|
214
|
-
* runs off `argsType`. Anything not ending in `_args` is not a tool payload
|
|
215
|
-
* (`id`, `exec_id`, `request_context_args`, …) and is reported as `undefined`.
|
|
216
|
-
*/
|
|
217
|
-
export function cursorVariantForExecArgs(
|
|
218
|
-
execServer: Record<string, unknown>,
|
|
219
|
-
): { readonly variant: CursorToolVariant; readonly args: Record<string, unknown> } | undefined {
|
|
220
|
-
for (const [key, value] of Object.entries(execServer)) {
|
|
221
|
-
if (value === null || value === undefined || !key.endsWith("_args")) continue;
|
|
222
|
-
const wanted = key.slice(0, -"_args".length);
|
|
223
|
-
const variant = [...CURSOR_TOOL_VARIANTS.values()].find((entry) =>
|
|
224
|
-
entry.argsType.toLowerCase().startsWith(wanted.toLowerCase()),
|
|
225
|
-
);
|
|
226
|
-
if (variant === undefined) continue;
|
|
227
|
-
return {
|
|
228
|
-
variant,
|
|
229
|
-
args: canonicalToolArguments(value),
|
|
230
|
-
};
|
|
231
|
-
}
|
|
232
|
-
return undefined;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
* The variant an inbound result must be encoded back into.
|
|
237
|
-
*
|
|
238
|
-
* Keyed by `call_id`, which is what the response carries and what the client
|
|
239
|
-
* echoes on the result. Consulted before encoding so a result for a tool this
|
|
240
|
-
* layer never decoded is not invented into some other variant's shape.
|
|
241
|
-
*/
|
|
242
|
-
export class CursorToolCallProvenance {
|
|
243
|
-
readonly #byCallId = new Map<string, CursorToolVariant>();
|
|
244
|
-
|
|
245
|
-
record(callId: string, variant: CursorToolVariant): void {
|
|
246
|
-
this.#byCallId.set(callId, variant);
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
lookup(callId: string): CursorToolVariant | undefined {
|
|
250
|
-
return this.#byCallId.get(callId);
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
/** Drops one call's provenance once its result has been encoded. */
|
|
254
|
-
complete(callId: string): void {
|
|
255
|
-
this.#byCallId.delete(callId);
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
/**
|
|
260
|
-
* A tool declaration the gateway can advertise for Cursor-native tools.
|
|
261
|
-
*
|
|
262
|
-
* Kept separate from `ToolDefinition`'s own name on purpose: the canonical name
|
|
263
|
-
* (`pi_read`) is not the name a client's schema would use, so advertising one
|
|
264
|
-
* under the other would make the call/result round trip undecidable.
|
|
265
|
-
*/
|
|
266
|
-
export function cursorNativeToolDeclaration(
|
|
267
|
-
variant: CursorToolVariant,
|
|
268
|
-
description: string,
|
|
269
|
-
): ToolDefinition {
|
|
270
|
-
return {
|
|
271
|
-
name: variant.name,
|
|
272
|
-
description,
|
|
273
|
-
jsonSchema: { type: "object", properties: {} },
|
|
274
|
-
};
|
|
275
|
-
}
|
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Devin authentication: OAuth login flows and credential import.
|
|
3
|
+
*
|
|
4
|
+
* Three paths are supported:
|
|
5
|
+
*
|
|
6
|
+
* 1. **Devin CLI** (`app.devin.ai`): PKCE S256 browser-code flow. Authorize
|
|
7
|
+
* at `https://app.devin.ai/auth/cli/continue`, exchange at
|
|
8
|
+
* `https://api.devin.ai/auth/cli/token` (body JSON, non-standard).
|
|
9
|
+
* 2. **Windsurf Enterprise** (`windsurf.com`): PKCE S256 loopback flow on
|
|
10
|
+
* port 59654, exchanging via `ExchangePKCEAuthorizationCode` to a raw
|
|
11
|
+
* seat key (`sk-ws-…`, stripped from the `gsk-ws-…` wire form).
|
|
12
|
+
* 3. **CLI adopt**: reads the official Devin CLI `credentials.toml`
|
|
13
|
+
* (`windsurf_api_key`) — no network, no prompts.
|
|
14
|
+
*
|
|
15
|
+
* All three store under the `devin` credential slot (`store-as "devin"`).
|
|
16
|
+
*
|
|
17
|
+
* Ported from oh-my-pi (`registry/oauth/devin-windsurf.ts` +
|
|
18
|
+
* `devin-cli.ts`, MIT) and opencode-devin-provider (`oauth.ts`, MIT).
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
22
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
23
|
+
import { join } from "node:path";
|
|
24
|
+
import {
|
|
25
|
+
base64url,
|
|
26
|
+
decodeJwt,
|
|
27
|
+
} from "jose";
|
|
28
|
+
import type {
|
|
29
|
+
OAuthAuthorizeRequest,
|
|
30
|
+
OAuthCodeExchangeContext,
|
|
31
|
+
OAuthExchangeResult,
|
|
32
|
+
OAuthImportInput,
|
|
33
|
+
OAuthLoginClient,
|
|
34
|
+
} from "../../authentication/oauth-flow-store";
|
|
35
|
+
import { callDevinUnary } from "./devin-http";
|
|
36
|
+
import { DevinMessageTypes } from "./protocol/devin-proto";
|
|
37
|
+
import {
|
|
38
|
+
DEVIN_DEFAULT_BASE_URL,
|
|
39
|
+
DEVIN_EXCHANGE_PATH,
|
|
40
|
+
DEVIN_GET_USER_STATUS_PATH,
|
|
41
|
+
} from "./devin-shared";
|
|
42
|
+
|
|
43
|
+
// ── PKCE ──
|
|
44
|
+
|
|
45
|
+
export function generatePKCE(): { verifier: string; challenge: string } {
|
|
46
|
+
const verifier = base64url.encode(randomBytes(96));
|
|
47
|
+
const challenge = base64url.encode(createHash("sha256").update(verifier).digest());
|
|
48
|
+
return { verifier, challenge };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// ── Identity resolution ──
|
|
52
|
+
|
|
53
|
+
/** JWT claim keys tried in order when deriving an email/identity label. */
|
|
54
|
+
const IDENTITY_CLAIM_KEYS = [
|
|
55
|
+
"email",
|
|
56
|
+
"preferred_username",
|
|
57
|
+
"name",
|
|
58
|
+
"sub",
|
|
59
|
+
"user_id",
|
|
60
|
+
"userId",
|
|
61
|
+
"session_id",
|
|
62
|
+
] as const;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Derives a display label from a session token without any network: decode
|
|
66
|
+
* the JWT payload and read the first present identity claim. A token that is
|
|
67
|
+
* not a JWT (raw `sk-ws-…` seat key) yields nothing.
|
|
68
|
+
*/
|
|
69
|
+
export function identityLabelFromDevinCredential(credential: string): string | undefined {
|
|
70
|
+
const key = credential.trim();
|
|
71
|
+
if (!key) return undefined;
|
|
72
|
+
const jwt = key.startsWith("devin-session-token$")
|
|
73
|
+
? key.slice("devin-session-token$".length)
|
|
74
|
+
: key;
|
|
75
|
+
if (jwt.split(".").length !== 3) return undefined;
|
|
76
|
+
let payload: Record<string, unknown>;
|
|
77
|
+
try {
|
|
78
|
+
payload = decodeJwt(jwt) as Record<string, unknown>;
|
|
79
|
+
} catch {
|
|
80
|
+
// The token is opaque — no claims to read. Callers fall back to the
|
|
81
|
+
// network identity below.
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
84
|
+
for (const claim of IDENTITY_CLAIM_KEYS) {
|
|
85
|
+
const value = payload[claim];
|
|
86
|
+
if (typeof value === "string" && value.length > 0 && value !== "unauthenticated") {
|
|
87
|
+
return value;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** A single identity string from `GetUserStatus`, if the upstream reports one. */
|
|
94
|
+
export function identityFromDevinUserStatus(planInfo: unknown): string | undefined {
|
|
95
|
+
if (typeof planInfo !== "object" || planInfo === null) return undefined;
|
|
96
|
+
const info = planInfo as {
|
|
97
|
+
userStatus?: { email?: string; teamId?: string };
|
|
98
|
+
planInfo?: { devinInfo?: { accountDisplayName?: string; orgId?: string } };
|
|
99
|
+
};
|
|
100
|
+
const email = info.userStatus?.email?.trim();
|
|
101
|
+
if (email) return email;
|
|
102
|
+
const displayName = info.planInfo?.devinInfo?.accountDisplayName?.trim();
|
|
103
|
+
if (displayName) return displayName;
|
|
104
|
+
const orgId = info.planInfo?.devinInfo?.orgId?.trim();
|
|
105
|
+
if (orgId) return orgId;
|
|
106
|
+
const teamId = info.userStatus?.teamId?.trim();
|
|
107
|
+
if (teamId) return teamId;
|
|
108
|
+
return undefined;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Resolves the human-friendly label for a Devin credential: JWT claims first
|
|
113
|
+
* (free), then `GetUserStatus` (network). Never throws — a failed lookup
|
|
114
|
+
* returns `undefined`, leaving the caller's default label in place.
|
|
115
|
+
*/
|
|
116
|
+
export async function resolveDevinAccountLabel(
|
|
117
|
+
credential: string,
|
|
118
|
+
fetcher: typeof fetch = fetch,
|
|
119
|
+
): Promise<string | undefined> {
|
|
120
|
+
const jwtLabel = identityLabelFromDevinCredential(credential);
|
|
121
|
+
if (jwtLabel) return jwtLabel;
|
|
122
|
+
try {
|
|
123
|
+
const response = await callDevinUnary<Record<string, unknown>>(
|
|
124
|
+
DEVIN_GET_USER_STATUS_PATH,
|
|
125
|
+
DevinMessageTypes.GetUserStatusRequest,
|
|
126
|
+
DevinMessageTypes.GetUserStatusResponse,
|
|
127
|
+
{ metadata: { apiKey: credential } },
|
|
128
|
+
{ baseUrl: DEVIN_DEFAULT_BASE_URL, fetchImpl: fetcher, signal: AbortSignal.timeout(10_000) },
|
|
129
|
+
);
|
|
130
|
+
return identityFromDevinUserStatus(response);
|
|
131
|
+
} catch {
|
|
132
|
+
return undefined;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// ── Devin CLI flow (app.devin.ai) ──
|
|
137
|
+
|
|
138
|
+
const DEVIN_AUTHORIZE_URL = "https://app.devin.ai/auth/cli/continue";
|
|
139
|
+
const DEVIN_TOKEN_URL = "https://api.devin.ai/auth/cli/token";
|
|
140
|
+
const DEVIN_BROWSER_REDIRECT_URI = "http://127.0.0.1:59653/callback";
|
|
141
|
+
|
|
142
|
+
export const devinOAuthClient: OAuthLoginClient = {
|
|
143
|
+
supportsDeviceCode: false,
|
|
144
|
+
supportsBrowserCode: true,
|
|
145
|
+
browserRedirectUri: DEVIN_BROWSER_REDIRECT_URI,
|
|
146
|
+
|
|
147
|
+
buildAuthorizeUrl(request: OAuthAuthorizeRequest): string {
|
|
148
|
+
const params = new URLSearchParams({
|
|
149
|
+
redirect_uri: DEVIN_BROWSER_REDIRECT_URI,
|
|
150
|
+
state: request.state,
|
|
151
|
+
prompt: "select_account",
|
|
152
|
+
code_challenge: request.codeChallenge,
|
|
153
|
+
code_challenge_method: "S256",
|
|
154
|
+
});
|
|
155
|
+
return `${DEVIN_AUTHORIZE_URL}?${params.toString()}`;
|
|
156
|
+
},
|
|
157
|
+
|
|
158
|
+
async exchangeCode(
|
|
159
|
+
code: string,
|
|
160
|
+
codeVerifier: string,
|
|
161
|
+
_redirectUri: string,
|
|
162
|
+
_state?: string,
|
|
163
|
+
_context?: OAuthCodeExchangeContext,
|
|
164
|
+
): Promise<OAuthExchangeResult> {
|
|
165
|
+
const response = await fetch(DEVIN_TOKEN_URL, {
|
|
166
|
+
method: "POST",
|
|
167
|
+
headers: { "content-type": "application/json", accept: "application/json" },
|
|
168
|
+
body: JSON.stringify({ code, code_verifier: codeVerifier }),
|
|
169
|
+
});
|
|
170
|
+
if (!response.ok) {
|
|
171
|
+
const text = await response.text().catch(() => "");
|
|
172
|
+
throw new Error(`Devin token exchange failed: HTTP ${response.status} ${text}`);
|
|
173
|
+
}
|
|
174
|
+
const body = (await response.json()) as { token?: string };
|
|
175
|
+
const token = body.token;
|
|
176
|
+
if (!token) throw new Error("Devin token exchange returned no token");
|
|
177
|
+
|
|
178
|
+
// Parse JWT exp, fallback to 1 year.
|
|
179
|
+
let expiresAt: Date;
|
|
180
|
+
try {
|
|
181
|
+
const claims = decodeJwt(token);
|
|
182
|
+
expiresAt = claims.exp ? new Date(claims.exp * 1000) : new Date(Date.now() + 365 * 24 * 3600 * 1000);
|
|
183
|
+
} catch {
|
|
184
|
+
expiresAt = new Date(Date.now() + 365 * 24 * 3600 * 1000);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// The exchange only returns a token; the label comes from the token's
|
|
188
|
+
// own claims (when present) or `GetUserStatus`. Never fail the login on
|
|
189
|
+
// a label lookup.
|
|
190
|
+
const accountLabel = await resolveDevinAccountLabel(token).catch(() => undefined);
|
|
191
|
+
|
|
192
|
+
return {
|
|
193
|
+
access: token,
|
|
194
|
+
refresh: "",
|
|
195
|
+
expiresAt,
|
|
196
|
+
...(accountLabel ? { accountLabel } : {}),
|
|
197
|
+
};
|
|
198
|
+
},
|
|
199
|
+
|
|
200
|
+
async importCredential(input: OAuthImportInput): Promise<OAuthExchangeResult> {
|
|
201
|
+
const credential = input.credential.trim();
|
|
202
|
+
if (!credential) throw new Error("Devin credential is empty");
|
|
203
|
+
// The key itself is the identity; resolve a label when the material can
|
|
204
|
+
// provide one (JWT claims or `GetUserStatus`), never failing on it.
|
|
205
|
+
const accountLabel = await resolveDevinAccountLabel(credential).catch(() => undefined);
|
|
206
|
+
return {
|
|
207
|
+
access: credential,
|
|
208
|
+
refresh: "",
|
|
209
|
+
expiresAt: new Date(8640000000000000),
|
|
210
|
+
...(accountLabel ? { accountLabel } : {}),
|
|
211
|
+
...(input.accountLabel ? { accountLabel: input.accountLabel } : {}),
|
|
212
|
+
};
|
|
213
|
+
},
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
// ── Windsurf Enterprise flow (windsurf.com/editor/signin) ──
|
|
217
|
+
|
|
218
|
+
const WINDSURF_AUTHORIZE_URL = "https://windsurf.com/editor/signin";
|
|
219
|
+
|
|
220
|
+
/** Loopback port the official Devin CLI uses for the Windsurf flow. */
|
|
221
|
+
export const WINDSURF_CALLBACK_PORT = 59654;
|
|
222
|
+
/** Loopback hostname for the Windsurf flow. */
|
|
223
|
+
export const WINDSURF_PREFERRED_HOSTNAME = "127.0.0.1";
|
|
224
|
+
|
|
225
|
+
export const devinWindsurfOAuthClient: OAuthLoginClient = {
|
|
226
|
+
supportsDeviceCode: false,
|
|
227
|
+
supportsBrowserCode: true,
|
|
228
|
+
|
|
229
|
+
buildAuthorizeUrl(request: OAuthAuthorizeRequest): string {
|
|
230
|
+
const params = new URLSearchParams({
|
|
231
|
+
response_type: "code",
|
|
232
|
+
redirect_uri: request.redirectUri,
|
|
233
|
+
state: request.state,
|
|
234
|
+
code_challenge: request.codeChallenge,
|
|
235
|
+
code_challenge_method: "S256",
|
|
236
|
+
prompt: "login",
|
|
237
|
+
redirect_parameters_type: "query",
|
|
238
|
+
});
|
|
239
|
+
return `${WINDSURF_AUTHORIZE_URL}?${params.toString()}`;
|
|
240
|
+
},
|
|
241
|
+
|
|
242
|
+
async exchangeCode(
|
|
243
|
+
code: string,
|
|
244
|
+
codeVerifier: string,
|
|
245
|
+
_redirectUri: string,
|
|
246
|
+
_state?: string,
|
|
247
|
+
_context?: OAuthCodeExchangeContext,
|
|
248
|
+
): Promise<OAuthExchangeResult> {
|
|
249
|
+
const response = await callDevinUnary<{
|
|
250
|
+
apiKey?: string;
|
|
251
|
+
name?: string;
|
|
252
|
+
apiServerUrl?: string;
|
|
253
|
+
devinWebappHost?: string;
|
|
254
|
+
devinApiUrl?: string;
|
|
255
|
+
}>(
|
|
256
|
+
DEVIN_EXCHANGE_PATH,
|
|
257
|
+
DevinMessageTypes.ExchangePKCEAuthorizationCodeRequest,
|
|
258
|
+
DevinMessageTypes.ExchangePKCEAuthorizationCodeResponse,
|
|
259
|
+
{ authorizationCode: code, codeVerifier },
|
|
260
|
+
{ baseUrl: DEVIN_DEFAULT_BASE_URL },
|
|
261
|
+
);
|
|
262
|
+
const apiKey = response.apiKey;
|
|
263
|
+
if (!apiKey) throw new Error("Windsurf code exchange returned no API key");
|
|
264
|
+
// The exchange returns the `g`-prefixed wire form (`gsk-ws-…`); RPCs
|
|
265
|
+
// authenticate with the raw key.
|
|
266
|
+
const key = apiKey.startsWith("gsk-") ? apiKey.slice(1) : apiKey;
|
|
267
|
+
// Prefer the upstream-reported name; fall back to the seat key's identity
|
|
268
|
+
// claims or `GetUserStatus` — never fail the login on a label lookup.
|
|
269
|
+
const accountLabel =
|
|
270
|
+
response.name?.trim() || (await resolveDevinAccountLabel(key).catch(() => undefined));
|
|
271
|
+
return {
|
|
272
|
+
access: key,
|
|
273
|
+
refresh: "",
|
|
274
|
+
expiresAt: new Date(8640000000000000), // seat key: never expires
|
|
275
|
+
...(accountLabel ? { accountLabel } : {}),
|
|
276
|
+
};
|
|
277
|
+
},
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
// ── CLI adopt (credentials.toml) ──
|
|
281
|
+
|
|
282
|
+
const KNOWN_API_HOSTS = new Set(["server.codeium.com", "server.enterprise.windsurf.com"]);
|
|
283
|
+
|
|
284
|
+
/** Candidate `credentials.toml` paths per platform. */
|
|
285
|
+
export function devinCliCredentialPaths(): string[] {
|
|
286
|
+
const paths: string[] = [];
|
|
287
|
+
if (process.platform === "win32") {
|
|
288
|
+
const appData = process.env.APPDATA;
|
|
289
|
+
if (appData) paths.push(join(appData, "devin", "credentials.toml"));
|
|
290
|
+
paths.push(join(process.env.HOME ?? "", ".local", "share", "devin", "credentials.toml"));
|
|
291
|
+
} else {
|
|
292
|
+
const xdg = process.env.XDG_DATA_HOME;
|
|
293
|
+
if (xdg) paths.push(join(xdg, "devin", "credentials.toml"));
|
|
294
|
+
paths.push(join(process.env.HOME ?? "", ".local", "share", "devin", "credentials.toml"));
|
|
295
|
+
if (process.platform === "darwin") {
|
|
296
|
+
paths.push(join(process.env.HOME ?? "", "Library", "Application Support", "devin", "credentials.toml"));
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return [...new Set(paths)];
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/** Parses a Devin CLI `credentials.toml` and returns the Windsurf seat key. */
|
|
303
|
+
export function readDevinCliCredentials(file: string): string {
|
|
304
|
+
const text = readFileSync(file, "utf8");
|
|
305
|
+
// Minimal TOML parse: key = "value" lines.
|
|
306
|
+
const record: Record<string, string> = {};
|
|
307
|
+
for (const line of text.split(/\r?\n/)) {
|
|
308
|
+
const trimmed = line.trim();
|
|
309
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
310
|
+
const eq = trimmed.indexOf("=");
|
|
311
|
+
if (eq < 0) continue;
|
|
312
|
+
const key = trimmed.slice(0, eq).trim();
|
|
313
|
+
let value = trimmed.slice(eq + 1).trim();
|
|
314
|
+
if (value.startsWith('"') && value.endsWith('"')) value = value.slice(1, -1);
|
|
315
|
+
record[key] = value;
|
|
316
|
+
}
|
|
317
|
+
const key = record["windsurf_api_key"]?.trim() ?? "";
|
|
318
|
+
if (!key) throw new Error(`Devin CLI credentials at ${file} have no windsurf_api_key`);
|
|
319
|
+
const serverUrl = record["api_server_url"]?.trim();
|
|
320
|
+
if (serverUrl) {
|
|
321
|
+
let host: string | undefined;
|
|
322
|
+
try {
|
|
323
|
+
host = new URL(serverUrl).host;
|
|
324
|
+
} catch {
|
|
325
|
+
host = undefined;
|
|
326
|
+
}
|
|
327
|
+
if (!host || !KNOWN_API_HOSTS.has(host)) {
|
|
328
|
+
throw new Error(`Devin CLI credentials at ${file} point at unsupported API server`);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return key;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/** Reads the first existing credentials file and returns its seat key. */
|
|
335
|
+
export function loginDevinCliHook(): Promise<string> {
|
|
336
|
+
for (const file of devinCliCredentialPaths()) {
|
|
337
|
+
if (!existsSync(file)) continue;
|
|
338
|
+
try {
|
|
339
|
+
return Promise.resolve(readDevinCliCredentials(file));
|
|
340
|
+
} catch (error) {
|
|
341
|
+
// First existing file that fails validation wins; no fallback probing.
|
|
342
|
+
return Promise.reject(error);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
return Promise.reject(
|
|
346
|
+
new Error(
|
|
347
|
+
`No Devin CLI credentials found (probed: ${devinCliCredentialPaths().join(", ")}). Run \`devin auth login\`, then retry.`,
|
|
348
|
+
),
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// ── Import credential (raw API key / session token) ──
|
|
353
|
+
// `devinOAuthClient.importCredential` handles pasted keys; no separate client.
|