cartethyia 2.4.6 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (302) hide show
  1. package/README.md +45 -13
  2. package/dist/dashboard/assets/BannedPage-9igfctfZ.js +1 -0
  3. package/dist/dashboard/assets/BannedPage-9igfctfZ.js.gz +0 -0
  4. package/dist/dashboard/assets/{CliToolDetailPage-Bcy150Jo.js → CliToolDetailPage-ZRr2K2sF.js} +1 -1
  5. package/dist/dashboard/assets/CliToolDetailPage-ZRr2K2sF.js.gz +0 -0
  6. package/dist/dashboard/assets/{CliToolsPage-DyNXefph.js → CliToolsPage-D3xqZbN-.js} +1 -1
  7. package/dist/dashboard/assets/CliToolsPage-D3xqZbN-.js.gz +0 -0
  8. package/dist/dashboard/assets/CombosPage-CVnQPBBz.js +1 -0
  9. package/dist/dashboard/assets/CombosPage-CVnQPBBz.js.gz +0 -0
  10. package/dist/dashboard/assets/{ConsoleLogPage-CATpAEOz.js → ConsoleLogPage-u6W1UXSc.js} +1 -1
  11. package/dist/dashboard/assets/ConsoleLogPage-u6W1UXSc.js.gz +0 -0
  12. package/dist/dashboard/assets/{CustomizationPage-D6jEU7nL.js → CustomizationPage-CTTpCb25.js} +1 -1
  13. package/dist/dashboard/assets/CustomizationPage-CTTpCb25.js.gz +0 -0
  14. package/dist/dashboard/assets/{HealthEventsModal-CZkpn0a7.js → HealthEventsModal-C5XpWlvy.js} +1 -1
  15. package/dist/dashboard/assets/HealthEventsModal-C5XpWlvy.js.gz +0 -0
  16. package/dist/dashboard/assets/{LoginPage-BJlMVN4U.js → LoginPage-DHoB3Agn.js} +1 -1
  17. package/dist/dashboard/assets/LoginPage-DHoB3Agn.js.gz +0 -0
  18. package/dist/dashboard/assets/{ModelPicker-Br3CXEau.js → ModelPicker-oQ-SDXp8.js} +1 -1
  19. package/dist/dashboard/assets/ModelPicker-oQ-SDXp8.js.gz +0 -0
  20. package/dist/dashboard/assets/OverviewPage-BrY4SgIt.js +1 -0
  21. package/dist/dashboard/assets/OverviewPage-BrY4SgIt.js.gz +0 -0
  22. package/dist/dashboard/assets/ProviderDetailPage-D9VSt7T_.js +3 -0
  23. package/dist/dashboard/assets/ProviderDetailPage-D9VSt7T_.js.gz +0 -0
  24. package/dist/dashboard/assets/ProviderIcon-CmfzxpVM.js +1 -0
  25. package/dist/dashboard/assets/ProviderIcon-CmfzxpVM.js.gz +0 -0
  26. package/dist/dashboard/assets/ProvidersPage-Df77V5I5.js +1 -0
  27. package/dist/dashboard/assets/ProvidersPage-Df77V5I5.js.gz +0 -0
  28. package/dist/dashboard/assets/ProxyPage-CDfxP7AC.js +7 -0
  29. package/dist/dashboard/assets/ProxyPage-CDfxP7AC.js.gz +0 -0
  30. package/dist/dashboard/assets/QuotaPage-CY4o2t4p.js +1 -0
  31. package/dist/dashboard/assets/QuotaPage-CY4o2t4p.js.gz +0 -0
  32. package/dist/dashboard/assets/{SettingsPage-BHW4Zt06.js → SettingsPage-CvjZxHE4.js} +1 -1
  33. package/dist/dashboard/assets/SettingsPage-CvjZxHE4.js.gz +0 -0
  34. package/dist/dashboard/assets/{SetupPage-VOYC_lIa.js → SetupPage-D3nza7LH.js} +1 -1
  35. package/dist/dashboard/assets/SetupPage-D3nza7LH.js.gz +0 -0
  36. package/dist/dashboard/assets/SortableList-Dtt12WT1.js +1 -0
  37. package/dist/dashboard/assets/SortableList-Dtt12WT1.js.gz +0 -0
  38. package/dist/dashboard/assets/{StudioPage-BNIDLiU6.js → StudioPage-CbK3hXvU.js} +4 -4
  39. package/dist/dashboard/assets/StudioPage-CbK3hXvU.js.gz +0 -0
  40. package/dist/dashboard/assets/UsagePage-BQlWbWg2.js +56 -0
  41. package/dist/dashboard/assets/UsagePage-BQlWbWg2.js.gz +0 -0
  42. package/dist/dashboard/assets/{api-keys-BETfaMYZ.js → api-keys-BmDbsior.js} +1 -1
  43. package/dist/dashboard/assets/api-keys-BmDbsior.js.gz +0 -0
  44. package/dist/dashboard/assets/app-BbpSarVV.css +2 -0
  45. package/dist/dashboard/assets/app-BbpSarVV.css.gz +0 -0
  46. package/dist/dashboard/assets/assert-BHfaei-X.js +1 -0
  47. package/dist/dashboard/assets/assert-BHfaei-X.js.gz +0 -0
  48. package/dist/dashboard/assets/{badge-BTyGk_DL.js → badge-DpXT4Ixt.js} +1 -1
  49. package/dist/dashboard/assets/badge-DpXT4Ixt.js.gz +0 -0
  50. package/dist/dashboard/assets/{banner-bujTWYM4.js → banner-CSAAWLJv.js} +1 -1
  51. package/dist/dashboard/assets/banner-CSAAWLJv.js.gz +0 -0
  52. package/dist/dashboard/assets/{card-B0Bnx5CA.js → card-DEhRXXw4.js} +1 -1
  53. package/dist/dashboard/assets/card-DEhRXXw4.js.gz +0 -0
  54. package/dist/dashboard/assets/{cli-tools-DE2ug812.js → cli-tools-B0wBq-RL.js} +1 -1
  55. package/dist/dashboard/assets/cli-tools-B0wBq-RL.js.gz +0 -0
  56. package/dist/dashboard/assets/{clipboard-button-R_rArH8S.js → clipboard-button-DOo6EU8O.js} +1 -1
  57. package/dist/dashboard/assets/clipboard-button-DOo6EU8O.js.gz +0 -0
  58. package/dist/dashboard/assets/{dialog-BWIP_EvW.js → dialog-BvQeBMfP.js} +1 -1
  59. package/dist/dashboard/assets/dialog-BvQeBMfP.js.gz +0 -0
  60. package/dist/dashboard/assets/{drawer-BKcgVugF.js → drawer-CMwPXwQB.js} +1 -1
  61. package/dist/dashboard/assets/drawer-CMwPXwQB.js.gz +0 -0
  62. package/dist/dashboard/assets/{entry-CcWkGR4a.js → entry-D4O2229X.js} +1 -1
  63. package/dist/dashboard/assets/{entry-CcWkGR4a.js.gz → entry-D4O2229X.js.gz} +0 -0
  64. package/dist/dashboard/assets/{entry-kTiTFrvh.js → entry-DKvr5Q9K.js} +1 -1
  65. package/dist/dashboard/assets/entry-DKvr5Q9K.js.gz +0 -0
  66. package/dist/dashboard/assets/entry-FQCejoDY.js +4 -0
  67. package/dist/dashboard/assets/entry-FQCejoDY.js.gz +0 -0
  68. package/dist/dashboard/assets/{github-badge-Booc5mNe.js → github-badge-zliLvBwr.js} +1 -1
  69. package/dist/dashboard/assets/github-badge-zliLvBwr.js.gz +0 -0
  70. package/dist/dashboard/assets/{index-D70pChfn.js → index-CXm3FIyt.js} +2 -2
  71. package/dist/dashboard/assets/index-CXm3FIyt.js.gz +0 -0
  72. package/dist/dashboard/assets/{inline-D1TCqM2D.js → inline-D1IlZZ8H.js} +1 -1
  73. package/dist/dashboard/assets/inline-D1IlZZ8H.js.gz +0 -0
  74. package/dist/dashboard/assets/{input-B9oyU93y.js → input-BpVZdrbc.js} +1 -1
  75. package/dist/dashboard/assets/input-BpVZdrbc.js.gz +0 -0
  76. package/dist/dashboard/assets/{layout-BArzXirQ.js → layout-BioLW7gN.js} +1 -1
  77. package/dist/dashboard/assets/layout-BioLW7gN.js.gz +0 -0
  78. package/dist/dashboard/assets/{list-row-BVZzaoHF.js → list-row-CwVcGAIc.js} +1 -1
  79. package/dist/dashboard/assets/list-row-CwVcGAIc.js.gz +0 -0
  80. package/dist/dashboard/assets/{live-EmuIayqp.js → live-yfEJFF9T.js} +1 -1
  81. package/dist/dashboard/assets/live-yfEJFF9T.js.gz +0 -0
  82. package/dist/dashboard/assets/{model-bans-CSPQ9xB0.js → model-bans-CT-TxSNX.js} +1 -1
  83. package/dist/dashboard/assets/model-bans-CT-TxSNX.js.gz +0 -0
  84. package/dist/dashboard/assets/providers/cursor.webp +0 -0
  85. package/dist/dashboard/assets/providers/trae.webp +0 -0
  86. package/dist/dashboard/assets/{routing-BExgxxBU.js → routing-Cs6jl49L.js} +1 -1
  87. package/dist/dashboard/assets/routing-Cs6jl49L.js.gz +0 -0
  88. package/dist/dashboard/assets/select-C0Rer3gF.js +41 -0
  89. package/dist/dashboard/assets/select-C0Rer3gF.js.gz +0 -0
  90. package/dist/dashboard/assets/settings-CfcTcOyU.js +1 -0
  91. package/dist/dashboard/assets/settings-CfcTcOyU.js.gz +0 -0
  92. package/dist/dashboard/assets/{stack-Ca5HxI5i.js → stack-C9_uUjaA.js} +1 -1
  93. package/dist/dashboard/assets/stack-C9_uUjaA.js.gz +0 -0
  94. package/dist/dashboard/assets/{state-CzUPfLXo.js → state-DA0B95UQ.js} +1 -1
  95. package/dist/dashboard/assets/state-DA0B95UQ.js.gz +0 -0
  96. package/dist/dashboard/assets/{switch-DOUIky_i.js → switch-Cittxy-x.js} +1 -1
  97. package/dist/dashboard/assets/switch-Cittxy-x.js.gz +0 -0
  98. package/dist/dashboard/assets/{toast-C76WrMhc.js → toast-CNt_jzO4.js} +1 -1
  99. package/dist/dashboard/assets/toast-CNt_jzO4.js.gz +0 -0
  100. package/dist/dashboard/assets/{useMutation-D87FZwH0.js → useMutation-BQKMcJ1H.js} +1 -1
  101. package/dist/dashboard/assets/useMutation-BQKMcJ1H.js.gz +0 -0
  102. package/dist/dashboard/index.html +1 -1
  103. package/dist/dashboard/index.html.gz +0 -0
  104. package/dist/dashboard/precompressed-assets.json +51 -52
  105. package/migrations/full-postgres/0015_add_payload_stages.sql +18 -0
  106. package/migrations/full-postgres/0016_add_share_link_slug.sql +20 -0
  107. package/migrations/full-postgres/0017_add_models_pro_only.sql +18 -0
  108. package/migrations/full-postgres/0018_add_accounts_quota_plan.sql +18 -0
  109. package/migrations/full-postgres/0019_add_models_free_tier.sql +15 -0
  110. package/migrations/lite-sqlite3/0015_add_payload_stages.sql +18 -0
  111. package/migrations/lite-sqlite3/0016_add_share_link_slug.sql +20 -0
  112. package/migrations/lite-sqlite3/0017_add_models_pro_only.sql +18 -0
  113. package/migrations/lite-sqlite3/0018_add_accounts_quota_plan.sql +18 -0
  114. package/migrations/lite-sqlite3/0019_add_models_free_tier.sql +15 -0
  115. package/package.json +3 -2
  116. package/scripts/cli/command/console-menu.ts +30 -11
  117. package/scripts/cli/command/start.ts +77 -13
  118. package/scripts/cli/command/update.ts +1 -1
  119. package/scripts/cli/gateway/instance-lock.ts +105 -0
  120. package/scripts/cli/gateway/spawn.ts +173 -101
  121. package/scripts/cli/ui/background.ts +110 -49
  122. package/src/boot/app.ts +20 -6
  123. package/src/boot/dependencies.ts +19 -0
  124. package/src/boot/elysia-typebox-bridge.ts +37 -0
  125. package/src/boot/lifecycle.ts +2 -0
  126. package/src/config/cooldowns.ts +138 -138
  127. package/src/config/providers.ts +5 -5
  128. package/src/config/runtime.ts +19 -3
  129. package/src/config/spec.ts +9 -0
  130. package/src/console/api-keys/contracts.ts +414 -391
  131. package/src/console/api-keys/routes.ts +880 -870
  132. package/src/console/auth/account-reset-store.ts +14 -0
  133. package/src/console/auth/account-reset.ts +3 -2
  134. package/src/console/auth/setup-service.ts +6 -3
  135. package/src/console/domain-registration.ts +9 -2
  136. package/src/console/observability/contracts.ts +475 -455
  137. package/src/console/observability/store.ts +1015 -952
  138. package/src/console/providers/catalog/contracts.ts +31 -0
  139. package/src/console/providers/catalog/provider-operations.ts +8 -0
  140. package/src/console/providers/catalog/store.ts +1532 -1525
  141. package/src/console/providers/oauth/callback-listener.ts +18 -3
  142. package/src/console/providers/oauth/routes.ts +38 -15
  143. package/src/console/quota/refresh.ts +19 -0
  144. package/src/console/updates/routes.ts +162 -4
  145. package/src/main.ts +3 -0
  146. package/src/network/http2-bidi.ts +85 -0
  147. package/src/network/outbound-fetch.ts +1 -26
  148. package/src/network/pool/agent.ts +478 -460
  149. package/src/network/pool/resolver.ts +1104 -544
  150. package/src/network/pool-health-machine.ts +12 -5
  151. package/src/observability/payload-capture.ts +344 -324
  152. package/src/persistence/db-pg.ts +9 -3
  153. package/src/persistence/db-sqlite.ts +497 -495
  154. package/src/persistence/health-event-flush.ts +137 -0
  155. package/src/persistence/migrate.ts +181 -129
  156. package/src/persistence/schema.ts +1360 -1295
  157. package/src/persistence/settings-revision.ts +25 -0
  158. package/src/persistence/shared-cache.ts +217 -0
  159. package/src/persistence/stores/share-store.ts +556 -528
  160. package/src/persistence/usage-flush.ts +61 -1
  161. package/src/protocol/canonical-model.ts +23 -1
  162. package/src/protocol/response/chat.ts +143 -10
  163. package/src/protocol/response/omp-tool-call-markup.ts +221 -0
  164. package/src/providers/default-registry.ts +173 -1
  165. package/src/providers/discovery/openai-model-discovery.ts +39 -3
  166. package/src/providers/discovery/openrouter-free-roster.ts +98 -0
  167. package/src/providers/discovery/probing-service.ts +1022 -1001
  168. package/src/providers/integrations/buddy/buddy-catalog-shared.ts +39 -0
  169. package/src/providers/integrations/buddy/buddy-chat-shared.ts +913 -914
  170. package/src/providers/integrations/buddy/buddy-conversation-headers.ts +18 -5
  171. package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +4 -0
  172. package/src/providers/integrations/buddy/codebuddy/provider.ts +180 -175
  173. package/src/providers/integrations/buddy/codebuddy/shared.ts +15 -6
  174. package/src/providers/integrations/buddy/workbuddy/provider.ts +206 -204
  175. package/src/providers/integrations/buddy/workbuddy/shared.ts +3 -3
  176. package/src/providers/integrations/claude/claude.ts +606 -582
  177. package/src/providers/integrations/cline/cline-quota.ts +18 -16
  178. package/src/providers/integrations/cline/cline.ts +539 -468
  179. package/src/providers/integrations/commandcode/commandcode.ts +675 -541
  180. package/src/providers/integrations/commandcode/discovery.ts +116 -0
  181. package/src/providers/integrations/commandcode/quota.ts +160 -0
  182. package/src/providers/integrations/cursor/cursor-auth.ts +418 -0
  183. package/src/providers/integrations/cursor/cursor-catalog.ts +368 -0
  184. package/src/providers/integrations/cursor/cursor-http2.ts +300 -0
  185. package/src/providers/integrations/cursor/cursor-identity.ts +92 -0
  186. package/src/providers/integrations/cursor/cursor-request.ts +471 -0
  187. package/src/providers/integrations/cursor/cursor-session-manager.ts +281 -0
  188. package/src/providers/integrations/cursor/cursor-shared.ts +108 -0
  189. package/src/providers/integrations/cursor/cursor.ts +960 -0
  190. package/src/providers/integrations/cursor/protocol/framing.ts +129 -0
  191. package/src/providers/integrations/cursor/protocol/messages.ts +2355 -0
  192. package/src/providers/integrations/cursor/protocol/struct.ts +305 -0
  193. package/src/providers/integrations/github/github.ts +4 -4
  194. package/src/providers/integrations/hermes.ts +79 -8
  195. package/src/providers/integrations/kilo/kilo-discovery.ts +10 -1
  196. package/src/providers/integrations/kilo/kilo.ts +153 -146
  197. package/src/providers/integrations/opencode/provider.ts +532 -538
  198. package/src/providers/integrations/openrouter/provider.ts +139 -281
  199. package/src/providers/integrations/qoder/qoder-catalog.ts +450 -0
  200. package/src/providers/integrations/qoder/qoder-oauth.ts +310 -257
  201. package/src/providers/integrations/qoder/qoder-realm.ts +106 -0
  202. package/src/providers/integrations/qoder/qoder-virtual.ts +77 -0
  203. package/src/providers/integrations/qoder/qoder.ts +865 -730
  204. package/src/providers/integrations/trae/trae-catalog.ts +190 -0
  205. package/src/providers/integrations/trae/trae-headers.ts +149 -0
  206. package/src/providers/integrations/trae/trae-oauth.ts +773 -0
  207. package/src/providers/integrations/trae/trae-protocol.ts +400 -0
  208. package/src/providers/integrations/trae/trae-realm.ts +220 -0
  209. package/src/providers/integrations/trae/trae.ts +458 -0
  210. package/src/providers/operations/account-health-service.ts +107 -10
  211. package/src/providers/operations/client-versions.ts +133 -6
  212. package/src/providers/operations/provider-catalog-seeder.ts +95 -86
  213. package/src/providers/operations/provider-credential-service.ts +46 -7
  214. package/src/providers/provider-contracts.ts +76 -0
  215. package/src/providers/provider-metadata.ts +78 -6
  216. package/src/providers/provider-model-definition.ts +373 -349
  217. package/src/security/api-key-auth.ts +126 -8
  218. package/src/transport/contracts.ts +3 -0
  219. package/src/transport/dispatch/attempt-finalize.ts +32 -1
  220. package/src/transport/dispatch/attempt-loop.ts +530 -515
  221. package/src/transport/dispatch/generation.ts +88 -21
  222. package/src/transport/dispatch/leases.ts +99 -2
  223. package/src/transport/dispatch/proxy-request.ts +60 -3
  224. package/src/transport/dispatch/streaming/finalize.ts +16 -1
  225. package/src/transport/dispatch/streaming/stream.ts +22 -2
  226. package/src/transport/dispatch/upstream.ts +19 -1
  227. package/src/transport/guards/auth-guard.ts +26 -1
  228. package/src/transport/guards/body-policy.ts +5 -4
  229. package/src/transport/request/preparer.ts +103 -0
  230. package/src/transport/request/state.ts +14 -0
  231. package/src/transport/routing/plan-gate.ts +45 -0
  232. package/src/transport/routing/route-catalog.ts +799 -777
  233. package/src/transport/routing/route-model.ts +52 -1
  234. package/src/transport/routing/router.ts +51 -0
  235. package/dist/dashboard/assets/BannedPage-QhvbJB9o.js +0 -1
  236. package/dist/dashboard/assets/BannedPage-QhvbJB9o.js.gz +0 -0
  237. package/dist/dashboard/assets/CliToolDetailPage-Bcy150Jo.js.gz +0 -0
  238. package/dist/dashboard/assets/CliToolsPage-DyNXefph.js.gz +0 -0
  239. package/dist/dashboard/assets/CombosPage-Cak0ljnO.js +0 -1
  240. package/dist/dashboard/assets/CombosPage-Cak0ljnO.js.gz +0 -0
  241. package/dist/dashboard/assets/ConsoleLogPage-CATpAEOz.js.gz +0 -0
  242. package/dist/dashboard/assets/CustomizationPage-D6jEU7nL.js.gz +0 -0
  243. package/dist/dashboard/assets/HealthEventsModal-CZkpn0a7.js.gz +0 -0
  244. package/dist/dashboard/assets/LoginPage-BJlMVN4U.js.gz +0 -0
  245. package/dist/dashboard/assets/ModelPicker-Br3CXEau.js.gz +0 -0
  246. package/dist/dashboard/assets/OverviewPage-CQxXbo2g.js +0 -1
  247. package/dist/dashboard/assets/OverviewPage-CQxXbo2g.js.gz +0 -0
  248. package/dist/dashboard/assets/ProviderDetailPage--0RBNh99.js +0 -3
  249. package/dist/dashboard/assets/ProviderDetailPage--0RBNh99.js.gz +0 -0
  250. package/dist/dashboard/assets/ProviderIcon-paOCq8I0.js +0 -1
  251. package/dist/dashboard/assets/ProviderIcon-paOCq8I0.js.gz +0 -0
  252. package/dist/dashboard/assets/ProvidersPage-1M-C3mbu.js +0 -1
  253. package/dist/dashboard/assets/ProvidersPage-1M-C3mbu.js.gz +0 -0
  254. package/dist/dashboard/assets/ProxyPage-CXiumA53.js +0 -7
  255. package/dist/dashboard/assets/ProxyPage-CXiumA53.js.gz +0 -0
  256. package/dist/dashboard/assets/QuotaPage-BGDIfIYP.js +0 -1
  257. package/dist/dashboard/assets/QuotaPage-BGDIfIYP.js.gz +0 -0
  258. package/dist/dashboard/assets/SettingsPage-BHW4Zt06.js.gz +0 -0
  259. package/dist/dashboard/assets/SetupPage-VOYC_lIa.js.gz +0 -0
  260. package/dist/dashboard/assets/SortableList-DpOTnGuH.js +0 -1
  261. package/dist/dashboard/assets/SortableList-DpOTnGuH.js.gz +0 -0
  262. package/dist/dashboard/assets/StudioPage-BNIDLiU6.js.gz +0 -0
  263. package/dist/dashboard/assets/UsagePage-BAFaSDQV.js +0 -56
  264. package/dist/dashboard/assets/UsagePage-BAFaSDQV.js.gz +0 -0
  265. package/dist/dashboard/assets/api-keys-BETfaMYZ.js.gz +0 -0
  266. package/dist/dashboard/assets/app-BLCvGdzb.css +0 -2
  267. package/dist/dashboard/assets/app-BLCvGdzb.css.gz +0 -0
  268. package/dist/dashboard/assets/assert-7J6_LVD3.js +0 -1
  269. package/dist/dashboard/assets/assert-7J6_LVD3.js.gz +0 -0
  270. package/dist/dashboard/assets/badge-BTyGk_DL.js.gz +0 -0
  271. package/dist/dashboard/assets/banner-bujTWYM4.js.gz +0 -0
  272. package/dist/dashboard/assets/card-B0Bnx5CA.js.gz +0 -0
  273. package/dist/dashboard/assets/cli-tools-DE2ug812.js.gz +0 -0
  274. package/dist/dashboard/assets/clipboard-button-R_rArH8S.js.gz +0 -0
  275. package/dist/dashboard/assets/dialog-BWIP_EvW.js.gz +0 -0
  276. package/dist/dashboard/assets/drawer-BKcgVugF.js.gz +0 -0
  277. package/dist/dashboard/assets/entry-7dpgvpJ3.js +0 -4
  278. package/dist/dashboard/assets/entry-7dpgvpJ3.js.gz +0 -0
  279. package/dist/dashboard/assets/entry-kTiTFrvh.js.gz +0 -0
  280. package/dist/dashboard/assets/github-badge-Booc5mNe.js.gz +0 -0
  281. package/dist/dashboard/assets/index-D70pChfn.js.gz +0 -0
  282. package/dist/dashboard/assets/inline-D1TCqM2D.js.gz +0 -0
  283. package/dist/dashboard/assets/input-B9oyU93y.js.gz +0 -0
  284. package/dist/dashboard/assets/layout-BArzXirQ.js.gz +0 -0
  285. package/dist/dashboard/assets/list-row-BVZzaoHF.js.gz +0 -0
  286. package/dist/dashboard/assets/live-EmuIayqp.js.gz +0 -0
  287. package/dist/dashboard/assets/model-bans-CSPQ9xB0.js.gz +0 -0
  288. package/dist/dashboard/assets/routing-BExgxxBU.js.gz +0 -0
  289. package/dist/dashboard/assets/select-C9mMoEpJ.js +0 -41
  290. package/dist/dashboard/assets/select-C9mMoEpJ.js.gz +0 -0
  291. package/dist/dashboard/assets/settings-C4_Gn_wq.js +0 -1
  292. package/dist/dashboard/assets/settings-C4_Gn_wq.js.gz +0 -0
  293. package/dist/dashboard/assets/sliders-horizontal-ClG7dBeJ.js +0 -1
  294. package/dist/dashboard/assets/sliders-horizontal-ClG7dBeJ.js.gz +0 -0
  295. package/dist/dashboard/assets/stack-Ca5HxI5i.js.gz +0 -0
  296. package/dist/dashboard/assets/state-CzUPfLXo.js.gz +0 -0
  297. package/dist/dashboard/assets/switch-DOUIky_i.js.gz +0 -0
  298. package/dist/dashboard/assets/toast-C76WrMhc.js.gz +0 -0
  299. package/dist/dashboard/assets/useMutation-D87FZwH0.js.gz +0 -0
  300. package/src/network/tls/bun-client-hello.ts +0 -112
  301. /package/dist/dashboard/assets/{app-Cjq7nrwu.js → app-C-Y4oZT0.js} +0 -0
  302. /package/dist/dashboard/assets/{app-Cjq7nrwu.js.gz → app-C-Y4oZT0.js.gz} +0 -0
