cartethyia 2.4.5 → 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 (415) hide show
  1. package/.env.example +4 -1
  2. package/README.md +63 -13
  3. package/dist/dashboard/assets/AccountCooldown-ChpdzxRH.js.gz +0 -0
  4. package/dist/dashboard/assets/BannedPage-9igfctfZ.js +1 -0
  5. package/dist/dashboard/assets/BannedPage-9igfctfZ.js.gz +0 -0
  6. package/dist/dashboard/assets/{CliToolDetailPage-BzGevuql.js → CliToolDetailPage-ZRr2K2sF.js} +1 -1
  7. package/dist/dashboard/assets/CliToolDetailPage-ZRr2K2sF.js.gz +0 -0
  8. package/dist/dashboard/assets/{CliToolsPage-BaRM_7We.js → CliToolsPage-D3xqZbN-.js} +1 -1
  9. package/dist/dashboard/assets/CliToolsPage-D3xqZbN-.js.gz +0 -0
  10. package/dist/dashboard/assets/CombosPage-CVnQPBBz.js +1 -0
  11. package/dist/dashboard/assets/CombosPage-CVnQPBBz.js.gz +0 -0
  12. package/dist/dashboard/assets/ConsoleLogPage-u6W1UXSc.js +1 -0
  13. package/dist/dashboard/assets/ConsoleLogPage-u6W1UXSc.js.gz +0 -0
  14. package/dist/dashboard/assets/{CustomizationPage-DqUGcoH0.js → CustomizationPage-CTTpCb25.js} +1 -1
  15. package/dist/dashboard/assets/CustomizationPage-CTTpCb25.js.gz +0 -0
  16. package/dist/dashboard/assets/HealthEventsModal-C5XpWlvy.js +1 -0
  17. package/dist/dashboard/assets/HealthEventsModal-C5XpWlvy.js.gz +0 -0
  18. package/dist/dashboard/assets/{LoginPage-DbhTGfhb.js → LoginPage-DHoB3Agn.js} +1 -1
  19. package/dist/dashboard/assets/LoginPage-DHoB3Agn.js.gz +0 -0
  20. package/dist/dashboard/assets/ModelPicker-oQ-SDXp8.js +1 -0
  21. package/dist/dashboard/assets/ModelPicker-oQ-SDXp8.js.gz +0 -0
  22. package/dist/dashboard/assets/OverviewPage-BrY4SgIt.js +1 -0
  23. package/dist/dashboard/assets/OverviewPage-BrY4SgIt.js.gz +0 -0
  24. package/dist/dashboard/assets/ProviderDetailPage-D9VSt7T_.js +3 -0
  25. package/dist/dashboard/assets/ProviderDetailPage-D9VSt7T_.js.gz +0 -0
  26. package/dist/dashboard/assets/ProviderIcon-CmfzxpVM.js +1 -0
  27. package/dist/dashboard/assets/ProviderIcon-CmfzxpVM.js.gz +0 -0
  28. package/dist/dashboard/assets/ProvidersPage-Df77V5I5.js +1 -0
  29. package/dist/dashboard/assets/ProvidersPage-Df77V5I5.js.gz +0 -0
  30. package/dist/dashboard/assets/ProxyPage-CDfxP7AC.js +7 -0
  31. package/dist/dashboard/assets/ProxyPage-CDfxP7AC.js.gz +0 -0
  32. package/dist/dashboard/assets/QuotaPage-CY4o2t4p.js +1 -0
  33. package/dist/dashboard/assets/QuotaPage-CY4o2t4p.js.gz +0 -0
  34. package/dist/dashboard/assets/{SettingsPage-YxRml8AT.js → SettingsPage-CvjZxHE4.js} +1 -1
  35. package/dist/dashboard/assets/SettingsPage-CvjZxHE4.js.gz +0 -0
  36. package/dist/dashboard/assets/SetupPage-D3nza7LH.js +1 -0
  37. package/dist/dashboard/assets/SetupPage-D3nza7LH.js.gz +0 -0
  38. package/dist/dashboard/assets/{SortableList-Bol1ASmI.js → SortableList-Dtt12WT1.js} +1 -1
  39. package/dist/dashboard/assets/SortableList-Dtt12WT1.js.gz +0 -0
  40. package/dist/dashboard/assets/StudioPage-CbK3hXvU.js +31 -0
  41. package/dist/dashboard/assets/StudioPage-CbK3hXvU.js.gz +0 -0
  42. package/dist/dashboard/assets/ToolIcon-K1ckcDKg.js.gz +0 -0
  43. package/dist/dashboard/assets/UsagePage-BQlWbWg2.js +56 -0
  44. package/dist/dashboard/assets/UsagePage-BQlWbWg2.js.gz +0 -0
  45. package/dist/dashboard/assets/api-keys-BmDbsior.js +1 -0
  46. package/dist/dashboard/assets/api-keys-BmDbsior.js.gz +0 -0
  47. package/dist/dashboard/assets/app-BbpSarVV.css +2 -0
  48. package/dist/dashboard/assets/app-BbpSarVV.css.gz +0 -0
  49. package/dist/dashboard/assets/{app-BDJWMThu.js → app-C-Y4oZT0.js} +3 -3
  50. package/dist/dashboard/assets/app-C-Y4oZT0.js.gz +0 -0
  51. package/dist/dashboard/assets/arrow-left-CpBxkoxI.js.gz +0 -0
  52. package/dist/dashboard/assets/arrow-right-Dl5yKnp8.js.gz +0 -0
  53. package/dist/dashboard/assets/assert-BHfaei-X.js +1 -0
  54. package/dist/dashboard/assets/assert-BHfaei-X.js.gz +0 -0
  55. package/dist/dashboard/assets/backup-file-gdKIlg8U.js.gz +0 -0
  56. package/dist/dashboard/assets/{badge-BwmwEOgA.js → badge-DpXT4Ixt.js} +1 -1
  57. package/dist/dashboard/assets/badge-DpXT4Ixt.js.gz +0 -0
  58. package/dist/dashboard/assets/{banner-BKBfKTqn.js → banner-CSAAWLJv.js} +1 -1
  59. package/dist/dashboard/assets/banner-CSAAWLJv.js.gz +0 -0
  60. package/dist/dashboard/assets/brain-Cwed_72z.js.gz +0 -0
  61. package/dist/dashboard/assets/{card-BTdbRFFg.js → card-DEhRXXw4.js} +1 -1
  62. package/dist/dashboard/assets/card-DEhRXXw4.js.gz +0 -0
  63. package/dist/dashboard/assets/check-D69FzdvC.js.gz +0 -0
  64. package/dist/dashboard/assets/chevron-right-BXIy5l3h.js.gz +0 -0
  65. package/dist/dashboard/assets/circle-alert-CntYHV5v.js.gz +0 -0
  66. package/dist/dashboard/assets/circle-check-BU3v_mFW.js.gz +0 -0
  67. package/dist/dashboard/assets/cli-tools-B0wBq-RL.js +1 -0
  68. package/dist/dashboard/assets/cli-tools-B0wBq-RL.js.gz +0 -0
  69. package/dist/dashboard/assets/clipboard-button-DOo6EU8O.js +1 -0
  70. package/dist/dashboard/assets/clipboard-button-DOo6EU8O.js.gz +0 -0
  71. package/dist/dashboard/assets/cog-CdWhsajs.js.gz +0 -0
  72. package/dist/dashboard/assets/copy-ngmQ9zcZ.js.gz +0 -0
  73. package/dist/dashboard/assets/{dialog-iocKA3jr.js → dialog-BvQeBMfP.js} +1 -1
  74. package/dist/dashboard/assets/dialog-BvQeBMfP.js.gz +0 -0
  75. package/dist/dashboard/assets/dialog-actions-B1axpEg7.js.gz +0 -0
  76. package/dist/dashboard/assets/download-A0SW9OCW.js.gz +0 -0
  77. package/dist/dashboard/assets/download-dRFo5_Wu.js.gz +0 -0
  78. package/dist/dashboard/assets/{drawer-CDKOTZdY.js → drawer-CMwPXwQB.js} +1 -1
  79. package/dist/dashboard/assets/drawer-CMwPXwQB.js.gz +0 -0
  80. package/dist/dashboard/assets/entry-D4O2229X.js +1 -0
  81. package/dist/dashboard/assets/entry-D4O2229X.js.gz +0 -0
  82. package/dist/dashboard/assets/entry-DKvr5Q9K.js +1 -0
  83. package/dist/dashboard/assets/entry-DKvr5Q9K.js.gz +0 -0
  84. package/dist/dashboard/assets/entry-FQCejoDY.js +4 -0
  85. package/dist/dashboard/assets/entry-FQCejoDY.js.gz +0 -0
  86. package/dist/dashboard/assets/eye-C_hawfH4.js.gz +0 -0
  87. package/dist/dashboard/assets/eye-off-Bk5g2luF.js.gz +0 -0
  88. package/dist/dashboard/assets/fingerprint-pattern-BWuHtbW4.js.gz +0 -0
  89. package/dist/dashboard/assets/gauge-BbIMy7MB.js.gz +0 -0
  90. package/dist/dashboard/assets/github-badge-zliLvBwr.js +1 -0
  91. package/dist/dashboard/assets/github-badge-zliLvBwr.js.gz +0 -0
  92. package/dist/dashboard/assets/image-BPaouViG.js.gz +0 -0
  93. package/dist/dashboard/assets/{index-C4hXfAMs.js → index-CXm3FIyt.js} +2 -2
  94. package/dist/dashboard/assets/index-CXm3FIyt.js.gz +0 -0
  95. package/dist/dashboard/assets/{inline-DCejSLlA.js → inline-D1IlZZ8H.js} +1 -1
  96. package/dist/dashboard/assets/inline-D1IlZZ8H.js.gz +0 -0
  97. package/dist/dashboard/assets/{input-Bn4_kNav.js → input-BpVZdrbc.js} +1 -1
  98. package/dist/dashboard/assets/input-BpVZdrbc.js.gz +0 -0
  99. package/dist/dashboard/assets/jsx-runtime-CXUMngI_.js.gz +0 -0
  100. package/dist/dashboard/assets/key-round-UkavsGxp.js.gz +0 -0
  101. package/dist/dashboard/assets/layers-2-glBbjl.js.gz +0 -0
  102. package/dist/dashboard/assets/{layout-Bv-NxqZ5.js → layout-BioLW7gN.js} +1 -1
  103. package/dist/dashboard/assets/layout-BioLW7gN.js.gz +0 -0
  104. package/dist/dashboard/assets/{list-row-BLA0sldD.js → list-row-CwVcGAIc.js} +1 -1
  105. package/dist/dashboard/assets/list-row-CwVcGAIc.js.gz +0 -0
  106. package/dist/dashboard/assets/{live-YlifPYox.js → live-yfEJFF9T.js} +1 -1
  107. package/dist/dashboard/assets/live-yfEJFF9T.js.gz +0 -0
  108. package/dist/dashboard/assets/log-in-BmRjy60c.js.gz +0 -0
  109. package/dist/dashboard/assets/message-circle-CCxGwRvv.js.gz +0 -0
  110. package/dist/dashboard/assets/model-bans-CT-TxSNX.js +1 -0
  111. package/dist/dashboard/assets/model-bans-CT-TxSNX.js.gz +0 -0
  112. package/dist/dashboard/assets/mutation-BkoLM5Ba.js +1 -0
  113. package/dist/dashboard/assets/mutation-BkoLM5Ba.js.gz +0 -0
  114. package/dist/dashboard/assets/numbers-CFL4_Dqc.js.gz +0 -0
  115. package/dist/dashboard/assets/pencil-768ysRAr.js.gz +0 -0
  116. package/dist/dashboard/assets/plus-DIdX_g-x.js.gz +0 -0
  117. package/dist/dashboard/assets/power-off-Yjw9GMJh.js +1 -0
  118. package/dist/dashboard/assets/power-off-Yjw9GMJh.js.gz +0 -0
  119. package/dist/dashboard/assets/privacy-mode-GM8bej85.js +1 -0
  120. package/dist/dashboard/assets/privacy-mode-GM8bej85.js.gz +0 -0
  121. package/dist/dashboard/assets/providers/agentrouter.svg.gz +0 -0
  122. package/dist/dashboard/assets/providers/aihubmix.svg.gz +0 -0
  123. package/dist/dashboard/assets/providers/alibaba-coding-plan.svg.gz +0 -0
  124. package/dist/dashboard/assets/providers/alibaba.svg.gz +0 -0
  125. package/dist/dashboard/assets/providers/antigravity.svg.gz +0 -0
  126. package/dist/dashboard/assets/providers/bai.svg.gz +0 -0
  127. package/dist/dashboard/assets/providers/blackbox.svg.gz +0 -0
  128. package/dist/dashboard/assets/providers/claude-code.svg.gz +0 -0
  129. package/dist/dashboard/assets/providers/cursor.webp +0 -0
  130. package/dist/dashboard/assets/providers/exa.svg.gz +0 -0
  131. package/dist/dashboard/assets/providers/gmi-cloud.svg.gz +0 -0
  132. package/dist/dashboard/assets/providers/inferhub.svg.gz +0 -0
  133. package/dist/dashboard/assets/providers/muse.svg.gz +0 -0
  134. package/dist/dashboard/assets/providers/nous-research.svg.gz +0 -0
  135. package/dist/dashboard/assets/providers/openai-light.svg.gz +0 -0
  136. package/dist/dashboard/assets/providers/parallel.svg.gz +0 -0
  137. package/dist/dashboard/assets/providers/tokenharbor.svg.gz +0 -0
  138. package/dist/dashboard/assets/providers/trae.webp +0 -0
  139. package/dist/dashboard/assets/providers/zai-coding-plan.svg.gz +0 -0
  140. package/dist/dashboard/assets/{query-keys-ROf-g1Wi.js → query-keys-D7wX2vM5.js} +1 -1
  141. package/dist/dashboard/assets/query-keys-D7wX2vM5.js.gz +0 -0
  142. package/dist/dashboard/assets/quota-DZGyp0N5.js.gz +0 -0
  143. package/dist/dashboard/assets/refresh-cw-BqJFk4sU.js.gz +0 -0
  144. package/dist/dashboard/assets/rotate-ccw-CufcqITi.js.gz +0 -0
  145. package/dist/dashboard/assets/route-CNSNj9Zm.js.gz +0 -0
  146. package/dist/dashboard/assets/routing-Cs6jl49L.js +1 -0
  147. package/dist/dashboard/assets/routing-Cs6jl49L.js.gz +0 -0
  148. package/dist/dashboard/assets/scaling-nWE4Cx8f.js.gz +0 -0
  149. package/dist/dashboard/assets/search-JOKus9rb.js.gz +0 -0
  150. package/dist/dashboard/assets/select-C0Rer3gF.js +41 -0
  151. package/dist/dashboard/assets/select-C0Rer3gF.js.gz +0 -0
  152. package/dist/dashboard/assets/settings-CfcTcOyU.js +1 -0
  153. package/dist/dashboard/assets/settings-CfcTcOyU.js.gz +0 -0
  154. package/dist/dashboard/assets/shield-check-DVS0Foqh.js.gz +0 -0
  155. package/dist/dashboard/assets/sparkles-BRaRUxAU.js.gz +0 -0
  156. package/dist/dashboard/assets/{stack-C1kTcOmP.js → stack-C9_uUjaA.js} +1 -1
  157. package/dist/dashboard/assets/stack-C9_uUjaA.js.gz +0 -0
  158. package/dist/dashboard/assets/{state-DHKdg-pm.js → state-DA0B95UQ.js} +1 -1
  159. package/dist/dashboard/assets/state-DA0B95UQ.js.gz +0 -0
  160. package/dist/dashboard/assets/stream-retry-5QnVuSSo.js.gz +0 -0
  161. package/dist/dashboard/assets/{switch-DIDeAiz9.js → switch-Cittxy-x.js} +1 -1
  162. package/dist/dashboard/assets/switch-Cittxy-x.js.gz +0 -0
  163. package/dist/dashboard/assets/terminal-Bd4ee8TA.js +1 -0
  164. package/dist/dashboard/assets/terminal-Bd4ee8TA.js.gz +0 -0
  165. package/dist/dashboard/assets/toast-CNt_jzO4.js +2 -0
  166. package/dist/dashboard/assets/toast-CNt_jzO4.js.gz +0 -0
  167. package/dist/dashboard/assets/tokens-DDxMbSRL.js.gz +0 -0
  168. package/dist/dashboard/assets/trash-Cppn5c3R.js.gz +0 -0
  169. package/dist/dashboard/assets/use-clipboard-B0Sy03fE.js.gz +0 -0
  170. package/dist/dashboard/assets/use-presence-BSZEBx7U.js.gz +0 -0
  171. package/dist/dashboard/assets/use-reduced-motion-C4B0R6Sz.js.gz +0 -0
  172. package/dist/dashboard/assets/use-timeout-BwcBBRrT.js.gz +0 -0
  173. package/dist/dashboard/assets/{useMutation-DVmwOKU-.js → useMutation-BQKMcJ1H.js} +1 -1
  174. package/dist/dashboard/assets/useMutation-BQKMcJ1H.js.gz +0 -0
  175. package/dist/dashboard/assets/wrench-B6E1oEuY.js.gz +0 -0
  176. package/dist/dashboard/index.html +1 -1
  177. package/dist/dashboard/index.html.gz +0 -0
  178. package/dist/dashboard/precompressed-assets.json +122 -0
  179. package/migrations/full-postgres/0013_add_providers_tenant_id_index.sql +22 -0
  180. package/migrations/full-postgres/0014_add_provider_accounts_tenant_id_index.sql +21 -0
  181. package/migrations/full-postgres/0015_add_payload_stages.sql +18 -0
  182. package/migrations/full-postgres/0016_add_share_link_slug.sql +20 -0
  183. package/migrations/full-postgres/0017_add_models_pro_only.sql +18 -0
  184. package/migrations/full-postgres/0018_add_accounts_quota_plan.sql +18 -0
  185. package/migrations/full-postgres/0019_add_models_free_tier.sql +15 -0
  186. package/migrations/lite-sqlite3/0000_baseline.sql +4 -2
  187. package/migrations/lite-sqlite3/0013_add_providers_tenant_id_index.sql +4 -0
  188. package/migrations/lite-sqlite3/0014_add_provider_accounts_tenant_id_index.sql +4 -0
  189. package/migrations/lite-sqlite3/0015_add_payload_stages.sql +18 -0
  190. package/migrations/lite-sqlite3/0016_add_share_link_slug.sql +20 -0
  191. package/migrations/lite-sqlite3/0017_add_models_pro_only.sql +18 -0
  192. package/migrations/lite-sqlite3/0018_add_accounts_quota_plan.sql +18 -0
  193. package/migrations/lite-sqlite3/0019_add_models_free_tier.sql +15 -0
  194. package/package.json +26 -30
  195. package/scripts/cli/{carte-launcher.cjs → bin/carte.cjs} +8 -8
  196. package/scripts/cli/{cli-launcher.cjs → bin/cartethyia.cjs} +167 -134
  197. package/scripts/cli/command/admin.ts +65 -0
  198. package/scripts/cli/command/console-menu.ts +246 -0
  199. package/scripts/cli/{doctor.ts → command/doctor.ts} +257 -258
  200. package/scripts/cli/{setup.ts → command/setup.ts} +8 -12
  201. package/scripts/cli/command/start.ts +77 -0
  202. package/scripts/cli/command/tray.ts +165 -0
  203. package/scripts/cli/command/update.ts +23 -0
  204. package/scripts/cli/{runtime-state.ts → gateway/drain-token.ts} +78 -78
  205. package/scripts/cli/gateway/instance-lock.ts +105 -0
  206. package/scripts/cli/gateway/spawn.ts +173 -0
  207. package/scripts/cli/gateway/stop.ts +51 -0
  208. package/scripts/cli/main.ts +94 -0
  209. package/scripts/cli/support/bun.ts +27 -0
  210. package/scripts/cli/support/env.ts +99 -0
  211. package/scripts/cli/support/platform.ts +64 -0
  212. package/scripts/cli/support/services.ts +88 -0
  213. package/scripts/cli/support/startup-signal.ts +23 -0
  214. package/scripts/cli/{version.ts → support/version.ts} +1 -1
  215. package/scripts/cli/tray/hidden-window.vbs +28 -0
  216. package/scripts/cli/{tray.ts → tray/index.ts} +3 -3
  217. package/scripts/cli/{tray.ps1 → tray/windows.ps1} +107 -98
  218. package/scripts/cli/ui/background.ts +110 -0
  219. package/src/boot/app.ts +23 -7
  220. package/src/boot/dependencies.ts +55 -13
  221. package/src/boot/elysia-typebox-bridge.ts +37 -0
  222. package/src/boot/lifecycle.ts +2 -0
  223. package/src/config/cooldowns.ts +138 -138
  224. package/src/config/providers.ts +31 -5
  225. package/src/config/runtime.ts +19 -3
  226. package/src/config/spec.ts +20 -0
  227. package/src/console/api-keys/contracts.ts +414 -391
  228. package/src/console/api-keys/routes.ts +880 -870
  229. package/src/console/auth/account-reset-store.ts +14 -0
  230. package/src/console/auth/account-reset.ts +3 -2
  231. package/src/console/auth/setup-service.ts +6 -3
  232. package/src/console/backup/routes.ts +8 -0
  233. package/src/console/cli-tools/contracts.ts +6 -6
  234. package/src/console/console-router.ts +5 -3
  235. package/src/console/dashboard-assets.ts +81 -11
  236. package/src/console/domain-registration.ts +9 -2
  237. package/src/console/observability/contracts.ts +475 -423
  238. package/src/console/observability/routes.ts +31 -6
  239. package/src/console/observability/store.ts +1015 -912
  240. package/src/console/providers/catalog/contracts.ts +31 -0
  241. package/src/console/providers/catalog/provider-operations.ts +8 -0
  242. package/src/console/providers/catalog/public-model-store.ts +91 -60
  243. package/src/console/providers/catalog/store.ts +1532 -1521
  244. package/src/console/providers/oauth/callback-listener.ts +18 -3
  245. package/src/console/providers/oauth/routes.ts +38 -15
  246. package/src/console/quota/account-quota-tenant.ts +9 -6
  247. package/src/console/quota/refresh.ts +19 -0
  248. package/src/console/response-compression.ts +69 -2
  249. package/src/console/routing/pools/probe-verdict.ts +72 -0
  250. package/src/console/share/share-router.ts +7 -4
  251. package/src/console/share/share-stats.ts +12 -5
  252. package/src/console/shared/read-through-cache.ts +133 -7
  253. package/src/console/updates/repository-updates.ts +39 -34
  254. package/src/console/updates/routes.ts +162 -4
  255. package/src/main.ts +3 -0
  256. package/src/network/http2-bidi.ts +85 -0
  257. package/src/network/outbound-fetch.ts +87 -24
  258. package/src/network/pool/agent.ts +478 -460
  259. package/src/network/pool/resolver.ts +1104 -544
  260. package/src/network/pool-health-machine.ts +12 -5
  261. package/src/observability/event-log.ts +29 -8
  262. package/src/observability/metrics.ts +40 -13
  263. package/src/observability/payload-capture.ts +344 -324
  264. package/src/observability/runtime-metrics.ts +7 -0
  265. package/src/persistence/db-pg.ts +9 -3
  266. package/src/persistence/db-sqlite.ts +497 -495
  267. package/src/persistence/health-event-flush.ts +137 -0
  268. package/src/persistence/migrate.ts +181 -129
  269. package/src/persistence/schema.ts +1360 -1257
  270. package/src/persistence/settings-revision.ts +25 -0
  271. package/src/persistence/shared-cache.ts +217 -0
  272. package/src/persistence/stores/share-store.ts +556 -528
  273. package/src/persistence/usage-flush.ts +61 -1
  274. package/src/protocol/canonical-model.ts +23 -1
  275. package/src/protocol/response/chat.ts +143 -10
  276. package/src/protocol/response/codex.ts +9 -75
  277. package/src/protocol/response/omp-tool-call-markup.ts +221 -0
  278. package/src/protocol/tool-identity.ts +43 -9
  279. package/src/providers/authentication/jwt-validator.ts +130 -187
  280. package/src/providers/authentication/oauth-flow-store.ts +16 -9
  281. package/src/providers/default-registry.ts +177 -1
  282. package/src/providers/discovery/catalog/catalog-format.ts +20 -0
  283. package/src/providers/discovery/models-dev-catalog.ts +39 -22
  284. package/src/providers/discovery/openai-model-discovery.ts +39 -3
  285. package/src/providers/discovery/openrouter-free-roster.ts +98 -0
  286. package/src/providers/discovery/probe-wire.ts +29 -5
  287. package/src/providers/discovery/probing-service.ts +1022 -1001
  288. package/src/providers/integrations/buddy/buddy-catalog-shared.ts +42 -2
  289. package/src/providers/integrations/buddy/buddy-chat-shared.ts +913 -914
  290. package/src/providers/integrations/buddy/buddy-cli-headers.ts +88 -0
  291. package/src/providers/integrations/buddy/buddy-conversation-headers.ts +22 -5
  292. package/src/providers/integrations/buddy/buddy-discovery-shared.ts +33 -1
  293. package/src/providers/integrations/buddy/buddy-identity.ts +46 -0
  294. package/src/providers/integrations/buddy/buddy-oauth-shared.ts +37 -1
  295. package/src/providers/integrations/buddy/buddy-usage-store.ts +40 -5
  296. package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +4 -0
  297. package/src/providers/integrations/buddy/codebuddy/provider.ts +180 -175
  298. package/src/providers/integrations/buddy/codebuddy/shared.ts +115 -73
  299. package/src/providers/integrations/buddy/workbuddy/cn-provider.ts +5 -2
  300. package/src/providers/integrations/buddy/workbuddy/provider.ts +206 -204
  301. package/src/providers/integrations/buddy/workbuddy/quota.ts +172 -159
  302. package/src/providers/integrations/buddy/workbuddy/shared.ts +200 -171
  303. package/src/providers/integrations/claude/claude.ts +606 -582
  304. package/src/providers/integrations/cline/cline-quota.ts +18 -16
  305. package/src/providers/integrations/cline/cline.ts +539 -468
  306. package/src/providers/integrations/codex/codex.ts +5 -8
  307. package/src/providers/integrations/commandcode/commandcode.ts +675 -541
  308. package/src/providers/integrations/commandcode/discovery.ts +116 -0
  309. package/src/providers/integrations/commandcode/quota.ts +160 -0
  310. package/src/providers/integrations/cursor/cursor-auth.ts +418 -0
  311. package/src/providers/integrations/cursor/cursor-catalog.ts +368 -0
  312. package/src/providers/integrations/cursor/cursor-http2.ts +300 -0
  313. package/src/providers/integrations/cursor/cursor-identity.ts +92 -0
  314. package/src/providers/integrations/cursor/cursor-request.ts +471 -0
  315. package/src/providers/integrations/cursor/cursor-session-manager.ts +281 -0
  316. package/src/providers/integrations/cursor/cursor-shared.ts +108 -0
  317. package/src/providers/integrations/cursor/cursor.ts +960 -0
  318. package/src/providers/integrations/cursor/protocol/framing.ts +129 -0
  319. package/src/providers/integrations/cursor/protocol/messages.ts +2355 -0
  320. package/src/providers/integrations/cursor/protocol/struct.ts +305 -0
  321. package/src/providers/integrations/factory/factory-oauth.ts +7 -11
  322. package/src/providers/integrations/github/github.ts +4 -4
  323. package/src/providers/integrations/hermes.ts +79 -8
  324. package/src/providers/integrations/kilo/kilo-discovery.ts +10 -1
  325. package/src/providers/integrations/kilo/kilo.ts +153 -146
  326. package/src/providers/integrations/opencode/opencode-go-quota.ts +130 -0
  327. package/src/providers/integrations/opencode/provider.ts +532 -499
  328. package/src/providers/integrations/openrouter/provider.ts +139 -281
  329. package/src/providers/integrations/qoder/qoder-catalog.ts +450 -0
  330. package/src/providers/integrations/qoder/qoder-oauth.ts +310 -263
  331. package/src/providers/integrations/qoder/qoder-realm.ts +106 -0
  332. package/src/providers/integrations/qoder/qoder-virtual.ts +77 -0
  333. package/src/providers/integrations/qoder/qoder.ts +865 -730
  334. package/src/providers/integrations/shared/install-id.ts +29 -2
  335. package/src/providers/integrations/trae/trae-catalog.ts +190 -0
  336. package/src/providers/integrations/trae/trae-headers.ts +149 -0
  337. package/src/providers/integrations/trae/trae-oauth.ts +773 -0
  338. package/src/providers/integrations/trae/trae-protocol.ts +400 -0
  339. package/src/providers/integrations/trae/trae-realm.ts +220 -0
  340. package/src/providers/integrations/trae/trae.ts +458 -0
  341. package/src/providers/operations/account-health-service.ts +107 -10
  342. package/src/providers/operations/client-versions.ts +143 -6
  343. package/src/providers/operations/model-catalog-cache.ts +18 -3
  344. package/src/providers/operations/provider-catalog-seeder.ts +95 -86
  345. package/src/providers/operations/provider-catalog-service.ts +76 -0
  346. package/src/providers/operations/provider-credential-service.ts +46 -7
  347. package/src/providers/provider-contracts.ts +76 -0
  348. package/src/providers/provider-metadata.ts +78 -6
  349. package/src/providers/provider-model-definition.ts +373 -349
  350. package/src/security/api-key-auth.ts +126 -8
  351. package/src/transport/contracts.ts +3 -0
  352. package/src/transport/dispatch/attempt-finalize.ts +39 -2
  353. package/src/transport/dispatch/attempt-loop.ts +530 -513
  354. package/src/transport/dispatch/empty-stream.ts +17 -26
  355. package/src/transport/dispatch/generation.ts +88 -21
  356. package/src/transport/dispatch/leases.ts +99 -2
  357. package/src/transport/dispatch/proxy-request.ts +60 -3
  358. package/src/transport/dispatch/streaming/finalize.ts +16 -1
  359. package/src/transport/dispatch/streaming/stream.ts +22 -2
  360. package/src/transport/dispatch/upstream.ts +19 -1
  361. package/src/transport/failure-policy.ts +20 -0
  362. package/src/transport/guards/auth-guard.ts +26 -1
  363. package/src/transport/guards/body-policy.ts +5 -4
  364. package/src/transport/request/preparer.ts +103 -0
  365. package/src/transport/request/state.ts +14 -0
  366. package/src/transport/routing/plan-gate.ts +45 -0
  367. package/src/transport/routing/route-catalog.ts +799 -738
  368. package/src/transport/routing/route-model.ts +52 -1
  369. package/src/transport/routing/router.ts +51 -0
  370. package/src/transport/surface/chat/encode.ts +18 -31
  371. package/src/transport/surface/messages/stream.ts +3 -2
  372. package/src/transport/translation/tool-repair.ts +37 -16
  373. package/src/workers/account-identity-sweep.ts +14 -12
  374. package/src/workers/daily-checkin.ts +62 -0
  375. package/src/workers/quota-refresh-sweep.ts +27 -2
  376. package/dist/dashboard/assets/BannedPage-DUrXpp-X.js +0 -1
  377. package/dist/dashboard/assets/CombosPage-B7ETkfVH.js +0 -1
  378. package/dist/dashboard/assets/ConsoleLogPage-AisQzCI1.js +0 -1
  379. package/dist/dashboard/assets/HealthEventsModal-BNflDm_f.js +0 -1
  380. package/dist/dashboard/assets/ModelPicker-CAiPR5Vd.js +0 -1
  381. package/dist/dashboard/assets/OverviewPage-C3NIzsDx.js +0 -1
  382. package/dist/dashboard/assets/ProviderDetailPage-BK8i5B5X.js +0 -3
  383. package/dist/dashboard/assets/ProviderIcon-paOCq8I0.js +0 -1
  384. package/dist/dashboard/assets/ProvidersPage-CvCVgm1e.js +0 -1
  385. package/dist/dashboard/assets/ProxyPage-DjabkuzP.js +0 -7
  386. package/dist/dashboard/assets/QuotaPage-Dxe0B0iu.js +0 -1
  387. package/dist/dashboard/assets/SetupPage-BaD4P_jW.js +0 -1
  388. package/dist/dashboard/assets/StudioPage-CLP4le3U.js +0 -31
  389. package/dist/dashboard/assets/UsagePage-Djes-Epy.js +0 -56
  390. package/dist/dashboard/assets/api-keys-CjIGQhe7.js +0 -1
  391. package/dist/dashboard/assets/app-Cjgo4-Lf.css +0 -2
  392. package/dist/dashboard/assets/assert-Bwh6DJTK.js +0 -1
  393. package/dist/dashboard/assets/cli-tools-DccaOfhX.js +0 -1
  394. package/dist/dashboard/assets/clipboard-button-DQmMikNQ.js +0 -1
  395. package/dist/dashboard/assets/entry-Cpi0rph1.js +0 -4
  396. package/dist/dashboard/assets/entry-Dm3PpDCO.js +0 -1
  397. package/dist/dashboard/assets/entry-keNDZ_Wz.js +0 -1
  398. package/dist/dashboard/assets/github-badge-BuAJr8oU.js +0 -1
  399. package/dist/dashboard/assets/model-bans-CVvHZ-qz.js +0 -1
  400. package/dist/dashboard/assets/mutation-BIizFZav.js +0 -1
  401. package/dist/dashboard/assets/privacy-mode-CQjbZ3xk.js +0 -1
  402. package/dist/dashboard/assets/routing-jntw9-Ui.js +0 -1
  403. package/dist/dashboard/assets/select-CGUuTQmj.js +0 -41
  404. package/dist/dashboard/assets/settings-BAS6QbmJ.js +0 -1
  405. package/dist/dashboard/assets/sliders-horizontal-ClG7dBeJ.js +0 -1
  406. package/dist/dashboard/assets/terminal-C9mZ4Ugm.js +0 -1
  407. package/dist/dashboard/assets/toast-DKAdP2mo.js +0 -2
  408. package/scripts/cli/cli.ts +0 -771
  409. package/scripts/operations/probe-egress.ts +0 -335
  410. package/scripts/operations/restart.ts +0 -120
  411. package/scripts/shared/env.ts +0 -269
  412. /package/{tray-assets → scripts/cli/tray/assets}/cartethyia.ico +0 -0
  413. /package/{tray-assets → scripts/cli/tray/assets}/cartethyia.png +0 -0
  414. /package/scripts/cli/{menu.ts → ui/prompt.ts} +0 -0
  415. /package/scripts/cli/{wordmark.ts → ui/wordmark.ts} +0 -0
