cartethyia 2.4.4 → 2.4.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 (304) hide show
  1. package/.env.example +4 -1
  2. package/README.md +18 -0
  3. package/dist/dashboard/assets/AccountCooldown-ChpdzxRH.js.gz +0 -0
  4. package/dist/dashboard/assets/{BannedPage-TDue2X0p.js → BannedPage-QhvbJB9o.js} +1 -1
  5. package/dist/dashboard/assets/BannedPage-QhvbJB9o.js.gz +0 -0
  6. package/dist/dashboard/assets/{CliToolDetailPage-qaHXuiI5.js → CliToolDetailPage-Bcy150Jo.js} +1 -1
  7. package/dist/dashboard/assets/CliToolDetailPage-Bcy150Jo.js.gz +0 -0
  8. package/dist/dashboard/assets/{CliToolsPage-BFuQBKez.js → CliToolsPage-DyNXefph.js} +1 -1
  9. package/dist/dashboard/assets/CliToolsPage-DyNXefph.js.gz +0 -0
  10. package/dist/dashboard/assets/CombosPage-Cak0ljnO.js +1 -0
  11. package/dist/dashboard/assets/CombosPage-Cak0ljnO.js.gz +0 -0
  12. package/dist/dashboard/assets/ConsoleLogPage-CATpAEOz.js +1 -0
  13. package/dist/dashboard/assets/ConsoleLogPage-CATpAEOz.js.gz +0 -0
  14. package/dist/dashboard/assets/{CustomizationPage-BhglcqyR.js → CustomizationPage-D6jEU7nL.js} +1 -1
  15. package/dist/dashboard/assets/CustomizationPage-D6jEU7nL.js.gz +0 -0
  16. package/dist/dashboard/assets/HealthEventsModal-CZkpn0a7.js +1 -0
  17. package/dist/dashboard/assets/HealthEventsModal-CZkpn0a7.js.gz +0 -0
  18. package/dist/dashboard/assets/{LoginPage-CeqROJrT.js → LoginPage-BJlMVN4U.js} +1 -1
  19. package/dist/dashboard/assets/LoginPage-BJlMVN4U.js.gz +0 -0
  20. package/dist/dashboard/assets/ModelPicker-Br3CXEau.js +1 -0
  21. package/dist/dashboard/assets/ModelPicker-Br3CXEau.js.gz +0 -0
  22. package/dist/dashboard/assets/{OverviewPage-CRXSAITY.js → OverviewPage-CQxXbo2g.js} +1 -1
  23. package/dist/dashboard/assets/OverviewPage-CQxXbo2g.js.gz +0 -0
  24. package/dist/dashboard/assets/ProviderDetailPage--0RBNh99.js +3 -0
  25. package/dist/dashboard/assets/ProviderDetailPage--0RBNh99.js.gz +0 -0
  26. package/dist/dashboard/assets/ProviderIcon-paOCq8I0.js.gz +0 -0
  27. package/dist/dashboard/assets/ProvidersPage-1M-C3mbu.js +1 -0
  28. package/dist/dashboard/assets/ProvidersPage-1M-C3mbu.js.gz +0 -0
  29. package/dist/dashboard/assets/ProxyPage-CXiumA53.js +7 -0
  30. package/dist/dashboard/assets/ProxyPage-CXiumA53.js.gz +0 -0
  31. package/dist/dashboard/assets/QuotaPage-BGDIfIYP.js +1 -0
  32. package/dist/dashboard/assets/QuotaPage-BGDIfIYP.js.gz +0 -0
  33. package/dist/dashboard/assets/{SettingsPage-YxRml8AT.js → SettingsPage-BHW4Zt06.js} +1 -1
  34. package/dist/dashboard/assets/SettingsPage-BHW4Zt06.js.gz +0 -0
  35. package/dist/dashboard/assets/SetupPage-VOYC_lIa.js +1 -0
  36. package/dist/dashboard/assets/SetupPage-VOYC_lIa.js.gz +0 -0
  37. package/dist/dashboard/assets/SortableList-DpOTnGuH.js +1 -0
  38. package/dist/dashboard/assets/SortableList-DpOTnGuH.js.gz +0 -0
  39. package/dist/dashboard/assets/StudioPage-BNIDLiU6.js +31 -0
  40. package/dist/dashboard/assets/StudioPage-BNIDLiU6.js.gz +0 -0
  41. package/dist/dashboard/assets/ToolIcon-K1ckcDKg.js.gz +0 -0
  42. package/dist/dashboard/assets/{UsagePage-B6LA4ewF.js → UsagePage-BAFaSDQV.js} +14 -14
  43. package/dist/dashboard/assets/UsagePage-BAFaSDQV.js.gz +0 -0
  44. package/dist/dashboard/assets/api-keys-BETfaMYZ.js +1 -0
  45. package/dist/dashboard/assets/api-keys-BETfaMYZ.js.gz +0 -0
  46. package/dist/dashboard/assets/app-BLCvGdzb.css +2 -0
  47. package/dist/dashboard/assets/app-BLCvGdzb.css.gz +0 -0
  48. package/dist/dashboard/assets/{app-BDJWMThu.js → app-Cjq7nrwu.js} +3 -3
  49. package/dist/dashboard/assets/app-Cjq7nrwu.js.gz +0 -0
  50. package/dist/dashboard/assets/arrow-left-CpBxkoxI.js.gz +0 -0
  51. package/dist/dashboard/assets/arrow-right-Dl5yKnp8.js.gz +0 -0
  52. package/dist/dashboard/assets/{assert-Bwh6DJTK.js → assert-7J6_LVD3.js} +1 -1
  53. package/dist/dashboard/assets/assert-7J6_LVD3.js.gz +0 -0
  54. package/dist/dashboard/assets/backup-file-gdKIlg8U.js.gz +0 -0
  55. package/dist/dashboard/assets/{badge-BwmwEOgA.js → badge-BTyGk_DL.js} +1 -1
  56. package/dist/dashboard/assets/badge-BTyGk_DL.js.gz +0 -0
  57. package/dist/dashboard/assets/{banner-BKBfKTqn.js → banner-bujTWYM4.js} +1 -1
  58. package/dist/dashboard/assets/banner-bujTWYM4.js.gz +0 -0
  59. package/dist/dashboard/assets/brain-Cwed_72z.js.gz +0 -0
  60. package/dist/dashboard/assets/{card-BTdbRFFg.js → card-B0Bnx5CA.js} +1 -1
  61. package/dist/dashboard/assets/card-B0Bnx5CA.js.gz +0 -0
  62. package/dist/dashboard/assets/check-D69FzdvC.js.gz +0 -0
  63. package/dist/dashboard/assets/chevron-right-BXIy5l3h.js.gz +0 -0
  64. package/dist/dashboard/assets/circle-alert-CntYHV5v.js.gz +0 -0
  65. package/dist/dashboard/assets/circle-check-BU3v_mFW.js.gz +0 -0
  66. package/dist/dashboard/assets/cli-tools-DE2ug812.js +1 -0
  67. package/dist/dashboard/assets/cli-tools-DE2ug812.js.gz +0 -0
  68. package/dist/dashboard/assets/clipboard-button-R_rArH8S.js +1 -0
  69. package/dist/dashboard/assets/clipboard-button-R_rArH8S.js.gz +0 -0
  70. package/dist/dashboard/assets/cog-CdWhsajs.js.gz +0 -0
  71. package/dist/dashboard/assets/copy-ngmQ9zcZ.js.gz +0 -0
  72. package/dist/dashboard/assets/{dialog-iocKA3jr.js → dialog-BWIP_EvW.js} +1 -1
  73. package/dist/dashboard/assets/dialog-BWIP_EvW.js.gz +0 -0
  74. package/dist/dashboard/assets/dialog-actions-B1axpEg7.js.gz +0 -0
  75. package/dist/dashboard/assets/download-A0SW9OCW.js.gz +0 -0
  76. package/dist/dashboard/assets/download-dRFo5_Wu.js.gz +0 -0
  77. package/dist/dashboard/assets/{drawer-CDKOTZdY.js → drawer-BKcgVugF.js} +1 -1
  78. package/dist/dashboard/assets/drawer-BKcgVugF.js.gz +0 -0
  79. package/dist/dashboard/assets/entry-7dpgvpJ3.js +4 -0
  80. package/dist/dashboard/assets/entry-7dpgvpJ3.js.gz +0 -0
  81. package/dist/dashboard/assets/entry-CcWkGR4a.js +1 -0
  82. package/dist/dashboard/assets/entry-CcWkGR4a.js.gz +0 -0
  83. package/dist/dashboard/assets/entry-kTiTFrvh.js +1 -0
  84. package/dist/dashboard/assets/entry-kTiTFrvh.js.gz +0 -0
  85. package/dist/dashboard/assets/eye-C_hawfH4.js.gz +0 -0
  86. package/dist/dashboard/assets/eye-off-Bk5g2luF.js.gz +0 -0
  87. package/dist/dashboard/assets/fingerprint-pattern-BWuHtbW4.js.gz +0 -0
  88. package/dist/dashboard/assets/gauge-BbIMy7MB.js.gz +0 -0
  89. package/dist/dashboard/assets/github-badge-Booc5mNe.js +1 -0
  90. package/dist/dashboard/assets/github-badge-Booc5mNe.js.gz +0 -0
  91. package/dist/dashboard/assets/image-BPaouViG.js.gz +0 -0
  92. package/dist/dashboard/assets/{index-BA_ni9Ix.js → index-D70pChfn.js} +2 -2
  93. package/dist/dashboard/assets/index-D70pChfn.js.gz +0 -0
  94. package/dist/dashboard/assets/{inline-DCejSLlA.js → inline-D1TCqM2D.js} +1 -1
  95. package/dist/dashboard/assets/inline-D1TCqM2D.js.gz +0 -0
  96. package/dist/dashboard/assets/{input-Bn4_kNav.js → input-B9oyU93y.js} +1 -1
  97. package/dist/dashboard/assets/input-B9oyU93y.js.gz +0 -0
  98. package/dist/dashboard/assets/jsx-runtime-CXUMngI_.js.gz +0 -0
  99. package/dist/dashboard/assets/key-round-UkavsGxp.js.gz +0 -0
  100. package/dist/dashboard/assets/layers-2-glBbjl.js.gz +0 -0
  101. package/dist/dashboard/assets/{layout-Bv-NxqZ5.js → layout-BArzXirQ.js} +1 -1
  102. package/dist/dashboard/assets/layout-BArzXirQ.js.gz +0 -0
  103. package/dist/dashboard/assets/{list-row-BLA0sldD.js → list-row-BVZzaoHF.js} +1 -1
  104. package/dist/dashboard/assets/list-row-BVZzaoHF.js.gz +0 -0
  105. package/dist/dashboard/assets/{live-YlifPYox.js → live-EmuIayqp.js} +1 -1
  106. package/dist/dashboard/assets/live-EmuIayqp.js.gz +0 -0
  107. package/dist/dashboard/assets/log-in-BmRjy60c.js.gz +0 -0
  108. package/dist/dashboard/assets/message-circle-CCxGwRvv.js.gz +0 -0
  109. package/dist/dashboard/assets/{model-bans-CVvHZ-qz.js → model-bans-CSPQ9xB0.js} +1 -1
  110. package/dist/dashboard/assets/model-bans-CSPQ9xB0.js.gz +0 -0
  111. package/dist/dashboard/assets/mutation-BkoLM5Ba.js +1 -0
  112. package/dist/dashboard/assets/mutation-BkoLM5Ba.js.gz +0 -0
  113. package/dist/dashboard/assets/numbers-CFL4_Dqc.js.gz +0 -0
  114. package/dist/dashboard/assets/pencil-768ysRAr.js.gz +0 -0
  115. package/dist/dashboard/assets/plus-DIdX_g-x.js.gz +0 -0
  116. package/dist/dashboard/assets/power-off-Yjw9GMJh.js +1 -0
  117. package/dist/dashboard/assets/power-off-Yjw9GMJh.js.gz +0 -0
  118. package/dist/dashboard/assets/privacy-mode-GM8bej85.js +1 -0
  119. package/dist/dashboard/assets/privacy-mode-GM8bej85.js.gz +0 -0
  120. package/dist/dashboard/assets/providers/agentrouter.svg.gz +0 -0
  121. package/dist/dashboard/assets/providers/aihubmix.svg.gz +0 -0
  122. package/dist/dashboard/assets/providers/alibaba-coding-plan.svg.gz +0 -0
  123. package/dist/dashboard/assets/providers/alibaba.svg.gz +0 -0
  124. package/dist/dashboard/assets/providers/antigravity.svg.gz +0 -0
  125. package/dist/dashboard/assets/providers/bai.svg.gz +0 -0
  126. package/dist/dashboard/assets/providers/blackbox.svg.gz +0 -0
  127. package/dist/dashboard/assets/providers/claude-code.svg.gz +0 -0
  128. package/dist/dashboard/assets/providers/exa.svg.gz +0 -0
  129. package/dist/dashboard/assets/providers/gmi-cloud.svg.gz +0 -0
  130. package/dist/dashboard/assets/providers/inferhub.svg.gz +0 -0
  131. package/dist/dashboard/assets/providers/muse.svg.gz +0 -0
  132. package/dist/dashboard/assets/providers/nous-research.svg.gz +0 -0
  133. package/dist/dashboard/assets/providers/openai-light.svg.gz +0 -0
  134. package/dist/dashboard/assets/providers/parallel.svg.gz +0 -0
  135. package/dist/dashboard/assets/providers/tokenharbor.svg.gz +0 -0
  136. package/dist/dashboard/assets/providers/zai-coding-plan.svg.gz +0 -0
  137. package/dist/dashboard/assets/{query-keys-ROf-g1Wi.js → query-keys-D7wX2vM5.js} +1 -1
  138. package/dist/dashboard/assets/query-keys-D7wX2vM5.js.gz +0 -0
  139. package/dist/dashboard/assets/quota-DZGyp0N5.js.gz +0 -0
  140. package/dist/dashboard/assets/refresh-cw-BqJFk4sU.js.gz +0 -0
  141. package/dist/dashboard/assets/rotate-ccw-CufcqITi.js.gz +0 -0
  142. package/dist/dashboard/assets/route-CNSNj9Zm.js.gz +0 -0
  143. package/dist/dashboard/assets/{routing-jntw9-Ui.js → routing-BExgxxBU.js} +1 -1
  144. package/dist/dashboard/assets/routing-BExgxxBU.js.gz +0 -0
  145. package/dist/dashboard/assets/scaling-nWE4Cx8f.js.gz +0 -0
  146. package/dist/dashboard/assets/search-JOKus9rb.js.gz +0 -0
  147. package/dist/dashboard/assets/{select-CGUuTQmj.js → select-C9mMoEpJ.js} +1 -1
  148. package/dist/dashboard/assets/select-C9mMoEpJ.js.gz +0 -0
  149. package/dist/dashboard/assets/settings-C4_Gn_wq.js +1 -0
  150. package/dist/dashboard/assets/settings-C4_Gn_wq.js.gz +0 -0
  151. package/dist/dashboard/assets/shield-check-DVS0Foqh.js.gz +0 -0
  152. package/dist/dashboard/assets/sliders-horizontal-ClG7dBeJ.js.gz +0 -0
  153. package/dist/dashboard/assets/sparkles-BRaRUxAU.js.gz +0 -0
  154. package/dist/dashboard/assets/{stack-C1kTcOmP.js → stack-Ca5HxI5i.js} +1 -1
  155. package/dist/dashboard/assets/stack-Ca5HxI5i.js.gz +0 -0
  156. package/dist/dashboard/assets/{state-DHKdg-pm.js → state-CzUPfLXo.js} +1 -1
  157. package/dist/dashboard/assets/state-CzUPfLXo.js.gz +0 -0
  158. package/dist/dashboard/assets/stream-retry-5QnVuSSo.js.gz +0 -0
  159. package/dist/dashboard/assets/{switch-DIDeAiz9.js → switch-DOUIky_i.js} +1 -1
  160. package/dist/dashboard/assets/switch-DOUIky_i.js.gz +0 -0
  161. package/dist/dashboard/assets/terminal-Bd4ee8TA.js +1 -0
  162. package/dist/dashboard/assets/terminal-Bd4ee8TA.js.gz +0 -0
  163. package/dist/dashboard/assets/toast-C76WrMhc.js +2 -0
  164. package/dist/dashboard/assets/toast-C76WrMhc.js.gz +0 -0
  165. package/dist/dashboard/assets/tokens-DDxMbSRL.js.gz +0 -0
  166. package/dist/dashboard/assets/trash-Cppn5c3R.js.gz +0 -0
  167. package/dist/dashboard/assets/use-clipboard-B0Sy03fE.js.gz +0 -0
  168. package/dist/dashboard/assets/use-presence-BSZEBx7U.js.gz +0 -0
  169. package/dist/dashboard/assets/use-reduced-motion-C4B0R6Sz.js.gz +0 -0
  170. package/dist/dashboard/assets/use-timeout-BwcBBRrT.js.gz +0 -0
  171. package/dist/dashboard/assets/{useMutation-DVmwOKU-.js → useMutation-D87FZwH0.js} +1 -1
  172. package/dist/dashboard/assets/useMutation-D87FZwH0.js.gz +0 -0
  173. package/dist/dashboard/assets/wrench-B6E1oEuY.js.gz +0 -0
  174. package/dist/dashboard/index.html +1 -1
  175. package/dist/dashboard/index.html.gz +0 -0
  176. package/dist/dashboard/precompressed-assets.json +123 -0
  177. package/migrations/full-postgres/0013_add_providers_tenant_id_index.sql +22 -0
  178. package/migrations/full-postgres/0014_add_provider_accounts_tenant_id_index.sql +21 -0
  179. package/migrations/lite-sqlite3/0000_baseline.sql +4 -2
  180. package/migrations/lite-sqlite3/0013_add_providers_tenant_id_index.sql +4 -0
  181. package/migrations/lite-sqlite3/0014_add_provider_accounts_tenant_id_index.sql +4 -0
  182. package/package.json +25 -30
  183. package/scripts/cli/{carte-launcher.cjs → bin/carte.cjs} +8 -8
  184. package/scripts/cli/{cli-launcher.cjs → bin/cartethyia.cjs} +167 -134
  185. package/scripts/cli/command/admin.ts +65 -0
  186. package/scripts/cli/command/console-menu.ts +227 -0
  187. package/scripts/cli/{doctor.ts → command/doctor.ts} +257 -258
  188. package/scripts/cli/{setup.ts → command/setup.ts} +8 -12
  189. package/scripts/cli/command/start.ts +13 -0
  190. package/scripts/cli/command/tray.ts +165 -0
  191. package/scripts/cli/command/update.ts +23 -0
  192. package/scripts/cli/{runtime-state.ts → gateway/drain-token.ts} +78 -78
  193. package/scripts/cli/gateway/spawn.ts +101 -0
  194. package/scripts/cli/gateway/stop.ts +51 -0
  195. package/scripts/cli/main.ts +94 -0
  196. package/scripts/cli/support/bun.ts +27 -0
  197. package/scripts/cli/support/env.ts +99 -0
  198. package/scripts/cli/support/platform.ts +64 -0
  199. package/scripts/cli/support/services.ts +88 -0
  200. package/scripts/cli/support/startup-signal.ts +23 -0
  201. package/scripts/cli/support/version.ts +37 -0
  202. package/scripts/cli/tray/hidden-window.vbs +28 -0
  203. package/scripts/cli/{tray.ts → tray/index.ts} +3 -3
  204. package/scripts/cli/{tray.ps1 → tray/windows.ps1} +107 -98
  205. package/scripts/cli/ui/background.ts +49 -0
  206. package/src/boot/app.ts +3 -1
  207. package/src/boot/dependencies.ts +36 -13
  208. package/src/config/providers.ts +27 -1
  209. package/src/config/spec.ts +11 -0
  210. package/src/console/backup/routes.ts +8 -0
  211. package/src/console/cli-tools/contracts.ts +6 -6
  212. package/src/console/console-router.ts +5 -3
  213. package/src/console/dashboard-assets.ts +81 -11
  214. package/src/console/observability/contracts.ts +54 -22
  215. package/src/console/observability/routes.ts +31 -6
  216. package/src/console/observability/store.ts +68 -28
  217. package/src/console/providers/catalog/public-model-store.ts +91 -60
  218. package/src/console/providers/catalog/store.ts +5 -1
  219. package/src/console/quota/account-quota-tenant.ts +9 -6
  220. package/src/console/response-compression.ts +69 -2
  221. package/src/console/routing/pools/probe-verdict.ts +72 -0
  222. package/src/console/share/share-router.ts +7 -4
  223. package/src/console/share/share-stats.ts +12 -5
  224. package/src/console/shared/read-through-cache.ts +133 -7
  225. package/src/console/updates/repository-updates.ts +39 -34
  226. package/src/network/outbound-fetch.ts +113 -25
  227. package/src/network/tls/bun-client-hello.ts +112 -0
  228. package/src/observability/event-log.ts +29 -8
  229. package/src/observability/metrics.ts +40 -13
  230. package/src/observability/runtime-metrics.ts +7 -0
  231. package/src/persistence/schema.ts +40 -2
  232. package/src/protocol/response/codex.ts +9 -75
  233. package/src/protocol/tool-identity.ts +43 -9
  234. package/src/providers/authentication/jwt-validator.ts +130 -187
  235. package/src/providers/authentication/oauth-flow-store.ts +16 -9
  236. package/src/providers/default-registry.ts +4 -0
  237. package/src/providers/discovery/catalog/catalog-format.ts +20 -0
  238. package/src/providers/discovery/models-dev-catalog.ts +39 -22
  239. package/src/providers/discovery/probe-wire.ts +29 -5
  240. package/src/providers/integrations/buddy/buddy-catalog-shared.ts +3 -2
  241. package/src/providers/integrations/buddy/buddy-cli-headers.ts +88 -0
  242. package/src/providers/integrations/buddy/buddy-conversation-headers.ts +4 -0
  243. package/src/providers/integrations/buddy/buddy-discovery-shared.ts +33 -1
  244. package/src/providers/integrations/buddy/buddy-identity.ts +46 -0
  245. package/src/providers/integrations/buddy/buddy-oauth-shared.ts +37 -1
  246. package/src/providers/integrations/buddy/buddy-usage-store.ts +40 -5
  247. package/src/providers/integrations/buddy/codebuddy/provider.ts +2 -2
  248. package/src/providers/integrations/buddy/codebuddy/shared.ts +106 -73
  249. package/src/providers/integrations/buddy/workbuddy/cn-provider.ts +5 -2
  250. package/src/providers/integrations/buddy/workbuddy/quota.ts +172 -159
  251. package/src/providers/integrations/buddy/workbuddy/shared.ts +200 -171
  252. package/src/providers/integrations/codex/codex.ts +5 -8
  253. package/src/providers/integrations/factory/factory-oauth.ts +7 -11
  254. package/src/providers/integrations/opencode/opencode-go-quota.ts +130 -0
  255. package/src/providers/integrations/opencode/provider.ts +42 -3
  256. package/src/providers/integrations/qoder/qoder-oauth.ts +3 -9
  257. package/src/providers/integrations/shared/install-id.ts +29 -2
  258. package/src/providers/operations/client-versions.ts +11 -1
  259. package/src/providers/operations/model-catalog-cache.ts +18 -3
  260. package/src/providers/operations/provider-catalog-service.ts +76 -0
  261. package/src/transport/dispatch/attempt-finalize.ts +7 -1
  262. package/src/transport/dispatch/attempt-loop.ts +9 -7
  263. package/src/transport/dispatch/empty-stream.ts +17 -26
  264. package/src/transport/failure-policy.ts +20 -0
  265. package/src/transport/routing/route-catalog.ts +42 -3
  266. package/src/transport/surface/chat/encode.ts +18 -31
  267. package/src/transport/surface/messages/stream.ts +3 -2
  268. package/src/transport/translation/tool-repair.ts +37 -16
  269. package/src/workers/account-identity-sweep.ts +14 -12
  270. package/src/workers/daily-checkin.ts +62 -0
  271. package/src/workers/quota-refresh-sweep.ts +27 -2
  272. package/dist/dashboard/assets/CombosPage-B7ETkfVH.js +0 -1
  273. package/dist/dashboard/assets/ConsoleLogPage-vkZBxMVo.js +0 -1
  274. package/dist/dashboard/assets/HealthEventsModal-DDkHfwpV.js +0 -1
  275. package/dist/dashboard/assets/ModelPicker-CAiPR5Vd.js +0 -1
  276. package/dist/dashboard/assets/ProviderDetailPage-cNAD_6uN.js +0 -3
  277. package/dist/dashboard/assets/ProvidersPage-Cv5tdxlx.js +0 -1
  278. package/dist/dashboard/assets/ProxyPage-CWvMfzjj.js +0 -7
  279. package/dist/dashboard/assets/QuotaPage-IYQOOHR4.js +0 -1
  280. package/dist/dashboard/assets/SetupPage-BPDNo3Ek.js +0 -1
  281. package/dist/dashboard/assets/SortableList-Bol1ASmI.js +0 -1
  282. package/dist/dashboard/assets/StudioPage-BE5DJONZ.js +0 -31
  283. package/dist/dashboard/assets/api-keys-CjIGQhe7.js +0 -1
  284. package/dist/dashboard/assets/app-Cjgo4-Lf.css +0 -2
  285. package/dist/dashboard/assets/cli-tools-DccaOfhX.js +0 -1
  286. package/dist/dashboard/assets/clipboard-button-DQmMikNQ.js +0 -1
  287. package/dist/dashboard/assets/entry-DTiWhIY-.js +0 -4
  288. package/dist/dashboard/assets/entry-Dm3PpDCO.js +0 -1
  289. package/dist/dashboard/assets/entry-keNDZ_Wz.js +0 -1
  290. package/dist/dashboard/assets/github-badge-BuAJr8oU.js +0 -1
  291. package/dist/dashboard/assets/mutation-BIizFZav.js +0 -1
  292. package/dist/dashboard/assets/privacy-mode-CQjbZ3xk.js +0 -1
  293. package/dist/dashboard/assets/settings-BAS6QbmJ.js +0 -1
  294. package/dist/dashboard/assets/terminal-C9mZ4Ugm.js +0 -1
  295. package/dist/dashboard/assets/toast-DKAdP2mo.js +0 -2
  296. package/scripts/cli/cli.ts +0 -766
  297. package/scripts/cli/version.ts +0 -66
  298. package/scripts/operations/probe-egress.ts +0 -335
  299. package/scripts/operations/restart.ts +0 -120
  300. package/scripts/shared/env.ts +0 -269
  301. /package/{tray-assets → scripts/cli/tray/assets}/cartethyia.ico +0 -0
  302. /package/{tray-assets → scripts/cli/tray/assets}/cartethyia.png +0 -0
  303. /package/scripts/cli/{menu.ts → ui/prompt.ts} +0 -0
  304. /package/scripts/cli/{wordmark.ts → ui/wordmark.ts} +0 -0
