cartethyia 2.7.8 → 2.7.9
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 +0 -1
- package/README.md +29 -59
- package/dist/dashboard/assets/BannedPage-BxoG1MrL.js +1 -0
- package/dist/dashboard/assets/BannedPage-BxoG1MrL.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolDetailPage-BRWKPQPf.js → CliToolDetailPage-ixwgKk53.js} +1 -1
- package/dist/dashboard/assets/CliToolDetailPage-ixwgKk53.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolsPage-BP-Y5iHN.js → CliToolsPage-BmttNV3U.js} +1 -1
- package/dist/dashboard/assets/CliToolsPage-BmttNV3U.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-BE3qwwfC.js +1 -0
- package/dist/dashboard/assets/CombosPage-BE3qwwfC.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-CRZdmMIX.js +1 -0
- package/dist/dashboard/assets/ConsoleLogPage-CRZdmMIX.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-Dv_FJ6Er.js +1 -0
- package/dist/dashboard/assets/CustomizationPage-Dv_FJ6Er.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-CoVrw2sM.js +1 -0
- package/dist/dashboard/assets/HealthEventsModal-CoVrw2sM.js.gz +0 -0
- package/dist/dashboard/assets/{InjectSystemPromptPanel-Cv-2Ol_K.js → InjectSystemPromptPanel-BOoO8rpz.js} +2 -2
- package/dist/dashboard/assets/InjectSystemPromptPanel-BOoO8rpz.js.gz +0 -0
- package/dist/dashboard/assets/{LoginPage-bKfz_b1K.js → LoginPage-ChJuNNVN.js} +1 -1
- package/dist/dashboard/assets/LoginPage-ChJuNNVN.js.gz +0 -0
- package/dist/dashboard/assets/{ModelPicker-B-WQxx_H.js → ModelPicker-BZAJtPg1.js} +1 -1
- package/dist/dashboard/assets/ModelPicker-BZAJtPg1.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-BE40s3u5.js +1 -0
- package/dist/dashboard/assets/OverviewPage-BE40s3u5.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-sfLoQtPV.js +8 -0
- package/dist/dashboard/assets/ProviderDetailPage-sfLoQtPV.js.gz +0 -0
- package/dist/dashboard/assets/ProviderIcon-CQ6bPUf_.js +1 -0
- package/dist/dashboard/assets/ProviderIcon-CQ6bPUf_.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-DcepmPWo.js +1 -0
- package/dist/dashboard/assets/ProvidersPage-DcepmPWo.js.gz +0 -0
- package/dist/dashboard/assets/{ProxyPage-emlTuxz6.js → ProxyPage-BJ87Pp0U.js} +1 -1
- package/dist/dashboard/assets/ProxyPage-BJ87Pp0U.js.gz +0 -0
- package/dist/dashboard/assets/{QuotaPage-CMJKNYWb.js → QuotaPage-gkSyRAKa.js} +1 -1
- package/dist/dashboard/assets/QuotaPage-gkSyRAKa.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-C5HPWqEv.js +1 -0
- package/dist/dashboard/assets/SettingsPage-C5HPWqEv.js.gz +0 -0
- package/dist/dashboard/assets/{SetupPage-CUZrKs9r.js → SetupPage-CFNcATJJ.js} +1 -1
- package/dist/dashboard/assets/SetupPage-CFNcATJJ.js.gz +0 -0
- package/dist/dashboard/assets/{StudioPage-jWmUdDpy.js → StudioPage-YoD4tY5l.js} +1 -1
- package/dist/dashboard/assets/StudioPage-YoD4tY5l.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-DxjaAhb_.js +56 -0
- package/dist/dashboard/assets/UsagePage-DxjaAhb_.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-BTlkq_Uk.js +1 -0
- package/dist/dashboard/assets/api-keys-BTlkq_Uk.js.gz +0 -0
- package/dist/dashboard/assets/app-BX2nnKqs.css +2 -0
- package/dist/dashboard/assets/app-BX2nnKqs.css.gz +0 -0
- package/dist/dashboard/assets/assert-CndthXFQ.js +1 -0
- package/dist/dashboard/assets/assert-CndthXFQ.js.gz +0 -0
- package/dist/dashboard/assets/{badge-DyI_mJfi.js → badge-DdbT_7Am.js} +1 -1
- package/dist/dashboard/assets/badge-DdbT_7Am.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-CsGN-nbm.js} +1 -1
- package/dist/dashboard/assets/banner-CsGN-nbm.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-mgZ_TLLZ.js} +1 -1
- package/dist/dashboard/assets/card-mgZ_TLLZ.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-A1-v8-03.js +1 -0
- package/dist/dashboard/assets/cli-tools-A1-v8-03.js.gz +0 -0
- package/dist/dashboard/assets/{clipboard-button-ByjCk0o9.js → clipboard-button-CJ4Zty89.js} +1 -1
- package/dist/dashboard/assets/clipboard-button-CJ4Zty89.js.gz +0 -0
- package/dist/dashboard/assets/{dialog-BZhOlfz-.js → dialog-B5L2jPQ_.js} +1 -1
- package/dist/dashboard/assets/dialog-B5L2jPQ_.js.gz +0 -0
- package/dist/dashboard/assets/{drawer-BADqIRYP.js → drawer-DkjUouAj.js} +1 -1
- package/dist/dashboard/assets/drawer-DkjUouAj.js.gz +0 -0
- package/dist/dashboard/assets/{entry-COaC-irN.js → entry-B-LVLV6o.js} +1 -1
- package/dist/dashboard/assets/entry-B-LVLV6o.js.gz +0 -0
- package/dist/dashboard/assets/entry-CAhdYl3B.js +1 -0
- package/dist/dashboard/assets/entry-CAhdYl3B.js.gz +0 -0
- package/dist/dashboard/assets/entry-D2xD0Tmd.js +4 -0
- package/dist/dashboard/assets/entry-D2xD0Tmd.js.gz +0 -0
- package/dist/dashboard/assets/{formatters-DcHJyRiu.js → formatters-CrsdLVsn.js} +1 -1
- package/dist/dashboard/assets/formatters-CrsdLVsn.js.gz +0 -0
- package/dist/dashboard/assets/{index-CgKmFngv.js → index-BU64Lqvp.js} +2 -2
- package/dist/dashboard/assets/index-BU64Lqvp.js.gz +0 -0
- package/dist/dashboard/assets/{inline-B2BirKry.js → inline-B2aDLyyg.js} +1 -1
- package/dist/dashboard/assets/inline-B2aDLyyg.js.gz +0 -0
- package/dist/dashboard/assets/{input-D-qV9dKY.js → input-BCVkdR9d.js} +1 -1
- package/dist/dashboard/assets/input-BCVkdR9d.js.gz +0 -0
- package/dist/dashboard/assets/{layout-B7tVWhtV.js → layout-DNcAdMK-.js} +1 -1
- package/dist/dashboard/assets/layout-DNcAdMK-.js.gz +0 -0
- package/dist/dashboard/assets/{list-row-CtkGE3bF.js → list-row-DgrIH0hw.js} +1 -1
- package/dist/dashboard/assets/list-row-DgrIH0hw.js.gz +0 -0
- package/dist/dashboard/assets/{live-DGizF06-.js → live-Cae01iu8.js} +1 -1
- package/dist/dashboard/assets/live-Cae01iu8.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-CRib7H_2.js} +1 -1
- package/dist/dashboard/assets/network-CRib7H_2.js.gz +0 -0
- package/dist/dashboard/assets/{numbers-BnAd22a_.js → numbers-BKQE8Xpz.js} +1 -1
- package/dist/dashboard/assets/numbers-BKQE8Xpz.js.gz +0 -0
- package/dist/dashboard/assets/{pagination-BAywyMzS.js → pagination-ecPvG_8g.js} +1 -1
- package/dist/dashboard/assets/pagination-ecPvG_8g.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/{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/routing-Ckm1UXuC.js +1 -0
- package/dist/dashboard/assets/routing-Ckm1UXuC.js.gz +0 -0
- package/dist/dashboard/assets/{select-BCOcv8WK.js → select-ChoFWyKz.js} +1 -1
- package/dist/dashboard/assets/select-ChoFWyKz.js.gz +0 -0
- package/dist/dashboard/assets/settings-CKjFPlKW.js +1 -0
- package/dist/dashboard/assets/settings-CKjFPlKW.js.gz +0 -0
- package/dist/dashboard/assets/{stack-ByKt3Q1g.js → stack-DWCwU3fh.js} +1 -1
- package/dist/dashboard/assets/stack-DWCwU3fh.js.gz +0 -0
- package/dist/dashboard/assets/{state-DXbGTx7N.js → state-Cg3VL5J_.js} +1 -1
- package/dist/dashboard/assets/state-Cg3VL5J_.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-Db70BMix.js} +1 -1
- package/dist/dashboard/assets/switch-Db70BMix.js.gz +0 -0
- package/dist/dashboard/assets/{useMutation-CbCP4w1o.js → useMutation-BqdE0LuM.js} +1 -1
- package/dist/dashboard/assets/useMutation-BqdE0LuM.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 +57 -55
- 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/lite-sqlite3/0044_add_models_warning_metadata.sql +11 -0
- package/migrations/lite-sqlite3/0045_migrate_workbuddy_to_codebuddy.sql +156 -0
- package/package.json +1 -1
- package/src/boot/dependencies.ts +11 -3
- package/src/config/cooldowns.ts +1 -1
- package/src/config/spec.ts +0 -6
- package/src/console/api-keys/routes.ts +11 -4
- package/src/console/console-router.ts +7 -0
- package/src/console/dashboard-assets.ts +5 -5
- package/src/console/domain-registration.ts +27 -0
- package/src/console/ip-bans/routes.ts +99 -0
- package/src/console/providers/catalog/catalog-projections.ts +5 -2
- package/src/console/providers/catalog/contracts.ts +123 -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 +64 -4
- package/src/console/providers/catalog/store-helpers.ts +30 -1
- package/src/console/providers/catalog/store.ts +243 -3
- package/src/console/quota/account-quota-global.ts +89 -1
- package/src/console/quota/native-identity.ts +2 -0
- package/src/console/settings/contracts.ts +18 -0
- package/src/console/settings/store.ts +32 -0
- package/src/console/system-prompt/contracts.ts +0 -1
- package/src/main.ts +1 -0
- package/src/observability/event-query.ts +18 -4
- package/src/persistence/dialect.ts +12 -0
- package/src/persistence/schema.ts +20 -2
- package/src/protocol/dsml.ts +1 -1
- package/src/protocol/gateway-error.ts +1 -0
- package/src/protocol/reasoning.ts +1 -1
- package/src/protocol/request/chat.ts +4 -4
- package/src/protocol/request/messages.ts +1 -1
- package/src/protocol/response/gemini.ts +6 -1
- package/src/protocol/sse-decoder.ts +25 -8
- package/src/protocol/stream-error-frames.ts +13 -3
- 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 +7 -5
- package/src/providers/authentication/oauth-refresh-service.ts +149 -36
- package/src/providers/default-registry.ts +68 -3
- package/src/providers/discovery/discovery-types.ts +12 -0
- package/src/providers/discovery/probe-phases.ts +61 -30
- package/src/providers/discovery/probing-service.ts +279 -164
- package/src/providers/integrations/antigravity/antigravity-protocol.ts +117 -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 +18 -18
- 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 +70 -0
- 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 +4 -41
- package/src/providers/integrations/buddy/codebuddy/cn-catalog.ts +2 -1
- package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +20 -1
- package/src/providers/integrations/buddy/codebuddy/provider.ts +2 -2
- package/src/providers/integrations/buddy/codebuddy/shared.ts +6 -10
- package/src/providers/integrations/cursor/cursor-catalog.ts +2 -0
- package/src/providers/integrations/cursor/cursor-exec.ts +738 -0
- package/src/providers/integrations/cursor/cursor-http2.ts +2 -0
- package/src/providers/integrations/cursor/cursor-request.ts +9 -8
- package/src/providers/integrations/cursor/cursor-shared.ts +19 -1
- package/src/providers/integrations/cursor/cursor.ts +50 -30
- 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 +584 -0
- package/src/providers/integrations/devin/protocol/framing.ts +124 -0
- package/src/providers/integrations/factory/factory.ts +2 -2
- 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/hermes/hermes-oauth.ts +94 -0
- package/src/providers/integrations/hermes.ts +4 -12
- package/src/providers/integrations/opencode/fingerprint.ts +1 -1
- package/src/providers/integrations/perch/perch-catalog.ts +105 -0
- package/src/providers/integrations/perch/perch-oauth.ts +170 -0
- package/src/providers/integrations/perch/perch-protocol.ts +211 -0
- package/src/providers/integrations/perch/perch-quota.ts +137 -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 +315 -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 +1 -1
- package/src/providers/integrations/qoder/qoder-adapter.ts +89 -28
- package/src/providers/integrations/qoder/qoder-cache.ts +32 -0
- package/src/providers/integrations/qoder/qoder-catalog.ts +6 -1
- package/src/providers/integrations/qoder/qoder-checkin.ts +2 -2
- package/src/providers/integrations/qoder/qoder-grpc.ts +210 -6
- package/src/providers/integrations/qoder/qoder-ide.ts +5 -1
- 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 -6
- 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 +3 -6
- package/src/providers/integrations/trae/trae-quota.ts +103 -21
- package/src/providers/integrations/trae/trae-realm.ts +36 -15
- package/src/providers/integrations/trae/trae.ts +97 -7
- package/src/providers/operations/account-error-classification.ts +66 -1
- package/src/providers/operations/account-health-service.ts +192 -26
- package/src/providers/operations/account-refresh-status.ts +284 -0
- package/src/providers/operations/account-tier.ts +67 -0
- package/src/providers/operations/client-versions.ts +37 -99
- package/src/providers/operations/cooldown-rules.ts +61 -0
- package/src/providers/operations/provider-catalog-seeder.ts +4 -0
- package/src/providers/provider-contracts.ts +29 -0
- package/src/providers/provider-metadata.ts +59 -4
- package/src/providers/provider-model-definition.ts +36 -0
- package/src/providers/quota/refresh.ts +21 -0
- package/src/security/abuse.ts +71 -0
- package/src/transport/dispatch/proxy-request.ts +1 -0
- package/src/transport/dispatch/streaming/stream.ts +1 -0
- package/src/transport/dispatch/upstream.ts +4 -1
- package/src/transport/failure-policy.ts +113 -7
- package/src/transport/routing/router.ts +25 -1
- package/src/transport/surface/messages/adapter.ts +2 -1
- package/src/transport/surface/responses/encode.ts +12 -1
- 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.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 +0 -1
- 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/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/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/dist/dashboard/assets/{app-CTxoqyYB.js → app-B7kIWFm5.js} +0 -0
- /package/dist/dashboard/assets/{app-CTxoqyYB.js.gz → app-B7kIWFm5.js.gz} +0 -0
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Disk cache + majority vote for Qoder native machine identities.
|
|
3
|
+
*
|
|
4
|
+
* Adopted from the donor reference implementation (`qoder_accounts.py`
|
|
5
|
+
* §native_machine_identity):
|
|
6
|
+
*
|
|
7
|
+
* - **Disk cache** (`machine_identity.json` per data dir): the runtime-info
|
|
8
|
+
* bridge outputs a machine-level identity derived from a seed file
|
|
9
|
+
* (`~/.config/.locale_cfg`). Re-running the bridge frequently returns the
|
|
10
|
+
* same identity, but container rebuilds/upgrades would discard the seed —
|
|
11
|
+
* a disk cache keeps the device identity stable across restarts. Cache
|
|
12
|
+
* wins: when a valid cache entry exists for the realm, the bridge is not
|
|
13
|
+
* re-run.
|
|
14
|
+
* - **Majority vote**: the bridge's VM classification jitters (1.5–10% of
|
|
15
|
+
* runs flip between branches). A single sample can permanently fix a user
|
|
16
|
+
* to the minority branch, so the first uncached acquisition samples the
|
|
17
|
+
* bridge 3 times and takes the majority (extending to 5 on disagreement).
|
|
18
|
+
* - **Expired-cache fallback**: when the bridge fails (missing glibc
|
|
19
|
+
* loader, removed component), fall back to the cached identity even if
|
|
20
|
+
* expired — a real identity is better than a generated one.
|
|
21
|
+
*
|
|
22
|
+
* The cache is per-realm (intl vs cn use different env codes and produce
|
|
23
|
+
* different identities). It is machine-global, not per-account: the seed is
|
|
24
|
+
* machine-scoped, and per-account isolation stays in the database
|
|
25
|
+
* (`provider_accounts.native_identity`).
|
|
26
|
+
*/
|
|
27
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
28
|
+
import { join } from "node:path";
|
|
29
|
+
import { resolveDataDir } from "../../../persistence/db-mode";
|
|
30
|
+
import { log } from "../../../observability/logger";
|
|
31
|
+
|
|
32
|
+
/** Cache record shape, one per realm. */
|
|
33
|
+
export interface MachineIdentityCacheEntry {
|
|
34
|
+
readonly machineToken: string;
|
|
35
|
+
readonly machineType: string;
|
|
36
|
+
readonly machineCode: string;
|
|
37
|
+
readonly isVm: boolean;
|
|
38
|
+
readonly source: string;
|
|
39
|
+
/** The env code the identity was minted under (`3` intl desktop, `0` cn). */
|
|
40
|
+
readonly environment: string;
|
|
41
|
+
/** Unix seconds when this entry was written. */
|
|
42
|
+
readonly cachedAt: number;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Written cache document. */
|
|
46
|
+
interface MachineIdentityCacheDoc {
|
|
47
|
+
readonly version: 1;
|
|
48
|
+
readonly realm: Record<string, MachineIdentityCacheEntry | undefined>;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const CACHE_VERSION = 1 as const;
|
|
52
|
+
const NATIVE_IDENTITY_TTL_MS = 30 * 60 * 1000; // 1800s, matches the donor
|
|
53
|
+
const VOTE_EXTEND_ROUNDS = 2;
|
|
54
|
+
|
|
55
|
+
/** Path to the machine-identity cache file. */
|
|
56
|
+
export function machineIdentityCachePath(env: NodeJS.ProcessEnv = process.env): string {
|
|
57
|
+
return join(resolveDataDir(env), "machine_identity.json");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function readCacheDoc(path: string): MachineIdentityCacheDoc {
|
|
61
|
+
try {
|
|
62
|
+
if (!existsSync(path)) return { version: CACHE_VERSION, realm: {} };
|
|
63
|
+
const raw = JSON.parse(readFileSync(path, "utf8")) as Partial<MachineIdentityCacheDoc>;
|
|
64
|
+
if (raw.version !== CACHE_VERSION || typeof raw.realm !== "object" || raw.realm === null) {
|
|
65
|
+
return { version: CACHE_VERSION, realm: {} };
|
|
66
|
+
}
|
|
67
|
+
return { version: CACHE_VERSION, realm: raw.realm as MachineIdentityCacheDoc["realm"] };
|
|
68
|
+
} catch {
|
|
69
|
+
return { version: CACHE_VERSION, realm: {} };
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function writeCacheDoc(path: string, doc: MachineIdentityCacheDoc): void {
|
|
74
|
+
try {
|
|
75
|
+
mkdirSync(join(path, ".."), { recursive: true });
|
|
76
|
+
const tmp = `${path}.tmp`;
|
|
77
|
+
writeFileSync(tmp, JSON.stringify(doc, null, 2), { encoding: "utf8", mode: 0o600 });
|
|
78
|
+
// Atomic replace so a crash never leaves a half-written cache.
|
|
79
|
+
renameSync(tmp, path);
|
|
80
|
+
} catch (error) {
|
|
81
|
+
log.warn("[qoder] machine identity cache write failed", error as Error);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function entryExpired(entry: MachineIdentityCacheEntry, now: number): boolean {
|
|
86
|
+
return now - entry.cachedAt >= NATIVE_IDENTITY_TTL_MS;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** Reads the cached identity for a realm, or `null` when absent/expired. */
|
|
90
|
+
export function readMachineIdentityCache(realm: string, env: NodeJS.ProcessEnv = process.env): MachineIdentityCacheEntry | null {
|
|
91
|
+
const doc = readCacheDoc(machineIdentityCachePath(env));
|
|
92
|
+
const entry = doc.realm[realm];
|
|
93
|
+
if (!entry) return null;
|
|
94
|
+
const now = Date.now();
|
|
95
|
+
if (entryExpired(entry, now)) return null;
|
|
96
|
+
return entry;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** Reads the cached identity for a realm, permitting an expired entry. */
|
|
100
|
+
export function readMachineIdentityCacheEvenExpired(realm: string, env: NodeJS.ProcessEnv = process.env): MachineIdentityCacheEntry | null {
|
|
101
|
+
const doc = readCacheDoc(machineIdentityCachePath(env));
|
|
102
|
+
const entry = doc.realm[realm];
|
|
103
|
+
return entry ?? null;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** Writes the identity for a realm into the disk cache. */
|
|
107
|
+
export function writeMachineIdentityCache(realm: string, entry: Omit<MachineIdentityCacheEntry, "cachedAt">, env: NodeJS.ProcessEnv = process.env): void {
|
|
108
|
+
const path = machineIdentityCachePath(env);
|
|
109
|
+
const doc = readCacheDoc(path);
|
|
110
|
+
doc.realm[realm] = { ...entry, cachedAt: Date.now() };
|
|
111
|
+
writeCacheDoc(path, doc);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Samples a native identity from the bridge, taking a majority vote to
|
|
116
|
+
* stabilize the VM-classification jitter. `sample` runs the bridge once
|
|
117
|
+
* (with the account id); it is called 3 times and, on disagreement, extended
|
|
118
|
+
* to 5. Returns the majority identity, or `null` when every sample failed.
|
|
119
|
+
*/
|
|
120
|
+
export function sampleIdentityWithVote(
|
|
121
|
+
sample: (accountId: string) => {
|
|
122
|
+
identity: { machineToken: string; machineType: string; machineCode: string; isVm: boolean; source: "runtime-info" | "generated" | "os" };
|
|
123
|
+
seed: string;
|
|
124
|
+
} | null,
|
|
125
|
+
accountId: string,
|
|
126
|
+
): {
|
|
127
|
+
identity: { machineToken: string; machineType: string; machineCode: string; isVm: boolean; source: "runtime-info" | "generated" | "os" };
|
|
128
|
+
seed: string;
|
|
129
|
+
} | null {
|
|
130
|
+
const take = (count: number): Array<NonNullable<ReturnType<typeof sample>>> => {
|
|
131
|
+
const out: Array<NonNullable<ReturnType<typeof sample>>> = [];
|
|
132
|
+
for (let i = 0; i < count; i += 1) {
|
|
133
|
+
const s = sample(accountId);
|
|
134
|
+
if (s) out.push(s);
|
|
135
|
+
}
|
|
136
|
+
return out;
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
// Sample progressively and abort as soon as two consecutive samples show a
|
|
140
|
+
// *different* machine token: the bridge is either a deterministic fake
|
|
141
|
+
// minter or its seed changed between runs, so voting has nothing to
|
|
142
|
+
// stabilize. This keeps the per-allocation bridge cost at 1-2 samples for
|
|
143
|
+
// unstable identities instead of always paying the full vote.
|
|
144
|
+
const samples: Array<NonNullable<ReturnType<typeof sample>>> = [];
|
|
145
|
+
const first = take(1)[0];
|
|
146
|
+
if (!first) return null;
|
|
147
|
+
samples.push(first);
|
|
148
|
+
const second = take(1)[0];
|
|
149
|
+
if (!second) return first;
|
|
150
|
+
samples.push(second);
|
|
151
|
+
if (second.identity.machineToken !== first.identity.machineToken) return first;
|
|
152
|
+
const third = take(1)[0];
|
|
153
|
+
if (!third) return first;
|
|
154
|
+
samples.push(third);
|
|
155
|
+
if (samples.length === 0) return null;
|
|
156
|
+
|
|
157
|
+
// Vote key: the machine token alone distinguishes identities; VM branch is
|
|
158
|
+
// part of the identity but the token is the stable anchor.
|
|
159
|
+
const tally = new Map<string, Array<NonNullable<ReturnType<typeof sample>>>>();
|
|
160
|
+
for (const s of samples) {
|
|
161
|
+
const key = s.identity.machineToken;
|
|
162
|
+
const arr = tally.get(key) ?? [];
|
|
163
|
+
arr.push(s);
|
|
164
|
+
tally.set(key, arr);
|
|
165
|
+
}
|
|
166
|
+
// Every sample produced a *different* token (e.g. a deterministic fake
|
|
167
|
+
// minter, or a bridge whose seed changed each run). Voting cannot pick a
|
|
168
|
+
// majority; take the first sample, matching the donor's "no majority →
|
|
169
|
+
// use first sample" fallback.
|
|
170
|
+
if (tally.size === samples.length) return samples[0]!;
|
|
171
|
+
if (tally.size === 1) return samples[0]!;
|
|
172
|
+
|
|
173
|
+
const extended = samples.concat(take(VOTE_EXTEND_ROUNDS));
|
|
174
|
+
const tally2 = new Map<string, Array<NonNullable<ReturnType<typeof sample>>>>();
|
|
175
|
+
for (const s of extended) {
|
|
176
|
+
const key = s.identity.machineToken;
|
|
177
|
+
const arr = tally2.get(key) ?? [];
|
|
178
|
+
arr.push(s);
|
|
179
|
+
tally2.set(key, arr);
|
|
180
|
+
}
|
|
181
|
+
const topKey = [...tally2.entries()].sort((a, b) => b[1].length - a[1].length)[0];
|
|
182
|
+
if (!topKey) return samples[0]!;
|
|
183
|
+
return topKey[1][0] ?? samples[0]!;
|
|
184
|
+
}
|
|
@@ -17,10 +17,15 @@ import { and, eq, isNotNull, ne } from "drizzle-orm";
|
|
|
17
17
|
import type { CartethyiaDatabase } from "../../../persistence/db-handle";
|
|
18
18
|
import { providerAccounts, type NativeIdentityRecord } from "../../../persistence/schema";
|
|
19
19
|
import {
|
|
20
|
-
|
|
21
|
-
replayQoderNativeIdentity,
|
|
20
|
+
mintQoderOsIdentity,
|
|
22
21
|
type QoderNativeIdentity,
|
|
23
22
|
} from "./qoder-umid";
|
|
23
|
+
import {
|
|
24
|
+
readMachineIdentityCache,
|
|
25
|
+
readMachineIdentityCacheEvenExpired,
|
|
26
|
+
sampleIdentityWithVote,
|
|
27
|
+
writeMachineIdentityCache,
|
|
28
|
+
} from "./qoder-identity-cache";
|
|
24
29
|
|
|
25
30
|
/** Stateful read/write boundary for bound native identities. */
|
|
26
31
|
export interface QoderNativeIdentityStore {
|
|
@@ -91,11 +96,11 @@ function withAllocationLock<T>(work: () => Promise<T>): Promise<T> {
|
|
|
91
96
|
}
|
|
92
97
|
|
|
93
98
|
/** Identity minting injected for tests; defaults to the real bridge. */
|
|
94
|
-
export type NativeIdentityMinter = (accountId
|
|
95
|
-
export type NativeIdentityReplayer = (seed: string, accountId
|
|
99
|
+
export type NativeIdentityMinter = (accountId?: string) => { identity: QoderNativeIdentity; seed: string } | null;
|
|
100
|
+
export type NativeIdentityReplayer = (seed: string, accountId?: string) => QoderNativeIdentity | null;
|
|
96
101
|
|
|
97
|
-
const defaultMinter: NativeIdentityMinter = (accountId) =>
|
|
98
|
-
const defaultReplayer: NativeIdentityReplayer = (
|
|
102
|
+
const defaultMinter: NativeIdentityMinter = (accountId = "") => ({ identity: mintQoderOsIdentity(accountId), seed: "" });
|
|
103
|
+
const defaultReplayer: NativeIdentityReplayer = () => null;
|
|
99
104
|
|
|
100
105
|
/**
|
|
101
106
|
* Mints and binds a fresh device identity for an account: runs the bridge
|
|
@@ -104,6 +109,12 @@ const defaultReplayer: NativeIdentityReplayer = (seed, accountId) => replayQoder
|
|
|
104
109
|
*
|
|
105
110
|
* `avoidToken` optionally excludes the account's own current token so a
|
|
106
111
|
* regenerate moves to a *different* device.
|
|
112
|
+
*
|
|
113
|
+
* The disk cache (per realm) is checked first — a cached native identity is
|
|
114
|
+
* reused without re-running the bridge, so container rebuilds keep the same
|
|
115
|
+
* device. When no cache exists, a majority vote stabilizes the bridge's VM
|
|
116
|
+
* jitter. If the bridge fails entirely, the cached identity (even expired)
|
|
117
|
+
* is preferred over a generated one.
|
|
107
118
|
*/
|
|
108
119
|
export function allocateQoderNativeIdentity(
|
|
109
120
|
store: QoderNativeIdentityStore,
|
|
@@ -113,27 +124,81 @@ export function allocateQoderNativeIdentity(
|
|
|
113
124
|
readonly avoidToken?: string;
|
|
114
125
|
readonly mint?: NativeIdentityMinter;
|
|
115
126
|
readonly replayer?: NativeIdentityReplayer;
|
|
127
|
+
readonly realm?: string;
|
|
128
|
+
readonly env?: NodeJS.ProcessEnv;
|
|
116
129
|
} = {},
|
|
117
130
|
): Promise<NativeIdentityRecord | null> {
|
|
118
131
|
const mint = options.mint ?? defaultMinter;
|
|
132
|
+
const realm = options.realm ?? "intl";
|
|
133
|
+
const env = options.env ?? process.env;
|
|
119
134
|
return withAllocationLock(async () => {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
135
|
+
// 1. Disk cache first — reuse the stable device identity across restarts.
|
|
136
|
+
// But the cache is machine-global: a token already bound to another
|
|
137
|
+
// account (unique index) must not be reused, so skip the cache and
|
|
138
|
+
// mint fresh when the cached token is occupied.
|
|
139
|
+
const cached = readMachineIdentityCache(realm, env);
|
|
140
|
+
if (cached) {
|
|
141
|
+
const occupied = await store.occupied(accountId);
|
|
142
|
+
if (cached.machineToken !== options.avoidToken && !occupied.has(cached.machineToken)) {
|
|
143
|
+
const existing = await store.get(providerId, accountId);
|
|
144
|
+
if (existing && existing.machineToken === cached.machineToken) return existing;
|
|
145
|
+
const record: NativeIdentityRecord = {
|
|
146
|
+
machineToken: cached.machineToken,
|
|
147
|
+
machineType: cached.machineType,
|
|
148
|
+
machineCode: cached.machineCode,
|
|
149
|
+
source: cached.source === "generated" ? "generated" : cached.source === "os" ? "os" : "runtime-info",
|
|
150
|
+
};
|
|
151
|
+
await store.bind(providerId, accountId, record);
|
|
152
|
+
return record;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// 2. No valid cache — sample with a majority vote (stabilizes VM jitter).
|
|
157
|
+
const voted = sampleIdentityWithVote(mint, accountId);
|
|
158
|
+
if (voted) {
|
|
159
|
+
const occupied = await store.occupied(accountId);
|
|
160
|
+
for (let i = 0; i < 6; i += 1) {
|
|
161
|
+
const minted = i === 0 ? voted : mint(accountId);
|
|
162
|
+
if (!minted) return null;
|
|
163
|
+
const token = minted.identity.machineToken;
|
|
164
|
+
if (occupied.has(token)) continue; // collision (rare) → mint again
|
|
165
|
+
if (token === options.avoidToken) continue;
|
|
166
|
+
const record: NativeIdentityRecord = {
|
|
167
|
+
machineToken: token,
|
|
168
|
+
machineType: minted.identity.machineType,
|
|
169
|
+
machineCode: minted.identity.machineCode,
|
|
170
|
+
...(minted.seed ? { seed: minted.seed } : {}),
|
|
171
|
+
source: minted.identity.source,
|
|
172
|
+
};
|
|
173
|
+
await store.bind(providerId, accountId, record);
|
|
174
|
+
// Persist the bound token to the disk cache so future runs reuse it.
|
|
175
|
+
writeMachineIdentityCache(realm, {
|
|
176
|
+
machineToken: token,
|
|
177
|
+
machineType: minted.identity.machineType,
|
|
178
|
+
machineCode: minted.identity.machineCode,
|
|
179
|
+
isVm: minted.identity.isVm,
|
|
180
|
+
source: minted.identity.source,
|
|
181
|
+
environment: realm === "cn" ? "0" : "3",
|
|
182
|
+
}, env);
|
|
183
|
+
return record;
|
|
184
|
+
}
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// 3. Bridge failed entirely — fall back to the cached identity even if
|
|
189
|
+
// expired. A real identity is better than a generated one.
|
|
190
|
+
const evenExpired = readMachineIdentityCacheEvenExpired(realm, env);
|
|
191
|
+
if (evenExpired) {
|
|
127
192
|
const record: NativeIdentityRecord = {
|
|
128
|
-
machineToken:
|
|
129
|
-
machineType:
|
|
130
|
-
machineCode:
|
|
131
|
-
|
|
132
|
-
source: minted.identity.source,
|
|
193
|
+
machineToken: evenExpired.machineToken,
|
|
194
|
+
machineType: evenExpired.machineType,
|
|
195
|
+
machineCode: evenExpired.machineCode,
|
|
196
|
+
source: evenExpired.source === "generated" ? "generated" : evenExpired.source === "os" ? "os" : "runtime-info",
|
|
133
197
|
};
|
|
134
198
|
await store.bind(providerId, accountId, record);
|
|
135
199
|
return record;
|
|
136
200
|
}
|
|
201
|
+
|
|
137
202
|
return null;
|
|
138
203
|
});
|
|
139
204
|
}
|
|
@@ -74,22 +74,25 @@ export const QODER_MODELS_PATH = "/algo/api/v2/model/list?Encode=1";
|
|
|
74
74
|
*/
|
|
75
75
|
export const QODER_IDE_CHAT_PATH = "/model/v1/chat/completions";
|
|
76
76
|
|
|
77
|
-
/** The model-server host for one realm (intl: `
|
|
77
|
+
/** The model-server host for one realm (intl: `api1`, cn: gateway). */
|
|
78
78
|
export function qoderIdeChatUrl(realm: QoderRealm): string {
|
|
79
79
|
return realm === "cn"
|
|
80
80
|
? `https://gateway.qoder.com.cn${QODER_IDE_CHAT_PATH}`
|
|
81
|
-
: `https://
|
|
81
|
+
: `https://api1.qoder.sh${QODER_IDE_CHAT_PATH}`;
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
/**
|
|
85
85
|
* The gRPC model-server host for one realm.
|
|
86
86
|
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
87
|
+
* Intl default is `api1.qoder.sh` (first host from `qoderInferenceCandidates`;
|
|
88
|
+
* the old `api2-v2.qoder.sh` has been NXDOMAIN since 2026-11-07 — see
|
|
89
|
+
* `documentation/research/qoder/live/
|
|
90
|
+
* 2026-11-07-qoder-host-inference-fallback.md`). The gRPC service is no
|
|
91
|
+
* longer verified alive on any host that resolves (UNIMPLEMENTED); this host
|
|
92
|
+
* is kept as the target so probes/gRPC still have an address.
|
|
90
93
|
*/
|
|
91
94
|
export function qoderGrpcHost(realm: QoderRealm): string {
|
|
92
|
-
return realm === "cn" ? "gateway.qoder.com.cn" : "
|
|
95
|
+
return realm === "cn" ? "gateway.qoder.com.cn" : "api1.qoder.sh";
|
|
93
96
|
}
|
|
94
97
|
|
|
95
98
|
/**
|