cartethyia 2.5.4 → 2.5.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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-CADDq4IU.js} +1 -1
  4. package/dist/dashboard/assets/BannedPage-CADDq4IU.js.gz +0 -0
  5. package/dist/dashboard/assets/CliToolDetailPage-_z1hID7E.js +1 -0
  6. package/dist/dashboard/assets/CliToolDetailPage-_z1hID7E.js.gz +0 -0
  7. package/dist/dashboard/assets/{CliToolsPage-BV6pxVQo.js → CliToolsPage-DuO1Z7dq.js} +1 -1
  8. package/dist/dashboard/assets/CliToolsPage-DuO1Z7dq.js.gz +0 -0
  9. package/dist/dashboard/assets/CombosPage-DNEPi3xU.js +1 -0
  10. package/dist/dashboard/assets/CombosPage-DNEPi3xU.js.gz +0 -0
  11. package/dist/dashboard/assets/{ConsoleLogPage-CW-wPmJ6.js → ConsoleLogPage-BVdpfiz1.js} +1 -1
  12. package/dist/dashboard/assets/ConsoleLogPage-BVdpfiz1.js.gz +0 -0
  13. package/dist/dashboard/assets/{CustomizationPage-0p8uX7vB.js → CustomizationPage-BR5HHvbi.js} +1 -1
  14. package/dist/dashboard/assets/CustomizationPage-BR5HHvbi.js.gz +0 -0
  15. package/dist/dashboard/assets/{HealthEventsModal-BjqSMfko.js → HealthEventsModal-mUfcknqm.js} +1 -1
  16. package/dist/dashboard/assets/HealthEventsModal-mUfcknqm.js.gz +0 -0
  17. package/dist/dashboard/assets/{LoginPage-BvzCx8Kr.js → LoginPage-V5faV9V2.js} +1 -1
  18. package/dist/dashboard/assets/LoginPage-V5faV9V2.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-BDu20Jdx.js +1 -0
  22. package/dist/dashboard/assets/OverviewPage-BDu20Jdx.js.gz +0 -0
  23. package/dist/dashboard/assets/ProviderDetailPage-Dllr_aFO.js +3 -0
  24. package/dist/dashboard/assets/ProviderDetailPage-Dllr_aFO.js.gz +0 -0
  25. package/dist/dashboard/assets/{ProvidersPage-Js9jUPSb.js → ProvidersPage-uPiGVTTK.js} +1 -1
  26. package/dist/dashboard/assets/ProvidersPage-uPiGVTTK.js.gz +0 -0
  27. package/dist/dashboard/assets/ProxyPage-BaUkO-4O.js +7 -0
  28. package/dist/dashboard/assets/ProxyPage-BaUkO-4O.js.gz +0 -0
  29. package/dist/dashboard/assets/QuotaPage-o0IFAsFb.js +1 -0
  30. package/dist/dashboard/assets/QuotaPage-o0IFAsFb.js.gz +0 -0
  31. package/dist/dashboard/assets/SettingsPage-CYWqbXjp.js +1 -0
  32. package/dist/dashboard/assets/SettingsPage-CYWqbXjp.js.gz +0 -0
  33. package/dist/dashboard/assets/{SetupPage-DDbMQsoo.js → SetupPage-UB690SE2.js} +1 -1
  34. package/dist/dashboard/assets/SetupPage-UB690SE2.js.gz +0 -0
  35. package/dist/dashboard/assets/{SortableList-CB3Z7VTf.js → SortableList-BLujdX7N.js} +1 -1
  36. package/dist/dashboard/assets/SortableList-BLujdX7N.js.gz +0 -0
  37. package/dist/dashboard/assets/{StudioPage-D95UCPHI.js → StudioPage-D5C2raAc.js} +3 -3
  38. package/dist/dashboard/assets/StudioPage-D5C2raAc.js.gz +0 -0
  39. package/dist/dashboard/assets/UsagePage-8uIcxa1W.js +56 -0
  40. package/dist/dashboard/assets/UsagePage-8uIcxa1W.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-CTP8AyiS.js +1 -0
  66. package/dist/dashboard/assets/entry-CTP8AyiS.js.gz +0 -0
  67. package/dist/dashboard/assets/entry-DxBHnauy.js +4 -0
  68. package/dist/dashboard/assets/entry-DxBHnauy.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-CmxZr14F.js} +2 -2
  72. package/dist/dashboard/assets/index-CmxZr14F.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-BYR_5K2c.js} +1 -1
  94. package/dist/dashboard/assets/select-BYR_5K2c.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 +96 -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