@@ -1,146 +1,153 @@
1
- /**
2
- * Kilo Code adapter.
3
- *
4
- * Kilo Code resells the OpenRouter catalog behind a bearer device token on an
5
- * OpenAI-compatible chat surface, so this adapter reuses the shared factory for
6
- * payload translation, transport, and SSE decoding.
7
- *
8
- * One thing sits outside the declarative `ApiKeyProviderSpec`: the stored
9
- * credential is a JSON envelope (`{ accessToken, orgId }`) because the gateway
10
- * scopes every request to the account's organization and the console stores one
11
- * opaque string per account. The factory forwards that string as the bearer
12
- * verbatim, so the envelope is decoded at the auth boundary here — the same
13
- * arrangement `kimi/kimi.ts` uses for its own envelope credential.
14
- *
15
- * The base URL is the completions path itself, because that is the path Kilo
16
- * Code publishes (`/api/openrouter/chat/completions`) and it is not derivable
17
- * from an origin plus a wire-family suffix.
18
- */
19
- import { defineModel } from "../../provider-model-definition";
20
- import type { ModelDefinition } from "../../provider-model-definition";
21
- import type { ProviderAdapter, ProviderDispatchContext, ProviderDispatchTarget } from "../../provider-contracts";
22
- import type { CanonicalRequest } from "../../../protocol/canonical-model";
23
- import { OpenAICompatibleAdapter, withBearerAuthentication } from "../../adapters/compatible-adapter";
24
- import { providerBaseUrl } from "../../provider-metadata";
25
- import { decodeKiloCredential } from "../../../security/credential-codec";
26
-
27
- export const KILO_PROVIDER_ID = "kilo" as const;
28
- export const KILO_BASE_URL = providerBaseUrl("kilo");
29
-
30
- /**
31
- * Endpoint path recorded on this provider's model rows and used by the adapter.
32
- *
33
- * The base URL carries Kilo Code's API prefix (`/api/openrouter`), so this is
34
- * the wire suffix that completes it — the same split Cline uses for
35
- * `/api/v1` + `/chat/completions`.
36
- */
37
- export const KILO_ENDPOINT_PATH = "/chat/completions" as const;
38
-
39
- interface KiloModelOptions {
40
- readonly vision?: boolean;
41
- readonly document?: boolean;
42
- readonly audio?: boolean;
43
- readonly reasoning?: boolean;
44
- readonly toolCall?: boolean;
45
- }
46
-
47
- function kiloModel(
48
- modelId: string,
49
- contextLimit: number,
50
- outputLimit: number,
51
- options: KiloModelOptions = {},
52
- ): ModelDefinition {
53
- return defineModel({
54
- id: modelId,
55
- providerId: KILO_PROVIDER_ID,
56
- wireFamily: "chat",
57
- endpoint: KILO_ENDPOINT_PATH,
58
- ctx: contextLimit,
59
- out: outputLimit,
60
- vision: options.vision ?? false,
61
- document: options.document ?? false,
62
- audio: options.audio ?? false,
63
- reasoning: options.reasoning ?? false,
64
- toolCall: options.toolCall ?? true,
65
- });
66
- }
67
-
68
- /**
69
- * Static fallback catalog, read from the live `/api/gateway/models` directory.
70
- *
71
- * Live discovery replaces this list whenever an account is available, so these
72
- * rows are the offline floor: the gateway's own routing aliases plus one
73
- * current model per family it resells. Limits and capability come from the
74
- * directory entry's own `top_provider` / `architecture` /
75
- * `supported_parameters` fields rather than from the base catalog, which prices
76
- * the underlying model and not this reseller's serving.
77
- */
78
- export const KILO_MODELS: readonly ModelDefinition[] = [
79
- kiloModel("kilo-auto/frontier", 1_000_000, 128_000, { vision: true, document: true, reasoning: true }),
80
- kiloModel("kilo-auto/balanced", 1_000_000, 65_536, { vision: true, reasoning: true }),
81
- kiloModel("kilo-auto/efficient", 1_000_000, 65_536, { vision: true, reasoning: true }),
82
- kiloModel("kilo-auto/small", 262_144, 32_768, { vision: true, reasoning: true }),
83
- kiloModel("kilo-auto/free", 256_000, 32_768, { reasoning: true }),
84
- kiloModel("anthropic/claude-opus-4.8", 1_000_000, 128_000, { vision: true, document: true, reasoning: true }),
85
- kiloModel("anthropic/claude-opus-4.7", 1_000_000, 128_000, { vision: true, document: true, reasoning: true }),
86
- kiloModel("anthropic/claude-sonnet-4.6", 1_000_000, 128_000, { vision: true, document: true, reasoning: true }),
87
- kiloModel("openai/gpt-6-sol", 1_050_000, 128_000, { vision: true, document: true, reasoning: true }),
88
- kiloModel("openai/gpt-6-luna", 1_050_000, 128_000, { vision: true, document: true, reasoning: true }),
89
- kiloModel("openai/gpt-4.1", 1_047_576, 32_768, { vision: true, document: true }),
90
- kiloModel("openai/o3", 200_000, 100_000, { vision: true, document: true, reasoning: true }),
91
- kiloModel("google/gemini-2.5-pro", 1_048_576, 65_536, { vision: true, document: true, audio: true, reasoning: true }),
92
- kiloModel("google/gemini-2.5-flash", 1_048_576, 65_535, { vision: true, document: true, audio: true, reasoning: true }),
93
- kiloModel("x-ai/grok-4.7", 500_000, 450_000, { vision: true, document: true, reasoning: true }),
94
- kiloModel("moonshotai/kimi-k3", 1_048_576, 943_718, { vision: true, reasoning: true }),
95
- kiloModel("z-ai/glm-5.3-flash", 1_048_576, 131_072, { vision: true, reasoning: true }),
96
- kiloModel("deepseek/deepseek-chat", 163_840, 16_384),
97
- ];
98
-
99
- /**
100
- * Adapter that decodes the credential envelope before the shared pipeline
101
- * authenticates the request.
102
- *
103
- * `prepareHeaders` is corrected rather than rebuilt: every other header the
104
- * factory contributes (content type, gateway identity, operator custom headers,
105
- * route user-agent) stays exactly as every other provider gets it.
106
- */
107
- class KiloAdapter extends OpenAICompatibleAdapter {
108
- constructor(fetchImpl?: typeof fetch) {
109
- super(
110
- withBearerAuthentication({
111
- provider_id: KILO_PROVIDER_ID,
112
- base_url: KILO_BASE_URL,
113
- endpoint_paths_by_wire_family: { chat: KILO_ENDPOINT_PATH },
114
- ...(fetchImpl ? { fetchImpl } : {}),
115
- }),
116
- );
117
- }
118
-
119
- protected override async prepareHeaders(
120
- context: ProviderDispatchContext,
121
- request: CanonicalRequest,
122
- candidate: ProviderDispatchTarget,
123
- ): Promise<Record<string, string>> {
124
- const headers = await super.prepareHeaders(context, request, candidate);
125
- const secret = context.credential.secret;
126
- if (secret === undefined || secret.length === 0) return headers;
127
- // A credential that does not decode is left as the factory sent it: the
128
- // request then fails closed at the upstream auth boundary, and the parse
129
- // error belongs to the credential boundary rather than to this hook.
130
- let credential: ReturnType<typeof decodeKiloCredential>;
131
- try {
132
- credential = decodeKiloCredential(secret);
133
- } catch {
134
- return headers;
135
- }
136
- headers.authorization = `Bearer ${credential.accessToken}`;
137
- // The upstream's own header name, not ours: renaming the Cartethyia
138
- // provider id does not rename a field the upstream reads.
139
- if (credential.orgId !== undefined) headers["X-Kilocode-OrganizationID"] = credential.orgId;
140
- return headers;
141
- }
142
- }
143
-
144
- /** Kilo Code provider adapter. */
145
- export const kiloAdapter: ProviderAdapter = new KiloAdapter();
146
-
1
+ /**
2
+ * Kilo Code adapter.
3
+ *
4
+ * Kilo Code resells the OpenRouter catalog behind a bearer device token on an
5
+ * OpenAI-compatible chat surface, so this adapter reuses the shared factory for
6
+ * payload translation, transport, and SSE decoding.
7
+ *
8
+ * One thing sits outside the declarative `ApiKeyProviderSpec`: the stored
9
+ * credential is a JSON envelope (`{ accessToken, orgId }`) because the gateway
10
+ * scopes every request to the account's organization and the console stores one
11
+ * opaque string per account. The factory forwards that string as the bearer
12
+ * verbatim, so the envelope is decoded at the auth boundary here — the same
13
+ * arrangement `kimi/kimi.ts` uses for its own envelope credential.
14
+ *
15
+ * The base URL is the completions path itself, because that is the path Kilo
16
+ * Code publishes (`/api/openrouter/chat/completions`) and it is not derivable
17
+ * from an origin plus a wire-family suffix.
18
+ */
19
+ import { defineModel } from "../../provider-model-definition";
20
+ import { openrouterFreeRoster } from "../../discovery/openrouter-free-roster";
21
+ import type { ModelDefinition } from "../../provider-model-definition";
22
+ import type { ProviderAdapter, ProviderDispatchContext, ProviderDispatchTarget } from "../../provider-contracts";
23
+ import type { CanonicalRequest } from "../../../protocol/canonical-model";
24
+ import { OpenAICompatibleAdapter, withBearerAuthentication } from "../../adapters/compatible-adapter";
25
+ import { providerBaseUrl } from "../../provider-metadata";
26
+ import { decodeKiloCredential } from "../../../security/credential-codec";
27
+
28
+ export const KILO_PROVIDER_ID = "kilo" as const;
29
+ export const KILO_BASE_URL = providerBaseUrl("kilo");
30
+
31
+ /**
32
+ * Endpoint path recorded on this provider's model rows and used by the adapter.
33
+ *
34
+ * The base URL carries Kilo Code's API prefix (`/api/openrouter`), so this is
35
+ * the wire suffix that completes it — the same split Cline uses for
36
+ * `/api/v1` + `/chat/completions`.
37
+ */
38
+ export const KILO_ENDPOINT_PATH = "/chat/completions" as const;
39
+
40
+ interface KiloModelOptions {
41
+ readonly vision?: boolean;
42
+ readonly document?: boolean;
43
+ readonly audio?: boolean;
44
+ readonly reasoning?: boolean;
45
+ readonly toolCall?: boolean;
46
+ }
47
+
48
+ function kiloModel(
49
+ modelId: string,
50
+ contextLimit: number,
51
+ outputLimit: number,
52
+ options: KiloModelOptions = {},
53
+ ): ModelDefinition {
54
+ return defineModel({
55
+ id: modelId,
56
+ providerId: KILO_PROVIDER_ID,
57
+ wireFamily: "chat",
58
+ endpoint: KILO_ENDPOINT_PATH,
59
+ ctx: contextLimit,
60
+ out: outputLimit,
61
+ vision: options.vision ?? false,
62
+ document: options.document ?? false,
63
+ audio: options.audio ?? false,
64
+ reasoning: options.reasoning ?? false,
65
+ toolCall: options.toolCall ?? true,
66
+ });
67
+ }
68
+
69
+ /**
70
+ * Static fallback catalog, read from the live `/api/gateway/models` directory.
71
+ *
72
+ * Live discovery replaces this list whenever an account is available, so these
73
+ * rows are the offline floor: the gateway's own routing aliases plus one
74
+ * current model per family it resells. Limits and capability come from the
75
+ * directory entry's own `top_provider` / `architecture` /
76
+ * `supported_parameters` fields rather than from the base catalog, which prices
77
+ * the underlying model and not this reseller's serving.
78
+ */
79
+ export const KILO_MODELS: readonly ModelDefinition[] = [
80
+ // Three routers, and nothing else. A committed catalog of specific ids was a
81
+ // snapshot of one afternoon: this provider resells the OpenRouter catalog,
82
+ // which adds and pulls models within days, so discovery is the authority and
83
+ // every hand-kept row outside these drifts out of truth.
84
+ //
85
+ // `kilo-auto/free` bills zero and `kilo-auto/small` bills a fraction of a
86
+ // cent; both route on the provider's own side, so their limits are the
87
+ // window the router may select into rather than one model's.
88
+ kiloModel("kilo-auto/free", 256_000, 32_768, { reasoning: true }),
89
+ kiloModel("kilo-auto/small", 262_144, 32_768, { vision: true, reasoning: true }),
90
+ kiloModel("openrouter/auto", 2_000_000, 128_000, { reasoning: true }),
91
+ ];
92
+
93
+ /**
94
+ * The shared free roster, spelled for this provider's endpoint.
95
+ *
96
+ * The same 17 `:free` ids Cline and OpenRouter serve, because this is the same
97
+ * catalog behind a different origin. Kept separate from `KILO_MODELS` so the
98
+ * free tier is its own statement: those three rows are routers, these are the
99
+ * zero-cost models, and the model list groups them differently.
100
+ */
101
+ export const KILO_FREE_MODELS: readonly ModelDefinition[] = openrouterFreeRoster({
102
+ providerId: KILO_PROVIDER_ID,
103
+ endpoint: KILO_ENDPOINT_PATH,
104
+ });
105
+
106
+ /**
107
+ * Adapter that decodes the credential envelope before the shared pipeline
108
+ * authenticates the request.
109
+ *
110
+ * `prepareHeaders` is corrected rather than rebuilt: every other header the
111
+ * factory contributes (content type, gateway identity, operator custom headers,
112
+ * route user-agent) stays exactly as every other provider gets it.
113
+ */
114
+ class KiloAdapter extends OpenAICompatibleAdapter {
115
+ constructor(fetchImpl?: typeof fetch) {
116
+ super(
117
+ withBearerAuthentication({
118
+ provider_id: KILO_PROVIDER_ID,
119
+ base_url: KILO_BASE_URL,
120
+ endpoint_paths_by_wire_family: { chat: KILO_ENDPOINT_PATH },
121
+ ...(fetchImpl ? { fetchImpl } : {}),
122
+ }),
123
+ );
124
+ }
125
+
126
+ protected override async prepareHeaders(
127
+ context: ProviderDispatchContext,
128
+ request: CanonicalRequest,
129
+ candidate: ProviderDispatchTarget,
130
+ ): Promise<Record<string, string>> {
131
+ const headers = await super.prepareHeaders(context, request, candidate);
132
+ const secret = context.credential.secret;
133
+ if (secret === undefined || secret.length === 0) return headers;
134
+ // A credential that does not decode is left as the factory sent it: the
135
+ // request then fails closed at the upstream auth boundary, and the parse
136
+ // error belongs to the credential boundary rather than to this hook.
137
+ let credential: ReturnType<typeof decodeKiloCredential>;
138
+ try {
139
+ credential = decodeKiloCredential(secret);
140
+ } catch {
141
+ return headers;
142
+ }
143
+ headers.authorization = `Bearer ${credential.accessToken}`;
144
+ // The upstream's own header name, not ours: renaming the Cartethyia
145
+ // provider id does not rename a field the upstream reads.
146
+ if (credential.orgId !== undefined) headers["X-Kilocode-OrganizationID"] = credential.orgId;
147
+ return headers;
148
+ }
149
+ }
150
+
151
+ /** Kilo Code provider adapter. */
152
+ export const kiloAdapter: ProviderAdapter = new KiloAdapter();
153
+
@@ -0,0 +1,130 @@
1
+ import {
2
+ getJson,
3
+ type FetchLike,
4
+ type ProviderQuotaResult,
5
+ type ProviderQuotaWindow,
6
+ } from "../../quota/quota-contracts";
7
+ import type { QuotaCollectionContext } from "../../quota/quota-support";
8
+
9
+ const SOURCE = "opencode-go";
10
+
11
+ /**
12
+ * The Go plan's `/v1/usage` answer.
13
+ *
14
+ * `usage` carries exactly three windows in the reference implementation —
15
+ * `rolling`, `weekly`, `monthly` — each with a `percent` and a `resetsAt`.
16
+ * The shape is read defensively: an unknown window name is still reported
17
+ * rather than dropped, since a new window is more useful to an operator than
18
+ * a silently narrower view.
19
+ */
20
+ interface GoUsageWindow {
21
+ readonly percent?: number | null;
22
+ readonly resetsAt?: string | null;
23
+ readonly status?: string | null;
24
+ }
25
+
26
+ interface GoUsagePayload {
27
+ readonly usage?: Readonly<Record<string, GoUsageWindow | undefined>> | null;
28
+ readonly plan?: string | null;
29
+ }
30
+
31
+ /** Windows whose meaning the reference names, in the order it lists them. */
32
+ const KNOWN_WINDOWS: readonly (readonly [string, string])[] = [
33
+ ["rolling", "Rolling"],
34
+ ["weekly", "Weekly"],
35
+ ["monthly", "Monthly"],
36
+ ];
37
+
38
+ function labelFor(kind: string): string {
39
+ for (const [name, label] of KNOWN_WINDOWS) {
40
+ if (name === kind) return label;
41
+ }
42
+ return kind.charAt(0).toUpperCase() + kind.slice(1);
43
+ }
44
+
45
+ function resetIso(value: string | null | undefined): string | null {
46
+ if (typeof value !== "string" || value.trim() === "") return null;
47
+ const parsed = Date.parse(value);
48
+ if (!Number.isFinite(parsed)) return null;
49
+ return new Date(parsed).toISOString();
50
+ }
51
+
52
+ /**
53
+ * One window, or `undefined` when the upstream omitted what makes it usable.
54
+ *
55
+ * A window with no percentage is not a zero-percent window — it is an absent
56
+ * measurement, and reporting it as `0` would tell the operator the plan is
57
+ * exhausted when the upstream simply did not say.
58
+ */
59
+ function windowFor(
60
+ kind: string,
61
+ raw: GoUsageWindow | undefined,
62
+ ): ProviderQuotaWindow | undefined {
63
+ if (!raw) return undefined;
64
+ const percent = typeof raw.percent === "number" && Number.isFinite(raw.percent)
65
+ ? Math.min(100, Math.max(0, raw.percent))
66
+ : null;
67
+ if (percent === null) return undefined;
68
+ return {
69
+ kind,
70
+ label: labelFor(kind),
71
+ // The endpoint reports subscription-wide percentages, never per-key or
72
+ // per-model balances. Every window of one subscription reads the same
73
+ // budget, so adding them would double-count: they are independent, and
74
+ // the lowest gates the account.
75
+ accounting: "independent",
76
+ usedPercent: percent,
77
+ remainingPercent: 100 - percent,
78
+ resetsAt: resetIso(raw.resetsAt),
79
+ };
80
+ }
81
+
82
+ function parseWindows(payload: GoUsagePayload): readonly ProviderQuotaWindow[] {
83
+ const usage = payload.usage;
84
+ if (!usage) return [];
85
+ const windows: ProviderQuotaWindow[] = [];
86
+ const seen = new Set<string>();
87
+ // Known windows first, in their documented order, so the dashboard is
88
+ // stable across refreshes; anything novel is appended.
89
+ for (const [name] of KNOWN_WINDOWS) {
90
+ seen.add(name);
91
+ const window = windowFor(name, usage[name]);
92
+ if (window) windows.push(window);
93
+ }
94
+ for (const [name, raw] of Object.entries(usage)) {
95
+ if (seen.has(name)) continue;
96
+ const window = windowFor(name, raw);
97
+ if (window) windows.push(window);
98
+ }
99
+ return windows;
100
+ }
101
+
102
+ /**
103
+ * Fetches the OpenCode Go plan's subscription quota from `/v1/usage`.
104
+ *
105
+ * The anonymous free tier has no usage surface — it is rate-limited by egress
106
+ * IP, not by an account balance — so this is the keyed `opencode-go` tier
107
+ * only. The endpoint reports percentages for a *shared* subscription: several
108
+ * Go keys can draw on one plan, so no window here may be summed against
109
+ * another account's.
110
+ */
111
+ export async function fetchOpenCodeGoQuota(
112
+ credential: string,
113
+ fetcher: FetchLike,
114
+ _context?: QuotaCollectionContext,
115
+ ): Promise<ProviderQuotaResult> {
116
+ const token = credential.trim();
117
+ const payload = (await getJson(
118
+ `https://opencode.ai/zen/go/v1/usage`,
119
+ {
120
+ authorization: `Bearer ${token}`,
121
+ accept: "application/json",
122
+ "x-opencode-client": "cli",
123
+ },
124
+ fetcher,
125
+ )) as GoUsagePayload;
126
+ const windows = parseWindows(payload);
127
+ const plan =
128
+ (typeof payload.plan === "string" && payload.plan.trim()) || "OpenCode Go";
129
+ return { source: SOURCE, plan, windows, error: null };
130
+ }