cartethyia 2.7.8 → 2.8.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 (519) hide show
  1. package/.env.example +3 -3
  2. package/README.md +29 -59
  3. package/dist/dashboard/assets/BannedPage-Cc0vKpMG.js +1 -0
  4. package/dist/dashboard/assets/BannedPage-Cc0vKpMG.js.gz +0 -0
  5. package/dist/dashboard/assets/{CliToolDetailPage-BRWKPQPf.js → CliToolDetailPage-Bqj2aa1T.js} +1 -1
  6. package/dist/dashboard/assets/CliToolDetailPage-Bqj2aa1T.js.gz +0 -0
  7. package/dist/dashboard/assets/{CliToolsPage-BP-Y5iHN.js → CliToolsPage-CXsaOAO2.js} +1 -1
  8. package/dist/dashboard/assets/CliToolsPage-CXsaOAO2.js.gz +0 -0
  9. package/dist/dashboard/assets/CombosPage-BeLpJ4ma.js +1 -0
  10. package/dist/dashboard/assets/CombosPage-BeLpJ4ma.js.gz +0 -0
  11. package/dist/dashboard/assets/ConsoleLogPage-DnV0uZ3m.js +1 -0
  12. package/dist/dashboard/assets/ConsoleLogPage-DnV0uZ3m.js.gz +0 -0
  13. package/dist/dashboard/assets/CustomizationPage-CBxAjo63.js +1 -0
  14. package/dist/dashboard/assets/CustomizationPage-CBxAjo63.js.gz +0 -0
  15. package/dist/dashboard/assets/HealthEventsModal-B5yEE0k6.js +1 -0
  16. package/dist/dashboard/assets/HealthEventsModal-B5yEE0k6.js.gz +0 -0
  17. package/dist/dashboard/assets/{InjectSystemPromptPanel-Cv-2Ol_K.js → InjectSystemPromptPanel-BWFLECmz.js} +2 -2
  18. package/dist/dashboard/assets/InjectSystemPromptPanel-BWFLECmz.js.gz +0 -0
  19. package/dist/dashboard/assets/{LoginPage-bKfz_b1K.js → LoginPage-CgoPc5B9.js} +1 -1
  20. package/dist/dashboard/assets/LoginPage-CgoPc5B9.js.gz +0 -0
  21. package/dist/dashboard/assets/{ModelPicker-B-WQxx_H.js → ModelPicker-D9bFQern.js} +1 -1
  22. package/dist/dashboard/assets/ModelPicker-D9bFQern.js.gz +0 -0
  23. package/dist/dashboard/assets/OverviewPage-B_p4tL8k.js +1 -0
  24. package/dist/dashboard/assets/OverviewPage-B_p4tL8k.js.gz +0 -0
  25. package/dist/dashboard/assets/ProviderDetailPage-rs5E2rxv.js +8 -0
  26. package/dist/dashboard/assets/ProviderDetailPage-rs5E2rxv.js.gz +0 -0
  27. package/dist/dashboard/assets/ProviderIcon-D_0PiZtg.js +1 -0
  28. package/dist/dashboard/assets/ProviderIcon-D_0PiZtg.js.gz +0 -0
  29. package/dist/dashboard/assets/ProvidersPage-CLI2bJTK.js +1 -0
  30. package/dist/dashboard/assets/ProvidersPage-CLI2bJTK.js.gz +0 -0
  31. package/dist/dashboard/assets/{ProxyPage-emlTuxz6.js → ProxyPage-BwNC_-Cx.js} +1 -1
  32. package/dist/dashboard/assets/ProxyPage-BwNC_-Cx.js.gz +0 -0
  33. package/dist/dashboard/assets/QuotaPage-DA-a1iSN.js +1 -0
  34. package/dist/dashboard/assets/QuotaPage-DA-a1iSN.js.gz +0 -0
  35. package/dist/dashboard/assets/SettingsPage-CctTga2C.js +1 -0
  36. package/dist/dashboard/assets/SettingsPage-CctTga2C.js.gz +0 -0
  37. package/dist/dashboard/assets/{SetupPage-CUZrKs9r.js → SetupPage-febLU4r1.js} +1 -1
  38. package/dist/dashboard/assets/SetupPage-febLU4r1.js.gz +0 -0
  39. package/dist/dashboard/assets/{StudioPage-jWmUdDpy.js → StudioPage-M6fvR5Wz.js} +1 -1
  40. package/dist/dashboard/assets/StudioPage-M6fvR5Wz.js.gz +0 -0
  41. package/dist/dashboard/assets/UsagePage-nyeuRqz9.js +56 -0
  42. package/dist/dashboard/assets/UsagePage-nyeuRqz9.js.gz +0 -0
  43. package/dist/dashboard/assets/api-keys-BFOlvrJC.js +1 -0
  44. package/dist/dashboard/assets/api-keys-BFOlvrJC.js.gz +0 -0
  45. package/dist/dashboard/assets/app-Dx2QgsNj.css +2 -0
  46. package/dist/dashboard/assets/app-Dx2QgsNj.css.gz +0 -0
  47. package/dist/dashboard/assets/{assert-CidQVoNo.js → assert-CqTLw5e7.js} +1 -1
  48. package/dist/dashboard/assets/assert-CqTLw5e7.js.gz +0 -0
  49. package/dist/dashboard/assets/{badge-DyI_mJfi.js → badge-C83EqLB0.js} +1 -1
  50. package/dist/dashboard/assets/badge-C83EqLB0.js.gz +0 -0
  51. package/dist/dashboard/assets/ban-durations-B58FyRxC.js +1 -0
  52. package/dist/dashboard/assets/ban-durations-B58FyRxC.js.gz +0 -0
  53. package/dist/dashboard/assets/{banner-B-yXtCqb.js → banner-D1xn7pIe.js} +1 -1
  54. package/dist/dashboard/assets/banner-D1xn7pIe.js.gz +0 -0
  55. package/dist/dashboard/assets/brand/bansos_page.webp +0 -0
  56. package/dist/dashboard/assets/brand/denia_bansos.webp +0 -0
  57. package/dist/dashboard/assets/brand/favicon.webp +0 -0
  58. package/dist/dashboard/assets/brand/login_register.webp +0 -0
  59. package/dist/dashboard/assets/brand/login_register_initial.webp +0 -0
  60. package/dist/dashboard/assets/brand/og_bansos.webp +0 -0
  61. package/dist/dashboard/assets/brand/og_image.webp +0 -0
  62. package/dist/dashboard/assets/brand/sidebar_ico.webp +0 -0
  63. package/dist/dashboard/assets/{card-_HwAEqFF.js → card-DU3Lq5Lm.js} +1 -1
  64. package/dist/dashboard/assets/card-DU3Lq5Lm.js.gz +0 -0
  65. package/dist/dashboard/assets/cli-tools-Dw1U_drK.js +1 -0
  66. package/dist/dashboard/assets/cli-tools-Dw1U_drK.js.gz +0 -0
  67. package/dist/dashboard/assets/{clipboard-button-ByjCk0o9.js → clipboard-button-CEL5Sg_J.js} +1 -1
  68. package/dist/dashboard/assets/clipboard-button-CEL5Sg_J.js.gz +0 -0
  69. package/dist/dashboard/assets/{dialog-BZhOlfz-.js → dialog-BjFR5UHy.js} +1 -1
  70. package/dist/dashboard/assets/dialog-BjFR5UHy.js.gz +0 -0
  71. package/dist/dashboard/assets/{drawer-BADqIRYP.js → drawer-HvBW0AjI.js} +1 -1
  72. package/dist/dashboard/assets/drawer-HvBW0AjI.js.gz +0 -0
  73. package/dist/dashboard/assets/entry-BSu3gFlt.js +4 -0
  74. package/dist/dashboard/assets/entry-BSu3gFlt.js.gz +0 -0
  75. package/dist/dashboard/assets/{entry-COaC-irN.js → entry-CECVELyy.js} +1 -1
  76. package/dist/dashboard/assets/entry-CECVELyy.js.gz +0 -0
  77. package/dist/dashboard/assets/entry-DYYofQ7W.js +1 -0
  78. package/dist/dashboard/assets/entry-DYYofQ7W.js.gz +0 -0
  79. package/dist/dashboard/assets/{formatters-DcHJyRiu.js → formatters-DLW4i8zK.js} +1 -1
  80. package/dist/dashboard/assets/formatters-DLW4i8zK.js.gz +0 -0
  81. package/dist/dashboard/assets/{index-CgKmFngv.js → index-1-fCqe64.js} +2 -2
  82. package/dist/dashboard/assets/index-1-fCqe64.js.gz +0 -0
  83. package/dist/dashboard/assets/{inline-B2BirKry.js → inline-DGvU2oLK.js} +1 -1
  84. package/dist/dashboard/assets/inline-DGvU2oLK.js.gz +0 -0
  85. package/dist/dashboard/assets/{input-D-qV9dKY.js → input-iNnO1X2K.js} +1 -1
  86. package/dist/dashboard/assets/input-iNnO1X2K.js.gz +0 -0
  87. package/dist/dashboard/assets/{layout-B7tVWhtV.js → layout-0q8UGypb.js} +1 -1
  88. package/dist/dashboard/assets/layout-0q8UGypb.js.gz +0 -0
  89. package/dist/dashboard/assets/{list-row-CtkGE3bF.js → list-row-C0w2bQjJ.js} +1 -1
  90. package/dist/dashboard/assets/list-row-C0w2bQjJ.js.gz +0 -0
  91. package/dist/dashboard/assets/{live-DGizF06-.js → live-M5aJ_xCa.js} +1 -1
  92. package/dist/dashboard/assets/live-M5aJ_xCa.js.gz +0 -0
  93. package/dist/dashboard/assets/{mutation-GU7XdEjz.js → mutation-BQ0ccH_A.js} +1 -1
  94. package/dist/dashboard/assets/mutation-BQ0ccH_A.js.gz +0 -0
  95. package/dist/dashboard/assets/{network-C9UE-bOr.js → network-BKeQGT3K.js} +1 -1
  96. package/dist/dashboard/assets/network-BKeQGT3K.js.gz +0 -0
  97. package/dist/dashboard/assets/{numbers-BnAd22a_.js → numbers-CivAk3da.js} +1 -1
  98. package/dist/dashboard/assets/numbers-CivAk3da.js.gz +0 -0
  99. package/dist/dashboard/assets/{pagination-BAywyMzS.js → pagination-CpzvI5ep.js} +1 -1
  100. package/dist/dashboard/assets/pagination-CpzvI5ep.js.gz +0 -0
  101. package/dist/dashboard/assets/providers/devin.svg +9 -0
  102. package/dist/dashboard/assets/providers/devin.svg.gz +0 -0
  103. package/dist/dashboard/assets/providers/windsurf.svg +10 -0
  104. package/dist/dashboard/assets/providers/windsurf.svg.gz +0 -0
  105. package/dist/dashboard/assets/providers/zro.svg +3 -0
  106. package/dist/dashboard/assets/providers/zro.svg.gz +0 -0
  107. package/dist/dashboard/assets/{query-keys-YSoQOUh6.js → query-keys-IKLh0YFd.js} +1 -1
  108. package/dist/dashboard/assets/query-keys-IKLh0YFd.js.gz +0 -0
  109. package/dist/dashboard/assets/quota-DiPD6UKH.js +1 -0
  110. package/dist/dashboard/assets/quota-DiPD6UKH.js.gz +0 -0
  111. package/dist/dashboard/assets/routing-BFQX2VBc.js +1 -0
  112. package/dist/dashboard/assets/routing-BFQX2VBc.js.gz +0 -0
  113. package/dist/dashboard/assets/{select-BCOcv8WK.js → select-CXbck0jG.js} +2 -2
  114. package/dist/dashboard/assets/select-CXbck0jG.js.gz +0 -0
  115. package/dist/dashboard/assets/settings-C_XvMHh9.js +1 -0
  116. package/dist/dashboard/assets/settings-C_XvMHh9.js.gz +0 -0
  117. package/dist/dashboard/assets/{stack-ByKt3Q1g.js → stack-DggRiCxE.js} +1 -1
  118. package/dist/dashboard/assets/stack-DggRiCxE.js.gz +0 -0
  119. package/dist/dashboard/assets/{state-DXbGTx7N.js → state-ClFzfbYp.js} +1 -1
  120. package/dist/dashboard/assets/state-ClFzfbYp.js.gz +0 -0
  121. package/dist/dashboard/assets/story/25817331.webp +0 -0
  122. package/dist/dashboard/assets/story/Shorekeeper.webp +0 -0
  123. package/dist/dashboard/assets/story/cartethyia-god.webp +0 -0
  124. package/dist/dashboard/assets/story/fleurdelys_plus.webp +0 -0
  125. package/dist/dashboard/assets/story/jinhsi-blossom.webp +0 -0
  126. package/dist/dashboard/assets/story/phrolova-a.webp +0 -0
  127. package/dist/dashboard/assets/story/requestdeniawokkjpg.webp +0 -0
  128. package/dist/dashboard/assets/story/wuthering-waves-hiyuki-aemeath-hiyuki-rover.webp +0 -0
  129. package/dist/dashboard/assets/{switch-ZeTsW623.js → switch-CTIFxKqS.js} +1 -1
  130. package/dist/dashboard/assets/switch-CTIFxKqS.js.gz +0 -0
  131. package/dist/dashboard/assets/{useMutation-CbCP4w1o.js → useMutation-BClG3yWj.js} +1 -1
  132. package/dist/dashboard/assets/useMutation-BClG3yWj.js.gz +0 -0
  133. package/dist/dashboard/console-backgrounds.webp +0 -0
  134. package/dist/dashboard/console-backgrounds_initial.webp +0 -0
  135. package/dist/dashboard/donation/qris-risun-marke.webp +0 -0
  136. package/dist/dashboard/index.html +3 -3
  137. package/dist/dashboard/index.html.gz +0 -0
  138. package/dist/dashboard/precompressed-assets.json +59 -56
  139. package/migrations/full-postgres/0044_add_models_warning_metadata.sql +10 -0
  140. package/migrations/full-postgres/0045_migrate_workbuddy_to_codebuddy.sql +156 -0
  141. package/migrations/full-postgres/0046_add_accounts_quota_plan_fetched_at.sql +7 -0
  142. package/migrations/lite-sqlite3/0044_add_models_warning_metadata.sql +11 -0
  143. package/migrations/lite-sqlite3/0045_migrate_workbuddy_to_codebuddy.sql +156 -0
  144. package/migrations/lite-sqlite3/0046_add_accounts_quota_plan_fetched_at.sql +4 -0
  145. package/package.json +1 -1
  146. package/src/boot/app.ts +10 -13
  147. package/src/boot/dependencies.ts +12 -4
  148. package/src/boot/flush.ts +20 -0
  149. package/src/boot/lifecycle.ts +7 -5
  150. package/src/config/cooldowns.ts +1 -1
  151. package/src/config/routing.ts +26 -0
  152. package/src/config/spec-metadata.ts +72 -0
  153. package/src/config/spec.ts +20 -6
  154. package/src/console/api-keys/contracts.ts +12 -1
  155. package/src/console/api-keys/routes.ts +50 -31
  156. package/src/console/auth/account-reset.ts +7 -9
  157. package/src/console/backup/contracts.ts +4 -0
  158. package/src/console/backup/export-endpoint.ts +7 -5
  159. package/src/console/cli-tools/service.ts +6 -12
  160. package/src/console/console-router-guards.ts +23 -16
  161. package/src/console/console-router.ts +7 -0
  162. package/src/console/dashboard-assets.ts +5 -5
  163. package/src/console/domain-registration.ts +27 -2
  164. package/src/console/inferhub/normalize.ts +24 -28
  165. package/src/console/inferhub/types.ts +3 -0
  166. package/src/console/ip-bans/routes.ts +93 -0
  167. package/src/console/observability/store.ts +0 -53
  168. package/src/console/providers/catalog/catalog-projections.ts +5 -2
  169. package/src/console/providers/catalog/contracts.ts +123 -0
  170. package/src/console/providers/catalog/discover-constants.ts +6 -0
  171. package/src/console/providers/catalog/model-operations.ts +122 -10
  172. package/src/console/providers/catalog/provider-operations.ts +116 -8
  173. package/src/console/providers/catalog/public-model-store.ts +0 -0
  174. package/src/console/providers/catalog/routes.ts +65 -4
  175. package/src/console/providers/catalog/store-helpers.ts +30 -1
  176. package/src/console/providers/catalog/store.ts +249 -4
  177. package/src/console/quota/account-quota-global.ts +97 -19
  178. package/src/console/quota/account-quota-shared.ts +49 -0
  179. package/src/console/quota/account-quota-tenant.ts +6 -18
  180. package/src/console/quota/native-identity.ts +2 -0
  181. package/src/console/quota/quota-view.ts +19 -3
  182. package/src/console/routing/pools/operations.ts +31 -46
  183. package/src/console/settings/contracts.ts +18 -0
  184. package/src/console/settings/store.ts +32 -0
  185. package/src/console/shared/errors.ts +33 -6
  186. package/src/console/system-prompt/contracts.ts +0 -1
  187. package/src/main.ts +3 -3
  188. package/src/network/pool/byte-accounting.ts +3 -2
  189. package/src/network/pool/selector.ts +182 -39
  190. package/src/network/pool-cooldown-store.ts +89 -14
  191. package/src/network/pool-health.ts +49 -61
  192. package/src/network/rate-limit-verdict.ts +1 -1
  193. package/src/network/ssrf.ts +6 -6
  194. package/src/observability/event-log.ts +7 -361
  195. package/src/observability/event-query.ts +18 -4
  196. package/src/observability/performance-metrics.ts +9 -0
  197. package/src/observability/runtime-metrics.ts +14 -9
  198. package/src/observability/telemetry-buffer.ts +15 -25
  199. package/src/observability/telemetry-reconciliation.ts +9 -37
  200. package/src/observability/telemetry-row.ts +125 -0
  201. package/src/persistence/db-mode.ts +4 -1
  202. package/src/persistence/dialect.ts +30 -0
  203. package/src/persistence/migrate.ts +6 -3
  204. package/src/persistence/schema.ts +28 -2
  205. package/src/persistence/ttl-cache.ts +20 -2
  206. package/src/protocol/codecs.ts +1 -1
  207. package/src/protocol/dsml.ts +35 -87
  208. package/src/protocol/gateway-error.ts +1 -0
  209. package/src/protocol/markup-stream-parser.ts +195 -0
  210. package/src/protocol/reasoning-text.ts +19 -0
  211. package/src/protocol/reasoning.ts +1 -1
  212. package/src/protocol/request/chat.ts +14 -14
  213. package/src/protocol/request/gemini.ts +8 -2
  214. package/src/protocol/request/messages.ts +4 -5
  215. package/src/protocol/response/chat.ts +12 -20
  216. package/src/protocol/response/gemini.ts +6 -1
  217. package/src/protocol/response/omp-tool-call-markup.ts +43 -86
  218. package/src/protocol/response/responses.ts +18 -2
  219. package/src/protocol/sse-decoder.ts +25 -8
  220. package/src/protocol/stop-reason.ts +23 -1
  221. package/src/protocol/stream-error-frames.ts +13 -3
  222. package/src/protocol/think-split.ts +112 -0
  223. package/src/protocol/translation/dialect/qwen.ts +26 -58
  224. package/src/protocol/translation/quirks.ts +1 -1
  225. package/src/protocol/translation/tool-repair.ts +2 -2
  226. package/src/protocol/upstream/send-claude-messages.ts +15 -4
  227. package/src/protocol/upstream-parsing.ts +1 -1
  228. package/src/providers/adapters/compatible-adapter.ts +78 -17
  229. package/src/providers/authentication/oauth-client.ts +1 -1
  230. package/src/providers/authentication/oauth-device-flow.ts +98 -8
  231. package/src/providers/authentication/oauth-refresh-service.ts +153 -59
  232. package/src/providers/configured-provider.ts +148 -0
  233. package/src/providers/default-registry.ts +117 -27
  234. package/src/providers/discovery/discovery-types.ts +12 -0
  235. package/src/providers/discovery/probe-phases.ts +74 -33
  236. package/src/providers/discovery/probing-service.ts +293 -165
  237. package/src/providers/integrations/alibabacp/alibabacp-models.ts +1 -2
  238. package/src/providers/integrations/{dashscope-models.ts → alibabacp/dashscope-models.ts} +2 -2
  239. package/src/providers/integrations/antigravity/antigravity-protocol.ts +121 -2
  240. package/src/providers/integrations/antigravity/antigravity.ts +13 -2
  241. package/src/providers/integrations/buddy/buddy-catalog-shared.ts +72 -34
  242. package/src/providers/integrations/buddy/buddy-chat-shared.ts +191 -35
  243. package/src/providers/integrations/buddy/buddy-checkin.ts +17 -39
  244. package/src/providers/integrations/buddy/buddy-conversation-headers.ts +2 -2
  245. package/src/providers/integrations/buddy/buddy-discovery-shared.ts +5 -5
  246. package/src/providers/integrations/buddy/buddy-identity.ts +89 -6
  247. package/src/providers/integrations/buddy/buddy-media.ts +4 -5
  248. package/src/providers/integrations/buddy/buddy-oauth-shared.ts +2 -2
  249. package/src/providers/integrations/buddy/buddy-quota-shared.ts +1 -1
  250. package/src/providers/integrations/buddy/buddy-usage-shared.ts +1 -3
  251. package/src/providers/integrations/buddy/capabilities.ts +6 -43
  252. package/src/providers/integrations/buddy/codebuddy/cn-catalog.ts +2 -1
  253. package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +23 -1
  254. package/src/providers/integrations/buddy/codebuddy/provider.ts +6 -2
  255. package/src/providers/integrations/buddy/codebuddy/shared.ts +38 -27
  256. package/src/providers/integrations/claude/claude-quota.ts +14 -17
  257. package/src/providers/integrations/cline/cline.ts +2 -2
  258. package/src/providers/integrations/commandcode/quota.ts +22 -28
  259. package/src/providers/integrations/cursor/cursor-auth.ts +0 -8
  260. package/src/providers/integrations/cursor/cursor-catalog.ts +2 -0
  261. package/src/providers/integrations/cursor/cursor-exec.ts +745 -0
  262. package/src/providers/integrations/cursor/cursor-http2.ts +2 -0
  263. package/src/providers/integrations/cursor/cursor-request.ts +35 -20
  264. package/src/providers/integrations/cursor/cursor-shared.ts +26 -5
  265. package/src/providers/integrations/cursor/cursor.ts +139 -70
  266. package/src/providers/integrations/cursor/protocol/messages.ts +22 -29
  267. package/src/providers/integrations/cursor/protocol/protobuf-schema.ts +37 -0
  268. package/src/providers/integrations/cursor/protocol/tool-canonical.ts +26 -100
  269. package/src/providers/integrations/devin/devin-auth.ts +353 -0
  270. package/src/providers/integrations/devin/devin-catalog.ts +207 -0
  271. package/src/providers/integrations/devin/devin-http.ts +91 -0
  272. package/src/providers/integrations/devin/devin-quota.ts +214 -0
  273. package/src/providers/integrations/devin/devin-shared.ts +111 -0
  274. package/src/providers/integrations/devin/devin.ts +539 -0
  275. package/src/providers/integrations/devin/protocol/devin-proto.ts +558 -0
  276. package/src/providers/integrations/devin/protocol/framing.ts +124 -0
  277. package/src/providers/integrations/factory/factory-oauth.ts +17 -44
  278. package/src/providers/integrations/factory/factory.ts +2 -2
  279. package/src/providers/integrations/freebuff/assets/official-system-manager.txt +88 -0
  280. package/src/providers/integrations/freebuff/assets/official-system-worker.txt +57 -0
  281. package/src/providers/integrations/freebuff/assets/official-tools.json +1070 -0
  282. package/src/providers/integrations/freebuff/freebuff-catalog.ts +120 -0
  283. package/src/providers/integrations/freebuff/freebuff-constants.ts +1233 -0
  284. package/src/providers/integrations/freebuff/freebuff-discovery.ts +108 -0
  285. package/src/providers/integrations/freebuff/freebuff-oauth.ts +240 -0
  286. package/src/providers/integrations/freebuff/freebuff-quota.ts +260 -0
  287. package/src/providers/integrations/freebuff/freebuff-virtual.ts +89 -0
  288. package/src/providers/integrations/freebuff/freebuff.ts +682 -0
  289. package/src/providers/integrations/freepi/freepi-catalog.ts +60 -0
  290. package/src/providers/integrations/freepi/freepi-discovery.ts +82 -0
  291. package/src/providers/integrations/freepi/freepi-headers.ts +21 -0
  292. package/src/providers/integrations/freepi/freepi-oauth.ts +142 -0
  293. package/src/providers/integrations/freepi/freepi-protocol.ts +242 -0
  294. package/src/providers/integrations/freepi/freepi-quota.ts +126 -0
  295. package/src/providers/integrations/freepi/freepi-realm.ts +35 -0
  296. package/src/providers/integrations/freepi/freepi.ts +292 -0
  297. package/src/providers/integrations/gemini.ts +2 -2
  298. package/src/providers/integrations/grok/grok-oauth.ts +48 -45
  299. package/src/providers/integrations/grok/grok-ratelimit-store.ts +10 -17
  300. package/src/providers/integrations/grok/grok-turn-index.ts +11 -16
  301. package/src/providers/integrations/hermes/hermes-oauth.ts +94 -0
  302. package/src/providers/integrations/{hermes.ts → hermes/hermes.ts} +13 -21
  303. package/src/providers/integrations/hermes/index.ts +2 -0
  304. package/src/providers/integrations/kiro/kiro-catalog.ts +17 -1
  305. package/src/providers/integrations/kiro/kiro-discovery.ts +10 -12
  306. package/src/providers/integrations/kiro/kiro-quota.ts +8 -4
  307. package/src/providers/integrations/kiro/kiro.ts +15 -19
  308. package/src/providers/integrations/ollamacloud/index.ts +2 -0
  309. package/src/providers/integrations/{ollamacloud-models.ts → ollamacloud/models.ts} +2 -2
  310. package/src/providers/integrations/{ollamacloud-quota.ts → ollamacloud/quota.ts} +3 -3
  311. package/src/providers/integrations/opencode/fingerprint.ts +1 -1
  312. package/src/providers/integrations/opencode/opencode-go-quota.ts +2 -8
  313. package/src/providers/integrations/perch/perch-catalog.ts +105 -0
  314. package/src/providers/integrations/perch/perch-credential.ts +25 -0
  315. package/src/providers/integrations/perch/perch-oauth.ts +170 -0
  316. package/src/providers/integrations/perch/perch-protocol.ts +208 -0
  317. package/src/providers/integrations/perch/perch-quota.ts +123 -0
  318. package/src/providers/integrations/perch/perch-realm.ts +82 -0
  319. package/src/providers/integrations/perch/perch-system-prompt.ts +13 -0
  320. package/src/providers/integrations/perch/perch.ts +305 -0
  321. package/src/providers/integrations/perch/saffron-system-prompt.txt +8 -0
  322. package/src/providers/integrations/qoder/chat-proto.ts +328 -328
  323. package/src/providers/integrations/qoder/claim-qoder-credits.ts +19 -60
  324. package/src/providers/integrations/qoder/qoder-adapter.ts +90 -40
  325. package/src/providers/integrations/qoder/qoder-auth.ts +101 -29
  326. package/src/providers/integrations/qoder/qoder-cache.ts +32 -0
  327. package/src/providers/integrations/qoder/qoder-catalog.ts +26 -6
  328. package/src/providers/integrations/qoder/qoder-chat.ts +7 -21
  329. package/src/providers/integrations/qoder/qoder-checkin.ts +6 -6
  330. package/src/providers/integrations/qoder/qoder-grpc.ts +210 -7
  331. package/src/providers/integrations/qoder/qoder-ide.ts +5 -108
  332. package/src/providers/integrations/qoder/qoder-identity-cache.ts +184 -0
  333. package/src/providers/integrations/qoder/qoder-native-identity-store.ts +83 -18
  334. package/src/providers/integrations/qoder/qoder-realm.ts +9 -6
  335. package/src/providers/integrations/qoder/qoder-umid.ts +109 -342
  336. package/src/providers/integrations/qoder/qoder-virtual.ts +33 -1
  337. package/src/providers/integrations/qoder/qoder.ts +3 -7
  338. package/src/providers/integrations/trae/trae-catalog.ts +9 -14
  339. package/src/providers/integrations/trae/trae-headers.ts +36 -11
  340. package/src/providers/integrations/trae/trae-oauth.ts +14 -17
  341. package/src/providers/integrations/trae/trae-protocol.ts +12 -11
  342. package/src/providers/integrations/trae/trae-quota.ts +96 -36
  343. package/src/providers/integrations/trae/trae-realm.ts +74 -15
  344. package/src/providers/integrations/trae/trae.ts +99 -26
  345. package/src/providers/integrations/zcode-start-plan/provider.ts +226 -23
  346. package/src/providers/integrations/zcode-start-plan/quota.ts +19 -2
  347. package/src/providers/integrations/zro/zro.ts +204 -0
  348. package/src/providers/operations/account-error-classification.ts +235 -278
  349. package/src/providers/operations/account-health-service.ts +273 -26
  350. package/src/providers/operations/account-refresh-status.ts +269 -0
  351. package/src/providers/operations/account-tier.ts +66 -0
  352. package/src/providers/operations/client-version-resolver.ts +1 -1
  353. package/src/providers/operations/client-versions.ts +42 -150
  354. package/src/providers/operations/cooldown-rules.ts +56 -0
  355. package/src/providers/operations/{model-catalog-cache.ts → provider-caches.ts} +68 -16
  356. package/src/providers/operations/provider-catalog-seeder.ts +4 -0
  357. package/src/providers/operations/provider-catalog-service.ts +1 -1
  358. package/src/providers/operations/provider-credential-service.ts +102 -32
  359. package/src/providers/operations/provider-rules/github.ts +48 -0
  360. package/src/providers/operations/provider-rules/grok.ts +33 -0
  361. package/src/providers/operations/provider-rules/inception.ts +49 -0
  362. package/src/providers/operations/provider-rules/index.ts +32 -0
  363. package/src/providers/operations/provider-rules/perch.ts +37 -0
  364. package/src/providers/operations/provider-rules/qoder.ts +70 -0
  365. package/src/providers/operations/provider-rules/trae.ts +81 -0
  366. package/src/providers/provider-contracts.ts +33 -2
  367. package/src/providers/{provider-credential-resolver.ts → provider-credentials.ts} +40 -3
  368. package/src/providers/provider-metadata.ts +99 -14
  369. package/src/providers/provider-model-definition.ts +36 -0
  370. package/src/providers/provider-probe.ts +15 -1
  371. package/src/providers/provider-registry.ts +42 -33
  372. package/src/providers/quota/quota-limit-windows.ts +16 -5
  373. package/src/providers/quota/quota-support.ts +1 -1
  374. package/src/providers/quota/quota-window-parser.ts +90 -18
  375. package/src/providers/quota/refresh.ts +96 -18
  376. package/src/security/abuse.ts +71 -0
  377. package/src/security/api-key-auth-cache.ts +1 -1
  378. package/src/security/api-key-auth.ts +6 -2
  379. package/src/transport/dispatch/attempt-finalize.ts +14 -13
  380. package/src/transport/dispatch/attempt-loop.ts +71 -17
  381. package/src/transport/dispatch/generation.ts +2 -8
  382. package/src/transport/dispatch/native-shared.ts +25 -0
  383. package/src/transport/dispatch/proxy-request.ts +9 -46
  384. package/src/transport/dispatch/responses-compact.ts +2 -8
  385. package/src/transport/dispatch/streaming/finalize.ts +9 -6
  386. package/src/transport/dispatch/streaming/stream.ts +9 -36
  387. package/src/transport/dispatch/systemone.ts +2 -8
  388. package/src/transport/dispatch/token-count.ts +2 -6
  389. package/src/transport/dispatch/upstream.ts +67 -1
  390. package/src/transport/drain-endpoint.ts +31 -4
  391. package/src/transport/failure-policy.ts +129 -37
  392. package/src/transport/guards/body-policy.ts +7 -1
  393. package/src/transport/guards/error-lifecycle.ts +13 -1
  394. package/src/transport/guards/request-context.ts +22 -14
  395. package/src/transport/request/preparer.ts +81 -71
  396. package/src/transport/routing/bounded-lru.ts +14 -0
  397. package/src/transport/routing/drain-reserve.ts +129 -0
  398. package/src/transport/routing/plan-gate.ts +7 -1
  399. package/src/transport/routing/round-robin.ts +60 -0
  400. package/src/transport/routing/route-catalog.ts +123 -111
  401. package/src/transport/routing/route-model.ts +51 -9
  402. package/src/transport/routing/router.ts +418 -33
  403. package/src/transport/surface/adapters.ts +11 -2
  404. package/src/transport/surface/chat/adapter.ts +2 -2
  405. package/src/transport/surface/chat/encode.ts +47 -4
  406. package/src/transport/surface/chat/parse.ts +2 -12
  407. package/src/transport/surface/completion.ts +44 -33
  408. package/src/transport/surface/content-parts.ts +21 -0
  409. package/src/transport/surface/messages/adapter.ts +9 -2
  410. package/src/transport/surface/messages/encode.ts +11 -3
  411. package/src/transport/surface/messages/parse.ts +2 -1
  412. package/src/transport/surface/messages/stream.ts +33 -17
  413. package/src/transport/surface/responses/encode.ts +34 -6
  414. package/src/transport/surface/responses/parse.ts +3 -11
  415. package/src/workers/daily-checkin.ts +1 -1
  416. package/src/workers/quota-refresh-sweep.ts +1 -1
  417. package/src/workers/scheduler.ts +22 -4
  418. package/dist/dashboard/assets/BannedPage-DeIbIiBU.js +0 -1
  419. package/dist/dashboard/assets/BannedPage-DeIbIiBU.js.gz +0 -0
  420. package/dist/dashboard/assets/CliToolDetailPage-BRWKPQPf.js.gz +0 -0
  421. package/dist/dashboard/assets/CliToolsPage-BP-Y5iHN.js.gz +0 -0
  422. package/dist/dashboard/assets/CombosPage-B7JHozVa.js +0 -1
  423. package/dist/dashboard/assets/CombosPage-B7JHozVa.js.gz +0 -0
  424. package/dist/dashboard/assets/ConsoleLogPage-GX7iGGcu.js +0 -1
  425. package/dist/dashboard/assets/ConsoleLogPage-GX7iGGcu.js.gz +0 -0
  426. package/dist/dashboard/assets/CustomizationPage-HVonbGEa.js +0 -1
  427. package/dist/dashboard/assets/CustomizationPage-HVonbGEa.js.gz +0 -0
  428. package/dist/dashboard/assets/HealthEventsModal-xaut4OJ9.js +0 -1
  429. package/dist/dashboard/assets/HealthEventsModal-xaut4OJ9.js.gz +0 -0
  430. package/dist/dashboard/assets/InjectSystemPromptPanel-Cv-2Ol_K.js.gz +0 -0
  431. package/dist/dashboard/assets/LoginPage-bKfz_b1K.js.gz +0 -0
  432. package/dist/dashboard/assets/ModelPicker-B-WQxx_H.js.gz +0 -0
  433. package/dist/dashboard/assets/OverviewPage-Z9pJZFo8.js +0 -1
  434. package/dist/dashboard/assets/OverviewPage-Z9pJZFo8.js.gz +0 -0
  435. package/dist/dashboard/assets/ProviderDetailPage-CMeDBxR1.js +0 -7
  436. package/dist/dashboard/assets/ProviderDetailPage-CMeDBxR1.js.gz +0 -0
  437. package/dist/dashboard/assets/ProviderIcon-jjqXJDA3.js +0 -1
  438. package/dist/dashboard/assets/ProviderIcon-jjqXJDA3.js.gz +0 -0
  439. package/dist/dashboard/assets/ProvidersPage-BXPdOpG4.js +0 -1
  440. package/dist/dashboard/assets/ProvidersPage-BXPdOpG4.js.gz +0 -0
  441. package/dist/dashboard/assets/ProxyPage-emlTuxz6.js.gz +0 -0
  442. package/dist/dashboard/assets/QuotaPage-CMJKNYWb.js +0 -1
  443. package/dist/dashboard/assets/QuotaPage-CMJKNYWb.js.gz +0 -0
  444. package/dist/dashboard/assets/SettingsPage-BSy7EwGo.js +0 -1
  445. package/dist/dashboard/assets/SettingsPage-BSy7EwGo.js.gz +0 -0
  446. package/dist/dashboard/assets/SetupPage-CUZrKs9r.js.gz +0 -0
  447. package/dist/dashboard/assets/StudioPage-jWmUdDpy.js.gz +0 -0
  448. package/dist/dashboard/assets/UsagePage-5F9tGVGG.js +0 -56
  449. package/dist/dashboard/assets/UsagePage-5F9tGVGG.js.gz +0 -0
  450. package/dist/dashboard/assets/api-keys-KvX83mRe.js +0 -1
  451. package/dist/dashboard/assets/api-keys-KvX83mRe.js.gz +0 -0
  452. package/dist/dashboard/assets/app-BEsU8hKs.css +0 -2
  453. package/dist/dashboard/assets/app-BEsU8hKs.css.gz +0 -0
  454. package/dist/dashboard/assets/assert-CidQVoNo.js.gz +0 -0
  455. package/dist/dashboard/assets/badge-DyI_mJfi.js.gz +0 -0
  456. package/dist/dashboard/assets/banner-B-yXtCqb.js.gz +0 -0
  457. package/dist/dashboard/assets/brand/bansos_page.png +0 -0
  458. package/dist/dashboard/assets/brand/denia_bansos.jpg +0 -0
  459. package/dist/dashboard/assets/brand/favicon.jpg +0 -0
  460. package/dist/dashboard/assets/brand/login_register.jpg +0 -0
  461. package/dist/dashboard/assets/brand/login_register_initial.jpg +0 -0
  462. package/dist/dashboard/assets/brand/og_bansos.jpg +0 -0
  463. package/dist/dashboard/assets/brand/og_image.jpg +0 -0
  464. package/dist/dashboard/assets/brand/sidebar_ico.jpg +0 -0
  465. package/dist/dashboard/assets/card-_HwAEqFF.js.gz +0 -0
  466. package/dist/dashboard/assets/cli-tools-Bwv5-zGZ.js +0 -1
  467. package/dist/dashboard/assets/cli-tools-Bwv5-zGZ.js.gz +0 -0
  468. package/dist/dashboard/assets/clipboard-button-ByjCk0o9.js.gz +0 -0
  469. package/dist/dashboard/assets/dialog-BZhOlfz-.js.gz +0 -0
  470. package/dist/dashboard/assets/drawer-BADqIRYP.js.gz +0 -0
  471. package/dist/dashboard/assets/entry-COaC-irN.js.gz +0 -0
  472. package/dist/dashboard/assets/entry-Ca7LSCet.js +0 -4
  473. package/dist/dashboard/assets/entry-Ca7LSCet.js.gz +0 -0
  474. package/dist/dashboard/assets/entry-PDd27uCd.js +0 -1
  475. package/dist/dashboard/assets/entry-PDd27uCd.js.gz +0 -0
  476. package/dist/dashboard/assets/formatters-DcHJyRiu.js.gz +0 -0
  477. package/dist/dashboard/assets/index-CgKmFngv.js.gz +0 -0
  478. package/dist/dashboard/assets/inline-B2BirKry.js.gz +0 -0
  479. package/dist/dashboard/assets/input-D-qV9dKY.js.gz +0 -0
  480. package/dist/dashboard/assets/layout-B7tVWhtV.js.gz +0 -0
  481. package/dist/dashboard/assets/list-row-CtkGE3bF.js.gz +0 -0
  482. package/dist/dashboard/assets/live-DGizF06-.js.gz +0 -0
  483. package/dist/dashboard/assets/minimize-2-BTmMTK4o.js +0 -1
  484. package/dist/dashboard/assets/minimize-2-BTmMTK4o.js.gz +0 -0
  485. package/dist/dashboard/assets/mutation-GU7XdEjz.js.gz +0 -0
  486. package/dist/dashboard/assets/network-C9UE-bOr.js.gz +0 -0
  487. package/dist/dashboard/assets/numbers-BnAd22a_.js.gz +0 -0
  488. package/dist/dashboard/assets/pagination-BAywyMzS.js.gz +0 -0
  489. package/dist/dashboard/assets/query-keys-YSoQOUh6.js.gz +0 -0
  490. package/dist/dashboard/assets/quota-DJ1QlAOq.js +0 -1
  491. package/dist/dashboard/assets/quota-DJ1QlAOq.js.gz +0 -0
  492. package/dist/dashboard/assets/routing-fnCsxgNO.js +0 -1
  493. package/dist/dashboard/assets/routing-fnCsxgNO.js.gz +0 -0
  494. package/dist/dashboard/assets/select-BCOcv8WK.js.gz +0 -0
  495. package/dist/dashboard/assets/settings-BxslsErn.js +0 -1
  496. package/dist/dashboard/assets/settings-BxslsErn.js.gz +0 -0
  497. package/dist/dashboard/assets/stack-ByKt3Q1g.js.gz +0 -0
  498. package/dist/dashboard/assets/state-DXbGTx7N.js.gz +0 -0
  499. package/dist/dashboard/assets/switch-ZeTsW623.js.gz +0 -0
  500. package/dist/dashboard/assets/useMutation-CbCP4w1o.js.gz +0 -0
  501. package/dist/dashboard/console-backgrounds.jpg +0 -0
  502. package/dist/dashboard/console-backgrounds_initial.jpg +0 -0
  503. package/dist/dashboard/donation/qris-risun-marke.png +0 -0
  504. package/src/providers/bundled-discovery-providers.ts +0 -98
  505. package/src/providers/configured-openai-providers.ts +0 -120
  506. package/src/providers/integrations/buddy/turing-device-token.ts +0 -262
  507. package/src/providers/integrations/buddy/workbuddy/cn-oauth.ts +0 -30
  508. package/src/providers/integrations/buddy/workbuddy/cn-provider.ts +0 -58
  509. package/src/providers/integrations/buddy/workbuddy/oauth.ts +0 -31
  510. package/src/providers/integrations/buddy/workbuddy/provider.ts +0 -209
  511. package/src/providers/integrations/buddy/workbuddy/quota.ts +0 -161
  512. package/src/providers/integrations/buddy/workbuddy/shared.ts +0 -285
  513. package/src/providers/operations/model-discovery-cache.ts +0 -34
  514. package/src/providers/operations/probe-fetch.ts +0 -15
  515. package/src/providers/operations/provider-version-cache.ts +0 -30
  516. package/src/providers/provider-capabilities.ts +0 -33
  517. package/src/providers/provider-credential-envelope.ts +0 -43
  518. /package/dist/dashboard/assets/{app-CTxoqyYB.js → app-DIXLjojg.js} +0 -0
  519. /package/dist/dashboard/assets/{app-CTxoqyYB.js.gz → app-DIXLjojg.js.gz} +0 -0
