cartethyia 2.8.0 → 2.8.1

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 (348) hide show
  1. package/.env.example +3 -3
  2. package/dist/dashboard/assets/{BannedPage-Cc0vKpMG.js → BannedPage-Dq530awD.js} +1 -1
  3. package/dist/dashboard/assets/BannedPage-Dq530awD.js.gz +0 -0
  4. package/dist/dashboard/assets/{CliToolDetailPage-Bqj2aa1T.js → CliToolDetailPage-DZzaS-7S.js} +1 -1
  5. package/dist/dashboard/assets/CliToolDetailPage-DZzaS-7S.js.gz +0 -0
  6. package/dist/dashboard/assets/{CliToolsPage-CXsaOAO2.js → CliToolsPage-DaZZ3cqP.js} +1 -1
  7. package/dist/dashboard/assets/CliToolsPage-DaZZ3cqP.js.gz +0 -0
  8. package/dist/dashboard/assets/{CombosPage-BeLpJ4ma.js → CombosPage-BlC_xdkX.js} +1 -1
  9. package/dist/dashboard/assets/CombosPage-BlC_xdkX.js.gz +0 -0
  10. package/dist/dashboard/assets/{ConsoleLogPage-DnV0uZ3m.js → ConsoleLogPage-D-rqeVtG.js} +1 -1
  11. package/dist/dashboard/assets/ConsoleLogPage-D-rqeVtG.js.gz +0 -0
  12. package/dist/dashboard/assets/{CustomizationPage-CBxAjo63.js → CustomizationPage-7xT5yg2E.js} +1 -1
  13. package/dist/dashboard/assets/CustomizationPage-7xT5yg2E.js.gz +0 -0
  14. package/dist/dashboard/assets/{HealthEventsModal-B5yEE0k6.js → HealthEventsModal-Clq8E9cW.js} +1 -1
  15. package/dist/dashboard/assets/HealthEventsModal-Clq8E9cW.js.gz +0 -0
  16. package/dist/dashboard/assets/{InjectSystemPromptPanel-BWFLECmz.js → InjectSystemPromptPanel-6Teoq9Se.js} +1 -1
  17. package/dist/dashboard/assets/InjectSystemPromptPanel-6Teoq9Se.js.gz +0 -0
  18. package/dist/dashboard/assets/{LoginPage-CgoPc5B9.js → LoginPage-CZuI0MAR.js} +1 -1
  19. package/dist/dashboard/assets/LoginPage-CZuI0MAR.js.gz +0 -0
  20. package/dist/dashboard/assets/{ModelPicker-D9bFQern.js → ModelPicker-C1hNTlkr.js} +1 -1
  21. package/dist/dashboard/assets/ModelPicker-C1hNTlkr.js.gz +0 -0
  22. package/dist/dashboard/assets/{OverviewPage-B_p4tL8k.js → OverviewPage-0yfhSI1C.js} +1 -1
  23. package/dist/dashboard/assets/OverviewPage-0yfhSI1C.js.gz +0 -0
  24. package/dist/dashboard/assets/ProviderDetailPage-xqTxdQ4c.js +8 -0
  25. package/dist/dashboard/assets/ProviderDetailPage-xqTxdQ4c.js.gz +0 -0
  26. package/dist/dashboard/assets/{ProviderIcon-D_0PiZtg.js → ProviderIcon-Ddhm1InL.js} +1 -1
  27. package/dist/dashboard/assets/ProviderIcon-Ddhm1InL.js.gz +0 -0
  28. package/dist/dashboard/assets/{ProvidersPage-CLI2bJTK.js → ProvidersPage-C3fYuu6i.js} +1 -1
  29. package/dist/dashboard/assets/ProvidersPage-C3fYuu6i.js.gz +0 -0
  30. package/dist/dashboard/assets/ProxyPage-CHtJtZ3u.js +9 -0
  31. package/dist/dashboard/assets/ProxyPage-CHtJtZ3u.js.gz +0 -0
  32. package/dist/dashboard/assets/{QuotaPage-DA-a1iSN.js → QuotaPage-D1RV_2BX.js} +1 -1
  33. package/dist/dashboard/assets/QuotaPage-D1RV_2BX.js.gz +0 -0
  34. package/dist/dashboard/assets/{SettingsPage-CctTga2C.js → SettingsPage-BzZAvYSX.js} +1 -1
  35. package/dist/dashboard/assets/SettingsPage-BzZAvYSX.js.gz +0 -0
  36. package/dist/dashboard/assets/{SetupPage-febLU4r1.js → SetupPage--s-EfEIL.js} +1 -1
  37. package/dist/dashboard/assets/SetupPage--s-EfEIL.js.gz +0 -0
  38. package/dist/dashboard/assets/{StudioPage-M6fvR5Wz.js → StudioPage-BjXFGSK4.js} +1 -1
  39. package/dist/dashboard/assets/StudioPage-BjXFGSK4.js.gz +0 -0
  40. package/dist/dashboard/assets/{UsagePage-nyeuRqz9.js → UsagePage-CP8F8BN7.js} +1 -1
  41. package/dist/dashboard/assets/UsagePage-CP8F8BN7.js.gz +0 -0
  42. package/dist/dashboard/assets/{api-keys-BFOlvrJC.js → api-keys-2hc12Uz2.js} +1 -1
  43. package/dist/dashboard/assets/api-keys-2hc12Uz2.js.gz +0 -0
  44. package/dist/dashboard/assets/app-DGXbNfAR.css +2 -0
  45. package/dist/dashboard/assets/app-DGXbNfAR.css.gz +0 -0
  46. package/dist/dashboard/assets/{assert-CqTLw5e7.js → assert-BMcj1xZE.js} +1 -1
  47. package/dist/dashboard/assets/assert-BMcj1xZE.js.gz +0 -0
  48. package/dist/dashboard/assets/{badge-C83EqLB0.js → badge-DkRUuVfz.js} +1 -1
  49. package/dist/dashboard/assets/badge-DkRUuVfz.js.gz +0 -0
  50. package/dist/dashboard/assets/{banner-D1xn7pIe.js → banner-CDjW841Q.js} +1 -1
  51. package/dist/dashboard/assets/banner-CDjW841Q.js.gz +0 -0
  52. package/dist/dashboard/assets/{card-DU3Lq5Lm.js → card-Bto5UlL9.js} +1 -1
  53. package/dist/dashboard/assets/card-Bto5UlL9.js.gz +0 -0
  54. package/dist/dashboard/assets/{cli-tools-Dw1U_drK.js → cli-tools-DaH6g9hL.js} +1 -1
  55. package/dist/dashboard/assets/cli-tools-DaH6g9hL.js.gz +0 -0
  56. package/dist/dashboard/assets/{clipboard-button-CEL5Sg_J.js → clipboard-button-BYKBCzjk.js} +1 -1
  57. package/dist/dashboard/assets/clipboard-button-BYKBCzjk.js.gz +0 -0
  58. package/dist/dashboard/assets/{dialog-BjFR5UHy.js → dialog-DL0Zftwv.js} +1 -1
  59. package/dist/dashboard/assets/dialog-DL0Zftwv.js.gz +0 -0
  60. package/dist/dashboard/assets/{drawer-HvBW0AjI.js → drawer-Dpx_UXaS.js} +1 -1
  61. package/dist/dashboard/assets/drawer-Dpx_UXaS.js.gz +0 -0
  62. package/dist/dashboard/assets/{entry-CECVELyy.js → entry-BV7-1NoM.js} +1 -1
  63. package/dist/dashboard/assets/entry-BV7-1NoM.js.gz +0 -0
  64. package/dist/dashboard/assets/{entry-DYYofQ7W.js → entry-CGvdNU6r.js} +1 -1
  65. package/dist/dashboard/assets/entry-CGvdNU6r.js.gz +0 -0
  66. package/dist/dashboard/assets/{entry-BSu3gFlt.js → entry-DScKYvZj.js} +3 -3
  67. package/dist/dashboard/assets/entry-DScKYvZj.js.gz +0 -0
  68. package/dist/dashboard/assets/{formatters-DLW4i8zK.js → formatters-BS3DZlZj.js} +1 -1
  69. package/dist/dashboard/assets/formatters-BS3DZlZj.js.gz +0 -0
  70. package/dist/dashboard/assets/{index-1-fCqe64.js → index-SQnvvTWX.js} +2 -2
  71. package/dist/dashboard/assets/index-SQnvvTWX.js.gz +0 -0
  72. package/dist/dashboard/assets/{inline-DGvU2oLK.js → inline-Dl-cuLK0.js} +1 -1
  73. package/dist/dashboard/assets/inline-Dl-cuLK0.js.gz +0 -0
  74. package/dist/dashboard/assets/{input-iNnO1X2K.js → input-Bfx0EzRc.js} +1 -1
  75. package/dist/dashboard/assets/input-Bfx0EzRc.js.gz +0 -0
  76. package/dist/dashboard/assets/{layout-0q8UGypb.js → layout-BxhbQ_JS.js} +1 -1
  77. package/dist/dashboard/assets/layout-BxhbQ_JS.js.gz +0 -0
  78. package/dist/dashboard/assets/{list-row-C0w2bQjJ.js → list-row-D49Y4ptn.js} +1 -1
  79. package/dist/dashboard/assets/list-row-D49Y4ptn.js.gz +0 -0
  80. package/dist/dashboard/assets/{live-M5aJ_xCa.js → live-CbVTdX9V.js} +1 -1
  81. package/dist/dashboard/assets/live-CbVTdX9V.js.gz +0 -0
  82. package/dist/dashboard/assets/{network-BKeQGT3K.js → network-JGvDveof.js} +1 -1
  83. package/dist/dashboard/assets/network-JGvDveof.js.gz +0 -0
  84. package/dist/dashboard/assets/{numbers-CivAk3da.js → numbers-Dw6kiew-.js} +1 -1
  85. package/dist/dashboard/assets/numbers-Dw6kiew-.js.gz +0 -0
  86. package/dist/dashboard/assets/{pagination-CpzvI5ep.js → pagination-iUoI8GeE.js} +1 -1
  87. package/dist/dashboard/assets/pagination-iUoI8GeE.js.gz +0 -0
  88. package/dist/dashboard/assets/providers/sensenova-intl.png +0 -0
  89. package/dist/dashboard/assets/providers/sensenova.png +0 -0
  90. package/dist/dashboard/assets/{routing-BFQX2VBc.js → routing-8jZr-3WE.js} +1 -1
  91. package/dist/dashboard/assets/routing-8jZr-3WE.js.gz +0 -0
  92. package/dist/dashboard/assets/{select-CXbck0jG.js → select-oO1FxMVb.js} +1 -1
  93. package/dist/dashboard/assets/select-oO1FxMVb.js.gz +0 -0
  94. package/dist/dashboard/assets/{settings-C_XvMHh9.js → settings-CLr3kdIx.js} +1 -1
  95. package/dist/dashboard/assets/settings-CLr3kdIx.js.gz +0 -0
  96. package/dist/dashboard/assets/{stack-DggRiCxE.js → stack-Y3pDteZr.js} +1 -1
  97. package/dist/dashboard/assets/stack-Y3pDteZr.js.gz +0 -0
  98. package/dist/dashboard/assets/{state-ClFzfbYp.js → state-CArX_Iak.js} +1 -1
  99. package/dist/dashboard/assets/state-CArX_Iak.js.gz +0 -0
  100. package/dist/dashboard/assets/{switch-CTIFxKqS.js → switch-DwlwmDO-.js} +1 -1
  101. package/dist/dashboard/assets/switch-DwlwmDO-.js.gz +0 -0
  102. package/dist/dashboard/assets/{useMutation-BClG3yWj.js → useMutation-DJ9GYEgf.js} +1 -1
  103. package/dist/dashboard/assets/useMutation-DJ9GYEgf.js.gz +0 -0
  104. package/dist/dashboard/index.html +2 -2
  105. package/dist/dashboard/index.html.gz +0 -0
  106. package/dist/dashboard/precompressed-assets.json +51 -51
  107. package/migrations/full-postgres/0047_add_provider_device_flow_proxy.sql +17 -0
  108. package/migrations/lite-sqlite3/0047_add_provider_device_flow_proxy.sql +19 -0
  109. package/package.json +1 -1
  110. package/src/boot/app.ts +1 -1
  111. package/src/boot/dependencies.ts +4 -6
  112. package/src/config/providers.ts +6 -5
  113. package/src/config/spec.ts +8 -8
  114. package/src/console/backup/nine-router.ts +71 -10
  115. package/src/console/backup/service.ts +8 -1
  116. package/src/console/console-router.ts +1 -1
  117. package/src/console/domain-registration.ts +7 -2
  118. package/src/console/inferhub/client.ts +1 -1
  119. package/src/console/observability/live.ts +2 -2
  120. package/src/console/providers/catalog/contracts.ts +9 -3
  121. package/src/console/providers/catalog/model-operations.ts +2 -3
  122. package/src/console/providers/catalog/provider-operations.ts +1 -1
  123. package/src/console/providers/catalog/routes.ts +2 -2
  124. package/src/console/providers/catalog/store.ts +1914 -1907
  125. package/src/console/providers/detail/routes.ts +1 -0
  126. package/src/console/providers/detail/store.ts +4 -0
  127. package/src/console/providers/oauth/callback-listener.ts +30 -11
  128. package/src/console/providers/oauth/device-egress.ts +123 -0
  129. package/src/console/providers/oauth/routes.ts +123 -16
  130. package/src/console/quota/account-quota-tenant.ts +5 -5
  131. package/src/console/quota/account-test-egress.ts +2 -2
  132. package/src/console/quota/daily-growth-job.ts +1 -1
  133. package/src/console/routing/pools/contracts.ts +1 -1
  134. package/src/console/routing/pools/operations.ts +1 -1
  135. package/src/console/routing/pools/probe-verdict.ts +2 -2
  136. package/src/console/routing/pools/relay-deploy.ts +1 -1
  137. package/src/console/routing/pools/store.ts +4 -4
  138. package/src/network/client.ts +67 -0
  139. package/src/network/egress/bidi-session.ts +322 -0
  140. package/src/network/egress/dial.ts +201 -0
  141. package/src/network/egress/factory.ts +191 -0
  142. package/src/network/{outbound-fetch.ts → egress/fetch.ts} +195 -29
  143. package/src/network/egress/tls-profile.ts +123 -0
  144. package/src/network/egress/ws.ts +175 -0
  145. package/src/network/{types.ts → pool/agent-config.ts} +1 -1
  146. package/src/network/pool/agent.ts +2 -2
  147. package/src/network/{pool-cooldown-store.ts → pool/cooldown-store.ts} +7 -7
  148. package/src/network/{pool-health-machine.ts → pool/health.ts} +205 -6
  149. package/src/network/pool/resolver.ts +10 -849
  150. package/src/network/pool/selector.ts +2 -2
  151. package/src/network/ssrf.ts +1 -1
  152. package/src/network/{retry.ts → util/retry.ts} +1 -1
  153. package/src/observability/telemetry-buffer.ts +1 -1
  154. package/src/persistence/schema.ts +9 -0
  155. package/src/persistence/ttl-cache.ts +1 -1
  156. package/src/protocol/codecs.ts +58 -1
  157. package/src/protocol/request/messages.ts +31 -18
  158. package/src/protocol/response/messages.ts +34 -7
  159. package/src/protocol/translation/quirks.ts +15 -0
  160. package/src/protocol/upstream/send-claude-messages.ts +2 -2
  161. package/src/providers/adapters/compatible-adapter.ts +5 -0
  162. package/src/providers/authentication/oauth-client.ts +40 -6
  163. package/src/providers/authentication/oauth-device-flow.ts +7 -3
  164. package/src/providers/authentication/oauth-flow-store.ts +82 -1
  165. package/src/providers/authentication/oauth-refresh-service.ts +766 -739
  166. package/src/providers/default-registry.ts +76 -0
  167. package/src/providers/discovery/discovery-types.ts +7 -0
  168. package/src/providers/discovery/probe-phases.ts +6 -2
  169. package/src/providers/discovery/probing-service.ts +7 -0
  170. package/src/providers/integrations/antigravity/antigravity-protocol.ts +11 -0
  171. package/src/providers/integrations/buddy/account.ts +969 -0
  172. package/src/providers/integrations/buddy/capabilities.ts +10 -10
  173. package/src/providers/integrations/buddy/{buddy-catalog-shared.ts → catalog.ts} +198 -136
  174. package/src/providers/integrations/buddy/{buddy-chat-shared.ts → chat.ts} +5 -5
  175. package/src/providers/integrations/buddy/codebuddy/index.ts +429 -0
  176. package/src/providers/integrations/buddy/codebuddy/shared.ts +4 -4
  177. package/src/providers/integrations/buddy/{buddy-identity.ts → headers.ts} +138 -140
  178. package/src/providers/integrations/buddy/lifecycle.ts +1018 -0
  179. package/src/providers/integrations/buddy/{buddy-media.ts → media.ts} +1 -1
  180. package/src/providers/integrations/cline/cline-oauth.ts +10 -5
  181. package/src/providers/integrations/cline/cline.ts +3 -4
  182. package/src/providers/integrations/clixad/clixad-oauth.ts +98 -0
  183. package/src/providers/integrations/clixad/clixad-quota.ts +132 -0
  184. package/src/providers/integrations/clixad/provider.ts +145 -0
  185. package/src/providers/integrations/codex/codex-oauth.ts +8 -5
  186. package/src/providers/integrations/cursor/cursor-auth.ts +1 -1
  187. package/src/providers/integrations/cursor/cursor-hardening.ts +279 -0
  188. package/src/providers/integrations/cursor/cursor-http2.ts +605 -6
  189. package/src/providers/integrations/cursor/cursor-shared.ts +1 -1
  190. package/src/providers/integrations/cursor/cursor.ts +485 -70
  191. package/src/providers/integrations/deepai/deepai-catalog.ts +149 -0
  192. package/src/providers/integrations/deepai/deepai-common.ts +145 -0
  193. package/src/providers/integrations/deepai/deepai-oauth.ts +129 -0
  194. package/src/providers/integrations/deepai/deepai-quota.ts +97 -0
  195. package/src/providers/integrations/deepai/provider.ts +42 -0
  196. package/src/providers/integrations/devin/devin-auth.ts +7 -0
  197. package/src/providers/integrations/factory/factory-oauth.ts +16 -7
  198. package/src/providers/integrations/freebuff/freebuff.ts +2 -2
  199. package/src/providers/integrations/freepi/freepi-catalog.ts +5 -0
  200. package/src/providers/integrations/freepi/freepi-discovery.ts +2 -2
  201. package/src/providers/integrations/freepi/freepi-headers.ts +2 -2
  202. package/src/providers/integrations/freepi/freepi-protocol.ts +11 -2
  203. package/src/providers/integrations/freepi/freepi-realm.ts +0 -3
  204. package/src/providers/integrations/freepi/freepi-session.ts +158 -0
  205. package/src/providers/integrations/freepi/freepi.ts +80 -54
  206. package/src/providers/integrations/github/github-discovery.ts +30 -13
  207. package/src/providers/integrations/github/github-oauth.ts +217 -44
  208. package/src/providers/integrations/github/github-quota.ts +22 -5
  209. package/src/providers/integrations/github/github.ts +40 -32
  210. package/src/providers/integrations/grok/grok-oauth.ts +4 -4
  211. package/src/providers/integrations/hermes/hermes-oauth.ts +3 -3
  212. package/src/providers/integrations/hermes/hermes.ts +34 -5
  213. package/src/providers/integrations/kilo/kilo-oauth.ts +4 -4
  214. package/src/providers/integrations/kilo/kilo.ts +1 -1
  215. package/src/providers/integrations/kimi/kimi-oauth.ts +3 -3
  216. package/src/providers/integrations/kiro/kiro-oauth.ts +2 -2
  217. package/src/providers/integrations/muse/muse-oauth.ts +5 -5
  218. package/src/providers/integrations/opencode/fingerprint.ts +1 -1
  219. package/src/providers/integrations/openrouter/provider.ts +1 -1
  220. package/src/providers/integrations/perch/perch-protocol.ts +0 -3
  221. package/src/providers/integrations/perch/perch.ts +3 -3
  222. package/src/providers/integrations/qoder/claim-qoder-credits.ts +1 -1
  223. package/src/providers/integrations/qoder/qoder-adapter.ts +19 -113
  224. package/src/providers/integrations/qoder/qoder-auth.ts +8 -1
  225. package/src/providers/integrations/qoder/qoder-catalog.ts +1 -1
  226. package/src/providers/integrations/qoder/qoder-chat.ts +25 -8
  227. package/src/providers/integrations/qoder/qoder-checkin.ts +1 -1
  228. package/src/providers/integrations/qoder/qoder-cosy.ts +37 -9
  229. package/src/providers/integrations/qoder/qoder-oauth.ts +9 -2
  230. package/src/providers/integrations/qoder/qoder-realm.ts +13 -36
  231. package/src/providers/integrations/qoder/qoder-sse.ts +447 -68
  232. package/src/providers/integrations/qoder/qoder-types.ts +9 -0
  233. package/src/providers/integrations/qoder/qoder.ts +3 -25
  234. package/src/providers/integrations/sensenova/provider.ts +144 -0
  235. package/src/providers/integrations/trae/trae-quota.ts +15 -1
  236. package/src/providers/integrations/vercel/provider.ts +117 -0
  237. package/src/providers/integrations/vercel/vercel-quota.ts +96 -0
  238. package/src/providers/integrations/xai/xai-oauth.ts +5 -5
  239. package/src/providers/integrations/zcode-start-plan/gifts.ts +1 -1
  240. package/src/providers/integrations/zcode-start-plan/oauth.ts +3 -3
  241. package/src/providers/integrations/zro/zro.ts +2 -1
  242. package/src/providers/operations/account-refresh-status.ts +14 -0
  243. package/src/providers/operations/client-versions.ts +95 -30
  244. package/src/providers/operations/oauth-refresh-lead.ts +46 -22
  245. package/src/providers/operations/provider-caches.ts +1 -1
  246. package/src/providers/operations/provider-credential-service.ts +22 -25
  247. package/src/providers/operations/session-resolution.ts +17 -1
  248. package/src/providers/provider-contracts.ts +2 -2
  249. package/src/providers/provider-metadata.ts +30 -0
  250. package/src/providers/quota/quota-contracts.ts +2 -0
  251. package/src/providers/quota/refresh.ts +25 -3
  252. package/src/security/ip-boundary.ts +1 -1
  253. package/src/transport/dispatch/attempt-finalize.ts +1 -1
  254. package/src/transport/dispatch/attempt-loop.ts +3 -3
  255. package/src/transport/dispatch/handler-deps.ts +1 -1
  256. package/src/transport/dispatch/leases.ts +1 -1
  257. package/src/transport/dispatch/retry-policy.ts +1 -1
  258. package/src/transport/dispatch/streaming/finalize.ts +2 -2
  259. package/src/transport/dispatch/streaming/stream.ts +1 -1
  260. package/src/transport/dispatch/upstream.ts +1 -1
  261. package/src/transport/shutdown-notice.ts +1 -1
  262. package/src/workers/buddy-growth-tasks.ts +8 -8
  263. package/src/workers/daily-checkin.ts +4 -4
  264. package/src/workers/quota-refresh-sweep.ts +1 -1
  265. package/src/workers/zcode-gift-claim.ts +1 -1
  266. package/dist/dashboard/assets/BannedPage-Cc0vKpMG.js.gz +0 -0
  267. package/dist/dashboard/assets/CliToolDetailPage-Bqj2aa1T.js.gz +0 -0
  268. package/dist/dashboard/assets/CliToolsPage-CXsaOAO2.js.gz +0 -0
  269. package/dist/dashboard/assets/CombosPage-BeLpJ4ma.js.gz +0 -0
  270. package/dist/dashboard/assets/ConsoleLogPage-DnV0uZ3m.js.gz +0 -0
  271. package/dist/dashboard/assets/CustomizationPage-CBxAjo63.js.gz +0 -0
  272. package/dist/dashboard/assets/HealthEventsModal-B5yEE0k6.js.gz +0 -0
  273. package/dist/dashboard/assets/InjectSystemPromptPanel-BWFLECmz.js.gz +0 -0
  274. package/dist/dashboard/assets/LoginPage-CgoPc5B9.js.gz +0 -0
  275. package/dist/dashboard/assets/ModelPicker-D9bFQern.js.gz +0 -0
  276. package/dist/dashboard/assets/OverviewPage-B_p4tL8k.js.gz +0 -0
  277. package/dist/dashboard/assets/ProviderDetailPage-rs5E2rxv.js +0 -8
  278. package/dist/dashboard/assets/ProviderDetailPage-rs5E2rxv.js.gz +0 -0
  279. package/dist/dashboard/assets/ProviderIcon-D_0PiZtg.js.gz +0 -0
  280. package/dist/dashboard/assets/ProvidersPage-CLI2bJTK.js.gz +0 -0
  281. package/dist/dashboard/assets/ProxyPage-BwNC_-Cx.js +0 -9
  282. package/dist/dashboard/assets/ProxyPage-BwNC_-Cx.js.gz +0 -0
  283. package/dist/dashboard/assets/QuotaPage-DA-a1iSN.js.gz +0 -0
  284. package/dist/dashboard/assets/SettingsPage-CctTga2C.js.gz +0 -0
  285. package/dist/dashboard/assets/SetupPage-febLU4r1.js.gz +0 -0
  286. package/dist/dashboard/assets/StudioPage-M6fvR5Wz.js.gz +0 -0
  287. package/dist/dashboard/assets/UsagePage-nyeuRqz9.js.gz +0 -0
  288. package/dist/dashboard/assets/api-keys-BFOlvrJC.js.gz +0 -0
  289. package/dist/dashboard/assets/app-Dx2QgsNj.css +0 -2
  290. package/dist/dashboard/assets/app-Dx2QgsNj.css.gz +0 -0
  291. package/dist/dashboard/assets/assert-CqTLw5e7.js.gz +0 -0
  292. package/dist/dashboard/assets/badge-C83EqLB0.js.gz +0 -0
  293. package/dist/dashboard/assets/banner-D1xn7pIe.js.gz +0 -0
  294. package/dist/dashboard/assets/card-DU3Lq5Lm.js.gz +0 -0
  295. package/dist/dashboard/assets/cli-tools-Dw1U_drK.js.gz +0 -0
  296. package/dist/dashboard/assets/clipboard-button-CEL5Sg_J.js.gz +0 -0
  297. package/dist/dashboard/assets/dialog-BjFR5UHy.js.gz +0 -0
  298. package/dist/dashboard/assets/drawer-HvBW0AjI.js.gz +0 -0
  299. package/dist/dashboard/assets/entry-BSu3gFlt.js.gz +0 -0
  300. package/dist/dashboard/assets/entry-CECVELyy.js.gz +0 -0
  301. package/dist/dashboard/assets/entry-DYYofQ7W.js.gz +0 -0
  302. package/dist/dashboard/assets/formatters-DLW4i8zK.js.gz +0 -0
  303. package/dist/dashboard/assets/index-1-fCqe64.js.gz +0 -0
  304. package/dist/dashboard/assets/inline-DGvU2oLK.js.gz +0 -0
  305. package/dist/dashboard/assets/input-iNnO1X2K.js.gz +0 -0
  306. package/dist/dashboard/assets/layout-0q8UGypb.js.gz +0 -0
  307. package/dist/dashboard/assets/list-row-C0w2bQjJ.js.gz +0 -0
  308. package/dist/dashboard/assets/live-M5aJ_xCa.js.gz +0 -0
  309. package/dist/dashboard/assets/network-BKeQGT3K.js.gz +0 -0
  310. package/dist/dashboard/assets/numbers-CivAk3da.js.gz +0 -0
  311. package/dist/dashboard/assets/pagination-CpzvI5ep.js.gz +0 -0
  312. package/dist/dashboard/assets/routing-BFQX2VBc.js.gz +0 -0
  313. package/dist/dashboard/assets/select-CXbck0jG.js.gz +0 -0
  314. package/dist/dashboard/assets/settings-C_XvMHh9.js.gz +0 -0
  315. package/dist/dashboard/assets/stack-DggRiCxE.js.gz +0 -0
  316. package/dist/dashboard/assets/state-ClFzfbYp.js.gz +0 -0
  317. package/dist/dashboard/assets/switch-CTIFxKqS.js.gz +0 -0
  318. package/dist/dashboard/assets/useMutation-BClG3yWj.js.gz +0 -0
  319. package/src/console/providers/catalog/discover-constants.ts +0 -6
  320. package/src/network/pool-health.ts +0 -198
  321. package/src/providers/integrations/buddy/buddy-checkin.ts +0 -521
  322. package/src/providers/integrations/buddy/buddy-cli-headers.ts +0 -76
  323. package/src/providers/integrations/buddy/buddy-conversation-headers.ts +0 -130
  324. package/src/providers/integrations/buddy/buddy-discovery-shared.ts +0 -234
  325. package/src/providers/integrations/buddy/buddy-growth-shared.ts +0 -496
  326. package/src/providers/integrations/buddy/buddy-oauth-shared.ts +0 -341
  327. package/src/providers/integrations/buddy/buddy-quota-shared.ts +0 -417
  328. package/src/providers/integrations/buddy/buddy-server-tools.ts +0 -240
  329. package/src/providers/integrations/buddy/buddy-usage-shared.ts +0 -221
  330. package/src/providers/integrations/buddy/buddy-usage-store.ts +0 -181
  331. package/src/providers/integrations/buddy/codebuddy/cn-catalog.ts +0 -37
  332. package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +0 -188
  333. package/src/providers/integrations/buddy/codebuddy/oauth.ts +0 -47
  334. package/src/providers/integrations/buddy/codebuddy/provider.ts +0 -179
  335. package/src/providers/integrations/buddy/codebuddy/quota.ts +0 -154
  336. package/src/providers/integrations/qoder/chat-proto.ts +0 -328
  337. package/src/providers/integrations/qoder/qoder-grpc.ts +0 -870
  338. package/src/providers/integrations/qoder/qoder-ide.ts +0 -481
  339. /package/dist/dashboard/assets/{app-DIXLjojg.js → app-C0gTXEoN.js} +0 -0
  340. /package/dist/dashboard/assets/{app-DIXLjojg.js.gz → app-C0gTXEoN.js.gz} +0 -0
  341. /package/src/network/{http2-bidi.ts → bidi.ts} +0 -0
  342. /package/src/network/pool/{byte-accounting.ts → accounting.ts} +0 -0
  343. /package/src/network/pool/{pool-scripts.ts → scripts.ts} +0 -0
  344. /package/src/network/pool/{pool-state.ts → state.ts} +0 -0
  345. /package/src/network/{backoff.ts → util/backoff.ts} +0 -0
  346. /package/src/network/{deduplication.ts → util/dedupe.ts} +0 -0
  347. /package/src/network/{ip-utils.ts → util/ip.ts} +0 -0
  348. /package/src/network/{rate-limit-verdict.ts → verdict.ts} +0 -0
