cartethyia 2.5.4 → 2.5.7

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.
Files changed (395) hide show
  1. package/.env.example +13 -4
  2. package/README.md +2 -2
  3. package/dist/dashboard/assets/{BannedPage-C2orBsI2.js → BannedPage-DE2607Tb.js} +1 -1
  4. package/dist/dashboard/assets/BannedPage-DE2607Tb.js.gz +0 -0
  5. package/dist/dashboard/assets/CliToolDetailPage-Duv6mfrl.js +1 -0
  6. package/dist/dashboard/assets/CliToolDetailPage-Duv6mfrl.js.gz +0 -0
  7. package/dist/dashboard/assets/{CliToolsPage-BV6pxVQo.js → CliToolsPage-C2PNYWzk.js} +1 -1
  8. package/dist/dashboard/assets/CliToolsPage-C2PNYWzk.js.gz +0 -0
  9. package/dist/dashboard/assets/CombosPage-TXP9OfAM.js +1 -0
  10. package/dist/dashboard/assets/CombosPage-TXP9OfAM.js.gz +0 -0
  11. package/dist/dashboard/assets/{ConsoleLogPage-CW-wPmJ6.js → ConsoleLogPage-B-9xnAQN.js} +1 -1
  12. package/dist/dashboard/assets/ConsoleLogPage-B-9xnAQN.js.gz +0 -0
  13. package/dist/dashboard/assets/{CustomizationPage-0p8uX7vB.js → CustomizationPage-xeax9nJt.js} +1 -1
  14. package/dist/dashboard/assets/CustomizationPage-xeax9nJt.js.gz +0 -0
  15. package/dist/dashboard/assets/{HealthEventsModal-BjqSMfko.js → HealthEventsModal-Df4jjaHJ.js} +1 -1
  16. package/dist/dashboard/assets/HealthEventsModal-Df4jjaHJ.js.gz +0 -0
  17. package/dist/dashboard/assets/{LoginPage-BvzCx8Kr.js → LoginPage-Dyojsm84.js} +1 -1
  18. package/dist/dashboard/assets/LoginPage-Dyojsm84.js.gz +0 -0
  19. package/dist/dashboard/assets/ModelPicker-C7pDb41R.js +1 -0
  20. package/dist/dashboard/assets/ModelPicker-C7pDb41R.js.gz +0 -0
  21. package/dist/dashboard/assets/OverviewPage-BJfg4ow6.js +1 -0
  22. package/dist/dashboard/assets/OverviewPage-BJfg4ow6.js.gz +0 -0
  23. package/dist/dashboard/assets/ProviderDetailPage-ChCX1gmT.js +3 -0
  24. package/dist/dashboard/assets/ProviderDetailPage-ChCX1gmT.js.gz +0 -0
  25. package/dist/dashboard/assets/{ProvidersPage-Js9jUPSb.js → ProvidersPage-DeWSOEUO.js} +1 -1
  26. package/dist/dashboard/assets/ProvidersPage-DeWSOEUO.js.gz +0 -0
  27. package/dist/dashboard/assets/ProxyPage-CkpWln2S.js +7 -0
  28. package/dist/dashboard/assets/ProxyPage-CkpWln2S.js.gz +0 -0
  29. package/dist/dashboard/assets/QuotaPage-B3VOgQmt.js +1 -0
  30. package/dist/dashboard/assets/QuotaPage-B3VOgQmt.js.gz +0 -0
  31. package/dist/dashboard/assets/SettingsPage-C_klIZom.js +1 -0
  32. package/dist/dashboard/assets/SettingsPage-C_klIZom.js.gz +0 -0
  33. package/dist/dashboard/assets/{SetupPage-DDbMQsoo.js → SetupPage-BYph-InK.js} +1 -1
  34. package/dist/dashboard/assets/SetupPage-BYph-InK.js.gz +0 -0
  35. package/dist/dashboard/assets/{SortableList-CB3Z7VTf.js → SortableList-CvyQCYWJ.js} +1 -1
  36. package/dist/dashboard/assets/SortableList-CvyQCYWJ.js.gz +0 -0
  37. package/dist/dashboard/assets/{StudioPage-D95UCPHI.js → StudioPage-Cm1JYilI.js} +3 -3
  38. package/dist/dashboard/assets/StudioPage-Cm1JYilI.js.gz +0 -0
  39. package/dist/dashboard/assets/UsagePage-DlFnc3_S.js +56 -0
  40. package/dist/dashboard/assets/UsagePage-DlFnc3_S.js.gz +0 -0
  41. package/dist/dashboard/assets/api-keys-DQYLQxpW.js +1 -0
  42. package/dist/dashboard/assets/api-keys-DQYLQxpW.js.gz +0 -0
  43. package/dist/dashboard/assets/app-CX_Z8cMs.css +2 -0
  44. package/dist/dashboard/assets/app-CX_Z8cMs.css.gz +0 -0
  45. package/dist/dashboard/assets/{assert-Chi7pCnt.js → assert-C9FD_JwJ.js} +1 -1
  46. package/dist/dashboard/assets/assert-C9FD_JwJ.js.gz +0 -0
  47. package/dist/dashboard/assets/{badge-D4pQapKj.js → badge-CR72dasT.js} +1 -1
  48. package/dist/dashboard/assets/badge-CR72dasT.js.gz +0 -0
  49. package/dist/dashboard/assets/{banner-DH6cg-_B.js → banner-CI9_eSfO.js} +1 -1
  50. package/dist/dashboard/assets/banner-CI9_eSfO.js.gz +0 -0
  51. package/dist/dashboard/assets/{card-BKqlUOe4.js → card-DS7CQEsO.js} +1 -1
  52. package/dist/dashboard/assets/card-DS7CQEsO.js.gz +0 -0
  53. package/dist/dashboard/assets/{cli-tools-fTgljTGA.js → cli-tools-CNqzrfdb.js} +1 -1
  54. package/dist/dashboard/assets/cli-tools-CNqzrfdb.js.gz +0 -0
  55. package/dist/dashboard/assets/{clipboard-button-D5Ys_sM0.js → clipboard-button-611pSsaX.js} +1 -1
  56. package/dist/dashboard/assets/clipboard-button-611pSsaX.js.gz +0 -0
  57. package/dist/dashboard/assets/{fingerprint-pattern-BWuHtbW4.js → concurrency-BDF0ok7y.js} +1 -1
  58. package/dist/dashboard/assets/concurrency-BDF0ok7y.js.gz +0 -0
  59. package/dist/dashboard/assets/dialog-k37exjNt.js +1 -0
  60. package/dist/dashboard/assets/dialog-k37exjNt.js.gz +0 -0
  61. package/dist/dashboard/assets/drawer-CX7N8ucR.js +1 -0
  62. package/dist/dashboard/assets/drawer-CX7N8ucR.js.gz +0 -0
  63. package/dist/dashboard/assets/{entry-CQBr6U9c.js → entry-B9Xvtnfj.js} +1 -1
  64. package/dist/dashboard/assets/entry-B9Xvtnfj.js.gz +0 -0
  65. package/dist/dashboard/assets/entry-Bog0p925.js +4 -0
  66. package/dist/dashboard/assets/entry-Bog0p925.js.gz +0 -0
  67. package/dist/dashboard/assets/entry-CTP8AyiS.js +1 -0
  68. package/dist/dashboard/assets/entry-CTP8AyiS.js.gz +0 -0
  69. package/dist/dashboard/assets/{github-badge-BlptL8Uf.js → github-badge-sltk1qUi.js} +1 -1
  70. package/dist/dashboard/assets/github-badge-sltk1qUi.js.gz +0 -0
  71. package/dist/dashboard/assets/{index-js6TJvdr.js → index-CZQIrdoX.js} +2 -2
  72. package/dist/dashboard/assets/index-CZQIrdoX.js.gz +0 -0
  73. package/dist/dashboard/assets/{inline-DUWDSmDV.js → inline-BhY2sSnO.js} +1 -1
  74. package/dist/dashboard/assets/inline-BhY2sSnO.js.gz +0 -0
  75. package/dist/dashboard/assets/{input-LVjgZq4f.js → input-V1umFiBk.js} +1 -1
  76. package/dist/dashboard/assets/input-V1umFiBk.js.gz +0 -0
  77. package/dist/dashboard/assets/layout-BBOYycyS.js +1 -0
  78. package/dist/dashboard/assets/layout-BBOYycyS.js.gz +0 -0
  79. package/dist/dashboard/assets/{list-row-DupvLfDx.js → list-row-1zzZYM0B.js} +1 -1
  80. package/dist/dashboard/assets/list-row-1zzZYM0B.js.gz +0 -0
  81. package/dist/dashboard/assets/{live-C4pEJUqI.js → live-BivGfuUs.js} +1 -1
  82. package/dist/dashboard/assets/live-BivGfuUs.js.gz +0 -0
  83. package/dist/dashboard/assets/{model-bans-BRiuufkB.js → model-bans-CmffjLuG.js} +1 -1
  84. package/dist/dashboard/assets/model-bans-CmffjLuG.js.gz +0 -0
  85. package/dist/dashboard/assets/{mutation-B4ROwk8L.js → mutation-46P0oWMe.js} +1 -1
  86. package/dist/dashboard/assets/mutation-46P0oWMe.js.gz +0 -0
  87. package/dist/dashboard/assets/numbers-DkfMR5Qs.js +2 -0
  88. package/dist/dashboard/assets/numbers-DkfMR5Qs.js.gz +0 -0
  89. package/dist/dashboard/assets/{query-keys-gmjzC3RS.js → query-keys-BFhGpwR1.js} +1 -1
  90. package/dist/dashboard/assets/query-keys-BFhGpwR1.js.gz +0 -0
  91. package/dist/dashboard/assets/{routing-C7tBT5o-.js → routing-CAb4F37R.js} +1 -1
  92. package/dist/dashboard/assets/routing-CAb4F37R.js.gz +0 -0
  93. package/dist/dashboard/assets/{select-WUCXorXw.js → select-BPpSsBgL.js} +1 -1
  94. package/dist/dashboard/assets/select-BPpSsBgL.js.gz +0 -0
  95. package/dist/dashboard/assets/{settings-C_zKl1GS.js → settings-DNX9sydi.js} +1 -1
  96. package/dist/dashboard/assets/settings-DNX9sydi.js.gz +0 -0
  97. package/dist/dashboard/assets/{stack-_3O0F8Xn.js → stack-BHTfXdz_.js} +1 -1
  98. package/dist/dashboard/assets/stack-BHTfXdz_.js.gz +0 -0
  99. package/dist/dashboard/assets/{state-BgTxHcJS.js → state-mPDRlQkl.js} +1 -1
  100. package/dist/dashboard/assets/state-mPDRlQkl.js.gz +0 -0
  101. package/dist/dashboard/assets/{switch-DEjTtOWf.js → switch-DOmJxg7H.js} +1 -1
  102. package/dist/dashboard/assets/switch-DOmJxg7H.js.gz +0 -0
  103. package/dist/dashboard/assets/tokens-COzario9.js +1 -0
  104. package/dist/dashboard/assets/tokens-COzario9.js.gz +0 -0
  105. package/dist/dashboard/assets/use-modal-focus-By7oJoGd.js +1 -0
  106. package/dist/dashboard/assets/use-modal-focus-By7oJoGd.js.gz +0 -0
  107. package/dist/dashboard/assets/{useMutation-BWSC0UAS.js → useMutation-Dem0lXQj.js} +1 -1
  108. package/dist/dashboard/assets/useMutation-Dem0lXQj.js.gz +0 -0
  109. package/dist/dashboard/index.html +1 -1
  110. package/dist/dashboard/index.html.gz +0 -0
  111. package/dist/dashboard/precompressed-assets.json +54 -54
  112. package/migrations/README.md +52 -52
  113. package/migrations/lite-sqlite3/0000_baseline.sql +2 -2
  114. package/package.json +95 -95
  115. package/scripts/cli/admin.ts +125 -0
  116. package/scripts/cli/{ui/background.ts → background.ts} +1 -1
  117. package/scripts/cli/{command/console-menu.ts → console-menu.ts} +275 -244
  118. package/scripts/cli/doctor.ts +37 -0
  119. package/scripts/cli/{support/env.ts → env.ts} +99 -99
  120. package/scripts/cli/{gateway/spawn.ts → gateway.ts} +112 -24
  121. package/scripts/cli/instance.ts +224 -0
  122. package/scripts/cli/main.ts +61 -18
  123. package/scripts/cli/{support/platform.ts → platform.ts} +64 -64
  124. package/scripts/cli/port.ts +100 -0
  125. package/scripts/cli/{support/services.ts → services.ts} +88 -88
  126. package/scripts/cli/{command/setup.ts → setup.ts} +35 -34
  127. package/scripts/cli/{command/start.ts → start.ts} +10 -5
  128. package/scripts/cli/{support/startup-signal.ts → startup-signal.ts} +23 -23
  129. package/scripts/cli/tray/index.ts +62 -12
  130. package/scripts/cli/{command/tray.ts → tray.ts} +208 -208
  131. package/scripts/cli/{command/update.ts → update.ts} +39 -39
  132. package/scripts/cli/version.ts +67 -0
  133. package/scripts/cli/{ui/wordmark.ts → wordmark.ts} +58 -58
  134. package/src/boot/app.ts +697 -693
  135. package/src/boot/dependencies.ts +647 -646
  136. package/src/boot/timeout.ts +2 -13
  137. package/src/config/cooldowns.ts +186 -138
  138. package/src/config/network.ts +8 -14
  139. package/src/config/providers.ts +7 -10
  140. package/src/config/runtime.ts +76 -76
  141. package/src/config/security.ts +15 -0
  142. package/src/config/spec.ts +20 -30
  143. package/src/config/telemetry.ts +0 -20
  144. package/src/config/timeouts.ts +0 -6
  145. package/src/console/admin/model-abuse/contracts.ts +28 -6
  146. package/src/console/admin/model-abuse/routes.ts +56 -3
  147. package/src/console/api-keys/contracts.ts +410 -414
  148. package/src/console/api-keys/routes.ts +881 -880
  149. package/src/console/auth/credentials.ts +3 -3
  150. package/src/console/auth/setup-service.ts +2 -2
  151. package/src/console/backup/export-endpoint.ts +6 -2
  152. package/src/console/backup/nine-router.ts +2 -5
  153. package/src/console/backup/service.ts +4 -0
  154. package/src/console/backup/store.ts +192 -29
  155. package/src/console/backup/validate.ts +3 -45
  156. package/src/console/cli-tools/fs-ops.ts +487 -487
  157. package/src/console/console-router-guards.ts +1 -1
  158. package/src/console/data-management/contracts.ts +13 -6
  159. package/src/console/data-management/operations.ts +23 -18
  160. package/src/console/data-management/routes.ts +0 -1
  161. package/src/console/domain-registration.ts +10 -5
  162. package/src/console/observability/live.ts +22 -0
  163. package/src/console/observability/store.ts +39 -16
  164. package/src/console/observability/usage-dimensions.ts +4 -4
  165. package/src/console/providers/catalog/catalog-projections.ts +6 -7
  166. package/src/console/providers/catalog/model-operations.ts +5 -2
  167. package/src/console/providers/catalog/provider-operations.ts +4 -4
  168. package/src/console/providers/catalog/public-model-store.ts +8 -11
  169. package/src/console/providers/catalog/store.ts +1553 -1553
  170. package/src/console/providers/oauth/routes.ts +8 -12
  171. package/src/console/quota/account-quota-tenant.ts +6 -6
  172. package/src/console/quota/quota-view.ts +1 -1
  173. package/src/console/remote-support/contracts.ts +61 -0
  174. package/src/console/remote-support/routes.ts +65 -0
  175. package/src/console/remote-support/service.ts +207 -0
  176. package/src/console/response-compression.ts +0 -3
  177. package/src/console/routing/pools/probe-result.ts +3 -2
  178. package/src/console/routing/pools/probe-verdict.ts +132 -132
  179. package/src/console/routing/pools/store.ts +8 -8
  180. package/src/console/settings/contracts.ts +58 -2
  181. package/src/console/settings/store.ts +30 -3
  182. package/src/console/shared/cursor.ts +8 -8
  183. package/src/console/shared/errors.ts +1 -3
  184. package/src/network/http2-bidi.ts +2 -4
  185. package/src/network/pool/agent.ts +478 -478
  186. package/src/network/pool/selector.ts +5 -4
  187. package/src/network/retry.ts +1 -2
  188. package/src/network/ssrf.ts +5 -4
  189. package/src/observability/event-compaction.ts +80 -78
  190. package/src/observability/event-day-index.ts +13 -15
  191. package/src/observability/event-log.ts +4 -4
  192. package/src/observability/logger.ts +6 -6
  193. package/src/observability/payload-capture.ts +151 -33
  194. package/src/observability/payload-store.ts +397 -440
  195. package/src/observability/redaction.ts +5 -6
  196. package/src/observability/request-notify.ts +43 -0
  197. package/src/observability/telemetry-status.ts +8 -9
  198. package/src/observability/token-speed.ts +5 -4
  199. package/src/persistence/db-mode.ts +7 -7
  200. package/src/persistence/readiness.ts +1 -1
  201. package/src/persistence/schema.ts +1406 -1402
  202. package/src/persistence/shared-cache.ts +1 -2
  203. package/src/persistence/stores/api-key-store.ts +18 -6
  204. package/src/persistence/stores/share-store.ts +4 -3
  205. package/src/persistence/stores/telemetry-store.ts +236 -237
  206. package/src/protocol/canonical-model.ts +11 -3
  207. package/src/protocol/codecs.ts +138 -4
  208. package/src/protocol/gateway-error.ts +6 -4
  209. package/src/protocol/request/chat.ts +21 -1
  210. package/src/protocol/request/codex.ts +10 -1
  211. package/src/protocol/request/messages.ts +4 -5
  212. package/src/protocol/request/responses.ts +9 -1
  213. package/src/protocol/response/chat.ts +34 -4
  214. package/src/protocol/response/codex.ts +7 -4
  215. package/src/protocol/response/dsml.ts +140 -28
  216. package/src/protocol/response/responses.ts +11 -5
  217. package/src/protocol/stream-error-frames.ts +4 -5
  218. package/src/providers/authentication/jwt-validator.ts +9 -10
  219. package/src/providers/authentication/oauth-refresh-service.ts +9 -11
  220. package/src/providers/configured-openai-providers.ts +134 -136
  221. package/src/providers/discovery/catalog/catalog-blob.ts +18 -18
  222. package/src/providers/discovery/catalog/catalog-format.ts +3 -6
  223. package/src/providers/discovery/models-dev-catalog.ts +354 -354
  224. package/src/providers/discovery/probe-phases.ts +4 -4
  225. package/src/providers/discovery/probe-wire.ts +6 -13
  226. package/src/providers/discovery/probing-service.ts +1117 -1045
  227. package/src/providers/integrations/alibabacp/alibabacp.ts +1 -1
  228. package/src/providers/integrations/antigravity/antigravity-quota.ts +5 -7
  229. package/src/providers/integrations/buddy/buddy-chat-shared.ts +23 -2
  230. package/src/providers/integrations/buddy/buddy-checkin.ts +1 -4
  231. package/src/providers/integrations/buddy/buddy-cli-headers.ts +23 -6
  232. package/src/providers/integrations/buddy/buddy-conversation-headers.ts +0 -1
  233. package/src/providers/integrations/buddy/buddy-identity.ts +52 -0
  234. package/src/providers/integrations/buddy/buddy-media.ts +2 -2
  235. package/src/providers/integrations/buddy/buddy-usage-store.ts +3 -4
  236. package/src/providers/integrations/buddy/codebuddy/quota.ts +2 -13
  237. package/src/providers/integrations/buddy/codebuddy/shared.ts +118 -115
  238. package/src/providers/integrations/buddy/workbuddy/quota.ts +0 -11
  239. package/src/providers/integrations/buddy/workbuddy/shared.ts +5 -2
  240. package/src/providers/integrations/claude/claude.ts +608 -608
  241. package/src/providers/integrations/cline/cline-quota.ts +132 -132
  242. package/src/providers/integrations/cline/cline.ts +537 -539
  243. package/src/providers/integrations/codex/codex-oauth.ts +1 -1
  244. package/src/providers/integrations/commandcode/commandcode.ts +674 -675
  245. package/src/providers/integrations/commandcode/discovery.ts +117 -116
  246. package/src/providers/integrations/cursor/cursor-auth.ts +418 -418
  247. package/src/providers/integrations/cursor/cursor-quota.ts +309 -310
  248. package/src/providers/integrations/cursor/cursor.ts +11 -163
  249. package/src/providers/integrations/factory/factory-models.ts +3 -5
  250. package/src/providers/integrations/grok/grok-install-id.ts +2 -3
  251. package/src/providers/integrations/grok/grok.ts +6 -7
  252. package/src/providers/integrations/hermes.ts +14 -18
  253. package/src/providers/integrations/kiro/kiro-discovery.ts +1 -1
  254. package/src/providers/integrations/kiro/kiro.ts +1 -1
  255. package/src/providers/integrations/mistral.ts +6 -6
  256. package/src/providers/integrations/opencode/fingerprint.ts +3 -3
  257. package/src/providers/integrations/opencode/provider.ts +8 -8
  258. package/src/providers/integrations/qoder/qoder-catalog.ts +450 -450
  259. package/src/providers/integrations/qoder/qoder-oauth.ts +388 -310
  260. package/src/providers/integrations/qoder/qoder.ts +884 -865
  261. package/src/providers/integrations/shared/connect.ts +6 -6
  262. package/src/providers/integrations/trae/trae-catalog.ts +1 -2
  263. package/src/providers/integrations/trae/trae.ts +2 -2
  264. package/src/providers/integrations/zcode/oauth.ts +6 -1
  265. package/src/providers/operations/account-health-service.ts +1528 -1523
  266. package/src/providers/operations/account-reset-service.ts +1 -1
  267. package/src/providers/operations/client-versions.ts +6 -6
  268. package/src/providers/operations/custom-cli-headers.ts +3 -4
  269. package/src/providers/operations/provider-catalog-seeder.ts +95 -95
  270. package/src/providers/operations/provider-catalog-service.ts +3 -4
  271. package/src/providers/provider-metadata.ts +4 -8
  272. package/src/providers/provider-registry.ts +6 -7
  273. package/src/providers/provider-usage.ts +1 -1
  274. package/src/security/abuse.ts +15 -10
  275. package/src/security/access-control.ts +144 -146
  276. package/src/security/admission/contracts.ts +11 -0
  277. package/src/security/admission/in-memory-store.ts +4 -3
  278. package/src/security/admission/lease-sweep.ts +6 -6
  279. package/src/security/admission/reasons.ts +5 -1
  280. package/src/security/admission/redis-store.ts +211 -210
  281. package/src/security/admission/service.ts +4 -0
  282. package/src/security/api-key-auth.ts +504 -504
  283. package/src/security/ip-boundary.ts +155 -15
  284. package/src/security/model-abuse.ts +366 -94
  285. package/src/security/outbound-headers.ts +3 -4
  286. package/src/shared/sleep.ts +4 -0
  287. package/src/transport/dispatch/attempt-finalize.ts +47 -5
  288. package/src/transport/dispatch/attempt-loop.ts +531 -530
  289. package/src/transport/dispatch/stream-bridge.ts +1 -3
  290. package/src/transport/dispatch/streaming/finalize.ts +1 -1
  291. package/src/transport/dispatch/streaming/stream.ts +5 -6
  292. package/src/transport/failure-policy.ts +162 -8
  293. package/src/transport/guards/auth-guard.ts +7 -4
  294. package/src/transport/guards/concurrency-guard.ts +0 -5
  295. package/src/transport/guards/error-lifecycle.ts +13 -6
  296. package/src/transport/guards/pipeline.ts +15 -3
  297. package/src/transport/guards/request-context.ts +8 -2
  298. package/src/transport/request/inflight.ts +5 -6
  299. package/src/transport/request/preparer.ts +2 -2
  300. package/src/transport/request/state.ts +12 -8
  301. package/src/transport/routing/admission.ts +4 -0
  302. package/src/transport/routing/route-catalog.ts +8 -1
  303. package/src/transport/routing/route-model.ts +46 -14
  304. package/src/transport/routing/router.ts +21 -14
  305. package/src/transport/surface/completion.ts +2 -3
  306. package/src/transport/surface/dialects.ts +5 -6
  307. package/src/transport/surface/responses/encode.ts +38 -0
  308. package/src/transport/surface/responses/parse.ts +4 -0
  309. package/src/transport/translation/capabilities.ts +2 -3
  310. package/src/transport/translation/quirks.ts +3 -3
  311. package/src/workers/buddy-growth-tasks.ts +5 -10
  312. package/src/workers/daily-checkin.ts +17 -23
  313. package/src/workers/quota-refresh-sweep.ts +26 -26
  314. package/dist/dashboard/assets/BannedPage-C2orBsI2.js.gz +0 -0
  315. package/dist/dashboard/assets/CliToolDetailPage-DUcZ6pMB.js +0 -1
  316. package/dist/dashboard/assets/CliToolDetailPage-DUcZ6pMB.js.gz +0 -0
  317. package/dist/dashboard/assets/CliToolsPage-BV6pxVQo.js.gz +0 -0
  318. package/dist/dashboard/assets/CombosPage-Bsan4679.js +0 -1
  319. package/dist/dashboard/assets/CombosPage-Bsan4679.js.gz +0 -0
  320. package/dist/dashboard/assets/ConsoleLogPage-CW-wPmJ6.js.gz +0 -0
  321. package/dist/dashboard/assets/CustomizationPage-0p8uX7vB.js.gz +0 -0
  322. package/dist/dashboard/assets/HealthEventsModal-BjqSMfko.js.gz +0 -0
  323. package/dist/dashboard/assets/LoginPage-BvzCx8Kr.js.gz +0 -0
  324. package/dist/dashboard/assets/ModelPicker-BY1aKEkP.js +0 -1
  325. package/dist/dashboard/assets/ModelPicker-BY1aKEkP.js.gz +0 -0
  326. package/dist/dashboard/assets/OverviewPage-DOQpy1y0.js +0 -1
  327. package/dist/dashboard/assets/OverviewPage-DOQpy1y0.js.gz +0 -0
  328. package/dist/dashboard/assets/ProviderDetailPage-ecxyUMzt.js +0 -3
  329. package/dist/dashboard/assets/ProviderDetailPage-ecxyUMzt.js.gz +0 -0
  330. package/dist/dashboard/assets/ProvidersPage-Js9jUPSb.js.gz +0 -0
  331. package/dist/dashboard/assets/ProxyPage-J3TBi3Kx.js +0 -7
  332. package/dist/dashboard/assets/ProxyPage-J3TBi3Kx.js.gz +0 -0
  333. package/dist/dashboard/assets/QuotaPage-C1gZS6xr.js +0 -1
  334. package/dist/dashboard/assets/QuotaPage-C1gZS6xr.js.gz +0 -0
  335. package/dist/dashboard/assets/SettingsPage-CS86ho5X.js +0 -1
  336. package/dist/dashboard/assets/SettingsPage-CS86ho5X.js.gz +0 -0
  337. package/dist/dashboard/assets/SetupPage-DDbMQsoo.js.gz +0 -0
  338. package/dist/dashboard/assets/SortableList-CB3Z7VTf.js.gz +0 -0
  339. package/dist/dashboard/assets/StudioPage-D95UCPHI.js.gz +0 -0
  340. package/dist/dashboard/assets/UsagePage-Cnae9SWA.js +0 -56
  341. package/dist/dashboard/assets/UsagePage-Cnae9SWA.js.gz +0 -0
  342. package/dist/dashboard/assets/api-keys-VY68Mhd1.js +0 -1
  343. package/dist/dashboard/assets/api-keys-VY68Mhd1.js.gz +0 -0
  344. package/dist/dashboard/assets/app-COlK95oi.css +0 -2
  345. package/dist/dashboard/assets/app-COlK95oi.css.gz +0 -0
  346. package/dist/dashboard/assets/assert-Chi7pCnt.js.gz +0 -0
  347. package/dist/dashboard/assets/badge-D4pQapKj.js.gz +0 -0
  348. package/dist/dashboard/assets/banner-DH6cg-_B.js.gz +0 -0
  349. package/dist/dashboard/assets/card-BKqlUOe4.js.gz +0 -0
  350. package/dist/dashboard/assets/cli-tools-fTgljTGA.js.gz +0 -0
  351. package/dist/dashboard/assets/clipboard-button-D5Ys_sM0.js.gz +0 -0
  352. package/dist/dashboard/assets/dialog-BYj-8WuK.js +0 -1
  353. package/dist/dashboard/assets/dialog-BYj-8WuK.js.gz +0 -0
  354. package/dist/dashboard/assets/drawer-CmXIZ6H1.js +0 -1
  355. package/dist/dashboard/assets/drawer-CmXIZ6H1.js.gz +0 -0
  356. package/dist/dashboard/assets/entry-CBg5zeu8.js +0 -1
  357. package/dist/dashboard/assets/entry-CBg5zeu8.js.gz +0 -0
  358. package/dist/dashboard/assets/entry-CQBr6U9c.js.gz +0 -0
  359. package/dist/dashboard/assets/entry-CgdSAzEV.js +0 -4
  360. package/dist/dashboard/assets/entry-CgdSAzEV.js.gz +0 -0
  361. package/dist/dashboard/assets/fingerprint-pattern-BWuHtbW4.js.gz +0 -0
  362. package/dist/dashboard/assets/github-badge-BlptL8Uf.js.gz +0 -0
  363. package/dist/dashboard/assets/index-js6TJvdr.js.gz +0 -0
  364. package/dist/dashboard/assets/inline-DUWDSmDV.js.gz +0 -0
  365. package/dist/dashboard/assets/input-LVjgZq4f.js.gz +0 -0
  366. package/dist/dashboard/assets/layout-CPfxpsfy.js +0 -1
  367. package/dist/dashboard/assets/layout-CPfxpsfy.js.gz +0 -0
  368. package/dist/dashboard/assets/list-row-DupvLfDx.js.gz +0 -0
  369. package/dist/dashboard/assets/live-C4pEJUqI.js.gz +0 -0
  370. package/dist/dashboard/assets/model-bans-BRiuufkB.js.gz +0 -0
  371. package/dist/dashboard/assets/mutation-B4ROwk8L.js.gz +0 -0
  372. package/dist/dashboard/assets/numbers-YNcHvRY7.js +0 -2
  373. package/dist/dashboard/assets/numbers-YNcHvRY7.js.gz +0 -0
  374. package/dist/dashboard/assets/query-keys-gmjzC3RS.js.gz +0 -0
  375. package/dist/dashboard/assets/routing-C7tBT5o-.js.gz +0 -0
  376. package/dist/dashboard/assets/select-WUCXorXw.js.gz +0 -0
  377. package/dist/dashboard/assets/settings-C_zKl1GS.js.gz +0 -0
  378. package/dist/dashboard/assets/stack-_3O0F8Xn.js.gz +0 -0
  379. package/dist/dashboard/assets/state-BgTxHcJS.js.gz +0 -0
  380. package/dist/dashboard/assets/switch-DEjTtOWf.js.gz +0 -0
  381. package/dist/dashboard/assets/tokens-DDxMbSRL.js +0 -1
  382. package/dist/dashboard/assets/tokens-DDxMbSRL.js.gz +0 -0
  383. package/dist/dashboard/assets/use-presence-BSZEBx7U.js +0 -1
  384. package/dist/dashboard/assets/use-presence-BSZEBx7U.js.gz +0 -0
  385. package/dist/dashboard/assets/useMutation-BWSC0UAS.js.gz +0 -0
  386. package/scripts/cli/command/admin.ts +0 -65
  387. package/scripts/cli/command/doctor.ts +0 -257
  388. package/scripts/cli/gateway/drain-token.ts +0 -78
  389. package/scripts/cli/gateway/instance-lock.ts +0 -105
  390. package/scripts/cli/gateway/stop.ts +0 -51
  391. package/scripts/cli/support/bun.ts +0 -27
  392. package/scripts/cli/support/version.ts +0 -37
  393. /package/dist/dashboard/assets/{app-DCQZRmHY.js → app-BIt446yE.js} +0 -0
  394. /package/dist/dashboard/assets/{app-DCQZRmHY.js.gz → app-BIt446yE.js.gz} +0 -0
  395. /package/scripts/cli/{ui/prompt.ts → prompt.ts} +0 -0