@@ -1,27 +1,27 @@
1
1
  // Cursor-native tool calls, unified into one canonical shape.
2
2
  //
3
- // Cursor's `agent.v1.ToolCall` is a oneof of ~30 variants spanning three
4
- // unrelated generations: the legacy natives (`ReadToolCall` 8, `ShellToolCall`
5
- // 1, `EditToolCall` 12, …), the modern exec family (`PiReadToolCall` 61 …
6
- // `PiLsToolCall` 67), and MCP (`McpToolCall` 15). Each carries its own args
7
- // message and its own `*ToolResult` oneof of `success`/`error`, so handling
8
- // them individually meant a decoder and a builder per variant — most of them
9
- // saying the same thing.
3
+ // Cursor's `agent.v1.ToolCall` is a oneof of ~30 variants spanning several
4
+ // generations: the legacy natives (`ReadToolCall` 8, `ShellToolCall` 1,
5
+ // `EditToolCall` 12, …) and the modern exec family (`PiReadToolCall` 61 …
6
+ // `PiLsToolCall` 67). Each carries its own args message and its own
7
+ // `*ToolResult` oneof of `success`/`error`.
10
8
  //
11
9
  // This module is the single join point. One table maps a wire variant to a
12
10
  // canonical tool identity, and the decode/encode paths below are written once
