cartethyia 2.5.10 → 2.6.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 (369) hide show
  1. package/.env.example +8 -0
  2. package/dist/dashboard/assets/{BannedPage-Cd30Z0b9.js → BannedPage-wr370U7a.js} +1 -1
  3. package/dist/dashboard/assets/BannedPage-wr370U7a.js.gz +0 -0
  4. package/dist/dashboard/assets/{CliToolDetailPage-wf5u-ww6.js → CliToolDetailPage-D1sCezWa.js} +1 -1
  5. package/dist/dashboard/assets/CliToolDetailPage-D1sCezWa.js.gz +0 -0
  6. package/dist/dashboard/assets/{CliToolsPage-DykPvuck.js → CliToolsPage-DVWbJPEQ.js} +1 -1
  7. package/dist/dashboard/assets/CliToolsPage-DVWbJPEQ.js.gz +0 -0
  8. package/dist/dashboard/assets/{CombosPage-DwvSD3vs.js → CombosPage-CZc7fyMe.js} +1 -1
  9. package/dist/dashboard/assets/CombosPage-CZc7fyMe.js.gz +0 -0
  10. package/dist/dashboard/assets/{ConsoleLogPage-CIr7KDex.js → ConsoleLogPage-OPN3qRCa.js} +1 -1
  11. package/dist/dashboard/assets/ConsoleLogPage-OPN3qRCa.js.gz +0 -0
  12. package/dist/dashboard/assets/{CustomizationPage-82X0DDdH.js → CustomizationPage-DGTSqmwm.js} +1 -1
  13. package/dist/dashboard/assets/CustomizationPage-DGTSqmwm.js.gz +0 -0
  14. package/dist/dashboard/assets/HealthEventsModal-BujG2QP4.js +1 -0
  15. package/dist/dashboard/assets/HealthEventsModal-BujG2QP4.js.gz +0 -0
  16. package/dist/dashboard/assets/{LoginPage-CS5mPuVF.js → LoginPage-C_Jd_KgP.js} +1 -1
  17. package/dist/dashboard/assets/LoginPage-C_Jd_KgP.js.gz +0 -0
  18. package/dist/dashboard/assets/{ModelPicker-C0UCUsVJ.js → ModelPicker-DVny4S5_.js} +1 -1
  19. package/dist/dashboard/assets/ModelPicker-DVny4S5_.js.gz +0 -0
  20. package/dist/dashboard/assets/OverviewPage-Bpbu-VeU.js +1 -0
  21. package/dist/dashboard/assets/OverviewPage-Bpbu-VeU.js.gz +0 -0
  22. package/dist/dashboard/assets/ProviderDetailPage-BEhXOO4L.js +3 -0
  23. package/dist/dashboard/assets/ProviderDetailPage-BEhXOO4L.js.gz +0 -0
  24. package/dist/dashboard/assets/{ProvidersPage-vdja5ZPK.js → ProvidersPage-DbQnexQd.js} +1 -1
  25. package/dist/dashboard/assets/ProvidersPage-DbQnexQd.js.gz +0 -0
  26. package/dist/dashboard/assets/{ProxyPage-BB4CNm4-.js → ProxyPage-ByprzADo.js} +1 -1
  27. package/dist/dashboard/assets/ProxyPage-ByprzADo.js.gz +0 -0
  28. package/dist/dashboard/assets/QuotaPage-CvSfv6tP.js +1 -0
  29. package/dist/dashboard/assets/QuotaPage-CvSfv6tP.js.gz +0 -0
  30. package/dist/dashboard/assets/SettingsPage-_NzLq3C-.js +1 -0
  31. package/dist/dashboard/assets/SettingsPage-_NzLq3C-.js.gz +0 -0
  32. package/dist/dashboard/assets/{SetupPage-FadUOl9S.js → SetupPage-Bg9DcG-G.js} +1 -1
  33. package/dist/dashboard/assets/SetupPage-Bg9DcG-G.js.gz +0 -0
  34. package/dist/dashboard/assets/{SortableList-Cfy6_Khv.js → SortableList-C2PWPzJm.js} +1 -1
  35. package/dist/dashboard/assets/SortableList-C2PWPzJm.js.gz +0 -0
  36. package/dist/dashboard/assets/{StudioPage-CM92fgJf.js → StudioPage-Dky1zZMt.js} +1 -1
  37. package/dist/dashboard/assets/StudioPage-Dky1zZMt.js.gz +0 -0
  38. package/dist/dashboard/assets/{UsagePage-BT4MyQeT.js → UsagePage-C5Vdpd_c.js} +2 -2
  39. package/dist/dashboard/assets/UsagePage-C5Vdpd_c.js.gz +0 -0
  40. package/dist/dashboard/assets/{api-keys-DQYLQxpW.js → api-keys-C23S9sgp.js} +1 -1
  41. package/dist/dashboard/assets/api-keys-C23S9sgp.js.gz +0 -0
  42. package/dist/dashboard/assets/{app-B7pVRhJ1.js → app-2KhtHCv9.js} +1 -1
  43. package/dist/dashboard/assets/{app-B7pVRhJ1.js.gz → app-2KhtHCv9.js.gz} +0 -0
  44. package/dist/dashboard/assets/app-CEeaMHOy.css +2 -0
  45. package/dist/dashboard/assets/app-CEeaMHOy.css.gz +0 -0
  46. package/dist/dashboard/assets/{assert-C9FD_JwJ.js → assert-DU6qrMA_.js} +1 -1
  47. package/dist/dashboard/assets/assert-DU6qrMA_.js.gz +0 -0
  48. package/dist/dashboard/assets/{badge-Bvyr7D0u.js → badge-CKsF123d.js} +1 -1
  49. package/dist/dashboard/assets/badge-CKsF123d.js.gz +0 -0
  50. package/dist/dashboard/assets/{banner-DIvKAZih.js → banner-8j7uChA9.js} +1 -1
  51. package/dist/dashboard/assets/banner-8j7uChA9.js.gz +0 -0
  52. package/dist/dashboard/assets/{card-D5_gYIS_.js → card-CdsSlWA3.js} +1 -1
  53. package/dist/dashboard/assets/card-CdsSlWA3.js.gz +0 -0
  54. package/dist/dashboard/assets/{cli-tools-CNqzrfdb.js → cli-tools-BaFUuFFF.js} +1 -1
  55. package/dist/dashboard/assets/cli-tools-BaFUuFFF.js.gz +0 -0
  56. package/dist/dashboard/assets/{clipboard-button-B6vDBtbm.js → clipboard-button-uL5aYLfW.js} +1 -1
  57. package/dist/dashboard/assets/clipboard-button-uL5aYLfW.js.gz +0 -0
  58. package/dist/dashboard/assets/{dialog-CpjrgdwJ.js → dialog-C07hr5_G.js} +1 -1
  59. package/dist/dashboard/assets/dialog-C07hr5_G.js.gz +0 -0
  60. package/dist/dashboard/assets/{drawer-BWmt3b5y.js → drawer-BPO1TcKH.js} +1 -1
  61. package/dist/dashboard/assets/drawer-BPO1TcKH.js.gz +0 -0
  62. package/dist/dashboard/assets/entry-BNFjUjQ0.js +4 -0
  63. package/dist/dashboard/assets/entry-BNFjUjQ0.js.gz +0 -0
  64. package/dist/dashboard/assets/{entry-C_oakV3z.js → entry-Bz_CtDfC.js} +1 -1
  65. package/dist/dashboard/assets/entry-Bz_CtDfC.js.gz +0 -0
  66. package/dist/dashboard/assets/entry-GJRbmrpA.js +1 -0
  67. package/dist/dashboard/assets/entry-GJRbmrpA.js.gz +0 -0
  68. package/dist/dashboard/assets/{github-badge-RRHHWGxh.js → github-badge-DmQreSDd.js} +1 -1
  69. package/dist/dashboard/assets/github-badge-DmQreSDd.js.gz +0 -0
  70. package/dist/dashboard/assets/{index-Bhey_rg_.js → index-DyllNVCY.js} +2 -2
  71. package/dist/dashboard/assets/index-DyllNVCY.js.gz +0 -0
  72. package/dist/dashboard/assets/{inline-C2_EQ5Uf.js → inline-C9dCYaBZ.js} +1 -1
  73. package/dist/dashboard/assets/inline-C9dCYaBZ.js.gz +0 -0
  74. package/dist/dashboard/assets/{input-BMRlQ450.js → input-CjCnXweJ.js} +1 -1
  75. package/dist/dashboard/assets/input-CjCnXweJ.js.gz +0 -0
  76. package/dist/dashboard/assets/{layout-XR5xP8ew.js → layout-V6y8DAkl.js} +1 -1
  77. package/dist/dashboard/assets/layout-V6y8DAkl.js.gz +0 -0
  78. package/dist/dashboard/assets/{list-row-Cw07dioc.js → list-row-CM1AaG_y.js} +1 -1
  79. package/dist/dashboard/assets/list-row-CM1AaG_y.js.gz +0 -0
  80. package/dist/dashboard/assets/{live-BivGfuUs.js → live-ta6GMb-8.js} +1 -1
  81. package/dist/dashboard/assets/live-ta6GMb-8.js.gz +0 -0
  82. package/dist/dashboard/assets/{model-bans-CmffjLuG.js → model-bans-BmYTmbAk.js} +1 -1
  83. package/dist/dashboard/assets/model-bans-BmYTmbAk.js.gz +0 -0
  84. package/dist/dashboard/assets/{mutation-46P0oWMe.js → mutation-g_fduiNw.js} +1 -1
  85. package/dist/dashboard/assets/mutation-g_fduiNw.js.gz +0 -0
  86. package/dist/dashboard/assets/{numbers-DrdA9oSM.js → numbers-BOevJzdz.js} +1 -1
  87. package/dist/dashboard/assets/numbers-BOevJzdz.js.gz +0 -0
  88. package/dist/dashboard/assets/{query-keys-BFhGpwR1.js → query-keys-UETqfytp.js} +1 -1
  89. package/dist/dashboard/assets/query-keys-UETqfytp.js.gz +0 -0
  90. package/dist/dashboard/assets/{routing-CAb4F37R.js → routing-BPUo-W8d.js} +1 -1
  91. package/dist/dashboard/assets/routing-BPUo-W8d.js.gz +0 -0
  92. package/dist/dashboard/assets/{select-CxVVB__N.js → select-DAhoTabv.js} +1 -1
  93. package/dist/dashboard/assets/select-DAhoTabv.js.gz +0 -0
  94. package/dist/dashboard/assets/{settings-DNX9sydi.js → settings--3hxSyry.js} +1 -1
  95. package/dist/dashboard/assets/settings--3hxSyry.js.gz +0 -0
  96. package/dist/dashboard/assets/{stack-uPOwM9Hs.js → stack-_gfTdLVB.js} +1 -1
  97. package/dist/dashboard/assets/stack-_gfTdLVB.js.gz +0 -0
  98. package/dist/dashboard/assets/{state-D1Yz79iL.js → state-2c5V4zo7.js} +1 -1
  99. package/dist/dashboard/assets/state-2c5V4zo7.js.gz +0 -0
  100. package/dist/dashboard/assets/{switch-sevsRrRo.js → switch-Dkke7Naf.js} +1 -1
  101. package/dist/dashboard/assets/switch-Dkke7Naf.js.gz +0 -0
  102. package/dist/dashboard/assets/{useMutation-Dem0lXQj.js → useMutation-EDFRkn1i.js} +1 -1
  103. package/dist/dashboard/assets/useMutation-EDFRkn1i.js.gz +0 -0
  104. package/dist/dashboard/index.html +1 -1
  105. package/dist/dashboard/index.html.gz +0 -0
  106. package/dist/dashboard/precompressed-assets.json +51 -51
  107. package/migrations/README.md +52 -52
  108. package/migrations/full-postgres/0020_add_telemetry_event_analytics.sql +77 -0
  109. package/migrations/full-postgres/0021_add_api_key_concurrency_tolerance.sql +13 -0
  110. package/migrations/full-postgres/0022_add_inferhub_config_key.sql +17 -0
  111. package/migrations/full-postgres/0023_drop_api_key_concurrency_tolerance.sql +13 -0
  112. package/migrations/lite-sqlite3/0020_add_telemetry_event_analytics.sql +69 -0
  113. package/migrations/lite-sqlite3/0021_add_api_key_concurrency_tolerance.sql +13 -0
  114. package/migrations/lite-sqlite3/0022_add_inferhub_config_key.sql +17 -0
  115. package/migrations/lite-sqlite3/0023_drop_api_key_concurrency_tolerance.sql +13 -0
  116. package/package.json +96 -95
  117. package/scripts/cli/admin.ts +126 -128
  118. package/scripts/cli/autostart.ts +237 -237
  119. package/scripts/cli/background.ts +123 -110
  120. package/scripts/cli/bin/carte.cjs +8 -8
  121. package/scripts/cli/bin/cartethyia.cjs +177 -167
  122. package/scripts/cli/console-menu.ts +45 -30
  123. package/scripts/cli/controller.ts +145 -0
  124. package/scripts/cli/env.ts +99 -99
  125. package/scripts/cli/gateway.ts +264 -260
  126. package/scripts/cli/instance.ts +234 -224
  127. package/scripts/cli/main.ts +195 -167
  128. package/scripts/cli/platform.ts +64 -64
  129. package/scripts/cli/prompt.ts +217 -79
  130. package/scripts/cli/services.ts +88 -88
  131. package/scripts/cli/setup.ts +445 -445
  132. package/scripts/cli/start.ts +85 -85
  133. package/scripts/cli/startup-signal.ts +23 -23
  134. package/scripts/cli/telemetry.ts +70 -0
  135. package/scripts/cli/tray/hidden-window.vbs +16 -2
  136. package/scripts/cli/tray/index.ts +263 -263
  137. package/scripts/cli/tray/windows.ps1 +107 -107
  138. package/scripts/cli/tray.ts +29 -4
  139. package/scripts/cli/update.ts +39 -39
  140. package/scripts/cli/version.ts +67 -67
  141. package/scripts/cli/wordmark.ts +58 -58
  142. package/src/boot/app.ts +16 -1
  143. package/src/boot/dependencies.ts +128 -25
  144. package/src/config/resources.ts +137 -0
  145. package/src/config/runtime.ts +133 -76
  146. package/src/config/spec.ts +30 -29
  147. package/src/config/telemetry.ts +0 -25
  148. package/src/console/api-keys/bucket-spend.ts +14 -17
  149. package/src/console/api-keys/contracts.ts +410 -410
  150. package/src/console/api-keys/routes.ts +12 -0
  151. package/src/console/audit/store.ts +2 -3
  152. package/src/console/auth/setup-service.ts +8 -1
  153. package/src/console/backup/routes.ts +7 -0
  154. package/src/console/backup/service.ts +463 -463
  155. package/src/console/backup/store.ts +16 -11
  156. package/src/console/backup/validate.ts +1 -4
  157. package/src/console/cli-tools/fs-ops.ts +18 -2
  158. package/src/console/data-management/contracts.ts +1 -8
  159. package/src/console/data-management/operations.ts +61 -48
  160. package/src/console/data-management/routes.ts +4 -2
  161. package/src/console/domain-registration.ts +25 -3
  162. package/src/console/inferhub/client.ts +139 -0
  163. package/src/console/inferhub/key-store.ts +129 -0
  164. package/src/console/inferhub/normalize.ts +347 -0
  165. package/src/console/inferhub/routes.ts +411 -0
  166. package/src/console/inferhub/store.ts +109 -0
  167. package/src/console/inferhub/types.ts +183 -0
  168. package/src/console/observability/contracts.ts +2 -41
  169. package/src/console/observability/store.ts +176 -371
  170. package/src/console/providers/catalog/public-model-store.ts +0 -0
  171. package/src/console/providers/catalog/store.ts +23 -36
  172. package/src/console/quota/account-quota-shared.ts +52 -52
  173. package/src/console/quota/account-quota-tenant.ts +16 -24
  174. package/src/console/quota/refresh.ts +441 -441
  175. package/src/console/routing/pools/import-parse.ts +206 -206
  176. package/src/console/routing/pools/operations.ts +543 -543
  177. package/src/console/routing/pools/probe-verdict.ts +132 -132
  178. package/src/console/routing/pools/routes.ts +181 -181
  179. package/src/console/settings/contracts.ts +42 -40
  180. package/src/console/settings/store.ts +25 -25
  181. package/src/console/share/share-stats.ts +22 -4
  182. package/src/console/share/share-usage.ts +30 -4
  183. package/src/console/shared/cursor.ts +15 -0
  184. package/src/console/updates/routes.ts +12 -0
  185. package/src/main.ts +13 -5
  186. package/src/network/pool/resolver.ts +1104 -1104
  187. package/src/observability/client-name.ts +22 -0
  188. package/src/observability/event-log.ts +5 -29
  189. package/src/observability/event-query.ts +690 -0
  190. package/src/observability/log-ring.ts +26 -2
  191. package/src/observability/log-sanitize.ts +118 -0
  192. package/src/observability/logger.ts +17 -13
  193. package/src/observability/metrics.ts +35 -0
  194. package/src/observability/payload-capture.ts +114 -41
  195. package/src/observability/payload-store.ts +249 -24
  196. package/src/observability/raw-event-writer.ts +118 -0
  197. package/src/observability/runtime-metrics.ts +71 -1
  198. package/src/observability/telemetry-buffer.ts +100 -17
  199. package/src/observability/telemetry-reconciliation.ts +417 -0
  200. package/src/persistence/boot.ts +20 -9
  201. package/src/persistence/db-pg.ts +13 -0
  202. package/src/persistence/db-sqlite.ts +569 -497
  203. package/src/persistence/dialect.ts +3 -2
  204. package/src/persistence/migrate.ts +181 -181
  205. package/src/persistence/schema.ts +1496 -1406
  206. package/src/persistence/shared-cache.ts +5 -1
  207. package/src/persistence/stores/api-key-store.ts +581 -581
  208. package/src/persistence/stores/telemetry-store.ts +124 -63
  209. package/src/protocol/reasoning-text.ts +30 -0
  210. package/src/protocol/response/chat.ts +33 -7
  211. package/src/protocol/response/codex.ts +14 -2
  212. package/src/protocol/response/messages.ts +5 -2
  213. package/src/providers/authentication/oauth-flow-store.ts +3 -10
  214. package/src/providers/bundled-discovery-providers.ts +122 -122
  215. package/src/providers/default-registry.ts +10 -0
  216. package/src/providers/discovery/catalog/catalog-blob.ts +18 -18
  217. package/src/providers/discovery/models-dev-catalog.ts +354 -354
  218. package/src/providers/discovery/probe-phases.ts +43 -7
  219. package/src/providers/discovery/probing-service.ts +70 -32
  220. package/src/providers/integrations/antigravity/antigravity.ts +9 -2
  221. package/src/providers/integrations/buddy/buddy-catalog-shared.ts +85 -17
  222. package/src/providers/integrations/buddy/buddy-chat-shared.ts +934 -934
  223. package/src/providers/integrations/buddy/buddy-checkin.ts +5 -9
  224. package/src/providers/integrations/buddy/buddy-discovery-shared.ts +3 -7
  225. package/src/providers/integrations/buddy/buddy-quota-shared.ts +3 -1
  226. package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +57 -49
  227. package/src/providers/integrations/buddy/codebuddy/provider.ts +180 -180
  228. package/src/providers/integrations/buddy/workbuddy/provider.ts +206 -206
  229. package/src/providers/integrations/buddy/workbuddy/quota.ts +161 -161
  230. package/src/providers/integrations/claude/claude-quota.ts +2 -2
  231. package/src/providers/integrations/claude/claude-user-profiles.ts +3 -2
  232. package/src/providers/integrations/claude/claude.ts +3 -4
  233. package/src/providers/integrations/cline/cline.ts +94 -8
  234. package/src/providers/integrations/codex/codex.ts +61 -37
  235. package/src/providers/integrations/cursor/cursor-catalog.ts +368 -368
  236. package/src/providers/integrations/cursor/cursor-http2.ts +300 -300
  237. package/src/providers/integrations/cursor/cursor-identity.ts +2 -4
  238. package/src/providers/integrations/cursor/cursor-request.ts +11 -0
  239. package/src/providers/integrations/cursor/cursor.ts +29 -17
  240. package/src/providers/integrations/cursor/protocol/framing.ts +129 -129
  241. package/src/providers/integrations/cursor/protocol/messages.ts +2380 -2380
  242. package/src/providers/integrations/cursor/protocol/struct.ts +305 -305
  243. package/src/providers/integrations/cursor/protocol/tool-canonical.ts +275 -0
  244. package/src/providers/integrations/grok/grok-quota.ts +279 -279
  245. package/src/providers/integrations/grok/grok-ratelimit-store.ts +73 -73
  246. package/src/providers/integrations/grok/grok-ratelimit.ts +218 -218
  247. package/src/providers/integrations/hermes.ts +7 -1
  248. package/src/providers/integrations/inferhub.ts +201 -73
  249. package/src/providers/integrations/kilo/kilo.ts +152 -152
  250. package/src/providers/integrations/kiro/kiro-machine-id.ts +2 -4
  251. package/src/providers/integrations/openrouter/provider.ts +129 -129
  252. package/src/providers/integrations/qoder/qoder-quota.ts +193 -192
  253. package/src/providers/integrations/qoder/qoder-realm.ts +106 -106
  254. package/src/providers/integrations/trae/trae-oauth.ts +4 -26
  255. package/src/providers/integrations/trae/trae-quota.ts +389 -384
  256. package/src/providers/integrations/trae/trae-realm.ts +15 -2
  257. package/src/providers/integrations/xiaomi-mimo/think-stream.ts +100 -24
  258. package/src/providers/integrations/zcode/oauth.ts +1 -1
  259. package/src/providers/operations/account-health-service.ts +605 -279
  260. package/src/providers/provider-metadata.ts +12 -1
  261. package/src/providers/provider-model-definition.ts +373 -373
  262. package/src/providers/quota/quota-contracts.ts +3 -7
  263. package/src/providers/search/search-provider.ts +2 -6
  264. package/src/security/admission/contracts.ts +10 -0
  265. package/src/security/admission/in-memory-store.ts +89 -14
  266. package/src/security/admission/lua.ts +191 -182
  267. package/src/security/admission/redis-store.ts +30 -0
  268. package/src/security/admission/service.ts +18 -0
  269. package/src/security/api-key-auth-cache.ts +96 -0
  270. package/src/security/api-key-auth.ts +11 -100
  271. package/src/security/client-router-fingerprint.ts +3 -7
  272. package/src/security/ip-boundary.ts +7 -3
  273. package/src/shared/coerce.ts +67 -0
  274. package/src/shared/hash.ts +6 -0
  275. package/src/shared/time.ts +7 -0
  276. package/src/transport/dispatch/attempt-finalize.ts +26 -138
  277. package/src/transport/dispatch/attempt-loop.ts +103 -81
  278. package/src/transport/dispatch/capture-policy.ts +78 -0
  279. package/src/transport/dispatch/proxy-request.ts +4 -2
  280. package/src/transport/dispatch/streaming/encoder.ts +111 -5
  281. package/src/transport/dispatch/streaming/stream.ts +19 -2
  282. package/src/transport/dispatch/streaming/thinking-loop.ts +300 -0
  283. package/src/transport/failure-policy.ts +27 -0
  284. package/src/transport/guards/abuse-guard.ts +2 -2
  285. package/src/transport/guards/auth-guard.ts +17 -0
  286. package/src/transport/guards/body-policy.ts +3 -2
  287. package/src/transport/guards/concurrency-guard.ts +89 -13
  288. package/src/transport/guards/early-rejection-capture.ts +43 -3
  289. package/src/transport/guards/error-lifecycle.ts +10 -2
  290. package/src/transport/guards/guard-errors.ts +23 -0
  291. package/src/transport/guards/headroom-guard.ts +41 -7
  292. package/src/transport/guards/pipeline.ts +24 -0
  293. package/src/transport/guards/request-context.ts +2 -1
  294. package/src/transport/routing/admission.ts +51 -9
  295. package/src/transport/routing/bounded-lru.ts +49 -0
  296. package/src/transport/routing/candidate-index.ts +88 -0
  297. package/src/transport/routing/reservations.ts +121 -7
  298. package/src/transport/routing/round-robin.ts +10 -22
  299. package/src/transport/routing/route-catalog.ts +26 -13
  300. package/src/transport/routing/route-model.ts +22 -2
  301. package/src/transport/routing/router.ts +53 -31
  302. package/src/transport/surface/chat/encode.ts +2 -3
  303. package/src/transport/surface/chat/parse.ts +2 -1
  304. package/src/transport/surface/dialects.ts +11 -3
  305. package/src/transport/surface/messages/encode.ts +2 -1
  306. package/src/transport/surface/messages/parse.ts +3 -1
  307. package/src/transport/surface/messages/stream.ts +2 -6
  308. package/src/workers/maintenance-lease.ts +200 -0
  309. package/src/workers/scheduler.ts +101 -1
  310. package/dist/dashboard/assets/BannedPage-Cd30Z0b9.js.gz +0 -0
  311. package/dist/dashboard/assets/CliToolDetailPage-wf5u-ww6.js.gz +0 -0
  312. package/dist/dashboard/assets/CliToolsPage-DykPvuck.js.gz +0 -0
  313. package/dist/dashboard/assets/CombosPage-DwvSD3vs.js.gz +0 -0
  314. package/dist/dashboard/assets/ConsoleLogPage-CIr7KDex.js.gz +0 -0
  315. package/dist/dashboard/assets/CustomizationPage-82X0DDdH.js.gz +0 -0
  316. package/dist/dashboard/assets/HealthEventsModal-BYPucTTn.js +0 -1
  317. package/dist/dashboard/assets/HealthEventsModal-BYPucTTn.js.gz +0 -0
  318. package/dist/dashboard/assets/LoginPage-CS5mPuVF.js.gz +0 -0
  319. package/dist/dashboard/assets/ModelPicker-C0UCUsVJ.js.gz +0 -0
  320. package/dist/dashboard/assets/OverviewPage-Dk_ew3YU.js +0 -1
  321. package/dist/dashboard/assets/OverviewPage-Dk_ew3YU.js.gz +0 -0
  322. package/dist/dashboard/assets/ProviderDetailPage-CAiRn2Q0.js +0 -3
  323. package/dist/dashboard/assets/ProviderDetailPage-CAiRn2Q0.js.gz +0 -0
  324. package/dist/dashboard/assets/ProvidersPage-vdja5ZPK.js.gz +0 -0
  325. package/dist/dashboard/assets/ProxyPage-BB4CNm4-.js.gz +0 -0
  326. package/dist/dashboard/assets/QuotaPage-FEc4iNyq.js +0 -1
  327. package/dist/dashboard/assets/QuotaPage-FEc4iNyq.js.gz +0 -0
  328. package/dist/dashboard/assets/SettingsPage-Dlfi5L4N.js +0 -1
  329. package/dist/dashboard/assets/SettingsPage-Dlfi5L4N.js.gz +0 -0
  330. package/dist/dashboard/assets/SetupPage-FadUOl9S.js.gz +0 -0
  331. package/dist/dashboard/assets/SortableList-Cfy6_Khv.js.gz +0 -0
  332. package/dist/dashboard/assets/StudioPage-CM92fgJf.js.gz +0 -0
  333. package/dist/dashboard/assets/UsagePage-BT4MyQeT.js.gz +0 -0
  334. package/dist/dashboard/assets/api-keys-DQYLQxpW.js.gz +0 -0
  335. package/dist/dashboard/assets/app-CX_Z8cMs.css +0 -2
  336. package/dist/dashboard/assets/app-CX_Z8cMs.css.gz +0 -0
  337. package/dist/dashboard/assets/assert-C9FD_JwJ.js.gz +0 -0
  338. package/dist/dashboard/assets/badge-Bvyr7D0u.js.gz +0 -0
  339. package/dist/dashboard/assets/banner-DIvKAZih.js.gz +0 -0
  340. package/dist/dashboard/assets/card-D5_gYIS_.js.gz +0 -0
  341. package/dist/dashboard/assets/cli-tools-CNqzrfdb.js.gz +0 -0
  342. package/dist/dashboard/assets/clipboard-button-B6vDBtbm.js.gz +0 -0
  343. package/dist/dashboard/assets/dialog-CpjrgdwJ.js.gz +0 -0
  344. package/dist/dashboard/assets/drawer-BWmt3b5y.js.gz +0 -0
  345. package/dist/dashboard/assets/entry-B-gvimrg.js +0 -1
  346. package/dist/dashboard/assets/entry-B-gvimrg.js.gz +0 -0
  347. package/dist/dashboard/assets/entry-C_oakV3z.js.gz +0 -0
  348. package/dist/dashboard/assets/entry-Dj0cHfEc.js +0 -4
  349. package/dist/dashboard/assets/entry-Dj0cHfEc.js.gz +0 -0
  350. package/dist/dashboard/assets/github-badge-RRHHWGxh.js.gz +0 -0
  351. package/dist/dashboard/assets/index-Bhey_rg_.js.gz +0 -0
  352. package/dist/dashboard/assets/inline-C2_EQ5Uf.js.gz +0 -0
  353. package/dist/dashboard/assets/input-BMRlQ450.js.gz +0 -0
  354. package/dist/dashboard/assets/layout-XR5xP8ew.js.gz +0 -0
  355. package/dist/dashboard/assets/list-row-Cw07dioc.js.gz +0 -0
  356. package/dist/dashboard/assets/live-BivGfuUs.js.gz +0 -0
  357. package/dist/dashboard/assets/model-bans-CmffjLuG.js.gz +0 -0
  358. package/dist/dashboard/assets/mutation-46P0oWMe.js.gz +0 -0
  359. package/dist/dashboard/assets/numbers-DrdA9oSM.js.gz +0 -0
  360. package/dist/dashboard/assets/query-keys-BFhGpwR1.js.gz +0 -0
  361. package/dist/dashboard/assets/routing-CAb4F37R.js.gz +0 -0
  362. package/dist/dashboard/assets/select-CxVVB__N.js.gz +0 -0
  363. package/dist/dashboard/assets/settings-DNX9sydi.js.gz +0 -0
  364. package/dist/dashboard/assets/stack-uPOwM9Hs.js.gz +0 -0
  365. package/dist/dashboard/assets/state-D1Yz79iL.js.gz +0 -0
  366. package/dist/dashboard/assets/switch-sevsRrRo.js.gz +0 -0
  367. package/dist/dashboard/assets/useMutation-Dem0lXQj.js.gz +0 -0
  368. package/src/observability/event-compaction.ts +0 -317
  369. package/src/observability/event-day-index.ts +0 -439
