cartethyia 2.5.10 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +8 -0
- package/dist/dashboard/assets/{BannedPage-Cd30Z0b9.js → BannedPage-l6XMnfr9.js} +1 -1
- package/dist/dashboard/assets/BannedPage-l6XMnfr9.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolDetailPage-wf5u-ww6.js → CliToolDetailPage-DwOzAW45.js} +1 -1
- package/dist/dashboard/assets/CliToolDetailPage-DwOzAW45.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolsPage-DykPvuck.js → CliToolsPage-BT3Up3QA.js} +1 -1
- package/dist/dashboard/assets/CliToolsPage-BT3Up3QA.js.gz +0 -0
- package/dist/dashboard/assets/{CombosPage-DwvSD3vs.js → CombosPage-6kYIUpzR.js} +1 -1
- package/dist/dashboard/assets/CombosPage-6kYIUpzR.js.gz +0 -0
- package/dist/dashboard/assets/{ConsoleLogPage-CIr7KDex.js → ConsoleLogPage-zRnj1mlR.js} +1 -1
- package/dist/dashboard/assets/ConsoleLogPage-zRnj1mlR.js.gz +0 -0
- package/dist/dashboard/assets/{CustomizationPage-82X0DDdH.js → CustomizationPage-C7m-H1Rz.js} +1 -1
- package/dist/dashboard/assets/CustomizationPage-C7m-H1Rz.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-C8MR_BdB.js +1 -0
- package/dist/dashboard/assets/HealthEventsModal-C8MR_BdB.js.gz +0 -0
- package/dist/dashboard/assets/{LoginPage-CS5mPuVF.js → LoginPage-CbphLvjg.js} +1 -1
- package/dist/dashboard/assets/LoginPage-CbphLvjg.js.gz +0 -0
- package/dist/dashboard/assets/{ModelPicker-C0UCUsVJ.js → ModelPicker-DVny4S5_.js} +1 -1
- package/dist/dashboard/assets/ModelPicker-DVny4S5_.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-DABu2Wgt.js +1 -0
- package/dist/dashboard/assets/OverviewPage-DABu2Wgt.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-C15x9q13.js +3 -0
- package/dist/dashboard/assets/ProviderDetailPage-C15x9q13.js.gz +0 -0
- package/dist/dashboard/assets/{ProvidersPage-vdja5ZPK.js → ProvidersPage-Dfb2896L.js} +1 -1
- package/dist/dashboard/assets/ProvidersPage-Dfb2896L.js.gz +0 -0
- package/dist/dashboard/assets/{ProxyPage-BB4CNm4-.js → ProxyPage-BaCIdAUt.js} +1 -1
- package/dist/dashboard/assets/ProxyPage-BaCIdAUt.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-BsdoCIw1.js +1 -0
- package/dist/dashboard/assets/QuotaPage-BsdoCIw1.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-KVJFh3Ip.js +1 -0
- package/dist/dashboard/assets/SettingsPage-KVJFh3Ip.js.gz +0 -0
- package/dist/dashboard/assets/{SetupPage-FadUOl9S.js → SetupPage-D4g6vOGc.js} +1 -1
- package/dist/dashboard/assets/SetupPage-D4g6vOGc.js.gz +0 -0
- package/dist/dashboard/assets/{SortableList-Cfy6_Khv.js → SortableList-C93i14BD.js} +1 -1
- package/dist/dashboard/assets/SortableList-C93i14BD.js.gz +0 -0
- package/dist/dashboard/assets/{StudioPage-CM92fgJf.js → StudioPage-SgQpymjm.js} +1 -1
- package/dist/dashboard/assets/{StudioPage-CM92fgJf.js.gz → StudioPage-SgQpymjm.js.gz} +0 -0
- package/dist/dashboard/assets/{UsagePage-BT4MyQeT.js → UsagePage-BFME-eba.js} +2 -2
- package/dist/dashboard/assets/UsagePage-BFME-eba.js.gz +0 -0
- package/dist/dashboard/assets/{api-keys-DQYLQxpW.js → api-keys-C23S9sgp.js} +1 -1
- package/dist/dashboard/assets/api-keys-C23S9sgp.js.gz +0 -0
- package/dist/dashboard/assets/{app-B7pVRhJ1.js → app-2KhtHCv9.js} +1 -1
- package/dist/dashboard/assets/{app-B7pVRhJ1.js.gz → app-2KhtHCv9.js.gz} +0 -0
- package/dist/dashboard/assets/app-CEeaMHOy.css +2 -0
- package/dist/dashboard/assets/app-CEeaMHOy.css.gz +0 -0
- package/dist/dashboard/assets/{assert-C9FD_JwJ.js → assert-DU6qrMA_.js} +1 -1
- package/dist/dashboard/assets/assert-DU6qrMA_.js.gz +0 -0
- package/dist/dashboard/assets/{badge-Bvyr7D0u.js → badge-CKsF123d.js} +1 -1
- package/dist/dashboard/assets/badge-CKsF123d.js.gz +0 -0
- package/dist/dashboard/assets/{banner-DIvKAZih.js → banner-8j7uChA9.js} +1 -1
- package/dist/dashboard/assets/banner-8j7uChA9.js.gz +0 -0
- package/dist/dashboard/assets/{card-D5_gYIS_.js → card-CdsSlWA3.js} +1 -1
- package/dist/dashboard/assets/card-CdsSlWA3.js.gz +0 -0
- package/dist/dashboard/assets/{cli-tools-CNqzrfdb.js → cli-tools-BaFUuFFF.js} +1 -1
- package/dist/dashboard/assets/cli-tools-BaFUuFFF.js.gz +0 -0
- package/dist/dashboard/assets/{clipboard-button-B6vDBtbm.js → clipboard-button-uL5aYLfW.js} +1 -1
- package/dist/dashboard/assets/clipboard-button-uL5aYLfW.js.gz +0 -0
- package/dist/dashboard/assets/{dialog-CpjrgdwJ.js → dialog-C07hr5_G.js} +1 -1
- package/dist/dashboard/assets/dialog-C07hr5_G.js.gz +0 -0
- package/dist/dashboard/assets/{drawer-BWmt3b5y.js → drawer-BPO1TcKH.js} +1 -1
- package/dist/dashboard/assets/drawer-BPO1TcKH.js.gz +0 -0
- package/dist/dashboard/assets/{entry-C_oakV3z.js → entry-Bz_CtDfC.js} +1 -1
- package/dist/dashboard/assets/entry-Bz_CtDfC.js.gz +0 -0
- package/dist/dashboard/assets/entry-CwPRKk0d.js +4 -0
- package/dist/dashboard/assets/entry-CwPRKk0d.js.gz +0 -0
- package/dist/dashboard/assets/entry-GJRbmrpA.js +1 -0
- package/dist/dashboard/assets/entry-GJRbmrpA.js.gz +0 -0
- package/dist/dashboard/assets/{github-badge-RRHHWGxh.js → github-badge-DmQreSDd.js} +1 -1
- package/dist/dashboard/assets/github-badge-DmQreSDd.js.gz +0 -0
- package/dist/dashboard/assets/{index-Bhey_rg_.js → index-Bblu6erR.js} +2 -2
- package/dist/dashboard/assets/index-Bblu6erR.js.gz +0 -0
- package/dist/dashboard/assets/{inline-C2_EQ5Uf.js → inline-C9dCYaBZ.js} +1 -1
- package/dist/dashboard/assets/inline-C9dCYaBZ.js.gz +0 -0
- package/dist/dashboard/assets/{input-BMRlQ450.js → input-CjCnXweJ.js} +1 -1
- package/dist/dashboard/assets/input-CjCnXweJ.js.gz +0 -0
- package/dist/dashboard/assets/{layout-XR5xP8ew.js → layout-V6y8DAkl.js} +1 -1
- package/dist/dashboard/assets/layout-V6y8DAkl.js.gz +0 -0
- package/dist/dashboard/assets/{list-row-Cw07dioc.js → list-row-CM1AaG_y.js} +1 -1
- package/dist/dashboard/assets/list-row-CM1AaG_y.js.gz +0 -0
- package/dist/dashboard/assets/{live-BivGfuUs.js → live-ta6GMb-8.js} +1 -1
- package/dist/dashboard/assets/live-ta6GMb-8.js.gz +0 -0
- package/dist/dashboard/assets/{model-bans-CmffjLuG.js → model-bans-BmYTmbAk.js} +1 -1
- package/dist/dashboard/assets/model-bans-BmYTmbAk.js.gz +0 -0
- package/dist/dashboard/assets/{mutation-46P0oWMe.js → mutation-g_fduiNw.js} +1 -1
- package/dist/dashboard/assets/mutation-g_fduiNw.js.gz +0 -0
- package/dist/dashboard/assets/{numbers-DrdA9oSM.js → numbers-BOevJzdz.js} +1 -1
- package/dist/dashboard/assets/numbers-BOevJzdz.js.gz +0 -0
- package/dist/dashboard/assets/{query-keys-BFhGpwR1.js → query-keys-UETqfytp.js} +1 -1
- package/dist/dashboard/assets/query-keys-UETqfytp.js.gz +0 -0
- package/dist/dashboard/assets/{routing-CAb4F37R.js → routing-BPUo-W8d.js} +1 -1
- package/dist/dashboard/assets/routing-BPUo-W8d.js.gz +0 -0
- package/dist/dashboard/assets/{select-CxVVB__N.js → select-C980c4cz.js} +1 -1
- package/dist/dashboard/assets/select-C980c4cz.js.gz +0 -0
- package/dist/dashboard/assets/{settings-DNX9sydi.js → settings--3hxSyry.js} +1 -1
- package/dist/dashboard/assets/settings--3hxSyry.js.gz +0 -0
- package/dist/dashboard/assets/{stack-uPOwM9Hs.js → stack-_gfTdLVB.js} +1 -1
- package/dist/dashboard/assets/stack-_gfTdLVB.js.gz +0 -0
- package/dist/dashboard/assets/{state-D1Yz79iL.js → state-2c5V4zo7.js} +1 -1
- package/dist/dashboard/assets/state-2c5V4zo7.js.gz +0 -0
- package/dist/dashboard/assets/{switch-sevsRrRo.js → switch-Dkke7Naf.js} +1 -1
- package/dist/dashboard/assets/switch-Dkke7Naf.js.gz +0 -0
- package/dist/dashboard/assets/{useMutation-Dem0lXQj.js → useMutation-EDFRkn1i.js} +1 -1
- package/dist/dashboard/assets/useMutation-EDFRkn1i.js.gz +0 -0
- package/dist/dashboard/index.html +1 -1
- package/dist/dashboard/index.html.gz +0 -0
- package/dist/dashboard/precompressed-assets.json +51 -51
- package/migrations/README.md +52 -52
- package/migrations/full-postgres/0020_add_telemetry_event_analytics.sql +77 -0
- package/migrations/full-postgres/0021_add_api_key_concurrency_tolerance.sql +13 -0
- package/migrations/full-postgres/0022_add_inferhub_config_key.sql +17 -0
- package/migrations/full-postgres/0023_drop_api_key_concurrency_tolerance.sql +13 -0
- package/migrations/lite-sqlite3/0020_add_telemetry_event_analytics.sql +69 -0
- package/migrations/lite-sqlite3/0021_add_api_key_concurrency_tolerance.sql +13 -0
- package/migrations/lite-sqlite3/0022_add_inferhub_config_key.sql +17 -0
- package/migrations/lite-sqlite3/0023_drop_api_key_concurrency_tolerance.sql +13 -0
- package/package.json +96 -95
- package/scripts/cli/admin.ts +126 -128
- package/scripts/cli/autostart.ts +237 -237
- package/scripts/cli/background.ts +120 -110
- package/scripts/cli/bin/carte.cjs +8 -8
- package/scripts/cli/bin/cartethyia.cjs +167 -167
- package/scripts/cli/console-menu.ts +39 -30
- package/scripts/cli/controller.ts +145 -0
- package/scripts/cli/env.ts +99 -99
- package/scripts/cli/gateway.ts +264 -260
- package/scripts/cli/instance.ts +234 -224
- package/scripts/cli/main.ts +188 -167
- package/scripts/cli/platform.ts +64 -64
- package/scripts/cli/prompt.ts +217 -79
- package/scripts/cli/services.ts +88 -88
- package/scripts/cli/setup.ts +445 -445
- package/scripts/cli/start.ts +85 -85
- package/scripts/cli/startup-signal.ts +23 -23
- package/scripts/cli/telemetry.ts +70 -0
- package/scripts/cli/tray/index.ts +263 -263
- package/scripts/cli/tray/windows.ps1 +107 -107
- package/scripts/cli/tray.ts +29 -4
- package/scripts/cli/update.ts +39 -39
- package/scripts/cli/version.ts +67 -67
- package/scripts/cli/wordmark.ts +58 -58
- package/src/boot/app.ts +16 -1
- package/src/boot/dependencies.ts +128 -25
- package/src/config/resources.ts +137 -0
- package/src/config/runtime.ts +133 -76
- package/src/config/spec.ts +30 -29
- package/src/config/telemetry.ts +0 -25
- package/src/console/api-keys/bucket-spend.ts +14 -17
- package/src/console/api-keys/contracts.ts +410 -410
- package/src/console/api-keys/routes.ts +12 -0
- package/src/console/audit/store.ts +2 -3
- package/src/console/auth/setup-service.ts +8 -1
- package/src/console/backup/routes.ts +7 -0
- package/src/console/backup/service.ts +463 -463
- package/src/console/backup/store.ts +16 -11
- package/src/console/backup/validate.ts +1 -4
- package/src/console/cli-tools/fs-ops.ts +18 -2
- package/src/console/data-management/contracts.ts +1 -8
- package/src/console/data-management/operations.ts +61 -48
- package/src/console/data-management/routes.ts +4 -2
- package/src/console/domain-registration.ts +25 -3
- package/src/console/inferhub/client.ts +139 -0
- package/src/console/inferhub/key-store.ts +129 -0
- package/src/console/inferhub/normalize.ts +347 -0
- package/src/console/inferhub/routes.ts +411 -0
- package/src/console/inferhub/store.ts +109 -0
- package/src/console/inferhub/types.ts +183 -0
- package/src/console/observability/contracts.ts +2 -41
- package/src/console/observability/store.ts +176 -371
- package/src/console/providers/catalog/public-model-store.ts +0 -0
- package/src/console/providers/catalog/store.ts +23 -36
- package/src/console/quota/account-quota-shared.ts +52 -52
- package/src/console/quota/account-quota-tenant.ts +16 -24
- package/src/console/quota/refresh.ts +441 -441
- package/src/console/routing/pools/import-parse.ts +206 -206
- package/src/console/routing/pools/operations.ts +543 -543
- package/src/console/routing/pools/probe-verdict.ts +132 -132
- package/src/console/routing/pools/routes.ts +181 -181
- package/src/console/settings/contracts.ts +42 -40
- package/src/console/settings/store.ts +25 -25
- package/src/console/share/share-stats.ts +22 -4
- package/src/console/share/share-usage.ts +30 -4
- package/src/console/shared/cursor.ts +15 -0
- package/src/console/updates/routes.ts +12 -0
- package/src/main.ts +13 -5
- package/src/network/pool/resolver.ts +1104 -1104
- package/src/observability/client-name.ts +22 -0
- package/src/observability/event-log.ts +5 -29
- package/src/observability/event-query.ts +690 -0
- package/src/observability/log-ring.ts +26 -2
- package/src/observability/log-sanitize.ts +118 -0
- package/src/observability/logger.ts +17 -13
- package/src/observability/metrics.ts +35 -0
- package/src/observability/payload-capture.ts +114 -41
- package/src/observability/payload-store.ts +249 -24
- package/src/observability/raw-event-writer.ts +118 -0
- package/src/observability/runtime-metrics.ts +71 -1
- package/src/observability/telemetry-buffer.ts +100 -17
- package/src/observability/telemetry-reconciliation.ts +417 -0
- package/src/persistence/boot.ts +20 -9
- package/src/persistence/db-pg.ts +13 -0
- package/src/persistence/db-sqlite.ts +569 -497
- package/src/persistence/dialect.ts +3 -2
- package/src/persistence/migrate.ts +181 -181
- package/src/persistence/schema.ts +1496 -1406
- package/src/persistence/shared-cache.ts +5 -1
- package/src/persistence/stores/api-key-store.ts +581 -581
- package/src/persistence/stores/telemetry-store.ts +124 -63
- package/src/protocol/reasoning-text.ts +30 -0
- package/src/protocol/response/chat.ts +33 -7
- package/src/protocol/response/codex.ts +14 -2
- package/src/protocol/response/messages.ts +5 -2
- package/src/providers/authentication/oauth-flow-store.ts +3 -10
- package/src/providers/bundled-discovery-providers.ts +122 -122
- package/src/providers/default-registry.ts +10 -0
- package/src/providers/discovery/catalog/catalog-blob.ts +18 -18
- package/src/providers/discovery/models-dev-catalog.ts +354 -354
- package/src/providers/discovery/probe-phases.ts +43 -7
- package/src/providers/discovery/probing-service.ts +70 -32
- package/src/providers/integrations/antigravity/antigravity.ts +9 -2
- package/src/providers/integrations/buddy/buddy-catalog-shared.ts +85 -17
- package/src/providers/integrations/buddy/buddy-chat-shared.ts +934 -934
- package/src/providers/integrations/buddy/buddy-checkin.ts +5 -9
- package/src/providers/integrations/buddy/buddy-discovery-shared.ts +3 -7
- package/src/providers/integrations/buddy/buddy-quota-shared.ts +3 -1
- package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +57 -49
- package/src/providers/integrations/buddy/codebuddy/provider.ts +180 -180
- package/src/providers/integrations/buddy/workbuddy/provider.ts +206 -206
- package/src/providers/integrations/buddy/workbuddy/quota.ts +161 -161
- package/src/providers/integrations/claude/claude-quota.ts +2 -2
- package/src/providers/integrations/claude/claude-user-profiles.ts +3 -2
- package/src/providers/integrations/claude/claude.ts +3 -4
- package/src/providers/integrations/cline/cline.ts +94 -8
- package/src/providers/integrations/codex/codex.ts +61 -37
- package/src/providers/integrations/cursor/cursor-catalog.ts +368 -368
- package/src/providers/integrations/cursor/cursor-http2.ts +300 -300
- package/src/providers/integrations/cursor/cursor-identity.ts +2 -4
- package/src/providers/integrations/cursor/cursor-request.ts +11 -0
- package/src/providers/integrations/cursor/cursor.ts +29 -17
- package/src/providers/integrations/cursor/protocol/framing.ts +129 -129
- package/src/providers/integrations/cursor/protocol/messages.ts +2380 -2380
- package/src/providers/integrations/cursor/protocol/struct.ts +305 -305
- package/src/providers/integrations/cursor/protocol/tool-canonical.ts +275 -0
- package/src/providers/integrations/grok/grok-quota.ts +279 -279
- package/src/providers/integrations/grok/grok-ratelimit-store.ts +73 -73
- package/src/providers/integrations/grok/grok-ratelimit.ts +218 -218
- package/src/providers/integrations/hermes.ts +7 -1
- package/src/providers/integrations/inferhub.ts +201 -73
- package/src/providers/integrations/kilo/kilo.ts +152 -152
- package/src/providers/integrations/kiro/kiro-machine-id.ts +2 -4
- package/src/providers/integrations/openrouter/provider.ts +129 -129
- package/src/providers/integrations/qoder/qoder-quota.ts +193 -192
- package/src/providers/integrations/qoder/qoder-realm.ts +106 -106
- package/src/providers/integrations/trae/trae-oauth.ts +4 -26
- package/src/providers/integrations/trae/trae-quota.ts +389 -384
- package/src/providers/integrations/trae/trae-realm.ts +15 -2
- package/src/providers/integrations/xiaomi-mimo/think-stream.ts +100 -24
- package/src/providers/integrations/zcode/oauth.ts +1 -1
- package/src/providers/operations/account-health-service.ts +605 -279
- package/src/providers/provider-metadata.ts +12 -1
- package/src/providers/provider-model-definition.ts +373 -373
- package/src/providers/quota/quota-contracts.ts +3 -7
- package/src/providers/search/search-provider.ts +2 -6
- package/src/security/admission/contracts.ts +10 -0
- package/src/security/admission/in-memory-store.ts +89 -14
- package/src/security/admission/lua.ts +191 -182
- package/src/security/admission/redis-store.ts +30 -0
- package/src/security/admission/service.ts +18 -0
- package/src/security/api-key-auth-cache.ts +96 -0
- package/src/security/api-key-auth.ts +11 -100
- package/src/security/client-router-fingerprint.ts +3 -7
- package/src/security/ip-boundary.ts +7 -3
- package/src/shared/coerce.ts +67 -0
- package/src/shared/hash.ts +6 -0
- package/src/shared/time.ts +7 -0
- package/src/transport/dispatch/attempt-finalize.ts +26 -138
- package/src/transport/dispatch/attempt-loop.ts +103 -81
- package/src/transport/dispatch/capture-policy.ts +78 -0
- package/src/transport/dispatch/proxy-request.ts +4 -2
- package/src/transport/dispatch/streaming/encoder.ts +111 -5
- package/src/transport/dispatch/streaming/stream.ts +19 -2
- package/src/transport/dispatch/streaming/thinking-loop.ts +300 -0
- package/src/transport/failure-policy.ts +27 -0
- package/src/transport/guards/abuse-guard.ts +2 -2
- package/src/transport/guards/auth-guard.ts +17 -0
- package/src/transport/guards/body-policy.ts +3 -2
- package/src/transport/guards/concurrency-guard.ts +89 -13
- package/src/transport/guards/early-rejection-capture.ts +43 -3
- package/src/transport/guards/error-lifecycle.ts +10 -2
- package/src/transport/guards/guard-errors.ts +23 -0
- package/src/transport/guards/headroom-guard.ts +41 -7
- package/src/transport/guards/pipeline.ts +24 -0
- package/src/transport/guards/request-context.ts +2 -1
- package/src/transport/routing/admission.ts +51 -9
- package/src/transport/routing/bounded-lru.ts +49 -0
- package/src/transport/routing/candidate-index.ts +88 -0
- package/src/transport/routing/reservations.ts +121 -7
- package/src/transport/routing/round-robin.ts +10 -22
- package/src/transport/routing/route-catalog.ts +26 -13
- package/src/transport/routing/route-model.ts +22 -2
- package/src/transport/routing/router.ts +53 -31
- package/src/transport/surface/chat/encode.ts +2 -3
- package/src/transport/surface/chat/parse.ts +2 -1
- package/src/transport/surface/dialects.ts +11 -3
- package/src/transport/surface/messages/encode.ts +2 -1
- package/src/transport/surface/messages/parse.ts +3 -1
- package/src/transport/surface/messages/stream.ts +2 -6
- package/src/workers/maintenance-lease.ts +200 -0
- package/src/workers/scheduler.ts +101 -1
- package/dist/dashboard/assets/BannedPage-Cd30Z0b9.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-wf5u-ww6.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-DykPvuck.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-DwvSD3vs.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-CIr7KDex.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-82X0DDdH.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-BYPucTTn.js +0 -1
- package/dist/dashboard/assets/HealthEventsModal-BYPucTTn.js.gz +0 -0
- package/dist/dashboard/assets/LoginPage-CS5mPuVF.js.gz +0 -0
- package/dist/dashboard/assets/ModelPicker-C0UCUsVJ.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-Dk_ew3YU.js +0 -1
- package/dist/dashboard/assets/OverviewPage-Dk_ew3YU.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-CAiRn2Q0.js +0 -3
- package/dist/dashboard/assets/ProviderDetailPage-CAiRn2Q0.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-vdja5ZPK.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-BB4CNm4-.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-FEc4iNyq.js +0 -1
- package/dist/dashboard/assets/QuotaPage-FEc4iNyq.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-Dlfi5L4N.js +0 -1
- package/dist/dashboard/assets/SettingsPage-Dlfi5L4N.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-FadUOl9S.js.gz +0 -0
- package/dist/dashboard/assets/SortableList-Cfy6_Khv.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-BT4MyQeT.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-DQYLQxpW.js.gz +0 -0
- package/dist/dashboard/assets/app-CX_Z8cMs.css +0 -2
- package/dist/dashboard/assets/app-CX_Z8cMs.css.gz +0 -0
- package/dist/dashboard/assets/assert-C9FD_JwJ.js.gz +0 -0
- package/dist/dashboard/assets/badge-Bvyr7D0u.js.gz +0 -0
- package/dist/dashboard/assets/banner-DIvKAZih.js.gz +0 -0
- package/dist/dashboard/assets/card-D5_gYIS_.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-CNqzrfdb.js.gz +0 -0
- package/dist/dashboard/assets/clipboard-button-B6vDBtbm.js.gz +0 -0
- package/dist/dashboard/assets/dialog-CpjrgdwJ.js.gz +0 -0
- package/dist/dashboard/assets/drawer-BWmt3b5y.js.gz +0 -0
- package/dist/dashboard/assets/entry-B-gvimrg.js +0 -1
- package/dist/dashboard/assets/entry-B-gvimrg.js.gz +0 -0
- package/dist/dashboard/assets/entry-C_oakV3z.js.gz +0 -0
- package/dist/dashboard/assets/entry-Dj0cHfEc.js +0 -4
- package/dist/dashboard/assets/entry-Dj0cHfEc.js.gz +0 -0
- package/dist/dashboard/assets/github-badge-RRHHWGxh.js.gz +0 -0
- package/dist/dashboard/assets/index-Bhey_rg_.js.gz +0 -0
- package/dist/dashboard/assets/inline-C2_EQ5Uf.js.gz +0 -0
- package/dist/dashboard/assets/input-BMRlQ450.js.gz +0 -0
- package/dist/dashboard/assets/layout-XR5xP8ew.js.gz +0 -0
- package/dist/dashboard/assets/list-row-Cw07dioc.js.gz +0 -0
- package/dist/dashboard/assets/live-BivGfuUs.js.gz +0 -0
- package/dist/dashboard/assets/model-bans-CmffjLuG.js.gz +0 -0
- package/dist/dashboard/assets/mutation-46P0oWMe.js.gz +0 -0
- package/dist/dashboard/assets/numbers-DrdA9oSM.js.gz +0 -0
- package/dist/dashboard/assets/query-keys-BFhGpwR1.js.gz +0 -0
- package/dist/dashboard/assets/routing-CAb4F37R.js.gz +0 -0
- package/dist/dashboard/assets/select-CxVVB__N.js.gz +0 -0
- package/dist/dashboard/assets/settings-DNX9sydi.js.gz +0 -0
- package/dist/dashboard/assets/stack-uPOwM9Hs.js.gz +0 -0
- package/dist/dashboard/assets/state-D1Yz79iL.js.gz +0 -0
- package/dist/dashboard/assets/switch-sevsRrRo.js.gz +0 -0
- package/dist/dashboard/assets/useMutation-Dem0lXQj.js.gz +0 -0
- package/src/observability/event-compaction.ts +0 -317
- package/src/observability/event-day-index.ts +0 -439
package/scripts/cli/start.ts
CHANGED
|
@@ -1,85 +1,85 @@
|
|
|
1
|
-
import { resolvePort } from "../../src/config/runtime";
|
|
2
|
-
import { ensureDrainToken } from "./instance";
|
|
3
|
-
import { clearInstanceLock, pidAlive, readInstanceLock, writeInstanceLock } from "./instance";
|
|
4
|
-
import { blockedPortMessage, listenPortErrorMessage, probeListenPort } from "./port";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Runs the gateway in the foreground, in this process.
|
|
8
|
-
*
|
|
9
|
-
* A foreground run still needs a drain token on disk: the gateway registers
|
|
10
|
-
* `/admin/drain` only when one is set, and "Hide to tray" hands this run to a
|
|
11
|
-
* tray that drains it through that route.
|
|
12
|
-
*
|
|
13
|
-
* Unlike the menu and tray paths this one does not spawn a child, so the
|
|
14
|
-
* port-busy check has to happen here too — otherwise a stale gateway makes a
|
|
15
|
-
* plain `cartethyia start` fail from inside `src/main` with a message that says
|
|
16
|
-
* nothing about what to do.
|
|
17
|
-
*/
|
|
18
|
-
export async function startForeground(): Promise<void> {
|
|
19
|
-
const token = ensureDrainToken();
|
|
20
|
-
process.env.CARTETHYIA_DRAIN_TOKEN ??= token;
|
|
21
|
-
const port = resolvePort();
|
|
22
|
-
const probe = await probeListenPort(port);
|
|
23
|
-
if (probe.status === "blocked" && probe.code !== "EADDRINUSE") {
|
|
24
|
-
throw new Error(listenPortErrorMessage(port, probe));
|
|
25
|
-
}
|
|
26
|
-
const blocker = await inspectPortHolder(port, token);
|
|
27
|
-
if (blocker !== null) throw new Error(blocker);
|
|
28
|
-
writeInstanceLock(port, process.pid, token);
|
|
29
|
-
// dynamic-import: `src/main` boots the gateway as a side effect of module
|
|
30
|
-
// evaluation. Importing it statically would start the server before the
|
|
31
|
-
// port probe + instance-lock sequence above has a chance to refuse the run.
|
|
32
|
-
await import("../../src/main");
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* What to tell the operator when the port is already taken, or `null` when the
|
|
37
|
-
* port is free (or was freed).
|
|
38
|
-
*
|
|
39
|
-
* Same rule as the spawned path: only ever stop a gateway that proves it is
|
|
40
|
-
* this install's own. A drain request is token-gated, so a 401 means another
|
|
41
|
-
* Cartethyia install and anything else is not a gateway at all — neither may be
|
|
42
|
-
* touched, and both are reported instead.
|
|
43
|
-
*/
|
|
44
|
-
async function inspectPortHolder(port: number, token: string): Promise<string | null> {
|
|
45
|
-
const up = await fetch(`http://127.0.0.1:${port}/health`, {
|
|
46
|
-
signal: AbortSignal.timeout(1_000),
|
|
47
|
-
}).catch(() => null);
|
|
48
|
-
if (up === null) {
|
|
49
|
-
// Port is free. Drop a stale marker from a crashed run so the next start
|
|
50
|
-
// does not read a dead pid as a live gateway.
|
|
51
|
-
const lock = readInstanceLock();
|
|
52
|
-
if (lock !== null && lock.port === port && !pidAlive(lock.pid)) clearInstanceLock();
|
|
53
|
-
return null;
|
|
54
|
-
}
|
|
55
|
-
const response = await fetch(`http://127.0.0.1:${port}/admin/drain`, {
|
|
56
|
-
method: "POST",
|
|
57
|
-
headers: { "x-drain-token": token },
|
|
58
|
-
signal: AbortSignal.timeout(3_000),
|
|
59
|
-
}).catch(() => null);
|
|
60
|
-
if (response === null) {
|
|
61
|
-
return blockedPortMessage(port);
|
|
62
|
-
}
|
|
63
|
-
if (response.status === 401) {
|
|
64
|
-
return `Another Cartethyia gateway is already running on port ${port} under a different install. Stop it from its own terminal or tray — this install will not stop a gateway it does not own.`;
|
|
65
|
-
}
|
|
66
|
-
if (response.status === 403) {
|
|
67
|
-
return `Port ${port} refused a drain from loopback. Stop what holds it, then start again.`;
|
|
68
|
-
}
|
|
69
|
-
if (response.status !== 202) {
|
|
70
|
-
return `Port ${port} is busy and refused to drain (HTTP ${response.status}). Stop it manually, then start again.`;
|
|
71
|
-
}
|
|
72
|
-
// Drain accepted; wait for the port to actually close.
|
|
73
|
-
const deadline = Date.now() + 30_000;
|
|
74
|
-
while (Date.now() < deadline) {
|
|
75
|
-
const stillUp = await fetch(`http://127.0.0.1:${port}/health`, {
|
|
76
|
-
signal: AbortSignal.timeout(500),
|
|
77
|
-
}).catch(() => null);
|
|
78
|
-
if (stillUp === null) {
|
|
79
|
-
clearInstanceLock();
|
|
80
|
-
return null;
|
|
81
|
-
}
|
|
82
|
-
await Bun.sleep(200);
|
|
83
|
-
}
|
|
84
|
-
return `The gateway on port ${port} accepted a drain but did not release the port within 30 seconds. Stop it manually, then start again.`;
|
|
85
|
-
}
|
|
1
|
+
import { resolvePort } from "../../src/config/runtime";
|
|
2
|
+
import { ensureDrainToken } from "./instance";
|
|
3
|
+
import { clearInstanceLock, pidAlive, readInstanceLock, writeInstanceLock } from "./instance";
|
|
4
|
+
import { blockedPortMessage, listenPortErrorMessage, probeListenPort } from "./port";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Runs the gateway in the foreground, in this process.
|
|
8
|
+
*
|
|
9
|
+
* A foreground run still needs a drain token on disk: the gateway registers
|
|
10
|
+
* `/admin/drain` only when one is set, and "Hide to tray" hands this run to a
|
|
11
|
+
* tray that drains it through that route.
|
|
12
|
+
*
|
|
13
|
+
* Unlike the menu and tray paths this one does not spawn a child, so the
|
|
14
|
+
* port-busy check has to happen here too — otherwise a stale gateway makes a
|
|
15
|
+
* plain `cartethyia start` fail from inside `src/main` with a message that says
|
|
16
|
+
* nothing about what to do.
|
|
17
|
+
*/
|
|
18
|
+
export async function startForeground(): Promise<void> {
|
|
19
|
+
const token = ensureDrainToken();
|
|
20
|
+
process.env.CARTETHYIA_DRAIN_TOKEN ??= token;
|
|
21
|
+
const port = resolvePort();
|
|
22
|
+
const probe = await probeListenPort(port);
|
|
23
|
+
if (probe.status === "blocked" && probe.code !== "EADDRINUSE") {
|
|
24
|
+
throw new Error(listenPortErrorMessage(port, probe));
|
|
25
|
+
}
|
|
26
|
+
const blocker = await inspectPortHolder(port, token);
|
|
27
|
+
if (blocker !== null) throw new Error(blocker);
|
|
28
|
+
writeInstanceLock(port, process.pid, token);
|
|
29
|
+
// dynamic-import: `src/main` boots the gateway as a side effect of module
|
|
30
|
+
// evaluation. Importing it statically would start the server before the
|
|
31
|
+
// port probe + instance-lock sequence above has a chance to refuse the run.
|
|
32
|
+
await import("../../src/main");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* What to tell the operator when the port is already taken, or `null` when the
|
|
37
|
+
* port is free (or was freed).
|
|
38
|
+
*
|
|
39
|
+
* Same rule as the spawned path: only ever stop a gateway that proves it is
|
|
40
|
+
* this install's own. A drain request is token-gated, so a 401 means another
|
|
41
|
+
* Cartethyia install and anything else is not a gateway at all — neither may be
|
|
42
|
+
* touched, and both are reported instead.
|
|
43
|
+
*/
|
|
44
|
+
async function inspectPortHolder(port: number, token: string): Promise<string | null> {
|
|
45
|
+
const up = await fetch(`http://127.0.0.1:${port}/health`, {
|
|
46
|
+
signal: AbortSignal.timeout(1_000),
|
|
47
|
+
}).catch(() => null);
|
|
48
|
+
if (up === null) {
|
|
49
|
+
// Port is free. Drop a stale marker from a crashed run so the next start
|
|
50
|
+
// does not read a dead pid as a live gateway.
|
|
51
|
+
const lock = readInstanceLock();
|
|
52
|
+
if (lock !== null && lock.port === port && !pidAlive(lock.pid)) clearInstanceLock();
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
const response = await fetch(`http://127.0.0.1:${port}/admin/drain`, {
|
|
56
|
+
method: "POST",
|
|
57
|
+
headers: { "x-drain-token": token },
|
|
58
|
+
signal: AbortSignal.timeout(3_000),
|
|
59
|
+
}).catch(() => null);
|
|
60
|
+
if (response === null) {
|
|
61
|
+
return blockedPortMessage(port);
|
|
62
|
+
}
|
|
63
|
+
if (response.status === 401) {
|
|
64
|
+
return `Another Cartethyia gateway is already running on port ${port} under a different install. Stop it from its own terminal or tray — this install will not stop a gateway it does not own.`;
|
|
65
|
+
}
|
|
66
|
+
if (response.status === 403) {
|
|
67
|
+
return `Port ${port} refused a drain from loopback. Stop what holds it, then start again.`;
|
|
68
|
+
}
|
|
69
|
+
if (response.status !== 202) {
|
|
70
|
+
return `Port ${port} is busy and refused to drain (HTTP ${response.status}). Stop it manually, then start again.`;
|
|
71
|
+
}
|
|
72
|
+
// Drain accepted; wait for the port to actually close.
|
|
73
|
+
const deadline = Date.now() + 30_000;
|
|
74
|
+
while (Date.now() < deadline) {
|
|
75
|
+
const stillUp = await fetch(`http://127.0.0.1:${port}/health`, {
|
|
76
|
+
signal: AbortSignal.timeout(500),
|
|
77
|
+
}).catch(() => null);
|
|
78
|
+
if (stillUp === null) {
|
|
79
|
+
clearInstanceLock();
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
await Bun.sleep(200);
|
|
83
|
+
}
|
|
84
|
+
return `The gateway on port ${port} accepted a drain but did not release the port within 30 seconds. Stop it manually, then start again.`;
|
|
85
|
+
}
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import { writeFileSync } from "node:fs";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Reports tray readiness to the launcher that is waiting on a signal file.
|
|
5
|
-
*
|
|
6
|
-
* The tray is spawned detached with no stdio, so the launcher cannot read its
|
|
7
|
-
* output; a one-shot file is the only channel that survives the parent exiting.
|
|
8
|
-
* `flag: "wx"` makes the write fail rather than overwrite, which keeps a late
|
|
9
|
-
* report from replacing the failure the launcher already acted on.
|
|
10
|
-
*/
|
|
11
|
-
export type TrayStartupSignal =
|
|
12
|
-
| { readonly status: "ready"; readonly url: string }
|
|
13
|
-
| { readonly status: "failed"; readonly message: string };
|
|
14
|
-
|
|
15
|
-
export function reportTrayStartup(signal: TrayStartupSignal): void {
|
|
16
|
-
const signalPath = process.env.CARTETHYIA_TRAY_STARTUP_SIGNAL;
|
|
17
|
-
if (!signalPath) return;
|
|
18
|
-
try {
|
|
19
|
-
writeFileSync(signalPath, JSON.stringify(signal), { encoding: "utf8", flag: "wx" });
|
|
20
|
-
} catch {
|
|
21
|
-
// The launcher may have timed out and removed the one-shot signal file.
|
|
22
|
-
}
|
|
23
|
-
}
|
|
1
|
+
import { writeFileSync } from "node:fs";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Reports tray readiness to the launcher that is waiting on a signal file.
|
|
5
|
+
*
|
|
6
|
+
* The tray is spawned detached with no stdio, so the launcher cannot read its
|
|
7
|
+
* output; a one-shot file is the only channel that survives the parent exiting.
|
|
8
|
+
* `flag: "wx"` makes the write fail rather than overwrite, which keeps a late
|
|
9
|
+
* report from replacing the failure the launcher already acted on.
|
|
10
|
+
*/
|
|
11
|
+
export type TrayStartupSignal =
|
|
12
|
+
| { readonly status: "ready"; readonly url: string }
|
|
13
|
+
| { readonly status: "failed"; readonly message: string };
|
|
14
|
+
|
|
15
|
+
export function reportTrayStartup(signal: TrayStartupSignal): void {
|
|
16
|
+
const signalPath = process.env.CARTETHYIA_TRAY_STARTUP_SIGNAL;
|
|
17
|
+
if (!signalPath) return;
|
|
18
|
+
try {
|
|
19
|
+
writeFileSync(signalPath, JSON.stringify(signal), { encoding: "utf8", flag: "wx" });
|
|
20
|
+
} catch {
|
|
21
|
+
// The launcher may have timed out and removed the one-shot signal file.
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `carte telemetry reconcile` — recovers telemetry rows the SQL table missed.
|
|
3
|
+
*
|
|
4
|
+
* The durable record is `telemetry_events`, written in the same transaction as
|
|
5
|
+
* the request's admission/usage accounting. The raw JSONL files are an
|
|
6
|
+
* at-least-once mirror: a crash between the raw append and the commit can
|
|
7
|
+
* leave a line whose row never landed. This command drains that gap, and is
|
|
8
|
+
* also how a deployment that predates the SQL table gets its history back.
|
|
9
|
+
*
|
|
10
|
+
* It talks to the database directly (not through the gateway) because the
|
|
11
|
+
* gateway may be down — a reconciliation is exactly what you run after an
|
|
12
|
+
* incident — and because the job is lease-guarded, so it is safe even with the
|
|
13
|
+
* gateway up and writing.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { bootDatabase, closeDb, getDb } from "../../src/persistence/boot";
|
|
17
|
+
import { reconcileTelemetry } from "../../src/observability/telemetry-reconciliation";
|
|
18
|
+
|
|
19
|
+
function usage(): string {
|
|
20
|
+
return [
|
|
21
|
+
"Usage:",
|
|
22
|
+
" cartethyia telemetry reconcile --verify report the gap, write nothing",
|
|
23
|
+
" cartethyia telemetry reconcile --apply insert the missing rows",
|
|
24
|
+
"",
|
|
25
|
+
"--verify is read-only and takes no lease, so it is safe to run while the",
|
|
26
|
+
"gateway is serving. --apply holds a lease for the duration of the run;",
|
|
27
|
+
"a second invocation reports `lease_held` and exits without writing.",
|
|
28
|
+
"",
|
|
29
|
+
"Usage counters (telemetry_usage_totals) are never modified: they were",
|
|
30
|
+
"charged at request time, and re-charging from a backfill would inflate",
|
|
31
|
+
"every dashboard figure for the affected window.",
|
|
32
|
+
].join("\n");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export async function telemetry(argv: readonly string[]): Promise<void> {
|
|
36
|
+
const mode = argv.find((arg) => arg === "--apply" || arg === "--verify");
|
|
37
|
+
if (mode === undefined) {
|
|
38
|
+
console.error(`No mode given.\n\n${usage()}`);
|
|
39
|
+
process.exitCode = 2;
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
await bootDatabase();
|
|
44
|
+
try {
|
|
45
|
+
const report = await reconcileTelemetry(getDb(), { verify: mode === "--verify" });
|
|
46
|
+
if (!report.ran) {
|
|
47
|
+
const why =
|
|
48
|
+
report.skippedReason === "lease_held"
|
|
49
|
+
? "another runner holds the lease — try again later"
|
|
50
|
+
: report.skippedReason === "no_files"
|
|
51
|
+
? "no eligible raw telemetry files (the current and previous UTC hour are always skipped)"
|
|
52
|
+
: "checkpoint is up to date — nothing to reconcile";
|
|
53
|
+
console.log(`telemetry reconcile (${mode}): skipped — ${why}`);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
console.log(
|
|
57
|
+
[
|
|
58
|
+
`telemetry reconcile (${mode}): done`,
|
|
59
|
+
` files completed : ${report.filesCompleted}`,
|
|
60
|
+
` events examined : ${report.eventsExamined}`,
|
|
61
|
+
` events inserted : ${report.eventsInserted}`,
|
|
62
|
+
` conflicts : ${report.conflicts} (already present)`,
|
|
63
|
+
` bytes read : ${report.bytesRead}`,
|
|
64
|
+
].join("\n"),
|
|
65
|
+
);
|
|
66
|
+
} finally {
|
|
67
|
+
await closeDb().catch(() => undefined);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|