cartethyia 2.7.4 → 2.7.6
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 +5 -0
- package/README.md +18 -6
- package/dist/dashboard/assets/BannedPage-B1N603cM.js +1 -0
- package/dist/dashboard/assets/BannedPage-B1N603cM.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-9q4_4NoK.js +3 -0
- package/dist/dashboard/assets/CliToolDetailPage-9q4_4NoK.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-DwshGtK-.js +1 -0
- package/dist/dashboard/assets/CliToolsPage-DwshGtK-.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-D762MIkp.js +1 -0
- package/dist/dashboard/assets/CombosPage-D762MIkp.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-KRYjHZsX.js +1 -0
- package/dist/dashboard/assets/ConsoleLogPage-KRYjHZsX.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-DXsxk5uM.js +1 -0
- package/dist/dashboard/assets/CustomizationPage-DXsxk5uM.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-BEjAjD4F.js +1 -0
- package/dist/dashboard/assets/HealthEventsModal-BEjAjD4F.js.gz +0 -0
- package/dist/dashboard/assets/InjectSystemPromptPanel-d5v3K_Yc.js +899 -0
- package/dist/dashboard/assets/InjectSystemPromptPanel-d5v3K_Yc.js.gz +0 -0
- package/dist/dashboard/assets/LoginPage-Ccv4tjNS.js +1 -0
- package/dist/dashboard/assets/LoginPage-Ccv4tjNS.js.gz +0 -0
- package/dist/dashboard/assets/{ModelPicker-BMS2t8BA.js → ModelPicker-C6WlpU5E.js} +1 -1
- package/dist/dashboard/assets/ModelPicker-C6WlpU5E.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-DN9fYNWA.js +1 -0
- package/dist/dashboard/assets/OverviewPage-DN9fYNWA.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-BY0ieUgz.js +5 -0
- package/dist/dashboard/assets/ProviderDetailPage-BY0ieUgz.js.gz +0 -0
- package/dist/dashboard/assets/ProviderIcon-jjqXJDA3.js +1 -0
- package/dist/dashboard/assets/ProviderIcon-jjqXJDA3.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-DNsbfea2.js +1 -0
- package/dist/dashboard/assets/ProvidersPage-DNsbfea2.js.gz +0 -0
- package/dist/dashboard/assets/{ProxyPage-lsrx7NYg.js → ProxyPage-DxjvUzSD.js} +1 -1
- package/dist/dashboard/assets/ProxyPage-DxjvUzSD.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-OaHScjpX.js +1 -0
- package/dist/dashboard/assets/QuotaPage-OaHScjpX.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-BW4AKj2H.js +1 -0
- package/dist/dashboard/assets/SettingsPage-BW4AKj2H.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-44BZrxFC.js +1 -0
- package/dist/dashboard/assets/SetupPage-44BZrxFC.js.gz +0 -0
- package/dist/dashboard/assets/{StudioPage-Cq5tW7hW.js → StudioPage-DRPavCdU.js} +4 -4
- package/dist/dashboard/assets/StudioPage-DRPavCdU.js.gz +0 -0
- package/dist/dashboard/assets/ToolIcon-CfeLA-Z_.js +1 -0
- package/dist/dashboard/assets/ToolIcon-CfeLA-Z_.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-B7M7LvMM.js +56 -0
- package/dist/dashboard/assets/UsagePage-B7M7LvMM.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-KvX83mRe.js +1 -0
- package/dist/dashboard/assets/api-keys-KvX83mRe.js.gz +0 -0
- package/dist/dashboard/assets/app-DRnQLhsc.js +9 -0
- package/dist/dashboard/assets/app-DRnQLhsc.js.gz +0 -0
- package/dist/dashboard/assets/app-mweRcsKp.css +2 -0
- package/dist/dashboard/assets/app-mweRcsKp.css.gz +0 -0
- package/dist/dashboard/assets/assert-CidQVoNo.js +1 -0
- package/dist/dashboard/assets/assert-CidQVoNo.js.gz +0 -0
- package/dist/dashboard/assets/{badge-D9CS6dZk.js → badge-BaX2GTrn.js} +1 -1
- package/dist/dashboard/assets/badge-BaX2GTrn.js.gz +0 -0
- package/dist/dashboard/assets/{banner-DympBNq4.js → banner-DFH4Bkte.js} +1 -1
- package/dist/dashboard/assets/banner-DFH4Bkte.js.gz +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/{card-ibRWU_uT.js → card-CxDw0lK6.js} +1 -1
- package/dist/dashboard/assets/card-CxDw0lK6.js.gz +0 -0
- package/dist/dashboard/assets/chevron-left-Bf6CaTSJ.js +1 -0
- package/dist/dashboard/assets/chevron-left-Bf6CaTSJ.js.gz +0 -0
- package/dist/dashboard/assets/circle-question-mark-Cz4un8sH.js +1 -0
- package/dist/dashboard/assets/circle-question-mark-Cz4un8sH.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-Bwv5-zGZ.js +1 -0
- package/dist/dashboard/assets/cli-tools-Bwv5-zGZ.js.gz +0 -0
- package/dist/dashboard/assets/{clipboard-button-DJm-9pz7.js → clipboard-button-DfS1ntiq.js} +1 -1
- package/dist/dashboard/assets/clipboard-button-DfS1ntiq.js.gz +0 -0
- package/dist/dashboard/assets/dialog-BK-NRr5u.js +1 -0
- package/dist/dashboard/assets/dialog-BK-NRr5u.js.gz +0 -0
- package/dist/dashboard/assets/{drawer-CqGYeOrd.js → drawer-QqPul6sC.js} +1 -1
- package/dist/dashboard/assets/drawer-QqPul6sC.js.gz +0 -0
- package/dist/dashboard/assets/entry-BMlYJVFj.js +1 -0
- package/dist/dashboard/assets/entry-BMlYJVFj.js.gz +0 -0
- package/dist/dashboard/assets/entry-D6WvojeD.js +4 -0
- package/dist/dashboard/assets/entry-D6WvojeD.js.gz +0 -0
- package/dist/dashboard/assets/entry-Dmx7gBiN.js +1 -0
- package/dist/dashboard/assets/entry-Dmx7gBiN.js.gz +0 -0
- package/dist/dashboard/assets/{formatters-D-MTJxMr.js → formatters-u7JPB5BX.js} +1 -1
- package/dist/dashboard/assets/formatters-u7JPB5BX.js.gz +0 -0
- package/dist/dashboard/assets/house-h9AZlJuT.js +1 -0
- package/dist/dashboard/assets/house-h9AZlJuT.js.gz +0 -0
- package/dist/dashboard/assets/{index-DBNPOfhV.js → index-Ko4dLRnV.js} +2 -2
- package/dist/dashboard/assets/index-Ko4dLRnV.js.gz +0 -0
- package/dist/dashboard/assets/{inline-BT0zntEr.js → inline-CHJQwxLa.js} +1 -1
- package/dist/dashboard/assets/inline-CHJQwxLa.js.gz +0 -0
- package/dist/dashboard/assets/{input-Da2ZViWg.js → input-BlmlizVV.js} +1 -1
- package/dist/dashboard/assets/input-BlmlizVV.js.gz +0 -0
- package/dist/dashboard/assets/{layout-BXNeLw6M.js → layout-Bz93I-yE.js} +1 -1
- package/dist/dashboard/assets/layout-Bz93I-yE.js.gz +0 -0
- package/dist/dashboard/assets/{list-row-BycOrrIV.js → list-row-Ml16KCfu.js} +1 -1
- package/dist/dashboard/assets/list-row-Ml16KCfu.js.gz +0 -0
- package/dist/dashboard/assets/live-7_QpnYGu.js +1 -0
- package/dist/dashboard/assets/live-7_QpnYGu.js.gz +0 -0
- package/dist/dashboard/assets/{mutation-Rr0TIvcj.js → mutation-GU7XdEjz.js} +1 -1
- package/dist/dashboard/assets/mutation-GU7XdEjz.js.gz +0 -0
- package/dist/dashboard/assets/network-CuMDaTzT.js +1 -0
- package/dist/dashboard/assets/network-CuMDaTzT.js.gz +0 -0
- package/dist/dashboard/assets/numbers-CoqpaDMx.js +2 -0
- package/dist/dashboard/assets/numbers-CoqpaDMx.js.gz +0 -0
- package/dist/dashboard/assets/pagination-B5aOoweZ.js +1 -0
- package/dist/dashboard/assets/pagination-B5aOoweZ.js.gz +0 -0
- package/dist/dashboard/assets/providers/zai.webp +0 -0
- package/dist/dashboard/assets/providers/zcode.webp +0 -0
- package/dist/dashboard/assets/{query-keys-BloKtaXJ.js → query-keys-YSoQOUh6.js} +1 -1
- package/dist/dashboard/assets/{query-keys-BloKtaXJ.js.gz → query-keys-YSoQOUh6.js.gz} +0 -0
- package/dist/dashboard/assets/quota-DJ1QlAOq.js +1 -0
- package/dist/dashboard/assets/quota-DJ1QlAOq.js.gz +0 -0
- package/dist/dashboard/assets/routing-fnCsxgNO.js +1 -0
- package/dist/dashboard/assets/routing-fnCsxgNO.js.gz +0 -0
- package/dist/dashboard/assets/{select-BIYIBkMU.js → select-BHqpd-bg.js} +2 -2
- package/dist/dashboard/assets/select-BHqpd-bg.js.gz +0 -0
- package/dist/dashboard/assets/settings-BxslsErn.js +1 -0
- package/dist/dashboard/assets/settings-BxslsErn.js.gz +0 -0
- package/dist/dashboard/assets/shield-BMQNxORh.js +1 -0
- package/dist/dashboard/assets/shield-BMQNxORh.js.gz +0 -0
- package/dist/dashboard/assets/{stack-DfgnFDWY.js → stack-j7cXjgYX.js} +1 -1
- package/dist/dashboard/assets/stack-j7cXjgYX.js.gz +0 -0
- package/dist/dashboard/assets/{state-CkfdYWel.js → state-DHmEnLa2.js} +1 -1
- package/dist/dashboard/assets/state-DHmEnLa2.js.gz +0 -0
- package/dist/dashboard/assets/{switch-SYm237HG.js → switch-DmZcyTIC.js} +1 -1
- package/dist/dashboard/assets/switch-DmZcyTIC.js.gz +0 -0
- package/dist/dashboard/assets/{useMutation-BQqCRNIi.js → useMutation-CbCP4w1o.js} +1 -1
- 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/index.html +2 -2
- package/dist/dashboard/index.html.gz +0 -0
- package/dist/dashboard/precompressed-assets.json +60 -59
- package/migrations/full-postgres/0036_system_prompt_presets_refs.sql +10 -0
- package/migrations/full-postgres/0037_share_concurrency_scope.sql +3 -0
- package/migrations/full-postgres/0038_add_accounts_quota_snapshot.sql +7 -0
- package/migrations/full-postgres/0039_add_telemetry_provider_model_indexes.sql +13 -0
- package/migrations/full-postgres/0040_add_models_dialect.sql +3 -0
- package/migrations/full-postgres/0041_add_daily_checkin_ledger_account_fk.sql +7 -0
- package/migrations/full-postgres/0042_add_telemetry_degenerate_stop.sql +14 -0
- package/migrations/lite-sqlite3/0036_system_prompt_presets_refs.sql +14 -0
- package/migrations/lite-sqlite3/0037_share_concurrency_scope.sql +3 -0
- package/migrations/lite-sqlite3/0038_add_accounts_quota_snapshot.sql +4 -0
- package/migrations/lite-sqlite3/0039_add_telemetry_provider_model_indexes.sql +6 -0
- package/migrations/lite-sqlite3/0040_add_models_dialect.sql +3 -0
- package/migrations/lite-sqlite3/0041_add_daily_checkin_ledger_account_fk.sql +26 -0
- package/migrations/lite-sqlite3/0042_add_telemetry_degenerate_stop.sql +12 -0
- package/package.json +4 -6
- package/scripts/cli/update.ts +15 -41
- package/src/boot/app.ts +58 -2
- package/src/boot/dependencies.ts +794 -732
- package/src/boot/lifecycle.ts +11 -12
- package/src/config/cooldowns.ts +34 -55
- package/src/config/network.ts +1 -1
- package/src/config/package-paths.ts +1 -1
- package/src/config/providers.ts +19 -14
- package/src/config/resources.ts +0 -5
- package/src/config/runtime.ts +2 -5
- package/src/config/spec.ts +33 -6
- package/src/config/usage.ts +27 -0
- package/src/console/api-keys/ban-constants.ts +38 -0
- package/src/console/api-keys/contracts.ts +71 -62
- package/src/console/api-keys/routes.ts +56 -24
- package/src/console/auth/access.ts +4 -4
- package/src/console/auth/account-reset.ts +1 -1
- package/src/console/auth/audit-recorder.ts +1 -1
- package/src/console/auth/lockout.ts +7 -3
- package/src/console/auth/row-coercion.ts +57 -12
- package/src/console/auth/session-resolver.ts +1 -1
- package/src/console/auth/session-service.ts +8 -2
- package/src/console/auth/session.ts +37 -31
- package/src/console/auth/setup-service.ts +4 -3
- package/src/console/auth/user-store.ts +1 -1
- package/src/console/backup/9router-map.ts +0 -3
- package/src/console/backup/contracts.ts +9 -9
- package/src/console/backup/export-endpoint.ts +5 -6
- package/src/console/backup/nine-router.ts +1 -7
- package/src/console/backup/routes.ts +29 -33
- package/src/console/backup/service.ts +468 -468
- package/src/console/backup/store.ts +47 -29
- package/src/console/backup/validate.ts +11 -1
- package/src/console/cli-tools/contracts.ts +43 -299
- package/src/console/cli-tools/fs-ops.ts +29 -0
- package/src/console/cli-tools/injectors/claude.ts +3 -3
- package/src/console/cli-tools/injectors/codex.ts +181 -181
- package/src/console/cli-tools/injectors/driver.ts +150 -247
- package/src/console/cli-tools/injectors/kilo.ts +146 -21
- package/src/console/cli-tools/injectors/opencode.ts +176 -153
- package/src/console/cli-tools/routes.ts +7 -1
- package/src/console/cli-tools/service.ts +8 -7
- package/src/console/cli-tools/store.ts +2 -2
- package/src/console/console-router.ts +32 -0
- package/src/console/dashboard-assets.ts +9 -9
- package/src/console/domain-registration.ts +16 -2
- package/src/console/inferhub/client.ts +0 -7
- package/src/console/inferhub/key-store.ts +1 -1
- package/src/console/inferhub/normalize.ts +2 -2
- package/src/console/inferhub/routes.ts +1 -1
- package/src/console/inferhub/types.ts +1 -1
- package/src/console/observability/contracts.ts +7 -1
- package/src/console/observability/live.ts +31 -18
- package/src/console/observability/logs.ts +1 -1
- package/src/console/observability/sse.ts +62 -8
- package/src/console/observability/store.ts +23 -4
- package/src/console/providers/catalog/catalog-projections.ts +1 -1
- package/src/console/providers/catalog/contracts.ts +39 -0
- package/src/console/providers/catalog/model-operations.ts +1 -1
- package/src/console/providers/catalog/provider-operations.ts +95 -17
- package/src/console/providers/catalog/public-model-store.ts +0 -0
- package/src/console/providers/catalog/routes.ts +27 -3
- package/src/console/providers/catalog/store.ts +147 -8
- package/src/console/providers/detail/routes.ts +1 -1
- package/src/console/providers/oauth/callback-listener.ts +100 -18
- package/src/console/providers/oauth/routes.ts +92 -13
- package/src/console/quota/account-quota-global.ts +41 -3
- package/src/console/quota/account-quota-shared.ts +10 -3
- package/src/console/quota/account-quota-tenant.ts +259 -66
- package/src/console/quota/daily-growth-job.ts +308 -0
- package/src/console/quota/native-identity.ts +2 -2
- package/src/console/quota/quota-view.ts +1 -1
- package/src/console/remote-support/routes.ts +1 -1
- package/src/console/remote-support/service.ts +2 -2
- package/src/console/routing/model/contracts.ts +1 -1
- package/src/console/routing/pools/contracts.ts +2 -2
- package/src/console/routing/pools/import-parse.ts +3 -3
- package/src/console/routing/pools/relay-deploy.ts +3 -3
- package/src/console/settings/contracts.ts +29 -2
- package/src/console/settings/store.ts +20 -0
- package/src/console/share/share-router.ts +100 -32
- package/src/console/share/share-stats.ts +11 -13
- package/src/console/share/share-usage.ts +1 -1
- package/src/console/shared/errors.ts +2 -2
- package/src/console/shared/object.ts +18 -0
- package/src/console/shared/read-through-cache.ts +4 -4
- package/src/console/shared/transaction.ts +14 -0
- package/src/console/system-prompt/contracts.ts +89 -12
- package/src/console/system-prompt/routes.ts +98 -45
- package/src/console/updates/apply-update.ts +244 -0
- package/src/console/updates/routes.ts +252 -97
- package/src/main.ts +11 -5
- package/src/network/http2-bidi.ts +1 -1
- package/src/network/ip-utils.ts +298 -0
- package/src/network/outbound-fetch.ts +1 -1
- package/src/network/pool/agent.ts +7 -6
- package/src/network/pool/byte-accounting.ts +1 -1
- package/src/network/pool/resolver.ts +16 -12
- package/src/network/pool/selector.ts +150 -136
- package/src/network/pool-health-machine.ts +1 -1
- package/src/network/rate-limit-verdict.ts +1 -1
- package/src/network/retry.ts +1 -1
- package/src/network/ssrf.ts +20 -71
- package/src/observability/event-log.ts +9 -2
- package/src/observability/event-query.ts +61 -291
- package/src/observability/log-sanitize.ts +1 -1
- package/src/observability/metrics.ts +4 -4
- package/src/observability/payload-capture.ts +6 -5
- package/src/observability/payload-store.ts +1 -1
- package/src/observability/runtime-metrics.ts +1 -1
- package/src/observability/telemetry-buffer.ts +19 -3
- package/src/observability/telemetry-reconciliation.ts +3 -3
- package/src/observability/token-speed.ts +1 -1
- package/src/persistence/connection-url.ts +1 -1
- package/src/persistence/db-handle.ts +1 -1
- package/src/persistence/db-pg.ts +2 -2
- package/src/persistence/db-sqlite.ts +3 -3
- package/src/persistence/dialect.ts +5 -1
- package/src/persistence/readiness.ts +1 -1
- package/src/persistence/redis.ts +1 -1
- package/src/persistence/schema.ts +121 -40
- package/src/persistence/shared-cache.ts +2 -2
- package/src/persistence/sort-order.ts +1 -1
- package/src/persistence/stores/api-key-store.ts +29 -2
- package/src/persistence/stores/share-store.ts +20 -8
- package/src/persistence/system-prompt-store.ts +63 -18
- package/src/persistence/tenant-preferences.ts +1 -1
- package/src/persistence/ttl-cache.ts +3 -3
- package/src/persistence/usage-flush.ts +7 -2
- package/src/protocol/canonical-model.ts +1 -1
- package/src/protocol/codecs.ts +6 -10
- package/src/protocol/dsml.ts +8 -125
- package/src/protocol/image-clamp.ts +2 -2
- package/src/protocol/reasoning-text.ts +1 -1
- package/src/protocol/reasoning.ts +7 -52
- package/src/protocol/registry.ts +50 -15
- package/src/protocol/request/chat.ts +46 -19
- package/src/protocol/request/codex.ts +1 -1
- package/src/protocol/request/messages.ts +46 -14
- package/src/protocol/request/responses.ts +19 -10
- package/src/protocol/response/chat.ts +25 -10
- package/src/protocol/response/codex.ts +1 -1
- package/src/protocol/response/messages.ts +1 -1
- package/src/protocol/response/omp-tool-call-markup.ts +1 -1
- package/src/protocol/response/responses.ts +1 -1
- package/src/protocol/sse-decoder.ts +50 -1
- package/src/protocol/stop-reason.ts +2 -2
- package/src/protocol/think-split.ts +347 -0
- package/src/protocol/translation/attachment-integrity.ts +3 -3
- package/src/protocol/translation/cache-controls.ts +8 -20
- package/src/protocol/translation/capabilities.ts +6 -6
- package/src/protocol/translation/dialect/deepseek.ts +10 -0
- package/src/protocol/translation/dialect/inband.ts +39 -0
- package/src/protocol/translation/dialect/model-thinking.ts +89 -0
- package/src/protocol/translation/dialect/qwen.ts +114 -0
- package/src/protocol/translation/dialect/resolver.ts +83 -0
- package/src/protocol/translation/dialect/rules.ts +93 -0
- package/src/protocol/translation/dialect/thinking-ladder.ts +245 -0
- package/src/protocol/translation/dialect/types.ts +58 -0
- package/src/protocol/translation/quirks.ts +18 -4
- package/src/protocol/translation/thinking.ts +12 -252
- package/src/protocol/translation/tool-id.ts +3 -3
- package/src/protocol/translation/tool-repair.ts +1 -1
- package/src/protocol/upstream/post-json.ts +6 -1
- package/src/providers/adapters/compatible-adapter.ts +71 -4
- package/src/providers/authentication/jwt-validator.ts +0 -5
- package/src/providers/authentication/oauth-client.ts +254 -253
- package/src/providers/authentication/oauth-flow-store.ts +42 -7
- package/src/providers/bundled-discovery-providers.ts +6 -30
- package/src/providers/configured-openai-providers.ts +82 -97
- package/src/providers/default-registry.ts +35 -37
- package/src/providers/discovery/catalog/catalog-format.ts +13 -2
- package/src/providers/discovery/discovery-types.ts +0 -1
- package/src/providers/discovery/openai-model-discovery.ts +2 -2
- package/src/providers/discovery/probe-phases.ts +48 -13
- package/src/providers/discovery/probing-service.ts +6 -8
- package/src/providers/integrations/agentrouter/agentrouter.ts +12 -2
- package/src/providers/integrations/antigravity/antigravity-oauth.ts +0 -1
- package/src/providers/integrations/antigravity/antigravity-protocol.ts +88 -28
- package/src/providers/integrations/antigravity/antigravity-quota.ts +18 -6
- package/src/providers/integrations/antigravity/antigravity.ts +22 -13
- package/src/providers/integrations/buddy/buddy-catalog-shared.ts +1 -1
- package/src/providers/integrations/buddy/buddy-chat-shared.ts +20 -4
- package/src/providers/integrations/buddy/buddy-cli-headers.ts +19 -52
- package/src/providers/integrations/buddy/buddy-identity.ts +86 -0
- package/src/providers/integrations/buddy/buddy-oauth-shared.ts +1 -1
- package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +1 -2
- package/src/providers/integrations/buddy/codebuddy/provider.ts +4 -15
- package/src/providers/integrations/buddy/codebuddy/shared.ts +30 -9
- package/src/providers/integrations/buddy/workbuddy/provider.ts +5 -9
- package/src/providers/integrations/buddy/workbuddy/shared.ts +21 -3
- package/src/providers/integrations/claude/claude-cch.ts +148 -148
- package/src/providers/integrations/claude/fallback-credit.ts +3 -7
- package/src/providers/integrations/cline/cline.ts +1 -1
- package/src/providers/integrations/codex/codex-device-code.ts +101 -101
- package/src/providers/integrations/codex/codex-oauth.ts +0 -1
- package/src/providers/integrations/commandcode/commandcode.ts +75 -115
- package/src/providers/integrations/commandcode/quota.ts +131 -51
- package/src/providers/integrations/cursor/cursor-http2.ts +0 -3
- package/src/providers/integrations/cursor/cursor-quota.ts +2 -6
- package/src/providers/integrations/cursor/cursor-request.ts +0 -87
- package/src/providers/integrations/cursor/cursor-shared.ts +0 -4
- package/src/providers/integrations/cursor/cursor.ts +35 -3
- package/src/providers/integrations/cursor/protocol/framing.ts +0 -56
- package/src/providers/integrations/cursor/protocol/messages.ts +0 -96
- package/src/providers/integrations/factory/factory.ts +9 -9
- package/src/providers/integrations/github/github-discovery.ts +70 -12
- package/src/providers/integrations/github/github-oauth.ts +184 -14
- package/src/providers/integrations/github/github.ts +134 -26
- package/src/providers/integrations/grok/grok-oauth.ts +261 -261
- package/src/providers/integrations/grok/grok-quota-frame.ts +1 -1
- package/src/providers/integrations/grok/grok-quota.ts +16 -7
- package/src/providers/integrations/grok/grok-ratelimit-store.ts +0 -5
- package/src/providers/integrations/grok/grok-ratelimit.ts +3 -0
- package/src/providers/integrations/grok/grok.ts +86 -36
- package/src/providers/integrations/kilo/kilo-oauth.ts +1 -1
- package/src/providers/integrations/kiro/kiro-cache.ts +31 -0
- package/src/providers/integrations/kiro/kiro-catalog.ts +31 -5
- package/src/providers/integrations/kiro/kiro-discovery.ts +47 -43
- package/src/providers/integrations/kiro/kiro-machine-id.ts +6 -3
- package/src/providers/integrations/kiro/kiro-oauth.ts +523 -255
- package/src/providers/integrations/kiro/kiro-quota.ts +35 -47
- package/src/providers/integrations/kiro/kiro-request.ts +8 -11
- package/src/providers/integrations/kiro/kiro-stream.ts +13 -0
- package/src/providers/integrations/kiro/kiro.ts +80 -68
- package/src/providers/integrations/muse/muse-oauth.ts +0 -1
- package/src/providers/integrations/muse/muse-quota.ts +0 -4
- package/src/providers/integrations/opencode/fingerprint.ts +7 -5
- package/src/providers/integrations/opencode/provider.ts +17 -24
- package/src/providers/integrations/qoder/qoder-catalog.ts +94 -11
- package/src/providers/integrations/qoder/qoder-oauth.ts +165 -25
- package/src/providers/integrations/qoder/qoder-quota.ts +48 -6
- package/src/providers/integrations/qoder/qoder-realm.ts +10 -31
- package/src/providers/integrations/qoder/qoder-sse.ts +159 -0
- package/src/providers/integrations/qoder/qoder-umid.ts +21 -25
- package/src/providers/integrations/qoder/qoder-virtual.ts +12 -0
- package/src/providers/integrations/qoder/qoder.ts +422 -71
- package/src/providers/integrations/shared/connect.ts +0 -54
- package/src/providers/integrations/shared/hash.ts +15 -0
- package/src/providers/integrations/shared/session-cache.ts +136 -0
- package/src/providers/integrations/trae/trae-cache.ts +7 -87
- package/src/providers/integrations/trae/trae-catalog.ts +1 -6
- package/src/providers/integrations/trae/trae-protocol.ts +17 -8
- package/src/providers/integrations/trae/trae-realm.ts +0 -7
- package/src/providers/integrations/trae/trae.ts +51 -8
- package/src/providers/integrations/xai/xai-oauth.ts +5 -5
- package/src/providers/integrations/zcode-start-plan/gifts.ts +265 -0
- package/src/providers/integrations/zcode-start-plan/oauth.ts +154 -0
- package/src/providers/integrations/zcode-start-plan/provider.ts +131 -0
- package/src/providers/integrations/zcode-start-plan/quota.ts +152 -0
- package/src/providers/integrations/zcode-start-plan/zcode_prompt.json +10 -0
- package/src/providers/operations/account-error-classification.ts +198 -133
- package/src/providers/operations/account-health-service.ts +31 -39
- package/src/providers/operations/account-reset-service.ts +58 -1
- package/src/providers/operations/byok-wire-profile.ts +19 -15
- package/src/providers/operations/cli-platform.ts +31 -5
- package/src/providers/operations/client-version-resolver.ts +4 -6
- package/src/providers/operations/client-versions.ts +10 -7
- package/src/providers/operations/provider-catalog-seeder.ts +2 -0
- package/src/providers/operations/provider-catalog-service.ts +18 -2
- package/src/providers/operations/provider-credential-service.ts +19 -2
- package/src/providers/provider-contracts.ts +18 -7
- package/src/providers/provider-metadata.ts +17 -2
- package/src/providers/provider-model-definition.ts +22 -1
- package/src/providers/provider-probe.ts +4 -2
- package/src/providers/provider-usage.ts +50 -19
- package/src/providers/quota/cache.ts +29 -0
- package/src/providers/quota/quota-contracts.ts +4 -0
- package/src/providers/quota/refresh.ts +27 -4
- package/src/providers/quota/snapshot.ts +94 -0
- package/src/providers/search/search-provider.ts +1 -3
- package/src/providers/search/search-providers.ts +2 -1
- package/src/security/abuse.ts +4 -4
- package/src/security/admission/service.ts +13 -6
- package/src/security/admission/ttl.ts +61 -61
- package/src/security/api-key-auth.ts +17 -3
- package/src/security/client-router-fingerprint.ts +4 -4
- package/src/security/credential-codec.ts +3 -3
- package/src/security/csrf.ts +2 -2
- package/src/security/ip-boundary.ts +16 -189
- package/src/security/model-access-rule.ts +1 -1
- package/src/security/outbound-headers.ts +18 -0
- package/src/shared/invoke-guard.ts +47 -0
- package/src/transport/contracts.ts +13 -4
- package/src/transport/dispatch/attempt-finalize.ts +70 -22
- package/src/transport/dispatch/attempt-loop.ts +22 -0
- package/src/transport/dispatch/capture-policy.ts +34 -37
- package/src/transport/dispatch/empty-stream.ts +23 -20
- package/src/transport/dispatch/generation.ts +25 -45
- package/src/transport/dispatch/native-shared.ts +127 -0
- package/src/transport/dispatch/proxy-request.ts +3 -1
- package/src/transport/dispatch/responses-compact.ts +25 -46
- package/src/transport/dispatch/streaming/encoder.ts +18 -72
- package/src/transport/dispatch/streaming/finalize.ts +2 -2
- package/src/transport/dispatch/streaming/stream.ts +7 -3
- package/src/transport/dispatch/streaming/thinking-loop.ts +1 -1
- package/src/transport/dispatch/systemone.ts +20 -48
- package/src/transport/dispatch/token-count.ts +41 -38
- package/src/transport/dispatch/websearch.ts +19 -45
- package/src/transport/drain-endpoint.ts +1 -1
- package/src/transport/failure-policy.ts +21 -1
- package/src/transport/guards/auth-guard.ts +0 -6
- package/src/transport/guards/body-policy.ts +3 -3
- package/src/transport/guards/error-lifecycle.ts +4 -0
- package/src/transport/guards/headroom-guard.ts +1 -1
- package/src/transport/guards/pipeline.ts +1 -1
- package/src/transport/guards/request-context.ts +12 -17
- package/src/transport/request/preparer.ts +286 -7
- package/src/transport/request/rtk/compress-request.ts +3 -3
- package/src/transport/request/rtk/rtk-constants.ts +2 -2
- package/src/transport/request/rtk/rtk-filters.ts +8 -8
- package/src/transport/request/state.ts +7 -13
- package/src/transport/request/system-prompt-injection.ts +74 -11
- package/src/transport/request/tenant-preferences.ts +22 -0
- package/src/transport/routing/candidate-index.ts +2 -2
- package/src/transport/routing/round-robin.ts +1 -1
- package/src/transport/routing/route-catalog.ts +17 -18
- package/src/transport/routing/route-model.ts +126 -33
- package/src/transport/routing/router.ts +159 -37
- package/src/transport/shutdown-notice.ts +2 -2
- package/src/transport/surface/adapters.ts +3 -3
- package/src/transport/surface/chat/encode.ts +7 -7
- package/src/transport/surface/chat/parse.ts +7 -7
- package/src/transport/surface/completion.ts +2 -2
- package/src/transport/surface/content-parts.ts +1 -1
- package/src/transport/surface/dialects.ts +2 -2
- package/src/transport/surface/messages/parse.ts +3 -3
- package/src/transport/surface/reasoning-summary.ts +9 -14
- package/src/transport/surface/responses/adapter.ts +1 -1
- package/src/transport/surface/responses/errors.ts +0 -9
- package/src/transport/vision-handoff-cache.ts +58 -0
- package/src/transport/vision-handoff.ts +431 -0
- package/src/workers/account-identity-sweep.ts +2 -2
- package/src/workers/buddy-growth-tasks.ts +392 -346
- package/src/workers/daily-checkin.ts +102 -49
- package/src/workers/maintenance-lease.ts +2 -35
- package/src/workers/oauth-refresh-sweep.ts +8 -1
- package/src/workers/quota-refresh-sweep.ts +120 -82
- package/src/workers/scheduler.ts +67 -4
- package/src/workers/sweep-runner.ts +24 -5
- package/src/workers/zcode-gift-claim.ts +108 -0
- package/dist/dashboard/assets/AccountCooldown-Bjo92Qat.js +0 -1
- package/dist/dashboard/assets/AccountCooldown-Bjo92Qat.js.gz +0 -0
- package/dist/dashboard/assets/BannedPage-ChG5svFb.js +0 -1
- package/dist/dashboard/assets/BannedPage-ChG5svFb.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-BIcWQun7.js +0 -1
- package/dist/dashboard/assets/CliToolDetailPage-BIcWQun7.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-Bf2VelDe.js +0 -1
- package/dist/dashboard/assets/CliToolsPage-Bf2VelDe.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-DCgm5g6g.js +0 -1
- package/dist/dashboard/assets/CombosPage-DCgm5g6g.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-a8mD0QF1.js +0 -1
- package/dist/dashboard/assets/ConsoleLogPage-a8mD0QF1.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-ggeMSjte.js +0 -1
- package/dist/dashboard/assets/CustomizationPage-ggeMSjte.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-DzSWzE_j.js +0 -1
- package/dist/dashboard/assets/HealthEventsModal-DzSWzE_j.js.gz +0 -0
- package/dist/dashboard/assets/LoginPage-U6AKaJcF.js +0 -1
- package/dist/dashboard/assets/LoginPage-U6AKaJcF.js.gz +0 -0
- package/dist/dashboard/assets/ModelPicker-BMS2t8BA.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-D2D4IiHl.js +0 -1
- package/dist/dashboard/assets/OverviewPage-D2D4IiHl.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-CrNf7j_X.js +0 -5
- package/dist/dashboard/assets/ProviderDetailPage-CrNf7j_X.js.gz +0 -0
- package/dist/dashboard/assets/ProviderIcon-FB6yS4v1.js +0 -1
- package/dist/dashboard/assets/ProviderIcon-FB6yS4v1.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-BSDbquc1.js +0 -1
- package/dist/dashboard/assets/ProvidersPage-BSDbquc1.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-lsrx7NYg.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-L0skzML8.js +0 -1
- package/dist/dashboard/assets/QuotaPage-L0skzML8.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-CmAbjRHW.js +0 -1
- package/dist/dashboard/assets/SettingsPage-CmAbjRHW.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-f0DE1h0-.js +0 -1
- package/dist/dashboard/assets/SetupPage-f0DE1h0-.js.gz +0 -0
- package/dist/dashboard/assets/SortableList-ClzpwyET.js +0 -1
- package/dist/dashboard/assets/SortableList-ClzpwyET.js.gz +0 -0
- package/dist/dashboard/assets/StudioPage-Cq5tW7hW.js.gz +0 -0
- package/dist/dashboard/assets/ToolIcon-K1ckcDKg.js +0 -1
- package/dist/dashboard/assets/ToolIcon-K1ckcDKg.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-Dfc9rWQn.js +0 -56
- package/dist/dashboard/assets/UsagePage-Dfc9rWQn.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-C38iXoO4.js +0 -1
- package/dist/dashboard/assets/api-keys-C38iXoO4.js.gz +0 -0
- package/dist/dashboard/assets/app-BayTTy01.js +0 -9
- package/dist/dashboard/assets/app-BayTTy01.js.gz +0 -0
- package/dist/dashboard/assets/app-a159k0ub.css +0 -2
- package/dist/dashboard/assets/app-a159k0ub.css.gz +0 -0
- package/dist/dashboard/assets/assert-DbRA8EG2.js +0 -15
- package/dist/dashboard/assets/assert-DbRA8EG2.js.gz +0 -0
- package/dist/dashboard/assets/badge-D9CS6dZk.js.gz +0 -0
- package/dist/dashboard/assets/banner-DympBNq4.js.gz +0 -0
- package/dist/dashboard/assets/card-ibRWU_uT.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-63qBGaRw.js +0 -1
- package/dist/dashboard/assets/cli-tools-63qBGaRw.js.gz +0 -0
- package/dist/dashboard/assets/clipboard-button-DJm-9pz7.js.gz +0 -0
- package/dist/dashboard/assets/dialog-8fiE6tec.js +0 -1
- package/dist/dashboard/assets/dialog-8fiE6tec.js.gz +0 -0
- package/dist/dashboard/assets/drawer-CqGYeOrd.js.gz +0 -0
- package/dist/dashboard/assets/entry-BSAsYsmV.js +0 -1
- package/dist/dashboard/assets/entry-BSAsYsmV.js.gz +0 -0
- package/dist/dashboard/assets/entry-CiIQULZD.js +0 -4
- package/dist/dashboard/assets/entry-CiIQULZD.js.gz +0 -0
- package/dist/dashboard/assets/entry-Daz0lJ-W.js +0 -1
- package/dist/dashboard/assets/entry-Daz0lJ-W.js.gz +0 -0
- package/dist/dashboard/assets/formatters-D-MTJxMr.js.gz +0 -0
- package/dist/dashboard/assets/github-badge-CPK47xQx.js +0 -1
- package/dist/dashboard/assets/github-badge-CPK47xQx.js.gz +0 -0
- package/dist/dashboard/assets/index-DBNPOfhV.js.gz +0 -0
- package/dist/dashboard/assets/inline-BT0zntEr.js.gz +0 -0
- package/dist/dashboard/assets/input-Da2ZViWg.js.gz +0 -0
- package/dist/dashboard/assets/layout-BXNeLw6M.js.gz +0 -0
- package/dist/dashboard/assets/list-row-BycOrrIV.js.gz +0 -0
- package/dist/dashboard/assets/live-DCQNZpF7.js +0 -1
- package/dist/dashboard/assets/live-DCQNZpF7.js.gz +0 -0
- package/dist/dashboard/assets/mutation-Rr0TIvcj.js.gz +0 -0
- package/dist/dashboard/assets/network-9Yj2ZyLo.js +0 -1
- package/dist/dashboard/assets/network-9Yj2ZyLo.js.gz +0 -0
- package/dist/dashboard/assets/numbers-CEagj6ZZ.js +0 -2
- package/dist/dashboard/assets/numbers-CEagj6ZZ.js.gz +0 -0
- package/dist/dashboard/assets/providers/zai-coding-plan.svg +0 -6
- package/dist/dashboard/assets/providers/zai-coding-plan.svg.gz +0 -0
- package/dist/dashboard/assets/quota-Caw7wqci.js +0 -1
- package/dist/dashboard/assets/quota-Caw7wqci.js.gz +0 -0
- package/dist/dashboard/assets/routing-CO9zCUus.js +0 -1
- package/dist/dashboard/assets/routing-CO9zCUus.js.gz +0 -0
- package/dist/dashboard/assets/select-BIYIBkMU.js.gz +0 -0
- package/dist/dashboard/assets/settings-jS3-PNSA.js +0 -1
- package/dist/dashboard/assets/settings-jS3-PNSA.js.gz +0 -0
- package/dist/dashboard/assets/stack-DfgnFDWY.js.gz +0 -0
- package/dist/dashboard/assets/state-CkfdYWel.js.gz +0 -0
- package/dist/dashboard/assets/stream-retry-5QnVuSSo.js +0 -1
- package/dist/dashboard/assets/stream-retry-5QnVuSSo.js.gz +0 -0
- package/dist/dashboard/assets/switch-SYm237HG.js.gz +0 -0
- package/dist/dashboard/assets/useMutation-BQqCRNIi.js.gz +0 -0
- package/src/console/cli-tools/injectors/cline.ts +0 -110
- package/src/console/cli-tools/injectors/copilot.ts +0 -108
- package/src/console/cli-tools/injectors/cowork.ts +0 -64
- package/src/console/cli-tools/injectors/deepseek-tui.ts +0 -85
- package/src/console/cli-tools/injectors/droid.ts +0 -96
- package/src/console/cli-tools/injectors/grok-build.ts +0 -70
- package/src/console/cli-tools/injectors/hermes.ts +0 -101
- package/src/console/cli-tools/injectors/jcode.ts +0 -115
- package/src/console/cli-tools/injectors/openclaw.ts +0 -161
- package/src/network/response-headers.ts +0 -39
- package/src/protocol/response/dsml.ts +0 -38
- package/src/providers/integrations/xiaomi-mimo/think-stream.ts +0 -229
- /package/dist/dashboard/assets/brand/{og_bansos.webp → og_bansos_initial.webp} +0 -0
- /package/dist/dashboard/assets/brand/{og_image.webp → og_image_initial.webp} +0 -0
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Command Code quota, read from the
|
|
2
|
+
* Command Code quota, read from the billing endpoints its client reads.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* renders still expects windows, so the balance is reported as one independent
|
|
7
|
-
* window — the honest reading, since credits are the only thing consumed.
|
|
4
|
+
* Monthly allowance and purchased/free credits are separate pooled windows:
|
|
5
|
+
* the monthly cap and reset do not limit or expire the additional balance.
|
|
8
6
|
*
|
|
9
7
|
* The endpoints, all on `https://api.commandcode.ai` (not the Provider API
|
|
10
8
|
* origin the model catalog lives on):
|
|
@@ -12,17 +10,42 @@
|
|
|
12
10
|
* `/alpha/whoami` identity, and the `orgId` when one exists
|
|
13
11
|
* `/alpha/billing/credits` the balance and any window limits
|
|
14
12
|
* `/alpha/billing/subscriptions` the plan, when there is one
|
|
15
|
-
* `/alpha/usage/summary` spend in the period, for context
|
|
16
13
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* balance has already got the answer even if the usage summary never came back.
|
|
14
|
+
* Identity resolves the organization before billing is read. Billing reads are
|
|
15
|
+
* independent: retain the balance or subscription when the other is unavailable.
|
|
20
16
|
*/
|
|
21
17
|
import type { FetchLike, ProviderQuotaResult, ProviderQuotaWindow } from "../../quota/quota-contracts";
|
|
22
18
|
|
|
23
19
|
const COMMANDCODE_API_BASE = "https://api.commandcode.ai" as const;
|
|
24
20
|
const REQUEST_TIMEOUT_MS = 15_000;
|
|
25
21
|
|
|
22
|
+
const PLAN_CAPS: Readonly<Record<string, number>> = {
|
|
23
|
+
"individual-go": 10,
|
|
24
|
+
"individual-goat": 70,
|
|
25
|
+
"individual-pro": 30,
|
|
26
|
+
"individual-provider": 15,
|
|
27
|
+
"individual-max": 150,
|
|
28
|
+
"individual-ultra": 300,
|
|
29
|
+
"teams-pro": 40,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const PLAN_CAP_OVERRIDES: Readonly<Record<string, number>> = {
|
|
33
|
+
"individual-pro-v1": 80,
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
function commandCodePlan(planId: string): { readonly label: string; readonly cap: number | null } {
|
|
37
|
+
const [scope, tier] = planId.toLowerCase().split("-");
|
|
38
|
+
if ((scope !== "individual" && scope !== "teams") || !tier) {
|
|
39
|
+
return { label: planId, cap: PLAN_CAP_OVERRIDES[planId] ?? PLAN_CAPS[planId] ?? null };
|
|
40
|
+
}
|
|
41
|
+
const tierLabel = tier === "goat" ? "GOAT" : `${tier[0]?.toUpperCase() ?? ""}${tier.slice(1)}`;
|
|
42
|
+
const normalizedId = `${scope}-${tier}`;
|
|
43
|
+
return {
|
|
44
|
+
label: `CommandCode ${scope === "teams" ? "Teams " : ""}${tierLabel}`,
|
|
45
|
+
cap: PLAN_CAP_OVERRIDES[planId] ?? PLAN_CAPS[normalizedId] ?? null,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
26
49
|
interface RequestOk {
|
|
27
50
|
readonly ok: true;
|
|
28
51
|
readonly value: unknown;
|
|
@@ -57,31 +80,69 @@ function recordValue(value: unknown): Record<string, unknown> | undefined {
|
|
|
57
80
|
}
|
|
58
81
|
|
|
59
82
|
function numberOrNull(value: unknown): number | null {
|
|
60
|
-
|
|
83
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
84
|
+
if (typeof value === "string" && value.trim() && Number.isFinite(Number(value))) {
|
|
85
|
+
return Number(value);
|
|
86
|
+
}
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function isoTimestamp(value: unknown): string | null {
|
|
91
|
+
const numeric = numberOrNull(value);
|
|
92
|
+
if (numeric !== null) {
|
|
93
|
+
if (numeric <= 0) return null;
|
|
94
|
+
const date = new Date(numeric > 1_000_000_000_000 ? numeric : numeric * 1000);
|
|
95
|
+
return Number.isFinite(date.getTime()) ? date.toISOString() : null;
|
|
96
|
+
}
|
|
97
|
+
if (typeof value !== "string" || !Number.isFinite(Date.parse(value))) return null;
|
|
98
|
+
return new Date(value).toISOString();
|
|
61
99
|
}
|
|
62
100
|
|
|
63
|
-
|
|
64
|
-
|
|
101
|
+
function withQuery(path: string, params: Readonly<Record<string, string | null>>): string {
|
|
102
|
+
const query = new URLSearchParams(
|
|
103
|
+
Object.entries(params).filter((entry): entry is [string, string] => entry[1] !== null),
|
|
104
|
+
).toString();
|
|
105
|
+
return query ? `${path}?${query}` : path;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** Only monthly credits share the subscription allowance and reset. */
|
|
109
|
+
function creditWindows(
|
|
110
|
+
credits: Record<string, unknown>,
|
|
111
|
+
planCap: number | null,
|
|
112
|
+
resetsAt: string | null,
|
|
113
|
+
): readonly ProviderQuotaWindow[] {
|
|
65
114
|
const monthly = numberOrNull(credits["monthlyCredits"]) ?? 0;
|
|
66
115
|
const purchased = numberOrNull(credits["purchasedCredits"]) ?? 0;
|
|
67
116
|
const free = numberOrNull(credits["freeCredits"]) ?? 0;
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
117
|
+
const used = planCap === null ? null : Math.max(0, planCap - monthly);
|
|
118
|
+
const usedPercent = planCap !== null && planCap > 0 && used !== null
|
|
119
|
+
? Math.min(100, Math.max(0, (used / planCap) * 100))
|
|
120
|
+
: null;
|
|
121
|
+
const windows: ProviderQuotaWindow[] = [{
|
|
73
122
|
kind: "credits",
|
|
74
|
-
label: "
|
|
75
|
-
// These are credits in one unit that can be spent interchangeably, so
|
|
76
|
-
// they are pooled like Qoder's plan/granted balances — not independent
|
|
77
|
-
// rate-limit lanes. The account-row pill and the Quota page both sum
|
|
78
|
-
// pooled windows, so this must be `pooled` or the balance never renders.
|
|
123
|
+
label: "Monthly credits",
|
|
79
124
|
accounting: "pooled",
|
|
80
|
-
usedPercent
|
|
81
|
-
remainingPercent: null,
|
|
82
|
-
resetsAt
|
|
83
|
-
|
|
84
|
-
|
|
125
|
+
usedPercent,
|
|
126
|
+
remainingPercent: usedPercent === null ? null : Math.max(0, 100 - usedPercent),
|
|
127
|
+
resetsAt,
|
|
128
|
+
used,
|
|
129
|
+
limit: planCap,
|
|
130
|
+
remaining: monthly,
|
|
131
|
+
}];
|
|
132
|
+
if (purchased + free > 0) {
|
|
133
|
+
windows.push({
|
|
134
|
+
kind: "additional_credits",
|
|
135
|
+
label: "Purchased/free credits",
|
|
136
|
+
accounting: "pooled",
|
|
137
|
+
usedPercent: null,
|
|
138
|
+
remainingPercent: null,
|
|
139
|
+
resetsAt: null,
|
|
140
|
+
used: null,
|
|
141
|
+
limit: null,
|
|
142
|
+
remaining: purchased + free,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
return windows;
|
|
85
146
|
}
|
|
86
147
|
|
|
87
148
|
function windowLimits(
|
|
@@ -92,17 +153,25 @@ function windowLimits(
|
|
|
92
153
|
const weekly = recordValue(limits["weekly"]);
|
|
93
154
|
const push = (source: Record<string, unknown> | undefined, kind: string, label: string) => {
|
|
94
155
|
if (source === undefined) return;
|
|
156
|
+
const used = numberOrNull(source["used"]) ?? 0;
|
|
157
|
+
const limit = numberOrNull(source["cap"]);
|
|
158
|
+
if ((limit === null || limit <= 0) && used <= 0) return;
|
|
159
|
+
const usedPercent = limit !== null && limit > 0
|
|
160
|
+
? Math.min(100, Math.max(0, (used / limit) * 100))
|
|
161
|
+
: null;
|
|
95
162
|
out.push({
|
|
96
163
|
kind,
|
|
97
164
|
label,
|
|
98
165
|
accounting: "independent",
|
|
99
|
-
usedPercent
|
|
100
|
-
remainingPercent:
|
|
101
|
-
resetsAt:
|
|
102
|
-
|
|
166
|
+
usedPercent,
|
|
167
|
+
remainingPercent: usedPercent === null ? null : Math.max(0, 100 - usedPercent),
|
|
168
|
+
resetsAt: isoTimestamp(source["resetAt"]),
|
|
169
|
+
used,
|
|
170
|
+
limit,
|
|
171
|
+
remaining: limit === null ? null : Math.max(0, limit - used),
|
|
103
172
|
});
|
|
104
173
|
};
|
|
105
|
-
push(fiveHour, "five_hour", "
|
|
174
|
+
push(fiveHour, "five_hour", "Session (5h)");
|
|
106
175
|
push(weekly, "weekly", "Weekly");
|
|
107
176
|
return out;
|
|
108
177
|
}
|
|
@@ -112,12 +181,8 @@ export async function fetchCommandCodeQuota(
|
|
|
112
181
|
fetcher: FetchLike,
|
|
113
182
|
): Promise<ProviderQuotaResult> {
|
|
114
183
|
const source = "commandcode";
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
readJson("/alpha/billing/credits", credential, fetcher),
|
|
118
|
-
readJson("/alpha/billing/subscriptions", credential, fetcher),
|
|
119
|
-
]);
|
|
120
|
-
if (!whoami.ok && !creditsRaw.ok) {
|
|
184
|
+
const whoami = await readJson(withQuery("/alpha/whoami", { limits: "1" }), credential, fetcher);
|
|
185
|
+
if (!whoami.ok) {
|
|
121
186
|
return {
|
|
122
187
|
source,
|
|
123
188
|
plan: null,
|
|
@@ -128,32 +193,47 @@ export async function fetchCommandCodeQuota(
|
|
|
128
193
|
|
|
129
194
|
const whoamiBody = whoami.ok ? recordValue(whoami.value) : undefined;
|
|
130
195
|
const user = recordValue(whoamiBody?.["user"]);
|
|
196
|
+
const organization = recordValue(whoamiBody?.["org"]);
|
|
197
|
+
const orgId = typeof organization?.["id"] === "string" ? organization["id"] : null;
|
|
131
198
|
const accountLabel =
|
|
132
199
|
(typeof user?.["email"] === "string" && user["email"]) ||
|
|
133
200
|
(typeof user?.["userName"] === "string" && user["userName"]) ||
|
|
201
|
+
(typeof user?.["name"] === "string" && user["name"]) ||
|
|
134
202
|
undefined;
|
|
135
203
|
|
|
204
|
+
const [creditsRaw, subscriptionRaw] = await Promise.all([
|
|
205
|
+
readJson(withQuery("/alpha/billing/credits", { orgId }), credential, fetcher),
|
|
206
|
+
readJson(withQuery("/alpha/billing/subscriptions", { orgId }), credential, fetcher),
|
|
207
|
+
]);
|
|
208
|
+
if (!creditsRaw.ok && !subscriptionRaw.ok) {
|
|
209
|
+
return {
|
|
210
|
+
source,
|
|
211
|
+
plan: null,
|
|
212
|
+
windows: [],
|
|
213
|
+
error: "Command Code did not answer its billing endpoints",
|
|
214
|
+
...(accountLabel === undefined ? {} : { accountLabel }),
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const subscriptionBody = subscriptionRaw.ok ? recordValue(subscriptionRaw.value) : undefined;
|
|
219
|
+
const planRecord = recordValue(subscriptionBody?.["data"]);
|
|
220
|
+
const planId = typeof planRecord?.["planId"] === "string" ? planRecord["planId"] : null;
|
|
221
|
+
const parsedPlan = planId === null ? null : commandCodePlan(planId);
|
|
222
|
+
const plan =
|
|
223
|
+
parsedPlan?.label ??
|
|
224
|
+
(typeof planRecord?.["name"] === "string" ? planRecord["name"] : null) ??
|
|
225
|
+
(creditsRaw.ok ? "Credits" : null);
|
|
226
|
+
const periodEnd = isoTimestamp(planRecord?.["currentPeriodEnd"]);
|
|
227
|
+
|
|
136
228
|
const creditsBody = creditsRaw.ok ? recordValue(creditsRaw.value) : undefined;
|
|
137
229
|
const windows: ProviderQuotaWindow[] = [];
|
|
138
230
|
if (creditsBody !== undefined) {
|
|
139
231
|
const credits = recordValue(creditsBody["credits"]);
|
|
140
|
-
if (credits !== undefined)
|
|
141
|
-
const window = creditWindow(credits);
|
|
142
|
-
if (window !== null) windows.push(window);
|
|
143
|
-
}
|
|
232
|
+
if (credits !== undefined) windows.push(...creditWindows(credits, parsedPlan?.cap ?? null, periodEnd));
|
|
144
233
|
const limits = recordValue(creditsBody["windowLimits"]);
|
|
145
234
|
if (limits !== undefined) windows.push(...windowLimits(limits));
|
|
146
235
|
}
|
|
147
236
|
|
|
148
|
-
const subscriptionBody = subscriptionRaw.ok ? recordValue(subscriptionRaw.value) : undefined;
|
|
149
|
-
const planRecord = recordValue(subscriptionBody?.["data"]);
|
|
150
|
-
const plan =
|
|
151
|
-
typeof planRecord?.["name"] === "string"
|
|
152
|
-
? planRecord["name"]
|
|
153
|
-
: creditsRaw.ok
|
|
154
|
-
? "Credits"
|
|
155
|
-
: null;
|
|
156
|
-
|
|
157
237
|
return {
|
|
158
238
|
source,
|
|
159
239
|
plan,
|
|
@@ -295,6 +295,3 @@ function concat(left: Uint8Array, right: Uint8Array): Uint8Array {
|
|
|
295
295
|
out.set(right, left.byteLength);
|
|
296
296
|
return out;
|
|
297
297
|
}
|
|
298
|
-
|
|
299
|
-
/** Heartbeat cadence while a Run is held open waiting for a tool result. */
|
|
300
|
-
export const RUN_HEARTBEAT_INTERVAL_MS = 20_000;
|
|
@@ -35,6 +35,7 @@ import {
|
|
|
35
35
|
} from "../../quota/quota-contracts";
|
|
36
36
|
import type { QuotaCollectionContext } from "../../quota/quota-support";
|
|
37
37
|
import { cursorAccountIdentity } from "./cursor-auth";
|
|
38
|
+
import { fnv1a32 } from "../shared/hash";
|
|
38
39
|
import { CURSOR_API_HOST, CURSOR_WEBSITE_HOST } from "./cursor-shared";
|
|
39
40
|
|
|
40
41
|
/** Timestamp keys naming the end of the current window. */
|
|
@@ -226,12 +227,7 @@ function authStateUserId(context: QuotaCollectionContext | undefined): string |
|
|
|
226
227
|
* subject it replaces.
|
|
227
228
|
*/
|
|
228
229
|
function cursorAccountTag(credential: string): string {
|
|
229
|
-
|
|
230
|
-
for (let index = 0; index < credential.length; index += 1) {
|
|
231
|
-
hash ^= credential.charCodeAt(index);
|
|
232
|
-
hash = Math.imul(hash, 0x01000193) >>> 0;
|
|
233
|
-
}
|
|
234
|
-
return `cursor-${hash.toString(36).padStart(7, "0").slice(0, 7)}`;
|
|
230
|
+
return `cursor-${fnv1a32(credential).toString(36).padStart(7, "0").slice(0, 7)}`;
|
|
235
231
|
}
|
|
236
232
|
|
|
237
233
|
export async function fetchCursorQuota(
|
|
@@ -303,17 +303,6 @@ export function buildHeartbeat(): Uint8Array {
|
|
|
303
303
|
return encodeMessage("AgentClientMessage", { client_heartbeat: {} });
|
|
304
304
|
}
|
|
305
305
|
|
|
306
|
-
/**
|
|
307
|
-
* `ACM#5 exec_client_control_message.heartbeat{id}`: Cursor CLI sends one every
|
|
308
|
-
* few seconds for each exec it is still running. A zero id is left out, as
|
|
309
|
-
* proto3 does for a default scalar.
|
|
310
|
-
*/
|
|
311
|
-
export function buildExecHeartbeat(execId: number): Uint8Array {
|
|
312
|
-
return encodeMessage("AgentClientMessage", {
|
|
313
|
-
exec_client_control_message: { heartbeat: execId === 0 ? {} : { id: execId } },
|
|
314
|
-
});
|
|
315
|
-
}
|
|
316
|
-
|
|
317
306
|
/** `ACM#5 exec_client_control_message.stream_close{id}` after an exec result. */
|
|
318
307
|
export function buildExecStreamClose(execId: number, execIdString?: string): Uint8Array {
|
|
319
308
|
return encodeMessage("AgentClientMessage", {
|
|
@@ -424,82 +413,6 @@ export function buildMcpResult(input: {
|
|
|
424
413
|
});
|
|
425
414
|
}
|
|
426
415
|
|
|
427
|
-
/**
|
|
428
|
-
* `ACM#2 exec_client_message{shell_result|write_result|read_result}` for a host
|
|
429
|
-
* exec the canonical client executed locally.
|
|
430
|
-
*
|
|
431
|
-
* Cursor's executor replies to its own host requests with the variant's typed
|
|
432
|
-
* result frame (the generic `mcp_result` leaves the server unmatched on a frame
|
|
433
|
-
* it did rank), and after every exec result it sends `stream_close` — without
|
|
434
|
-
* it the cloud waits forever on shell execs. `is_error` keeps the failure as
|
|
435
|
-
* the variant's error/failure case rather than a crafted success.
|
|
436
|
-
*/
|
|
437
|
-
export type CursorHostExecResultVariant = "shell" | "write" | "read";
|
|
438
|
-
|
|
439
|
-
export function buildHostExecResult(input: {
|
|
440
|
-
readonly execId: number;
|
|
441
|
-
readonly execIdString?: string;
|
|
442
|
-
readonly variant: CursorHostExecResultVariant;
|
|
443
|
-
readonly text: string;
|
|
444
|
-
readonly isError: boolean;
|
|
445
|
-
readonly host: {
|
|
446
|
-
readonly command?: string;
|
|
447
|
-
readonly workingDirectory?: string;
|
|
448
|
-
readonly path?: string;
|
|
449
|
-
readonly lines?: number;
|
|
450
|
-
readonly fileSize?: number;
|
|
451
|
-
};
|
|
452
|
-
}): Uint8Array[] {
|
|
453
|
-
const id = { id: input.execId, exec_id: input.execIdString ?? "" };
|
|
454
|
-
const variant = input.variant;
|
|
455
|
-
const text = input.text;
|
|
456
|
-
let result: Record<string, unknown>;
|
|
457
|
-
if (variant === "shell") {
|
|
458
|
-
result = {
|
|
459
|
-
shell_result: input.isError
|
|
460
|
-
? { failure: { command: input.host.command ?? "", exit_code: 1, stderr: text } }
|
|
461
|
-
: {
|
|
462
|
-
success: {
|
|
463
|
-
command: input.host.command ?? "",
|
|
464
|
-
exit_code: 0,
|
|
465
|
-
stdout: text,
|
|
466
|
-
...(input.host.workingDirectory === undefined ? {} : { working_directory: input.host.workingDirectory }),
|
|
467
|
-
},
|
|
468
|
-
},
|
|
469
|
-
};
|
|
470
|
-
} else if (variant === "write") {
|
|
471
|
-
result = {
|
|
472
|
-
write_result: input.isError
|
|
473
|
-
? { error: { path: input.host.path ?? "", error: text } }
|
|
474
|
-
: {
|
|
475
|
-
success: {
|
|
476
|
-
path: input.host.path ?? "",
|
|
477
|
-
lines_created: input.host.lines ?? 0,
|
|
478
|
-
file_size: input.host.fileSize ?? 0,
|
|
479
|
-
},
|
|
480
|
-
},
|
|
481
|
-
};
|
|
482
|
-
} else {
|
|
483
|
-
result = {
|
|
484
|
-
read_result: input.isError
|
|
485
|
-
? { error: { path: input.host.path ?? "", error: text } }
|
|
486
|
-
: {
|
|
487
|
-
success: {
|
|
488
|
-
path: input.host.path ?? "",
|
|
489
|
-
content: text,
|
|
490
|
-
total_lines: text.length > 0 ? text.split("\n").length : 0,
|
|
491
|
-
},
|
|
492
|
-
},
|
|
493
|
-
};
|
|
494
|
-
}
|
|
495
|
-
return [
|
|
496
|
-
encodeMessage("AgentClientMessage", { exec_client_message: { ...id, ...result } }),
|
|
497
|
-
// The real CLI pairs every typed exec result with stream_close — the cloud
|
|
498
|
-
// waits on it for shell execs specifically.
|
|
499
|
-
buildExecStreamClose(input.execId, input.execIdString),
|
|
500
|
-
];
|
|
501
|
-
}
|
|
502
|
-
|
|
503
416
|
/**
|
|
504
417
|
* `ACM#2 exec_client_message{mcp_result}` rejecting a tool the client never
|
|
505
418
|
* declared.
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
// protocol was verified against: they are declared once so the auth flow, the
|
|
6
6
|
// unary catalog calls, and the Run stream cannot drift apart on host, path, or
|
|
7
7
|
// client id.
|
|
8
|
-
import type { WireFamily } from "../../../protocol/canonical-model";
|
|
9
8
|
|
|
10
9
|
/** Canonical bundled provider id. */
|
|
11
10
|
export const CURSOR_PROVIDER_ID = "cursor";
|
|
@@ -72,9 +71,6 @@ export const SESSION_REFRESH_TIMEOUT_MS = 20_000;
|
|
|
72
71
|
*/
|
|
73
72
|
export const RUN_IDLE_TTL_MS = 10 * 60_000;
|
|
74
73
|
|
|
75
|
-
/** Chat wire is the declared default; the adapter owns the native protocol. */
|
|
76
|
-
export const CURSOR_WIRE_FAMILY: WireFamily = "chat";
|
|
77
|
-
|
|
78
74
|
/**
|
|
79
75
|
* Any HTTPS subdomain of `cursor.sh` is an acceptable Run host: the region
|
|
80
76
|
* Cursor routes an account to varies (`agentn.*`, `agent.*`, `api5`, …).
|
|
@@ -62,6 +62,7 @@ import { defaultParameterValues, fetchCursorModels } from "./cursor-catalog";
|
|
|
62
62
|
import type { CursorModelInfo } from "./cursor-catalog";
|
|
63
63
|
import { decodeValueToJson, decodeStructEntriesToJson } from "./protocol/struct";
|
|
64
64
|
import { cursorVariantForExecArgs } from "./protocol/tool-canonical";
|
|
65
|
+
import { fnv1a32 } from "../shared/hash";
|
|
65
66
|
|
|
66
67
|
/**
|
|
67
68
|
* Client-heartbeat cadence for every Cursor Run.
|
|
@@ -81,8 +82,38 @@ const CURSOR_HEARTBEAT_INTERVAL_MS = 5_000;
|
|
|
81
82
|
* every dispatch.
|
|
82
83
|
*/
|
|
83
84
|
const CURSOR_ROSTER_TTL_MS = 300_000;
|
|
84
|
-
/**
|
|
85
|
+
/**
|
|
86
|
+
* credential → { roster, fetchedAt } for the parameter lookup.
|
|
87
|
+
*
|
|
88
|
+
* Keyed by an FNV-1a digest of the credential rather than the raw token so a
|
|
89
|
+
* long-lived map does not hold live credentials as keys. Bounded by
|
|
90
|
+
* `ROSTER_CACHE_MAX` with oldest-first eviction: the TTL is only checked on
|
|
91
|
+
* read, so without a cap rotated tokens would grow the map without bound.
|
|
92
|
+
*/
|
|
93
|
+
const ROSTER_CACHE_MAX = 1024;
|
|
85
94
|
const rosterCache = new Map<string, { roster: readonly CursorModelInfo[]; fetchedAt: number }>();
|
|
95
|
+
|
|
96
|
+
function rosterCacheSet(credential: string, roster: readonly CursorModelInfo[]): void {
|
|
97
|
+
const key = String(fnv1a32(credential));
|
|
98
|
+
rosterCache.delete(key); // re-set moves the entry to newest position
|
|
99
|
+
rosterCache.set(key, { roster, fetchedAt: Date.now() });
|
|
100
|
+
while (rosterCache.size > ROSTER_CACHE_MAX) {
|
|
101
|
+
const oldest = rosterCache.keys().next().value;
|
|
102
|
+
if (oldest === undefined) break;
|
|
103
|
+
rosterCache.delete(oldest);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Test-only access to the roster cache (cap/eviction/TTL behavior is covered
|
|
109
|
+
* by `test/providers/cursor-roster-cache.test.ts` without a full dispatch).
|
|
110
|
+
*/
|
|
111
|
+
export const rosterCacheForTests = {
|
|
112
|
+
size: (): number => rosterCache.size,
|
|
113
|
+
set: rosterCacheSet,
|
|
114
|
+
get: (credential: string): { roster: readonly CursorModelInfo[]; fetchedAt: number } | undefined =>
|
|
115
|
+
rosterCache.get(String(fnv1a32(credential))),
|
|
116
|
+
};
|
|
86
117
|
/** Client-heartbeat cadence the Cursor edge expects (donor `heartbeatMs`). */
|
|
87
118
|
const CURSOR_HEARTBEAT_INTERVAL_OVERRIDE = (() => {
|
|
88
119
|
const raw = process.env.CARTETHYIA_CURSOR_HEARTBEAT_MS?.trim();
|
|
@@ -846,7 +877,8 @@ class CursorAdapter implements ProviderAdapter {
|
|
|
846
877
|
credential: string,
|
|
847
878
|
context: ProviderDispatchContext,
|
|
848
879
|
): Promise<readonly CursorModelInfo[]> {
|
|
849
|
-
const
|
|
880
|
+
const key = String(fnv1a32(credential));
|
|
881
|
+
const cached = rosterCache.get(key);
|
|
850
882
|
if (cached !== undefined && Date.now() - cached.fetchedAt < CURSOR_ROSTER_TTL_MS) {
|
|
851
883
|
return cached.roster;
|
|
852
884
|
}
|
|
@@ -858,7 +890,7 @@ class CursorAdapter implements ProviderAdapter {
|
|
|
858
890
|
: { fetcher: context.outbound_fetch as unknown as typeof fetch }),
|
|
859
891
|
signal: context.abort_signal,
|
|
860
892
|
});
|
|
861
|
-
|
|
893
|
+
rosterCacheSet(credential, roster);
|
|
862
894
|
return roster;
|
|
863
895
|
} catch {
|
|
864
896
|
return cached?.roster ?? [];
|
|
@@ -71,59 +71,3 @@ export function* streamFrames(buffer: Uint8Array): Generator<Frame, void, void>
|
|
|
71
71
|
offset = start + len
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
|
-
|
|
75
|
-
export async function* asyncStreamFrames(
|
|
76
|
-
stream: ReadableStream<Uint8Array>,
|
|
77
|
-
): AsyncGenerator<Frame, void, void> {
|
|
78
|
-
const reader = stream.getReader()
|
|
79
|
-
const chunks: Uint8Array[] = []
|
|
80
|
-
let pendingLength = 0
|
|
81
|
-
|
|
82
|
-
try {
|
|
83
|
-
while (true) {
|
|
84
|
-
const { done, value } = await reader.read()
|
|
85
|
-
if (done && chunks.length === 0) return
|
|
86
|
-
if (value) {
|
|
87
|
-
chunks.push(value)
|
|
88
|
-
pendingLength += value.length
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// Try to parse frames from accumulated data
|
|
92
|
-
const merged = mergeChunks(chunks)
|
|
93
|
-
const frames = Array.from(streamFrames(merged))
|
|
94
|
-
const consumed = frames.reduce((sum, f) => sum + 5 + f.payload.length, 0)
|
|
95
|
-
|
|
96
|
-
if (frames.length > 0) {
|
|
97
|
-
for (const frame of frames) {
|
|
98
|
-
yield frame
|
|
99
|
-
}
|
|
100
|
-
// Keep any trailing bytes for next iteration
|
|
101
|
-
const remaining = merged.subarray(consumed)
|
|
102
|
-
chunks.length = 0
|
|
103
|
-
if (remaining.length > 0) {
|
|
104
|
-
chunks.push(remaining)
|
|
105
|
-
pendingLength = remaining.length
|
|
106
|
-
} else {
|
|
107
|
-
pendingLength = 0
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
if (done) return
|
|
112
|
-
}
|
|
113
|
-
} finally {
|
|
114
|
-
reader.releaseLock()
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function mergeChunks(chunks: Uint8Array[]): Uint8Array {
|
|
119
|
-
const first = chunks[0]
|
|
120
|
-
if (chunks.length === 1 && first !== undefined) return first
|
|
121
|
-
const total = chunks.reduce((s, c) => s + c.length, 0)
|
|
122
|
-
const merged = new Uint8Array(total)
|
|
123
|
-
let offset = 0
|
|
124
|
-
for (const c of chunks) {
|
|
125
|
-
merged.set(c, offset)
|
|
126
|
-
offset += c.length
|
|
127
|
-
}
|
|
128
|
-
return merged
|
|
129
|
-
}
|
|
@@ -2282,99 +2282,3 @@ export function decodeMessage<T = Record<string, unknown>>(
|
|
|
2282
2282
|
const decoded = type.decode(data)
|
|
2283
2283
|
return type.toObject(decoded, { defaults: true, json: true, longs: Number }) as T
|
|
2284
2284
|
}
|
|
2285
|
-
|
|
2286
|
-
/** Decode without inventing absent proto defaults (used for byte-stable snapshots). */
|
|
2287
|
-
export function decodeMessageSparse<T = Record<string, unknown>>(
|
|
2288
|
-
typeName: string,
|
|
2289
|
-
data: Uint8Array,
|
|
2290
|
-
): T {
|
|
2291
|
-
const root = getMessageTypes()
|
|
2292
|
-
const type = root.lookupType(typeName)
|
|
2293
|
-
const decoded = type.decode(data)
|
|
2294
|
-
return type.toObject(decoded, { json: true, longs: Number }) as T
|
|
2295
|
-
}
|
|
2296
|
-
|
|
2297
|
-
type RawField = {
|
|
2298
|
-
field: number
|
|
2299
|
-
wireType: number
|
|
2300
|
-
varint?: string
|
|
2301
|
-
fixed?: number | string
|
|
2302
|
-
bytes?: Uint8Array
|
|
2303
|
-
}
|
|
2304
|
-
|
|
2305
|
-
/** Schema-free walk of one message's top-level wire fields (no nested descent). */
|
|
2306
|
-
function readRawFields(buf: Uint8Array): RawField[] {
|
|
2307
|
-
const reader = protobuf.Reader.create(buf)
|
|
2308
|
-
const fields: RawField[] = []
|
|
2309
|
-
while (reader.pos < reader.len) {
|
|
2310
|
-
const tag = reader.uint32()
|
|
2311
|
-
const field = tag >>> 3
|
|
2312
|
-
const wireType = tag & 7
|
|
2313
|
-
switch (wireType) {
|
|
2314
|
-
case 0:
|
|
2315
|
-
fields.push({ field, wireType, varint: reader.uint64().toString() })
|
|
2316
|
-
break
|
|
2317
|
-
case 1:
|
|
2318
|
-
fields.push({ field, wireType, fixed: reader.fixed64().toString() })
|
|
2319
|
-
break
|
|
2320
|
-
case 2:
|
|
2321
|
-
fields.push({ field, wireType, bytes: reader.bytes() })
|
|
2322
|
-
break
|
|
2323
|
-
case 5:
|
|
2324
|
-
fields.push({ field, wireType, fixed: reader.fixed32() })
|
|
2325
|
-
break
|
|
2326
|
-
default:
|
|
2327
|
-
// Groups (3/4) aren't used on this wire; bail rather than desync the reader.
|
|
2328
|
-
return fields
|
|
2329
|
-
}
|
|
2330
|
-
}
|
|
2331
|
-
return fields
|
|
2332
|
-
}
|
|
2333
|
-
|
|
2334
|
-
/**
|
|
2335
|
-
* Diagnostic-only: walk AgentServerMessage.interaction_update(1).turn_ended(14)
|
|
2336
|
-
* without going through our hand-written TurnEnded schema, so a `cache_write`/
|
|
2337
|
-
* `reasoning_tokens` question can be checked against the raw wire instead of
|
|
2338
|
-
* guessed. Confirmed field ids 1-5 (input/output/cache_read/cache_write/
|
|
2339
|
-
* reasoning) decode correctly. Live captures routinely include `f4` explicitly
|
|
2340
|
-
* as `0` while `f3` (cache_read) and `f5` (reasoning) are non-zero — Cursor's
|
|
2341
|
-
* agent TurnEnded populates the field but does not report write counts here.
|
|
2342
|
-
*/
|
|
2343
|
-
export function debugWalkTurnEnded(payload: Uint8Array): string {
|
|
2344
|
-
try {
|
|
2345
|
-
const top = readRawFields(payload)
|
|
2346
|
-
const iuField = top.find((f) => f.field === 1 && f.wireType === 2)
|
|
2347
|
-
if (!iuField?.bytes) return "(no interaction_update field)"
|
|
2348
|
-
const iu = readRawFields(iuField.bytes)
|
|
2349
|
-
const teField = iu.find((f) => f.field === 14 && f.wireType === 2)
|
|
2350
|
-
if (!teField?.bytes) return "(no turn_ended field in interaction_update)"
|
|
2351
|
-
const te = readRawFields(teField.bytes)
|
|
2352
|
-
return te
|
|
2353
|
-
.map(
|
|
2354
|
-
(f) =>
|
|
2355
|
-
`f${f.field}:wt${f.wireType}=${f.varint ?? f.fixed ?? (f.bytes ? `bytes[${f.bytes.length}]` : "?")}`,
|
|
2356
|
-
)
|
|
2357
|
-
.join(" ")
|
|
2358
|
-
} catch (e) {
|
|
2359
|
-
return `(walk failed: ${(e as Error).message})`
|
|
2360
|
-
}
|
|
2361
|
-
}
|
|
2362
|
-
|
|
2363
|
-
/**
|
|
2364
|
-
* Decode a protobuf sub-message from a frame payload that wraps it in
|
|
2365
|
-
* a top-level field key + length varint. Skips the outer wrapper and
|
|
2366
|
-
* decodes the inner body as `typeName`.
|
|
2367
|
-
*/
|
|
2368
|
-
export function decodeWrappedMessage<T = Record<string, unknown>>(
|
|
2369
|
-
typeName: string,
|
|
2370
|
-
data: Uint8Array,
|
|
2371
|
-
): T {
|
|
2372
|
-
let offset = 1 // skip field key
|
|
2373
|
-
// skip varint length
|
|
2374
|
-
while (offset < data.length) {
|
|
2375
|
-
const b = data[offset] ?? 0
|
|
2376
|
-
offset++
|
|
2377
|
-
if (!(b & 0x80)) break
|
|
2378
|
-
}
|
|
2379
|
-
return decodeMessage<T>(typeName, data.subarray(offset))
|
|
2380
|
-
}
|