@@ -1,305 +1,305 @@
1
- /**
2
- * Vendored from `cursor-opencode-provider` (protocol layer only).
3
- *
4
- * MIT License
5
- *
6
- * Copyright (c) 2026 Oleksiy Akimov
7
- *
8
- * Permission is hereby granted, free of charge, to any person obtaining a copy
9
- * of this software and associated documentation files (the "Software"), to deal
10
- * in the Software without restriction, including without limitation the rights
11
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
- * copies of the Software, and to permit persons to whom the Software is
13
- * furnished to do so, subject to the following conditions:
14
- *
15
- * The above copyright notice and this permission notice shall be included in all
16
- * copies or substantial portions of the Software.
17
- *
18
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
- * SOFTWARE.
25
- */
26
-
27
- // Minimal encoder for google.protobuf.Value / Struct / ListValue.
28
- //
29
- // Cursor's per-turn tool descriptors carry the tool `input_schema` (a JSON
30
- // Schema object) as a `google.protobuf.Value` whose `struct_value` holds the
31
- // schema — NOT a JSON string. Verified against a live capture
32
- // (request_context #7 → McpToolDefinition #3):
33
- // 2a 9a07 0a10 0a04 74797065 1208 1a06 6f626a656374 ...
34
- // = Value{#5 struct_value: Struct{#1 fields: {"type": Value{#3 string "object"}}}}
35
- //
36
- // Field numbers (well-known types):
37
- // Value: 1 null_value, 2 number_value(double), 3 string_value,
38
- // 4 bool_value, 5 struct_value(Struct), 6 list_value(ListValue)
39
- // Struct: 1 fields (map<string, Value>) — each entry msg{1 key, 2 value}
40
- // ListValue: 1 values (repeated Value)
41
-
42
- function writeVarint(out: number[], n: number): void {
43
- let v = n >>> 0
44
- while (v > 0x7f) {
45
- out.push((v & 0x7f) | 0x80)
46
- v >>>= 7
47
- }
48
- out.push(v)
49
- }
50
-
51
- function writeTag(out: number[], field: number, wire: number): void {
52
- writeVarint(out, (field << 3) | wire)
53
- }
54
-
55
- function writeLengthDelimited(out: number[], field: number, bytes: Uint8Array): void {
56
- writeTag(out, field, 2)
57
- writeVarint(out, bytes.length)
58
- for (let i = 0; i < bytes.length; i++) out.push(bytes[i] ?? 0)
59
- }
60
-
61
- function writeString(out: number[], field: number, str: string): void {
62
- writeLengthDelimited(out, field, new TextEncoder().encode(str))
63
- }
64
-
65
- function writeDouble(out: number[], field: number, num: number): void {
66
- writeTag(out, field, 1) // 64-bit
67
- const buf = new ArrayBuffer(8)
68
- new DataView(buf).setFloat64(0, num, true) // little-endian
69
- const view = new Uint8Array(buf)
70
- for (let i = 0; i < 8; i++) out.push(view[i] ?? 0)
71
- }
72
-
73
- // ── Decoding (reverse): google.protobuf.Value bytes → JSON ──
74
-
75
- export type RawField = { fn: number; wt: number; varint: number; bytes?: Uint8Array; i64?: Uint8Array }
76
-
77
- function readVarintAt(b: Uint8Array, i: number): [number, number] {
78
- let r = 0, s = 0
79
- while (i < b.length) {
80
- const x = b[i++] ?? 0
81
- r |= (x & 0x7f) << s
82
- if (!(x & 0x80)) break
83
- s += 7
84
- }
85
- return [r >>> 0, i]
86
- }
87
-
88
- /** Walk a protobuf message's top-level fields off the raw wire bytes. */
89
- export function readAllFields(b: Uint8Array): RawField[] {
90
- let i = 0
91
- const out: RawField[] = []
92
- while (i < b.length) {
93
- let key: number
94
- ;[key, i] = readVarintAt(b, i)
95
- const fn = key >>> 3, wt = key & 7
96
- if (wt === 0) {
97
- let v: number
98
- ;[v, i] = readVarintAt(b, i)
99
- out.push({ fn, wt, varint: v })
100
- } else if (wt === 2) {
101
- let len: number
102
- ;[len, i] = readVarintAt(b, i)
103
- out.push({ fn, wt, varint: 0, bytes: b.subarray(i, i + len) })
104
- i += len
105
- } else if (wt === 1) {
106
- out.push({ fn, wt, varint: 0, i64: b.subarray(i, i + 8) })
107
- i += 8
108
- } else if (wt === 5) {
109
- i += 4 // i32 — not used by Value
110
- } else break
111
- }
112
- return out
113
- }
114
-
115
- export type StrictRawField = {
116
- fn: number
117
- wt: number
118
- varint?: bigint
119
- bytes?: Uint8Array
120
- fixed64?: Uint8Array
121
- fixed32?: Uint8Array
122
- }
123
-
124
- type DecodedVarint = { value: bigint; nextOffset: number }
125
-
126
- const MAX_UINT32 = 0xffff_ffffn
127
- const MAX_UINT64 = 0xffff_ffff_ffff_ffffn
128
- const MAX_PROTOBUF_FIELD_NUMBER = 0x1fff_ffff
129
-
130
- /**
131
- * Decode one unsigned protobuf varint without JavaScript's 32-bit bitwise
132
- * truncation. `maximum` also enforces the protocol width: tags and lengths are
133
- * uint32, while wire-type 0 scalar values may use the full uint64 range.
134
- */
135
- function readBoundedVarint(
136
- bytes: Uint8Array,
137
- offset: number,
138
- maximum: bigint,
139
- ): DecodedVarint | undefined {
140
- let value = 0n
141
- let shift = 0n
142
- for (let index = offset; index < bytes.length && index < offset + 10; index++) {
143
- const byte = bytes[index]!
144
- value |= BigInt(byte & 0x7f) << shift
145
- if (value > maximum) return undefined
146
- if ((byte & 0x80) === 0) return { value, nextOffset: index + 1 }
147
- shift += 7n
148
- }
149
- return undefined
150
- }
151
-
152
- /**
153
- * Strictly walk a protobuf message for security/replay decisions.
154
- *
155
- * Unlike `readAllFields`, this parser consumes the complete input, preserves
156
- * uint64 varints as bigint, represents fixed-width fields, and rejects invalid
157
- * tags, truncation, overflow, groups, and unsupported wire types. It deliberately
158
- * returns `undefined` instead of a partial result: callers must fail closed when
159
- * deciding whether replay is safe.
160
- */
161
- export function readAllFieldsStrict(bytes: Uint8Array): StrictRawField[] | undefined {
162
- let offset = 0
163
- const fields: StrictRawField[] = []
164
-
165
- while (offset < bytes.length) {
166
- const tag = readBoundedVarint(bytes, offset, MAX_UINT32)
167
- if (!tag) return undefined
168
- offset = tag.nextOffset
169
-
170
- const fieldNumber = Number(tag.value >> 3n)
171
- const wireType = Number(tag.value & 7n)
172
- if (fieldNumber === 0 || fieldNumber > MAX_PROTOBUF_FIELD_NUMBER) return undefined
173
-
174
- if (wireType === 0) {
175
- const scalar = readBoundedVarint(bytes, offset, MAX_UINT64)
176
- if (!scalar) return undefined
177
- fields.push({ fn: fieldNumber, wt: wireType, varint: scalar.value })
178
- offset = scalar.nextOffset
179
- continue
180
- }
181
-
182
- if (wireType === 1) {
183
- if (offset + 8 > bytes.length) return undefined
184
- fields.push({ fn: fieldNumber, wt: wireType, fixed64: bytes.subarray(offset, offset + 8) })
185
- offset += 8
186
- continue
187
- }
188
-
189
- if (wireType === 2) {
190
- const encodedLength = readBoundedVarint(bytes, offset, MAX_UINT32)
191
- if (!encodedLength) return undefined
192
- offset = encodedLength.nextOffset
193
- const length = Number(encodedLength.value)
194
- if (offset + length > bytes.length) return undefined
195
- fields.push({ fn: fieldNumber, wt: wireType, bytes: bytes.subarray(offset, offset + length) })
196
- offset += length
197
- continue
198
- }
199
-
200
- if (wireType === 5) {
201
- if (offset + 4 > bytes.length) return undefined
202
- fields.push({ fn: fieldNumber, wt: wireType, fixed32: bytes.subarray(offset, offset + 4) })
203
- offset += 4
204
- continue
205
- }
206
-
207
- // Groups (3/4) are deprecated and recursive; no replay-safe frame uses them.
208
- return undefined
209
- }
210
-
211
- return fields
212
- }
213
-
214
- function decodeStructBytes(b: Uint8Array): Record<string, unknown> {
215
- const obj: Record<string, unknown> = {}
216
- for (const f of readAllFields(b)) {
217
- if (f.fn !== 1 || !f.bytes) continue // Struct.fields (map) entries
218
- const { key, valBytes } = readMapEntry(f.bytes)
219
- if (key !== undefined) obj[key] = valBytes ? decodeValueToJson(valBytes) : null
220
- }
221
- return obj
222
- }
223
-
224
- function decodeListBytes(b: Uint8Array): unknown[] {
225
- const arr: unknown[] = []
226
- for (const f of readAllFields(b)) {
227
- if (f.fn === 1 && f.bytes) arr.push(decodeValueToJson(f.bytes))
228
- }
229
- return arr
230
- }
231
-
232
- function readMapEntry(b: Uint8Array): { key?: string; valBytes?: Uint8Array } {
233
- let key: string | undefined
234
- let valBytes: Uint8Array | undefined
235
- for (const e of readAllFields(b)) {
236
- if (e.fn === 1 && e.bytes) key = new TextDecoder().decode(e.bytes)
237
- else if (e.fn === 2 && e.bytes) valBytes = e.bytes
238
- }
239
- return { ...(key === undefined ? {} : { key }), ...(valBytes === undefined ? {} : { valBytes }) }
240
- }
241
-
242
- /** Decode a google.protobuf.Value message (bytes) back into a JSON value. */
243
- export function decodeValueToJson(bytes: Uint8Array): unknown {
244
- const fs = readAllFields(bytes)
245
- const f = fs[0]
246
- if (f === undefined) return null
247
- switch (f.fn) {
248
- case 1: return null // null_value
249
- case 2: return f.i64 ? new DataView(f.i64.buffer, f.i64.byteOffset, 8).getFloat64(0, true) : 0
250
- case 3: return f.bytes ? new TextDecoder().decode(f.bytes) : ""
251
- case 4: return f.varint !== 0
252
- case 5: return f.bytes ? decodeStructBytes(f.bytes) : {}
253
- case 6: return f.bytes ? decodeListBytes(f.bytes) : []
254
- default: return null
255
- }
256
- }
257
-
258
- /**
259
- * Decode a `map<string, Value>` field that was captured as repeated map-entry
260
- * messages (each `{1 key, 2 value}`) into a plain JSON object. Used for
261
- * `McpArgs.args`, which arrives as repeated field #2 on the wire.
262
- */
263
- export function decodeStructEntriesToJson(entries: Uint8Array[]): Record<string, unknown> {
264
- const obj: Record<string, unknown> = {}
265
- for (const entry of entries) {
266
- const { key, valBytes } = readMapEntry(entry)
267
- if (key !== undefined) obj[key] = valBytes ? decodeValueToJson(valBytes) : null
268
- }
269
- return obj
270
- }
271
-
272
- /** Encode an arbitrary JSON value as google.protobuf.Value bytes. */
273
- export function encodeJsonAsValue(v: unknown): Uint8Array {
274
- const out: number[] = []
275
- if (v === null || v === undefined) {
276
- writeTag(out, 1, 0) // null_value = 0
277
- writeVarint(out, 0)
278
- } else if (typeof v === "number") {
279
- writeDouble(out, 2, v)
280
- } else if (typeof v === "boolean") {
281
- writeTag(out, 4, 0)
282
- writeVarint(out, v ? 1 : 0)
283
- } else if (typeof v === "string") {
284
- writeString(out, 3, v)
285
- } else if (Array.isArray(v)) {
286
- const lv: number[] = []
287
- for (const item of v) writeLengthDelimited(lv, 1, encodeJsonAsValue(item))
288
- writeLengthDelimited(out, 6, new Uint8Array(lv))
289
- } else if (typeof v === "object") {
290
- const st: number[] = []
291
- for (const [key, val] of Object.entries(v as Record<string, unknown>).sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0)) {
292
- if (val === undefined) continue
293
- const entry: number[] = []
294
- writeString(entry, 1, key)
295
- writeLengthDelimited(entry, 2, encodeJsonAsValue(val))
296
- writeLengthDelimited(st, 1, new Uint8Array(entry))
297
- }
298
- writeLengthDelimited(out, 5, new Uint8Array(st))
299
- } else {
300
- // Fallback: treat as null.
301
- writeTag(out, 1, 0)
302
- writeVarint(out, 0)
303
- }
304
- return new Uint8Array(out)
305
- }
1
+ /**
2
+ * Vendored from `cursor-opencode-provider` (protocol layer only).
3
+ *
4
+ * MIT License
5
+ *
6
+ * Copyright (c) 2026 Oleksiy Akimov
7
+ *
8
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ * of this software and associated documentation files (the "Software"), to deal
10
+ * in the Software without restriction, including without limitation the rights
11
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ * copies of the Software, and to permit persons to whom the Software is
13
+ * furnished to do so, subject to the following conditions:
14
+ *
15
+ * The above copyright notice and this permission notice shall be included in all
16
+ * copies or substantial portions of the Software.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24
+ * SOFTWARE.
25
+ */
26
+
27
+ // Minimal encoder for google.protobuf.Value / Struct / ListValue.
28
+ //
29
+ // Cursor's per-turn tool descriptors carry the tool `input_schema` (a JSON
30
+ // Schema object) as a `google.protobuf.Value` whose `struct_value` holds the
31
+ // schema — NOT a JSON string. Verified against a live capture
32
+ // (request_context #7 → McpToolDefinition #3):
33
+ // 2a 9a07 0a10 0a04 74797065 1208 1a06 6f626a656374 ...
34
+ // = Value{#5 struct_value: Struct{#1 fields: {"type": Value{#3 string "object"}}}}
35
+ //
36
+ // Field numbers (well-known types):
37
+ // Value: 1 null_value, 2 number_value(double), 3 string_value,
38
+ // 4 bool_value, 5 struct_value(Struct), 6 list_value(ListValue)
39
+ // Struct: 1 fields (map<string, Value>) — each entry msg{1 key, 2 value}
40
+ // ListValue: 1 values (repeated Value)
41
+
42
+ function writeVarint(out: number[], n: number): void {
43
+ let v = n >>> 0
44
+ while (v > 0x7f) {
45
+ out.push((v & 0x7f) | 0x80)
46
+ v >>>= 7
47
+ }
48
+ out.push(v)
49
+ }
50
+
51
+ function writeTag(out: number[], field: number, wire: number): void {
52
+ writeVarint(out, (field << 3) | wire)
53
+ }
54
+
55
+ function writeLengthDelimited(out: number[], field: number, bytes: Uint8Array): void {
56
+ writeTag(out, field, 2)
57
+ writeVarint(out, bytes.length)
58
+ for (let i = 0; i < bytes.length; i++) out.push(bytes[i] ?? 0)
59
+ }
60
+
61
+ function writeString(out: number[], field: number, str: string): void {
62
+ writeLengthDelimited(out, field, new TextEncoder().encode(str))
63
+ }
64
+
65
+ function writeDouble(out: number[], field: number, num: number): void {
66
+ writeTag(out, field, 1) // 64-bit
67
+ const buf = new ArrayBuffer(8)
68
+ new DataView(buf).setFloat64(0, num, true) // little-endian
69
+ const view = new Uint8Array(buf)
70
+ for (let i = 0; i < 8; i++) out.push(view[i] ?? 0)
71
+ }
72
+
73
+ // ── Decoding (reverse): google.protobuf.Value bytes → JSON ──
74
+
75
+ export type RawField = { fn: number; wt: number; varint: number; bytes?: Uint8Array; i64?: Uint8Array }
76
+
77
+ function readVarintAt(b: Uint8Array, i: number): [number, number] {
78
+ let r = 0, s = 0
79
+ while (i < b.length) {
80
+ const x = b[i++] ?? 0
81
+ r |= (x & 0x7f) << s
82
+ if (!(x & 0x80)) break
83
+ s += 7
84
+ }
85
+ return [r >>> 0, i]
86
+ }
87
+
88
+ /** Walk a protobuf message's top-level fields off the raw wire bytes. */
89
+ export function readAllFields(b: Uint8Array): RawField[] {
90
+ let i = 0
91
+ const out: RawField[] = []
92
+ while (i < b.length) {
93
+ let key: number
94
+ ;[key, i] = readVarintAt(b, i)
95
+ const fn = key >>> 3, wt = key & 7
96
+ if (wt === 0) {
97
+ let v: number
98
+ ;[v, i] = readVarintAt(b, i)
99
+ out.push({ fn, wt, varint: v })
100
+ } else if (wt === 2) {
101
+ let len: number
102
+ ;[len, i] = readVarintAt(b, i)
103
+ out.push({ fn, wt, varint: 0, bytes: b.subarray(i, i + len) })
104
+ i += len
105
+ } else if (wt === 1) {
106
+ out.push({ fn, wt, varint: 0, i64: b.subarray(i, i + 8) })
107
+ i += 8
108
+ } else if (wt === 5) {
109
+ i += 4 // i32 — not used by Value
110
+ } else break
111
+ }
112
+ return out
113
+ }
114
+
115
+ export type StrictRawField = {
116
+ fn: number
117
+ wt: number
118
+ varint?: bigint
119
+ bytes?: Uint8Array
120
+ fixed64?: Uint8Array
121
+ fixed32?: Uint8Array
122
+ }
123
+
124
+ type DecodedVarint = { value: bigint; nextOffset: number }
125
+
126
+ const MAX_UINT32 = 0xffff_ffffn
127
+ const MAX_UINT64 = 0xffff_ffff_ffff_ffffn
128
+ const MAX_PROTOBUF_FIELD_NUMBER = 0x1fff_ffff
129
+
130
+ /**
131
+ * Decode one unsigned protobuf varint without JavaScript's 32-bit bitwise
132
+ * truncation. `maximum` also enforces the protocol width: tags and lengths are
133
+ * uint32, while wire-type 0 scalar values may use the full uint64 range.
134
+ */
135
+ function readBoundedVarint(
136
+ bytes: Uint8Array,
137
+ offset: number,
138
+ maximum: bigint,
139
+ ): DecodedVarint | undefined {
140
+ let value = 0n
141
+ let shift = 0n
142
+ for (let index = offset; index < bytes.length && index < offset + 10; index++) {
143
+ const byte = bytes[index]!
144
+ value |= BigInt(byte & 0x7f) << shift
145
+ if (value > maximum) return undefined
146
+ if ((byte & 0x80) === 0) return { value, nextOffset: index + 1 }
147
+ shift += 7n
148
+ }
149
+ return undefined
150
+ }
151
+
152
+ /**
153
+ * Strictly walk a protobuf message for security/replay decisions.
154
+ *
155
+ * Unlike `readAllFields`, this parser consumes the complete input, preserves
156
+ * uint64 varints as bigint, represents fixed-width fields, and rejects invalid
157
+ * tags, truncation, overflow, groups, and unsupported wire types. It deliberately
158
+ * returns `undefined` instead of a partial result: callers must fail closed when
159
+ * deciding whether replay is safe.
160
+ */
161
+ export function readAllFieldsStrict(bytes: Uint8Array): StrictRawField[] | undefined {
162
+ let offset = 0
163
+ const fields: StrictRawField[] = []
164
+
165
+ while (offset < bytes.length) {
166
+ const tag = readBoundedVarint(bytes, offset, MAX_UINT32)
167
+ if (!tag) return undefined
168
+ offset = tag.nextOffset
169
+
170
+ const fieldNumber = Number(tag.value >> 3n)
171
+ const wireType = Number(tag.value & 7n)
172
+ if (fieldNumber === 0 || fieldNumber > MAX_PROTOBUF_FIELD_NUMBER) return undefined
173
+
174
+ if (wireType === 0) {
175
+ const scalar = readBoundedVarint(bytes, offset, MAX_UINT64)
176
+ if (!scalar) return undefined
177
+ fields.push({ fn: fieldNumber, wt: wireType, varint: scalar.value })
178
+ offset = scalar.nextOffset
179
+ continue
180
+ }
181
+
182
+ if (wireType === 1) {
183
+ if (offset + 8 > bytes.length) return undefined
184
+ fields.push({ fn: fieldNumber, wt: wireType, fixed64: bytes.subarray(offset, offset + 8) })
185
+ offset += 8
186
+ continue
187
+ }
188
+
189
+ if (wireType === 2) {
190
+ const encodedLength = readBoundedVarint(bytes, offset, MAX_UINT32)
191
+ if (!encodedLength) return undefined
192
+ offset = encodedLength.nextOffset
193
+ const length = Number(encodedLength.value)
194
+ if (offset + length > bytes.length) return undefined
195
+ fields.push({ fn: fieldNumber, wt: wireType, bytes: bytes.subarray(offset, offset + length) })
196
+ offset += length
197
+ continue
198
+ }
199
+
200
+ if (wireType === 5) {
201
+ if (offset + 4 > bytes.length) return undefined
202
+ fields.push({ fn: fieldNumber, wt: wireType, fixed32: bytes.subarray(offset, offset + 4) })
203
+ offset += 4
204
+ continue
205
+ }
206
+
207
+ // Groups (3/4) are deprecated and recursive; no replay-safe frame uses them.
208
+ return undefined
209
+ }
210
+
211
+ return fields
212
+ }
213
+
214
+ function decodeStructBytes(b: Uint8Array): Record<string, unknown> {
215
+ const obj: Record<string, unknown> = {}
216
+ for (const f of readAllFields(b)) {
217
+ if (f.fn !== 1 || !f.bytes) continue // Struct.fields (map) entries
218
+ const { key, valBytes } = readMapEntry(f.bytes)
219
+ if (key !== undefined) obj[key] = valBytes ? decodeValueToJson(valBytes) : null
220
+ }
221
+ return obj
222
+ }
223
+
224
+ function decodeListBytes(b: Uint8Array): unknown[] {
225
+ const arr: unknown[] = []
226
+ for (const f of readAllFields(b)) {
227
+ if (f.fn === 1 && f.bytes) arr.push(decodeValueToJson(f.bytes))
228
+ }
229
+ return arr
230
+ }
231
+
232
+ function readMapEntry(b: Uint8Array): { key?: string; valBytes?: Uint8Array } {
233
+ let key: string | undefined
234
+ let valBytes: Uint8Array | undefined
235
+ for (const e of readAllFields(b)) {
236
+ if (e.fn === 1 && e.bytes) key = new TextDecoder().decode(e.bytes)
237
+ else if (e.fn === 2 && e.bytes) valBytes = e.bytes
238
+ }
239
+ return { ...(key === undefined ? {} : { key }), ...(valBytes === undefined ? {} : { valBytes }) }
240
+ }
241
+
242
+ /** Decode a google.protobuf.Value message (bytes) back into a JSON value. */
243
+ export function decodeValueToJson(bytes: Uint8Array): unknown {
244
+ const fs = readAllFields(bytes)
245
+ const f = fs[0]
246
+ if (f === undefined) return null
247
+ switch (f.fn) {
248
+ case 1: return null // null_value
249
+ case 2: return f.i64 ? new DataView(f.i64.buffer, f.i64.byteOffset, 8).getFloat64(0, true) : 0
250
+ case 3: return f.bytes ? new TextDecoder().decode(f.bytes) : ""
251
+ case 4: return f.varint !== 0
252
+ case 5: return f.bytes ? decodeStructBytes(f.bytes) : {}
253
+ case 6: return f.bytes ? decodeListBytes(f.bytes) : []
254
+ default: return null
255
+ }
256
+ }
257
+
258
+ /**
259
+ * Decode a `map<string, Value>` field that was captured as repeated map-entry
260
+ * messages (each `{1 key, 2 value}`) into a plain JSON object. Used for
261
+ * `McpArgs.args`, which arrives as repeated field #2 on the wire.
262
+ */
263
+ export function decodeStructEntriesToJson(entries: Uint8Array[]): Record<string, unknown> {
264
+ const obj: Record<string, unknown> = {}
265
+ for (const entry of entries) {
266
+ const { key, valBytes } = readMapEntry(entry)
267
+ if (key !== undefined) obj[key] = valBytes ? decodeValueToJson(valBytes) : null
268
+ }
269
+ return obj
270
+ }
271
+
272
+ /** Encode an arbitrary JSON value as google.protobuf.Value bytes. */
273
+ export function encodeJsonAsValue(v: unknown): Uint8Array {
274
+ const out: number[] = []
275
+ if (v === null || v === undefined) {
276
+ writeTag(out, 1, 0) // null_value = 0
277
+ writeVarint(out, 0)
278
+ } else if (typeof v === "number") {
279
+ writeDouble(out, 2, v)
280
+ } else if (typeof v === "boolean") {
281
+ writeTag(out, 4, 0)
282
+ writeVarint(out, v ? 1 : 0)
283
+ } else if (typeof v === "string") {
284
+ writeString(out, 3, v)
285
+ } else if (Array.isArray(v)) {
286
+ const lv: number[] = []
287
+ for (const item of v) writeLengthDelimited(lv, 1, encodeJsonAsValue(item))
288
+ writeLengthDelimited(out, 6, new Uint8Array(lv))
289
+ } else if (typeof v === "object") {
290
+ const st: number[] = []
291
+ for (const [key, val] of Object.entries(v as Record<string, unknown>).sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0)) {
292
+ if (val === undefined) continue
293
+ const entry: number[] = []
294
+ writeString(entry, 1, key)
295
+ writeLengthDelimited(entry, 2, encodeJsonAsValue(val))
296
+ writeLengthDelimited(st, 1, new Uint8Array(entry))
297
+ }
298
+ writeLengthDelimited(out, 5, new Uint8Array(st))
299
+ } else {
300
+ // Fallback: treat as null.
301
+ writeTag(out, 1, 0)
302
+ writeVarint(out, 0)
303
+ }
304
+ return new Uint8Array(out)
305
+ }