13
11
  // against that table rather than once per variant.
14
12
  //
15
- // **Variants stay separate.** `ReadToolCall` and `PiReadToolCall` are two tools,
16
- // not one tool seen twice: their args and their result shapes genuinely differ,
17
- // and folding them would mean picking one shape and lying about the other. A
18
- // new variant is one table row, not a new converter.
13
+ // **Generation aliases collapse to one canonical name.** `ReadToolCall` and
14
+ // `PiReadToolCall` are the *same tool* across two wire generations — the pi_
15
+ // family is the modern executor, the legacy family the older surface. They are
16
+ // folded onto one name (`read`, `shell`, `edit`, `write`, `grep`, `find`,
17
+ // `ls`) so callers reason about tools, not about which wire arm carried them.
18
+ // The `field`/`argsType`/`resultType` still differ per row, so encode/decode
19
+ // round-trips preserve the exact arm that arrived.
19
20
  //
20
21
  // **Cursor-scoped on purpose.** Nothing here is shared with the other provider
21
- // integrations. The canonical vocabulary is Cursor's own (`read`, `pi_read`,
22
- // `shell`, …), so a tool named `read` on Cursor and a `read` on some other
22
+ // integrations. The canonical vocabulary is Cursor's own (`read`, `shell`,
23
+ // `edit`, …), so a tool named `read` on Cursor and a `read` on some other
23
24
  // provider are unrelated and cannot collide through a shared registry.
