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
@@ -0,0 +1,281 @@
1
+ // Live Cursor Run sessions, and the tool-call continuation they make possible.
2
+ //
3
+ // Cursor's tool loop spans *two* client HTTP requests: the first returns a tool
4
+ // call, the second submits that tool's result. The upstream Run must be the same
5
+ // Run, and it must stay open between them, so the Run cannot be owned by either
6
+ // request — it is owned here.
7
+ //
8
+ // This manager is process-local by construction. A Run is an HTTP/2 socket; it
9
+ // cannot survive a restart, and it is not shared across processes. After a
10
+ // restart the adapter rebases from the complete request history instead (see
11
+ // `cursor.ts`), which is why an orphan tool result with no history fails
12
+ // explicitly rather than silently starting a new Run.
13
+ //
14
+ // Everything the manager holds is bounded: one idle TTL, one release per
15
+ // session, one frame pump per Run, and one terminal path that closes the stream
16
+ // and releases the borrowed lease exactly once.
17
+ import { GatewayError } from "../../../protocol/gateway-error";
18
+ import type { UsageRecord } from "../../../protocol/canonical-model";
19
+ import type { AttemptLeaseOwnership } from "../../provider-contracts";
20
+ import { RUN_IDLE_TTL_MS } from "./cursor-shared";
21
+ import type { CursorToolDescriptor } from "./cursor-request";
22
+
23
+ /** Identity a later request must present to claim a pending tool call. */
24
+ export interface CursorContinuationScope {
25
+ readonly tenantId: string;
26
+ readonly apiKeyId: string;
27
+ readonly providerId: string;
28
+ readonly providerAccountId: string;
29
+ }
30
+
31
+ /** One pending external tool call awaiting the client's result. */
32
+ export interface CursorPendingToolCall {
33
+ /** Unguessable call id handed to the client. */
34
+ readonly callId: string;
35
+ /** Cursor's exec message id the result must echo. */
36
+ readonly execId: number;
37
+ /** Bare function name the client declared. */
38
+ readonly toolName: string;
39
+ }
40
+
41
+ /** Everything one live Run session owns. */
42
+ export interface CursorRunSession {
43
+ readonly runId: string;
44
+ readonly conversationId: string;
45
+ readonly scope: CursorContinuationScope;
46
+ /** Declared tools for this Run; an inbound call outside them is refused. */
47
+ readonly descriptors: readonly CursorToolDescriptor[];
48
+ /** Cursor exec id → pending call id. */
49
+ readonly pending: Map<number, string>;
50
+ /** Pending call id → Cursor exec id and name. */
51
+ readonly calls: Map<string, CursorPendingToolCall>;
52
+ /** Usage reported by the Run's `turn_ended`, when it has arrived. */
53
+ usage: UsageRecord | undefined;
54
+ /** Terminal reason this Run ended, once it has. */
55
+ failure: GatewayError | undefined;
56
+ }
57
+
58
+ /** Registry entry: one live Run, its expiry, and its borrowed lease release. */
59
+ interface LiveRun {
60
+ readonly session: CursorRunSession;
61
+ /**
62
+ * The borrowed account/network-pool lease release. Optional and mutable: a
63
+ * continuation request that re-enters an already-registered Run hands over the
64
+ * lease it took, and `adoptLease` refuses when one is already stored — so the
65
+ * slot is released exactly once however many requests touched the Run.
66
+ */
67
+ releaseLease?: (() => void) | undefined;
68
+ readonly close: (reason?: string) => void;
69
+ expiryTimer: ReturnType<typeof setTimeout>;
70
+ expiresAt: number;
71
+ }
72
+
73
+ /**
74
+ * Bounded, tenant/API-key-scoped registry of live Cursor Runs.
75
+ *
76
+ * A continuation is authorized by *server-recorded* affinity only: a call id is
77
+ * unguessable, and resolving one additionally requires the same tenant, API key,
78
+ * provider, and account that created it. A caller that guesses or replays a call
79
+ * id from another key resolves nothing, so one tenant's tool result can never be
80
+ * written onto another tenant's Run.
81
+ */
82
+ export class CursorRunSessionManager {
83
+ /** runId → live Run. */
84
+ private readonly runs = new Map<string, LiveRun>();
85
+ /** Pending call id → runId. Second index: resolution is by call id. */
86
+ private readonly callOwners = new Map<string, string>();
87
+
88
+ /** Live Run count, for tests and runtime assertions. */
89
+ get size(): number {
90
+ return this.runs.size;
91
+ }
92
+
93
+ /**
94
+ * Registers one live Run.
95
+ *
96
+ * `releaseLease` is the borrowed account/network-pool lease the manager now
97
+ * owns: the request that opened the Run transferred it instead of releasing it
98
+ * at response time. It is called exactly once, on the Run's single terminal
99
+ * path.
100
+ */
101
+ register(input: {
102
+ readonly session: CursorRunSession;
103
+ readonly releaseLease?: (() => void) | undefined;
104
+ readonly close: (reason?: string) => void;
105
+ readonly idleTtlMs?: number;
106
+ }): void {
107
+ const idleTtlMs = input.idleTtlMs ?? RUN_IDLE_TTL_MS;
108
+ const runId = input.session.runId;
109
+ const entry: LiveRun = {
110
+ session: input.session,
111
+ ...(input.releaseLease === undefined ? {} : { releaseLease: input.releaseLease }),
112
+ close: input.close,
113
+ expiresAt: Date.now() + idleTtlMs,
114
+ expiryTimer: setTimeout(() => {
115
+ this.terminate(runId, "Cursor Run idle-expired waiting for a tool result");
116
+ }, idleTtlMs),
117
+ };
118
+ entry.expiryTimer.unref?.();
119
+ this.runs.set(runId, entry);
120
+ }
121
+
122
+ /** Ends one Run: closes its stream and releases what it borrowed, once. */
123
+ terminate(runId: string, reason?: string): void {
124
+ const entry = this.runs.get(runId);
125
+ if (entry === undefined) return;
126
+ this.runs.delete(runId);
127
+ for (const callId of entry.session.pending.values()) {
128
+ if (this.callOwners.get(callId) === runId) this.callOwners.delete(callId);
129
+ }
130
+ for (const call of entry.session.calls.values()) {
131
+ if (this.callOwners.get(call.callId) === runId) this.callOwners.delete(call.callId);
132
+ }
133
+ clearTimeout(entry.expiryTimer);
134
+ try {
135
+ entry.close(reason);
136
+ } catch {
137
+ // Closing a dead stream must not skip the lease release below.
138
+ }
139
+ try {
140
+ entry.releaseLease?.();
141
+ } catch {
142
+ // A failed release must not propagate out of teardown.
143
+ }
144
+ }
145
+
146
+ /** Registers one pending external tool call on a live Run. */
147
+ registerPendingCall(runId: string, call: CursorPendingToolCall): boolean {
148
+ const entry = this.runs.get(runId);
149
+ if (entry === undefined) return false;
150
+ entry.session.pending.set(call.execId, call.callId);
151
+ entry.session.calls.set(call.callId, call);
152
+ this.callOwners.set(call.callId, runId);
153
+ return true;
154
+ }
155
+
156
+ /**
157
+ * Resolves one pending call id to its live Run, scoped to the caller.
158
+ *
159
+ * Returns the Run only when the id is pending *and* every scope field matches
160
+ * the Run that created it. A mismatch is a hard refusal, not a fallback:
161
+ * routing one account's tool result onto another account's Run would corrupt
162
+ * both conversations and leak the first account's context into the second.
163
+ */
164
+ resolveCall(
165
+ callId: string,
166
+ scope: CursorContinuationScope,
167
+ ): { session: CursorRunSession; call: CursorPendingToolCall } | undefined {
168
+ const runId = this.callOwners.get(callId);
169
+ if (runId === undefined) return undefined;
170
+ const entry = this.runs.get(runId);
171
+ if (entry === undefined) return undefined;
172
+ const { session } = entry;
173
+ if (
174
+ session.scope.tenantId !== scope.tenantId ||
175
+ session.scope.apiKeyId !== scope.apiKeyId ||
176
+ session.scope.providerId !== scope.providerId ||
177
+ session.scope.providerAccountId !== scope.providerAccountId
178
+ ) {
179
+ return undefined;
180
+ }
181
+ const call = session.calls.get(callId);
182
+ if (call === undefined) return undefined;
183
+ return { session, call };
184
+ }
185
+
186
+ /** Clears one pending call after its result has been written to the Run. */
187
+ clearPendingCall(runId: string, callId: string): void {
188
+ const entry = this.runs.get(runId);
189
+ if (entry === undefined) return;
190
+ const call = entry.session.calls.get(callId);
191
+ if (call !== undefined) entry.session.pending.delete(call.execId);
192
+ entry.session.calls.delete(callId);
193
+ this.callOwners.delete(callId);
194
+ this.touch(runId);
195
+ }
196
+
197
+ /** Extends one Run's idle expiry: the client answered, so the Run is live. */
198
+ touch(runId: string, idleTtlMs = RUN_IDLE_TTL_MS): void {
199
+ const entry = this.runs.get(runId);
200
+ if (entry === undefined) return;
201
+ clearTimeout(entry.expiryTimer);
202
+ entry.expiresAt = Date.now() + idleTtlMs;
203
+ entry.expiryTimer = setTimeout(() => {
204
+ this.terminate(runId, "Cursor Run idle-expired waiting for a tool result");
205
+ }, idleTtlMs);
206
+ entry.expiryTimer.unref?.();
207
+ }
208
+
209
+ /** Records the Run's authoritative terminal usage before it is closed. */
210
+ recordUsage(runId: string, usage: UsageRecord): void {
211
+ const entry = this.runs.get(runId);
212
+ if (entry === undefined) return;
213
+ entry.session.usage = usage;
214
+ }
215
+
216
+ /** Records why a Run failed, so the next request reports it rather than hanging. */
217
+ recordFailure(runId: string, failure: GatewayError): void {
218
+ const entry = this.runs.get(runId);
219
+ if (entry === undefined) return;
220
+ entry.session.failure = failure;
221
+ }
222
+
223
+ /** Reads one live Run by id, for the frame continuation path. */
224
+ get(runId: string): CursorRunSession | undefined {
225
+ return this.runs.get(runId)?.session;
226
+ }
227
+
228
+ /**
229
+ * Describes one pending call by id and caller identity.
230
+ *
231
+ * The routing layer needs the owning account *before* it knows which provider
232
+ * a candidate belongs to, so this reads the same server-recorded scope the
233
+ * adapter will later re-check: tenant and API key here, provider and account
234
+ * in the answer. A call id from another tenant or key resolves nothing.
235
+ */
236
+ describePendingCall(
237
+ callId: string,
238
+ scope: { readonly tenantId: string; readonly apiKeyId: string },
239
+ ): { readonly providerId: string; readonly providerAccountId: string } | undefined {
240
+ const runId = this.callOwners.get(callId);
241
+ if (runId === undefined) return undefined;
242
+ const entry = this.runs.get(runId);
243
+ if (entry === undefined) return undefined;
244
+ const { session } = entry;
245
+ if (
246
+ session.scope.tenantId !== scope.tenantId ||
247
+ session.scope.apiKeyId !== scope.apiKeyId
248
+ ) {
249
+ return undefined;
250
+ }
251
+ if (!session.calls.has(callId)) return undefined;
252
+ return {
253
+ providerId: session.scope.providerId,
254
+ providerAccountId: session.scope.providerAccountId,
255
+ };
256
+ }
257
+
258
+ /**
259
+ * Takes over the borrowed lease for a Run that is already registered.
260
+ *
261
+ * Idempotent: a second transfer stores nothing, so a retry of the same
262
+ * continuation request cannot double-release the slot.
263
+ */
264
+ adoptLease(runId: string, ownership: AttemptLeaseOwnership | undefined): void {
265
+ if (ownership === undefined) return;
266
+ const entry = this.runs.get(runId);
267
+ if (entry === undefined || entry.releaseLease !== undefined) return;
268
+ const release = ownership.transferToProviderSession();
269
+ if (release === undefined) return;
270
+ entry.releaseLease = release;
271
+ }
272
+
273
+ /** Drops every live Run. Shutdown and test seam. */
274
+ terminateAll(reason?: string): void {
275
+ for (const runId of [...this.runs.keys()]) this.terminate(runId, reason);
276
+ this.callOwners.clear();
277
+ }
278
+ }
279
+
280
+ /** Process-local manager: one active Run set per gateway process. */
281
+ export const cursorRunSessions = new CursorRunSessionManager();
@@ -0,0 +1,108 @@
1
+ // Cursor constants shared by the adapter, auth client, catalog, transport, and
2
+ // session manager.
3
+ //
4
+ // Every literal below is a Cursor endpoint or client identity the donor
5
+ // protocol was verified against: they are declared once so the auth flow, the
6
+ // unary catalog calls, and the Run stream cannot drift apart on host, path, or
7
+ // client id.
8
+ import type { WireFamily } from "../../../protocol/canonical-model";
9
+
10
+ /** Canonical bundled provider id. */
11
+ export const CURSOR_PROVIDER_ID = "cursor";
12
+
13
+ /** Cursor's API origin: auth, token, catalog and server-config calls. */
14
+ export const CURSOR_API_HOST = "api2.cursor.sh";
15
+ export const CURSOR_API_BASE_URL = `https://${CURSOR_API_HOST}`;
16
+ /** Cursor's website, where the browser login opens. */
17
+ export const CURSOR_WEBSITE_HOST = "cursor.com";
18
+ export const CURSOR_WEBSITE_URL = `https://${CURSOR_WEBSITE_HOST}`;
19
+
20
+ /**
21
+ * Production OAuth client id Cursor's IDE sends on `POST /oauth/token`
22
+ * (Cursor 3.17.19 `workbench.desktop.main.js`, `cursorCreds.authClientId` for
23
+ * `backendUrl` `https://api2.cursor.sh`). The IDE's non-production id is not
24
+ * used.
25
+ */
26
+ export const CURSOR_OAUTH_CLIENT_ID = "KbZUR41cY7W6zRSdpSUJ7I7mLYBKOCmB";
27
+
28
+ /**
29
+ * Client version sent when no local or remote Cursor build version resolves.
30
+ *
31
+ * Kept equal to `VERSION_SOURCES.cursor.fallback`: two fallbacks for one
32
+ * identity drifted apart (the header sent `cli-2026.07.09-a3815c0` while the
33
+ * badge reported `cli-2026.10.19-6bbf2c4`), so what the console showed an
34
+ * operator was not what the request carried. Discovery supersedes both on its
35
+ * first successful fetch.
36
+ */
37
+ export const FALLBACK_CLIENT_VERSION = "cli-2026.10.19-6bbf2c4";
38
+
39
+ /** Connect-RPC paths. Run is served by the discovered agent origin, not the API host. */
40
+ export const RUN_PATH = "/agent.v1.AgentService/Run";
41
+ export const AVAILABLE_MODELS_PATH = "/aiserver.v1.AiService/AvailableModels";
42
+ export const SERVER_CONFIG_PATH = "/aiserver.v1.ServerConfigService/GetServerConfig";
43
+
44
+ /** Connect unary/bidi protocol headers. */
45
+ export const CONTENT_TYPE_CONNECT_PROTO = "application/connect+proto";
46
+ export const CONNECT_PROTOCOL_VERSION = "1";
47
+
48
+ /** A raw Cursor API key (as opposed to a JWT already exchanged from one). */
49
+ const CURSOR_API_KEY_PREFIX = "crsr_";
50
+
51
+ /** True for a raw Cursor API key, which must be exchanged before dispatch. */
52
+ export function isExchangeableApiKey(value: string): boolean {
53
+ return value.startsWith(CURSOR_API_KEY_PREFIX);
54
+ }
55
+
56
+ /** Server error code Cursor surfaces as a sign-in policy block. */
57
+ export const SIGN_IN_POLICY_VIOLATION = "sign_in_policy_violation";
58
+
59
+ /** Seconds before a JWT is considered expiring and worth refreshing. */
60
+ export const TOKEN_EXPIRY_THRESHOLD_S = 300;
61
+
62
+ /** Individual auth/unary request timeout. */
63
+ export const AUTH_REQUEST_TIMEOUT_MS = 5_000;
64
+ /** Cursor IDE aborts its session refresh after 20 s (`_performAccessTokenRefresh`). */
65
+ export const SESSION_REFRESH_TIMEOUT_MS = 20_000;
66
+
67
+ /**
68
+ * How long a live Cursor Run is held open waiting for the client's next
69
+ * tool-result request. Matches the donor's continuation default: a tool round
70
+ * the client never answers must not hold an HTTP/2 stream, an account lease, or
71
+ * a pool slot for the life of the process.
72
+ */
73
+ export const RUN_IDLE_TTL_MS = 10 * 60_000;
74
+
75
+ /** Chat wire is the declared default; the adapter owns the native protocol. */
76
+ export const CURSOR_WIRE_FAMILY: WireFamily = "chat";
77
+
78
+ /**
79
+ * Any HTTPS subdomain of `cursor.sh` is an acceptable Run host: the region
80
+ * Cursor routes an account to varies (`agentn.*`, `agent.*`, `api5`, …).
81
+ */
82
+ export function isAllowedAgentHost(hostname: string): boolean {
83
+ return /^([a-z0-9-]+\.)+cursor\.sh$/i.test(hostname);
84
+ }
85
+
86
+ /**
87
+ * Normalizes a GetServerConfig agent URL to an https origin.
88
+ *
89
+ * Returns `null` for missing, malformed, non-HTTPS, credential-bearing, or
90
+ * non-`*.cursor.sh` hosts: the Run stream carries the account's credential, so
91
+ * a host that is not a Cursor origin is a fail-closed refusal rather than
92
+ * something to dial anyway.
93
+ */
94
+ export function normalizeAgentRunOrigin(raw: string | undefined): string | null {
95
+ if (raw === undefined || raw === null) return null;
96
+ const trimmed = String(raw).trim();
97
+ if (!trimmed) return null;
98
+ try {
99
+ const withScheme = /^https?:\/\//i.test(trimmed) ? trimmed : `https://${trimmed}`;
100
+ const parsed = new URL(withScheme);
101
+ if (parsed.protocol !== "https:") return null;
102
+ if (parsed.username || parsed.password) return null;
103
+ if (!isAllowedAgentHost(parsed.hostname)) return null;
104
+ return parsed.origin;
105
+ } catch {
106
+ return null;
107
+ }
108
+ }