@@ -27,7 +27,7 @@ import { mapUpstreamHttpError } from "../../../transport/failure-policy";
27
27
  import type { ImageGenerationOutcome, ProviderDispatchContext, ProviderDispatchTarget, ValidatedOutboundFetch } from "../../provider-contracts";
28
28
  import type { CanonicalRequest } from "../../../protocol/canonical-model";
29
29
  import { codebuddyHeaders, type CodeBuddyVariant } from "./codebuddy/shared";
30
- import { applyBuddySystemPrompt, buddyPrePayloadCommon } from "./buddy-chat-shared";
30
+ import { applyBuddySystemPrompt, buddyPrePayloadCommon } from "./chat";
31
31
 
32
32
  /** Media adapter identity: the variant's headers, its leading system turn, and base URL. */
33
33
  export interface BuddyMediaConfig {
@@ -8,6 +8,7 @@ import {
8
8
  record,
9
9
  } from "../../authentication/oauth-flow-store";
10
10
  import type { OAuthDeviceFlowContext, OAuthDevicePollResult, OAuthDeviceStartResult, OAuthExchangeResult } from "../../authentication/oauth-flow-store";
11
+ import { oauthAccountIdentity } from "../../authentication/oauth-flow-store";
11
12
  import type { OAuthTokenRefreshResult } from "../../authentication/oauth-refresh-service";
12
13
  import { OAuthDeviceFlow } from "../../authentication/oauth-device-flow";
13
14
 
@@ -45,14 +46,18 @@ function tokenResult(value: unknown, fallbackRefresh?: string): OAuthExchangeRes
45
46
  const refresh =
46
47
  nonEmptyTrimmedString(payload.refresh_token) ?? nonEmptyTrimmedString(payload.refreshToken) ?? fallbackRefresh;
47
48
  if (!access || !refresh) throw new Error("Cline OAuth response omitted access or refresh token");
49
+ const identity = oauthAccountIdentity(value);
48
50
  const accountLabel =
49
51
  nonEmptyTrimmedString(payload.email) ??
50
52
  nonEmptyTrimmedString(record(payload.userInfo)?.email) ??
51
- nonEmptyTrimmedString(record(payload.user)?.email);
53
+ nonEmptyTrimmedString(record(payload.user)?.email) ??
54
+ identity.accountEmail ??
55
+ identity.accountName;
52
56
  return {
53
57
  access,
54
58
  refresh,
55
59
  expiresAt: tokenExpiry(payload),
60
+ ...identity,
56
61
  ...(accountLabel === undefined ? {} : { accountLabel }),
57
62
  };
58
63
  }