@@ -3,20 +3,68 @@ import { DrizzleTelemetryStore } from "../persistence/stores/telemetry-store";
3
3
  import { prunePayloadFrames, writePayloadFrame } from "./payload-store";
4
4
  import { resolveTelemetryPayloadMaxBytes } from "../config/telemetry";
5
5
  import { preferencesReaderFor } from "../persistence/tenant-preferences";
6
- import type { TelemetryPayloadDepth, TelemetryPayloadMode } from "../console/settings/contracts";
6
+ import type {
7
+ TelemetryPayloadDepth,
8
+ TelemetryPayloadMode,
9
+ TelemetryPayloadRetentionMinutes,
10
+ } from "../console/settings/contracts";
7
11
  export type CaptureScope = "tenant" | "debug_session" | "operator_flag";
8
12
 
13
+ /**
14
+ * How long a captured payload frame lives when the deployment has not chosen.
15
+ *
16
+ * Exported so surfaces that report on disk usage quote the same window the
17
+ * capture path enforces, rather than a second copy of the default that would
18
+ * drift the first time this one changes.
19
+ */
20
+ export function payloadRetentionMs(): number {
21
+ const raw = Number(process.env.CARTETHYIA_TELEMETRY_PAYLOAD_RETENTION_MS ?? 15 * 60_000);
22
+ if (!Number.isFinite(raw) || raw < 1_000 || raw > MAX_PAYLOAD_RETENTION_MS) return 15 * 60_000;
23
+ return Math.floor(raw);
24
+ }
25
+
26
+ /**
27
+ * The longest payload retention a tenant may ask for: seven days.
28
+ *
29
+ * Two things depend on this being a hard ceiling rather than a suggestion.
30
+ *
31
+ * The prune pass deletes a frame file it cannot parse once the file's last
32
+ * write is older than the retention window — that bound is the only thing that
33
+ * makes a damaged file reclaimable at all. A tenant allowed to keep frames for
34
+ * a year while the prune assumed an hour would have live frames deleted out
35
+ * from under them.
36
+ *
37
+ * The disk-usage panel counts a frame as reclaimable once its file is older
38
+ * than the same window. Without a ceiling it would offer a reclaim button for
39
+ * frames that are still live, and the operator would press it and see
40
+ * "nothing to reclaim".
41
+ */
42
+ export const MAX_PAYLOAD_RETENTION_MS = 7 * 24 * 60 * 60_000;
43
+
44
+ /** Milliseconds one tenant's chosen retention resolves to. */
45
+ export function retentionMsFor(minutes: number | null | undefined): number {
46
+ if (minutes === null || minutes === undefined) return payloadRetentionMs();
47
+ if (!Number.isFinite(minutes)) return payloadRetentionMs();
48
+ return Math.min(Math.max(1_000, Math.floor(minutes * 60_000)), MAX_PAYLOAD_RETENTION_MS);
49
+ }
50
+
9
51
  /**
10
52
  * Settings-gated payload capture. Request-event metadata is always retained;
11
53
  * tenants opt into drawer capture through Settings → Privacy: `metadata`
12
54
  * keeps only the Proxy→Provider request line, `full` keeps redacted bodies
13
- * at the tenant's chosen depth. Fail-closed on error.
55
+ * at the tenant's chosen depth, and both live for the tenant's chosen
56
+ * retention. Fail-closed on error.
14
57
  */
15
58
  export async function resolvePayloadCapture(
16
59
  db: CartethyiaDatabase,
17
60
  tenantId: string | null,
18
61
  ): Promise<