@@ -1,52 +1,52 @@
1
- # Database baselines
2
-
3
- Cartethyia keeps one SQL baseline per database backend:
4
-
5
- - `full-postgres/0000_baseline.sql` defines the foundational PostgreSQL schema
6
- for a new database.
7
- - `lite-sqlite3/0000_baseline.sql` is generated from the PostgreSQL baseline by
8
- `scripts/generate/sqlite-ddl.ts`; do not edit it by hand.
9
-
10
- The startup runner applies the baseline and numbered forward migrations,
11
- recording them in `cartethyia_schema_migrations` along with a hash marker for
12
- the exact baseline contents. Released baselines are immutable so existing
13
- installations keep matching their marker; numbered migrations bring that
14
- foundational schema up to the current schema. Each backend's migrations must
15
- have matching behavior. Startup fails with a recovery instruction for a
16
- database with unsupported retired migration history instead of treating it as
17
- current.
18
-
19
- ## Recovering an existing installation
20
-
21
- 1. Export a backup from the existing installation before switching it to a
22
- release with unsupported migration history.
23
- 2. Create a fresh database and point the application at it.
24
- 3. Start the application so it creates the baseline schema.
25
- 4. Restore the backup through the console restore flow.
26
-
27
- Restore normalizes legacy values that no longer satisfy current constraints,
28
- including `bypass_proxy` → `skip_proxy`, `bridge` → `https`, the retired
29
- provider User-Agent default, Cline's skip-proxy default, and `fusion` →
30
- `fallback`. Unknown or retired columns are reported and skipped according to
31
- the backup contract.
32
-
33
- Do not point tests or recovery steps at development or production databases.
34
- The startup path runs `ensureMigrated()` before provider/catalog seeding. Full
35
- mode uses `src/persistence/db-pg.ts` and an advisory lock; Lite uses
36
- `src/persistence/db-sqlite.ts`. Readiness compares the ledger to the available baseline and forward migration
37
- files. A failed migration aborts startup and is not recorded.
38
-
39
- Migrations are package assets, not resolved from the process working directory:
40
- `src/config/package-paths.ts` resolves them from the package root. `package.json`
41
- includes `migrations/` in the published files, and the Dockerfile copies the
42
- migration directories into `/app/migrations`.
43
-
44
- ## Next schema change
45
-
46
- 1. Update `src/persistence/schema.ts` and add matching numbered migrations to
47
- both backends. Preserve released baseline files so existing baseline markers
48
- remain valid.
49
- 2. Update backup validation/mapping when old exported rows need normalization
50
- or new required values.
51
- 3. Run focused migration, restore, and typecheck tests. Validate against an
52
- isolated database only.
1
+ # Database baselines
2
+
3
+ Cartethyia keeps one SQL baseline per database backend:
4
+
5
+ - `full-postgres/0000_baseline.sql` defines the foundational PostgreSQL schema
6
+ for a new database.
7
+ - `lite-sqlite3/0000_baseline.sql` is generated from the PostgreSQL baseline by
8
+ `scripts/tools/generate-sqlite.ts`; do not edit it by hand.
9
+
10
+ The startup runner applies the baseline and numbered forward migrations,
11
+ recording them in `cartethyia_schema_migrations` along with a hash marker for
12
+ the exact baseline contents. Released baselines are immutable so existing
13
+ installations keep matching their marker; numbered migrations bring that
14
+ foundational schema up to the current schema. Each backend's migrations must
15
+ have matching behavior. Startup fails with a recovery instruction for a
16
+ database with unsupported retired migration history instead of treating it as
17
+ current.
18
+
19
+ ## Recovering an existing installation
20
+
21
+ 1. Export a backup from the existing installation before switching it to a
22
+ release with unsupported migration history.
23
+ 2. Create a fresh database and point the application at it.
24
+ 3. Start the application so it creates the baseline schema.
25
+ 4. Restore the backup through the console restore flow.
26
+
27
+ Restore normalizes legacy values that no longer satisfy current constraints,
28
+ including `bypass_proxy` → `skip_proxy`, `bridge` → `https`, the retired
29
+ provider User-Agent default, Cline's skip-proxy default, and `fusion` →
30
+ `fallback`. Unknown or retired columns are reported and skipped according to
31
+ the backup contract.
32
+
33
+ Do not point tests or recovery steps at development or production databases.
34
+ The startup path runs `ensureMigrated()` before provider/catalog seeding. Full
35
+ mode uses `src/persistence/db-pg.ts` and an advisory lock; Lite uses
36
+ `src/persistence/db-sqlite.ts`. Readiness compares the ledger to the available baseline and forward migration
37
+ files. A failed migration aborts startup and is not recorded.
38
+
39
+ Migrations are package assets, not resolved from the process working directory:
40
+ `src/config/package-paths.ts` resolves them from the package root. `package.json`
41
+ includes `migrations/` in the published files, and the Dockerfile copies the
42
+ migration directories into `/app/migrations`.
43
+
44
+ ## Next schema change
45
+
46
+ 1. Update `src/persistence/schema.ts` and add matching numbered migrations to
47
+ both backends. Preserve released baseline files so existing baseline markers
48
+ remain valid.
49
+ 2. Update backup validation/mapping when old exported rows need normalization
50
+ or new required values.
51
+ 3. Run focused migration, restore, and typecheck tests. Validate against an
52
+ isolated database only.
@@ -1,6 +1,6 @@
1
- -- Generated by scripts/generate/sqlite-ddl.ts from migrations/full-postgres/0000_baseline.sql.
1
+ -- Generated by scripts/tools/generate-sqlite.ts from migrations/full-postgres/0000_baseline.sql.
2
2
  -- Do not edit by hand: change src/persistence/schema.ts, then re-run