@@ -107,8 +112,8 @@ export class ClineOAuthClient extends OAuthDeviceFlow {
107
112
  }
108
113
  }
109
114
 
110
- override async startDeviceAuth(_context?: OAuthDeviceFlowContext): Promise<OAuthDeviceStartResult> {
111
- const response = await this.fetchFn(WORKOS_DEVICE_AUTHORIZATION_URL, {
115
+ override async startDeviceAuth(context?: OAuthDeviceFlowContext): Promise<OAuthDeviceStartResult> {
116
+ const response = await this.fetchFor(context)(WORKOS_DEVICE_AUTHORIZATION_URL, {
112
117
  method: "POST",
113
118
  headers: { "content-type": "application/x-www-form-urlencoded", accept: "application/json" },
114
119
  body: new URLSearchParams({ client_id: CLINE_WORKOS_CLIENT_ID }),
@@ -145,7 +150,7 @@ export class ClineOAuthClient extends OAuthDeviceFlow {
145
150
  this.#sessions.delete(deviceAuthId);
146
151
  return { status: "failed", reason: "Cline device authorization expired" };
147
152
  }
148
- const response = await this.fetchFn(WORKOS_AUTHENTICATE_URL, {
153
+ const response = await this.fetchFor(context)(WORKOS_AUTHENTICATE_URL, {
149
154
  method: "POST",
150
155
  headers: { "content-type": "application/x-www-form-urlencoded", accept: "application/json" },
151
156
  body: new URLSearchParams({
@@ -185,7 +190,7 @@ export class ClineOAuthClient extends OAuthDeviceFlow {
185
190
  // exception that escapes the poll.
186
191
  let registered: Record<string, unknown>;
187
192
  try {
188
- const registerResponse = await this.fetchFn(CLINE_REGISTER_URL, {
193
+ const registerResponse = await this.fetchFor(context)(CLINE_REGISTER_URL, {
189
194
  method: "POST",
190
195
  headers: { "content-type": "application/json", accept: "application/json" },
191
196
  body: JSON.stringify({ accessToken, refreshToken }),
@@ -8,7 +8,7 @@ import { completeRequiredSchema, isRecord } from "../../../protocol/codecs";
8
8
  import { providerBaseUrl } from "../../provider-metadata";
9
9
  import { getCachedModelDiscovery } from "../../operations/provider-caches";
10
10
  import { defineModel } from "../../provider-model-definition";
11
- import { clineReasoningReplayPrepares } from "../buddy/buddy-chat-shared";
11
+ import { clineReasoningReplayPrepares } from "../buddy/chat";
12
12
  import { clinePlatform, clinePlatformVersion } from "../../operations/cli-platform";
13
13
  import {
14
14
  getClineCliVersion,
@@ -105,7 +105,7 @@ function completeClineToolSchemas(payload: Record<string, unknown>): void {
105
105
  });
106
106
  }
107
107
 
108
- function clinePrePayload(
108
+ export function clinePrePayload(
109
109
  payload: Record<string, unknown>,
110
110
  request: CanonicalRequest,
111
111
  candidate: ProviderDispatchTarget,
@@ -576,11 +576,10 @@ function clineRow(
576
576
  * not a tier marker — membership of the bucket is what makes a row free.
577
577
  */
578
578
  const CLINE_FREE_ROWS: readonly ClineSeedRow[] = [
579
- { id: "reflection/beam-free", ctx: 128_000, out: 32_000 },
580
579
  { id: "cline-free/nemotron-3.5-super-vl", ctx: 1_000_000, out: 131_072, vision: true },
581
580
  { id: "nvidia/nemotron-3.5-lightning-free", ctx: 1_000_000, out: 65_536 },
582
- { id: "poolside/laguna-s-2.1-free", ctx: 262_144, out: 32_768 },
583
581
  { id: "cline-free/solar-mini4", ctx: 524_288, out: 131_072 },
582
+ { id: "baidu/ernie-5.5-flash-preview:free", ctx: 1_000_000, out: 921_600 },
584
583
  ];
585
584
 
586
585
  /**
@@ -0,0 +1,98 @@
1
+ // Clixad credential login (GitHub device flow).
2
+ //
3
+ // Clixad's only production login is a GitHub device flow served by the
4
+ // gateway: `POST /v1/auth/device/start` returns a GitHub verification URL +
5
+ // user code; the gateway polls `POST /v1/auth/device/poll` with the session
6
+ // until the operator approves in the browser, then mints the CLI's bearer
7
+ // token (`adg_...`). There is no refresh token — the token is long-lived and
8
+ // the flow is re-run when needed.
9
+
10
+ import { OAuthClient } from "../../authentication/oauth-client";
11
+ import type {
12
+ OAuthDeviceStartResult,
13
+ OAuthDevicePollResult,
14
+ OAuthDeviceFlowContext,
15
+ } from "../../authentication/oauth-flow-store";
16
+
17
+ const CLIXAD_HANDOFF_PATH = "/v1/auth/device/start";
18
+ const CLIXAD_POLL_PATH = "/v1/auth/device/poll";
19
+ const CLIXAD_BASE_URL = "https://clixad.onrender.com";
20
+
21
+ export class ClixadOAuthClient extends OAuthClient {
22
+ readonly supportsDeviceCode = true;
23
+ readonly supportsBrowserCode = false;
24
+ protected readonly providerLabel = "clixad";
25
+ protected readonly clientId = "";
26
+ protected readonly tokenUrl = "";
27
+ protected readonly scopes = "";
28
+
29
+ async startDeviceAuth(): Promise<OAuthDeviceStartResult> {
30
+ const res = await this.fetchFn(new URL(CLIXAD_HANDOFF_PATH, CLIXAD_BASE_URL), {
31
+ method: "POST",
32
+ headers: { "content-type": "application/json", accept: "application/json" },
33
+ });
34
+ if (!res.ok) {
35
+ const text = await res.text().catch(() => "");
36
+ throw new Error(`clixad device flow start failed: HTTP ${res.status} ${text.slice(0, 300)}`);
37
+ }
38
+ const body = (await res.json()) as Record<string, unknown>;
39
+ return {
40
+ verificationUri: String(body["verification_uri"] ?? ""),
41
+ userCode: String(body["user_code"] ?? ""),
42
+ deviceAuthId: String(body["session"] ?? ""),
43
+ intervalSeconds: Number(body["interval"] ?? 5),
44
+ expiresInSeconds: Number(body["expires_in"] ?? 900),
45
+ providerState: JSON.stringify({ session: body["session"] }),
46
+ };
47
+ }
48
+
49
+ async pollDeviceAuth(deviceAuthId: string, context?: OAuthDeviceFlowContext): Promise<OAuthDevicePollResult> {
50
+ let providerState: Record<string, unknown> = {};
51
+ try {
52
+ providerState = JSON.parse(context?.providerState ?? "{}") as Record<string, unknown>;
53
+ } catch {
54
+ /* ignore */
55
+ }
56
+ const session = String(providerState["session"] ?? deviceAuthId);
57
+ const res = await this.fetchFn(new URL(CLIXAD_POLL_PATH, CLIXAD_BASE_URL), {
58
+ method: "POST",
59
+ headers: { "content-type": "application/json", accept: "application/json" },
60
+ body: JSON.stringify({ session }),
61
+ });
62
+ const body = (await res.json().catch(() => ({}))) as Record<string, unknown>;
63
+ const status = String(body["status"] ?? "");
64
+ if (status === "complete") {
65
+ const token = String(body["token"] ?? "");
66
+ return {
67
+ status: "complete",
68
+ result: {
69
+ access: token,
70
+ // Clixad issues no refresh token — the bearer is long-lived and the
71
+ // flow is re-run when needed. Mirror the access token so the console
72
+ // store always has a non-empty refresh field.
73
+ refresh: token,
74
+ expiresAt: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000),
75
+ accountLabel: String(body["email"] ?? body["login"] ?? ""),
76
+ auth_state: {
77
+ userId: body["userId"],
78
+ email: body["email"],
79
+ login: body["login"],
80
+ defaultModel: body["default_model"],
81
+ },
82
+ },
83
+ };
84
+ }
85
+ if (status === "closed") {
86
+ return {
87
+ status: "failed",
88
+ reason: `signup closed: ${String(body["message"] ?? "")} (${String(body["waitlist_url"] ?? "")})`,
89
+ };
90
+ }
91
+ if (status === "pending") return { status: "pending" };
92
+ if (status === "unavailable") return { status: "failed", reason: `unavailable: ${String(body["error"] ?? "")}` };
93
+ return { status: "failed", reason: `device poll failed: ${String(body["error"] ?? body["status"] ?? res.status)}` };
94
+ }
95
+ }
96
+
97
+ /** Shared Clixad device-login client instance (registry-facing). */
98
+ export const clixadOAuthClient = new ClixadOAuthClient();
@@ -0,0 +1,132 @@
1
+ // Clixad quota collector.
2
+ //
3
+ // Reads the account's credit surface from the gateway's wallet endpoint
4
+ // (`GET /v1/wallet` with the stored bearer token). The wallet reports the
5
+ // billed balance, the daily free-tier allowance (`free_tier.daily_credits` /
6
+ // `credits_left` — resets at midnight UTC), turns left per free model, and
7
+ // the ad-reward earnings cap (`max_reward_usd_per_day`). Reads are
8
+ // Bearer-authenticated; never throws — a failed read returns a null result so
9
+ // the router treats it as unknown rather than dead.
10
+
11
+ import type { FetchLike, ProviderQuotaResult, ProviderQuotaWindow } from "../../quota/quota-contracts";
12
+ import { cleanError, number, percentWindow, text } from "../../quota/quota-contracts";
13
+ import type { QuotaCollectionContext } from "../../quota/quota-support";
14
+
15
+ async function readWallet(
16
+ baseUrl: string,
17
+ token: string,
18
+ fetcher: FetchLike,
19
+ ): Promise<Record<string, unknown> | null> {
20
+ if (!token) return null;
21
+ return fetcher(`${baseUrl}/v1/wallet`, {
22
+ method: "GET",
23
+ headers: {
24
+ accept: "application/json",
25
+ authorization: `Bearer ${token}`,
26
+ },
27
+ signal: AbortSignal.timeout(15_000),
28
+ })
29
+ .then(async (res) => {
30
+ if (!res.ok) return null;
31
+ try {
32
+ return (await res.json()) as Record<string, unknown>;
33
+ } catch {
34
+ return null;
35
+ }
36
+ })
37
+ .catch(() => null);
38
+ }
39
+
40
+ /** Next midnight UTC, for the free-tier reset window. */
41
+ function nextMidnightUtc(): string {
42
+ const now = new Date();
43
+ const next = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate() + 1));
44
+ return next.toISOString();
45
+ }
46
+
47
+ /**
48
+ * Reads the account quota and returns a normalized result.
49
+ *
50
+ * Pooled windows: the billed balance (no ceiling — absolute remaining only)
51
+ * and the daily free-tier allowance (120k credits/day, resets at midnight
52
+ * UTC). Independent window: the ad-reward earnings cap ($5/day).
53
+ */
54
+ export async function fetchClixadQuota(
55
+ credential: string,
56
+ fetcher: FetchLike,
57
+ _context?: QuotaCollectionContext,
58
+ ): Promise<ProviderQuotaResult> {
59
+ try {
60
+ const token = text(credential) ?? "";
61
+ const wallet = await readWallet("https://clixad.onrender.com", token, fetcher);
62
+ if (!wallet) {
63
+ return { source: "clixad", plan: null, windows: [], error: "Clixad wallet endpoint unavailable" };
64
+ }
65
+ const windows: ProviderQuotaWindow[] = [];
66
+
67
+ const balance = number(wallet["balance"]);
68
+ if (balance !== null) {
69
+ // Billed balance: pooled, absolute remaining, no ceiling (a bonus pack
70
+ // has no declared limit — it simply is what it is).
71
+ windows.push({
72
+ kind: "credits",
73
+ label: "Account credits",
74
+ accounting: "pooled",
75
+ usedPercent: null,
76
+ remainingPercent: null,
77
+ resetsAt: null,
78
+ remaining: Math.max(0, balance),
79
+ recurring: false,
80
+ });
81
+ }
82
+
83
+ const freeTier = wallet["free_tier"] as Record<string, unknown> | undefined;
84
+ const dailyCredits = freeTier === undefined ? null : number(freeTier["daily_credits"]);
85
+ if (dailyCredits !== null && dailyCredits > 0) {
86
+ const creditsLeft = freeTier === undefined ? null : number(freeTier["credits_left"]);
87
+ const used = creditsLeft === null ? null : Math.max(0, dailyCredits - creditsLeft);
88
+ // Daily free tier: pooled (it is credit the account can spend), ceiling
89
+ // = the daily allowance, resets at midnight UTC.
90
+ windows.push(
91
+ percentWindow(
92
+ "free_daily",
93
+ "Daily free tier",
94
+ used === null ? null : (used / dailyCredits) * 100,
95
+ nextMidnightUtc(),
96
+ used,
97
+ dailyCredits,
98
+ "pooled",
99
+ ),
100
+ );
101
+ }
102
+
103
+ const maxRewardUsd = number(wallet["max_reward_usd_per_day"]);
104
+ if (maxRewardUsd !== null && maxRewardUsd > 0) {
105
+ const earnedUsd = number(wallet["earned_usd_today"]) ?? 0;
106
+ const usedUsd = Math.min(maxRewardUsd, Math.max(0, earnedUsd));
107
+ // Ad-reward earnings cap: independent (it does not fund model calls
108
+ // directly — it caps how much *earning* can happen per day).
109
+ windows.push(
110
+ percentWindow(
111
+ "earn_usd_daily",
112
+ "Daily reward cap",
113
+ (usedUsd / maxRewardUsd) * 100,
114
+ nextMidnightUtc(),
115
+ usedUsd,
116
+ maxRewardUsd,
117
+ "independent",
118
+ ),
119
+ );
120
+ }
121
+
122
+ const plan = number(wallet["balance"]) !== null ? "metered" : null;
123
+ return {
124
+ source: "clixad",
125
+ plan,
126
+ windows,
127
+ error: null,
128
+ };
129
+ } catch (error) {
130
+ return { source: "clixad", plan: null, windows: [], error: cleanError(error) };
131
+ }
132
+ }
@@ -0,0 +1,145 @@
1
+ // Clixad provider — TypeScript, Clixad gateway, Bun gateway.
2
+ //
3
+ // Clixad is an ad-funded terminal coding agent whose gateway
4
+ // (`https://clixad.onrender.com`) meters model calls and keeps the account
5
+ // balance, free-tier allowance, and ad-reward network server-side. The chat
6
+ // surface is OpenAI-compatible (`/v1/chat/completions`) with a bearer token
7
+ // (`adg_...`) minted by the GitHub device flow at login; model calls report
8
+ // credit accounting in an extra `clixad` envelope.
9
+ //
10
+ // Verified live 2026-11-11 (evidence ledger:
11
+ // `documentation/research/clixad/2026-11-11-clixad-wire.md`):
12
+ // - GET /v1/models → 200, 14 rows; the five `free: true` rows are
13
+ // served on the daily free tier (120k credits/day) and are the ones seeded
14
+ // below. The remaining rows are billed against the account balance.
15
+ // - POST /v1/chat/completions → 200 stream for all five free models, with
16
+ // `clixad.credits_waived` accounting the free-tier draw.
17
+ // - GET /v1/wallet → balance + free_tier (daily allowance, turns
18
+ // left per model), the quota source.
19
+ //
20
+ // The static roster carries the five live-verified free rows so the Free
21
+ // Limited section is populated before any fetch. Live discovery keeps the list
22
+ // current; the roster rows are preserved when the upstream listing reports the
23
+ // same id (the shared reader would otherwise overwrite freeTier/reasoning/tool
24
+ // flags with its conservative defaults).
25
+
26
+ import type { ApiKeyProviderSpec } from "../../configured-provider";
27
+ import { fetchOpenAICompatibleModels } from "../../discovery/openai-model-discovery";
28
+ import {
29
+ defineModel,
30
+ type ModelDefinition,
31
+ } from "../../provider-model-definition";
32
+
33
+ const CLIXAD_PROVIDER_ID = "clixad" as const;
34
+
35
+ /** Chat path below the `/v1` base root. */
36
+ const CLIXAD_CHAT_PATH = "/chat/completions";
37
+
38
+ /**
39
+ * Clixad adapter spec: plain bearer, OpenAI-compatible chat.
40
+ *
41
+ * The model call endpoint accepts standard OpenAI fields and streams normally,
42
+ * so the generic API-key adapter serves it. No bespoke headers are required
43
+ * beyond the bearer. (The upstream's gzipped-body fallback is a *client-side*
44
+ * workaround for an edge WAF; the gateway itself answers plain JSON.)
45
+ */
46
+ export const CLIXAD_SPEC: ApiKeyProviderSpec = {
47
+ provider_id: CLIXAD_PROVIDER_ID,
48
+ endpoint_paths_by_wire_family: { chat: CLIXAD_CHAT_PATH },
49
+ };
50
+
51
+ /**
52
+ * Default rows for the Clixad provider (2026-11-11).
53
+ *
54
+ * Every row below was verified live on a fresh account: it streams a reply and
55
+ * draws from the daily free tier (`credits_waived` per call). Context windows
56
+ * and effort ladders come from the upstream's own `/v1/models` listing; token
57
+ * prices are the credits-per-1M figures the upstream publishes, kept here as
58
+ * `cost` for the operator (the tier itself bills zero — `FREE_TIER_COST`).
59
+ */
60
+ export const CLIXAD_DEFAULT_MODELS: readonly ModelDefinition[] = [
61
+ defineModel({
62
+ id: "gpt-5-nano",
63
+ wireFamily: "chat",
64
+ endpoint: CLIXAD_CHAT_PATH,
65
+ ctx: 400_000,
66
+ out: 60_000,
67
+ reasoning: true,
68
+ toolCall: true,
69
+ free: true,
70
+ freeTier: true,
71
+ reasoningEfforts: ["minimal", "low", "medium", "high"]
72
+ }),
73
+ defineModel({
74
+ id: "gemini-2.5-flash-lite",
75
+ wireFamily: "chat",
76
+ endpoint: CLIXAD_CHAT_PATH,
77
+ ctx: 1_048_576,
78
+ out: 60_000,
79
+ reasoning: true,
80
+ toolCall: true,
81
+ free: true,
82
+ freeTier: true,
83
+ reasoningEfforts: ["off", "low", "medium", "high"]
84
+ }),
85
+ defineModel({
86
+ id: "claude-haiku-5.5",
87
+ wireFamily: "chat",
88
+ endpoint: CLIXAD_CHAT_PATH,
89
+ ctx: 24_000,
90
+ // The gateway publishes no output cap; clamp under the 24k context so a
91
+ // request can never exceed the endpoint (input + output budget).
92
+ out: 16_000,
93
+ reasoning: true,
94
+ toolCall: true,
95
+ free: true,
96
+ freeTier: true,
97
+ reasoningEfforts: ["off", "low", "medium", "high", "xhigh", "max"]
98
+ }),
99
+ defineModel({
100
+ id: "deepseek-v4-flash",
101
+ wireFamily: "chat",
102
+ endpoint: CLIXAD_CHAT_PATH,
103
+ ctx: 1_048_576,
104
+ out: 42_000,
105
+ reasoning: true,
106
+ toolCall: true,
107
+ free: true,
108
+ freeTier: true,
109
+ reasoningEfforts: ["off", "low", "medium", "high", "xhigh", "max"]
110
+ }),
111
+ defineModel({
112
+ id: "gemini-3.5-flash-lite",
113
+ wireFamily: "chat",
114
+ endpoint: CLIXAD_CHAT_PATH,
115
+ ctx: 1_048_576,
116
+ out: 375_000,
117
+ reasoning: true,
118
+ toolCall: true,
119
+ free: true,
120
+ freeTier: true,
121
+ reasoningEfforts: ["off", "low", "medium", "high", "xhigh", "max"]
122
+ }),
123
+ ];
124
+
125
+ /**
126
+ * Live `/v1/models` listing.
127
+ *
128
+ * The listing is unauthenticated (verified live). Every fetched row is kept
129
+ * as the shared reader resolved it, except ids the static roster already knows
130
+ * — those keep the roster row whole so the freeTier/reasoning/tool flags are
131
+ * not overwritten by the listing's conservative defaults.
132
+ */
133
+ export async function discoverClixadModels(options: {
134
+ readonly baseUrl: string;
135
+ readonly fetcher?: typeof fetch;
136
+ }): Promise<readonly ModelDefinition[] | null> {
137
+ const listed = await fetchOpenAICompatibleModels({
138
+ baseUrl: options.baseUrl,
139
+ providerId: "clixad",
140
+ ...(options.fetcher === undefined ? {} : { fetcher: options.fetcher }),
141
+ });
142
+ if (listed === null) return null;
143
+ const known = new Map(CLIXAD_DEFAULT_MODELS.map((model) => [model.modelId, model]));
144
+ return listed.map((model) => known.get(model.modelId) ?? model);
145
+ }
@@ -3,6 +3,8 @@ import {
3
3
  postFormTokenRequest,
4
4
  InMemoryOAuthFlowStore,
5
5
  OAuthFlowStore,
6
+ type OAuthCodeExchangeContext,
7
+ type OAuthDeviceFlowContext,
6
8
  type OAuthDevicePollResult,
7
9
  type OAuthDeviceStartResult,
8
10
  type OAuthExchangeResult,
@@ -200,12 +202,13 @@ export class CodexOAuthClient extends OAuthDeviceFlow {
200
202
  codeVerifier: string,
201
203
  redirectUri: string,
202
204
  _state?: string,
205
+ _context?: OAuthCodeExchangeContext,
203
206
  ): Promise<OAuthExchangeResult> {
204
207
  return exchangeCodeForToken(code, codeVerifier, redirectUri, this.fetchFn);
205
208
  }
206
209
 
207
- override async startDeviceAuth(): Promise<OAuthDeviceStartResult> {
208
- const started = await startCodexDeviceAuth(CODEX_CLIENT_ID, this.fetchFn);
210
+ override async startDeviceAuth(context?: OAuthDeviceFlowContext): Promise<OAuthDeviceStartResult> {
211
+ const started = await startCodexDeviceAuth(CODEX_CLIENT_ID, this.fetchFor(context));
209
212
  await this.#requireStore().saveDeviceState(started.deviceAuthId, { ...started });
210
213
  return {
211
214
  verificationUri: "https://auth.openai.com/codex/device",
@@ -216,7 +219,7 @@ export class CodexOAuthClient extends OAuthDeviceFlow {
216
219
  };
217
220
  }
218
221
 
219
- override async pollDeviceAuth(deviceAuthId: string): Promise<OAuthDevicePollResult> {
222
+ override async pollDeviceAuth(deviceAuthId: string, context?: OAuthDeviceFlowContext): Promise<OAuthDevicePollResult> {
220
223
  const store = this.#requireStore();
221
224
  const stored = await store.getDeviceState(deviceAuthId);
222
225
  const device = stored === undefined ? undefined : parseCodexDeviceStart(stored);
@@ -227,7 +230,7 @@ export class CodexOAuthClient extends OAuthDeviceFlow {
227
230
  // never an exception that escapes the dashboard's poll request.
228
231
  let authorization;
229
232
  try {
230
- authorization = await pollCodexDeviceAuth(device, this.fetchFn);
233
+ authorization = await pollCodexDeviceAuth(device, this.fetchFor(context));
231
234
  } catch (error) {
232
235
  return { status: "failed", reason: error instanceof Error ? error.message : "Codex device polling failed" };
233
236
  }
@@ -238,7 +241,7 @@ export class CodexOAuthClient extends OAuthDeviceFlow {
238
241
  authorization.authorizationCode,
239
242
  authorization.codeVerifier,
240
243
  CODEX_DEVICE_REDIRECT_URI,
241
- this.fetchFn,
244
+ this.fetchFor(context),
242
245
  );
243
246
  } catch (error) {
244
247
  return { status: "failed", reason: error instanceof Error ? error.message : "Codex token exchange failed" };
@@ -279,7 +279,7 @@ export class CursorOAuthClient extends OAuthDeviceFlow {
279
279
  `${CURSOR_API_BASE_URL}/auth/poll?uuid=${encodeURIComponent(deviceAuthId)}` +
280
280
  `&verifier=${encodeURIComponent(state.verifier)}`;
281
281
  const outcome = await fetchJson(
282
- asFetchFn(this.fetchFn),
282
+ asFetchFn(this.fetchFor(context)),
283
283
  url,
284
284
  { method: "GET", headers: { accept: "application/json" } },
285
285
  AUTH_REQUEST_TIMEOUT_MS,