19
- | { readonly ok: true; readonly mode: TelemetryPayloadMode; readonly depth: TelemetryPayloadDepth }
62
+ | {
63
+ readonly ok: true;
64
+ readonly mode: TelemetryPayloadMode;
65
+ readonly depth: TelemetryPayloadDepth;
66
+ readonly retentionMs: number;
67
+ }
20
68
  | { readonly ok: false }
21
69
  > {
22
70
  if (!tenantId) return { ok: false };
@@ -24,6 +72,7 @@ export async function resolvePayloadCapture(
24
72
  const prefs = await preferencesReaderFor(db).readPreferences(tenantId);
25
73
  const mode = prefs?.telemetryPayloads;
26
74
  const depth = prefs?.telemetryPayloadDepth;
75
+ const retention = prefs?.telemetryPayloadRetentionMinutes;
27
76
  return {
28
77
  ok: true,
29
78
  mode: mode === "full" || mode === "metadata" || mode === "none" ? mode : "none",
@@ -37,12 +86,13 @@ export async function resolvePayloadCapture(
37
86
  : depth === "full"
38
87
  ? "maximum"
39
88
  : "minimum",
89
+ retentionMs: retentionMsFor(retention as TelemetryPayloadRetentionMinutes | undefined),
40
90
  };
41
91
  } catch {
42
92
  // A preference read that fails must not invent capture. Off keeps nothing.
43
93
  // Reported as its own state rather than silently as `none`: an operator
44
94
  // whose capture is off by choice and one whose preference read is failing
45
- // need different fixes, and both used to look like "not configured".
95
+ // need different fixes, and both would otherwise look like "not configured".
46
96
  return { ok: false };
47
97
  }
48
98
  }
@@ -99,6 +149,12 @@ export interface PayloadCaptureInput {
99
149
  * Defaults to the configured capture limit.
100
150
  */
101
151
  maxBytes?: number;
152
+ /**
153
+ * How long this frame lives, in ms. Defaults to the tenant's chosen
154
+ * retention, then the deployment default. Bounded by
155
+ * {@link MAX_PAYLOAD_RETENTION_MS} either way.
156
+ */
157
+ retentionMs?: number;
102
158
  scope: CaptureScope;
103
159
  /** Links the row to `telemetry_events.request_id`. */
104
160
  requestId?: string;
@@ -147,11 +203,6 @@ export interface StoredPayload {
147
203
  * capture path enforces, rather than a second copy of the default that would
148
204
  * drift the first time this one changes.
149
205
  */
150
- export function payloadRetentionMs(): number {
151
- const raw = Number(process.env.CARTETHYIA_TELEMETRY_PAYLOAD_RETENTION_MS ?? 15 * 60_000);
152
- if (!Number.isFinite(raw) || raw < 1_000 || raw > 7 * 24 * 60 * 60_000) return 15 * 60_000;
153
- return Math.floor(raw);
154
- }
155
206
  function isCaptureAllowed(input: PayloadCaptureInput): boolean {
156
207
  // Exactly one opt-in must be set, and it must be the one `scope` names:
157
208
  // two flags at once would silently widen capture beyond the declared scope.
@@ -209,28 +260,29 @@ function payloadSignals(values: readonly unknown[]): PayloadSignals {
209
260
  * `maxBytes` (post-redaction, defaulting to the configured capture limit): a
210
261
  * body that no longer fits is replaced with a truncation marker — no object
211
262
  * store exists, so an oversized body is never referenced, only accounted.
212
- * Payloads remain redacted and bounded during the 15-minute retention window.
263
+ * Payloads remain redacted and bounded during their retention window.
213
264
  *
214
265
  * Drawer order is the allocation order, and that is deliberate: the cap is a
215
266
  * single shared budget, so whatever is accounted first is what survives a
216
267
  * large request. `response_body` is the legacy alias of the client response
217
- * and names no panel of its own, so it is accounted **last** — while it was
218
- * second, a large client request plus its own duplicate consumed the whole
219
- * budget before the Provider Request and Provider Response panels were
220
- * reached, and those two read empty for a request that did reach an upstream.
268
+ * and names no panel of its own, so it is accounted **last** — accounting it
269
+ * earlier lets a large client request plus its own duplicate consume the whole
270
+ * budget before the Provider Request and Provider Response panels are reached,
271
+ * and those two then read empty for a request that did reach an upstream.
221
272
  */
222
273
  export function buildPayloadRecord(
223
274
  input: PayloadCaptureInput,
224
275
  now = new Date(),
225
276
  maxBytes = resolveTelemetryPayloadMaxBytes(),
277
+ retentionMs = payloadRetentionMs(),
226
278
  ): Omit<StoredPayload, "id"> {
227
- const expiresAt = new Date(now.getTime() + payloadRetentionMs());
279
+ const expiresAt = new Date(now.getTime() + retentionMs);
228
280
  // Each body is serialized once, in drawer order, and only while the running
229
- // total still fits the cap. The old path serialized every body up front to
230
- // measure them and then serialized the whole record again to store it, so a
231
- // capture held two copies of every body at once — measured at 23 MB of heap
232
- // for 8 MB of bodies. A body that would cross the cap is never touched: its
233
- // text is not built and its object is not walked for signals.
281
+ // total still fits the cap. Serializing every body up front to measure them
282
+ // and then serializing the whole record again to store it holds two copies of
283
+ // every body at once — measured at 23 MB of heap for 8 MB of bodies. A body
284
+ // that would cross the cap is never touched: its text is not built and its
285
+ // object is not walked for signals.
234
286
  const surfaces: ReadonlyArray<readonly [keyof StoredPayload, unknown]> = [
235
287
  ["request_body", input.requestBody],
236
288
  ["provider_request_body", input.providerRequestBody],
@@ -270,11 +322,11 @@ export function buildPayloadRecord(
270
322
  serialized.push(text);
271
323
  kept.push(body);
272
324
  }
273
- // Only a surface that *had* a body and lost it to the cap is marked. The
274
- // previous form stamped the marker onto every null surface, including ones
275
- // that never carried anything — a request that never reached an upstream
276
- // then reported "truncated" for a provider panel that was never captured,
277
- // and the stage bitmask counted a marker as captured content.
325
+ // Only a surface that *had* a body and lost it to the cap is marked.
326
+ // Stamping the marker onto every null surface would also mark surfaces that
327
+ // never carried anything — a request that never reached an upstream then
328
+ // reports "truncated" for a provider panel that was never captured, and the
329
+ // stage bitmask counts a marker as captured content.
278
330
  const marker = (originalBytes: number): unknown => ({
279
331
  _truncated: true,
280
332
  _original_bytes: originalBytes,
@@ -310,14 +362,26 @@ export function buildPayloadRecord(
310
362
  }
311
363
 
312
364
  /**
313
- * Postgres-backed redacted request/response payload capture. Payloads have a
314
- * 15-minute retention window and are automatically pruned.
365
+ * Postgres-backed redacted request/response payload capture. Payloads live for
366
+ * the tenant's chosen retention — 15 minutes by default — and are pruned by the
367
+ * sweep.
315
368
 
316
369
  */
317
370
  export class TelemetryPayloadCapture {
318
371
  private readonly store: DrizzleTelemetryStore;
319
372
 
320
- constructor(db: CartethyiaDatabase) {
373
+ constructor(
374
+ db: CartethyiaDatabase,
375
+ /**
376
+ * Reads the tenant's chosen retention for captures that arrive without one.
377
+ *
378
+ * Injected rather than imported so the capture path does not depend on the
379
+ * console's settings module, and so a test can pin a retention without
380
+ * touching the database. Absent means every capture uses the deployment
381
+ * default, which is what a probe or a debug session wants anyway.
382
+ */
383
+ private readonly retentionFor?: (tenantId: string) => Promise<number> | number,
384
+ ) {
321
385
  this.store = new DrizzleTelemetryStore(db);
322
386
  }
323
387
 
@@ -327,7 +391,17 @@ export class TelemetryPayloadCapture {
327
391
  code: "capture_not_opted_in",
328
392
  });
329
393
  }
330
- const record = buildPayloadRecord(input, new Date(), input.maxBytes ?? resolveTelemetryPayloadMaxBytes());
394
+ // A caller that knows the answer passes it; otherwise the tenant's own
395
+ // preference is resolved, and failing that the deployment default. The
396
+ // early-rejection path has no preference to hand and lands here, which is
397
+ // why the default must be the deployment one rather than the shortest.
398
+ const retentionMs = await resolveRetention(input, this.retentionFor);
399
+ const record = buildPayloadRecord(
400
+ input,
401
+ new Date(),
402
+ input.maxBytes ?? resolveTelemetryPayloadMaxBytes(),
403
+ retentionMs,
404
+ );
331
405
  const reference = await writePayloadFrame(record, record.expires_at, record._serialized
332
406
  ? {
333
407
  requestId: record.request_id,
@@ -364,10 +438,54 @@ export class TelemetryPayloadCapture {
364
438
  deleted += batch;
365
439
  if (batch < batchSize) break;
366
440
  }
367
- // Every frame expires `payloadRetentionMs()` after it is written, so a file
368
- // last written before that window closed cannot still hold a live frame.
369
- // That bound is what makes a damaged, unparsable file reclaimable at all.
370
- deleted += await prunePayloadFrames(now, new Date(now.getTime() - payloadRetentionMs()));
441
+ // A file last written before *the longest retention a tenant can choose*
442
+ // closed cannot still hold a live frame — whatever its tenant picked, that
443
+ // frame has expired. Using the deployment default here instead was correct
444
+ // only while every frame shared one window: with a tenant allowed to keep
445
+ // frames for a week, a 15-minute bound would delete files still holding
446
+ // frames their rows address, and the drawer would silently read empty.
447
+ deleted += await prunePayloadFrames(now, payloadPruneBound(now));
371
448
  return { deleted };
372
449
  }
373
450
  }
451
+
452
+ /**
453
+ * The cutoff before which a frame file can be deleted wholesale.
454
+ *
455
+ * Every frame expires at most {@link MAX_PAYLOAD_RETENTION_MS} after it is
456
+ * written, so a file last touched before that instant cannot still hold a live
457
+ * frame — and that is the only thing that makes a damaged, unparsable file
458
+ * reclaimable at all. Exported so the bound is pinned without a database: the
459
+ * alternative is a test that deletes a live frame and notices nothing.
460
+ */
461
+ export function payloadPruneBound(now: Date): Date {
462
+ return new Date(now.getTime() - MAX_PAYLOAD_RETENTION_MS);
463
+ }
464
+
465
+ /**
466
+ * How long one capture's frame should live.
467
+ *
468
+ * Order of authority: the caller's own value, then the tenant's preference,
469
+ * then the deployment default. A failure resolving the tenant's preference
470
+ * falls back rather than throwing — an unknown retention must not turn into a
471
+ * lost capture, and the deployment default is always a valid answer.
472
+ */
473
+ export async function resolveRetention(
474
+ input: PayloadCaptureInput,
475
+ retentionFor?: (tenantId: string) => Promise<number> | number,
476
+ ): Promise<number> {
477
+ if (typeof input.retentionMs === "number" && Number.isFinite(input.retentionMs)) {
478
+ return Math.min(Math.max(1_000, Math.floor(input.retentionMs)), MAX_PAYLOAD_RETENTION_MS);
479
+ }
480
+ if (retentionFor) {
481
+ try {
482
+ const value = await retentionFor(input.tenantId);
483
+ if (Number.isFinite(value)) {
484
+ return Math.min(Math.max(1_000, Math.floor(value)), MAX_PAYLOAD_RETENTION_MS);
485
+ }
486
+ } catch {
487
+ // Falls through to the deployment default below.
488
+ }
489
+ }
490
+ return payloadRetentionMs();
491
+ }