cartethyia 2.4.6 → 2.5.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/README.md +45 -13
- package/dist/dashboard/assets/BannedPage-ChqnTRpZ.js +1 -0
- package/dist/dashboard/assets/BannedPage-ChqnTRpZ.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolDetailPage-Bcy150Jo.js → CliToolDetailPage-Bb9CNuoh.js} +1 -1
- package/dist/dashboard/assets/CliToolDetailPage-Bb9CNuoh.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolsPage-DyNXefph.js → CliToolsPage-BXUaRCQQ.js} +1 -1
- package/dist/dashboard/assets/CliToolsPage-BXUaRCQQ.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-CisNZOUt.js +1 -0
- package/dist/dashboard/assets/CombosPage-CisNZOUt.js.gz +0 -0
- package/dist/dashboard/assets/{ConsoleLogPage-CATpAEOz.js → ConsoleLogPage-BOpI_LOH.js} +1 -1
- package/dist/dashboard/assets/ConsoleLogPage-BOpI_LOH.js.gz +0 -0
- package/dist/dashboard/assets/{CustomizationPage-D6jEU7nL.js → CustomizationPage-DAkdvJ4k.js} +1 -1
- package/dist/dashboard/assets/CustomizationPage-DAkdvJ4k.js.gz +0 -0
- package/dist/dashboard/assets/{HealthEventsModal-CZkpn0a7.js → HealthEventsModal-DeT-VXHd.js} +1 -1
- package/dist/dashboard/assets/HealthEventsModal-DeT-VXHd.js.gz +0 -0
- package/dist/dashboard/assets/{LoginPage-BJlMVN4U.js → LoginPage-CytxSeGP.js} +1 -1
- package/dist/dashboard/assets/LoginPage-CytxSeGP.js.gz +0 -0
- package/dist/dashboard/assets/{ModelPicker-Br3CXEau.js → ModelPicker-oQ-SDXp8.js} +1 -1
- package/dist/dashboard/assets/ModelPicker-oQ-SDXp8.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-CU7S1wJs.js +1 -0
- package/dist/dashboard/assets/OverviewPage-CU7S1wJs.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-DLm2baot.js +3 -0
- package/dist/dashboard/assets/ProviderDetailPage-DLm2baot.js.gz +0 -0
- package/dist/dashboard/assets/ProviderIcon-CmfzxpVM.js +1 -0
- package/dist/dashboard/assets/ProviderIcon-CmfzxpVM.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-DOXfuzfL.js +1 -0
- package/dist/dashboard/assets/ProvidersPage-DOXfuzfL.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-wvk0ciQN.js +7 -0
- package/dist/dashboard/assets/ProxyPage-wvk0ciQN.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-Cn_fcUHE.js +1 -0
- package/dist/dashboard/assets/QuotaPage-Cn_fcUHE.js.gz +0 -0
- package/dist/dashboard/assets/{SettingsPage-BHW4Zt06.js → SettingsPage-8-eVadhc.js} +1 -1
- package/dist/dashboard/assets/SettingsPage-8-eVadhc.js.gz +0 -0
- package/dist/dashboard/assets/{SetupPage-VOYC_lIa.js → SetupPage-uEIXPyGO.js} +1 -1
- package/dist/dashboard/assets/SetupPage-uEIXPyGO.js.gz +0 -0
- package/dist/dashboard/assets/SortableList-DCY0TPTZ.js +1 -0
- package/dist/dashboard/assets/SortableList-DCY0TPTZ.js.gz +0 -0
- package/dist/dashboard/assets/{StudioPage-BNIDLiU6.js → StudioPage-DqK5E26W.js} +4 -4
- package/dist/dashboard/assets/StudioPage-DqK5E26W.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-38JfiZ0H.js +56 -0
- package/dist/dashboard/assets/UsagePage-38JfiZ0H.js.gz +0 -0
- package/dist/dashboard/assets/{api-keys-BETfaMYZ.js → api-keys-BmDbsior.js} +1 -1
- package/dist/dashboard/assets/api-keys-BmDbsior.js.gz +0 -0
- package/dist/dashboard/assets/app-BbpSarVV.css +2 -0
- package/dist/dashboard/assets/app-BbpSarVV.css.gz +0 -0
- package/dist/dashboard/assets/assert-BHfaei-X.js +1 -0
- package/dist/dashboard/assets/assert-BHfaei-X.js.gz +0 -0
- package/dist/dashboard/assets/{badge-BTyGk_DL.js → badge-DpXT4Ixt.js} +1 -1
- package/dist/dashboard/assets/badge-DpXT4Ixt.js.gz +0 -0
- package/dist/dashboard/assets/{banner-bujTWYM4.js → banner-CSAAWLJv.js} +1 -1
- package/dist/dashboard/assets/banner-CSAAWLJv.js.gz +0 -0
- package/dist/dashboard/assets/{card-B0Bnx5CA.js → card-DEhRXXw4.js} +1 -1
- package/dist/dashboard/assets/card-DEhRXXw4.js.gz +0 -0
- package/dist/dashboard/assets/{cli-tools-DE2ug812.js → cli-tools-B0wBq-RL.js} +1 -1
- package/dist/dashboard/assets/cli-tools-B0wBq-RL.js.gz +0 -0
- package/dist/dashboard/assets/{clipboard-button-R_rArH8S.js → clipboard-button-DOo6EU8O.js} +1 -1
- package/dist/dashboard/assets/clipboard-button-DOo6EU8O.js.gz +0 -0
- package/dist/dashboard/assets/{dialog-BWIP_EvW.js → dialog-BvQeBMfP.js} +1 -1
- package/dist/dashboard/assets/dialog-BvQeBMfP.js.gz +0 -0
- package/dist/dashboard/assets/{drawer-BKcgVugF.js → drawer-CMwPXwQB.js} +1 -1
- package/dist/dashboard/assets/drawer-CMwPXwQB.js.gz +0 -0
- package/dist/dashboard/assets/entry--yj84zk3.js +4 -0
- package/dist/dashboard/assets/entry--yj84zk3.js.gz +0 -0
- package/dist/dashboard/assets/{entry-CcWkGR4a.js → entry-D4O2229X.js} +1 -1
- package/dist/dashboard/assets/{entry-CcWkGR4a.js.gz → entry-D4O2229X.js.gz} +0 -0
- package/dist/dashboard/assets/{entry-kTiTFrvh.js → entry-DKvr5Q9K.js} +1 -1
- package/dist/dashboard/assets/entry-DKvr5Q9K.js.gz +0 -0
- package/dist/dashboard/assets/{github-badge-Booc5mNe.js → github-badge-zliLvBwr.js} +1 -1
- package/dist/dashboard/assets/github-badge-zliLvBwr.js.gz +0 -0
- package/dist/dashboard/assets/{index-D70pChfn.js → index-CcD1eSJ6.js} +2 -2
- package/dist/dashboard/assets/index-CcD1eSJ6.js.gz +0 -0
- package/dist/dashboard/assets/{inline-D1TCqM2D.js → inline-D1IlZZ8H.js} +1 -1
- package/dist/dashboard/assets/inline-D1IlZZ8H.js.gz +0 -0
- package/dist/dashboard/assets/{input-B9oyU93y.js → input-BpVZdrbc.js} +1 -1
- package/dist/dashboard/assets/input-BpVZdrbc.js.gz +0 -0
- package/dist/dashboard/assets/{layout-BArzXirQ.js → layout-BioLW7gN.js} +1 -1
- package/dist/dashboard/assets/layout-BioLW7gN.js.gz +0 -0
- package/dist/dashboard/assets/{list-row-BVZzaoHF.js → list-row-CwVcGAIc.js} +1 -1
- package/dist/dashboard/assets/list-row-CwVcGAIc.js.gz +0 -0
- package/dist/dashboard/assets/{live-EmuIayqp.js → live-yfEJFF9T.js} +1 -1
- package/dist/dashboard/assets/live-yfEJFF9T.js.gz +0 -0
- package/dist/dashboard/assets/{model-bans-CSPQ9xB0.js → model-bans-CT-TxSNX.js} +1 -1
- package/dist/dashboard/assets/model-bans-CT-TxSNX.js.gz +0 -0
- package/dist/dashboard/assets/providers/cursor.webp +0 -0
- package/dist/dashboard/assets/providers/trae.webp +0 -0
- package/dist/dashboard/assets/{routing-BExgxxBU.js → routing-Cs6jl49L.js} +1 -1
- package/dist/dashboard/assets/routing-Cs6jl49L.js.gz +0 -0
- package/dist/dashboard/assets/select-XPJ-dIw3.js +41 -0
- package/dist/dashboard/assets/select-XPJ-dIw3.js.gz +0 -0
- package/dist/dashboard/assets/settings-CfcTcOyU.js +1 -0
- package/dist/dashboard/assets/settings-CfcTcOyU.js.gz +0 -0
- package/dist/dashboard/assets/{stack-Ca5HxI5i.js → stack-C9_uUjaA.js} +1 -1
- package/dist/dashboard/assets/stack-C9_uUjaA.js.gz +0 -0
- package/dist/dashboard/assets/{state-CzUPfLXo.js → state-DA0B95UQ.js} +1 -1
- package/dist/dashboard/assets/state-DA0B95UQ.js.gz +0 -0
- package/dist/dashboard/assets/{switch-DOUIky_i.js → switch-Cittxy-x.js} +1 -1
- package/dist/dashboard/assets/switch-Cittxy-x.js.gz +0 -0
- package/dist/dashboard/assets/{toast-C76WrMhc.js → toast-CNt_jzO4.js} +1 -1
- package/dist/dashboard/assets/toast-CNt_jzO4.js.gz +0 -0
- package/dist/dashboard/assets/{useMutation-D87FZwH0.js → useMutation-BQKMcJ1H.js} +1 -1
- package/dist/dashboard/assets/useMutation-BQKMcJ1H.js.gz +0 -0
- package/dist/dashboard/index.html +1 -1
- package/dist/dashboard/index.html.gz +0 -0
- package/dist/dashboard/precompressed-assets.json +51 -52
- package/migrations/full-postgres/0015_add_payload_stages.sql +18 -0
- package/migrations/full-postgres/0016_add_share_link_slug.sql +20 -0
- package/migrations/full-postgres/0017_add_models_pro_only.sql +18 -0
- package/migrations/full-postgres/0018_add_accounts_quota_plan.sql +18 -0
- package/migrations/full-postgres/0019_add_models_free_tier.sql +15 -0
- package/migrations/lite-sqlite3/0015_add_payload_stages.sql +18 -0
- package/migrations/lite-sqlite3/0016_add_share_link_slug.sql +20 -0
- package/migrations/lite-sqlite3/0017_add_models_pro_only.sql +18 -0
- package/migrations/lite-sqlite3/0018_add_accounts_quota_plan.sql +18 -0
- package/migrations/lite-sqlite3/0019_add_models_free_tier.sql +15 -0
- package/package.json +3 -2
- package/scripts/cli/command/console-menu.ts +30 -11
- package/scripts/cli/command/start.ts +77 -13
- package/scripts/cli/command/tray.ts +47 -8
- package/scripts/cli/command/update.ts +1 -1
- package/scripts/cli/gateway/instance-lock.ts +105 -0
- package/scripts/cli/gateway/spawn.ts +173 -101
- package/scripts/cli/ui/background.ts +110 -49
- package/src/boot/app.ts +20 -6
- package/src/boot/dependencies.ts +19 -0
- package/src/boot/elysia-typebox-bridge.ts +37 -0
- package/src/boot/lifecycle.ts +2 -0
- package/src/config/cooldowns.ts +138 -138
- package/src/config/providers.ts +5 -5
- package/src/config/runtime.ts +19 -3
- package/src/config/spec.ts +9 -0
- package/src/console/api-keys/contracts.ts +414 -391
- package/src/console/api-keys/routes.ts +880 -870
- package/src/console/auth/account-reset-store.ts +14 -0
- package/src/console/auth/account-reset.ts +3 -2
- package/src/console/auth/setup-service.ts +6 -3
- package/src/console/domain-registration.ts +9 -2
- package/src/console/observability/contracts.ts +475 -455
- package/src/console/observability/store.ts +1015 -952
- package/src/console/providers/catalog/contracts.ts +31 -0
- package/src/console/providers/catalog/provider-operations.ts +8 -0
- package/src/console/providers/catalog/store.ts +1532 -1525
- package/src/console/providers/oauth/callback-listener.ts +18 -3
- package/src/console/providers/oauth/routes.ts +38 -15
- package/src/console/quota/refresh.ts +19 -0
- package/src/console/updates/routes.ts +162 -4
- package/src/main.ts +3 -0
- package/src/network/http2-bidi.ts +85 -0
- package/src/network/outbound-fetch.ts +1 -26
- package/src/network/pool/agent.ts +478 -460
- package/src/network/pool/resolver.ts +1104 -544
- package/src/network/pool-health-machine.ts +12 -5
- package/src/observability/payload-capture.ts +344 -324
- package/src/persistence/db-pg.ts +9 -3
- package/src/persistence/db-sqlite.ts +497 -495
- package/src/persistence/health-event-flush.ts +137 -0
- package/src/persistence/migrate.ts +181 -129
- package/src/persistence/schema.ts +1360 -1295
- package/src/persistence/settings-revision.ts +25 -0
- package/src/persistence/shared-cache.ts +217 -0
- package/src/persistence/stores/share-store.ts +556 -528
- package/src/persistence/usage-flush.ts +61 -1
- package/src/protocol/canonical-model.ts +23 -1
- package/src/protocol/response/chat.ts +143 -10
- package/src/protocol/response/omp-tool-call-markup.ts +221 -0
- package/src/providers/default-registry.ts +173 -1
- package/src/providers/discovery/openai-model-discovery.ts +39 -3
- package/src/providers/discovery/openrouter-free-roster.ts +98 -0
- package/src/providers/discovery/probing-service.ts +1022 -1001
- package/src/providers/integrations/buddy/buddy-catalog-shared.ts +39 -0
- package/src/providers/integrations/buddy/buddy-chat-shared.ts +913 -914
- package/src/providers/integrations/buddy/buddy-conversation-headers.ts +18 -5
- package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +4 -0
- package/src/providers/integrations/buddy/codebuddy/provider.ts +180 -175
- package/src/providers/integrations/buddy/codebuddy/shared.ts +15 -6
- package/src/providers/integrations/buddy/workbuddy/provider.ts +206 -204
- package/src/providers/integrations/buddy/workbuddy/shared.ts +3 -3
- package/src/providers/integrations/claude/claude.ts +606 -582
- package/src/providers/integrations/cline/cline-quota.ts +18 -16
- package/src/providers/integrations/cline/cline.ts +539 -468
- package/src/providers/integrations/commandcode/commandcode.ts +675 -541
- package/src/providers/integrations/commandcode/discovery.ts +116 -0
- package/src/providers/integrations/commandcode/quota.ts +160 -0
- package/src/providers/integrations/cursor/cursor-auth.ts +418 -0
- package/src/providers/integrations/cursor/cursor-catalog.ts +368 -0
- package/src/providers/integrations/cursor/cursor-http2.ts +300 -0
- package/src/providers/integrations/cursor/cursor-identity.ts +92 -0
- package/src/providers/integrations/cursor/cursor-request.ts +471 -0
- package/src/providers/integrations/cursor/cursor-session-manager.ts +281 -0
- package/src/providers/integrations/cursor/cursor-shared.ts +108 -0
- package/src/providers/integrations/cursor/cursor.ts +960 -0
- package/src/providers/integrations/cursor/protocol/framing.ts +129 -0
- package/src/providers/integrations/cursor/protocol/messages.ts +2355 -0
- package/src/providers/integrations/cursor/protocol/struct.ts +305 -0
- package/src/providers/integrations/github/github.ts +4 -4
- package/src/providers/integrations/hermes.ts +79 -8
- package/src/providers/integrations/kilo/kilo-discovery.ts +10 -1
- package/src/providers/integrations/kilo/kilo.ts +153 -146
- package/src/providers/integrations/opencode/provider.ts +532 -538
- package/src/providers/integrations/openrouter/provider.ts +139 -281
- package/src/providers/integrations/qoder/qoder-catalog.ts +450 -0
- package/src/providers/integrations/qoder/qoder-oauth.ts +310 -257
- package/src/providers/integrations/qoder/qoder-realm.ts +106 -0
- package/src/providers/integrations/qoder/qoder-virtual.ts +77 -0
- package/src/providers/integrations/qoder/qoder.ts +865 -730
- package/src/providers/integrations/trae/trae-catalog.ts +190 -0
- package/src/providers/integrations/trae/trae-headers.ts +149 -0
- package/src/providers/integrations/trae/trae-oauth.ts +773 -0
- package/src/providers/integrations/trae/trae-protocol.ts +400 -0
- package/src/providers/integrations/trae/trae-realm.ts +220 -0
- package/src/providers/integrations/trae/trae.ts +458 -0
- package/src/providers/operations/account-health-service.ts +107 -10
- package/src/providers/operations/client-versions.ts +133 -6
- package/src/providers/operations/provider-catalog-seeder.ts +95 -86
- package/src/providers/operations/provider-credential-service.ts +46 -7
- package/src/providers/provider-contracts.ts +76 -0
- package/src/providers/provider-metadata.ts +78 -6
- package/src/providers/provider-model-definition.ts +373 -349
- package/src/security/api-key-auth.ts +126 -8
- package/src/transport/contracts.ts +3 -0
- package/src/transport/dispatch/attempt-finalize.ts +32 -1
- package/src/transport/dispatch/attempt-loop.ts +530 -515
- package/src/transport/dispatch/generation.ts +88 -21
- package/src/transport/dispatch/leases.ts +99 -2
- package/src/transport/dispatch/proxy-request.ts +60 -3
- package/src/transport/dispatch/streaming/finalize.ts +16 -1
- package/src/transport/dispatch/streaming/stream.ts +22 -2
- package/src/transport/dispatch/upstream.ts +19 -1
- package/src/transport/guards/auth-guard.ts +26 -1
- package/src/transport/guards/body-policy.ts +5 -4
- package/src/transport/request/preparer.ts +103 -0
- package/src/transport/request/state.ts +14 -0
- package/src/transport/routing/plan-gate.ts +45 -0
- package/src/transport/routing/route-catalog.ts +799 -777
- package/src/transport/routing/route-model.ts +52 -1
- package/src/transport/routing/router.ts +51 -0
- package/dist/dashboard/assets/BannedPage-QhvbJB9o.js +0 -1
- package/dist/dashboard/assets/BannedPage-QhvbJB9o.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-Bcy150Jo.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-DyNXefph.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-Cak0ljnO.js +0 -1
- package/dist/dashboard/assets/CombosPage-Cak0ljnO.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-CATpAEOz.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-D6jEU7nL.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-CZkpn0a7.js.gz +0 -0
- package/dist/dashboard/assets/LoginPage-BJlMVN4U.js.gz +0 -0
- package/dist/dashboard/assets/ModelPicker-Br3CXEau.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-CQxXbo2g.js +0 -1
- package/dist/dashboard/assets/OverviewPage-CQxXbo2g.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage--0RBNh99.js +0 -3
- package/dist/dashboard/assets/ProviderDetailPage--0RBNh99.js.gz +0 -0
- package/dist/dashboard/assets/ProviderIcon-paOCq8I0.js +0 -1
- package/dist/dashboard/assets/ProviderIcon-paOCq8I0.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-1M-C3mbu.js +0 -1
- package/dist/dashboard/assets/ProvidersPage-1M-C3mbu.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-CXiumA53.js +0 -7
- package/dist/dashboard/assets/ProxyPage-CXiumA53.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-BGDIfIYP.js +0 -1
- package/dist/dashboard/assets/QuotaPage-BGDIfIYP.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-BHW4Zt06.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-VOYC_lIa.js.gz +0 -0
- package/dist/dashboard/assets/SortableList-DpOTnGuH.js +0 -1
- package/dist/dashboard/assets/SortableList-DpOTnGuH.js.gz +0 -0
- package/dist/dashboard/assets/StudioPage-BNIDLiU6.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-BAFaSDQV.js +0 -56
- package/dist/dashboard/assets/UsagePage-BAFaSDQV.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-BETfaMYZ.js.gz +0 -0
- package/dist/dashboard/assets/app-BLCvGdzb.css +0 -2
- package/dist/dashboard/assets/app-BLCvGdzb.css.gz +0 -0
- package/dist/dashboard/assets/assert-7J6_LVD3.js +0 -1
- package/dist/dashboard/assets/assert-7J6_LVD3.js.gz +0 -0
- package/dist/dashboard/assets/badge-BTyGk_DL.js.gz +0 -0
- package/dist/dashboard/assets/banner-bujTWYM4.js.gz +0 -0
- package/dist/dashboard/assets/card-B0Bnx5CA.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-DE2ug812.js.gz +0 -0
- package/dist/dashboard/assets/clipboard-button-R_rArH8S.js.gz +0 -0
- package/dist/dashboard/assets/dialog-BWIP_EvW.js.gz +0 -0
- package/dist/dashboard/assets/drawer-BKcgVugF.js.gz +0 -0
- package/dist/dashboard/assets/entry-7dpgvpJ3.js +0 -4
- package/dist/dashboard/assets/entry-7dpgvpJ3.js.gz +0 -0
- package/dist/dashboard/assets/entry-kTiTFrvh.js.gz +0 -0
- package/dist/dashboard/assets/github-badge-Booc5mNe.js.gz +0 -0
- package/dist/dashboard/assets/index-D70pChfn.js.gz +0 -0
- package/dist/dashboard/assets/inline-D1TCqM2D.js.gz +0 -0
- package/dist/dashboard/assets/input-B9oyU93y.js.gz +0 -0
- package/dist/dashboard/assets/layout-BArzXirQ.js.gz +0 -0
- package/dist/dashboard/assets/list-row-BVZzaoHF.js.gz +0 -0
- package/dist/dashboard/assets/live-EmuIayqp.js.gz +0 -0
- package/dist/dashboard/assets/model-bans-CSPQ9xB0.js.gz +0 -0
- package/dist/dashboard/assets/routing-BExgxxBU.js.gz +0 -0
- package/dist/dashboard/assets/select-C9mMoEpJ.js +0 -41
- package/dist/dashboard/assets/select-C9mMoEpJ.js.gz +0 -0
- package/dist/dashboard/assets/settings-C4_Gn_wq.js +0 -1
- package/dist/dashboard/assets/settings-C4_Gn_wq.js.gz +0 -0
- package/dist/dashboard/assets/sliders-horizontal-ClG7dBeJ.js +0 -1
- package/dist/dashboard/assets/sliders-horizontal-ClG7dBeJ.js.gz +0 -0
- package/dist/dashboard/assets/stack-Ca5HxI5i.js.gz +0 -0
- package/dist/dashboard/assets/state-CzUPfLXo.js.gz +0 -0
- package/dist/dashboard/assets/switch-DOUIky_i.js.gz +0 -0
- package/dist/dashboard/assets/toast-C76WrMhc.js.gz +0 -0
- package/dist/dashboard/assets/useMutation-D87FZwH0.js.gz +0 -0
- package/src/network/tls/bun-client-hello.ts +0 -112
- /package/dist/dashboard/assets/{app-Cjq7nrwu.js → app-C-Y4oZT0.js} +0 -0
- /package/dist/dashboard/assets/{app-Cjq7nrwu.js.gz → app-C-Y4oZT0.js.gz} +0 -0
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
// Live Cursor Run sessions, and the tool-call continuation they make possible.
|
|
2
|
+
//
|
|
3
|
+
// Cursor's tool loop spans *two* client HTTP requests: the first returns a tool
|
|
4
|
+
// call, the second submits that tool's result. The upstream Run must be the same
|
|
5
|
+
// Run, and it must stay open between them, so the Run cannot be owned by either
|
|
6
|
+
// request — it is owned here.
|
|
7
|
+
//
|
|
8
|
+
// This manager is process-local by construction. A Run is an HTTP/2 socket; it
|
|
9
|
+
// cannot survive a restart, and it is not shared across processes. After a
|
|
10
|
+
// restart the adapter rebases from the complete request history instead (see
|
|
11
|
+
// `cursor.ts`), which is why an orphan tool result with no history fails
|
|
12
|
+
// explicitly rather than silently starting a new Run.
|
|
13
|
+
//
|
|
14
|
+
// Everything the manager holds is bounded: one idle TTL, one release per
|
|
15
|
+
// session, one frame pump per Run, and one terminal path that closes the stream
|
|
16
|
+
// and releases the borrowed lease exactly once.
|
|
17
|
+
import { GatewayError } from "../../../protocol/gateway-error";
|
|
18
|
+
import type { UsageRecord } from "../../../protocol/canonical-model";
|
|
19
|
+
import type { AttemptLeaseOwnership } from "../../provider-contracts";
|
|
20
|
+
import { RUN_IDLE_TTL_MS } from "./cursor-shared";
|
|
21
|
+
import type { CursorToolDescriptor } from "./cursor-request";
|
|
22
|
+
|
|
23
|
+
/** Identity a later request must present to claim a pending tool call. */
|
|
24
|
+
export interface CursorContinuationScope {
|
|
25
|
+
readonly tenantId: string;
|
|
26
|
+
readonly apiKeyId: string;
|
|
27
|
+
readonly providerId: string;
|
|
28
|
+
readonly providerAccountId: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** One pending external tool call awaiting the client's result. */
|
|
32
|
+
export interface CursorPendingToolCall {
|
|
33
|
+
/** Unguessable call id handed to the client. */
|
|
34
|
+
readonly callId: string;
|
|
35
|
+
/** Cursor's exec message id the result must echo. */
|
|
36
|
+
readonly execId: number;
|
|
37
|
+
/** Bare function name the client declared. */
|
|
38
|
+
readonly toolName: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Everything one live Run session owns. */
|
|
42
|
+
export interface CursorRunSession {
|
|
43
|
+
readonly runId: string;
|
|
44
|
+
readonly conversationId: string;
|
|
45
|
+
readonly scope: CursorContinuationScope;
|
|
46
|
+
/** Declared tools for this Run; an inbound call outside them is refused. */
|
|
47
|
+
readonly descriptors: readonly CursorToolDescriptor[];
|
|
48
|
+
/** Cursor exec id → pending call id. */
|
|
49
|
+
readonly pending: Map<number, string>;
|
|
50
|
+
/** Pending call id → Cursor exec id and name. */
|
|
51
|
+
readonly calls: Map<string, CursorPendingToolCall>;
|
|
52
|
+
/** Usage reported by the Run's `turn_ended`, when it has arrived. */
|
|
53
|
+
usage: UsageRecord | undefined;
|
|
54
|
+
/** Terminal reason this Run ended, once it has. */
|
|
55
|
+
failure: GatewayError | undefined;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Registry entry: one live Run, its expiry, and its borrowed lease release. */
|
|
59
|
+
interface LiveRun {
|
|
60
|
+
readonly session: CursorRunSession;
|
|
61
|
+
/**
|
|
62
|
+
* The borrowed account/network-pool lease release. Optional and mutable: a
|
|
63
|
+
* continuation request that re-enters an already-registered Run hands over the
|
|
64
|
+
* lease it took, and `adoptLease` refuses when one is already stored — so the
|
|
65
|
+
* slot is released exactly once however many requests touched the Run.
|
|
66
|
+
*/
|
|
67
|
+
releaseLease?: (() => void) | undefined;
|
|
68
|
+
readonly close: (reason?: string) => void;
|
|
69
|
+
expiryTimer: ReturnType<typeof setTimeout>;
|
|
70
|
+
expiresAt: number;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Bounded, tenant/API-key-scoped registry of live Cursor Runs.
|
|
75
|
+
*
|
|
76
|
+
* A continuation is authorized by *server-recorded* affinity only: a call id is
|
|
77
|
+
* unguessable, and resolving one additionally requires the same tenant, API key,
|
|
78
|
+
* provider, and account that created it. A caller that guesses or replays a call
|
|
79
|
+
* id from another key resolves nothing, so one tenant's tool result can never be
|
|
80
|
+
* written onto another tenant's Run.
|
|
81
|
+
*/
|
|
82
|
+
export class CursorRunSessionManager {
|
|
83
|
+
/** runId → live Run. */
|
|
84
|
+
private readonly runs = new Map<string, LiveRun>();
|
|
85
|
+
/** Pending call id → runId. Second index: resolution is by call id. */
|
|
86
|
+
private readonly callOwners = new Map<string, string>();
|
|
87
|
+
|
|
88
|
+
/** Live Run count, for tests and runtime assertions. */
|
|
89
|
+
get size(): number {
|
|
90
|
+
return this.runs.size;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Registers one live Run.
|
|
95
|
+
*
|
|
96
|
+
* `releaseLease` is the borrowed account/network-pool lease the manager now
|
|
97
|
+
* owns: the request that opened the Run transferred it instead of releasing it
|
|
98
|
+
* at response time. It is called exactly once, on the Run's single terminal
|
|
99
|
+
* path.
|
|
100
|
+
*/
|
|
101
|
+
register(input: {
|
|
102
|
+
readonly session: CursorRunSession;
|
|
103
|
+
readonly releaseLease?: (() => void) | undefined;
|
|
104
|
+
readonly close: (reason?: string) => void;
|
|
105
|
+
readonly idleTtlMs?: number;
|
|
106
|
+
}): void {
|
|
107
|
+
const idleTtlMs = input.idleTtlMs ?? RUN_IDLE_TTL_MS;
|
|
108
|
+
const runId = input.session.runId;
|
|
109
|
+
const entry: LiveRun = {
|
|
110
|
+
session: input.session,
|
|
111
|
+
...(input.releaseLease === undefined ? {} : { releaseLease: input.releaseLease }),
|
|
112
|
+
close: input.close,
|
|
113
|
+
expiresAt: Date.now() + idleTtlMs,
|
|
114
|
+
expiryTimer: setTimeout(() => {
|
|
115
|
+
this.terminate(runId, "Cursor Run idle-expired waiting for a tool result");
|
|
116
|
+
}, idleTtlMs),
|
|
117
|
+
};
|
|
118
|
+
entry.expiryTimer.unref?.();
|
|
119
|
+
this.runs.set(runId, entry);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** Ends one Run: closes its stream and releases what it borrowed, once. */
|
|
123
|
+
terminate(runId: string, reason?: string): void {
|
|
124
|
+
const entry = this.runs.get(runId);
|
|
125
|
+
if (entry === undefined) return;
|
|
126
|
+
this.runs.delete(runId);
|
|
127
|
+
for (const callId of entry.session.pending.values()) {
|
|
128
|
+
if (this.callOwners.get(callId) === runId) this.callOwners.delete(callId);
|
|
129
|
+
}
|
|
130
|
+
for (const call of entry.session.calls.values()) {
|
|
131
|
+
if (this.callOwners.get(call.callId) === runId) this.callOwners.delete(call.callId);
|
|
132
|
+
}
|
|
133
|
+
clearTimeout(entry.expiryTimer);
|
|
134
|
+
try {
|
|
135
|
+
entry.close(reason);
|
|
136
|
+
} catch {
|
|
137
|
+
// Closing a dead stream must not skip the lease release below.
|
|
138
|
+
}
|
|
139
|
+
try {
|
|
140
|
+
entry.releaseLease?.();
|
|
141
|
+
} catch {
|
|
142
|
+
// A failed release must not propagate out of teardown.
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** Registers one pending external tool call on a live Run. */
|
|
147
|
+
registerPendingCall(runId: string, call: CursorPendingToolCall): boolean {
|
|
148
|
+
const entry = this.runs.get(runId);
|
|
149
|
+
if (entry === undefined) return false;
|
|
150
|
+
entry.session.pending.set(call.execId, call.callId);
|
|
151
|
+
entry.session.calls.set(call.callId, call);
|
|
152
|
+
this.callOwners.set(call.callId, runId);
|
|
153
|
+
return true;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Resolves one pending call id to its live Run, scoped to the caller.
|
|
158
|
+
*
|
|
159
|
+
* Returns the Run only when the id is pending *and* every scope field matches
|
|
160
|
+
* the Run that created it. A mismatch is a hard refusal, not a fallback:
|
|
161
|
+
* routing one account's tool result onto another account's Run would corrupt
|
|
162
|
+
* both conversations and leak the first account's context into the second.
|
|
163
|
+
*/
|
|
164
|
+
resolveCall(
|
|
165
|
+
callId: string,
|
|
166
|
+
scope: CursorContinuationScope,
|
|
167
|
+
): { session: CursorRunSession; call: CursorPendingToolCall } | undefined {
|
|
168
|
+
const runId = this.callOwners.get(callId);
|
|
169
|
+
if (runId === undefined) return undefined;
|
|
170
|
+
const entry = this.runs.get(runId);
|
|
171
|
+
if (entry === undefined) return undefined;
|
|
172
|
+
const { session } = entry;
|
|
173
|
+
if (
|
|
174
|
+
session.scope.tenantId !== scope.tenantId ||
|
|
175
|
+
session.scope.apiKeyId !== scope.apiKeyId ||
|
|
176
|
+
session.scope.providerId !== scope.providerId ||
|
|
177
|
+
session.scope.providerAccountId !== scope.providerAccountId
|
|
178
|
+
) {
|
|
179
|
+
return undefined;
|
|
180
|
+
}
|
|
181
|
+
const call = session.calls.get(callId);
|
|
182
|
+
if (call === undefined) return undefined;
|
|
183
|
+
return { session, call };
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/** Clears one pending call after its result has been written to the Run. */
|
|
187
|
+
clearPendingCall(runId: string, callId: string): void {
|
|
188
|
+
const entry = this.runs.get(runId);
|
|
189
|
+
if (entry === undefined) return;
|
|
190
|
+
const call = entry.session.calls.get(callId);
|
|
191
|
+
if (call !== undefined) entry.session.pending.delete(call.execId);
|
|
192
|
+
entry.session.calls.delete(callId);
|
|
193
|
+
this.callOwners.delete(callId);
|
|
194
|
+
this.touch(runId);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/** Extends one Run's idle expiry: the client answered, so the Run is live. */
|
|
198
|
+
touch(runId: string, idleTtlMs = RUN_IDLE_TTL_MS): void {
|
|
199
|
+
const entry = this.runs.get(runId);
|
|
200
|
+
if (entry === undefined) return;
|
|
201
|
+
clearTimeout(entry.expiryTimer);
|
|
202
|
+
entry.expiresAt = Date.now() + idleTtlMs;
|
|
203
|
+
entry.expiryTimer = setTimeout(() => {
|
|
204
|
+
this.terminate(runId, "Cursor Run idle-expired waiting for a tool result");
|
|
205
|
+
}, idleTtlMs);
|
|
206
|
+
entry.expiryTimer.unref?.();
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/** Records the Run's authoritative terminal usage before it is closed. */
|
|
210
|
+
recordUsage(runId: string, usage: UsageRecord): void {
|
|
211
|
+
const entry = this.runs.get(runId);
|
|
212
|
+
if (entry === undefined) return;
|
|
213
|
+
entry.session.usage = usage;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/** Records why a Run failed, so the next request reports it rather than hanging. */
|
|
217
|
+
recordFailure(runId: string, failure: GatewayError): void {
|
|
218
|
+
const entry = this.runs.get(runId);
|
|
219
|
+
if (entry === undefined) return;
|
|
220
|
+
entry.session.failure = failure;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/** Reads one live Run by id, for the frame continuation path. */
|
|
224
|
+
get(runId: string): CursorRunSession | undefined {
|
|
225
|
+
return this.runs.get(runId)?.session;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Describes one pending call by id and caller identity.
|
|
230
|
+
*
|
|
231
|
+
* The routing layer needs the owning account *before* it knows which provider
|
|
232
|
+
* a candidate belongs to, so this reads the same server-recorded scope the
|
|
233
|
+
* adapter will later re-check: tenant and API key here, provider and account
|
|
234
|
+
* in the answer. A call id from another tenant or key resolves nothing.
|
|
235
|
+
*/
|
|
236
|
+
describePendingCall(
|
|
237
|
+
callId: string,
|
|
238
|
+
scope: { readonly tenantId: string; readonly apiKeyId: string },
|
|
239
|
+
): { readonly providerId: string; readonly providerAccountId: string } | undefined {
|
|
240
|
+
const runId = this.callOwners.get(callId);
|
|
241
|
+
if (runId === undefined) return undefined;
|
|
242
|
+
const entry = this.runs.get(runId);
|
|
243
|
+
if (entry === undefined) return undefined;
|
|
244
|
+
const { session } = entry;
|
|
245
|
+
if (
|
|
246
|
+
session.scope.tenantId !== scope.tenantId ||
|
|
247
|
+
session.scope.apiKeyId !== scope.apiKeyId
|
|
248
|
+
) {
|
|
249
|
+
return undefined;
|
|
250
|
+
}
|
|
251
|
+
if (!session.calls.has(callId)) return undefined;
|
|
252
|
+
return {
|
|
253
|
+
providerId: session.scope.providerId,
|
|
254
|
+
providerAccountId: session.scope.providerAccountId,
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Takes over the borrowed lease for a Run that is already registered.
|
|
260
|
+
*
|
|
261
|
+
* Idempotent: a second transfer stores nothing, so a retry of the same
|
|
262
|
+
* continuation request cannot double-release the slot.
|
|
263
|
+
*/
|
|
264
|
+
adoptLease(runId: string, ownership: AttemptLeaseOwnership | undefined): void {
|
|
265
|
+
if (ownership === undefined) return;
|
|
266
|
+
const entry = this.runs.get(runId);
|
|
267
|
+
if (entry === undefined || entry.releaseLease !== undefined) return;
|
|
268
|
+
const release = ownership.transferToProviderSession();
|
|
269
|
+
if (release === undefined) return;
|
|
270
|
+
entry.releaseLease = release;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/** Drops every live Run. Shutdown and test seam. */
|
|
274
|
+
terminateAll(reason?: string): void {
|
|
275
|
+
for (const runId of [...this.runs.keys()]) this.terminate(runId, reason);
|
|
276
|
+
this.callOwners.clear();
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/** Process-local manager: one active Run set per gateway process. */
|
|
281
|
+
export const cursorRunSessions = new CursorRunSessionManager();
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// Cursor constants shared by the adapter, auth client, catalog, transport, and
|
|
2
|
+
// session manager.
|
|
3
|
+
//
|
|
4
|
+
// Every literal below is a Cursor endpoint or client identity the donor
|
|
5
|
+
// protocol was verified against: they are declared once so the auth flow, the
|
|
6
|
+
// unary catalog calls, and the Run stream cannot drift apart on host, path, or
|
|
7
|
+
// client id.
|
|
8
|
+
import type { WireFamily } from "../../../protocol/canonical-model";
|
|
9
|
+
|
|
10
|
+
/** Canonical bundled provider id. */
|
|
11
|
+
export const CURSOR_PROVIDER_ID = "cursor";
|
|
12
|
+
|
|
13
|
+
/** Cursor's API origin: auth, token, catalog and server-config calls. */
|
|
14
|
+
export const CURSOR_API_HOST = "api2.cursor.sh";
|
|
15
|
+
export const CURSOR_API_BASE_URL = `https://${CURSOR_API_HOST}`;
|
|
16
|
+
/** Cursor's website, where the browser login opens. */
|
|
17
|
+
export const CURSOR_WEBSITE_HOST = "cursor.com";
|
|
18
|
+
export const CURSOR_WEBSITE_URL = `https://${CURSOR_WEBSITE_HOST}`;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Production OAuth client id Cursor's IDE sends on `POST /oauth/token`
|
|
22
|
+
* (Cursor 3.17.19 `workbench.desktop.main.js`, `cursorCreds.authClientId` for
|
|
23
|
+
* `backendUrl` `https://api2.cursor.sh`). The IDE's non-production id is not
|
|
24
|
+
* used.
|
|
25
|
+
*/
|
|
26
|
+
export const CURSOR_OAUTH_CLIENT_ID = "KbZUR41cY7W6zRSdpSUJ7I7mLYBKOCmB";
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Client version sent when no local or remote Cursor build version resolves.
|
|
30
|
+
*
|
|
31
|
+
* Kept equal to `VERSION_SOURCES.cursor.fallback`: two fallbacks for one
|
|
32
|
+
* identity drifted apart (the header sent `cli-2026.07.09-a3815c0` while the
|
|
33
|
+
* badge reported `cli-2026.10.19-6bbf2c4`), so what the console showed an
|
|
34
|
+
* operator was not what the request carried. Discovery supersedes both on its
|
|
35
|
+
* first successful fetch.
|
|
36
|
+
*/
|
|
37
|
+
export const FALLBACK_CLIENT_VERSION = "cli-2026.10.19-6bbf2c4";
|
|
38
|
+
|
|
39
|
+
/** Connect-RPC paths. Run is served by the discovered agent origin, not the API host. */
|
|
40
|
+
export const RUN_PATH = "/agent.v1.AgentService/Run";
|
|
41
|
+
export const AVAILABLE_MODELS_PATH = "/aiserver.v1.AiService/AvailableModels";
|
|
42
|
+
export const SERVER_CONFIG_PATH = "/aiserver.v1.ServerConfigService/GetServerConfig";
|
|
43
|
+
|
|
44
|
+
/** Connect unary/bidi protocol headers. */
|
|
45
|
+
export const CONTENT_TYPE_CONNECT_PROTO = "application/connect+proto";
|
|
46
|
+
export const CONNECT_PROTOCOL_VERSION = "1";
|
|
47
|
+
|
|
48
|
+
/** A raw Cursor API key (as opposed to a JWT already exchanged from one). */
|
|
49
|
+
const CURSOR_API_KEY_PREFIX = "crsr_";
|
|
50
|
+
|
|
51
|
+
/** True for a raw Cursor API key, which must be exchanged before dispatch. */
|
|
52
|
+
export function isExchangeableApiKey(value: string): boolean {
|
|
53
|
+
return value.startsWith(CURSOR_API_KEY_PREFIX);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Server error code Cursor surfaces as a sign-in policy block. */
|
|
57
|
+
export const SIGN_IN_POLICY_VIOLATION = "sign_in_policy_violation";
|
|
58
|
+
|
|
59
|
+
/** Seconds before a JWT is considered expiring and worth refreshing. */
|
|
60
|
+
export const TOKEN_EXPIRY_THRESHOLD_S = 300;
|
|
61
|
+
|
|
62
|
+
/** Individual auth/unary request timeout. */
|
|
63
|
+
export const AUTH_REQUEST_TIMEOUT_MS = 5_000;
|
|
64
|
+
/** Cursor IDE aborts its session refresh after 20 s (`_performAccessTokenRefresh`). */
|
|
65
|
+
export const SESSION_REFRESH_TIMEOUT_MS = 20_000;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* How long a live Cursor Run is held open waiting for the client's next
|
|
69
|
+
* tool-result request. Matches the donor's continuation default: a tool round
|
|
70
|
+
* the client never answers must not hold an HTTP/2 stream, an account lease, or
|
|
71
|
+
* a pool slot for the life of the process.
|
|
72
|
+
*/
|
|
73
|
+
export const RUN_IDLE_TTL_MS = 10 * 60_000;
|
|
74
|
+
|
|
75
|
+
/** Chat wire is the declared default; the adapter owns the native protocol. */
|
|
76
|
+
export const CURSOR_WIRE_FAMILY: WireFamily = "chat";
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Any HTTPS subdomain of `cursor.sh` is an acceptable Run host: the region
|
|
80
|
+
* Cursor routes an account to varies (`agentn.*`, `agent.*`, `api5`, …).
|
|
81
|
+
*/
|
|
82
|
+
export function isAllowedAgentHost(hostname: string): boolean {
|
|
83
|
+
return /^([a-z0-9-]+\.)+cursor\.sh$/i.test(hostname);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Normalizes a GetServerConfig agent URL to an https origin.
|
|
88
|
+
*
|
|
89
|
+
* Returns `null` for missing, malformed, non-HTTPS, credential-bearing, or
|
|
90
|
+
* non-`*.cursor.sh` hosts: the Run stream carries the account's credential, so
|
|
91
|
+
* a host that is not a Cursor origin is a fail-closed refusal rather than
|
|
92
|
+
* something to dial anyway.
|
|
93
|
+
*/
|
|
94
|
+
export function normalizeAgentRunOrigin(raw: string | undefined): string | null {
|
|
95
|
+
if (raw === undefined || raw === null) return null;
|
|
96
|
+
const trimmed = String(raw).trim();
|
|
97
|
+
if (!trimmed) return null;
|
|
98
|
+
try {
|
|
99
|
+
const withScheme = /^https?:\/\//i.test(trimmed) ? trimmed : `https://${trimmed}`;
|
|
100
|
+
const parsed = new URL(withScheme);
|
|
101
|
+
if (parsed.protocol !== "https:") return null;
|
|
102
|
+
if (parsed.username || parsed.password) return null;
|
|
103
|
+
if (!isAllowedAgentHost(parsed.hostname)) return null;
|
|
104
|
+
return parsed.origin;
|
|
105
|
+
} catch {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
}
|