24
- import type { ToolDefinition } from "../../../../protocol/canonical-model";
25
25
 
26
26
  /**
27
27
  * One `ToolCall` oneof arm, as it exists on the wire.
@@ -41,9 +41,8 @@ export interface CursorToolVariant {
41
41
  /**
42
42
  * Canonical tool name for this variant.
43
43
  *
44
- * Deliberately not shared across generations: `read` and `pi_read` are two
45
- * names because they are two tools. A caller that wants both treats them as
46
- * both; a caller that wants one filters on one.
44
+ * Shared across wire generations: `read` is both `ReadToolCall` and
45
+ * `PiReadToolCall`.
47
46
  */
48
47
  readonly name: string;
49
48
  }
@@ -59,14 +58,18 @@ const VARIANT = (
59
58
  /**
60
59
  * Every Cursor-native tool variant this layer speaks, keyed by oneof field.
61
60
  *
62
- * `McpToolCall` is absent on purpose: client-declared tools have no native
63
- * slot anywhere in `agent.proto` — `RequestContext.tools` (#7) is
64
- * `repeated McpToolDefinition` and `AgentRunRequest.mcp_tools` (#4) is the only
65
- * other place tools travel — so those stay on the MCP meta-tool path. This
66
- * table is for the arms Cursor itself owns.
61
+ * MCP (`McpToolCall`) is intentionally absent: the gateway no longer speaks
62
+ * the MCP meta-tool channel. Client-declared tools have no native slot in
63
+ * `agent.proto`; they are not advertised and any inbound MCP arm is refused.
67
64
  */
68
65
  export const CURSOR_TOOL_VARIANTS: ReadonlyMap<number, CursorToolVariant> = new Map([
69
66
  VARIANT(1, "ShellToolCall", "ShellArgs", "ShellResult", "shell"),
67
+ // Legacy write has no ToolCall oneof arm — it arrives only as
68
+ // `ExecServerMessage.write_args` (field 3). The variant is registered with
69
+ // a dedicated field number so the executor can resolve it without colliding
70
+ // with `DeleteToolCall` (which also owns field 3); the field is otherwise
71
+ // unused by the ToolCall path.
72
+ VARIANT(0, "WriteToolCall", "WriteArgs", "WriteResult", "write"),
70
73
  VARIANT(3, "DeleteToolCall", "DeleteArgs", "DeleteResult", "delete"),
71
74
  VARIANT(4, "GlobToolCall", "GlobArgs", "GlobResult", "glob"),
72
75
  VARIANT(5, "GrepToolCall", "GrepArgs", "GrepResult", "grep"),
@@ -93,14 +96,6 @@ export const CURSOR_TOOL_VARIANTS: ReadonlyMap<number, CursorToolVariant> = new
93
96
  VARIANT(32, "ReflectToolCall", "ReflectArgs", "ReflectResult", "reflect"),
94
97
  VARIANT(33, "SetupVmEnvironmentToolCall", "SetupVmEnvironmentArgs", "SetupVmEnvironmentResult", "setup_vm_environment"),
95
98
  VARIANT(34, "TruncatedToolCall", "TruncatedArgs", "TruncatedResult", "truncated"),
96
- // The modern exec family. Same join point, separate identities.
97
- VARIANT(61, "PiReadToolCall", "PiReadToolArgs", "PiReadExecResult", "pi_read"),
98
- VARIANT(62, "PiBashToolCall", "PiBashToolArgs", "PiBashExecResult", "pi_bash"),
99
- VARIANT(63, "PiEditToolCall", "PiEditToolArgs", "PiEditExecResult", "pi_edit"),
100
- VARIANT(64, "PiWriteToolCall", "PiWriteToolArgs", "PiWriteExecResult", "pi_write"),
101
- VARIANT(65, "PiGrepToolCall", "PiGrepToolArgs", "PiGrepExecResult", "pi_grep"),
102
- VARIANT(66, "PiFindToolCall", "PiFindToolArgs", "PiFindExecResult", "pi_find"),
103
- VARIANT(67, "PiLsToolCall", "PiLsToolArgs", "PiLsExecResult", "pi_ls"),
104
99
  ].map((entry) => [entry.field, entry]));
105
100
 
106
101
  /**
@@ -126,8 +121,7 @@ type OneofArm = { readonly field: number; readonly payload: Record<string, unkno
126
121
  *
127
122
  * A oneof has exactly one populated field; a message with none is not a tool
128
123
  * call at all and is reported as `undefined` rather than guessed at. An arm
129
- * this layer does not know is also `undefined` — that is what leaves room for
130
- * MCP to claim it.
124
+ * this layer does not know is also `undefined`.
131
125
  */
132
126
  export function cursorToolArm(
133
127
  toolCall: Record<string, unknown>,
@@ -205,71 +199,3 @@ function snakeCaseKey(key: string): string {
205
199
  .replace(/[\s-]+/g, "_")
206
200
  .toLowerCase();
207
201
  }
208
-
209
- /**
210
- * The variant whose args a host-exec frame is carrying.
211
- *
212
- * Exec frames name their payload after the args message — `read_args`,
213
- * `shell_args`, `pi_read_args` — not after the `ToolCall` arm, so the lookup
214
- * runs off `argsType`. Anything not ending in `_args` is not a tool payload
215
- * (`id`, `exec_id`, `request_context_args`, …) and is reported as `undefined`.
216
- */
217
- export function cursorVariantForExecArgs(
218
- execServer: Record<string, unknown>,
219
- ): { readonly variant: CursorToolVariant; readonly args: Record<string, unknown> } | undefined {
220
- for (const [key, value] of Object.entries(execServer)) {
221
- if (value === null || value === undefined || !key.endsWith("_args")) continue;
222
- const wanted = key.slice(0, -"_args".length);
223
- const variant = [...CURSOR_TOOL_VARIANTS.values()].find((entry) =>
224
- entry.argsType.toLowerCase().startsWith(wanted.toLowerCase()),
225
- );
226
- if (variant === undefined) continue;
227
- return {
228
- variant,
229
- args: canonicalToolArguments(value),
230
- };
231
- }
232
- return undefined;
233
- }
234
-
235
- /**
236
- * The variant an inbound result must be encoded back into.
237
- *
238
- * Keyed by `call_id`, which is what the response carries and what the client
239
- * echoes on the result. Consulted before encoding so a result for a tool this
240
- * layer never decoded is not invented into some other variant's shape.
241
- */
242
- export class CursorToolCallProvenance {
243
- readonly #byCallId = new Map<string, CursorToolVariant>();
244
-
245
- record(callId: string, variant: CursorToolVariant): void {
246
- this.#byCallId.set(callId, variant);
247
- }
248
-
249
- lookup(callId: string): CursorToolVariant | undefined {
250
- return this.#byCallId.get(callId);
251
- }
252
-
253
- /** Drops one call's provenance once its result has been encoded. */
254
- complete(callId: string): void {
255
- this.#byCallId.delete(callId);
256
- }
257
- }
258
-
259
- /**
260
- * A tool declaration the gateway can advertise for Cursor-native tools.
261
- *
262
- * Kept separate from `ToolDefinition`'s own name on purpose: the canonical name
263
- * (`pi_read`) is not the name a client's schema would use, so advertising one
264
- * under the other would make the call/result round trip undecidable.
265
- */
266
- export function cursorNativeToolDeclaration(
267
- variant: CursorToolVariant,
268
- description: string,
269
- ): ToolDefinition {
270
- return {
271
- name: variant.name,
272
- description,
273
- jsonSchema: { type: "object", properties: {} },
274
- };
275
- }
@@ -0,0 +1,353 @@
1
+ /**
2
+ * Devin authentication: OAuth login flows and credential import.
3
+ *
4
+ * Three paths are supported:
5
+ *
6
+ * 1. **Devin CLI** (`app.devin.ai`): PKCE S256 browser-code flow. Authorize
7
+ * at `https://app.devin.ai/auth/cli/continue`, exchange at
8
+ * `https://api.devin.ai/auth/cli/token` (body JSON, non-standard).
9
+ * 2. **Windsurf Enterprise** (`windsurf.com`): PKCE S256 loopback flow on
10
+ * port 59654, exchanging via `ExchangePKCEAuthorizationCode` to a raw
11
+ * seat key (`sk-ws-…`, stripped from the `gsk-ws-…` wire form).
12
+ * 3. **CLI adopt**: reads the official Devin CLI `credentials.toml`
13
+ * (`windsurf_api_key`) — no network, no prompts.
14
+ *
15
+ * All three store under the `devin` credential slot (`store-as "devin"`).
16
+ *
17
+ * Ported from oh-my-pi (`registry/oauth/devin-windsurf.ts` +
18
+ * `devin-cli.ts`, MIT) and opencode-devin-provider (`oauth.ts`, MIT).
19
+ */
20
+
21
+ import { createHash, randomBytes } from "node:crypto";
22
+ import { readFileSync, existsSync } from "node:fs";
23
+ import { join } from "node:path";
24
+ import {
25
+ base64url,
26
+ decodeJwt,
27
+ } from "jose";
28
+ import type {
29
+ OAuthAuthorizeRequest,
30
+ OAuthCodeExchangeContext,
31
+ OAuthExchangeResult,
32
+ OAuthImportInput,
33
+ OAuthLoginClient,
34
+ } from "../../authentication/oauth-flow-store";
35
+ import { callDevinUnary } from "./devin-http";
36
+ import { DevinMessageTypes } from "./protocol/devin-proto";
37
+ import {
38
+ DEVIN_DEFAULT_BASE_URL,
39
+ DEVIN_EXCHANGE_PATH,
40
+ DEVIN_GET_USER_STATUS_PATH,
41
+ } from "./devin-shared";
42
+
43
+ // ── PKCE ──
44
+
45
+ export function generatePKCE(): { verifier: string; challenge: string } {
46
+ const verifier = base64url.encode(randomBytes(96));
47
+ const challenge = base64url.encode(createHash("sha256").update(verifier).digest());
48
+ return { verifier, challenge };
49
+ }
50
+
51
+ // ── Identity resolution ──
52
+
53
+ /** JWT claim keys tried in order when deriving an email/identity label. */
54
+ const IDENTITY_CLAIM_KEYS = [
55
+ "email",
56
+ "preferred_username",
57
+ "name",
58
+ "sub",
59
+ "user_id",
60
+ "userId",
61
+ "session_id",
62
+ ] as const;
63
+
64
+ /**
65
+ * Derives a display label from a session token without any network: decode
66
+ * the JWT payload and read the first present identity claim. A token that is
67
+ * not a JWT (raw `sk-ws-…` seat key) yields nothing.
68
+ */
69
+ export function identityLabelFromDevinCredential(credential: string): string | undefined {
70
+ const key = credential.trim();
71
+ if (!key) return undefined;
72
+ const jwt = key.startsWith("devin-session-token$")
73
+ ? key.slice("devin-session-token$".length)
74
+ : key;
75
+ if (jwt.split(".").length !== 3) return undefined;
76
+ let payload: Record<string, unknown>;
77
+ try {
78
+ payload = decodeJwt(jwt) as Record<string, unknown>;
79
+ } catch {
80
+ // The token is opaque — no claims to read. Callers fall back to the
81
+ // network identity below.
82
+ return undefined;
83
+ }
84
+ for (const claim of IDENTITY_CLAIM_KEYS) {
85
+ const value = payload[claim];
86
+ if (typeof value === "string" && value.length > 0 && value !== "unauthenticated") {
87
+ return value;
88
+ }
89
+ }
90
+ return undefined;
91
+ }
92
+
93
+ /** A single identity string from `GetUserStatus`, if the upstream reports one. */
94
+ export function identityFromDevinUserStatus(planInfo: unknown): string | undefined {
95
+ if (typeof planInfo !== "object" || planInfo === null) return undefined;
96
+ const info = planInfo as {
97
+ userStatus?: { email?: string; teamId?: string };
98
+ planInfo?: { devinInfo?: { accountDisplayName?: string; orgId?: string } };
99
+ };
100
+ const email = info.userStatus?.email?.trim();
101
+ if (email) return email;
102
+ const displayName = info.planInfo?.devinInfo?.accountDisplayName?.trim();
103
+ if (displayName) return displayName;
104
+ const orgId = info.planInfo?.devinInfo?.orgId?.trim();
105
+ if (orgId) return orgId;
106
+ const teamId = info.userStatus?.teamId?.trim();
107
+ if (teamId) return teamId;
108
+ return undefined;
109
+ }
110
+
111
+ /**
112
+ * Resolves the human-friendly label for a Devin credential: JWT claims first
113
+ * (free), then `GetUserStatus` (network). Never throws — a failed lookup
114
+ * returns `undefined`, leaving the caller's default label in place.
115
+ */
116
+ export async function resolveDevinAccountLabel(
117
+ credential: string,
118
+ fetcher: typeof fetch = fetch,
119
+ ): Promise<string | undefined> {
120
+ const jwtLabel = identityLabelFromDevinCredential(credential);
121
+ if (jwtLabel) return jwtLabel;
122
+ try {
123
+ const response = await callDevinUnary<Record<string, unknown>>(
124
+ DEVIN_GET_USER_STATUS_PATH,
125
+ DevinMessageTypes.GetUserStatusRequest,
126
+ DevinMessageTypes.GetUserStatusResponse,
127
+ { metadata: { apiKey: credential } },
128
+ { baseUrl: DEVIN_DEFAULT_BASE_URL, fetchImpl: fetcher, signal: AbortSignal.timeout(10_000) },
129
+ );
130
+ return identityFromDevinUserStatus(response);
131
+ } catch {
132
+ return undefined;
133
+ }
134
+ }
135
+
136
+ // ── Devin CLI flow (app.devin.ai) ──
137
+
138
+ const DEVIN_AUTHORIZE_URL = "https://app.devin.ai/auth/cli/continue";
139
+ const DEVIN_TOKEN_URL = "https://api.devin.ai/auth/cli/token";
140
+ const DEVIN_BROWSER_REDIRECT_URI = "http://127.0.0.1:59653/callback";
141
+
142
+ export const devinOAuthClient: OAuthLoginClient = {
143
+ supportsDeviceCode: false,
144
+ supportsBrowserCode: true,
145
+ browserRedirectUri: DEVIN_BROWSER_REDIRECT_URI,
146
+
147
+ buildAuthorizeUrl(request: OAuthAuthorizeRequest): string {
148
+ const params = new URLSearchParams({
149
+ redirect_uri: DEVIN_BROWSER_REDIRECT_URI,
150
+ state: request.state,
151
+ prompt: "select_account",
152
+ code_challenge: request.codeChallenge,
153
+ code_challenge_method: "S256",
154
+ });
155
+ return `${DEVIN_AUTHORIZE_URL}?${params.toString()}`;
156
+ },
157
+
158
+ async exchangeCode(
159
+ code: string,
160
+ codeVerifier: string,
161
+ _redirectUri: string,
162
+ _state?: string,
163
+ _context?: OAuthCodeExchangeContext,
164
+ ): Promise<OAuthExchangeResult> {
165
+ const response = await fetch(DEVIN_TOKEN_URL, {
166
+ method: "POST",
167
+ headers: { "content-type": "application/json", accept: "application/json" },
168
+ body: JSON.stringify({ code, code_verifier: codeVerifier }),
169
+ });
170
+ if (!response.ok) {
171
+ const text = await response.text().catch(() => "");
172
+ throw new Error(`Devin token exchange failed: HTTP ${response.status} ${text}`);
173
+ }
174
+ const body = (await response.json()) as { token?: string };
175
+ const token = body.token;
176
+ if (!token) throw new Error("Devin token exchange returned no token");
177
+
178
+ // Parse JWT exp, fallback to 1 year.
179
+ let expiresAt: Date;
180
+ try {
181
+ const claims = decodeJwt(token);
182
+ expiresAt = claims.exp ? new Date(claims.exp * 1000) : new Date(Date.now() + 365 * 24 * 3600 * 1000);
183
+ } catch {
184
+ expiresAt = new Date(Date.now() + 365 * 24 * 3600 * 1000);
185
+ }
186
+
187
+ // The exchange only returns a token; the label comes from the token's
188
+ // own claims (when present) or `GetUserStatus`. Never fail the login on
189
+ // a label lookup.
190
+ const accountLabel = await resolveDevinAccountLabel(token).catch(() => undefined);
191
+
192
+ return {
193
+ access: token,
194
+ refresh: "",
195
+ expiresAt,
196
+ ...(accountLabel ? { accountLabel } : {}),
197
+ };
198
+ },
199
+
200
+ async importCredential(input: OAuthImportInput): Promise<OAuthExchangeResult> {
201
+ const credential = input.credential.trim();
202
+ if (!credential) throw new Error("Devin credential is empty");
203
+ // The key itself is the identity; resolve a label when the material can
204
+ // provide one (JWT claims or `GetUserStatus`), never failing on it.
205
+ const accountLabel = await resolveDevinAccountLabel(credential).catch(() => undefined);
206
+ return {
207
+ access: credential,
208
+ refresh: "",
209
+ expiresAt: new Date(8640000000000000),
210
+ ...(accountLabel ? { accountLabel } : {}),
211
+ ...(input.accountLabel ? { accountLabel: input.accountLabel } : {}),
212
+ };
213
+ },
214
+ };
215
+
216
+ // ── Windsurf Enterprise flow (windsurf.com/editor/signin) ──
217
+
218
+ const WINDSURF_AUTHORIZE_URL = "https://windsurf.com/editor/signin";
219
+
220
+ /** Loopback port the official Devin CLI uses for the Windsurf flow. */
221
+ export const WINDSURF_CALLBACK_PORT = 59654;
222
+ /** Loopback hostname for the Windsurf flow. */
223
+ export const WINDSURF_PREFERRED_HOSTNAME = "127.0.0.1";
224
+
225
+ export const devinWindsurfOAuthClient: OAuthLoginClient = {
226
+ supportsDeviceCode: false,
227
+ supportsBrowserCode: true,
228
+
229
+ buildAuthorizeUrl(request: OAuthAuthorizeRequest): string {
230
+ const params = new URLSearchParams({
231
+ response_type: "code",
232
+ redirect_uri: request.redirectUri,
233
+ state: request.state,
234
+ code_challenge: request.codeChallenge,
235
+ code_challenge_method: "S256",
236
+ prompt: "login",
237
+ redirect_parameters_type: "query",
238
+ });
239
+ return `${WINDSURF_AUTHORIZE_URL}?${params.toString()}`;
240
+ },
241
+
242
+ async exchangeCode(
243
+ code: string,
244
+ codeVerifier: string,
245
+ _redirectUri: string,
246
+ _state?: string,
247
+ _context?: OAuthCodeExchangeContext,
248
+ ): Promise<OAuthExchangeResult> {
249
+ const response = await callDevinUnary<{
250
+ apiKey?: string;
251
+ name?: string;
252
+ apiServerUrl?: string;
253
+ devinWebappHost?: string;
254
+ devinApiUrl?: string;
255
+ }>(
256
+ DEVIN_EXCHANGE_PATH,
257
+ DevinMessageTypes.ExchangePKCEAuthorizationCodeRequest,
258
+ DevinMessageTypes.ExchangePKCEAuthorizationCodeResponse,
259
+ { authorizationCode: code, codeVerifier },
260
+ { baseUrl: DEVIN_DEFAULT_BASE_URL },
261
+ );
262
+ const apiKey = response.apiKey;
263
+ if (!apiKey) throw new Error("Windsurf code exchange returned no API key");
264
+ // The exchange returns the `g`-prefixed wire form (`gsk-ws-…`); RPCs
265
+ // authenticate with the raw key.
266
+ const key = apiKey.startsWith("gsk-") ? apiKey.slice(1) : apiKey;
267
+ // Prefer the upstream-reported name; fall back to the seat key's identity
268
+ // claims or `GetUserStatus` — never fail the login on a label lookup.
269
+ const accountLabel =
270
+ response.name?.trim() || (await resolveDevinAccountLabel(key).catch(() => undefined));
271
+ return {
272
+ access: key,
273
+ refresh: "",
274
+ expiresAt: new Date(8640000000000000), // seat key: never expires
275
+ ...(accountLabel ? { accountLabel } : {}),
276
+ };
277
+ },
278
+ };
279
+
280
+ // ── CLI adopt (credentials.toml) ──
281
+
282
+ const KNOWN_API_HOSTS = new Set(["server.codeium.com", "server.enterprise.windsurf.com"]);
283
+
284
+ /** Candidate `credentials.toml` paths per platform. */
285
+ export function devinCliCredentialPaths(): string[] {
286
+ const paths: string[] = [];
287
+ if (process.platform === "win32") {
288
+ const appData = process.env.APPDATA;
289
+ if (appData) paths.push(join(appData, "devin", "credentials.toml"));
290
+ paths.push(join(process.env.HOME ?? "", ".local", "share", "devin", "credentials.toml"));
291
+ } else {
292
+ const xdg = process.env.XDG_DATA_HOME;
293
+ if (xdg) paths.push(join(xdg, "devin", "credentials.toml"));
294
+ paths.push(join(process.env.HOME ?? "", ".local", "share", "devin", "credentials.toml"));
295
+ if (process.platform === "darwin") {
296
+ paths.push(join(process.env.HOME ?? "", "Library", "Application Support", "devin", "credentials.toml"));
297
+ }
298
+ }
299
+ return [...new Set(paths)];
300
+ }
301
+
302
+ /** Parses a Devin CLI `credentials.toml` and returns the Windsurf seat key. */
303
+ export function readDevinCliCredentials(file: string): string {
304
+ const text = readFileSync(file, "utf8");
305
+ // Minimal TOML parse: key = "value" lines.
306
+ const record: Record<string, string> = {};
307
+ for (const line of text.split(/\r?\n/)) {
308
+ const trimmed = line.trim();
309
+ if (!trimmed || trimmed.startsWith("#")) continue;
310
+ const eq = trimmed.indexOf("=");
311
+ if (eq < 0) continue;
312
+ const key = trimmed.slice(0, eq).trim();
313
+ let value = trimmed.slice(eq + 1).trim();
314
+ if (value.startsWith('"') && value.endsWith('"')) value = value.slice(1, -1);
315
+ record[key] = value;
316
+ }
317
+ const key = record["windsurf_api_key"]?.trim() ?? "";
318
+ if (!key) throw new Error(`Devin CLI credentials at ${file} have no windsurf_api_key`);
319
+ const serverUrl = record["api_server_url"]?.trim();
320
+ if (serverUrl) {
321
+ let host: string | undefined;
322
+ try {
323
+ host = new URL(serverUrl).host;
324
+ } catch {
325
+ host = undefined;
326
+ }
327
+ if (!host || !KNOWN_API_HOSTS.has(host)) {
328
+ throw new Error(`Devin CLI credentials at ${file} point at unsupported API server`);
329
+ }
330
+ }
331
+ return key;
332
+ }
333
+
334
+ /** Reads the first existing credentials file and returns its seat key. */
335
+ export function loginDevinCliHook(): Promise<string> {
336
+ for (const file of devinCliCredentialPaths()) {
337
+ if (!existsSync(file)) continue;
338
+ try {
339
+ return Promise.resolve(readDevinCliCredentials(file));
340
+ } catch (error) {
341
+ // First existing file that fails validation wins; no fallback probing.
342
+ return Promise.reject(error);
343
+ }
344
+ }
345
+ return Promise.reject(
346
+ new Error(
347
+ `No Devin CLI credentials found (probed: ${devinCliCredentialPaths().join(", ")}). Run \`devin auth login\`, then retry.`,
348
+ ),
349
+ );
350
+ }
351
+
352
+ // ── Import credential (raw API key / session token) ──
353
+ // `devinOAuthClient.importCredential` handles pasted keys; no separate client.