cartethyia 2.7.9 → 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 (496) hide show
  1. package/.env.example +6 -5
  2. package/dist/dashboard/assets/{BannedPage-BxoG1MrL.js → BannedPage-Dq530awD.js} +1 -1
  3. package/dist/dashboard/assets/BannedPage-Dq530awD.js.gz +0 -0
  4. package/dist/dashboard/assets/{CliToolDetailPage-ixwgKk53.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-BmttNV3U.js → CliToolsPage-DaZZ3cqP.js} +1 -1
  7. package/dist/dashboard/assets/CliToolsPage-DaZZ3cqP.js.gz +0 -0
  8. package/dist/dashboard/assets/{CombosPage-BE3qwwfC.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-CRZdmMIX.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-Dv_FJ6Er.js → CustomizationPage-7xT5yg2E.js} +1 -1
  13. package/dist/dashboard/assets/CustomizationPage-7xT5yg2E.js.gz +0 -0
  14. package/dist/dashboard/assets/HealthEventsModal-Clq8E9cW.js +1 -0
  15. package/dist/dashboard/assets/HealthEventsModal-Clq8E9cW.js.gz +0 -0
  16. package/dist/dashboard/assets/{InjectSystemPromptPanel-BOoO8rpz.js → InjectSystemPromptPanel-6Teoq9Se.js} +2 -2
  17. package/dist/dashboard/assets/InjectSystemPromptPanel-6Teoq9Se.js.gz +0 -0
  18. package/dist/dashboard/assets/{LoginPage-ChJuNNVN.js → LoginPage-CZuI0MAR.js} +1 -1
  19. package/dist/dashboard/assets/LoginPage-CZuI0MAR.js.gz +0 -0
  20. package/dist/dashboard/assets/{ModelPicker-BZAJtPg1.js → ModelPicker-C1hNTlkr.js} +1 -1
  21. package/dist/dashboard/assets/ModelPicker-C1hNTlkr.js.gz +0 -0
  22. package/dist/dashboard/assets/{OverviewPage-BE40s3u5.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-CQ6bPUf_.js → ProviderIcon-Ddhm1InL.js} +1 -1
  27. package/dist/dashboard/assets/ProviderIcon-Ddhm1InL.js.gz +0 -0
  28. package/dist/dashboard/assets/ProvidersPage-C3fYuu6i.js +1 -0
  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-D1RV_2BX.js +1 -0
  33. package/dist/dashboard/assets/QuotaPage-D1RV_2BX.js.gz +0 -0
  34. package/dist/dashboard/assets/{SettingsPage-C5HPWqEv.js → SettingsPage-BzZAvYSX.js} +1 -1
  35. package/dist/dashboard/assets/SettingsPage-BzZAvYSX.js.gz +0 -0
  36. package/dist/dashboard/assets/{SetupPage-CFNcATJJ.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-YoD4tY5l.js → StudioPage-BjXFGSK4.js} +1 -1
  39. package/dist/dashboard/assets/StudioPage-BjXFGSK4.js.gz +0 -0
  40. package/dist/dashboard/assets/{UsagePage-DxjaAhb_.js → UsagePage-CP8F8BN7.js} +1 -1
  41. package/dist/dashboard/assets/UsagePage-CP8F8BN7.js.gz +0 -0
  42. package/dist/dashboard/assets/{api-keys-BTlkq_Uk.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-BMcj1xZE.js +1 -0
  47. package/dist/dashboard/assets/assert-BMcj1xZE.js.gz +0 -0
  48. package/dist/dashboard/assets/{badge-DdbT_7Am.js → badge-DkRUuVfz.js} +1 -1
  49. package/dist/dashboard/assets/badge-DkRUuVfz.js.gz +0 -0
  50. package/dist/dashboard/assets/{banner-CsGN-nbm.js → banner-CDjW841Q.js} +1 -1
  51. package/dist/dashboard/assets/banner-CDjW841Q.js.gz +0 -0
  52. package/dist/dashboard/assets/{card-mgZ_TLLZ.js → card-Bto5UlL9.js} +1 -1
  53. package/dist/dashboard/assets/card-Bto5UlL9.js.gz +0 -0
  54. package/dist/dashboard/assets/{cli-tools-A1-v8-03.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-CJ4Zty89.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-B5L2jPQ_.js → dialog-DL0Zftwv.js} +1 -1
  59. package/dist/dashboard/assets/dialog-DL0Zftwv.js.gz +0 -0
  60. package/dist/dashboard/assets/{drawer-DkjUouAj.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-B-LVLV6o.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-CAhdYl3B.js → entry-CGvdNU6r.js} +1 -1
  65. package/dist/dashboard/assets/entry-CGvdNU6r.js.gz +0 -0
  66. package/dist/dashboard/assets/entry-DScKYvZj.js +4 -0
  67. package/dist/dashboard/assets/entry-DScKYvZj.js.gz +0 -0
  68. package/dist/dashboard/assets/{formatters-CrsdLVsn.js → formatters-BS3DZlZj.js} +1 -1
  69. package/dist/dashboard/assets/formatters-BS3DZlZj.js.gz +0 -0
  70. package/dist/dashboard/assets/{index-BU64Lqvp.js → index-SQnvvTWX.js} +2 -2
  71. package/dist/dashboard/assets/index-SQnvvTWX.js.gz +0 -0
  72. package/dist/dashboard/assets/{inline-B2aDLyyg.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-BCVkdR9d.js → input-Bfx0EzRc.js} +1 -1
  75. package/dist/dashboard/assets/input-Bfx0EzRc.js.gz +0 -0
  76. package/dist/dashboard/assets/{layout-DNcAdMK-.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-DgrIH0hw.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-Cae01iu8.js → live-CbVTdX9V.js} +1 -1
  81. package/dist/dashboard/assets/live-CbVTdX9V.js.gz +0 -0
  82. package/dist/dashboard/assets/{network-CRib7H_2.js → network-JGvDveof.js} +1 -1
  83. package/dist/dashboard/assets/network-JGvDveof.js.gz +0 -0
  84. package/dist/dashboard/assets/{numbers-BKQE8Xpz.js → numbers-Dw6kiew-.js} +1 -1
  85. package/dist/dashboard/assets/numbers-Dw6kiew-.js.gz +0 -0
  86. package/dist/dashboard/assets/{pagination-ecPvG_8g.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/providers/zro.svg +3 -0
  91. package/dist/dashboard/assets/providers/zro.svg.gz +0 -0
  92. package/dist/dashboard/assets/quota-DiPD6UKH.js +1 -0
  93. package/dist/dashboard/assets/quota-DiPD6UKH.js.gz +0 -0
  94. package/dist/dashboard/assets/{routing-Ckm1UXuC.js → routing-8jZr-3WE.js} +1 -1
  95. package/dist/dashboard/assets/routing-8jZr-3WE.js.gz +0 -0
  96. package/dist/dashboard/assets/{select-ChoFWyKz.js → select-oO1FxMVb.js} +2 -2
  97. package/dist/dashboard/assets/select-oO1FxMVb.js.gz +0 -0
  98. package/dist/dashboard/assets/{settings-CKjFPlKW.js → settings-CLr3kdIx.js} +1 -1
  99. package/dist/dashboard/assets/settings-CLr3kdIx.js.gz +0 -0
  100. package/dist/dashboard/assets/{stack-DWCwU3fh.js → stack-Y3pDteZr.js} +1 -1
  101. package/dist/dashboard/assets/stack-Y3pDteZr.js.gz +0 -0
  102. package/dist/dashboard/assets/{state-Cg3VL5J_.js → state-CArX_Iak.js} +1 -1
  103. package/dist/dashboard/assets/state-CArX_Iak.js.gz +0 -0
  104. package/dist/dashboard/assets/{switch-Db70BMix.js → switch-DwlwmDO-.js} +1 -1
  105. package/dist/dashboard/assets/switch-DwlwmDO-.js.gz +0 -0
  106. package/dist/dashboard/assets/{useMutation-BqdE0LuM.js → useMutation-DJ9GYEgf.js} +1 -1
  107. package/dist/dashboard/assets/useMutation-DJ9GYEgf.js.gz +0 -0
  108. package/dist/dashboard/index.html +2 -2
  109. package/dist/dashboard/index.html.gz +0 -0
  110. package/dist/dashboard/precompressed-assets.json +54 -53
  111. package/migrations/full-postgres/0046_add_accounts_quota_plan_fetched_at.sql +7 -0
  112. package/migrations/full-postgres/0047_add_provider_device_flow_proxy.sql +17 -0
  113. package/migrations/lite-sqlite3/0046_add_accounts_quota_plan_fetched_at.sql +4 -0
  114. package/migrations/lite-sqlite3/0047_add_provider_device_flow_proxy.sql +19 -0
  115. package/package.json +1 -1
  116. package/src/boot/app.ts +11 -14
  117. package/src/boot/dependencies.ts +5 -7
  118. package/src/boot/flush.ts +20 -0
  119. package/src/boot/lifecycle.ts +7 -5
  120. package/src/config/providers.ts +6 -5
  121. package/src/config/routing.ts +26 -0
  122. package/src/config/spec-metadata.ts +72 -0
  123. package/src/config/spec.ts +28 -8
  124. package/src/console/api-keys/contracts.ts +12 -1
  125. package/src/console/api-keys/routes.ts +40 -28
  126. package/src/console/auth/account-reset.ts +7 -9
  127. package/src/console/backup/contracts.ts +4 -0
  128. package/src/console/backup/export-endpoint.ts +7 -5
  129. package/src/console/backup/nine-router.ts +71 -10
  130. package/src/console/backup/service.ts +8 -1
  131. package/src/console/cli-tools/service.ts +6 -12
  132. package/src/console/console-router-guards.ts +23 -16
  133. package/src/console/console-router.ts +1 -1
  134. package/src/console/domain-registration.ts +7 -4
  135. package/src/console/inferhub/client.ts +1 -1
  136. package/src/console/inferhub/normalize.ts +24 -28
  137. package/src/console/inferhub/types.ts +3 -0
  138. package/src/console/ip-bans/routes.ts +7 -13
  139. package/src/console/observability/live.ts +2 -2
  140. package/src/console/observability/store.ts +0 -53
  141. package/src/console/providers/catalog/contracts.ts +9 -3
  142. package/src/console/providers/catalog/model-operations.ts +2 -3
  143. package/src/console/providers/catalog/provider-operations.ts +1 -1
  144. package/src/console/providers/catalog/routes.ts +3 -2
  145. package/src/console/providers/catalog/store.ts +1914 -1902
  146. package/src/console/providers/detail/routes.ts +1 -0
  147. package/src/console/providers/detail/store.ts +4 -0
  148. package/src/console/providers/oauth/callback-listener.ts +30 -11
  149. package/src/console/providers/oauth/device-egress.ts +123 -0
  150. package/src/console/providers/oauth/routes.ts +123 -16
  151. package/src/console/quota/account-quota-global.ts +14 -24
  152. package/src/console/quota/account-quota-shared.ts +49 -0
  153. package/src/console/quota/account-quota-tenant.ts +11 -23
  154. package/src/console/quota/account-test-egress.ts +2 -2
  155. package/src/console/quota/daily-growth-job.ts +1 -1
  156. package/src/console/quota/quota-view.ts +19 -3
  157. package/src/console/routing/pools/contracts.ts +1 -1
  158. package/src/console/routing/pools/operations.ts +32 -47
  159. package/src/console/routing/pools/probe-verdict.ts +2 -2
  160. package/src/console/routing/pools/relay-deploy.ts +1 -1
  161. package/src/console/routing/pools/store.ts +4 -4
  162. package/src/console/shared/errors.ts +33 -6
  163. package/src/main.ts +2 -3
  164. package/src/network/client.ts +67 -0
  165. package/src/network/egress/bidi-session.ts +322 -0
  166. package/src/network/egress/dial.ts +201 -0
  167. package/src/network/egress/factory.ts +191 -0
  168. package/src/network/{outbound-fetch.ts → egress/fetch.ts} +195 -29
  169. package/src/network/egress/tls-profile.ts +123 -0
  170. package/src/network/egress/ws.ts +175 -0
  171. package/src/network/pool/{byte-accounting.ts → accounting.ts} +3 -2
  172. package/src/network/{types.ts → pool/agent-config.ts} +1 -1
  173. package/src/network/pool/agent.ts +2 -2
  174. package/src/network/{pool-cooldown-store.ts → pool/cooldown-store.ts} +95 -20
  175. package/src/network/{pool-health-machine.ts → pool/health.ts} +205 -6
  176. package/src/network/pool/resolver.ts +10 -849
  177. package/src/network/pool/selector.ts +184 -41
  178. package/src/network/ssrf.ts +7 -7
  179. package/src/network/{retry.ts → util/retry.ts} +1 -1
  180. package/src/network/{rate-limit-verdict.ts → verdict.ts} +1 -1
  181. package/src/observability/event-log.ts +7 -361
  182. package/src/observability/performance-metrics.ts +9 -0
  183. package/src/observability/runtime-metrics.ts +14 -9
  184. package/src/observability/telemetry-buffer.ts +16 -26
  185. package/src/observability/telemetry-reconciliation.ts +9 -37
  186. package/src/observability/telemetry-row.ts +125 -0
  187. package/src/persistence/db-mode.ts +4 -1
  188. package/src/persistence/dialect.ts +18 -0
  189. package/src/persistence/migrate.ts +6 -3
  190. package/src/persistence/schema.ts +17 -0
  191. package/src/persistence/ttl-cache.ts +21 -3
  192. package/src/protocol/codecs.ts +59 -2
  193. package/src/protocol/dsml.ts +34 -86
  194. package/src/protocol/markup-stream-parser.ts +195 -0
  195. package/src/protocol/reasoning-text.ts +19 -0
  196. package/src/protocol/request/chat.ts +10 -10
  197. package/src/protocol/request/gemini.ts +8 -2
  198. package/src/protocol/request/messages.ts +34 -22
  199. package/src/protocol/response/chat.ts +12 -20
  200. package/src/protocol/response/messages.ts +34 -7
  201. package/src/protocol/response/omp-tool-call-markup.ts +43 -86
  202. package/src/protocol/response/responses.ts +18 -2
  203. package/src/protocol/stop-reason.ts +23 -1
  204. package/src/protocol/think-split.ts +112 -0
  205. package/src/protocol/translation/dialect/qwen.ts +26 -58
  206. package/src/protocol/translation/quirks.ts +15 -0
  207. package/src/protocol/upstream/send-claude-messages.ts +2 -2
  208. package/src/providers/adapters/compatible-adapter.ts +76 -12
  209. package/src/providers/authentication/oauth-client.ts +40 -6
  210. package/src/providers/authentication/oauth-device-flow.ts +105 -11
  211. package/src/providers/authentication/oauth-flow-store.ts +82 -1
  212. package/src/providers/authentication/oauth-refresh-service.ts +766 -758
  213. package/src/providers/configured-provider.ts +148 -0
  214. package/src/providers/default-registry.ts +137 -36
  215. package/src/providers/discovery/discovery-types.ts +7 -0
  216. package/src/providers/discovery/probe-phases.ts +20 -6
  217. package/src/providers/discovery/probing-service.ts +22 -2
  218. package/src/providers/integrations/alibabacp/alibabacp-models.ts +1 -2
  219. package/src/providers/integrations/{dashscope-models.ts → alibabacp/dashscope-models.ts} +2 -2
  220. package/src/providers/integrations/antigravity/antigravity-protocol.ts +16 -1
  221. package/src/providers/integrations/buddy/account.ts +969 -0
  222. package/src/providers/integrations/buddy/capabilities.ts +12 -12
  223. package/src/providers/integrations/buddy/{buddy-catalog-shared.ts → catalog.ts} +198 -136
  224. package/src/providers/integrations/buddy/{buddy-chat-shared.ts → chat.ts} +176 -20
  225. package/src/providers/integrations/buddy/codebuddy/index.ts +429 -0
  226. package/src/providers/integrations/buddy/codebuddy/shared.ts +41 -26
  227. package/src/providers/integrations/buddy/headers.ts +311 -0
  228. package/src/providers/integrations/buddy/lifecycle.ts +1018 -0
  229. package/src/providers/integrations/buddy/{buddy-media.ts → media.ts} +1 -1
  230. package/src/providers/integrations/claude/claude-quota.ts +14 -17
  231. package/src/providers/integrations/cline/cline-oauth.ts +10 -5
  232. package/src/providers/integrations/cline/cline.ts +5 -6
  233. package/src/providers/integrations/clixad/clixad-oauth.ts +98 -0
  234. package/src/providers/integrations/clixad/clixad-quota.ts +132 -0
  235. package/src/providers/integrations/clixad/provider.ts +145 -0
  236. package/src/providers/integrations/codex/codex-oauth.ts +8 -5
  237. package/src/providers/integrations/commandcode/quota.ts +22 -28
  238. package/src/providers/integrations/cursor/cursor-auth.ts +1 -9
  239. package/src/providers/integrations/cursor/cursor-exec.ts +9 -2
  240. package/src/providers/integrations/cursor/cursor-hardening.ts +279 -0
  241. package/src/providers/integrations/cursor/cursor-http2.ts +605 -6
  242. package/src/providers/integrations/cursor/cursor-request.ts +26 -12
  243. package/src/providers/integrations/cursor/cursor-shared.ts +8 -5
  244. package/src/providers/integrations/cursor/cursor.ts +574 -110
  245. package/src/providers/integrations/cursor/protocol/messages.ts +22 -29
  246. package/src/providers/integrations/cursor/protocol/protobuf-schema.ts +37 -0
  247. package/src/providers/integrations/deepai/deepai-catalog.ts +149 -0
  248. package/src/providers/integrations/deepai/deepai-common.ts +145 -0
  249. package/src/providers/integrations/deepai/deepai-oauth.ts +129 -0
  250. package/src/providers/integrations/deepai/deepai-quota.ts +97 -0
  251. package/src/providers/integrations/deepai/provider.ts +42 -0
  252. package/src/providers/integrations/devin/devin-auth.ts +7 -0
  253. package/src/providers/integrations/devin/protocol/devin-proto.ts +1 -27
  254. package/src/providers/integrations/factory/factory-oauth.ts +33 -51
  255. package/src/providers/integrations/freebuff/assets/official-system-manager.txt +88 -0
  256. package/src/providers/integrations/freebuff/assets/official-system-worker.txt +57 -0
  257. package/src/providers/integrations/freebuff/assets/official-tools.json +1070 -0
  258. package/src/providers/integrations/freebuff/freebuff-catalog.ts +120 -0
  259. package/src/providers/integrations/freebuff/freebuff-constants.ts +1233 -0
  260. package/src/providers/integrations/freebuff/freebuff-discovery.ts +108 -0
  261. package/src/providers/integrations/freebuff/freebuff-oauth.ts +240 -0
  262. package/src/providers/integrations/freebuff/freebuff-quota.ts +260 -0
  263. package/src/providers/integrations/freebuff/freebuff-virtual.ts +89 -0
  264. package/src/providers/integrations/freebuff/freebuff.ts +682 -0
  265. package/src/providers/integrations/freepi/freepi-catalog.ts +5 -0
  266. package/src/providers/integrations/freepi/freepi-discovery.ts +2 -2
  267. package/src/providers/integrations/freepi/freepi-headers.ts +2 -2
  268. package/src/providers/integrations/freepi/freepi-protocol.ts +11 -2
  269. package/src/providers/integrations/freepi/freepi-realm.ts +0 -3
  270. package/src/providers/integrations/freepi/freepi-session.ts +158 -0
  271. package/src/providers/integrations/freepi/freepi.ts +80 -54
  272. package/src/providers/integrations/github/github-discovery.ts +30 -13
  273. package/src/providers/integrations/github/github-oauth.ts +217 -44
  274. package/src/providers/integrations/github/github-quota.ts +22 -5
  275. package/src/providers/integrations/github/github.ts +40 -32
  276. package/src/providers/integrations/grok/grok-oauth.ts +52 -49
  277. package/src/providers/integrations/grok/grok-ratelimit-store.ts +10 -17
  278. package/src/providers/integrations/grok/grok-turn-index.ts +11 -16
  279. package/src/providers/integrations/hermes/hermes-oauth.ts +3 -3
  280. package/src/providers/integrations/{hermes.ts → hermes/hermes.ts} +42 -13
  281. package/src/providers/integrations/hermes/index.ts +2 -0
  282. package/src/providers/integrations/kilo/kilo-oauth.ts +4 -4
  283. package/src/providers/integrations/kilo/kilo.ts +1 -1
  284. package/src/providers/integrations/kimi/kimi-oauth.ts +3 -3
  285. package/src/providers/integrations/kiro/kiro-catalog.ts +17 -1
  286. package/src/providers/integrations/kiro/kiro-discovery.ts +10 -12
  287. package/src/providers/integrations/kiro/kiro-oauth.ts +2 -2
  288. package/src/providers/integrations/kiro/kiro-quota.ts +8 -4
  289. package/src/providers/integrations/kiro/kiro.ts +15 -19
  290. package/src/providers/integrations/muse/muse-oauth.ts +5 -5
  291. package/src/providers/integrations/ollamacloud/index.ts +2 -0
  292. package/src/providers/integrations/{ollamacloud-models.ts → ollamacloud/models.ts} +2 -2
  293. package/src/providers/integrations/{ollamacloud-quota.ts → ollamacloud/quota.ts} +3 -3
  294. package/src/providers/integrations/opencode/fingerprint.ts +1 -1
  295. package/src/providers/integrations/opencode/opencode-go-quota.ts +2 -8
  296. package/src/providers/integrations/openrouter/provider.ts +1 -1
  297. package/src/providers/integrations/perch/perch-credential.ts +25 -0
  298. package/src/providers/integrations/perch/perch-protocol.ts +0 -6
  299. package/src/providers/integrations/perch/perch-quota.ts +2 -16
  300. package/src/providers/integrations/perch/perch.ts +6 -16
  301. package/src/providers/integrations/qoder/claim-qoder-credits.ts +19 -60
  302. package/src/providers/integrations/qoder/qoder-adapter.ts +20 -125
  303. package/src/providers/integrations/qoder/qoder-auth.ts +109 -30
  304. package/src/providers/integrations/qoder/qoder-catalog.ts +21 -6
  305. package/src/providers/integrations/qoder/qoder-chat.ts +32 -29
  306. package/src/providers/integrations/qoder/qoder-checkin.ts +5 -5
  307. package/src/providers/integrations/qoder/qoder-cosy.ts +37 -9
  308. package/src/providers/integrations/qoder/qoder-oauth.ts +9 -2
  309. package/src/providers/integrations/qoder/qoder-realm.ts +13 -36
  310. package/src/providers/integrations/qoder/qoder-sse.ts +447 -68
  311. package/src/providers/integrations/qoder/qoder-types.ts +9 -0
  312. package/src/providers/integrations/qoder/qoder.ts +3 -26
  313. package/src/providers/integrations/sensenova/provider.ts +144 -0
  314. package/src/providers/integrations/trae/trae-protocol.ts +9 -5
  315. package/src/providers/integrations/trae/trae-quota.ts +21 -29
  316. package/src/providers/integrations/trae/trae-realm.ts +38 -0
  317. package/src/providers/integrations/trae/trae.ts +7 -24
  318. package/src/providers/integrations/vercel/provider.ts +117 -0
  319. package/src/providers/integrations/vercel/vercel-quota.ts +96 -0
  320. package/src/providers/integrations/xai/xai-oauth.ts +5 -5
  321. package/src/providers/integrations/zcode-start-plan/gifts.ts +1 -1
  322. package/src/providers/integrations/zcode-start-plan/oauth.ts +3 -3
  323. package/src/providers/integrations/zcode-start-plan/provider.ts +226 -23
  324. package/src/providers/integrations/zcode-start-plan/quota.ts +19 -2
  325. package/src/providers/integrations/zro/zro.ts +205 -0
  326. package/src/providers/operations/account-error-classification.ts +199 -307
  327. package/src/providers/operations/account-health-service.ts +82 -1
  328. package/src/providers/operations/account-refresh-status.ts +36 -37
  329. package/src/providers/operations/account-tier.ts +15 -16
  330. package/src/providers/operations/client-version-resolver.ts +1 -1
  331. package/src/providers/operations/client-versions.ts +100 -81
  332. package/src/providers/operations/cooldown-rules.ts +11 -16
  333. package/src/providers/operations/oauth-refresh-lead.ts +46 -22
  334. package/src/providers/operations/{model-catalog-cache.ts → provider-caches.ts} +68 -16
  335. package/src/providers/operations/provider-catalog-service.ts +1 -1
  336. package/src/providers/operations/provider-credential-service.ts +118 -51
  337. package/src/providers/operations/provider-rules/github.ts +48 -0
  338. package/src/providers/operations/provider-rules/grok.ts +33 -0
  339. package/src/providers/operations/provider-rules/inception.ts +49 -0
  340. package/src/providers/operations/provider-rules/index.ts +32 -0
  341. package/src/providers/operations/provider-rules/perch.ts +37 -0
  342. package/src/providers/operations/provider-rules/qoder.ts +70 -0
  343. package/src/providers/operations/provider-rules/trae.ts +81 -0
  344. package/src/providers/operations/session-resolution.ts +17 -1
  345. package/src/providers/provider-contracts.ts +6 -4
  346. package/src/providers/{provider-credential-resolver.ts → provider-credentials.ts} +40 -3
  347. package/src/providers/provider-metadata.ts +70 -10
  348. package/src/providers/provider-probe.ts +15 -1
  349. package/src/providers/provider-registry.ts +42 -33
  350. package/src/providers/quota/quota-contracts.ts +2 -0
  351. package/src/providers/quota/quota-limit-windows.ts +16 -5
  352. package/src/providers/quota/quota-support.ts +1 -1
  353. package/src/providers/quota/quota-window-parser.ts +90 -18
  354. package/src/providers/quota/refresh.ts +100 -21
  355. package/src/security/api-key-auth-cache.ts +1 -1
  356. package/src/security/api-key-auth.ts +6 -2
  357. package/src/security/ip-boundary.ts +1 -1
  358. package/src/transport/dispatch/attempt-finalize.ts +15 -14
  359. package/src/transport/dispatch/attempt-loop.ts +73 -19
  360. package/src/transport/dispatch/generation.ts +2 -8
  361. package/src/transport/dispatch/handler-deps.ts +1 -1
  362. package/src/transport/dispatch/leases.ts +1 -1
  363. package/src/transport/dispatch/native-shared.ts +25 -0
  364. package/src/transport/dispatch/proxy-request.ts +8 -46
  365. package/src/transport/dispatch/responses-compact.ts +2 -8
  366. package/src/transport/dispatch/retry-policy.ts +1 -1
  367. package/src/transport/dispatch/streaming/finalize.ts +10 -7
  368. package/src/transport/dispatch/streaming/stream.ts +9 -37
  369. package/src/transport/dispatch/systemone.ts +2 -8
  370. package/src/transport/dispatch/token-count.ts +2 -6
  371. package/src/transport/dispatch/upstream.ts +63 -0
  372. package/src/transport/drain-endpoint.ts +31 -4
  373. package/src/transport/failure-policy.ts +16 -30
  374. package/src/transport/guards/body-policy.ts +7 -1
  375. package/src/transport/guards/error-lifecycle.ts +13 -1
  376. package/src/transport/guards/request-context.ts +22 -14
  377. package/src/transport/request/preparer.ts +81 -71
  378. package/src/transport/routing/bounded-lru.ts +14 -0
  379. package/src/transport/routing/drain-reserve.ts +129 -0
  380. package/src/transport/routing/plan-gate.ts +7 -1
  381. package/src/transport/routing/round-robin.ts +60 -0
  382. package/src/transport/routing/route-catalog.ts +123 -111
  383. package/src/transport/routing/route-model.ts +51 -9
  384. package/src/transport/routing/router.ts +393 -32
  385. package/src/transport/shutdown-notice.ts +1 -1
  386. package/src/transport/surface/adapters.ts +11 -2
  387. package/src/transport/surface/chat/adapter.ts +2 -2
  388. package/src/transport/surface/chat/encode.ts +47 -4
  389. package/src/transport/surface/chat/parse.ts +2 -12
  390. package/src/transport/surface/completion.ts +44 -33
  391. package/src/transport/surface/content-parts.ts +21 -0
  392. package/src/transport/surface/messages/adapter.ts +7 -1
  393. package/src/transport/surface/messages/encode.ts +11 -3
  394. package/src/transport/surface/messages/parse.ts +2 -1
  395. package/src/transport/surface/messages/stream.ts +33 -17
  396. package/src/transport/surface/responses/encode.ts +22 -5
  397. package/src/transport/surface/responses/parse.ts +3 -11
  398. package/src/workers/buddy-growth-tasks.ts +8 -8
  399. package/src/workers/daily-checkin.ts +4 -4
  400. package/src/workers/quota-refresh-sweep.ts +1 -1
  401. package/src/workers/zcode-gift-claim.ts +1 -1
  402. package/dist/dashboard/assets/BannedPage-BxoG1MrL.js.gz +0 -0
  403. package/dist/dashboard/assets/CliToolDetailPage-ixwgKk53.js.gz +0 -0
  404. package/dist/dashboard/assets/CliToolsPage-BmttNV3U.js.gz +0 -0
  405. package/dist/dashboard/assets/CombosPage-BE3qwwfC.js.gz +0 -0
  406. package/dist/dashboard/assets/ConsoleLogPage-CRZdmMIX.js.gz +0 -0
  407. package/dist/dashboard/assets/CustomizationPage-Dv_FJ6Er.js.gz +0 -0
  408. package/dist/dashboard/assets/HealthEventsModal-CoVrw2sM.js +0 -1
  409. package/dist/dashboard/assets/HealthEventsModal-CoVrw2sM.js.gz +0 -0
  410. package/dist/dashboard/assets/InjectSystemPromptPanel-BOoO8rpz.js.gz +0 -0
  411. package/dist/dashboard/assets/LoginPage-ChJuNNVN.js.gz +0 -0
  412. package/dist/dashboard/assets/ModelPicker-BZAJtPg1.js.gz +0 -0
  413. package/dist/dashboard/assets/OverviewPage-BE40s3u5.js.gz +0 -0
  414. package/dist/dashboard/assets/ProviderDetailPage-sfLoQtPV.js +0 -8
  415. package/dist/dashboard/assets/ProviderDetailPage-sfLoQtPV.js.gz +0 -0
  416. package/dist/dashboard/assets/ProviderIcon-CQ6bPUf_.js.gz +0 -0
  417. package/dist/dashboard/assets/ProvidersPage-DcepmPWo.js +0 -1
  418. package/dist/dashboard/assets/ProvidersPage-DcepmPWo.js.gz +0 -0
  419. package/dist/dashboard/assets/ProxyPage-BJ87Pp0U.js +0 -9
  420. package/dist/dashboard/assets/ProxyPage-BJ87Pp0U.js.gz +0 -0
  421. package/dist/dashboard/assets/QuotaPage-gkSyRAKa.js +0 -1
  422. package/dist/dashboard/assets/QuotaPage-gkSyRAKa.js.gz +0 -0
  423. package/dist/dashboard/assets/SettingsPage-C5HPWqEv.js.gz +0 -0
  424. package/dist/dashboard/assets/SetupPage-CFNcATJJ.js.gz +0 -0
  425. package/dist/dashboard/assets/StudioPage-YoD4tY5l.js.gz +0 -0
  426. package/dist/dashboard/assets/UsagePage-DxjaAhb_.js.gz +0 -0
  427. package/dist/dashboard/assets/api-keys-BTlkq_Uk.js.gz +0 -0
  428. package/dist/dashboard/assets/app-BX2nnKqs.css +0 -2
  429. package/dist/dashboard/assets/app-BX2nnKqs.css.gz +0 -0
  430. package/dist/dashboard/assets/assert-CndthXFQ.js +0 -1
  431. package/dist/dashboard/assets/assert-CndthXFQ.js.gz +0 -0
  432. package/dist/dashboard/assets/badge-DdbT_7Am.js.gz +0 -0
  433. package/dist/dashboard/assets/banner-CsGN-nbm.js.gz +0 -0
  434. package/dist/dashboard/assets/card-mgZ_TLLZ.js.gz +0 -0
  435. package/dist/dashboard/assets/cli-tools-A1-v8-03.js.gz +0 -0
  436. package/dist/dashboard/assets/clipboard-button-CJ4Zty89.js.gz +0 -0
  437. package/dist/dashboard/assets/dialog-B5L2jPQ_.js.gz +0 -0
  438. package/dist/dashboard/assets/drawer-DkjUouAj.js.gz +0 -0
  439. package/dist/dashboard/assets/entry-B-LVLV6o.js.gz +0 -0
  440. package/dist/dashboard/assets/entry-CAhdYl3B.js.gz +0 -0
  441. package/dist/dashboard/assets/entry-D2xD0Tmd.js +0 -4
  442. package/dist/dashboard/assets/entry-D2xD0Tmd.js.gz +0 -0
  443. package/dist/dashboard/assets/formatters-CrsdLVsn.js.gz +0 -0
  444. package/dist/dashboard/assets/index-BU64Lqvp.js.gz +0 -0
  445. package/dist/dashboard/assets/inline-B2aDLyyg.js.gz +0 -0
  446. package/dist/dashboard/assets/input-BCVkdR9d.js.gz +0 -0
  447. package/dist/dashboard/assets/layout-DNcAdMK-.js.gz +0 -0
  448. package/dist/dashboard/assets/list-row-DgrIH0hw.js.gz +0 -0
  449. package/dist/dashboard/assets/live-Cae01iu8.js.gz +0 -0
  450. package/dist/dashboard/assets/network-CRib7H_2.js.gz +0 -0
  451. package/dist/dashboard/assets/numbers-BKQE8Xpz.js.gz +0 -0
  452. package/dist/dashboard/assets/pagination-ecPvG_8g.js.gz +0 -0
  453. package/dist/dashboard/assets/quota-DJ1QlAOq.js +0 -1
  454. package/dist/dashboard/assets/quota-DJ1QlAOq.js.gz +0 -0
  455. package/dist/dashboard/assets/routing-Ckm1UXuC.js.gz +0 -0
  456. package/dist/dashboard/assets/select-ChoFWyKz.js.gz +0 -0
  457. package/dist/dashboard/assets/settings-CKjFPlKW.js.gz +0 -0
  458. package/dist/dashboard/assets/stack-DWCwU3fh.js.gz +0 -0
  459. package/dist/dashboard/assets/state-Cg3VL5J_.js.gz +0 -0
  460. package/dist/dashboard/assets/switch-Db70BMix.js.gz +0 -0
  461. package/dist/dashboard/assets/useMutation-BqdE0LuM.js.gz +0 -0
  462. package/src/network/pool-health.ts +0 -210
  463. package/src/providers/bundled-discovery-providers.ts +0 -98
  464. package/src/providers/configured-openai-providers.ts +0 -120
  465. package/src/providers/integrations/buddy/buddy-checkin.ts +0 -521
  466. package/src/providers/integrations/buddy/buddy-cli-headers.ts +0 -76
  467. package/src/providers/integrations/buddy/buddy-conversation-headers.ts +0 -130
  468. package/src/providers/integrations/buddy/buddy-discovery-shared.ts +0 -234
  469. package/src/providers/integrations/buddy/buddy-growth-shared.ts +0 -496
  470. package/src/providers/integrations/buddy/buddy-identity.ts +0 -300
  471. package/src/providers/integrations/buddy/buddy-oauth-shared.ts +0 -341
  472. package/src/providers/integrations/buddy/buddy-quota-shared.ts +0 -417
  473. package/src/providers/integrations/buddy/buddy-server-tools.ts +0 -240
  474. package/src/providers/integrations/buddy/buddy-usage-shared.ts +0 -221
  475. package/src/providers/integrations/buddy/buddy-usage-store.ts +0 -181
  476. package/src/providers/integrations/buddy/codebuddy/cn-catalog.ts +0 -37
  477. package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +0 -185
  478. package/src/providers/integrations/buddy/codebuddy/oauth.ts +0 -47
  479. package/src/providers/integrations/buddy/codebuddy/provider.ts +0 -175
  480. package/src/providers/integrations/buddy/codebuddy/quota.ts +0 -154
  481. package/src/providers/integrations/qoder/chat-proto.ts +0 -328
  482. package/src/providers/integrations/qoder/qoder-grpc.ts +0 -871
  483. package/src/providers/integrations/qoder/qoder-ide.ts +0 -588
  484. package/src/providers/operations/model-discovery-cache.ts +0 -34
  485. package/src/providers/operations/probe-fetch.ts +0 -15
  486. package/src/providers/operations/provider-version-cache.ts +0 -30
  487. package/src/providers/provider-capabilities.ts +0 -33
  488. package/src/providers/provider-credential-envelope.ts +0 -43
  489. /package/dist/dashboard/assets/{app-B7kIWFm5.js → app-C0gTXEoN.js} +0 -0
  490. /package/dist/dashboard/assets/{app-B7kIWFm5.js.gz → app-C0gTXEoN.js.gz} +0 -0
  491. /package/src/network/{http2-bidi.ts → bidi.ts} +0 -0
  492. /package/src/network/pool/{pool-scripts.ts → scripts.ts} +0 -0
  493. /package/src/network/pool/{pool-state.ts → state.ts} +0 -0
  494. /package/src/network/{backoff.ts → util/backoff.ts} +0 -0
  495. /package/src/network/{deduplication.ts → util/dedupe.ts} +0 -0
  496. /package/src/network/{ip-utils.ts → util/ip.ts} +0 -0
@@ -15,6 +15,8 @@
15
15
  * independent: retain the balance or subscription when the other is unavailable.
16
16
  */
17
17
  import type { FetchLike, ProviderQuotaResult, ProviderQuotaWindow } from "../../quota/quota-contracts";
18
+ import { isoDate } from "../../quota/quota-contracts";
19
+ import { asCoercedNumber, asRecord } from "../../../shared/coerce";
18
20
 
19
21
  const COMMANDCODE_API_BASE = "https://api.commandcode.ai" as const;
20
22
  const REQUEST_TIMEOUT_MS = 15_000;
@@ -73,29 +75,21 @@ async function readJson(
73
75
  }
74
76
  }
75
77
 
76
- function recordValue(value: unknown): Record<string, unknown> | undefined {
77
- return typeof value === "object" && value !== null && !Array.isArray(value)
78
- ? (value as Record<string, unknown>)
79
- : undefined;
80
- }
81
-
78
+ /** Numeric value coerced via the shared helper, or `null` (shared sentinel). */
82
79
  function numberOrNull(value: unknown): number | null {
83
- if (typeof value === "number" && Number.isFinite(value)) return value;
84
- if (typeof value === "string" && value.trim() && Number.isFinite(Number(value))) {
85
- return Number(value);
86
- }
87
- return null;
80
+ return asCoercedNumber(value) ?? null;
88
81
  }
89
82
 
83
+ /**
84
+ * ISO timestamp from a numeric epoch (seconds vs ms via the 1e12 boundary) or
85
+ * a parseable date string, else `null` — the shared `isoDate` semantics. The
86
+ * one local delta kept: a non-positive numeric is `null` (no deadline) rather
87
+ * than an epoch 0/negative instant.
88
+ */
90
89
  function isoTimestamp(value: unknown): string | null {
91
90
  const numeric = numberOrNull(value);
92
- if (numeric !== null) {
93
- if (numeric <= 0) return null;
94
- const date = new Date(numeric > 1_000_000_000_000 ? numeric : numeric * 1000);
95
- return Number.isFinite(date.getTime()) ? date.toISOString() : null;
96
- }
97
- if (typeof value !== "string" || !Number.isFinite(Date.parse(value))) return null;
98
- return new Date(value).toISOString();
91
+ if (numeric !== null && numeric <= 0) return null;
92
+ return isoDate(value);
99
93
  }
100
94
 
101
95
  function withQuery(path: string, params: Readonly<Record<string, string | null>>): string {
@@ -149,8 +143,8 @@ function windowLimits(
149
143
  limits: Record<string, unknown>,
150
144
  ): readonly ProviderQuotaWindow[] {
151
145
  const out: ProviderQuotaWindow[] = [];
152
- const fiveHour = recordValue(limits["fiveHour"]);
153
- const weekly = recordValue(limits["weekly"]);
146
+ const fiveHour = asRecord(limits["fiveHour"]);
147
+ const weekly = asRecord(limits["weekly"]);
154
148
  const push = (source: Record<string, unknown> | undefined, kind: string, label: string) => {
155
149
  if (source === undefined) return;
156
150
  const used = numberOrNull(source["used"]) ?? 0;
@@ -191,9 +185,9 @@ export async function fetchCommandCodeQuota(
191
185
  };
192
186
  }
193
187
 
194
- const whoamiBody = whoami.ok ? recordValue(whoami.value) : undefined;
195
- const user = recordValue(whoamiBody?.["user"]);
196
- const organization = recordValue(whoamiBody?.["org"]);
188
+ const whoamiBody = whoami.ok ? asRecord(whoami.value) : undefined;
189
+ const user = asRecord(whoamiBody?.["user"]);
190
+ const organization = asRecord(whoamiBody?.["org"]);
197
191
  const orgId = typeof organization?.["id"] === "string" ? organization["id"] : null;
198
192
  const accountLabel =
199
193
  (typeof user?.["email"] === "string" && user["email"]) ||
@@ -215,8 +209,8 @@ export async function fetchCommandCodeQuota(
215
209
  };
216
210
  }
217
211
 
218
- const subscriptionBody = subscriptionRaw.ok ? recordValue(subscriptionRaw.value) : undefined;
219
- const planRecord = recordValue(subscriptionBody?.["data"]);
212
+ const subscriptionBody = subscriptionRaw.ok ? asRecord(subscriptionRaw.value) : undefined;
213
+ const planRecord = asRecord(subscriptionBody?.["data"]);
220
214
  const planId = typeof planRecord?.["planId"] === "string" ? planRecord["planId"] : null;
221
215
  const parsedPlan = planId === null ? null : commandCodePlan(planId);
222
216
  const plan =
@@ -225,12 +219,12 @@ export async function fetchCommandCodeQuota(
225
219
  (creditsRaw.ok ? "Credits" : null);
226
220
  const periodEnd = isoTimestamp(planRecord?.["currentPeriodEnd"]);
227
221
 
228
- const creditsBody = creditsRaw.ok ? recordValue(creditsRaw.value) : undefined;
222
+ const creditsBody = creditsRaw.ok ? asRecord(creditsRaw.value) : undefined;
229
223
  const windows: ProviderQuotaWindow[] = [];
230
224
  if (creditsBody !== undefined) {
231
- const credits = recordValue(creditsBody["credits"]);
225
+ const credits = asRecord(creditsBody["credits"]);
232
226
  if (credits !== undefined) windows.push(...creditWindows(credits, parsedPlan?.cap ?? null, periodEnd));
233
- const limits = recordValue(creditsBody["windowLimits"]);
227
+ const limits = asRecord(creditsBody["windowLimits"]);
234
228
  if (limits !== undefined) windows.push(...windowLimits(limits));
235
229
  }
236
230
 
@@ -41,7 +41,6 @@ import {
41
41
  CURSOR_WEBSITE_URL,
42
42
  SESSION_REFRESH_TIMEOUT_MS,
43
43
  SIGN_IN_POLICY_VIOLATION,
44
- TOKEN_EXPIRY_THRESHOLD_S,
45
44
  isExchangeableApiKey,
46
45
  } from "./cursor-shared";
47
46
 
@@ -92,13 +91,6 @@ export function decodeJwtExpiryMs(token: string): number | undefined {
92
91
  return exp * 1000;
93
92
  }
94
93
 
95
- /** True when a JWT expires within the refresh threshold. */
96
- export function isExpiringSoon(token: string, thresholdSeconds = TOKEN_EXPIRY_THRESHOLD_S): boolean {
97
- const expiry = decodeJwtExpiryMs(token);
98
- if (expiry === undefined) return false;
99
- return expiry - Date.now() < thresholdSeconds * 1000;
100
- }
101
-
102
94
  /**
103
95
  * The account identity Cursor itself asserts, from the access token's `sub`.
104
96
  *
@@ -287,7 +279,7 @@ export class CursorOAuthClient extends OAuthDeviceFlow {
287
279
  `${CURSOR_API_BASE_URL}/auth/poll?uuid=${encodeURIComponent(deviceAuthId)}` +
288
280
  `&verifier=${encodeURIComponent(state.verifier)}`;
289
281
  const outcome = await fetchJson(
290
- asFetchFn(this.fetchFn),
282
+ asFetchFn(this.fetchFor(context)),
291
283
  url,
292
284
  { method: "GET", headers: { accept: "application/json" } },
293
285
  AUTH_REQUEST_TIMEOUT_MS,
@@ -389,15 +389,22 @@ function globFiles(args: Record<string, unknown>, root: string): Record<string,
389
389
  return { files: out };
390
390
  }
391
391
 
392
- /** Minimal glob matcher: `*` (within a segment), `**` (any depth), `?`. */
392
+ /**
393
+ * Minimal glob matcher: `*` (within a segment), `**` (any depth), `?`.
394
+ * The value is normalized to forward slashes first, so a Windows `\` path
395
+ * matches exactly like a POSIX `/` path — otherwise `*.ts` matches
396
+ * `src\a.ts` on Windows but not `src/a.ts`, and the same pattern behaves
397
+ * differently depending on which separator `relative()` happened to emit.
398
+ */
393
399
  function simpleGlobMatch(pattern: string, value: string): boolean {
400
+ const normalized = value.replace(/\\/g, "/");
394
401
  const re = pattern
395
402
  .replace(/[.+^${}()|[\]\\]/g, "\\$&")
396
403
  .replace(/\*\*/g, "__GLOBSTAR__")
397
404
  .replace(/\*/g, "[^/]*")
398
405
  .replace(/__GLOBSTAR__/g, ".*")
399
406
  .replace(/\?/g, ".");
400
- return new RegExp(`^${re}$`).test(value);
407
+ return new RegExp(`^${re}$`).test(normalized);
401
408
  }
402
409
 
403
410
  function grepFiles(args: Record<string, unknown>, root: string, pi: boolean): Record<string, unknown> {
@@ -0,0 +1,279 @@
1
+ // Cursor Run hardening, adapted end-to-end from oh-my-pi's streamCursorWithWireMode.
2
+ //
3
+ // The wire opens in cursor-http2.ts; the lifecycle lives in the adapter. These
4
+ // are the policies that make a tool loop reliable: classify a transport
5
+ // failure once (a model-not-found is never retried, an HTTP/2 block is never
6
+ // retried as HTTP/2), keep checkpoint/exec accounting across a stream's
7
+ // exits, and drain async handlers on BOTH exits before anything is finalized.
8
+ import { GatewayError } from "../../../protocol/gateway-error";
9
+
10
+ /** One decoded frame's shape — no text, tokens, ids, or arguments. */
11
+ export interface CursorFrameShape {
12
+ readonly at: number;
13
+ readonly kind: string;
14
+ readonly fields: readonly number[];
15
+ readonly size: number;
16
+ }
17
+
18
+ /** The last checkpoint a Run reported, and the calls it owns. */
19
+ export interface CursorCheckpointState {
20
+ /** Checkpoint number in this Run. */
21
+ index: number;
22
+ /** Checkpoint number within its step. */
23
+ step: number;
24
+ /** Consecutive checkpoints with no semantic frame between them. */
25
+ streak: number;
26
+ /** Shapes of the frames preceding the last checkpoint. */
27
+ kinds: readonly string[];
28
+ /** Opaque bytes to resume from, when the Run must be rebuilt. */
29
+ bytes: Uint8Array | undefined;
30
+ /** Calls the server requested but this client has not answered. */
31
+ pendingCallIds: Set<string>;
32
+ /** Calls the server already counted: never re-submit these. */
33
+ completedCallIds: Set<string>;
34
+ /** Calls Cursor served itself, already in its own tool count. */
35
+ serverOwnedCount: number;
36
+ /** `tool_requests_listed.call_count`, when the edge declared it. */
37
+ expectedCallCount: number | undefined;
38
+ /** Calls this client dispatched to its executor. */
39
+ dispatchedCount: number;
40
+ }
41
+
42
+ export function createCheckpointState(): CursorCheckpointState {
43
+ return {
44
+ index: 0,
45
+ step: 0,
46
+ streak: 0,
47
+ kinds: [],
48
+ bytes: undefined,
49
+ pendingCallIds: new Set<string>(),
50
+ completedCallIds: new Set<string>(),
51
+ serverOwnedCount: 0,
52
+ expectedCallCount: undefined,
53
+ dispatchedCount: 0,
54
+ };
55
+ }
56
+
57
+ /** The first meaningful key of a decoded AgentServerMessage, for traces. */
58
+ export function frameKindOf(message: Record<string, unknown>): string {
59
+ const keys = Object.keys(message).filter((key) => message[key] !== undefined && key !== "__bytes");
60
+ return keys[0] ?? "unknown";
61
+ }
62
+
63
+ /** Shape-only trace entry: sizes and timings, never payload text or ids. */
64
+ export function frameShapeOf(message: Record<string, unknown>, at = Date.now()): CursorFrameShape {
65
+ const bytes = message["__bytes"] instanceof Uint8Array ? (message["__bytes"] as Uint8Array) : undefined;
66
+ return {
67
+ at,
68
+ kind: frameKindOf(message),
69
+ fields: bytes === undefined ? [] : topLevelFieldNumbers(bytes),
70
+ size: bytes?.byteLength ?? 0,
71
+ };
72
+ }
73
+
74
+ /** Top-level protobuf field numbers of one decoded frame's raw bytes. */
75
+ export function topLevelFieldNumbers(bytes: Uint8Array): number[] {
76
+ const numbers: number[] = [];
77
+ let at = 0;
78
+ while (at < bytes.byteLength && numbers.length < 64) {
79
+ let tag = 0;
80
+ let shift = 0;
81
+ for (;;) {
82
+ if (at >= bytes.byteLength) return numbers;
83
+ const byte = bytes[at] ?? 0;
84
+ at += 1;
85
+ tag |= (byte & 0x7f) << shift;
86
+ if ((byte & 0x80) === 0) break;
87
+ shift += 7;
88
+ if (shift > 35) return numbers;
89
+ }
90
+ const field = tag >>> 3;
91
+ if (field > 0) numbers.push(field);
92
+ const wire = tag & 7;
93
+ if (wire === 0) {
94
+ while (at < bytes.byteLength && ((bytes[at] ?? 0) & 0x80) !== 0) at += 1;
95
+ at += 1;
96
+ } else if (wire === 1) at += 8;
97
+ else if (wire === 2) {
98
+ let length = 0;
99
+ shift = 0;
100
+ for (;;) {
101
+ if (at >= bytes.byteLength) return numbers;
102
+ const byte = bytes[at] ?? 0;
103
+ at += 1;
104
+ length |= (byte & 0x7f) << shift;
105
+ if ((byte & 0x80) === 0) break;
106
+ shift += 7;
107
+ if (shift > 35) return numbers;
108
+ }
109
+ at += length;
110
+ } else if (wire === 5) at += 4;
111
+ else return numbers;
112
+ }
113
+ return numbers;
114
+ }
115
+
116
+ /** Max in-memory shape-only trace entries before a failed Run is flushed. */
117
+ export const CURSOR_WIRE_TRACE_MAX = 256;
118
+ /** Opt-in: `CARTETHYIA_CURSOR_WIRE_TRACE=1`. Shape only; never payload text. */
119
+ export function wireTraceEnabled(): boolean {
120
+ return process.env.CARTETHYIA_CURSOR_WIRE_TRACE === "1";
121
+ }
122
+
123
+ /** The "went quiet" error, naming the last checkpoint (donor 0.2.34). */
124
+ export function cursorQuietError(checkpoint: CursorCheckpointState | undefined): GatewayError {
125
+ if (checkpoint === undefined || checkpoint.index === 0) {
126
+ return new GatewayError(
127
+ "platform_unavailable",
128
+ 502,
129
+ "Cursor Run went quiet before any checkpoint (request {requestId}). The upstream came back empty-handed — retry 🌙",
130
+ { providerId: "cursor", kind: "quiet" },
131
+ "upstream",
132
+ );
133
+ }
134
+ return new GatewayError(
135
+ "platform_unavailable",
136
+ 502,
137
+ `Cursor Run went quiet at checkpoint ${checkpoint.index} (step checkpoint #${checkpoint.step}, ` +
138
+ `${checkpoint.streak} in a row; preceded by ${checkpoint.kinds.join(", ") || "no frames"}) (request {requestId}). ` +
139
+ "The upstream came back empty-handed — retry 🌙",
140
+ { providerId: "cursor", kind: "quiet", checkpointIndex: checkpoint.index },
141
+ "upstream",
142
+ );
143
+ }
144
+
145
+ /** Structured failure kinds, mapped once from an upstream error. */
146
+ export type CursorFailureKind =
147
+ | "model_not_found"
148
+ | "conversation_rejected"
149
+ | "resource_exhausted"
150
+ | "not_implemented"
151
+ | "h2_blocked"
152
+ | "quiet"
153
+ | "transport"
154
+ | "authentication"
155
+ | "fatal";
156
+
157
+ export interface CursorFailureClassification {
158
+ readonly kind: CursorFailureKind;
159
+ readonly retryable: boolean;
160
+ readonly fallbackH1: boolean;
161
+ readonly rotateConversation: boolean;
162
+ }
163
+
164
+ /** Donor patterns (cursor.ts L381-L405). */
165
+ const MODEL_NOT_FOUND = /^(?:Connect error not_found:|gRPC error 5:)|AI Model Not Found/i;
166
+ const RESOURCE_EXHAUSTED = /resource.?exhausted/i;
167
+ const CONVERSATION_REJECTED = /conversation.*(rejected|conflict|stale|not found)|store conflict/i;
168
+ const NOT_IMPLEMENTED = /not implemented by this client$/i;
169
+
170
+ export function classifyCursorFailure(error: unknown, transport: "http2" | "http1"): CursorFailureClassification {
171
+ if (error instanceof GatewayError) {
172
+ if (error.code === "authentication_failed") {
173
+ return { kind: "authentication", retryable: false, fallbackH1: false, rotateConversation: false };
174
+ }
175
+ if (error.code === "quota_exceeded" || RESOURCE_EXHAUSTED.test(error.message)) {
176
+ return { kind: "resource_exhausted", retryable: false, fallbackH1: false, rotateConversation: false };
177
+ }
178
+ if (MODEL_NOT_FOUND.test(error.message)) {
179
+ return { kind: "model_not_found", retryable: false, fallbackH1: false, rotateConversation: false };
180
+ }
181
+ if (error.code === "invalid_request") {
182
+ return { kind: "fatal", retryable: false, fallbackH1: false, rotateConversation: false };
183
+ }
184
+ if (error.details["kind"] === "quiet") {
185
+ return { kind: "quiet", retryable: true, fallbackH1: false, rotateConversation: false };
186
+ }
187
+ }
188
+ const message = error instanceof Error ? error.message : String(error);
189
+ if (MODEL_NOT_FOUND.test(message)) {
190
+ return { kind: "model_not_found", retryable: false, fallbackH1: false, rotateConversation: false };
191
+ }
192
+ if (CONVERSATION_REJECTED.test(message)) {
193
+ return { kind: "conversation_rejected", retryable: true, fallbackH1: false, rotateConversation: true };
194
+ }
195
+ if (RESOURCE_EXHAUSTED.test(message)) {
196
+ return { kind: "resource_exhausted", retryable: false, fallbackH1: false, rotateConversation: false };
197
+ }
198
+ if (NOT_IMPLEMENTED.test(message)) {
199
+ return { kind: "not_implemented", retryable: false, fallbackH1: false, rotateConversation: false };
200
+ }
201
+ if (/http\/?2|nghttp2|alpn|rst_stream|goaway|protocol error/i.test(message) && transport === "http2") {
202
+ return { kind: "h2_blocked", retryable: true, fallbackH1: true, rotateConversation: false };
203
+ }
204
+ if (/quiet|no server message|heartbeat/i.test(message)) {
205
+ return { kind: "quiet", retryable: true, fallbackH1: false, rotateConversation: false };
206
+ }
207
+ return { kind: "transport", retryable: true, fallbackH1: false, rotateConversation: false };
208
+ }
209
+
210
+ /**
211
+ * One settlement for a Run's transport: `end` / `error` / `timeout`,
212
+ * whichever arrives first. Late events are no-ops (donor settleH2).
213
+ */
214
+ export function createRunCompletion() {
215
+ let settle!: (reason: "end" | "error" | "timeout") => void;
216
+ const promise = new Promise<"end" | "error" | "timeout">((resolve) => {
217
+ settle = resolve;
218
+ });
219
+ let settled = false;
220
+ return {
221
+ promise,
222
+ settle(reason: "end" | "error" | "timeout"): boolean {
223
+ if (settled) return false;
224
+ settled = true;
225
+ settle(reason);
226
+ return true;
227
+ },
228
+ get settled(): boolean {
229
+ return settled;
230
+ },
231
+ };
232
+ }
233
+
234
+ /**
235
+ * Drains dispatched exec handlers on BOTH exits (donor L1198-L1233).
236
+ *
237
+ * A dispatch can spawn another, so the set is re-checked rather than awaited
238
+ * as one snapshot. The wait is bounded by the abort signal: an exec handler
239
+ * has no cancellation contract, and a hung tool must not hold the terminal
240
+ * event hostage after the caller gave up.
241
+ */
242
+ export async function drainInFlightDispatches(
243
+ dispatches: Set<Promise<void>>,
244
+ signal?: AbortSignal,
245
+ ): Promise<void> {
246
+ if (dispatches.size === 0 || signal?.aborted === true) return;
247
+ if (signal === undefined) {
248
+ while (dispatches.size > 0) await Promise.all(dispatches);
249
+ return;
250
+ }
251
+ let onAbort: (() => void) | undefined;
252
+ const aborted = new Promise<void>((resolve) => {
253
+ onAbort = resolve;
254
+ signal.addEventListener("abort", onAbort, { once: true });
255
+ });
256
+ try {
257
+ while (dispatches.size > 0 && !signal.aborted) {
258
+ await Promise.race([Promise.all(dispatches), aborted]);
259
+ }
260
+ } finally {
261
+ if (onAbort !== undefined) signal.removeEventListener("abort", onAbort);
262
+ }
263
+ }
264
+
265
+ /**
266
+ * A step ends when the server's own tool count covers the calls this client
267
+ * dispatched (donor/magpie 0.2.35): waiting out the heartbeats after that is
268
+ * what made a finished tool round look hung. Server-owned calls are already
269
+ * in the count and are never re-sent.
270
+ */
271
+ export function reconcileToolCount(
272
+ checkpoint: CursorCheckpointState,
273
+ serverToolCount: number,
274
+ ): { endStep: boolean; resend: string[] } {
275
+ const resend = [...checkpoint.pendingCallIds].filter((id) => !checkpoint.completedCallIds.has(id));
276
+ const expected = checkpoint.expectedCallCount ?? serverToolCount;
277
+ const counted = serverToolCount + checkpoint.serverOwnedCount;
278
+ return { endStep: counted >= Math.max(checkpoint.dispatchedCount, expected), resend };
279
+ }