@@ -12,6 +12,8 @@ import { createAnthropicCompatibleAdapter } from "./integrations/anthropic";
12
12
  import { defineModel } from "./provider-model-definition";
13
13
  import type { ProviderModelDiscovery } from "./discovery/discovery-types";
14
14
  import type { ProviderDispatchContext } from "./provider-contracts";
15
+ import type { QoderRealm } from "./integrations/qoder/qoder-realm";
16
+ import type { TraeRealm } from "./integrations/trae/trae-realm";
15
17
  import type { WireFamily } from "../protocol/canonical-model";
16
18
  import type { CanonicalRequest } from "../protocol/canonical-model";
17
19
 
@@ -25,6 +27,106 @@ function configuredProvider(
25
27
  };
26
28
  }
27
29
 
30
+ /**
31
+ * Qoder's live model list for one realm.
32
+ *
33
+ * The request has to be signed with the account's COSY identity and has to
34
+ * carry the body that was signed — a bare GET is refused — so discovery cannot
35
+ * use the generic bearer helper. It resolves the same identity dispatch uses
36
+ * (PAT exchange or the persisted OAuth state) and then lists against the
37
+ * realm's own gateway hosts.
38
+ */
39
+ /**
40
+ * Trae model discovery for one realm.
41
+ *
42
+ * The listing is per account region: it answers on CN and on the intl region
43
+ * host that serves the account. This returns the static roster when the live
44
+ * call yields nothing, rather than raising, so one unsupported account cannot
45
+ * fail the whole catalog refresh.
46
+ */
47
+ function traeDiscovery(
48
+ realm: TraeRealm,
49
+ providerId: string,
50
+ ): NonNullable<ProviderModuleCapabilities["loadModelDiscovery"]> {
51
+ return async () => async (request: Parameters<ProviderModelDiscovery>[0]) => {
52
+ const { discoverTraeModels } = await import("./integrations/trae/trae");
53
+ const { TRAE_INTL_MODELS, TRAE_CN_MODELS } = await import("./integrations/trae/trae-catalog");
54
+ const secret = request.credential.trim();
55
+ const fetcher = request.fetcher as unknown as typeof fetch | undefined;
56
+ if (secret.length === 0 || fetcher === undefined) {
57
+ return realm === "cn" ? TRAE_CN_MODELS : TRAE_INTL_MODELS;
58
+ }
59
+ let token = secret;
60
+ if (secret.startsWith("{")) {
61
+ try {
62
+ const parsed = JSON.parse(secret) as Record<string, unknown>;
63
+ const found = ["accessToken", "access_token", "token"].find(
64
+ (key) => typeof parsed[key] === "string" && (parsed[key] as string).length > 0,
65
+ );
66
+ if (found !== undefined) token = parsed[found] as string;
67
+ } catch {
68
+ // Use the raw secret as the token.
69
+ }
70
+ }
71
+ const region = request.authState?.["region"];
72
+ const rows = await discoverTraeModels({
73
+ realm,
74
+ token,
75
+ uid: request.authState?.["accountId"] as string | undefined ?? "",
76
+ fetcher,
77
+ providerId,
78
+ ...(typeof region === "string" ? { region } : {}),
79
+ });
80
+ if (rows.length === 0) return realm === "cn" ? TRAE_CN_MODELS : TRAE_INTL_MODELS;
81
+ const fallback = realm === "cn" ? TRAE_CN_MODELS : TRAE_INTL_MODELS;
82
+ const byId = new Map(fallback.map((model) => [model.modelId, model]));
83
+ return rows.map((row) => {
84
+ const existing = byId.get(row.id);
85
+ if (existing === undefined) {
86
+ // Discovered upstream but absent from the static roster: clone the
87
+ // realm's first row so a new model is routable with the shape this
88
+ // provider serves, carrying the window upstream reported.
89
+ const template = fallback[0];
90
+ if (template === undefined) return undefined;
91
+ return { ...template, modelId: row.id, contextLimit: row.ctx ?? null };
92
+ }
93
+ return row.ctx === undefined ? existing : { ...existing, contextLimit: row.ctx };
94
+ }).filter((model): model is NonNullable<typeof model> => model !== undefined);
95
+ };
96
+ }
97
+
98
+ function qoderDiscovery(
99
+ realm: QoderRealm,
100
+ providerId: string,
101
+ ): NonNullable<ProviderModuleCapabilities["loadModelDiscovery"]> {
102
+ return async () => async (request: Parameters<ProviderModelDiscovery>[0]) => {
103
+ const { discoverQoderModels } = await import("./integrations/qoder/qoder-catalog");
104
+ const { resolveQoderAuth, qoderSignerFor, qoderEncodeBody } = await import("./integrations/qoder/qoder");
105
+ const secret = request.credential.trim();
106
+ if (secret.length === 0) throw new Error("Qoder credential is required");
107
+ const fetcher = request.fetcher as unknown as typeof fetch | undefined;
108
+ // The discovery context carries only the secret plus the non-secret
109
+ // `authState` an OAuth login persisted; the account id lives there too, so
110
+ // an OAuth credential resolves to the same identity dispatch would use.
111
+ const auth = await resolveQoderAuth({
112
+ secret,
113
+ authState: request.authState,
114
+ signal: AbortSignal.timeout(15_000),
115
+ fetcher: (url: string, init: RequestInit) => (fetcher ?? globalThis.fetch)(url, init),
116
+ });
117
+ const signer = qoderSignerFor(auth);
118
+ return discoverQoderModels({
119
+ realm,
120
+ providerId,
121
+ credential: secret,
122
+ headers: (url: string, body: string) => Promise.resolve(signer(url, body)),
123
+ ...(fetcher === undefined ? {} : { fetcher }),
124
+ encode: qoderEncodeBody,
125
+ });
126
+ };
127
+ }
128
+
129
+
28
130
  /**
29
131
  * Builds the `loadAdapter` + `loadModelDiscovery` pair every plain bearer
30
132
  * provider needs.
@@ -201,6 +303,29 @@ export const PROVIDER_CAPABILITIES = {
201
303
  loadAuthentication: oauthCapability(() => import("./integrations/kimi/kimi-oauth"), "kimiCodeOAuthClient", { withRefresher: true }),
202
304
  loadQuotaCollector: quotaCapability(() => import("./integrations/kimi/kimi-quota"), "fetchKimiQuota"),
203
305
  },
306
+ cursor: {
307
+ // Cursor's Run is a Connect-RPC bidi stream on a *dynamically discovered*
308
+ // agent origin, not the API host the auth and catalog calls use. The path
309
+ // is pinned here so a probe verifies the endpoint dispatch actually calls;
310
+ // the origin itself is resolved per dispatch from GetServerConfig.
311
+ endpointPathsByWireFamily: { chat: "/agent.v1.AgentService/Run" },
312
+ loadAdapter: async () => (await import("./integrations/cursor/cursor")).cursorAdapter,
313
+ loadModels: async () => (await import("./integrations/cursor/cursor-catalog")).CURSOR_MODELS,
314
+ loadAuthentication: oauthCapability(() => import("./integrations/cursor/cursor-auth"), "cursorOAuthClient", {
315
+ withRefresher: true,
316
+ }),
317
+ // No quota collector: no Cursor quota endpoint is established by the donor
318
+ // or the API evidence, and inventing one would publish a balance this
319
+ // gateway cannot measure.
320
+ //
321
+ // The roster is per-account and per-plan, and Cursor declares each model's
322
+ // capabilities, so discovery is the catalog rather than a static list.
323
+ loadModelDiscovery: async () => async ({ credential, fetcher }) =>
324
+ (await import("./integrations/cursor/cursor-catalog")).discoverCursorModels({
325
+ credential,
326
+ ...(fetcher === undefined ? {} : { fetcher }),
327
+ }),
328
+ },
204
329
  cerebras: {
205
330
  endpointPathsByWireFamily: { chat: "/chat/completions" },
206
331
  loadAdapter: async () => createApiKeyAdapter((await import("./integrations/cerebras")).CEREBRAS_SPEC),
@@ -324,7 +449,10 @@ export const PROVIDER_CAPABILITIES = {
324
449
  },
325
450
  kilo: {
326
451
  loadAdapter: async () => (await import("./integrations/kilo/kilo")).kiloAdapter,
327
- loadModels: async () => (await import("./integrations/kilo/kilo")).KILO_MODELS,
452
+ loadModels: async () => {
453
+ const spec = await import("./integrations/kilo/kilo");
454
+ return [...spec.KILO_MODELS, ...spec.KILO_FREE_MODELS];
455
+ },
328
456
  // No `withRefresher`: Kilo Code has no refresh grant, so this client
329
457
  // declares no refresher and the stored token is used exactly as issued.
330
458
  // Registering one would make the 401 retry path call a method that always
@@ -339,6 +467,14 @@ export const PROVIDER_CAPABILITIES = {
339
467
  commandcode: {
340
468
  loadAdapter: async () => (await import("./integrations/commandcode/commandcode")).createCommandCodeAdapter(),
341
469
  loadModels: async () => (await import("./integrations/commandcode/commandcode")).COMMANDCODE_MODELS,
470
+ // The Provider API publishes the real roster with each model's wire, so the
471
+ // static seed above is the offline floor rather than the catalog.
472
+ loadModelDiscovery: async () => async (input) =>
473
+ (await import("./integrations/commandcode/discovery")).discoverCommandCodeModels(input),
474
+ loadQuotaCollector: quotaCapability(
475
+ () => import("./integrations/commandcode/quota"),
476
+ "fetchCommandCodeQuota",
477
+ ),
342
478
  },
343
479
  qoder: {
344
480
  loadAdapter: async () => (await import("./integrations/qoder/qoder")).createQoderAdapter(),
@@ -347,6 +483,42 @@ export const PROVIDER_CAPABILITIES = {
347
483
  // device flow, so the issued token is used exactly as issued until the
348
484
  // operator re-runs login — same shape as Kilo Code.
349
485
  loadAuthentication: oauthCapability(() => import("./integrations/qoder/qoder-oauth"), "qoderOAuthClient"),
486
+ // Discovery signed by the account's own COSY identity: the model list is
487
+ // per-account and per-realm, and a GET without the signed body is 403.
488
+ loadModelDiscovery: qoderDiscovery("intl", "qoder"),
489
+ },
490
+ // Separate provider, not a region flag: a CN account has its own gateway
491
+ // host, OAuth client id, and model roster, and is refused by the global host.
492
+ qodercn: {
493
+ loadAdapter: async () => (await import("./integrations/qoder/qoder")).createQoderCnAdapter(),
494
+ loadModels: async () => (await import("./integrations/qoder/qoder-catalog")).QODER_CN_MODELS,
495
+ // The CN client, not the intl one: a device login opened on
496
+ // `qoder.com/device/selectAccounts` polled `openapi.qoder.sh`, which a CN
497
+ // account is refused by. `qoderCnOAuthClient` is the same class bound to
498
+ // `QODER_REALMS.cn` — its own login/token/userinfo hosts, client id, and
499
+ // native redirect.
500
+ loadAuthentication: oauthCapability(() => import("./integrations/qoder/qoder-oauth"), "qoderCnOAuthClient"),
501
+ loadModelDiscovery: qoderDiscovery("cn", "qodercn"),
502
+ },
503
+ trae: {
504
+ loadAdapter: async () => (await import("./integrations/trae/trae")).createTraeAdapter(),
505
+ loadModels: async () => (await import("./integrations/trae/trae-catalog")).TRAE_INTL_MODELS,
506
+ // A Trae credential is an access/refresh pair and the refresh token is what
507
+ // keeps it alive, so the refresher is registered rather than optional:
508
+ // without it the account dies at first expiry.
509
+ loadAuthentication: oauthCapability(() => import("./integrations/trae/trae-oauth"), "traeOAuthClient", { withRefresher: true }),
510
+ // Live model list is intl-unsupported: upstream answers `403 no schema
511
+ // found`, so discovery returning nothing is the truthful result and the
512
+ // static roster above stays authoritative.
513
+ loadModelDiscovery: traeDiscovery("intl", "trae"),
514
+ },
515
+ traecn: {
516
+ loadAdapter: async () => (await import("./integrations/trae/trae")).createTraeCnAdapter(),
517
+ loadModels: async () => (await import("./integrations/trae/trae-catalog")).TRAE_CN_MODELS,
518
+ // The CN client, not the intl one: the exchange runs on the CN account
519
+ // host, and a refresh posted to the intl host is refused.
520
+ loadAuthentication: oauthCapability(() => import("./integrations/trae/trae-oauth"), "traeCnOAuthClient", { withRefresher: true }),
521
+ loadModelDiscovery: traeDiscovery("cn", "traecn"),
350
522
  },
351
523
  inferhub: {
352
524
  loadAdapter: async () => (await import("./integrations/inferhub")).createInferhubAdapter(),
@@ -54,10 +54,18 @@ export async function fetchOpenAICompatibleModels(
54
54
  modalityContextLimit(entry);
55
55
  const contextWindow = parsedContext ?? fallback?.contextLimit ?? 200_000;
56
56
 
57
+ // `max_completion_tokens` first: it is the name an OpenAI-shaped catalog
58
+ // uses, and it is the name this gateway's own `/v1/models` emits. A
59
+ // reader that knew only `max_output_tokens`/`maxTokens` saw none of them
60
+ // and fell through to the 64_192 default, so every model on such an
61
+ // upstream was advertised at the same wrong ceiling no matter what the
62
+ // upstream reported.
57
63
  const parsedOutput =
64
+ positiveNumber(entry.max_completion_tokens) ??
58
65
  positiveNumber(entry.max_output_tokens) ??
59
66
  positiveNumber((entry as Record<string, unknown>).max_output_tokens) ??
60
67
  positiveNumber(entry.maxTokens) ??
68
+ positiveNumber((entry as Record<string, unknown>).completion_token_limit) ??
61
69
  modalityOutputLimit(entry);
62
70
  const maxOutputTokens = parsedOutput ?? fallback?.outputLimit ?? 64_192;
63
71
  const outputTokens = Math.min(maxOutputTokens, contextWindow);
@@ -74,7 +82,14 @@ export async function fetchOpenAICompatibleModels(
74
82
  // the upstream declares for the model it serves. A catalog that declares
75
83
  // it as an `input_modalities[]` array instead of a `modality` string was
76
84
  // read as text-only, so a vision model lost image input.
77
- const hasImage = rawModality.includes("image") || modalityImageInput(entry);
85
+ // `capabilities.input` is a third spelling — an array of modality names,
86
+ // used by OpenAI-shaped catalogs including this gateway's own. Read
87
+ // alongside the other two so a vision model is not downgraded to
88
+ // text-only, which then drops image parts before they reach the upstream.
89
+ const hasImage =
90
+ rawModality.includes("image") ||
91
+ modalityImageInput(entry) ||
92
+ capabilityImageInput(entry);
78
93
  const responsesWire = isResponsesNativeModelId(id);
79
94
  byId.set(id, {
80
95
  modelId: id,
@@ -83,8 +98,14 @@ export async function fetchOpenAICompatibleModels(
83
98
  contextLimit: contextWindow,
84
99
  outputLimit: outputTokens,
85
100
  modalities: { input: hasImage ? ["text", "image"] : ["text"], output: ["text"] },
86
- reasoning: false,
87
- toolCall: true,
101
+ // Upstream declares reasoning, so believe it rather than pinning false:
102
+ // a reasoning model advertised as non-reasoning is routed without the
103
+ // thinking budget it needs, and the caller's `reasoning_effort` is
104
+ // dropped as unsupported.
105
+ reasoning: entry.reasoning === true,
106
+ // Same for tool calling — an upstream that names a model as
107
+ // non-tool-capable must not have tools routed to it.
108
+ toolCall: entry.tool_call === false ? false : true,
88
109
  cost,
89
110
  });
90
111
  }
@@ -150,6 +171,21 @@ function modalityImageInput(entry: Record<string, unknown>): boolean {
150
171
 
151
172
 
152
173
 
174
+ /**
175
+ * Image input from a `capabilities.input` array.
176
+ *
177
+ * The field is a plain list of modality names (`["text","image"]`), not the
178
+ * structured `input_modalities[]` objects the sibling reader expects. A catalog
179
+ * that spells it this way was read as text-only.
180
+ */
181
+ function capabilityImageInput(entry: Record<string, unknown>): boolean {
182
+ const capabilities = entry.capabilities;
183
+ if (!isRecord(capabilities)) return false;
184
+ const inputs = capabilities.input;
185
+ if (!Array.isArray(inputs)) return false;
186
+ return inputs.some((name) => typeof name === "string" && name.toLowerCase().includes("image"));
187
+ }
188
+
153
189
  function extractEntries(payload: unknown): readonly Record<string, unknown>[] | null {
154
190
  if (Array.isArray(payload)) return payload.filter(isRecord);
155
191
  if (typeof payload !== "object" || payload === null) return null;
@@ -0,0 +1,98 @@
1
+ /**
2
+ * The free tier shared by the OpenRouter-backed providers.
3
+ *
4
+ * Cline, Kilo Code and OpenRouter serve one model catalog: the same 469 ids,
5
+ * and the same 17 of them carrying a `:free` suffix. Verified against all three
6
+ * live listings — every id below is present under `openrouter`, `kilo` and
7
+ * `cline` — so this roster is a catalog fact, not a per-provider guess, and it
8
+ * lives in one place rather than being restated three times.
9
+ *
10
+ * The limits, modalities and capability flags are read from OpenRouter's own
11
+ * `/api/v1/models`, which states `context_length`,
12
+ * `top_provider.max_completion_tokens`, `architecture.input_modalities` and
13
+ * `supported_parameters`. That is the serving catalog's declaration, so these
14
+ * are measurements rather than defaults.
15
+ *
16
+ * This is a floor, not the authority: each provider also discovers live, and a
17
+ * row the listing carries that this roster does not is still found there. The
18
+ * roster exists so a fresh install has a usable free tier before any fetch, and
19
+ * so the free section is populated even when discovery is unavailable.
20
+ */
21
+ import { defineModel } from "../provider-model-definition";
22
+ import type { ModelDefinition } from "../provider-model-definition";
23
+
24
+ export interface FreeRosterOptions {
25
+ readonly providerId: string;
26
+ /** The wire suffix that completes the provider's base URL. */
27
+ readonly endpoint: string;
28
+ }
29
+
30
+ interface FreeRow {
31
+ readonly id: string;
32
+ readonly ctx: number;
33
+ readonly out: number;
34
+ readonly vision?: boolean;
35
+ /** `supported_parameters` omits `tools` on the safety classifier only. */
36
+ readonly toolCall?: boolean;
37
+ }
38
+
39
+ /**
40
+ * The 17 `:free` ids, with the limits the catalog states for each.
41
+ *
42
+ * Every row declares `reasoning`: `supported_parameters` lists it on all
43
+ * seventeen. `toolCall` is `true` unless stated otherwise, because a row that
44
+ * advertises tools must keep them — a false `toolCall` makes the preflight
45
+ * strip `tools` from the request, which is a wrong capability rather than a
46
+ * conservative one.
47
+ */
48
+ const FREE_ROWS: readonly FreeRow[] = [
49
+ { id: "cohere/north-mini-code:free", ctx: 256_000, out: 64_000 },
50
+ { id: "dots-studio/dots-3-note-preview:free", ctx: 512_000, out: 460_800, vision: true },
51
+ { id: "google/gemma-4-26b-a4b-it:free", ctx: 262_144, out: 32_768, vision: true },
52
+ { id: "google/gemma-4-31b-it:free", ctx: 262_144, out: 32_768, vision: true },
53
+ { id: "liquid/lfm-2.5-2.6b:free", ctx: 65_536, out: 8_192 },
54
+ { id: "minimax/minimax-m3.1-flash:free", ctx: 1_000_000, out: 524_288, vision: true },
55
+ {
56
+ id: "nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free",
57
+ ctx: 256_000,
58
+ out: 65_536,
59
+ vision: true,
60
+ },
61
+ { id: "nvidia/nemotron-3-super-120b-a12b:free", ctx: 262_144, out: 235_929 },
62
+ { id: "nvidia/nemotron-3-ultra-550b-a55b:free", ctx: 1_000_000, out: 65_536 },
63
+ {
64
+ id: "nvidia/nemotron-3.5-content-safety:free",
65
+ ctx: 128_000,
66
+ out: 8_192,
67
+ vision: true,
68
+ toolCall: false,
69
+ },
70
+ { id: "nvidia/nemotron-3.5-lightning:free", ctx: 1_000_000, out: 65_536 },
71
+ { id: "nvidia/nemotron-3.5-super-vl:free", ctx: 1_000_000, out: 131_072, vision: true },
72
+ { id: "poolside/laguna-s-2.1:free", ctx: 262_144, out: 32_768 },
73
+ { id: "poolside/laguna-xs-2.1:free", ctx: 262_144, out: 32_768 },
74
+ { id: "thinkingmachines/inkling-small:free", ctx: 1_048_576, out: 262_144, vision: true },
75
+ { id: "thinkingmachines/inkling:free", ctx: 1_048_576, out: 262_144, vision: true },
76
+ { id: "xingchen-agi/xing4.0-29b-a4b:free", ctx: 262_144, out: 235_929 },
77
+ ];
78
+
79
+ /** Builds this roster for one provider, since each spells its own endpoint. */
80
+ export function openrouterFreeRoster(options: FreeRosterOptions): readonly ModelDefinition[] {
81
+ return FREE_ROWS.map((row) =>
82
+ defineModel({
83
+ id: row.id,
84
+ providerId: options.providerId,
85
+ wireFamily: "chat",
86
+ endpoint: options.endpoint,
87
+ ctx: row.ctx,
88
+ out: row.out,
89
+ vision: row.vision ?? false,
90
+ reasoning: true,
91
+ toolCall: row.toolCall ?? true,
92
+ // `free` is the billing statement and `freeTier` the catalog one. The
93
+ // `:free` suffix makes both true, and the model list groups on the tier.
94
+ free: true,
95
+ freeTier: true,
96
+ }),
97
+ );
98
+ }