cartethyia 2.5.9 → 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 +15 -42
- package/README.md +11 -10
- package/dist/dashboard/assets/{BannedPage-Brvuj_Eb.js → BannedPage-l6XMnfr9.js} +1 -1
- package/dist/dashboard/assets/BannedPage-l6XMnfr9.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolDetailPage-CqfXtI3y.js → CliToolDetailPage-DwOzAW45.js} +1 -1
- package/dist/dashboard/assets/CliToolDetailPage-DwOzAW45.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolsPage-GQeS91bg.js → CliToolsPage-BT3Up3QA.js} +1 -1
- package/dist/dashboard/assets/CliToolsPage-BT3Up3QA.js.gz +0 -0
- package/dist/dashboard/assets/{CombosPage-BDRsTXBB.js → CombosPage-6kYIUpzR.js} +1 -1
- package/dist/dashboard/assets/CombosPage-6kYIUpzR.js.gz +0 -0
- package/dist/dashboard/assets/{ConsoleLogPage-zP8AFHX0.js → ConsoleLogPage-zRnj1mlR.js} +1 -1
- package/dist/dashboard/assets/ConsoleLogPage-zRnj1mlR.js.gz +0 -0
- package/dist/dashboard/assets/{CustomizationPage-BmfrNZ14.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-DoreIgm8.js → LoginPage-CbphLvjg.js} +1 -1
- package/dist/dashboard/assets/LoginPage-CbphLvjg.js.gz +0 -0
- package/dist/dashboard/assets/{ModelPicker-C7pDb41R.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-BnoPgA7w.js → ProvidersPage-Dfb2896L.js} +1 -1
- package/dist/dashboard/assets/ProvidersPage-Dfb2896L.js.gz +0 -0
- package/dist/dashboard/assets/{ProxyPage-Bq_TGgdb.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-Day3mCOn.js → SetupPage-D4g6vOGc.js} +1 -1
- package/dist/dashboard/assets/SetupPage-D4g6vOGc.js.gz +0 -0
- package/dist/dashboard/assets/{SortableList-DQxllnB5.js → SortableList-C93i14BD.js} +1 -1
- package/dist/dashboard/assets/SortableList-C93i14BD.js.gz +0 -0
- package/dist/dashboard/assets/{StudioPage-uMExoWu1.js → StudioPage-SgQpymjm.js} +1 -1
- package/dist/dashboard/assets/{StudioPage-uMExoWu1.js.gz → StudioPage-SgQpymjm.js.gz} +0 -0
- package/dist/dashboard/assets/{UsagePage-DXa1oR-4.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-BIt446yE.js → app-2KhtHCv9.js} +1 -1
- package/dist/dashboard/assets/{app-BIt446yE.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-CR72dasT.js → badge-CKsF123d.js} +1 -1
- package/dist/dashboard/assets/badge-CKsF123d.js.gz +0 -0
- package/dist/dashboard/assets/{banner-CI9_eSfO.js → banner-8j7uChA9.js} +1 -1
- package/dist/dashboard/assets/banner-8j7uChA9.js.gz +0 -0
- package/dist/dashboard/assets/{card-DS7CQEsO.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-611pSsaX.js → clipboard-button-uL5aYLfW.js} +1 -1
- package/dist/dashboard/assets/clipboard-button-uL5aYLfW.js.gz +0 -0
- package/dist/dashboard/assets/{dialog-k37exjNt.js → dialog-C07hr5_G.js} +1 -1
- package/dist/dashboard/assets/dialog-C07hr5_G.js.gz +0 -0
- package/dist/dashboard/assets/{drawer-CX7N8ucR.js → drawer-BPO1TcKH.js} +1 -1
- package/dist/dashboard/assets/drawer-BPO1TcKH.js.gz +0 -0
- package/dist/dashboard/assets/{entry-CTP8AyiS.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-sltk1qUi.js → github-badge-DmQreSDd.js} +1 -1
- package/dist/dashboard/assets/github-badge-DmQreSDd.js.gz +0 -0
- package/dist/dashboard/assets/{index-z3zDOSMM.js → index-Bblu6erR.js} +2 -2
- package/dist/dashboard/assets/index-Bblu6erR.js.gz +0 -0
- package/dist/dashboard/assets/{inline-BhY2sSnO.js → inline-C9dCYaBZ.js} +1 -1
- package/dist/dashboard/assets/inline-C9dCYaBZ.js.gz +0 -0
- package/dist/dashboard/assets/{input-V1umFiBk.js → input-CjCnXweJ.js} +1 -1
- package/dist/dashboard/assets/input-CjCnXweJ.js.gz +0 -0
- package/dist/dashboard/assets/{layout-BBOYycyS.js → layout-V6y8DAkl.js} +1 -1
- package/dist/dashboard/assets/layout-V6y8DAkl.js.gz +0 -0
- package/dist/dashboard/assets/{list-row-1zzZYM0B.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-DkfMR5Qs.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-C6MMiaio.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-BHTfXdz_.js → stack-_gfTdLVB.js} +1 -1
- package/dist/dashboard/assets/stack-_gfTdLVB.js.gz +0 -0
- package/dist/dashboard/assets/{state-mPDRlQkl.js → state-2c5V4zo7.js} +1 -1
- package/dist/dashboard/assets/state-2c5V4zo7.js.gz +0 -0
- package/dist/dashboard/assets/{switch-DOmJxg7H.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 -97
- package/scripts/cli/admin.ts +126 -125
- 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 +308 -275
- package/scripts/cli/controller.ts +145 -0
- package/scripts/cli/doctor.ts +1 -1
- package/scripts/cli/env.ts +99 -99
- package/scripts/cli/gateway.ts +264 -261
- package/scripts/{health.ts → cli/health.ts} +4 -4
- package/scripts/cli/instance.ts +234 -224
- package/scripts/cli/main.ts +188 -164
- package/scripts/cli/platform.ts +64 -64
- package/scripts/cli/prompt.ts +275 -107
- package/scripts/cli/services.ts +88 -88
- package/scripts/cli/setup.ts +445 -445
- package/scripts/cli/start.ts +85 -82
- 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 +192 -208
- 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/package-paths.ts +24 -0
- 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/remote-support/service.ts +270 -114
- 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/routing/pools/store.ts +1 -1
- 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/repository-updates.ts +40 -39
- 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/registry.ts +2 -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 +14 -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/capabilities.ts +4 -0
- 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/github/github.ts +3 -1
- 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/opencode/provider.ts +2 -0
- 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-headers.ts +17 -48
- 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/trae/trae.ts +22 -24
- 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/provider-probe.ts +3 -0
- 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-Brvuj_Eb.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-CqfXtI3y.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-GQeS91bg.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-BDRsTXBB.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-zP8AFHX0.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-BmfrNZ14.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-Dn3M6WZc.js +0 -1
- package/dist/dashboard/assets/HealthEventsModal-Dn3M6WZc.js.gz +0 -0
- package/dist/dashboard/assets/LoginPage-DoreIgm8.js.gz +0 -0
- package/dist/dashboard/assets/ModelPicker-C7pDb41R.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-CvvD1Ugk.js +0 -1
- package/dist/dashboard/assets/OverviewPage-CvvD1Ugk.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-Clbn1gsW.js +0 -3
- package/dist/dashboard/assets/ProviderDetailPage-Clbn1gsW.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-BnoPgA7w.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-Bq_TGgdb.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-D9DHXvom.js +0 -1
- package/dist/dashboard/assets/QuotaPage-D9DHXvom.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-7xV8WkWL.js +0 -1
- package/dist/dashboard/assets/SettingsPage-7xV8WkWL.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-Day3mCOn.js.gz +0 -0
- package/dist/dashboard/assets/SortableList-DQxllnB5.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-DXa1oR-4.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-CR72dasT.js.gz +0 -0
- package/dist/dashboard/assets/banner-CI9_eSfO.js.gz +0 -0
- package/dist/dashboard/assets/card-DS7CQEsO.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-CNqzrfdb.js.gz +0 -0
- package/dist/dashboard/assets/clipboard-button-611pSsaX.js.gz +0 -0
- package/dist/dashboard/assets/dialog-k37exjNt.js.gz +0 -0
- package/dist/dashboard/assets/drawer-CX7N8ucR.js.gz +0 -0
- package/dist/dashboard/assets/entry-B9Xvtnfj.js +0 -1
- package/dist/dashboard/assets/entry-B9Xvtnfj.js.gz +0 -0
- package/dist/dashboard/assets/entry-ByMGkR3C.js +0 -4
- package/dist/dashboard/assets/entry-ByMGkR3C.js.gz +0 -0
- package/dist/dashboard/assets/entry-CTP8AyiS.js.gz +0 -0
- package/dist/dashboard/assets/github-badge-sltk1qUi.js.gz +0 -0
- package/dist/dashboard/assets/index-z3zDOSMM.js.gz +0 -0
- package/dist/dashboard/assets/inline-BhY2sSnO.js.gz +0 -0
- package/dist/dashboard/assets/input-V1umFiBk.js.gz +0 -0
- package/dist/dashboard/assets/layout-BBOYycyS.js.gz +0 -0
- package/dist/dashboard/assets/list-row-1zzZYM0B.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-DkfMR5Qs.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-C6MMiaio.js.gz +0 -0
- package/dist/dashboard/assets/settings-DNX9sydi.js.gz +0 -0
- package/dist/dashboard/assets/stack-BHTfXdz_.js.gz +0 -0
- package/dist/dashboard/assets/state-mPDRlQkl.js.gz +0 -0
- package/dist/dashboard/assets/switch-DOmJxg7H.js.gz +0 -0
- package/dist/dashboard/assets/useMutation-Dem0lXQj.js.gz +0 -0
- package/scripts/build/aot.ts +0 -143
- package/scripts/build/build.ts +0 -24
- package/scripts/build/compile.ts +0 -88
- package/scripts/build/restart.ts +0 -120
- package/scripts/build/start.ts +0 -25
- package/src/observability/event-compaction.ts +0 -317
- package/src/observability/event-day-index.ts +0 -440
|
@@ -1,275 +1,308 @@
|
|
|
1
|
-
import { existsSync } from "node:fs";
|
|
2
|
-
import { tmpdir } from "node:os";
|
|
3
|
-
import { join } from "node:path";
|
|
4
|
-
import { randomUUID } from "node:crypto";
|
|
5
|
-
import { isNewerRelease } from "../../src/console/updates/version-compare";
|
|
6
|
-
import { resolvePackagePath } from "../../src/config/package-paths";
|
|
7
|
-
import { resolvePort } from "../../src/config/runtime";
|
|
8
|
-
import { ensureDrainToken } from "./instance";
|
|
9
|
-
import { attachGateway, stopAttachedGateway, type RunningGateway } from "./instance";
|
|
10
|
-
import { startGateway } from "./gateway";
|
|
11
|
-
import { stopGateway } from "./gateway";
|
|
12
|
-
import { ENV_PATH, readEnvFile } from "./env";
|
|
13
|
-
import { readInstalledVersion, readLatestPublishedVersion } from "./version";
|
|
14
|
-
import { launchBackgroundWithStatus, openUrl } from "./background";
|
|
15
|
-
import { chooseFromMenu, confirmByTyping, confirmStep } from "./prompt";
|
|
16
|
-
import { renderWordmark } from "./wordmark";
|
|
17
|
-
import { exportBackup, resetConsoleAccount } from "./admin";
|
|
18
|
-
import { runDetachedUpdate } from "./update";
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
*
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
);
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
if (
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
const
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
//
|
|
187
|
-
// the
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
//
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
console.log("
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
console.log("
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { randomUUID } from "node:crypto";
|
|
5
|
+
import { isNewerRelease } from "../../src/console/updates/version-compare";
|
|
6
|
+
import { resolvePackagePath } from "../../src/config/package-paths";
|
|
7
|
+
import { resolvePort } from "../../src/config/runtime";
|
|
8
|
+
import { ensureDrainToken } from "./instance";
|
|
9
|
+
import { attachGateway, stopAttachedGateway, type RunningGateway } from "./instance";
|
|
10
|
+
import { startGateway } from "./gateway";
|
|
11
|
+
import { stopGateway } from "./gateway";
|
|
12
|
+
import { ENV_PATH, readEnvFile } from "./env";
|
|
13
|
+
import { readInstalledVersion, readLatestPublishedVersion } from "./version";
|
|
14
|
+
import { launchBackgroundWithStatus, openUrl } from "./background";
|
|
15
|
+
import { chooseFromMenu, confirmByTyping, confirmStep, type MenuRow } from "./prompt";
|
|
16
|
+
import { renderWordmark } from "./wordmark";
|
|
17
|
+
import { exportBackup, resetConsoleAccount } from "./admin";
|
|
18
|
+
import { runDetachedUpdate } from "./update";
|
|
19
|
+
import { acquireController } from "./controller";
|
|
20
|
+
import { restoreControllerAfterFailedHandoff } from "./controller";
|
|
21
|
+
import { attachGateway as attachRunningGateway } from "./instance";
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The default `carte` experience: start the gateway, then offer an arrow-key
|
|
26
|
+
* menu. This needs no desktop environment, so it works over SSH, on a headless
|
|
27
|
+
* box, and on Windows where the tray icon lands in the hidden-icons overflow
|
|
28
|
+
* and is never seen. `carte --tray` opts into the icon instead.
|
|
29
|
+
*/
|
|
30
|
+
export async function startMenu(): Promise<void> {
|
|
31
|
+
const controller = acquireController("menu");
|
|
32
|
+
const releaseController = (): void => controller.release();
|
|
33
|
+
process.once("exit", releaseController);
|
|
34
|
+
try {
|
|
35
|
+
await runMenu(controller.handoff);
|
|
36
|
+
} finally {
|
|
37
|
+
controller.release();
|
|
38
|
+
process.removeListener("exit", releaseController);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function runMenu(handoff: { readonly token: string; readonly parentPid: number }): Promise<void> {
|
|
43
|
+
// A fresh install has no config file yet, and the gateway refuses to boot
|
|
44
|
+
// without CARTETHYIA_DB_MODE — which surfaced as a stack trace about a
|
|
45
|
+
// missing database mode rather than "you have not set this up". Run setup
|
|
46
|
+
// first, the way `carte` is expected to behave on a new install.
|
|
47
|
+
const configured = existsSync(ENV_PATH) && (await readEnvFile(ENV_PATH)).CARTETHYIA_DB_MODE;
|
|
48
|
+
if (!configured) {
|
|
49
|
+
console.log(
|
|
50
|
+
existsSync(ENV_PATH)
|
|
51
|
+
? "Cartethyia is missing its database mode. Starting setup.\n"
|
|
52
|
+
: "Cartethyia is not set up yet. Starting setup.\n",
|
|
53
|
+
);
|
|
54
|
+
// dynamic-import: `setup` pulls in the whole wizard and the database mode
|
|
55
|
+
// resolver, and it is only reachable on a first run. A static import
|
|
56
|
+
// would pay that cost on every `carte`, which is the one path that has
|
|
57
|
+
// to stay fast.
|
|
58
|
+
const { setup } = await import("./setup");
|
|
59
|
+
await setup();
|
|
60
|
+
const after = existsSync(ENV_PATH) ? (await readEnvFile(ENV_PATH)).CARTETHYIA_DB_MODE : undefined;
|
|
61
|
+
if (!after) {
|
|
62
|
+
console.error(
|
|
63
|
+
`Setup did not record CARTETHYIA_DB_MODE in ${ENV_PATH}; run \`cartethyia setup\` and try again.`,
|
|
64
|
+
);
|
|
65
|
+
process.exitCode = 1;
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
process.env.CARTETHYIA_DB_MODE = after;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const port = resolvePort();
|
|
72
|
+
const drainToken = ensureDrainToken();
|
|
73
|
+
const dashboardUrl = `http://127.0.0.1:${port}/console`;
|
|
74
|
+
const currentVersion = await readInstalledVersion();
|
|
75
|
+
|
|
76
|
+
// Reattach without draining a healthy instance. A new child must either be
|
|
77
|
+
// ready or produce its actionable failure before the menu is shown; otherwise
|
|
78
|
+
// the UI offers gateway actions for a process that already exited.
|
|
79
|
+
const attached = await attachGateway(port, drainToken);
|
|
80
|
+
let startupError: unknown = null;
|
|
81
|
+
const ready: Promise<Bun.Subprocess | null> = attached
|
|
82
|
+
? Promise.resolve(null)
|
|
83
|
+
: startGateway(port, drainToken).catch((error: unknown) => {
|
|
84
|
+
startupError = error;
|
|
85
|
+
return null;
|
|
86
|
+
});
|
|
87
|
+
let gateway: Bun.Subprocess | null = null;
|
|
88
|
+
const runningAttached: RunningGateway | null = attached;
|
|
89
|
+
void ready.then((child) => {
|
|
90
|
+
if (child === null) return;
|
|
91
|
+
gateway = child;
|
|
92
|
+
child.unref();
|
|
93
|
+
}).catch((error: unknown) => {
|
|
94
|
+
console.error(`The gateway did not start: ${error instanceof Error ? error.message : "unknown error"}`);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
if (!attached) {
|
|
98
|
+
await ready;
|
|
99
|
+
if (startupError !== null) {
|
|
100
|
+
const detail = startupError instanceof Error ? startupError.message : "unknown startup error";
|
|
101
|
+
console.error(`The gateway did not start on port ${port}.\n${detail}`);
|
|
102
|
+
console.error("Fix the reported issue, then run `carte` again.");
|
|
103
|
+
process.exitCode = 1;
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
let stopping = false;
|
|
109
|
+
let handedOff = false;
|
|
110
|
+
const shutDown = async (): Promise<void> => {
|
|
111
|
+
if (stopping) return;
|
|
112
|
+
stopping = true;
|
|
113
|
+
const child = gateway ?? (await ready.catch(() => null));
|
|
114
|
+
if (child) await stopGateway(child, port, drainToken);
|
|
115
|
+
else if (runningAttached) await stopAttachedGateway(runningAttached, drainToken);
|
|
116
|
+
};
|
|
117
|
+
const detachAttached = (): void => {
|
|
118
|
+
if (runningAttached !== null) stopping = true;
|
|
119
|
+
};
|
|
120
|
+
// Ctrl-C has to stop the gateway, and the drain endpoint cannot be called
|
|
121
|
+
// from an exit path: it is async, and enquirer's own Ctrl-C handler calls
|
|
122
|
+
// process.exit(130) while a prompt is live. So the gateway is a child in this
|
|
123
|
+
// process group — a terminal's Ctrl-C signals the whole group, and the
|
|
124
|
+
// gateway drains through the SIGINT handler it already has in src/main.ts —
|
|
125
|
+
// and `process.on("exit")` is the synchronous backstop for every other way
|
|
126
|
+
// this process can end (a closed terminal, a crash, a signal Bun cannot
|
|
127
|
+
// deliver on Windows). That handler can only call synchronous APIs, which is
|
|
128
|
+
// why it signals the child rather than awaiting the drain endpoint.
|
|
129
|
+
// `handedOff` is set by "Hide to tray": the gateway is being given to a tray
|
|
130
|
+
// that will own it, so this process must not kill it on the way out.
|
|
131
|
+
process.on("exit", () => {
|
|
132
|
+
if (stopping || handedOff || gateway === null || runningAttached !== null) return;
|
|
133
|
+
try {
|
|
134
|
+
gateway.kill();
|
|
135
|
+
} catch {
|
|
136
|
+
// Already gone; nothing to stop.
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
const interrupt = async (): Promise<void> => {
|
|
140
|
+
if (runningAttached !== null) {
|
|
141
|
+
detachAttached();
|
|
142
|
+
process.exit(0);
|
|
143
|
+
}
|
|
144
|
+
process.stdout.write("\u001b[2J\u001b[H");
|
|
145
|
+
console.log("Stopping Cartethyia…");
|
|
146
|
+
await shutDown();
|
|
147
|
+
process.exit(0);
|
|
148
|
+
};
|
|
149
|
+
process.on("SIGTERM", () => void interrupt());
|
|
150
|
+
process.on("SIGINT", () => void interrupt());
|
|
151
|
+
|
|
152
|
+
let latestVersion = await readLatestPublishedVersion();
|
|
153
|
+
let running = true;
|
|
154
|
+
let backupStatus: { readonly tone: "success" | "error"; readonly text: string } | undefined;
|
|
155
|
+
|
|
156
|
+
while (running) {
|
|
157
|
+
const upToDate = latestVersion === null || !isNewerRelease(currentVersion, latestVersion);
|
|
158
|
+
// Header-line version checker. When something newer is published the line
|
|
159
|
+
// calls it out and the menu adds an `Update to X.Y.Z` row that the arrow
|
|
160
|
+
// keys land on by default — the operator still has to press Enter, so a
|
|
161
|
+
// reflex Enter cannot run an update by accident, but attention is on the
|
|
162
|
+
// action that matters.
|
|
163
|
+
const versionCheckerLine =
|
|
164
|
+
latestVersion === null
|
|
165
|
+
? `${currentVersion} \u00b7 registry unavailable`
|
|
166
|
+
: upToDate
|
|
167
|
+
? `${currentVersion} \u00b7 up to date`
|
|
168
|
+
: `${currentVersion} \u2192 ${latestVersion} available`;
|
|
169
|
+
const header = [
|
|
170
|
+
...renderWordmark(),
|
|
171
|
+
`Console ${dashboardUrl}`,
|
|
172
|
+
`Version ${versionCheckerLine}`,
|
|
173
|
+
"",
|
|
174
|
+
];
|
|
175
|
+
|
|
176
|
+
// Anything that talks to the gateway waits for it to be listening; the menu
|
|
177
|
+
// itself does not.
|
|
178
|
+
const whenReady = async (): Promise<void> => {
|
|
179
|
+
await ready.catch(() => undefined);
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
const actions: readonly (() => Promise<void>)[] = [
|
|
183
|
+
async () => openUrl(dashboardUrl),
|
|
184
|
+
async () => {
|
|
185
|
+
// Transfer the live gateway rather than draining it first. The tray
|
|
186
|
+
// adopts this instance through the ownership marker and reports ready
|
|
187
|
+
// before the menu returns to the shell.
|
|
188
|
+
running = false;
|
|
189
|
+
stopping = true;
|
|
190
|
+
handedOff = true;
|
|
191
|
+
console.log("Starting the tray in the background…");
|
|
192
|
+
const signalPath = join(tmpdir(), `cartethyia-tray-menu-${process.pid}-${randomUUID()}.json`);
|
|
193
|
+
try {
|
|
194
|
+
const url = await launchBackgroundWithStatus(
|
|
195
|
+
["run", resolvePackagePath("scripts", "cli", "main.ts"), "tray"],
|
|
196
|
+
{ signalPath, controllerHandoff: handoff },
|
|
197
|
+
);
|
|
198
|
+
console.log(`Cartethyia is running in the background at ${url || dashboardUrl}.`);
|
|
199
|
+
console.log("The tray icon owns it; use Exit there to stop it.");
|
|
200
|
+
} catch (error) {
|
|
201
|
+
restoreControllerAfterFailedHandoff(handoff);
|
|
202
|
+
handedOff = false;
|
|
203
|
+
console.error(
|
|
204
|
+
`Could not hand off to the tray: ${error instanceof Error ? error.message : "unknown error"}`,
|
|
205
|
+
);
|
|
206
|
+
console.error("Cartethyia is stopped. Start it again from this menu.");
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
async () => {
|
|
210
|
+
// Export straight to the download directory. The console page asks for
|
|
211
|
+
// the operator password, which is exactly the thing a locked-out
|
|
212
|
+
// operator does not have; the CLI already runs as the OS user who owns
|
|
213
|
+
// the database, so the loopback token is the whole gate.
|
|
214
|
+
await whenReady();
|
|
215
|
+
const result = await exportBackup(port, drainToken);
|
|
216
|
+
backupStatus = "error" in result
|
|
217
|
+
? { tone: "error", text: `Backup failed: ${result.error}` }
|
|
218
|
+
: {
|
|
219
|
+
tone: "success",
|
|
220
|
+
text: `Backup saved at: ${result.path} (${(result.bytes / 1024).toFixed(1)} KiB)`,
|
|
221
|
+
};
|
|
222
|
+
},
|
|
223
|
+
async () => {
|
|
224
|
+
// Deleting the console account is the only real password recovery:
|
|
225
|
+
// /change-password needs the current password, and first-boot setup
|
|
226
|
+
// only runs when no user exists. Removing the user puts the wizard
|
|
227
|
+
// back. Providers, keys, and routing are untouched.
|
|
228
|
+
console.log("");
|
|
229
|
+
console.log("This deletes every console account and its sessions.");
|
|
230
|
+
console.log("The next visit to /console asks you to create a new one.");
|
|
231
|
+
console.log("Providers, API keys, and routing are not touched.");
|
|
232
|
+
console.log("");
|
|
233
|
+
if (!(await confirmStep("Continue with the reset?"))) {
|
|
234
|
+
console.log("Cancelled.");
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
if (!(await confirmByTyping("RESET", "Confirm deleting the console account"))) {
|
|
238
|
+
console.log("Cancelled.");
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
await whenReady();
|
|
242
|
+
const status = await resetConsoleAccount(port, drainToken);
|
|
243
|
+
console.log(
|
|
244
|
+
status === 0
|
|
245
|
+
? `Console account removed. Open ${dashboardUrl} to create a new one.`
|
|
246
|
+
: "Reset failed; see the gateway log.",
|
|
247
|
+
);
|
|
248
|
+
},
|
|
249
|
+
async () => {
|
|
250
|
+
running = false;
|
|
251
|
+
},
|
|
252
|
+
];
|
|
253
|
+
// The Update action is only wired in when there is something newer to go
|
|
254
|
+
// to; otherwise the menu's up-to-date state is already told by the header
|
|
255
|
+
// line and an extra row would be noise.
|
|
256
|
+
const updateAction = async (): Promise<void> => {
|
|
257
|
+
if (upToDate || latestVersion === null) return;
|
|
258
|
+
// npm cannot replace this package's directory while this process is
|
|
259
|
+
// running out of it: on Windows the rename fails with EBUSY and npm
|
|
260
|
+
// exits 14. Even with the gateway stopped, the CLI itself is executing
|
|
261
|
+
// from that directory, so an in-process install can never succeed.
|
|
262
|
+
// Print the command and exit, the way 9router does.
|
|
263
|
+
await shutDown();
|
|
264
|
+
runDetachedUpdate();
|
|
265
|
+
console.log("");
|
|
266
|
+
console.log(`Update available: ${currentVersion} \u2192 ${latestVersion}`);
|
|
267
|
+
console.log("Detached update started; this process will exit now.");
|
|
268
|
+
console.log("Re-run `carte` after it finishes.");
|
|
269
|
+
console.log("");
|
|
270
|
+
running = false;
|
|
271
|
+
process.exit(0);
|
|
272
|
+
};
|
|
273
|
+
const extendedActions: readonly (() => Promise<void>)[] = upToDate
|
|
274
|
+
? actions
|
|
275
|
+
: [...actions.slice(0, actions.length - 1), updateAction, actions[actions.length - 1] ?? (async () => undefined)];
|
|
276
|
+
|
|
277
|
+
const rows: MenuRow[] = [
|
|
278
|
+
{ kind: "action", label: "Open Console", hint: "Open dashboard in browser" },
|
|
279
|
+
{ kind: "action", label: "Hide to Tray", hint: "Keep the gateway running" },
|
|
280
|
+
{ kind: "action", label: "Backup", hint: "Export config to Downloads" },
|
|
281
|
+
{ kind: "action", label: "Reset", hint: "Delete console account" },
|
|
282
|
+
];
|
|
283
|
+
if (!upToDate && latestVersion !== null) {
|
|
284
|
+
rows.push({ kind: "action", label: `Update to ${latestVersion}`, hint: "installs now and exits" });
|
|
285
|
+
}
|
|
286
|
+
rows.push({ kind: "rule" });
|
|
287
|
+
rows.push({ kind: "action", label: "Exit", hint: "Stop the gateway" });
|
|
288
|
+
|
|
289
|
+
// Focus the Update row by default when it exists, so the operator who
|
|
290
|
+
// launched `carte` *because* they saw the version checker gets a one-key
|
|
291
|
+
// path to the fix.
|
|
292
|
+
const updateIndex = upToDate || latestVersion === null ? -1 : 4;
|
|
293
|
+
const initialActionIndex = updateIndex >= 0 ? updateIndex : 0;
|
|
294
|
+
const choice = await chooseFromMenu(header, rows, { initialIndex: initialActionIndex, ...(backupStatus ? { status: backupStatus } : {}) });
|
|
295
|
+
if (choice === -1) break;
|
|
296
|
+
const action = extendedActions[choice];
|
|
297
|
+
if (action) await action();
|
|
298
|
+
}
|
|
299
|
+
// "Hide to tray" has already given the gateway to the tray. Draining here
|
|
300
|
+
// would stop the very process the tray just adopted, which is why the menu
|
|
301
|
+
// appeared to hand over a gateway that was not listening.
|
|
302
|
+
if (handedOff) return;
|
|
303
|
+
if (runningAttached !== null || (await attachRunningGateway(port, drainToken)) !== null) {
|
|
304
|
+
detachAttached();
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
await shutDown();
|
|
308
|
+
}
|