@@ -1,66 +0,0 @@
1
- import { spawn } from "node:child_process";
2
- import { tmpdir } from "node:os";
3
- import { resolvePackagePath } from "../../src/config/package-paths";
4
-
5
- /** Reads the version from the installed package manifest. */
6
- export async function readInstalledVersion(): Promise<string> {
7
- const metadata: unknown = await Bun.file(resolvePackagePath("package.json")).json();
8
- if (
9
- metadata === null ||
10
- typeof metadata !== "object" ||
11
- !("version" in metadata) ||
12
- typeof metadata.version !== "string"
13
- ) {
14
- throw new Error("Cartethyia package version is unavailable");
15
- }
16
- return metadata.version;
17
- }
18
-
19
- /** Asks the npm registry for the newest published version, or null on failure. */
20
- export async function readLatestPublishedVersion(): Promise<string | null> {
21
- try {
22
- const response = await fetch("https://registry.npmjs.org/cartethyia/latest", {
23
- signal: AbortSignal.timeout(4_000),
24
- });
25
- if (!response.ok) return null;
26
- const metadata: unknown = await response.json();
27
- if (
28
- metadata !== null &&
29
- typeof metadata === "object" &&
30
- "version" in metadata &&
31
- typeof metadata.version === "string"
32
- ) {
33
- return metadata.version;
34
- }
35
- return null;
36
- } catch {
37
- return null;
38
- }
39
- }
40
-
41
- /**
42
- * Runs `npm install --global cartethyia@latest`. On Windows npm is a shell
43
- * script, so it has to go through cmd.exe rather than being spawned directly.
44
- */
45
- export function npmUpdate(): Promise<number> {
46
- return new Promise((resolveExit) => {
47
- const command = process.platform === "win32" ? "cmd.exe" : "npm";
48
- const args =
49
- process.platform === "win32"
50
- ? ["/d", "/s", "/c", "npm install --global cartethyia@latest"]
51
- : ["install", "--global", "cartethyia@latest"];
52
- let child;
53
- try {
54
- child = spawn(command, args, { cwd: tmpdir(), stdio: "inherit" });
55
- } catch {
56
- console.error("Could not start npm. Install Node.js with npm, then retry the update.");
57
- resolveExit(1);
58
- return;
59
- }
60
- child.once("error", () => {
61
- console.error("Could not start npm. Install Node.js with npm, then retry the update.");
62
- resolveExit(1);
63
- });
64
- child.once("exit", (code) => resolveExit(code ?? 1));
65
- });
66
- }
@@ -1,335 +0,0 @@
1
- /**
2
- * Asks a provider whether it will serve traffic from a given egress.
3
- *
4
- * The question this answers is not "is the proxy up". A proxy can carry
5
- * traffic, pass a neutral canary, and still be refused by one provider: OpenCode
6
- * answers `GET /inference/v1/models` with 200 from a flagged address and only
7
- * refuses on the dispatch route. So this sends the provider's own dispatch —
8
- * the adapter's headers, the agent tool set, `stream: true` — through the same
9
- * `createValidatedFetch` + pool agent the gateway uses. A hand-built stand-in
10
- * can pass while dispatch fails, which is the failure the probe exists to
11
- * avoid.
12
- *
13
- * Run it instead of hand-rolling a `fetch` in a scratch file:
14
- *
15
- * bun run scripts/operations/probe-egress.ts --provider opencode \
16
- * --direct \
17
- * --proxy http://nozomi.proxy.rlwy.net:48011 \
18
- * --proxy iriguchi.proxy.rlwy.net:23244
19
- *
20
- * # Read endpoints from a file, one per line (# comments allowed).
21
- * bun run scripts/operations/probe-egress.ts -p opencode -f proxies.txt
22
- *
23
- * # Pipe them in.
24
- * cat proxies.txt | bun run scripts/operations/probe-egress.ts -p opencode
25
- *
26
- * Every endpoint is probed concurrently (default 4 at a time, `--concurrency`).
27
- * Exit code is 0 when at least one egress is usable, 1 otherwise, so it can gate
28
- * a shell pipeline.
29
- *
30
- * Verdicts:
31
- *
32
- * allowed the upstream served the dispatch (2xx) — or answered with its
33
- * own validation error, which proves the IP gate let the address
34
- * through. This is the distinction that matters: a 400
35
- * `messages must not be empty` is an ALLOWED egress and a broken
36
- * probe body, not a broken proxy.
37
- * blocked the upstream refused the address itself (`403 FreeTierError`).
38
- * Replacing the proxy is the only fix; waiting does nothing.
39
- * unreachable the probe never got a usable answer: CONNECT failed, DNS
40
- * failed, or the upstream answered 5xx. Says nothing about
41
- * whether the address is refused.
42
- * throttled the upstream answered 429. The address is accepted; it is the
43
- * rate that is spent.
44
- */
45
- import { createHttpProxyAgent } from "../../src/network/pool/agent";
46
- import { createValidatedFetch } from "../../src/network/outbound-fetch";
47
- import { buildProviderProbeRequest, isProbeableProvider } from "../../src/providers/provider-probe";
48
- import { classifyProviderProbeAnswer, type ProbeVerdict } from "../../src/console/routing/pools/probe-verdict";
49
- import { BUNDLED_PROVIDER_METADATA } from "../../src/providers/provider-metadata";
50
-
51
- /** One egress under test, plus how to build its dial. */
52
- interface EgressTarget {
53
- /** Human label for the result row. */
54
- readonly label: string;
55
- /** `undefined` dials direct. */
56
- readonly proxy?: string;
57
- }
58
-
59
- interface ProbeOutcome {
60
- readonly label: string;
61
- readonly verdict: ProbeVerdict;
62
- readonly httpStatus?: number;
63
- readonly latencyMs?: number;
64
- readonly detail?: string;
65
- }
66
-
67
- const DEFAULT_CONCURRENCY = 4;
68
- const PROBE_TIMEOUT_MS = 30_000;
69
-
70
- interface Options {
71
- readonly providerId: string;
72
- readonly targets: readonly EgressTarget[];
73
- readonly concurrency: number;
74
- readonly timeoutMs: number;
75
- readonly json: boolean;
76
- }
77
-
78
- function usage(): never {
79
- console.error(
80
- [
81
- "Usage: bun run scripts/operations/probe-egress.ts --provider <id> [options]",
82
- "",
83
- "Options:",
84
- " -p, --provider <id> Provider to probe (must be IP-scoped; opencode is the only one)",
85
- " --direct Also probe this machine's own egress",
86
- " --proxy <endpoint> Add a proxy (repeatable). Bare host:port is read as http://",
87
- " -f, --file <path> Read endpoints from a file, one per line ('#' comments allowed)",
88
- " --stdin Read endpoints from stdin",
89
- " --concurrency <n> Parallel probes (default 4)",
90
- " --timeout <ms> Per-probe timeout (default 30000)",
91
- " --json Print one JSON object per line instead of a table",
92
- " -h, --help This message",
93
- "",
94
- "Endpoints may be http://, https://, socks5://, or bare host:port (http).",
95
- "Exit code: 0 if any egress is usable, 1 otherwise.",
96
- ].join("\n"),
97
- );
98
- process.exit(2);
99
- }
100
-
101
- /** Normalizes an operator-supplied endpoint. Bare `host:port` means HTTP. */
102
- function normalizeEndpoint(raw: string): string {
103
- const trimmed = raw.trim();
104
- if (trimmed.includes("://")) return trimmed;
105
- return `http://${trimmed}`;
106
- }
107
-
108
- function collectEndpointsFromText(text: string): string[] {
109
- return text
110
- .split(/\r?\n/)
111
- .map((line) => line.replace(/#.*$/, "").trim())
112
- .filter((line) => line.length > 0);
113
- }
114
-
115
- function parseArgs(argv: readonly string[]): Options {
116
- let providerId: string | undefined;
117
- const targets: EgressTarget[] = [];
118
- let concurrency = DEFAULT_CONCURRENCY;
119
- let timeoutMs = PROBE_TIMEOUT_MS;
120
- let json = false;
121
- const files: string[] = [];
122
- let readStdin = false;
123
-
124
- for (let index = 0; index < argv.length; index += 1) {
125
- const arg = argv[index];
126
- if (arg === undefined) continue;
127
- const next = (): string => {
128
- const value = argv[index + 1];
129
- if (value === undefined) usage();
130
- index += 1;
131
- return value;
132
- };
133
- switch (arg) {
134
- case "-p":
135
- case "--provider":
136
- providerId = next();
137
- break;
138
- case "--direct":
139
- targets.push({ label: "direct" });
140
- break;
141
- case "--proxy":
142
- targets.push({ label: "", proxy: normalizeEndpoint(next()) });
143
- break;
144
- case "-f":
145
- case "--file":
146
- files.push(next());
147
- break;
148
- case "--stdin":
149
- readStdin = true;
150
- break;
151
- case "--concurrency":
152
- concurrency = Math.max(1, Number(next()) || DEFAULT_CONCURRENCY);
153
- break;
154
- case "--timeout":
155
- timeoutMs = Math.max(1_000, Number(next()) || PROBE_TIMEOUT_MS);
156
- break;
157
- case "--json":
158
- json = true;
159
- break;
160
- case "-h":
161
- case "--help":
162
- usage();
163
- break;
164
- default:
165
- // A bare argument is an endpoint, so `... --provider opencode host:port`
166
- // works without a flag. Anything starting with `-` is a mistake.
167
- if (arg.startsWith("-")) {
168
- console.error(`Unknown option: ${arg}`);
169
- usage();
170
- }
171
- targets.push({ label: "", proxy: normalizeEndpoint(arg) });
172
- break;
173
- }
174
- }
175
-
176
- if (providerId === undefined) {
177
- console.error("--provider is required");
178
- usage();
179
- }
180
-
181
- const fromFiles: EgressTarget[] = [];
182
- for (const file of files) {
183
- const text = readFileText(file);
184
- for (const endpoint of collectEndpointsFromText(text)) {
185
- fromFiles.push({ label: "", proxy: normalizeEndpoint(endpoint) });
186
- }
187
- }
188
- if (readStdin) {
189
- const text = readFileText(0);
190
- for (const endpoint of collectEndpointsFromText(text)) {
191
- fromFiles.push({ label: "", proxy: normalizeEndpoint(endpoint) });
192
- }
193
- }
194
-
195
- const all = [...targets, ...fromFiles];
196
- if (all.length === 0) {
197
- console.error("No egress to probe: pass --direct, --proxy, --file, or --stdin");
198
- usage();
199
- }
200
-
201
- return {
202
- providerId,
203
- targets: all.map((target) => ({
204
- // The label is what the operator typed, minus the scheme they may have
205
- // omitted — printing `http://` on every row buries the distinguishing part.
206
- label: target.proxy === undefined ? target.label : target.proxy.replace(/^[a-z0-9+.-]+:\/\//i, ""),
207
- ...(target.proxy === undefined ? {} : { proxy: target.proxy }),
208
- })),
209
- concurrency,
210
- timeoutMs,
211
- json,
212
- };
213
- }
214
-
215
- /** Reads a file path, or fd 0 for stdin. Kept separate so `parseArgs` stays pure-ish. */
216
- function readFileText(path: string | 0): string {
217
- try {
218
- return require("node:fs").readFileSync(path, "utf8") as string;
219
- } catch (error) {
220
- console.error(`Cannot read ${path === 0 ? "stdin" : path}: ${error instanceof Error ? error.message : String(error)}`);
221
- process.exit(2);
222
- }
223
- }
224
-
225
- /**
226
- * Maps one response to a verdict through the same classifier the console uses,
227
- * so a CLI run and the dashboard's "Test OpenCode" button can never disagree
228
- * about what an answer means.
229
- */
230
- async function probeOne(
231
- spec: NonNullable<Awaited<ReturnType<typeof buildProviderProbeRequest>>>,
232
- target: EgressTarget,
233
- timeoutMs: number,
234
- ): Promise<ProbeOutcome> {
235
- const started = performance.now();
236
- try {
237
- const agent = target.proxy === undefined ? undefined : createHttpProxyAgent(target.proxy);
238
- const dial = createValidatedFetch(agent === undefined ? {} : { agent });
239
- const response = await dial(spec.url, {
240
- method: "POST",
241
- headers: spec.headers,
242
- body: JSON.stringify(spec.body),
243
- signal: AbortSignal.timeout(timeoutMs),
244
- });
245
- const body = await response.text().catch(() => "");
246
- const answer = classifyProviderProbeAnswer(response.status, body);
247
- return {
248
- label: target.label,
249
- verdict: answer.status,
250
- httpStatus: response.status,
251
- latencyMs: Math.round(performance.now() - started),
252
- ...(answer.reason === undefined ? {} : { detail: answer.reason }),
253
- };
254
- } catch (error) {
255
- const message = error instanceof Error ? error.message : String(error);
256
- const timedOut =
257
- (error instanceof Error && error.name === "AbortError") ||
258
- /timed out|timeout|ETIMEDOUT/i.test(message);
259
- return {
260
- label: target.label,
261
- verdict: "unreachable",
262
- latencyMs: Math.round(performance.now() - started),
263
- detail: timedOut ? "probe timed out" : message.split("\n")[0]!.slice(0, 120),
264
- };
265
- }
266
- }
267
-
268
- const VERDICT_GLYPH: Record<ProbeVerdict, string> = {
269
- allowed: "OK ",
270
- blocked: "BLOCK",
271
- throttled: "RATE ",
272
- unreachable: "FAIL ",
273
- };
274
-
275
- async function main(): Promise<void> {
276
- const options = parseArgs(process.argv.slice(2));
277
-
278
- if (!isProbeableProvider(options.providerId)) {
279
- console.error(
280
- `${options.providerId} is not IP-scoped, so a probe cannot tell an egress refusal from a credential problem. ` +
281
- `Probeable: ${BUNDLED_PROVIDER_METADATA.filter((entry) => isProbeableProvider(entry.id)).map((entry) => entry.id).join(", ") || "(none)"}`,
282
- );
283
- process.exit(2);
284
- }
285
-
286
- const spec = await buildProviderProbeRequest(options.providerId);
287
- if (!spec) {
288
- console.error(`No probe spec for ${options.providerId}`);
289
- process.exit(2);
290
- }
291
-
292
- if (!options.json) {
293
- console.error(`Probing ${options.providerId} via ${spec.url}`);
294
- console.error(`${options.targets.length} egress(es), ${options.concurrency} at a time\n`);
295
- }
296
-
297
- const results: ProbeOutcome[] = new Array(options.targets.length);
298
- let cursor = 0;
299
- const worker = async (): Promise<void> => {
300
- for (;;) {
301
- const index = cursor++;
302
- const target = options.targets[index];
303
- if (target === undefined) return;
304
- results[index] = await probeOne(spec, target, options.timeoutMs);
305
- }
306
- };
307
- await Promise.all(
308
- Array.from({ length: Math.min(options.concurrency, options.targets.length) }, () => worker()),
309
- );
310
-
311
- if (options.json) {
312
- for (const result of results) console.log(JSON.stringify(result));
313
- } else {
314
- const labelWidth = Math.max(...results.map((result) => result.label.length), 8);
315
- for (const result of results) {
316
- const status = result.httpStatus === undefined ? " -" : String(result.httpStatus).padStart(3);
317
- const latency = result.latencyMs === undefined ? "" : `${String(result.latencyMs).padStart(6)}ms`;
318
- console.log(
319
- `${result.label.padEnd(labelWidth)} ${VERDICT_GLYPH[result.verdict]} ${status} ${latency.padStart(9)} ${result.detail ?? ""}`,
320
- );
321
- }
322
- const tally = (verdict: ProbeVerdict): number => results.filter((r) => r.verdict === verdict).length;
323
- console.log(
324
- `\nallowed ${tally("allowed")} · blocked ${tally("blocked")} · ` +
325
- `throttled ${tally("throttled")} · unreachable ${tally("unreachable")}`,
326
- );
327
- }
328
-
329
- const usable = results.some(
330
- (result) => result.verdict === "allowed" || result.verdict === "throttled",
331
- );
332
- process.exit(usable ? 0 : 1);
333
- }
334
-
335
- await main();
@@ -1,120 +0,0 @@
1
- #!/usr/bin/env bun
2
- /**
3
- * restart.ts — rebuild and restart the compiled gateway gracefully.
4
- *
5
- * Why this exists: a hard kill (`taskkill /F`, `kill -9`) truncates every
6
- * in-flight response. On Linux the process handles SIGTERM/SIGINT and drains,
7
- * but Windows has no deliverable catchable signal — `process.kill(pid,
8
- * "SIGTERM")` of a console-less Bun process runs no JS handler (measured). So
9
- * this script stops the running instance through the drain endpoint when
10
- * `CARTETHYIA_DRAIN_TOKEN` is set (loopback + `x-drain-token`), and only falls
11
- * back to a hard kill when no token is configured.
12
- *
13
- * Env:
14
- * CARTETHYIA_DRAIN_TOKEN token for POST /admin/drain (required for graceful stop)
15
- * PORT gateway port (default 12800)
16
- * DRAIN_WAIT_MS how long to wait for the drain to finish (default 30000)
17
- */
18
- import { compiledBinaryPath } from "../build/binary";
19
-
20
- function intEnv(name: string, fallback: number): number {
21
- const raw = process.env[name];
22
- if (raw === undefined || raw.trim() === "") return fallback;
23
- const value = Number(raw);
24
- return Number.isFinite(value) && value > 0 ? Math.trunc(value) : fallback;
25
- }
26
-
27
- const PORT = intEnv("PORT", 12800);
28
- const DRAIN_WAIT_MS = intEnv("DRAIN_WAIT_MS", 30_000);
29
-
30
- /** PIDs currently listening on `port` (best-effort, platform-specific). */
31
- async function listeningPids(port: number): Promise<number[]> {
32
- try {
33
- if (process.platform === "win32") {
34
- const proc = Bun.spawnSync(["netstat", "-ano", "-p", "TCP"]);
35
- const out = new TextDecoder().decode(proc.stdout);
36
- const pids = new Set<number>();
37
- for (const line of out.split(/\r?\n/)) {
38
- if (!line.includes(`:${port} `) || !line.includes("LISTENING")) continue;
39
- const pid = Number(line.trim().split(/\s+/).pop());
40
- if (Number.isInteger(pid) && pid > 0) pids.add(pid);
41
- }
42
- return [...pids];
43
- }
44
- const proc = Bun.spawnSync(["lsof", "-ti", `tcp:${port}`, "-sTCP:LISTEN"]);
45
- return new TextDecoder()
46
- .decode(proc.stdout)
47
- .split(/\s+/)
48
- .map(Number)
49
- .filter((n) => Number.isInteger(n) && n > 0);
50
- } catch {
51
- return [];
52
- }
53
- }
54
-
55
- async function waitForPortFree(port: number, timeoutMs: number): Promise<boolean> {
56
- const deadline = Date.now() + timeoutMs;
57
- while (Date.now() < deadline) {
58
- if ((await listeningPids(port)).length === 0) return true;
59
- await new Promise((r) => setTimeout(r, 250));
60
- }
61
- return (await listeningPids(port)).length === 0;
62
- }
63
-
64
- async function stopGracefully(): Promise<boolean> {
65
- const token = process.env.CARTETHYIA_DRAIN_TOKEN?.trim();
66
- if (token === undefined || token.length === 0) {
67
- console.warn("[restart] CARTETHYIA_DRAIN_TOKEN unset — cannot drain gracefully");
68
- return false;
69
- }
70
- try {
71
- const response = await fetch(`http://127.0.0.1:${PORT}/admin/drain`, {
72
- method: "POST",
73
- headers: { "x-drain-token": token },
74
- });
75
- if (!response.ok) {
76
- console.warn(`[restart] drain request returned HTTP ${response.status}`);
77
- return false;
78
- }
79
- console.log("[restart] drain acknowledged; waiting for the process to exit");
80
- return await waitForPortFree(PORT, DRAIN_WAIT_MS);
81
- } catch (error) {
82
- console.warn(`[restart] drain request failed: ${(error as Error).message}`);
83
- return false;
84
- }
85
- }
86
-
87
- async function hardKill(): Promise<void> {
88
- const pids = await listeningPids(PORT);
89
- if (pids.length === 0) return;
90
- console.warn(`[restart] force-killing pid(s) ${pids.join(", ")} on :${PORT}`);
91
- for (const pid of pids) {
92
- try {
93
- process.kill(pid, "SIGKILL");
94
- } catch {
95
- // Already gone.
96
- }
97
- }
98
- await waitForPortFree(PORT, 5_000);
99
- }
100
-
101
- async function main(): Promise<number> {
102
- const graceful = await stopGracefully();
103
- if (!graceful) await hardKill();
104
-
105
- console.log("[restart] building");
106
- const build = Bun.spawnSync(["bun", "run", "build"], { stdout: "inherit", stderr: "inherit" });
107
- if (build.exitCode !== 0) {
108
- console.error("[restart] build failed");
109
- return build.exitCode ?? 1;
110
- }
111
-
112
- const binary = compiledBinaryPath();
113
- console.log(`[restart] starting ${binary}`);
114
- const child = Bun.spawn([binary], { stdin: "ignore", stdout: "inherit", stderr: "inherit" });
115
- return await child.exited;
116
- }
117
-
118
- if (import.meta.main) {
119
- process.exit(await main());
120
- }