3
- -- `bun scripts/generate/sqlite-ddl.ts`. The PostgreSQL baseline this is
3
+ -- `bun scripts/tools/generate-sqlite.ts`. The PostgreSQL baseline this is
4
4
  -- derived from is hand-written and hash-pinned; add a numbered migration
5
5
  -- for a schema change instead of editing it.
6
6
  --> statement-breakpoint
package/package.json CHANGED
@@ -1,95 +1,95 @@
1
- {
2
- "name": "cartethyia",
3
- "version": "2.5.4",
4
- "description": "A powerful, self-hosted reverse proxy for OpenAI- and Anthropic-compatible AI clients, powered by native Bun and Elysia. It serves both protocols from a single server, routes every model across any configured provider, and translates requests and responses in real time — streaming and prompt caching included. Underneath it runs a full delivery engine: per-account health tracking, quota and cooldown enforcement, automatic failover across pools and providers, usage accounting, and telemetry. Point OpenCode, Cline, Claude Code, Codex, or any compatible client at Cartethyia and it keeps its native protocol while the gateway absorbs every provider-specific difference behind it. Runs on embedded SQLite or external PostgreSQL with optional Redis coordination, ships as a global CLI with a system-tray console, and needs only Bun 1.4+ alongside Node.js/npm.",
5
- "license": "GPL-3.0-only",
6
- "type": "module",
7
- "packageManager": "bun@1.4.0",
8
- "repository": {
9
- "type": "git",
10
- "url": "git+https://github.com/risunCodex/Cartethyia.git"
11
- },
12
- "homepage": "https://github.com/risunCodex/Cartethyia#readme",
13
- "bugs": {
14
- "url": "https://github.com/risunCodex/Cartethyia/issues"
15
- },
16
- "keywords": [
17
- "ai",
18
- "gateway",
19
- "llm",
20
- "bun",
21
- "self-hosted"
22
- ],
23
- "bin": {
24
- "cartethyia": "scripts/cli/bin/cartethyia.cjs",
25
- "carte": "scripts/cli/bin/carte.cjs"
26
- },
27
- "files": [
28
- "scripts/cli/",
29
- "src/",
30
- "migrations/",
31
- "dist/dashboard/",
32
- ".env.example",
33
- "README.md"
34
- ],
35
- "workspaces": [
36
- "dashboard"
37
- ],
38
- "engines": {
39
- "bun": ">=1.4.0"
40
- },
41
- "scripts": {
42
- "dev": "bun run dev:stack",
43
- "dev:watch": "bun run scripts/dev/supervisor.ts",
44
- "test": "bun run scripts/ci/run.ts",
45
- "build": "bun run scripts/binary/build.ts",
46
- "prepack": "bun run dashboard:build",
47
- "setup": "bun run scripts/cli/command/setup.ts",
48
- "start": "bun run scripts/cli/main.ts start",
49
- "doctor": "bun run scripts/cli/command/doctor.ts",
50
- "probe:egress": "bun run scripts/operations/probe-egress.ts",
51
- "restart": "bun run scripts/binary/restart.ts",
52
- "build:aot": "bun run scripts/binary/aot.ts",
53
- "dev:stack": "concurrently -n BACKEND,DASHBOARD -c cyan,magenta --kill-others-on-fail \"bun run dev:backend\" \"bun run dashboard:dev\"",
54
- "typecheck": "tsc --noEmit",
55
- "test:watch": "bun run scripts/ci/run.ts --watch",
56
- "test-db:up": "docker compose -f docker-compose.test.yml up -d --wait postgres-test",
57
- "dev:backend": "bun run --hot src/main.ts",
58
- "dev:console-auth": "bun run scripts/qa/console-session.ts",
59
- "dev:visual-baseline": "bun run scripts/qa/visual-baseline.ts",
60
- "build:binary": "bun run scripts/binary/compile.ts",
61
- "test:backend": "bun run scripts/ci/run.ts --scope backend",
62
- "test-db:down": "docker compose -f docker-compose.test.yml down",
63
- "dashboard:dev": "bun run --cwd dashboard dev",
64
- "test-db:check": "bun run scripts/ci/db-check.ts",
65
- "dashboard:test": "bun run scripts/ci/run.ts --scope dashboard",
66
- "test-db:reset": "docker compose -f docker-compose.test.yml down -v && docker compose -f docker-compose.test.yml up -d --wait postgres-test",
67
- "dashboard:build": "bun run --cwd dashboard build",
68
- "dashboard:typecheck": "bun run --cwd dashboard typecheck",
69
- "check:migrations": "bun run scripts/ci/check-migrations.ts"
70
- },
71
- "dependencies": {
72
- "drizzle-orm": "0.45.2",
73
- "elysia": "^2.0.0-beta.16",
74
- "enquirer": "^2.4.1",
75
- "ioredis": "6.0.0",
76
- "jose": "^6.2.12",
77
- "jsonrepair": "^3.15.0",
78
- "pg": "8.23.0",
79
- "pino": "^10.3.1",
80
- "pino-pretty": "^13.1.3",
81
- "protobufjs": "^7.6.5",
82
- "socks-proxy-agent": "^10.1.0",
83
- "systray2": "2.1.4",
84
- "typebox": "1.3.27",
85
- "ws": "8.22.0"
86
- },
87
- "devDependencies": {
88
- "@types/pg": "8.11.10",
89
- "@types/ws": "8.18.1",
90
- "bun-types": "1.4.0",
91
- "concurrently": "^10.0.5",
92
- "drizzle-kit": "^0.31.11",
93
- "typescript": "5.9.2"
94
- }
95
- }
1
+ {
2
+ "name": "cartethyia",
3
+ "version": "2.5.7",
4
+ "description": "A powerful, self-hosted reverse proxy for OpenAI- and Anthropic-compatible AI clients, powered by native Bun and Elysia. It serves both protocols from a single server, routes every model across any configured provider, and translates requests and responses in real time \u2014 streaming and prompt caching included. Underneath it runs a full delivery engine: per-account health tracking, quota and cooldown enforcement, automatic failover across pools and providers, usage accounting, and telemetry. Point OpenCode, Cline, Claude Code, Codex, or any compatible client at Cartethyia and it keeps its native protocol while the gateway absorbs every provider-specific difference behind it. Runs on embedded SQLite or external PostgreSQL with optional Redis coordination, ships as a global CLI with a system-tray console, and needs only Bun 1.4+ alongside Node.js/npm.",
5
+ "license": "GPL-3.0-only",
6
+ "type": "module",
7
+ "packageManager": "bun@1.4.0",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/risunCodex/Cartethyia.git"
11
+ },
12
+ "homepage": "https://github.com/risunCodex/Cartethyia#readme",
13
+ "bugs": {
14
+ "url": "https://github.com/risunCodex/Cartethyia/issues"
15
+ },
16
+ "keywords": [
17
+ "ai",
18
+ "gateway",
19
+ "llm",
20
+ "bun",
21
+ "self-hosted"
22
+ ],
23
+ "bin": {
24
+ "cartethyia": "scripts/cli/bin/cartethyia.cjs",
25
+ "carte": "scripts/cli/bin/carte.cjs"
26
+ },
27
+ "files": [
28
+ "scripts/cli/",
29
+ "src/",
30
+ "migrations/",
31
+ "dist/dashboard/",
32
+ ".env.example",
33
+ "README.md"
34
+ ],
35
+ "workspaces": [
36
+ "dashboard"
37
+ ],
38
+ "engines": {
39
+ "bun": ">=1.4.0"
40
+ },
41
+ "scripts": {
42
+ "dev": "bun run dev:stack",
43
+ "dev:watch": "bun run scripts/dev/supervisor.ts",
44
+ "test": "bun run scripts/test/run.ts",
45
+ "build": "bun run scripts/build/build.ts",
46
+ "prepack": "bun run dashboard:build",
47
+ "setup": "bun run scripts/cli/setup.ts",
48
+ "start": "bun run scripts/cli/main.ts start",
49
+ "doctor": "bun run scripts/cli/doctor.ts",
50
+ "probe:egress": "bun run scripts/tools/probe-egress.ts",
51
+ "restart": "bun run scripts/build/restart.ts",
52
+ "build:aot": "bun run scripts/build/aot.ts",
53
+ "dev:stack": "concurrently -n BACKEND,DASHBOARD -c cyan,magenta --kill-others-on-fail \"bun run dev:backend\" \"bun run dashboard:dev\"",
54
+ "typecheck": "tsc --noEmit",
55
+ "test:watch": "bun run scripts/test/run.ts --watch",
56
+ "test-db:up": "docker compose -f docker-compose.test.yml up -d --wait postgres-test",
57
+ "dev:backend": "bun run --hot src/main.ts",
58
+ "dev:console-auth": "bun run scripts/test/console-session.ts",
59
+ "dev:visual-baseline": "bun run scripts/test/visual-baseline.ts",
60
+ "build:binary": "bun run scripts/build/compile.ts",
61
+ "test:backend": "bun run scripts/test/run.ts --scope backend",
62
+ "test-db:down": "docker compose -f docker-compose.test.yml down",
63
+ "dashboard:dev": "bun run --cwd dashboard dev",
64
+ "test-db:check": "bun run scripts/test/check-db.ts",
65
+ "dashboard:test": "bun run scripts/test/run.ts --scope dashboard",
66
+ "test-db:reset": "docker compose -f docker-compose.test.yml down -v && docker compose -f docker-compose.test.yml up -d --wait postgres-test",
67
+ "dashboard:build": "bun run --cwd dashboard build",
68
+ "dashboard:typecheck": "bun run --cwd dashboard typecheck",
69
+ "check:migrations": "bun run scripts/test/check-migrations.ts"
70
+ },
71
+ "dependencies": {
72
+ "drizzle-orm": "0.45.2",
73
+ "elysia": "2.0.0-beta.16",
74
+ "enquirer": "^2.4.1",
75
+ "ioredis": "6.0.0",
76
+ "jose": "^6.2.12",
77
+ "jsonrepair": "^3.15.0",
78
+ "pg": "8.23.0",
79
+ "pino": "^10.3.1",
80
+ "pino-pretty": "^13.1.3",
81
+ "protobufjs": "^7.6.5",
82
+ "socks-proxy-agent": "^10.1.0",
83
+ "systray2": "2.1.4",
84
+ "typebox": "1.3.27",
85
+ "ws": "8.22.0"
86
+ },
87
+ "devDependencies": {
88
+ "@types/pg": "8.11.10",
89
+ "@types/ws": "8.18.1",
90
+ "bun-types": "1.4.0",
91
+ "concurrently": "^10.0.5",
92
+ "drizzle-kit": "^0.31.11",
93
+ "typescript": "5.9.2"
94
+ }
95
+ }
@@ -0,0 +1,125 @@
1
+ /**
2
+ * The two admin actions the menu and the tray both offer.
3
+ *
4
+ * Both go through the running gateway rather than the database file: the
5
+ * gateway holds the connection and the schema is dialect-dependent, so reading
6
+ * or writing the tables from this process would need a second implementation
7
+ * of both.
8
+ */
9
+
10
+ import { ENV_PATH, readEnvFile } from "./env";
11
+
12
+ /**
13
+ * Asks the gateway to write a gzipped config backup into the download
14
+ * directory. Returns the written path and counts, or null when it failed.
15
+ */
16
+ export async function exportBackup(
17
+ port: number,
18
+ token: string,
19
+ ): Promise<{ path: string; bytes: number; counts: Record<string, number> } | null> {
20
+ try {
21
+ const response = await fetch(`http://127.0.0.1:${port}/admin/export-backup`, {
22
+ method: "POST",
23
+ headers: { "content-type": "application/json", "x-drain-token": token },
24
+ body: JSON.stringify({}),
25
+ signal: AbortSignal.timeout(60_000),
26
+ });
27
+ if (!response.ok) {
28
+ const detail = await response.text().catch(() => "");
29
+ console.error(`The gateway refused the backup (HTTP ${response.status}). ${detail}`.trim());
30
+ return null;
31
+ }
32
+ return (await response.json()) as {
33
+ path: string;
34
+ bytes: number;
35
+ counts: Record<string, number>;
36
+ };
37
+ } catch {
38
+ console.error("Could not reach the gateway. Is it still running?");
39
+ return null;
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Posts the console-account reset to the running gateway.
45
+ *
46
+ * Returns 0 on success and 1 on any failure so the caller can print one line
47
+ * either way.
48
+ */
49
+ export async function resetConsoleAccount(port: number, token: string): Promise<number> {
50
+ try {
51
+ const response = await fetch(`http://127.0.0.1:${port}/admin/reset-console-account`, {
52
+ method: "POST",
53
+ headers: { "content-type": "application/json", "x-drain-token": token },
54
+ body: JSON.stringify({ confirm: "RESET" }),
55
+ signal: AbortSignal.timeout(10_000),
56
+ });
57
+ if (!response.ok) {
58
+ const detail = await response.text().catch(() => "");
59
+ console.error(`The gateway refused the reset (HTTP ${response.status}). ${detail}`.trim());
60
+ return 1;
61
+ }
62
+ return 0;
63
+ } catch {
64
+ console.error("Could not reach the gateway. Is it still running?");
65
+ return 1;
66
+ }
67
+ }
68
+
69
+
70
+ /**
71
+ * Operator escape hatch: clears the console login lockout bucket.
72
+ *
73
+ * The lockout is keyed by `<username>:<clientIp>` and lasts an hour, and there
74
+ * is no console surface to clear it — a locked-out operator has no way back in
75
+ * short of editing the database by hand. This is the documented reset.
76
+ *
77
+ * Usage:
78
+ * cartethyia admin reset-lockout <username> <clientIp>
79
+ * cartethyia admin reset-lockout --all
80
+ */
81
+ export async function resetLockout(args: readonly string[]): Promise<void> {
82
+ const all = args.includes("--all");
83
+ const positional = args.filter((arg) => !arg.startsWith("--"));
84
+ if (!all && positional.length < 2) {
85
+ console.error("Usage: cartethyia admin reset-lockout <username> <clientIp>");
86
+ console.error(" cartethyia admin reset-lockout --all");
87
+ process.exit(1);
88
+ }
89
+
90
+ const env = await readEnvFile(ENV_PATH);
91
+ const databaseUrl = env.DATABASE_URL ?? process.env.DATABASE_URL;
92
+ if (!databaseUrl) {
93
+ console.error("✗ DATABASE_URL is not set; cannot reach the lockout table.");
94
+ process.exit(1);
95
+ }
96
+ process.env.DATABASE_URL = databaseUrl;
97
+
98
+ const { getDb, closeDb } = await import("../../src/persistence/boot");
99
+ const { consoleLockouts } = await import("../../src/persistence/schema");
100
+ const { eq, or } = await import("drizzle-orm");
101
+
102
+ const db = getDb();
103
+ try {
104
+ if (all) {
105
+ const cleared = await db.delete(consoleLockouts).returning({ ip: consoleLockouts.ip });
106
+ console.log(`✓ Cleared ${cleared.length} lockout row(s).`);
107
+ return;
108
+ }
109
+ const username = positional[0]!.trim().toLowerCase();
110
+ const clientIp = positional[1]!;
111
+ // The bucket key is `<identifier>:<ip>`; match either exact spelling so
112
+ // an operator does not have to guess how the identifier was normalized.
113
+ const cleared = await db
114
+ .delete(consoleLockouts)
115
+ .where(or(eq(consoleLockouts.ip, `${username}:${clientIp}`), eq(consoleLockouts.ip, clientIp)))
116
+ .returning({ ip: consoleLockouts.ip });
117
+ if (cleared.length === 0) {
118
+ console.log(`• No lockout row for ${username}:${clientIp} (already clear).`);
119
+ } else {
120
+ console.log(`✓ Cleared lockout for ${cleared.map((row) => row.ip).join(", ")}.`);
121
+ }
122
+ } finally {
123
+ await closeDb();
124
+ }
125
+ }
@@ -1,6 +1,6 @@
1
1
  import { spawn } from "node:child_process";
2
2
  import { readFileSync, unlinkSync } from "node:fs";
3
- import { PACKAGE_ROOT, resolvePackagePath } from "../../../src/config/package-paths";
3
+ import { PACKAGE_ROOT, resolvePackagePath } from "../../src/config/package-paths";
4
4
 
5
5
  /** Opens a URL in the operator's default browser, ignoring a missing handler. */
6
6
  export function openUrl(url: string): Promise<void> {