cartethyia 2.4.6 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (302) hide show
  1. package/README.md +45 -13
  2. package/dist/dashboard/assets/BannedPage-9igfctfZ.js +1 -0
  3. package/dist/dashboard/assets/BannedPage-9igfctfZ.js.gz +0 -0
  4. package/dist/dashboard/assets/{CliToolDetailPage-Bcy150Jo.js → CliToolDetailPage-ZRr2K2sF.js} +1 -1
  5. package/dist/dashboard/assets/CliToolDetailPage-ZRr2K2sF.js.gz +0 -0
  6. package/dist/dashboard/assets/{CliToolsPage-DyNXefph.js → CliToolsPage-D3xqZbN-.js} +1 -1
  7. package/dist/dashboard/assets/CliToolsPage-D3xqZbN-.js.gz +0 -0
  8. package/dist/dashboard/assets/CombosPage-CVnQPBBz.js +1 -0
  9. package/dist/dashboard/assets/CombosPage-CVnQPBBz.js.gz +0 -0
  10. package/dist/dashboard/assets/{ConsoleLogPage-CATpAEOz.js → ConsoleLogPage-u6W1UXSc.js} +1 -1
  11. package/dist/dashboard/assets/ConsoleLogPage-u6W1UXSc.js.gz +0 -0
  12. package/dist/dashboard/assets/{CustomizationPage-D6jEU7nL.js → CustomizationPage-CTTpCb25.js} +1 -1
  13. package/dist/dashboard/assets/CustomizationPage-CTTpCb25.js.gz +0 -0
  14. package/dist/dashboard/assets/{HealthEventsModal-CZkpn0a7.js → HealthEventsModal-C5XpWlvy.js} +1 -1
  15. package/dist/dashboard/assets/HealthEventsModal-C5XpWlvy.js.gz +0 -0
  16. package/dist/dashboard/assets/{LoginPage-BJlMVN4U.js → LoginPage-DHoB3Agn.js} +1 -1
  17. package/dist/dashboard/assets/LoginPage-DHoB3Agn.js.gz +0 -0
  18. package/dist/dashboard/assets/{ModelPicker-Br3CXEau.js → ModelPicker-oQ-SDXp8.js} +1 -1
  19. package/dist/dashboard/assets/ModelPicker-oQ-SDXp8.js.gz +0 -0
  20. package/dist/dashboard/assets/OverviewPage-BrY4SgIt.js +1 -0
  21. package/dist/dashboard/assets/OverviewPage-BrY4SgIt.js.gz +0 -0
  22. package/dist/dashboard/assets/ProviderDetailPage-D9VSt7T_.js +3 -0
  23. package/dist/dashboard/assets/ProviderDetailPage-D9VSt7T_.js.gz +0 -0
  24. package/dist/dashboard/assets/ProviderIcon-CmfzxpVM.js +1 -0
  25. package/dist/dashboard/assets/ProviderIcon-CmfzxpVM.js.gz +0 -0
  26. package/dist/dashboard/assets/ProvidersPage-Df77V5I5.js +1 -0
  27. package/dist/dashboard/assets/ProvidersPage-Df77V5I5.js.gz +0 -0
  28. package/dist/dashboard/assets/ProxyPage-CDfxP7AC.js +7 -0
  29. package/dist/dashboard/assets/ProxyPage-CDfxP7AC.js.gz +0 -0
  30. package/dist/dashboard/assets/QuotaPage-CY4o2t4p.js +1 -0
  31. package/dist/dashboard/assets/QuotaPage-CY4o2t4p.js.gz +0 -0
  32. package/dist/dashboard/assets/{SettingsPage-BHW4Zt06.js → SettingsPage-CvjZxHE4.js} +1 -1
  33. package/dist/dashboard/assets/SettingsPage-CvjZxHE4.js.gz +0 -0
  34. package/dist/dashboard/assets/{SetupPage-VOYC_lIa.js → SetupPage-D3nza7LH.js} +1 -1
  35. package/dist/dashboard/assets/SetupPage-D3nza7LH.js.gz +0 -0
  36. package/dist/dashboard/assets/SortableList-Dtt12WT1.js +1 -0
  37. package/dist/dashboard/assets/SortableList-Dtt12WT1.js.gz +0 -0
  38. package/dist/dashboard/assets/{StudioPage-BNIDLiU6.js → StudioPage-CbK3hXvU.js} +4 -4
  39. package/dist/dashboard/assets/StudioPage-CbK3hXvU.js.gz +0 -0
  40. package/dist/dashboard/assets/UsagePage-BQlWbWg2.js +56 -0
  41. package/dist/dashboard/assets/UsagePage-BQlWbWg2.js.gz +0 -0
  42. package/dist/dashboard/assets/{api-keys-BETfaMYZ.js → api-keys-BmDbsior.js} +1 -1
  43. package/dist/dashboard/assets/api-keys-BmDbsior.js.gz +0 -0
  44. package/dist/dashboard/assets/app-BbpSarVV.css +2 -0
  45. package/dist/dashboard/assets/app-BbpSarVV.css.gz +0 -0
  46. package/dist/dashboard/assets/assert-BHfaei-X.js +1 -0
  47. package/dist/dashboard/assets/assert-BHfaei-X.js.gz +0 -0
  48. package/dist/dashboard/assets/{badge-BTyGk_DL.js → badge-DpXT4Ixt.js} +1 -1
  49. package/dist/dashboard/assets/badge-DpXT4Ixt.js.gz +0 -0
  50. package/dist/dashboard/assets/{banner-bujTWYM4.js → banner-CSAAWLJv.js} +1 -1
  51. package/dist/dashboard/assets/banner-CSAAWLJv.js.gz +0 -0
  52. package/dist/dashboard/assets/{card-B0Bnx5CA.js → card-DEhRXXw4.js} +1 -1
  53. package/dist/dashboard/assets/card-DEhRXXw4.js.gz +0 -0
  54. package/dist/dashboard/assets/{cli-tools-DE2ug812.js → cli-tools-B0wBq-RL.js} +1 -1
  55. package/dist/dashboard/assets/cli-tools-B0wBq-RL.js.gz +0 -0
  56. package/dist/dashboard/assets/{clipboard-button-R_rArH8S.js → clipboard-button-DOo6EU8O.js} +1 -1
  57. package/dist/dashboard/assets/clipboard-button-DOo6EU8O.js.gz +0 -0
  58. package/dist/dashboard/assets/{dialog-BWIP_EvW.js → dialog-BvQeBMfP.js} +1 -1
  59. package/dist/dashboard/assets/dialog-BvQeBMfP.js.gz +0 -0
  60. package/dist/dashboard/assets/{drawer-BKcgVugF.js → drawer-CMwPXwQB.js} +1 -1
  61. package/dist/dashboard/assets/drawer-CMwPXwQB.js.gz +0 -0
  62. package/dist/dashboard/assets/{entry-CcWkGR4a.js → entry-D4O2229X.js} +1 -1
  63. package/dist/dashboard/assets/{entry-CcWkGR4a.js.gz → entry-D4O2229X.js.gz} +0 -0
  64. package/dist/dashboard/assets/{entry-kTiTFrvh.js → entry-DKvr5Q9K.js} +1 -1
  65. package/dist/dashboard/assets/entry-DKvr5Q9K.js.gz +0 -0
  66. package/dist/dashboard/assets/entry-FQCejoDY.js +4 -0
  67. package/dist/dashboard/assets/entry-FQCejoDY.js.gz +0 -0
  68. package/dist/dashboard/assets/{github-badge-Booc5mNe.js → github-badge-zliLvBwr.js} +1 -1
  69. package/dist/dashboard/assets/github-badge-zliLvBwr.js.gz +0 -0
  70. package/dist/dashboard/assets/{index-D70pChfn.js → index-CXm3FIyt.js} +2 -2
  71. package/dist/dashboard/assets/index-CXm3FIyt.js.gz +0 -0
  72. package/dist/dashboard/assets/{inline-D1TCqM2D.js → inline-D1IlZZ8H.js} +1 -1
  73. package/dist/dashboard/assets/inline-D1IlZZ8H.js.gz +0 -0
  74. package/dist/dashboard/assets/{input-B9oyU93y.js → input-BpVZdrbc.js} +1 -1
  75. package/dist/dashboard/assets/input-BpVZdrbc.js.gz +0 -0
  76. package/dist/dashboard/assets/{layout-BArzXirQ.js → layout-BioLW7gN.js} +1 -1
  77. package/dist/dashboard/assets/layout-BioLW7gN.js.gz +0 -0
  78. package/dist/dashboard/assets/{list-row-BVZzaoHF.js → list-row-CwVcGAIc.js} +1 -1
  79. package/dist/dashboard/assets/list-row-CwVcGAIc.js.gz +0 -0
  80. package/dist/dashboard/assets/{live-EmuIayqp.js → live-yfEJFF9T.js} +1 -1
  81. package/dist/dashboard/assets/live-yfEJFF9T.js.gz +0 -0
  82. package/dist/dashboard/assets/{model-bans-CSPQ9xB0.js → model-bans-CT-TxSNX.js} +1 -1
  83. package/dist/dashboard/assets/model-bans-CT-TxSNX.js.gz +0 -0
  84. package/dist/dashboard/assets/providers/cursor.webp +0 -0
  85. package/dist/dashboard/assets/providers/trae.webp +0 -0
  86. package/dist/dashboard/assets/{routing-BExgxxBU.js → routing-Cs6jl49L.js} +1 -1
  87. package/dist/dashboard/assets/routing-Cs6jl49L.js.gz +0 -0
  88. package/dist/dashboard/assets/select-C0Rer3gF.js +41 -0
  89. package/dist/dashboard/assets/select-C0Rer3gF.js.gz +0 -0
  90. package/dist/dashboard/assets/settings-CfcTcOyU.js +1 -0
  91. package/dist/dashboard/assets/settings-CfcTcOyU.js.gz +0 -0
  92. package/dist/dashboard/assets/{stack-Ca5HxI5i.js → stack-C9_uUjaA.js} +1 -1
  93. package/dist/dashboard/assets/stack-C9_uUjaA.js.gz +0 -0
  94. package/dist/dashboard/assets/{state-CzUPfLXo.js → state-DA0B95UQ.js} +1 -1
  95. package/dist/dashboard/assets/state-DA0B95UQ.js.gz +0 -0
  96. package/dist/dashboard/assets/{switch-DOUIky_i.js → switch-Cittxy-x.js} +1 -1
  97. package/dist/dashboard/assets/switch-Cittxy-x.js.gz +0 -0
  98. package/dist/dashboard/assets/{toast-C76WrMhc.js → toast-CNt_jzO4.js} +1 -1
  99. package/dist/dashboard/assets/toast-CNt_jzO4.js.gz +0 -0
  100. package/dist/dashboard/assets/{useMutation-D87FZwH0.js → useMutation-BQKMcJ1H.js} +1 -1
  101. package/dist/dashboard/assets/useMutation-BQKMcJ1H.js.gz +0 -0
  102. package/dist/dashboard/index.html +1 -1
  103. package/dist/dashboard/index.html.gz +0 -0
  104. package/dist/dashboard/precompressed-assets.json +51 -52
  105. package/migrations/full-postgres/0015_add_payload_stages.sql +18 -0
  106. package/migrations/full-postgres/0016_add_share_link_slug.sql +20 -0
  107. package/migrations/full-postgres/0017_add_models_pro_only.sql +18 -0
  108. package/migrations/full-postgres/0018_add_accounts_quota_plan.sql +18 -0
  109. package/migrations/full-postgres/0019_add_models_free_tier.sql +15 -0
  110. package/migrations/lite-sqlite3/0015_add_payload_stages.sql +18 -0
  111. package/migrations/lite-sqlite3/0016_add_share_link_slug.sql +20 -0
  112. package/migrations/lite-sqlite3/0017_add_models_pro_only.sql +18 -0
  113. package/migrations/lite-sqlite3/0018_add_accounts_quota_plan.sql +18 -0
  114. package/migrations/lite-sqlite3/0019_add_models_free_tier.sql +15 -0
  115. package/package.json +3 -2
  116. package/scripts/cli/command/console-menu.ts +30 -11
  117. package/scripts/cli/command/start.ts +77 -13
  118. package/scripts/cli/command/update.ts +1 -1
  119. package/scripts/cli/gateway/instance-lock.ts +105 -0
  120. package/scripts/cli/gateway/spawn.ts +173 -101
  121. package/scripts/cli/ui/background.ts +110 -49
  122. package/src/boot/app.ts +20 -6
  123. package/src/boot/dependencies.ts +19 -0
  124. package/src/boot/elysia-typebox-bridge.ts +37 -0
  125. package/src/boot/lifecycle.ts +2 -0
  126. package/src/config/cooldowns.ts +138 -138
  127. package/src/config/providers.ts +5 -5
  128. package/src/config/runtime.ts +19 -3
  129. package/src/config/spec.ts +9 -0
  130. package/src/console/api-keys/contracts.ts +414 -391
  131. package/src/console/api-keys/routes.ts +880 -870
  132. package/src/console/auth/account-reset-store.ts +14 -0
  133. package/src/console/auth/account-reset.ts +3 -2
  134. package/src/console/auth/setup-service.ts +6 -3
  135. package/src/console/domain-registration.ts +9 -2
  136. package/src/console/observability/contracts.ts +475 -455
  137. package/src/console/observability/store.ts +1015 -952
  138. package/src/console/providers/catalog/contracts.ts +31 -0
  139. package/src/console/providers/catalog/provider-operations.ts +8 -0
  140. package/src/console/providers/catalog/store.ts +1532 -1525
  141. package/src/console/providers/oauth/callback-listener.ts +18 -3
  142. package/src/console/providers/oauth/routes.ts +38 -15
  143. package/src/console/quota/refresh.ts +19 -0
  144. package/src/console/updates/routes.ts +162 -4
  145. package/src/main.ts +3 -0
  146. package/src/network/http2-bidi.ts +85 -0
  147. package/src/network/outbound-fetch.ts +1 -26
  148. package/src/network/pool/agent.ts +478 -460
  149. package/src/network/pool/resolver.ts +1104 -544
  150. package/src/network/pool-health-machine.ts +12 -5
  151. package/src/observability/payload-capture.ts +344 -324
  152. package/src/persistence/db-pg.ts +9 -3
  153. package/src/persistence/db-sqlite.ts +497 -495
  154. package/src/persistence/health-event-flush.ts +137 -0
  155. package/src/persistence/migrate.ts +181 -129
  156. package/src/persistence/schema.ts +1360 -1295
  157. package/src/persistence/settings-revision.ts +25 -0
  158. package/src/persistence/shared-cache.ts +217 -0
  159. package/src/persistence/stores/share-store.ts +556 -528
  160. package/src/persistence/usage-flush.ts +61 -1
  161. package/src/protocol/canonical-model.ts +23 -1
  162. package/src/protocol/response/chat.ts +143 -10
  163. package/src/protocol/response/omp-tool-call-markup.ts +221 -0
  164. package/src/providers/default-registry.ts +173 -1
  165. package/src/providers/discovery/openai-model-discovery.ts +39 -3
  166. package/src/providers/discovery/openrouter-free-roster.ts +98 -0
  167. package/src/providers/discovery/probing-service.ts +1022 -1001
  168. package/src/providers/integrations/buddy/buddy-catalog-shared.ts +39 -0
  169. package/src/providers/integrations/buddy/buddy-chat-shared.ts +913 -914
  170. package/src/providers/integrations/buddy/buddy-conversation-headers.ts +18 -5
  171. package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +4 -0
  172. package/src/providers/integrations/buddy/codebuddy/provider.ts +180 -175
  173. package/src/providers/integrations/buddy/codebuddy/shared.ts +15 -6
  174. package/src/providers/integrations/buddy/workbuddy/provider.ts +206 -204
  175. package/src/providers/integrations/buddy/workbuddy/shared.ts +3 -3
  176. package/src/providers/integrations/claude/claude.ts +606 -582
  177. package/src/providers/integrations/cline/cline-quota.ts +18 -16
  178. package/src/providers/integrations/cline/cline.ts +539 -468
  179. package/src/providers/integrations/commandcode/commandcode.ts +675 -541
  180. package/src/providers/integrations/commandcode/discovery.ts +116 -0
  181. package/src/providers/integrations/commandcode/quota.ts +160 -0
  182. package/src/providers/integrations/cursor/cursor-auth.ts +418 -0
  183. package/src/providers/integrations/cursor/cursor-catalog.ts +368 -0
  184. package/src/providers/integrations/cursor/cursor-http2.ts +300 -0
  185. package/src/providers/integrations/cursor/cursor-identity.ts +92 -0
  186. package/src/providers/integrations/cursor/cursor-request.ts +471 -0
  187. package/src/providers/integrations/cursor/cursor-session-manager.ts +281 -0
  188. package/src/providers/integrations/cursor/cursor-shared.ts +108 -0
  189. package/src/providers/integrations/cursor/cursor.ts +960 -0
  190. package/src/providers/integrations/cursor/protocol/framing.ts +129 -0
  191. package/src/providers/integrations/cursor/protocol/messages.ts +2355 -0
  192. package/src/providers/integrations/cursor/protocol/struct.ts +305 -0
  193. package/src/providers/integrations/github/github.ts +4 -4
  194. package/src/providers/integrations/hermes.ts +79 -8
  195. package/src/providers/integrations/kilo/kilo-discovery.ts +10 -1
  196. package/src/providers/integrations/kilo/kilo.ts +153 -146
  197. package/src/providers/integrations/opencode/provider.ts +532 -538
  198. package/src/providers/integrations/openrouter/provider.ts +139 -281
  199. package/src/providers/integrations/qoder/qoder-catalog.ts +450 -0
  200. package/src/providers/integrations/qoder/qoder-oauth.ts +310 -257
  201. package/src/providers/integrations/qoder/qoder-realm.ts +106 -0
  202. package/src/providers/integrations/qoder/qoder-virtual.ts +77 -0
  203. package/src/providers/integrations/qoder/qoder.ts +865 -730
  204. package/src/providers/integrations/trae/trae-catalog.ts +190 -0
  205. package/src/providers/integrations/trae/trae-headers.ts +149 -0
  206. package/src/providers/integrations/trae/trae-oauth.ts +773 -0
  207. package/src/providers/integrations/trae/trae-protocol.ts +400 -0
  208. package/src/providers/integrations/trae/trae-realm.ts +220 -0
  209. package/src/providers/integrations/trae/trae.ts +458 -0
  210. package/src/providers/operations/account-health-service.ts +107 -10
  211. package/src/providers/operations/client-versions.ts +133 -6
  212. package/src/providers/operations/provider-catalog-seeder.ts +95 -86
  213. package/src/providers/operations/provider-credential-service.ts +46 -7
  214. package/src/providers/provider-contracts.ts +76 -0
  215. package/src/providers/provider-metadata.ts +78 -6
  216. package/src/providers/provider-model-definition.ts +373 -349
  217. package/src/security/api-key-auth.ts +126 -8
  218. package/src/transport/contracts.ts +3 -0
  219. package/src/transport/dispatch/attempt-finalize.ts +32 -1
  220. package/src/transport/dispatch/attempt-loop.ts +530 -515
  221. package/src/transport/dispatch/generation.ts +88 -21
  222. package/src/transport/dispatch/leases.ts +99 -2
  223. package/src/transport/dispatch/proxy-request.ts +60 -3
  224. package/src/transport/dispatch/streaming/finalize.ts +16 -1
  225. package/src/transport/dispatch/streaming/stream.ts +22 -2
  226. package/src/transport/dispatch/upstream.ts +19 -1
  227. package/src/transport/guards/auth-guard.ts +26 -1
  228. package/src/transport/guards/body-policy.ts +5 -4
  229. package/src/transport/request/preparer.ts +103 -0
  230. package/src/transport/request/state.ts +14 -0
  231. package/src/transport/routing/plan-gate.ts +45 -0
  232. package/src/transport/routing/route-catalog.ts +799 -777
  233. package/src/transport/routing/route-model.ts +52 -1
  234. package/src/transport/routing/router.ts +51 -0
  235. package/dist/dashboard/assets/BannedPage-QhvbJB9o.js +0 -1
  236. package/dist/dashboard/assets/BannedPage-QhvbJB9o.js.gz +0 -0
  237. package/dist/dashboard/assets/CliToolDetailPage-Bcy150Jo.js.gz +0 -0
  238. package/dist/dashboard/assets/CliToolsPage-DyNXefph.js.gz +0 -0
  239. package/dist/dashboard/assets/CombosPage-Cak0ljnO.js +0 -1
  240. package/dist/dashboard/assets/CombosPage-Cak0ljnO.js.gz +0 -0
  241. package/dist/dashboard/assets/ConsoleLogPage-CATpAEOz.js.gz +0 -0
  242. package/dist/dashboard/assets/CustomizationPage-D6jEU7nL.js.gz +0 -0
  243. package/dist/dashboard/assets/HealthEventsModal-CZkpn0a7.js.gz +0 -0
  244. package/dist/dashboard/assets/LoginPage-BJlMVN4U.js.gz +0 -0
  245. package/dist/dashboard/assets/ModelPicker-Br3CXEau.js.gz +0 -0
  246. package/dist/dashboard/assets/OverviewPage-CQxXbo2g.js +0 -1
  247. package/dist/dashboard/assets/OverviewPage-CQxXbo2g.js.gz +0 -0
  248. package/dist/dashboard/assets/ProviderDetailPage--0RBNh99.js +0 -3
  249. package/dist/dashboard/assets/ProviderDetailPage--0RBNh99.js.gz +0 -0
  250. package/dist/dashboard/assets/ProviderIcon-paOCq8I0.js +0 -1
  251. package/dist/dashboard/assets/ProviderIcon-paOCq8I0.js.gz +0 -0
  252. package/dist/dashboard/assets/ProvidersPage-1M-C3mbu.js +0 -1
  253. package/dist/dashboard/assets/ProvidersPage-1M-C3mbu.js.gz +0 -0
  254. package/dist/dashboard/assets/ProxyPage-CXiumA53.js +0 -7
  255. package/dist/dashboard/assets/ProxyPage-CXiumA53.js.gz +0 -0
  256. package/dist/dashboard/assets/QuotaPage-BGDIfIYP.js +0 -1
  257. package/dist/dashboard/assets/QuotaPage-BGDIfIYP.js.gz +0 -0
  258. package/dist/dashboard/assets/SettingsPage-BHW4Zt06.js.gz +0 -0
  259. package/dist/dashboard/assets/SetupPage-VOYC_lIa.js.gz +0 -0
  260. package/dist/dashboard/assets/SortableList-DpOTnGuH.js +0 -1
  261. package/dist/dashboard/assets/SortableList-DpOTnGuH.js.gz +0 -0
  262. package/dist/dashboard/assets/StudioPage-BNIDLiU6.js.gz +0 -0
  263. package/dist/dashboard/assets/UsagePage-BAFaSDQV.js +0 -56
  264. package/dist/dashboard/assets/UsagePage-BAFaSDQV.js.gz +0 -0
  265. package/dist/dashboard/assets/api-keys-BETfaMYZ.js.gz +0 -0
  266. package/dist/dashboard/assets/app-BLCvGdzb.css +0 -2
  267. package/dist/dashboard/assets/app-BLCvGdzb.css.gz +0 -0
  268. package/dist/dashboard/assets/assert-7J6_LVD3.js +0 -1
  269. package/dist/dashboard/assets/assert-7J6_LVD3.js.gz +0 -0
  270. package/dist/dashboard/assets/badge-BTyGk_DL.js.gz +0 -0
  271. package/dist/dashboard/assets/banner-bujTWYM4.js.gz +0 -0
  272. package/dist/dashboard/assets/card-B0Bnx5CA.js.gz +0 -0
  273. package/dist/dashboard/assets/cli-tools-DE2ug812.js.gz +0 -0
  274. package/dist/dashboard/assets/clipboard-button-R_rArH8S.js.gz +0 -0
  275. package/dist/dashboard/assets/dialog-BWIP_EvW.js.gz +0 -0
  276. package/dist/dashboard/assets/drawer-BKcgVugF.js.gz +0 -0
  277. package/dist/dashboard/assets/entry-7dpgvpJ3.js +0 -4
  278. package/dist/dashboard/assets/entry-7dpgvpJ3.js.gz +0 -0
  279. package/dist/dashboard/assets/entry-kTiTFrvh.js.gz +0 -0
  280. package/dist/dashboard/assets/github-badge-Booc5mNe.js.gz +0 -0
  281. package/dist/dashboard/assets/index-D70pChfn.js.gz +0 -0
  282. package/dist/dashboard/assets/inline-D1TCqM2D.js.gz +0 -0
  283. package/dist/dashboard/assets/input-B9oyU93y.js.gz +0 -0
  284. package/dist/dashboard/assets/layout-BArzXirQ.js.gz +0 -0
  285. package/dist/dashboard/assets/list-row-BVZzaoHF.js.gz +0 -0
  286. package/dist/dashboard/assets/live-EmuIayqp.js.gz +0 -0
  287. package/dist/dashboard/assets/model-bans-CSPQ9xB0.js.gz +0 -0
  288. package/dist/dashboard/assets/routing-BExgxxBU.js.gz +0 -0
  289. package/dist/dashboard/assets/select-C9mMoEpJ.js +0 -41
  290. package/dist/dashboard/assets/select-C9mMoEpJ.js.gz +0 -0
  291. package/dist/dashboard/assets/settings-C4_Gn_wq.js +0 -1
  292. package/dist/dashboard/assets/settings-C4_Gn_wq.js.gz +0 -0
  293. package/dist/dashboard/assets/sliders-horizontal-ClG7dBeJ.js +0 -1
  294. package/dist/dashboard/assets/sliders-horizontal-ClG7dBeJ.js.gz +0 -0
  295. package/dist/dashboard/assets/stack-Ca5HxI5i.js.gz +0 -0
  296. package/dist/dashboard/assets/state-CzUPfLXo.js.gz +0 -0
  297. package/dist/dashboard/assets/switch-DOUIky_i.js.gz +0 -0
  298. package/dist/dashboard/assets/toast-C76WrMhc.js.gz +0 -0
  299. package/dist/dashboard/assets/useMutation-D87FZwH0.js.gz +0 -0
  300. package/src/network/tls/bun-client-hello.ts +0 -112
  301. /package/dist/dashboard/assets/{app-Cjq7nrwu.js → app-C-Y4oZT0.js} +0 -0
  302. /package/dist/dashboard/assets/{app-Cjq7nrwu.js.gz → app-C-Y4oZT0.js.gz} +0 -0
@@ -0,0 +1,2355 @@
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
+ import protobuf from "protobufjs"
28
+
29
+ // ── Helper: create a root and add a Type with fields ──
30
+
31
+ type FieldDef = { id: number; name: string; type: string; repeated?: boolean }
32
+ type OneofDef = { name: string; fields: string[] }
33
+
34
+ function addType(
35
+ root: protobuf.Root,
36
+ name: string,
37
+ fields: FieldDef[],
38
+ oneofs?: OneofDef[],
39
+ ): protobuf.Type {
40
+ const t = new protobuf.Type(name)
41
+ for (const f of fields) {
42
+ t.add(new protobuf.Field(f.name, f.id, f.type, f.repeated ? "repeated" : undefined))
43
+ }
44
+ for (const o of oneofs ?? []) {
45
+ t.add(new protobuf.OneOf(o.name, o.fields))
46
+ }
47
+ root.add(t)
48
+ return t
49
+ }
50
+
51
+ // ── Utility messages ──
52
+
53
+ export function createMessageTypes(): protobuf.Root {
54
+ const root = new protobuf.Root()
55
+
56
+ addType(root, "TextDeltaUpdate", [
57
+ { id: 1, name: "text", type: "string" },
58
+ ])
59
+
60
+ addType(root, "ThinkingDeltaUpdate", [
61
+ { id: 1, name: "text", type: "string" },
62
+ ])
63
+
64
+ addType(root, "TurnEnded", [
65
+ { id: 1, name: "input_tokens", type: "uint32" },
66
+ { id: 2, name: "output_tokens", type: "uint32" },
67
+ { id: 3, name: "cache_read", type: "uint32" },
68
+ { id: 4, name: "cache_write", type: "uint32" },
69
+ { id: 5, name: "reasoning_tokens", type: "uint32" },
70
+ ])
71
+
72
+ addType(root, "Heartbeat", [])
73
+
74
+ // Display ToolCall (interaction_update.tool_call_*) — agent.v1 oneof, not
75
+ // {tool_name,args} strings. Decode finalized todo state for mirroring and
76
+ // MCP errors for diagnostics; other completion results are not replayed.
77
+ root.add(new protobuf.Enum("TodoStatus", {
78
+ TODO_STATUS_UNSPECIFIED: 0,
79
+ TODO_STATUS_PENDING: 1,
80
+ TODO_STATUS_IN_PROGRESS: 2,
81
+ TODO_STATUS_COMPLETED: 3,
82
+ TODO_STATUS_CANCELLED: 4,
83
+ }))
84
+ addType(root, "TodoItem", [
85
+ { id: 1, name: "id", type: "string" },
86
+ { id: 2, name: "content", type: "string" },
87
+ { id: 3, name: "status", type: "TodoStatus" },
88
+ { id: 4, name: "created_at", type: "int64" },
89
+ { id: 5, name: "updated_at", type: "int64" },
90
+ { id: 6, name: "dependencies", type: "string", repeated: true },
91
+ ])
92
+ addType(root, "UpdateTodosArgs", [
93
+ { id: 1, name: "todos", type: "TodoItem", repeated: true },
94
+ { id: 2, name: "merge", type: "bool" },
95
+ ])
96
+ addType(root, "UpdateTodosSuccess", [
97
+ { id: 1, name: "todos", type: "TodoItem", repeated: true },
98
+ { id: 2, name: "total_count", type: "int32" },
99
+ { id: 3, name: "was_merge", type: "bool" },
100
+ ])
101
+ addType(root, "UpdateTodosError", [{ id: 1, name: "error", type: "string" }])
102
+ addType(
103
+ root,
104
+ "UpdateTodosResult",
105
+ [
106
+ { id: 1, name: "success", type: "UpdateTodosSuccess" },
107
+ { id: 2, name: "error", type: "UpdateTodosError" },
108
+ ],
109
+ [{ name: "result", fields: ["success", "error"] }],
110
+ )
111
+ addType(root, "UpdateTodosToolCall", [
112
+ { id: 1, name: "args", type: "UpdateTodosArgs" },
113
+ { id: 2, name: "result", type: "UpdateTodosResult" },
114
+ ])
115
+ addType(root, "ReadToolArgs", [
116
+ { id: 1, name: "path", type: "string" },
117
+ { id: 2, name: "offset", type: "int32" },
118
+ { id: 3, name: "limit", type: "int32" },
119
+ ])
120
+ addType(root, "ReadToolCall", [{ id: 1, name: "args", type: "ReadToolArgs" }])
121
+ addType(root, "ShellToolCall", [{ id: 1, name: "args", type: "ShellArgs" }])
122
+ addType(root, "DeleteToolCall", [{ id: 1, name: "args", type: "DeleteArgs" }])
123
+ addType(root, "GlobToolCall", [{ id: 1, name: "args", type: "GlobArgs" }])
124
+ addType(root, "GrepToolCall", [{ id: 1, name: "args", type: "GrepArgs" }])
125
+ addType(root, "EditToolArgs", [
126
+ { id: 1, name: "path", type: "string" },
127
+ { id: 6, name: "stream_content", type: "string" },
128
+ ])
129
+ addType(root, "EditToolCall", [{ id: 1, name: "args", type: "EditToolArgs" }])
130
+ addType(root, "LsToolCall", [{ id: 1, name: "args", type: "LsArgs" }])
131
+ addType(root, "McpToolCall", [
132
+ { id: 1, name: "args", type: "McpArgs" },
133
+ { id: 2, name: "result", type: "McpResult" },
134
+ ])
135
+ addType(root, "CreatePlanArgs", [
136
+ { id: 1, name: "plan", type: "string" },
137
+ { id: 2, name: "todos", type: "TodoItem", repeated: true },
138
+ { id: 3, name: "overview", type: "string" },
139
+ { id: 4, name: "name", type: "string" },
140
+ { id: 5, name: "is_project", type: "bool" },
141
+ ])
142
+ addType(root, "CreatePlanToolCall", [{ id: 1, name: "args", type: "CreatePlanArgs" }])
143
+ addType(root, "WebSearchToolArgs", [
144
+ { id: 1, name: "search_term", type: "string" },
145
+ { id: 2, name: "tool_call_id", type: "string" },
146
+ ])
147
+ addType(root, "WebSearchToolCall", [{ id: 1, name: "args", type: "WebSearchToolArgs" }])
148
+ addType(root, "SubagentTypeUnspecified", [])
149
+ addType(root, "SubagentTypeComputerUse", [])
150
+ addType(root, "SubagentTypeCustom", [{ id: 1, name: "name", type: "string" }])
151
+ addType(root, "SubagentTypeExplore", [])
152
+ addType(root, "SubagentTypeMediaReview", [])
153
+ addType(root, "SubagentTypeBash", [])
154
+ addType(root, "SubagentTypeBrowserUse", [])
155
+ addType(root, "SubagentTypeShell", [])
156
+ addType(root, "SubagentTypeVmSetupHelper", [])
157
+ addType(root, "SubagentTypeDebug", [])
158
+ addType(root, "SubagentTypeCursorGuide", [])
159
+ addType(root, "SubagentTypeWatchVideo", [])
160
+ addType(
161
+ root,
162
+ "SubagentType",
163
+ [
164
+ { id: 1, name: "unspecified", type: "SubagentTypeUnspecified" },
165
+ { id: 2, name: "computer_use", type: "SubagentTypeComputerUse" },
166
+ { id: 3, name: "custom", type: "SubagentTypeCustom" },
167
+ { id: 4, name: "explore", type: "SubagentTypeExplore" },
168
+ { id: 5, name: "media_review", type: "SubagentTypeMediaReview" },
169
+ { id: 6, name: "bash", type: "SubagentTypeBash" },
170
+ { id: 7, name: "browser_use", type: "SubagentTypeBrowserUse" },
171
+ { id: 8, name: "shell", type: "SubagentTypeShell" },
172
+ { id: 9, name: "vm_setup_helper", type: "SubagentTypeVmSetupHelper" },
173
+ { id: 10, name: "debug", type: "SubagentTypeDebug" },
174
+ { id: 11, name: "cursor_guide", type: "SubagentTypeCursorGuide" },
175
+ { id: 12, name: "watch_video", type: "SubagentTypeWatchVideo" },
176
+ ],
177
+ [{
178
+ name: "type",
179
+ fields: [
180
+ "unspecified", "computer_use", "custom", "explore", "media_review", "bash",
181
+ "browser_use", "shell", "vm_setup_helper", "debug", "cursor_guide", "watch_video",
182
+ ],
183
+ }],
184
+ )
185
+ addType(root, "TaskToolArgs", [
186
+ { id: 1, name: "description", type: "string" },
187
+ { id: 2, name: "prompt", type: "string" },
188
+ { id: 3, name: "subagent_type", type: "SubagentType" },
189
+ { id: 4, name: "model", type: "string" },
190
+ { id: 5, name: "resume", type: "string" },
191
+ { id: 6, name: "agent_id", type: "string" },
192
+ { id: 7, name: "attachments", type: "string", repeated: true },
193
+ ])
194
+ addType(root, "TaskToolCall", [{ id: 1, name: "args", type: "TaskToolArgs" }])
195
+
196
+ // Native subagent execution is separate from the display-only TaskToolCall.
197
+ // Cursor asks the local client to run the task through ExecServerMessage #28
198
+ // and waits for the correlated SubagentResult at ExecClientMessage #28.
199
+ addType(root, "SubagentArgs", [
200
+ { id: 1, name: "tool_call_id", type: "string" },
201
+ { id: 2, name: "subagent_type", type: "string" },
202
+ { id: 3, name: "model_id", type: "string" },
203
+ { id: 4, name: "prompt", type: "string" },
204
+ { id: 5, name: "readonly", type: "bool" },
205
+ { id: 6, name: "resume_agent_id", type: "string" },
206
+ { id: 7, name: "run_in_background", type: "bool" },
207
+ ])
208
+ addType(root, "SubagentSuccess", [
209
+ { id: 1, name: "agent_id", type: "string" },
210
+ { id: 2, name: "final_message", type: "string" },
211
+ { id: 3, name: "tool_call_count", type: "int32" },
212
+ { id: 4, name: "background_reason", type: "int32" },
213
+ { id: 5, name: "transcript_path", type: "string" },
214
+ ])
215
+ addType(root, "SubagentError", [
216
+ { id: 1, name: "agent_id", type: "string" },
217
+ { id: 2, name: "error", type: "string" },
218
+ ])
219
+ addType(
220
+ root,
221
+ "SubagentResult",
222
+ [
223
+ { id: 1, name: "success", type: "SubagentSuccess" },
224
+ { id: 2, name: "error", type: "SubagentError" },
225
+ ],
226
+ [{ name: "result", fields: ["success", "error"] }],
227
+ )
228
+ addType(root, "AskQuestionOption", [
229
+ { id: 1, name: "id", type: "string" },
230
+ { id: 2, name: "label", type: "string" },
231
+ ])
232
+ addType(root, "AskQuestionItem", [
233
+ { id: 1, name: "id", type: "string" },
234
+ { id: 2, name: "prompt", type: "string" },
235
+ { id: 3, name: "options", type: "AskQuestionOption", repeated: true },
236
+ { id: 4, name: "allow_multiple", type: "bool" },
237
+ ])
238
+ addType(root, "AskQuestionArgs", [
239
+ { id: 1, name: "title", type: "string" },
240
+ { id: 2, name: "questions", type: "AskQuestionItem", repeated: true },
241
+ // #5/#6 drive Cursor's non-blocking AskQuestion: the client answers the
242
+ // interaction with `async` right away and delivers the real answers later
243
+ // through ConversationAction.async_ask_question_completion_action, keyed by
244
+ // the originating tool call id. See protocol/ask-question.ts.
245
+ { id: 5, name: "run_async", type: "bool" },
246
+ { id: 6, name: "async_original_tool_call_id", type: "string" },
247
+ ])
248
+ addType(root, "AskQuestionToolCall", [{ id: 1, name: "args", type: "AskQuestionArgs" }])
249
+ addType(root, "FetchToolArgs", [
250
+ { id: 1, name: "url", type: "string" },
251
+ { id: 2, name: "tool_call_id", type: "string" },
252
+ ])
253
+ addType(root, "FetchToolCall", [{ id: 1, name: "args", type: "FetchToolArgs" }])
254
+ addType(root, "WebFetchToolCall", [{ id: 1, name: "args", type: "FetchToolArgs" }])
255
+ addType(root, "SwitchModeToolArgs", [
256
+ { id: 1, name: "target_mode_id", type: "string" },
257
+ { id: 2, name: "explanation", type: "string" },
258
+ { id: 3, name: "tool_call_id", type: "string" },
259
+ ])
260
+ // Display ToolCall.result (CLI success hardcodes from_mode_id=""); distinct from
261
+ // InteractionResponse approved/rejected, which is the consent gate.
262
+ addType(root, "SwitchModeSuccess", [
263
+ { id: 1, name: "from_mode_id", type: "string" },
264
+ { id: 2, name: "to_mode_id", type: "string" },
265
+ ])
266
+ addType(root, "SwitchModeError", [{ id: 1, name: "error", type: "string" }])
267
+ addType(root, "SwitchModeRejected", [{ id: 1, name: "reason", type: "string" }])
268
+ addType(root, "SwitchModeResult", [
269
+ { id: 1, name: "success", type: "SwitchModeSuccess" },
270
+ { id: 2, name: "error", type: "SwitchModeError" },
271
+ { id: 3, name: "rejected", type: "SwitchModeRejected" },
272
+ ], [{ name: "result", fields: ["success", "error", "rejected"] }])
273
+ addType(root, "SwitchModeToolCall", [
274
+ { id: 1, name: "args", type: "SwitchModeToolArgs" },
275
+ { id: 2, name: "result", type: "SwitchModeResult" },
276
+ ])
277
+ addType(root, "PiReadToolArgs", [
278
+ { id: 1, name: "path", type: "string" },
279
+ { id: 2, name: "offset", type: "int32" },
280
+ { id: 3, name: "limit", type: "int32" },
281
+ ])
282
+ addType(root, "PiBashToolArgs", [
283
+ { id: 1, name: "command", type: "string" },
284
+ { id: 2, name: "timeout", type: "double" },
285
+ ])
286
+ addType(root, "PiEditReplacement", [
287
+ { id: 1, name: "old_text", type: "string" },
288
+ { id: 2, name: "new_text", type: "string" },
289
+ ])
290
+ addType(root, "PiEditToolArgs", [
291
+ { id: 1, name: "path", type: "string" },
292
+ { id: 2, name: "edits", type: "PiEditReplacement", repeated: true },
293
+ ])
294
+ addType(root, "PiWriteToolArgs", [
295
+ { id: 1, name: "path", type: "string" },
296
+ { id: 2, name: "content", type: "string" },
297
+ ])
298
+ addType(root, "PiGrepToolArgs", [
299
+ { id: 1, name: "pattern", type: "string" },
300
+ { id: 2, name: "path", type: "string" },
301
+ { id: 3, name: "glob", type: "string" },
302
+ { id: 4, name: "ignore_case", type: "bool" },
303
+ { id: 5, name: "literal", type: "bool" },
304
+ { id: 6, name: "context", type: "int32" },
305
+ { id: 7, name: "limit", type: "int32" },
306
+ ])
307
+ addType(root, "PiFindToolArgs", [
308
+ { id: 1, name: "pattern", type: "string" },
309
+ { id: 2, name: "path", type: "string" },
310
+ { id: 3, name: "limit", type: "int32" },
311
+ ])
312
+ addType(root, "PiLsToolArgs", [
313
+ { id: 1, name: "path", type: "string" },
314
+ { id: 2, name: "limit", type: "int32" },
315
+ ])
316
+ addType(root, "PiWriteToolCall", [{ id: 1, name: "args", type: "PiWriteToolArgs" }])
317
+ addType(root, "PiReadToolCall", [{ id: 1, name: "args", type: "PiReadToolArgs" }])
318
+ addType(root, "PiBashToolCall", [{ id: 1, name: "args", type: "PiBashToolArgs" }])
319
+ addType(root, "PiEditToolCall", [{ id: 1, name: "args", type: "PiEditToolArgs" }])
320
+ addType(root, "PiGrepToolCall", [{ id: 1, name: "args", type: "PiGrepToolArgs" }])
321
+ addType(root, "PiFindToolCall", [{ id: 1, name: "args", type: "PiFindToolArgs" }])
322
+ addType(root, "PiLsToolCall", [{ id: 1, name: "args", type: "PiLsToolArgs" }])
323
+ // Display-only native tools Cursor may complete without an ExecServerMessage.
324
+ // ReadTodos mirrors UpdateTodos: args + result (see agent.v1 ReadTodosToolCall).
325
+ addType(root, "ReadTodosArgs", [
326
+ { id: 1, name: "status_filter", type: "TodoStatus", repeated: true },
327
+ { id: 2, name: "id_filter", type: "string", repeated: true },
328
+ ])
329
+ addType(root, "ReadTodosSuccess", [
330
+ { id: 1, name: "todos", type: "TodoItem", repeated: true },
331
+ { id: 2, name: "total_count", type: "int32" },
332
+ ])
333
+ addType(root, "ReadTodosError", [{ id: 1, name: "error", type: "string" }])
334
+ addType(
335
+ root,
336
+ "ReadTodosResult",
337
+ [
338
+ { id: 1, name: "success", type: "ReadTodosSuccess" },
339
+ { id: 2, name: "error", type: "ReadTodosError" },
340
+ ],
341
+ [{ name: "result", fields: ["success", "error"] }],
342
+ )
343
+ addType(root, "ReadTodosToolCall", [
344
+ { id: 1, name: "args", type: "ReadTodosArgs" },
345
+ { id: 2, name: "result", type: "ReadTodosResult" },
346
+ ])
347
+ addType(root, "AwaitArgs", [
348
+ { id: 1, name: "task_id", type: "string" },
349
+ { id: 2, name: "block_until_ms", type: "uint32" },
350
+ { id: 3, name: "regex", type: "string" },
351
+ ])
352
+ addType(root, "AwaitToolCall", [{ id: 1, name: "args", type: "AwaitArgs" }])
353
+ addType(root, "GetMcpToolsArgs", [
354
+ { id: 1, name: "server", type: "string" },
355
+ { id: 2, name: "tool_name", type: "string" },
356
+ { id: 3, name: "pattern", type: "string" },
357
+ { id: 4, name: "tool_call_id", type: "string" },
358
+ ])
359
+ // agent.v1 GetMcpToolsToolCall is args + result. Cursor's agent fills result
360
+ // locally (GetDynamicTools / GetMcpTools); large catalogs spill through
361
+ // write_args and put the spill path on GetMcpToolsSuccess.output_file_path.
362
+ addType(root, "GetMcpToolsSuccess", [
363
+ { id: 1, name: "content", type: "string" },
364
+ { id: 2, name: "output_file_path", type: "string" },
365
+ ])
366
+ addType(root, "GetMcpToolsError", [{ id: 1, name: "error", type: "string" }])
367
+ addType(root, "GetMcpToolsAgentResult", [
368
+ { id: 1, name: "success", type: "GetMcpToolsSuccess" },
369
+ { id: 2, name: "error", type: "GetMcpToolsError" },
370
+ ], [{ name: "result", fields: ["success", "error"] }])
371
+ addType(root, "GetMcpToolsToolCall", [
372
+ { id: 1, name: "args", type: "GetMcpToolsArgs" },
373
+ { id: 2, name: "result", type: "GetMcpToolsAgentResult" },
374
+ ])
375
+
376
+ addType(root, "GenerateImageToolArgs", [
377
+ { id: 1, name: "description", type: "string" },
378
+ { id: 2, name: "file_path", type: "string" },
379
+ { id: 5, name: "reference_image_paths", type: "string", repeated: true },
380
+ ])
381
+ // Cursor generates the image server-side and returns it on the display
382
+ // tool_call frame. `image_data` is a base64 string, not bytes.
383
+ addType(root, "GenerateImageSuccess", [
384
+ { id: 1, name: "file_path", type: "string" },
385
+ { id: 2, name: "image_data", type: "string" },
386
+ ])
387
+ addType(root, "GenerateImageError", [{ id: 1, name: "error", type: "string" }])
388
+ addType(root, "GenerateImageResult", [
389
+ { id: 1, name: "success", type: "GenerateImageSuccess" },
390
+ { id: 2, name: "error", type: "GenerateImageError" },
391
+ ], [{ name: "result", fields: ["success", "error"] }])
392
+ addType(root, "GenerateImageToolCall", [
393
+ { id: 1, name: "args", type: "GenerateImageToolArgs" },
394
+ { id: 2, name: "result", type: "GenerateImageResult" },
395
+ ])
396
+ // InteractionQuery keeps query bodies opaque; decoded on demand like
397
+ // AskQuestionInteractionQuery.
398
+ addType(root, "GenerateImageRequestQuery", [
399
+ { id: 1, name: "args", type: "GenerateImageToolArgs" },
400
+ { id: 2, name: "tool_call_id", type: "string" },
401
+ ])
402
+
403
+ addType(
404
+ root,
405
+ "ToolCall",
406
+ [
407
+ { id: 57, name: "tool_call_id", type: "string" },
408
+ { id: 1, name: "shell_tool_call", type: "ShellToolCall" },
409
+ { id: 3, name: "delete_tool_call", type: "DeleteToolCall" },
410
+ { id: 4, name: "glob_tool_call", type: "GlobToolCall" },
411
+ { id: 5, name: "grep_tool_call", type: "GrepToolCall" },
412
+ { id: 8, name: "read_tool_call", type: "ReadToolCall" },
413
+ { id: 9, name: "update_todos_tool_call", type: "UpdateTodosToolCall" },
414
+ { id: 10, name: "read_todos_tool_call", type: "ReadTodosToolCall" },
415
+ { id: 12, name: "edit_tool_call", type: "EditToolCall" },
416
+ { id: 13, name: "ls_tool_call", type: "LsToolCall" },
417
+ { id: 15, name: "mcp_tool_call", type: "McpToolCall" },
418
+ { id: 17, name: "create_plan_tool_call", type: "CreatePlanToolCall" },
419
+ { id: 18, name: "web_search_tool_call", type: "WebSearchToolCall" },
420
+ { id: 19, name: "task_tool_call", type: "TaskToolCall" },
421
+ { id: 23, name: "ask_question_tool_call", type: "AskQuestionToolCall" },
422
+ { id: 24, name: "fetch_tool_call", type: "FetchToolCall" },
423
+ { id: 25, name: "switch_mode_tool_call", type: "SwitchModeToolCall" },
424
+ { id: 28, name: "generate_image_tool_call", type: "GenerateImageToolCall" },
425
+ { id: 37, name: "web_fetch_tool_call", type: "WebFetchToolCall" },
426
+ { id: 42, name: "await_tool_call", type: "AwaitToolCall" },
427
+ { id: 44, name: "get_mcp_tools_tool_call", type: "GetMcpToolsToolCall" },
428
+ { id: 61, name: "pi_read_tool_call", type: "PiReadToolCall" },
429
+ { id: 62, name: "pi_bash_tool_call", type: "PiBashToolCall" },
430
+ { id: 63, name: "pi_edit_tool_call", type: "PiEditToolCall" },
431
+ { id: 64, name: "pi_write_tool_call", type: "PiWriteToolCall" },
432
+ { id: 65, name: "pi_grep_tool_call", type: "PiGrepToolCall" },
433
+ { id: 66, name: "pi_find_tool_call", type: "PiFindToolCall" },
434
+ { id: 67, name: "pi_ls_tool_call", type: "PiLsToolCall" },
435
+ ],
436
+ [{
437
+ name: "tool",
438
+ fields: [
439
+ "shell_tool_call", "delete_tool_call", "glob_tool_call", "grep_tool_call",
440
+ "read_tool_call", "update_todos_tool_call", "read_todos_tool_call",
441
+ "edit_tool_call", "ls_tool_call",
442
+ "mcp_tool_call", "create_plan_tool_call", "web_search_tool_call", "task_tool_call",
443
+ "ask_question_tool_call", "fetch_tool_call", "switch_mode_tool_call",
444
+ "generate_image_tool_call", "web_fetch_tool_call", "await_tool_call", "get_mcp_tools_tool_call",
445
+ "pi_read_tool_call", "pi_bash_tool_call", "pi_edit_tool_call",
446
+ "pi_write_tool_call", "pi_grep_tool_call", "pi_find_tool_call", "pi_ls_tool_call",
447
+ ],
448
+ }],
449
+ )
450
+
451
+ addType(root, "ToolCallStarted", [
452
+ { id: 1, name: "call_id", type: "string" },
453
+ { id: 2, name: "tool_call", type: "ToolCall" },
454
+ { id: 3, name: "model_call_id", type: "string" },
455
+ ])
456
+
457
+ // agent.v1 ToolCallCompletedUpdate has no string result field — result lives
458
+ // inside the typed ToolCall variant.
459
+ addType(root, "ToolCallCompleted", [
460
+ { id: 1, name: "call_id", type: "string" },
461
+ { id: 2, name: "tool_call", type: "ToolCall" },
462
+ { id: 3, name: "model_call_id", type: "string" },
463
+ ])
464
+
465
+ addType(root, "PartialToolCall", [
466
+ { id: 1, name: "call_id", type: "string" },
467
+ { id: 2, name: "tool_call", type: "ToolCall" },
468
+ { id: 3, name: "args_text_delta", type: "string" },
469
+ { id: 4, name: "model_call_id", type: "string" },
470
+ ])
471
+
472
+ // agent.v1 ToolCallDeltaUpdate: keep the nested delta opaque; the pump
473
+ // needs its presence as generation progress, not its display-only content.
474
+ addType(root, "ToolCallDeltaUpdate", [
475
+ { id: 1, name: "call_id", type: "string" },
476
+ { id: 2, name: "tool_call_delta", type: "bytes" },
477
+ { id: 3, name: "model_call_id", type: "string" },
478
+ ])
479
+
480
+ // agent.v1 StepStartedUpdate / StepCompletedUpdate: step_id is uint64 (T:4),
481
+ // not string — wrong type made every step_completed frame throw
482
+ // "index out of range" in decodeMessage.
483
+ addType(root, "StepStarted", [
484
+ { id: 1, name: "step_id", type: "uint64" },
485
+ ])
486
+
487
+ addType(root, "StepCompleted", [
488
+ { id: 1, name: "step_id", type: "uint64" },
489
+ { id: 2, name: "step_duration_ms", type: "int64" },
490
+ ])
491
+
492
+ // agent.v1 ToolRequestsListedUpdate — Cursor lists how many tool calls this
493
+ // generation will send so the client can place its step boundary (CLI does
494
+ // not need this; OpenCode's AI SDK step does). Field 27 on InteractionUpdate.
495
+ addType(root, "ToolRequestsListedUpdate", [
496
+ { id: 1, name: "call_count", type: "uint32" },
497
+ ])
498
+
499
+ // InteractionUpdate — the core streaming update message
500
+ addType(
501
+ root,
502
+ "InteractionUpdate",
503
+ [
504
+ { id: 1, name: "text_delta", type: "TextDeltaUpdate" },
505
+ { id: 2, name: "tool_call_started", type: "ToolCallStarted" },
506
+ { id: 3, name: "tool_call_completed", type: "ToolCallCompleted" },
507
+ { id: 4, name: "thinking_delta", type: "ThinkingDeltaUpdate" },
508
+ { id: 7, name: "partial_tool_call", type: "PartialToolCall" },
509
+ { id: 13, name: "heartbeat", type: "Heartbeat" },
510
+ { id: 14, name: "turn_ended", type: "TurnEnded" },
511
+ { id: 15, name: "tool_call_delta", type: "ToolCallDeltaUpdate" },
512
+ { id: 16, name: "step_started", type: "StepStarted" },
513
+ { id: 17, name: "step_completed", type: "StepCompleted" },
514
+ { id: 23, name: "context_injection_state", type: "ContextInjectionStateUpdate" },
515
+ { id: 27, name: "tool_requests_listed", type: "ToolRequestsListedUpdate" },
516
+ ],
517
+ [{ name: "update", fields: ["text_delta", "tool_call_started", "tool_call_completed", "thinking_delta", "partial_tool_call", "heartbeat", "turn_ended", "tool_call_delta", "step_started", "step_completed", "context_injection_state", "tool_requests_listed"] }],
518
+ )
519
+
520
+ // Server status for an `inject_context_action` (InteractionUpdate #23).
521
+ // Cursor CLI only tracks it to show queued steer delivery; it carries no output.
522
+ addType(root, "ContextInjectionQueued", [])
523
+ addType(root, "ContextInjectionQueuedForNextTurn", [])
524
+ addType(root, "ContextInjectionCancelled", [])
525
+ addType(root, "ContextInjectionDelivered", [
526
+ { id: 1, name: "step", type: "int32" },
527
+ { id: 2, name: "delivery_batch_id", type: "string" },
528
+ { id: 3, name: "delivered_at_ms", type: "int64" },
529
+ ])
530
+ addType(root, "ContextInjectionRejected", [
531
+ { id: 1, name: "reason", type: "string" },
532
+ ])
533
+ addType(
534
+ root,
535
+ "ContextInjectionState",
536
+ [
537
+ { id: 1, name: "queued", type: "ContextInjectionQueued" },
538
+ { id: 2, name: "delivered", type: "ContextInjectionDelivered" },
539
+ { id: 3, name: "queued_for_next_turn", type: "ContextInjectionQueuedForNextTurn" },
540
+ { id: 4, name: "cancelled", type: "ContextInjectionCancelled" },
541
+ { id: 5, name: "rejected", type: "ContextInjectionRejected" },
542
+ ],
543
+ [{ name: "state", fields: ["queued", "delivered", "queued_for_next_turn", "cancelled", "rejected"] }],
544
+ )
545
+ addType(root, "ContextInjectionStateUpdate", [
546
+ { id: 1, name: "injection_id", type: "string" },
547
+ { id: 2, name: "state", type: "ContextInjectionState" },
548
+ ])
549
+
550
+ // ── Exec channel ──
551
+
552
+ // Field numbers match agent.v1. Extra fields we don't use are still declared
553
+ // so protobufjs doesn't drop them on decode.
554
+ addType(root, "ReadArgs", [
555
+ { id: 1, name: "path", type: "string" },
556
+ { id: 2, name: "tool_call_id", type: "string" },
557
+ { id: 4, name: "offset", type: "int32" },
558
+ { id: 5, name: "limit", type: "uint32" },
559
+ ])
560
+
561
+ // agent.v1 ReadResult is a oneof — flat {content,error} was rejected by the
562
+ // server (endless heartbeats after read_result).
563
+ addType(
564
+ root,
565
+ "ReadSuccess",
566
+ [
567
+ { id: 1, name: "path", type: "string" },
568
+ { id: 2, name: "content", type: "string" },
569
+ { id: 3, name: "total_lines", type: "int32" },
570
+ { id: 4, name: "file_size", type: "int64" },
571
+ { id: 5, name: "data", type: "bytes" },
572
+ { id: 6, name: "truncated", type: "bool" },
573
+ { id: 7, name: "output_blob_id", type: "bytes" },
574
+ { id: 8, name: "range_applied", type: "bool" },
575
+ ],
576
+ [{ name: "output", fields: ["content", "data"] }],
577
+ )
578
+ addType(root, "ReadError", [
579
+ { id: 1, name: "path", type: "string" },
580
+ { id: 2, name: "error", type: "string" },
581
+ ])
582
+ // Cursor's LocalReadExecutor validates the target before execution and, for a
583
+ // missing / non-regular path, returns one of these typed ReadResult cases
584
+ // instead of running the tool. Mirroring the exact field ids/shapes lets this
585
+ // provider reply the same way so the model sees a structured file-not-found
586
+ // observation and the host never surfaces a permission prompt.
587
+ addType(root, "ReadFileNotFound", [{ id: 1, name: "path", type: "string" }])
588
+ addType(root, "ReadPermissionDenied", [{ id: 1, name: "path", type: "string" }])
589
+ addType(root, "ReadInvalidFile", [
590
+ { id: 1, name: "path", type: "string" },
591
+ { id: 2, name: "reason", type: "string" },
592
+ ])
593
+ addType(root, "ReadRejected", [
594
+ { id: 1, name: "path", type: "string" },
595
+ { id: 2, name: "reason", type: "string" },
596
+ ])
597
+ addType(
598
+ root,
599
+ "ReadResult",
600
+ [
601
+ { id: 1, name: "success", type: "ReadSuccess" },
602
+ { id: 2, name: "error", type: "ReadError" },
603
+ { id: 3, name: "rejected", type: "ReadRejected" },
604
+ { id: 4, name: "file_not_found", type: "ReadFileNotFound" },
605
+ { id: 5, name: "permission_denied", type: "ReadPermissionDenied" },
606
+ { id: 6, name: "invalid_file", type: "ReadInvalidFile" },
607
+ ],
608
+ [
609
+ {
610
+ name: "result",
611
+ fields: ["success", "error", "rejected", "file_not_found", "permission_denied", "invalid_file"],
612
+ },
613
+ ],
614
+ )
615
+
616
+ addType(root, "GrepArgs", [
617
+ { id: 1, name: "pattern", type: "string" },
618
+ { id: 2, name: "path", type: "string" },
619
+ { id: 3, name: "glob", type: "string" },
620
+ { id: 4, name: "output_mode", type: "string" },
621
+ { id: 8, name: "case_insensitive", type: "bool" },
622
+ { id: 10, name: "head_limit", type: "int32" },
623
+ { id: 14, name: "tool_call_id", type: "string" },
624
+ { id: 16, name: "offset", type: "int32" },
625
+ ])
626
+
627
+ addType(root, "GrepError", [{ id: 1, name: "error", type: "string" }])
628
+ addType(root, "GrepFilesResult", [
629
+ { id: 1, name: "files", type: "string", repeated: true },
630
+ { id: 2, name: "total_files", type: "int32" },
631
+ { id: 3, name: "client_truncated", type: "bool" },
632
+ ])
633
+ addType(root, "GrepContentMatch", [
634
+ { id: 1, name: "line_number", type: "int32" },
635
+ { id: 2, name: "content", type: "string" },
636
+ ])
637
+ addType(root, "GrepFileMatch", [
638
+ { id: 1, name: "file", type: "string" },
639
+ { id: 2, name: "matches", type: "GrepContentMatch", repeated: true },
640
+ ])
641
+ addType(root, "GrepContentResult", [
642
+ { id: 1, name: "matches", type: "GrepFileMatch", repeated: true },
643
+ { id: 2, name: "total_lines", type: "int32" },
644
+ { id: 3, name: "total_matched_lines", type: "int32" },
645
+ { id: 4, name: "client_truncated", type: "bool" },
646
+ { id: 5, name: "ripgrep_truncated", type: "bool" },
647
+ ])
648
+ addType(
649
+ root,
650
+ "GrepUnionResult",
651
+ [
652
+ { id: 2, name: "files", type: "GrepFilesResult" },
653
+ { id: 3, name: "content", type: "GrepContentResult" },
654
+ ],
655
+ [{ name: "result", fields: ["files", "content"] }],
656
+ )
657
+ {
658
+ const t = new protobuf.Type("GrepSuccess")
659
+ t.add(new protobuf.Field("pattern", 1, "string"))
660
+ t.add(new protobuf.Field("path", 2, "string"))
661
+ t.add(new protobuf.Field("output_mode", 3, "string"))
662
+ t.add(new protobuf.MapField("workspace_results", 4, "string", "GrepUnionResult"))
663
+ root.add(t)
664
+ }
665
+ addType(
666
+ root,
667
+ "GrepResult",
668
+ [
669
+ { id: 1, name: "success", type: "GrepSuccess" },
670
+ { id: 2, name: "error", type: "GrepError" },
671
+ ],
672
+ [{ name: "result", fields: ["success", "error"] }],
673
+ )
674
+
675
+ // agent.v1.WriteArgs. Cursor's own LocalWriteExecutor reads `file_bytes`
676
+ // first and only falls back to `file_text`, so a write whose content arrives
677
+ // as bytes decodes to an empty string unless field 5 is declared here.
678
+ addType(root, "WriteArgs", [
679
+ { id: 1, name: "path", type: "string" },
680
+ { id: 2, name: "file_text", type: "string" },
681
+ { id: 3, name: "tool_call_id", type: "string" },
682
+ { id: 4, name: "return_file_content_after_write", type: "bool" },
683
+ { id: 5, name: "file_bytes", type: "bytes" },
684
+ { id: 6, name: "encoding_hint", type: "string" },
685
+ ])
686
+
687
+ addType(root, "WriteSuccess", [
688
+ { id: 1, name: "path", type: "string" },
689
+ { id: 2, name: "lines_created", type: "int32" },
690
+ { id: 3, name: "file_size", type: "int32" },
691
+ { id: 4, name: "file_content_after_write", type: "string" },
692
+ ])
693
+ addType(root, "WriteError", [
694
+ { id: 1, name: "path", type: "string" },
695
+ { id: 2, name: "error", type: "string" },
696
+ ])
697
+ // Cursor's own executor reports a refused write with this variant rather than
698
+ // a generic error, and its agent reads `operation` / `is_readonly` back.
699
+ addType(root, "WritePermissionDenied", [
700
+ { id: 1, name: "path", type: "string" },
701
+ { id: 2, name: "directory", type: "string" },
702
+ { id: 3, name: "operation", type: "string" },
703
+ { id: 4, name: "error", type: "string" },
704
+ { id: 5, name: "is_readonly", type: "bool" },
705
+ ])
706
+ addType(root, "WriteRejected", [
707
+ { id: 1, name: "path", type: "string" },
708
+ { id: 2, name: "reason", type: "string" },
709
+ ])
710
+ addType(
711
+ root,
712
+ "WriteResult",
713
+ [
714
+ { id: 1, name: "success", type: "WriteSuccess" },
715
+ { id: 3, name: "permission_denied", type: "WritePermissionDenied" },
716
+ { id: 5, name: "error", type: "WriteError" },
717
+ { id: 6, name: "rejected", type: "WriteRejected" },
718
+ ],
719
+ [{ name: "result", fields: ["success", "permission_denied", "error", "rejected"] }],
720
+ )
721
+
722
+ // agent.v1 Pi exec results. Cursor places Pi requests at ExecServerMessage
723
+ // fields #45..#51 and their corresponding ExecClientMessage results at
724
+ // #46..#52 (the result fields are deliberately offset by one).
725
+ //
726
+ // The success payloads contain additional optional truncation/diff metadata;
727
+ // OpenCode returns text, so the minimal output/error shapes are sufficient.
728
+ addType(root, "PiWriteArgs", [
729
+ { id: 1, name: "path", type: "string" },
730
+ { id: 2, name: "content", type: "string" },
731
+ ])
732
+ addType(root, "PiWriteSuccess", [
733
+ { id: 1, name: "output", type: "string" },
734
+ ])
735
+ addType(root, "PiWriteError", [
736
+ { id: 1, name: "error", type: "string" },
737
+ ])
738
+ addType(root, "PiWriteRejected", [
739
+ { id: 1, name: "reason", type: "string" },
740
+ ])
741
+ addType(
742
+ root,
743
+ "PiWriteResult",
744
+ [
745
+ { id: 1, name: "success", type: "PiWriteSuccess" },
746
+ { id: 2, name: "error", type: "PiWriteError" },
747
+ { id: 3, name: "rejected", type: "PiWriteRejected" },
748
+ ],
749
+ [{ name: "result", fields: ["success", "error", "rejected"] }],
750
+ )
751
+ // agent.v1.PiTruncation. Every Pi *ExecSuccess shares output(1)+truncation(2)
752
+ // and only diverges at field 3, so the shared PiOutputSuccess can carry it.
753
+ // Cursor's own CLI always reports truncation rather than silently shortening
754
+ // a payload; emitting this keeps a capped read distinguishable from a
755
+ // complete one.
756
+ addType(root, "PiTruncation", [
757
+ { id: 1, name: "truncated", type: "bool" },
758
+ { id: 2, name: "truncated_by", type: "string" },
759
+ { id: 3, name: "total_lines", type: "uint32" },
760
+ { id: 4, name: "output_lines", type: "uint32" },
761
+ { id: 5, name: "output_bytes", type: "uint32" },
762
+ { id: 6, name: "max_lines", type: "uint32" },
763
+ { id: 7, name: "max_bytes", type: "uint32" },
764
+ { id: 8, name: "first_line_exceeds_limit", type: "bool" },
765
+ { id: 9, name: "last_line_partial", type: "bool" },
766
+ ])
767
+ addType(root, "PiOutputSuccess", [
768
+ { id: 1, name: "output", type: "string" },
769
+ { id: 2, name: "truncation", type: "PiTruncation" },
770
+ ])
771
+ addType(root, "PiExecError", [{ id: 1, name: "error", type: "string" }])
772
+ addType(root, "PiExecRejected", [{ id: 1, name: "reason", type: "string" }])
773
+ for (const resultType of [
774
+ "PiReadExecResult",
775
+ "PiBashExecResult",
776
+ "PiGrepExecResult",
777
+ "PiFindExecResult",
778
+ "PiLsExecResult",
779
+ ]) {
780
+ addType(
781
+ root,
782
+ resultType,
783
+ [
784
+ { id: 1, name: "success", type: "PiOutputSuccess" },
785
+ { id: 2, name: "error", type: "PiExecError" },
786
+ ],
787
+ [{ name: "result", fields: ["success", "error"] }],
788
+ )
789
+ }
790
+ addType(
791
+ root,
792
+ "PiEditExecResult",
793
+ [
794
+ { id: 1, name: "success", type: "PiOutputSuccess" },
795
+ { id: 2, name: "error", type: "PiExecError" },
796
+ { id: 3, name: "rejected", type: "PiExecRejected" },
797
+ ],
798
+ [{ name: "result", fields: ["success", "error", "rejected"] }],
799
+ )
800
+
801
+ addType(root, "DeleteArgs", [
802
+ { id: 1, name: "path", type: "string" },
803
+ { id: 2, name: "tool_call_id", type: "string" },
804
+ ])
805
+
806
+ addType(root, "DeleteSuccess", [
807
+ { id: 1, name: "path", type: "string" },
808
+ { id: 2, name: "deleted_file", type: "string" },
809
+ ])
810
+ addType(root, "DeleteError", [
811
+ { id: 1, name: "path", type: "string" },
812
+ { id: 2, name: "error", type: "string" },
813
+ ])
814
+ addType(root, "DeletePermissionDenied", [
815
+ { id: 1, name: "path", type: "string" },
816
+ { id: 2, name: "client_visible_error", type: "string" },
817
+ { id: 3, name: "is_readonly", type: "bool" },
818
+ ])
819
+ addType(root, "DeleteRejected", [
820
+ { id: 1, name: "path", type: "string" },
821
+ { id: 2, name: "reason", type: "string" },
822
+ ])
823
+ addType(
824
+ root,
825
+ "DeleteResult",
826
+ [
827
+ { id: 1, name: "success", type: "DeleteSuccess" },
828
+ { id: 4, name: "permission_denied", type: "DeletePermissionDenied" },
829
+ { id: 6, name: "rejected", type: "DeleteRejected" },
830
+ { id: 7, name: "error", type: "DeleteError" },
831
+ ],
832
+ [{ name: "result", fields: ["success", "permission_denied", "rejected", "error"] }],
833
+ )
834
+
835
+ addType(root, "LsArgs", [
836
+ { id: 1, name: "path", type: "string" },
837
+ { id: 2, name: "ignore", type: "string", repeated: true },
838
+ { id: 3, name: "tool_call_id", type: "string" },
839
+ ])
840
+
841
+ addType(root, "LsDirectoryTreeFile", [{ id: 1, name: "name", type: "string" }])
842
+ addType(root, "LsDirectoryTreeNode", [
843
+ { id: 1, name: "abs_path", type: "string" },
844
+ { id: 2, name: "children_dirs", type: "LsDirectoryTreeNode", repeated: true },
845
+ { id: 3, name: "children_files", type: "LsDirectoryTreeFile", repeated: true },
846
+ { id: 6, name: "num_files", type: "int32" },
847
+ ])
848
+ addType(root, "LsSuccess", [
849
+ { id: 1, name: "directory_tree_root", type: "LsDirectoryTreeNode" },
850
+ ])
851
+ addType(root, "LsError", [
852
+ { id: 1, name: "path", type: "string" },
853
+ { id: 2, name: "error", type: "string" },
854
+ ])
855
+ addType(root, "LsRejected", [
856
+ { id: 1, name: "path", type: "string" },
857
+ { id: 2, name: "reason", type: "string" },
858
+ ])
859
+ addType(
860
+ root,
861
+ "LsResult",
862
+ [
863
+ { id: 1, name: "success", type: "LsSuccess" },
864
+ { id: 2, name: "error", type: "LsError" },
865
+ { id: 3, name: "rejected", type: "LsRejected" },
866
+ ],
867
+ [{ name: "result", fields: ["success", "error", "rejected"] }],
868
+ )
869
+
870
+ addType(root, "ShellArgs", [
871
+ { id: 1, name: "command", type: "string" },
872
+ { id: 2, name: "working_directory", type: "string" },
873
+ { id: 3, name: "timeout", type: "uint32" },
874
+ { id: 4, name: "tool_call_id", type: "string" },
875
+ // Canonical agent.v1 fields used by the native CLI to distinguish a
876
+ // foreground cancellation deadline from a soft background handoff.
877
+ { id: 13, name: "timeout_behavior", type: "uint32" },
878
+ { id: 14, name: "hard_timeout", type: "uint32" },
879
+ { id: 15, name: "description", type: "string" },
880
+ ])
881
+
882
+ addType(root, "ShellStreamStart", []) // optional SandboxPolicy only; empty is valid
883
+ addType(root, "ShellStreamStdout", [{ id: 1, name: "data", type: "string" }])
884
+ addType(root, "ShellStreamStderr", [{ id: 1, name: "data", type: "string" }])
885
+ // agent.v1: code is uint32; protobufjs must emit code=0 (defaults are load-bearing).
886
+ addType(root, "ShellStreamExit", [
887
+ { id: 1, name: "code", type: "uint32" },
888
+ { id: 2, name: "cwd", type: "string" },
889
+ { id: 4, name: "aborted", type: "bool" },
890
+ { id: 5, name: "abort_reason", type: "uint32" },
891
+ { id: 6, name: "local_execution_time_ms", type: "uint32" },
892
+ ])
893
+ addType(root, "ShellStreamBackgrounded", [
894
+ { id: 1, name: "shell_id", type: "uint32" },
895
+ { id: 2, name: "command", type: "string" },
896
+ { id: 3, name: "working_directory", type: "string" },
897
+ { id: 4, name: "pid", type: "uint32" },
898
+ { id: 5, name: "ms_to_wait", type: "uint32" },
899
+ { id: 6, name: "reason", type: "uint32" },
900
+ ])
901
+ // ShellRejected / ShellPermissionDenied (shared with ShellResult) — reason/error at #3.
902
+ addType(root, "ShellRejected", [
903
+ { id: 1, name: "command", type: "string" },
904
+ { id: 2, name: "working_directory", type: "string" },
905
+ { id: 3, name: "reason", type: "string" },
906
+ ])
907
+ addType(root, "ShellPermissionDenied", [
908
+ { id: 1, name: "command", type: "string" },
909
+ { id: 2, name: "working_directory", type: "string" },
910
+ { id: 3, name: "error", type: "string" },
911
+ ])
912
+
913
+ // ── Soft-deny stubs for known unsupported Cursor-native exec variants ──
914
+ // These are encode-only: enough to emit a populated deny, not full success.
915
+ // Canonical field numbers from agent.proto ExecClientMessage.
916
+ // ShellResult is also the live reply for exec #2 shell_args (OpenCode bash).
917
+ addType(root, "ShellSuccess", [
918
+ { id: 1, name: "command", type: "string" },
919
+ { id: 2, name: "working_directory", type: "string" },
920
+ { id: 3, name: "exit_code", type: "int32" },
921
+ { id: 4, name: "signal", type: "string" },
922
+ { id: 5, name: "stdout", type: "string" },
923
+ { id: 6, name: "stderr", type: "string" },
924
+ { id: 7, name: "execution_time", type: "int32" },
925
+ { id: 9, name: "shell_id", type: "uint32" },
926
+ { id: 11, name: "pid", type: "uint32" },
927
+ { id: 12, name: "ms_to_wait", type: "int32" },
928
+ { id: 13, name: "local_execution_time_ms", type: "int32" },
929
+ { id: 14, name: "background_reason", type: "uint32" },
930
+ ])
931
+ addType(root, "ShellFailure", [
932
+ { id: 1, name: "command", type: "string" },
933
+ { id: 2, name: "working_directory", type: "string" },
934
+ { id: 3, name: "exit_code", type: "int32" },
935
+ { id: 4, name: "signal", type: "string" },
936
+ { id: 5, name: "stdout", type: "string" },
937
+ { id: 6, name: "stderr", type: "string" },
938
+ { id: 7, name: "execution_time", type: "int32" },
939
+ { id: 10, name: "abort_reason", type: "uint32" },
940
+ { id: 11, name: "aborted", type: "bool" },
941
+ ])
942
+ addType(root, "ShellTimeout", [
943
+ { id: 1, name: "command", type: "string" },
944
+ { id: 2, name: "working_directory", type: "string" },
945
+ { id: 3, name: "timeout_ms", type: "int32" },
946
+ ])
947
+ addType(
948
+ root,
949
+ "ShellResult",
950
+ [
951
+ { id: 1, name: "success", type: "ShellSuccess" },
952
+ { id: 2, name: "failure", type: "ShellFailure" },
953
+ { id: 3, name: "timeout", type: "ShellTimeout" },
954
+ { id: 4, name: "rejected", type: "ShellRejected" },
955
+ { id: 7, name: "permission_denied", type: "ShellPermissionDenied" },
956
+ { id: 102, name: "is_background", type: "bool" },
957
+ { id: 104, name: "pid", type: "uint32" },
958
+ ],
959
+ [{ name: "result", fields: ["success", "failure", "timeout", "rejected", "permission_denied"] }],
960
+ )
961
+ addType(root, "DiagnosticsError", [
962
+ { id: 1, name: "path", type: "string" },
963
+ { id: 2, name: "error", type: "string" },
964
+ ])
965
+ addType(root, "DiagnosticsResult", [
966
+ { id: 2, name: "error", type: "DiagnosticsError" },
967
+ ], [{ name: "result", fields: ["error"] }])
968
+ addType(root, "FetchError", [
969
+ { id: 1, name: "url", type: "string" },
970
+ { id: 2, name: "error", type: "string" },
971
+ ])
972
+ addType(root, "FetchResult", [
973
+ { id: 2, name: "error", type: "FetchError" },
974
+ ], [{ name: "result", fields: ["error"] }])
975
+ addType(root, "RecordScreenFailure", [
976
+ { id: 1, name: "error", type: "string" },
977
+ ])
978
+ addType(root, "RecordScreenResult", [
979
+ { id: 4, name: "failure", type: "RecordScreenFailure" },
980
+ ], [{ name: "result", fields: ["failure"] }])
981
+ addType(root, "ComputerUseError", [
982
+ { id: 1, name: "error", type: "string" },
983
+ ])
984
+ addType(root, "ComputerUseResult", [
985
+ { id: 2, name: "error", type: "ComputerUseError" },
986
+ ], [{ name: "result", fields: ["error"] }])
987
+ addType(root, "WriteShellStdinError", [
988
+ { id: 1, name: "error", type: "string" },
989
+ ])
990
+ addType(root, "WriteShellStdinResult", [
991
+ { id: 2, name: "error", type: "WriteShellStdinError" },
992
+ ], [{ name: "result", fields: ["error"] }])
993
+ addType(root, "SubagentAwaitError", [
994
+ { id: 1, name: "agent_id", type: "string" },
995
+ { id: 2, name: "error", type: "string" },
996
+ ])
997
+ addType(root, "SubagentAwaitResult", [
998
+ { id: 4, name: "error", type: "SubagentAwaitError" },
999
+ ], [{ name: "result", fields: ["error"] }])
1000
+ addType(root, "SmartModeClassifierError", [
1001
+ { id: 1, name: "error", type: "string" },
1002
+ ])
1003
+ addType(root, "SmartModeClassifierResult", [
1004
+ { id: 2, name: "error", type: "SmartModeClassifierError" },
1005
+ ], [{ name: "result", fields: ["error"] }])
1006
+ addType(root, "CanvasDiagnosticsError", [
1007
+ { id: 1, name: "path", type: "string" },
1008
+ { id: 2, name: "error", type: "string" },
1009
+ ])
1010
+ addType(root, "CanvasDiagnosticsResult", [
1011
+ { id: 2, name: "error", type: "CanvasDiagnosticsError" },
1012
+ ], [{ name: "result", fields: ["error"] }])
1013
+ addType(root, "ShellAllowlistPrecheckResult", [
1014
+ { id: 1, name: "allowlisted", type: "bool" },
1015
+ ])
1016
+ addType(root, "McpAllowlistPrecheckResult", [
1017
+ { id: 1, name: "allowlisted", type: "bool" },
1018
+ ])
1019
+ addType(root, "WebFetchAllowlistPrecheckResult", [
1020
+ { id: 1, name: "allowlisted", type: "bool" },
1021
+ ])
1022
+ addType(root, "ForceBackgroundShellResult", [
1023
+ { id: 1, name: "status", type: "uint32" },
1024
+ ])
1025
+ addType(root, "ForceBackgroundSubagentResult", [
1026
+ { id: 1, name: "status", type: "uint32" },
1027
+ ])
1028
+ addType(root, "ConversationSearchHit", [
1029
+ { id: 1, name: "conversation_id", type: "string" },
1030
+ { id: 2, name: "title", type: "string" },
1031
+ { id: 3, name: "source", type: "uint32" },
1032
+ { id: 4, name: "updated_at_ms", type: "int64" },
1033
+ { id: 5, name: "snippet", type: "string" },
1034
+ ])
1035
+ addType(root, "ConversationSearchSuccess", [
1036
+ { id: 1, name: "hits", type: "ConversationSearchHit", repeated: true },
1037
+ { id: 2, name: "truncated", type: "bool" },
1038
+ { id: 3, name: "partial", type: "bool" },
1039
+ { id: 4, name: "rebuilding", type: "bool" },
1040
+ ])
1041
+ addType(root, "ConversationSearchError", [
1042
+ { id: 1, name: "error", type: "string" },
1043
+ ])
1044
+ addType(
1045
+ root,
1046
+ "ConversationSearchResult",
1047
+ [
1048
+ { id: 1, name: "success", type: "ConversationSearchSuccess" },
1049
+ { id: 2, name: "error", type: "ConversationSearchError" },
1050
+ ],
1051
+ [{ name: "result", fields: ["success", "error"] }],
1052
+ )
1053
+ addType(root, "AgentStoreConflictError", [
1054
+ { id: 1, name: "error", type: "string" },
1055
+ ])
1056
+ addType(
1057
+ root,
1058
+ "AgentStoreConflictResult",
1059
+ [
1060
+ { id: 2, name: "error", type: "AgentStoreConflictError" },
1061
+ ],
1062
+ [{ name: "result", fields: ["error"] }],
1063
+ )
1064
+ addType(
1065
+ root,
1066
+ "AdoptResult",
1067
+ [
1068
+ { id: 1, name: "source_agent_id", type: "string" },
1069
+ { id: 2, name: "target_agent_id", type: "string" },
1070
+ { id: 3, name: "project_root_id", type: "string" },
1071
+ { id: 5, name: "error", type: "string" },
1072
+ ],
1073
+ [{ name: "result", fields: ["error"] }],
1074
+ )
1075
+
1076
+ // aiserver.v1.GetDiffRequest / GetDiffResponse (exec #44). Enums as uint32
1077
+ // so protobufjs json decode does not stringify output_format / diff_type.
1078
+ addType(root, "GitDiffChunk", [
1079
+ { id: 1, name: "content", type: "string" },
1080
+ { id: 2, name: "lines", type: "string", repeated: true },
1081
+ { id: 3, name: "old_start", type: "int32" },
1082
+ { id: 4, name: "old_lines", type: "int32" },
1083
+ { id: 5, name: "new_start", type: "int32" },
1084
+ { id: 6, name: "new_lines", type: "int32" },
1085
+ ])
1086
+ addType(root, "GitFileDiff", [
1087
+ { id: 1, name: "from", type: "string" },
1088
+ { id: 2, name: "to", type: "string" },
1089
+ { id: 3, name: "chunks", type: "GitDiffChunk", repeated: true },
1090
+ { id: 4, name: "added", type: "int32" },
1091
+ { id: 5, name: "removed", type: "int32" },
1092
+ { id: 6, name: "before_file_contents", type: "string" },
1093
+ { id: 7, name: "after_file_contents", type: "string" },
1094
+ { id: 8, name: "is_generated", type: "bool" },
1095
+ ])
1096
+ addType(root, "GitDiff", [
1097
+ { id: 1, name: "diffs", type: "GitFileDiff", repeated: true },
1098
+ { id: 2, name: "diff_type", type: "uint32" },
1099
+ ])
1100
+ addType(root, "GitDiffSubmoduleDiff", [
1101
+ { id: 1, name: "relative_path", type: "string" },
1102
+ { id: 2, name: "diff", type: "GitDiff" },
1103
+ { id: 3, name: "errored", type: "bool" },
1104
+ ])
1105
+ addType(root, "GetDiffRequest", [
1106
+ { id: 1, name: "cwd", type: "string" },
1107
+ { id: 2, name: "ref", type: "string" },
1108
+ { id: 3, name: "base_ref", type: "string" },
1109
+ { id: 4, name: "merge_base", type: "bool" },
1110
+ { id: 5, name: "target_paths", type: "string", repeated: true },
1111
+ { id: 6, name: "unified_context_lines", type: "int32" },
1112
+ { id: 7, name: "max_untracked_files", type: "int32" },
1113
+ { id: 8, name: "output_format", type: "uint32" },
1114
+ { id: 9, name: "submodule_recurse_depth", type: "int32" },
1115
+ { id: 10, name: "include_space_changes", type: "bool" },
1116
+ { id: 11, name: "committed_only", type: "bool" },
1117
+ { id: 12, name: "compute_patch_id", type: "bool" },
1118
+ { id: 13, name: "return_head_sha", type: "bool" },
1119
+ { id: 14, name: "max_response_bytes", type: "int32" },
1120
+ ])
1121
+ addType(root, "GetDiffResponse", [
1122
+ { id: 1, name: "diff", type: "GitDiff" },
1123
+ { id: 2, name: "submodule_diffs", type: "GitDiffSubmoduleDiff", repeated: true },
1124
+ { id: 3, name: "patch_id", type: "string" },
1125
+ { id: 4, name: "head_sha", type: "string" },
1126
+ { id: 5, name: "has_uncommitted_changes", type: "bool" },
1127
+ ])
1128
+
1129
+ // Cursor's non-blocking shell path is a separate exec variant from the
1130
+ // foreground ShellStream above. The host only needs the fields used at the
1131
+ // OpenCode boundary; protobufjs safely skips the richer classifier/approval
1132
+ // messages that are private to Cursor's native client.
1133
+ addType(root, "BackgroundShellSpawnArgs", [
1134
+ { id: 1, name: "command", type: "string" },
1135
+ { id: 2, name: "working_directory", type: "string" },
1136
+ { id: 3, name: "tool_call_id", type: "string" },
1137
+ { id: 6, name: "enable_write_shell_stdin_tool", type: "bool" },
1138
+ { id: 7, name: "description", type: "string" },
1139
+ { id: 12, name: "skip_approval", type: "bool" },
1140
+ { id: 13, name: "conversation_id", type: "string" },
1141
+ ])
1142
+ addType(root, "BackgroundShellSpawnSuccess", [
1143
+ { id: 1, name: "shell_id", type: "uint32" },
1144
+ { id: 2, name: "command", type: "string" },
1145
+ { id: 3, name: "working_directory", type: "string" },
1146
+ { id: 4, name: "pid", type: "uint32" },
1147
+ ])
1148
+ addType(root, "BackgroundShellSpawnError", [
1149
+ { id: 1, name: "command", type: "string" },
1150
+ { id: 2, name: "working_directory", type: "string" },
1151
+ { id: 3, name: "error", type: "string" },
1152
+ ])
1153
+ addType(
1154
+ root,
1155
+ "BackgroundShellSpawnResult",
1156
+ [
1157
+ { id: 1, name: "success", type: "BackgroundShellSpawnSuccess" },
1158
+ { id: 2, name: "error", type: "BackgroundShellSpawnError" },
1159
+ { id: 3, name: "rejected", type: "ShellRejected" },
1160
+ { id: 4, name: "permission_denied", type: "ShellPermissionDenied" },
1161
+ ],
1162
+ [{ name: "result", fields: ["success", "error", "rejected", "permission_denied"] }],
1163
+ )
1164
+
1165
+ // Cursor CLI postToolUse hook context: ExecClientMessage #45 on a unary
1166
+ // result, ShellStream #8 on a shell stream (agent.v1 hook_additional_context).
1167
+ addType(root, "HookAdditionalContext", [
1168
+ { id: 1, name: "hook_event_name", type: "string" },
1169
+ { id: 2, name: "content", type: "string" },
1170
+ ])
1171
+ addType(root, "ShellStreamHookContext", [
1172
+ { id: 1, name: "hook_additional_contexts", type: "HookAdditionalContext", repeated: true },
1173
+ ])
1174
+
1175
+ addType(
1176
+ root,
1177
+ "ShellStream",
1178
+ [
1179
+ { id: 1, name: "stdout", type: "ShellStreamStdout" },
1180
+ { id: 2, name: "stderr", type: "ShellStreamStderr" },
1181
+ { id: 3, name: "exit", type: "ShellStreamExit" },
1182
+ { id: 4, name: "start", type: "ShellStreamStart" },
1183
+ { id: 5, name: "rejected", type: "ShellRejected" },
1184
+ { id: 6, name: "permission_denied", type: "ShellPermissionDenied" },
1185
+ { id: 7, name: "backgrounded", type: "ShellStreamBackgrounded" },
1186
+ { id: 8, name: "hook_context", type: "ShellStreamHookContext" },
1187
+ ],
1188
+ [{ name: "event", fields: ["stdout", "stderr", "exit", "start", "rejected", "permission_denied", "backgrounded", "hook_context"] }],
1189
+ )
1190
+
1191
+ addType(root, "GlobArgs", [
1192
+ { id: 1, name: "target_directory", type: "string" },
1193
+ { id: 2, name: "glob_pattern", type: "string" },
1194
+ ])
1195
+
1196
+ addType(root, "GlobResult", [
1197
+ { id: 1, name: "files", type: "string", repeated: true },
1198
+ { id: 2, name: "error", type: "string" },
1199
+ ])
1200
+
1201
+ // `args` is a map<string, google.protobuf.Value> on the wire (repeated map
1202
+ // entries at field #2). We capture each entry as raw bytes and decode them in
1203
+ // tools.ts via struct.decodeStructEntriesToJson.
1204
+ addType(root, "McpArgs", [
1205
+ { id: 1, name: "name", type: "string" },
1206
+ { id: 2, name: "args", type: "bytes", repeated: true },
1207
+ { id: 3, name: "tool_call_id", type: "string" },
1208
+ { id: 4, name: "provider_identifier", type: "string" },
1209
+ { id: 5, name: "tool_name", type: "string" },
1210
+ ])
1211
+
1212
+ addType(root, "McpTextContent", [{ id: 1, name: "text", type: "string" }])
1213
+ // Cursor CLI 2026.10.01 `agent/v1/mcp_exec_pb.js`: "McpImageContent|1 data 12|2 mime_type 9",
1214
+ // "McpToolResultContentItem|1 text #0 content|2 image #1 content".
1215
+ addType(root, "McpImageContent", [
1216
+ { id: 1, name: "data", type: "bytes" },
1217
+ { id: 2, name: "mime_type", type: "string" },
1218
+ ])
1219
+ addType(
1220
+ root,
1221
+ "McpToolResultContentItem",
1222
+ [
1223
+ { id: 1, name: "text", type: "McpTextContent" },
1224
+ { id: 2, name: "image", type: "McpImageContent" },
1225
+ ],
1226
+ [{ name: "content", fields: ["text", "image"] }],
1227
+ )
1228
+ addType(root, "McpRejected", [
1229
+ { id: 1, name: "reason", type: "string" },
1230
+ { id: 2, name: "is_readonly", type: "bool" },
1231
+ ])
1232
+ addType(root, "McpPermissionDenied", [
1233
+ { id: 1, name: "error", type: "string" },
1234
+ { id: 2, name: "is_readonly", type: "bool" },
1235
+ ])
1236
+ addType(root, "McpSuccess", [
1237
+ { id: 1, name: "content", type: "McpToolResultContentItem", repeated: true },
1238
+ { id: 2, name: "is_error", type: "bool" },
1239
+ ])
1240
+ addType(root, "McpError", [
1241
+ { id: 1, name: "error", type: "string" },
1242
+ // Server-side CallDynamicTool validation uses a title (#1) and detail (#2).
1243
+ { id: 2, name: "detail", type: "string" },
1244
+ ])
1245
+ addType(
1246
+ root,
1247
+ "McpResult",
1248
+ [
1249
+ { id: 1, name: "success", type: "McpSuccess" },
1250
+ { id: 2, name: "error", type: "McpError" },
1251
+ { id: 3, name: "rejected", type: "McpRejected" },
1252
+ { id: 4, name: "permission_denied", type: "McpPermissionDenied" },
1253
+ ],
1254
+ [{ name: "result", fields: ["success", "error", "rejected", "permission_denied"] }],
1255
+ )
1256
+
1257
+ // McpToolDefinition — agent.v1 shape for RequestContext.tools (#7) and
1258
+ // AgentRunRequest.mcp_tools (#4). Defined early so RequestContext* can
1259
+ // reference it.
1260
+ addType(root, "McpToolDefinition", [
1261
+ { id: 1, name: "name", type: "string" },
1262
+ { id: 2, name: "description", type: "string" },
1263
+ { id: 3, name: "input_schema", type: "bytes" },
1264
+ { id: 4, name: "provider_identifier", type: "string" },
1265
+ { id: 5, name: "tool_name", type: "string" },
1266
+ ])
1267
+
1268
+ // ── MCP resource exec (fields 17/18) ──
1269
+ // agent.v1 ListMcpResourcesExecArgs/Result, ReadMcpResourceExecArgs/Result.
1270
+ // Native Cursor exec variants: no descriptor, no advertisement, and Cursor
1271
+ // may emit either unsolicited regardless of what this provider advertises
1272
+ // (tasks/plans/fix-cursor-mcp-resource-exec.md, Correction 2). Under Option
1273
+ // B, list_mcp_resources/read_mcp_resource execute through the ordinary
1274
+ // field-11 MCP path via the alias rules below, so any 17/18 that still
1275
+ // reaches this provider gets the total fallback built in tools.ts.
1276
+ addType(root, "SmartModeApproval", [
1277
+ { id: 1, name: "request_id", type: "string" },
1278
+ { id: 2, name: "reason", type: "string" },
1279
+ ])
1280
+ addType(root, "OutputLocation", [
1281
+ { id: 1, name: "file_path", type: "string" },
1282
+ { id: 2, name: "size_bytes", type: "int64" },
1283
+ { id: 3, name: "line_count", type: "int64" },
1284
+ ])
1285
+
1286
+ addType(root, "ListMcpResourcesExecArgs", [
1287
+ { id: 1, name: "server", type: "string" },
1288
+ ])
1289
+ {
1290
+ const t = new protobuf.Type("ListMcpResourcesExecResult_McpResource")
1291
+ t.add(new protobuf.Field("uri", 1, "string"))
1292
+ t.add(new protobuf.Field("name", 2, "string"))
1293
+ t.add(new protobuf.Field("description", 3, "string"))
1294
+ t.add(new protobuf.Field("mime_type", 4, "string"))
1295
+ t.add(new protobuf.Field("server", 5, "string"))
1296
+ t.add(new protobuf.MapField("annotations", 6, "string", "string"))
1297
+ root.add(t)
1298
+ }
1299
+ addType(root, "ListMcpResourcesSuccess", [
1300
+ { id: 1, name: "resources", type: "ListMcpResourcesExecResult_McpResource", repeated: true },
1301
+ ])
1302
+ addType(root, "ListMcpResourcesError", [{ id: 1, name: "error", type: "string" }])
1303
+ addType(root, "ListMcpResourcesRejected", [{ id: 1, name: "reason", type: "string" }])
1304
+ addType(
1305
+ root,
1306
+ "ListMcpResourcesExecResult",
1307
+ [
1308
+ { id: 1, name: "success", type: "ListMcpResourcesSuccess" },
1309
+ { id: 2, name: "error", type: "ListMcpResourcesError" },
1310
+ { id: 3, name: "rejected", type: "ListMcpResourcesRejected" },
1311
+ ],
1312
+ [{ name: "result", fields: ["success", "error", "rejected"] }],
1313
+ )
1314
+
1315
+ addType(root, "ReadMcpResourceExecArgs", [
1316
+ { id: 1, name: "server", type: "string" },
1317
+ { id: 2, name: "uri", type: "string" },
1318
+ { id: 3, name: "download_path", type: "string" },
1319
+ { id: 4, name: "tool_call_id", type: "string" },
1320
+ { id: 5, name: "smart_mode_approval", type: "SmartModeApproval" },
1321
+ ])
1322
+ {
1323
+ // Interleaved field order matches agent.proto exactly: the text/blob oneof
1324
+ // (5/6) sits between the shared metadata (1-4) and the trailing
1325
+ // annotations/download/output fields (7-9).
1326
+ const t = new protobuf.Type("ReadMcpResourceSuccess")
1327
+ t.add(new protobuf.Field("uri", 1, "string"))
1328
+ t.add(new protobuf.Field("name", 2, "string"))
1329
+ t.add(new protobuf.Field("description", 3, "string"))
1330
+ t.add(new protobuf.Field("mime_type", 4, "string"))
1331
+ t.add(new protobuf.Field("text", 5, "string"))
1332
+ t.add(new protobuf.Field("blob", 6, "bytes"))
1333
+ t.add(new protobuf.MapField("annotations", 7, "string", "string"))
1334
+ t.add(new protobuf.Field("download_path", 8, "string"))
1335
+ t.add(new protobuf.Field("output_location", 9, "OutputLocation"))
1336
+ t.add(new protobuf.OneOf("content", ["text", "blob"]))
1337
+ root.add(t)
1338
+ }
1339
+ addType(root, "ReadMcpResourceError", [
1340
+ { id: 1, name: "uri", type: "string" },
1341
+ { id: 2, name: "error", type: "string" },
1342
+ ])
1343
+ // Cursor quirk: on `rejected` only `reason` is set — `uri` (field 1) is
1344
+ // deliberately left empty. Mirror this; do not backfill uri on encode.
1345
+ addType(root, "ReadMcpResourceRejected", [
1346
+ { id: 1, name: "uri", type: "string" },
1347
+ { id: 2, name: "reason", type: "string" },
1348
+ ])
1349
+ addType(root, "ReadMcpResourceNotFound", [{ id: 1, name: "uri", type: "string" }])
1350
+ addType(
1351
+ root,
1352
+ "ReadMcpResourceExecResult",
1353
+ [
1354
+ { id: 1, name: "success", type: "ReadMcpResourceSuccess" },
1355
+ { id: 2, name: "error", type: "ReadMcpResourceError" },
1356
+ { id: 3, name: "rejected", type: "ReadMcpResourceRejected" },
1357
+ { id: 4, name: "not_found", type: "ReadMcpResourceNotFound" },
1358
+ ],
1359
+ [{ name: "result", fields: ["success", "error", "rejected", "not_found"] }],
1360
+ )
1361
+
1362
+ // ── request_context (#10): server-initiated setup probe ──
1363
+ // At the start of an agent turn the server sends ExecServerMessage
1364
+ // {request_context_args} to ask the client for workspace/env/tool context.
1365
+ // The reply is ExecClientMessage {request_context_result{success{request_context}}}.
1366
+ // If we don't reply, the server blocks on heartbeats forever (the "times out,
1367
+ // no response" symptom). We populate a minimal-but-real RequestContext — env
1368
+ // (workspace/shell/os) plus the tool list echoed into #7 tools (same
1369
+ // McpToolDefinition shape as AgentRunRequest #4 mcp_tools) so the model keeps
1370
+ // the tools opencode advertised.
1371
+ addType(root, "RequestContextArgs", [
1372
+ { id: 2, name: "notes_session_id", type: "string" },
1373
+ { id: 3, name: "workspace_id", type: "string" },
1374
+ { id: 7, name: "use_cached", type: "bool" },
1375
+ ])
1376
+
1377
+ addType(root, "RequestContextEnv", [
1378
+ { id: 1, name: "os_version", type: "string" },
1379
+ { id: 2, name: "workspace_paths", type: "string", repeated: true },
1380
+ { id: 3, name: "shell", type: "string" },
1381
+ { id: 5, name: "sandbox_enabled", type: "bool" },
1382
+ { id: 7, name: "terminals_folder", type: "string" },
1383
+ { id: 10, name: "time_zone", type: "string" },
1384
+ { id: 11, name: "project_folder", type: "string" },
1385
+ { id: 12, name: "agent_transcripts_folder", type: "string" },
1386
+ { id: 14, name: "sandbox_supported", type: "bool" },
1387
+ { id: 20, name: "is_working_dir_home_dir", type: "bool" },
1388
+ { id: 21, name: "process_working_directory", type: "string" },
1389
+ ])
1390
+
1391
+ // Cursor applies a rule by its type: `global` is the CLI's `alwaysApply: true`
1392
+ // (its AGENTS.md / CLAUDE.md default). An untyped rule is only attachable on
1393
+ // request, so its content never reaches the model on its own.
1394
+ addType(root, "CursorRuleTypeGlobal", [])
1395
+ addType(root, "CursorRuleTypeFileGlobs", [
1396
+ { id: 1, name: "globs", type: "string", repeated: true },
1397
+ ])
1398
+ addType(root, "CursorRuleTypeAgentFetched", [
1399
+ { id: 1, name: "description", type: "string" },
1400
+ ])
1401
+ addType(root, "CursorRuleTypeManuallyAttached", [])
1402
+ addType(root, "CursorRuleType", [
1403
+ { id: 1, name: "global", type: "CursorRuleTypeGlobal" },
1404
+ { id: 2, name: "file_globbed", type: "CursorRuleTypeFileGlobs" },
1405
+ { id: 3, name: "agent_fetched", type: "CursorRuleTypeAgentFetched" },
1406
+ { id: 4, name: "manually_attached", type: "CursorRuleTypeManuallyAttached" },
1407
+ ], [{ name: "type", fields: ["global", "file_globbed", "agent_fetched", "manually_attached"] }])
1408
+ addType(root, "CursorRule", [
1409
+ { id: 1, name: "full_path", type: "string" },
1410
+ { id: 2, name: "content", type: "string" },
1411
+ { id: 3, name: "type", type: "CursorRuleType" },
1412
+ ])
1413
+
1414
+ addType(root, "RepositoryIndexingInfo", [
1415
+ { id: 1, name: "relative_workspace_path", type: "string" },
1416
+ { id: 2, name: "remote_urls", type: "string", repeated: true },
1417
+ { id: 3, name: "remote_names", type: "string", repeated: true },
1418
+ { id: 4, name: "repo_name", type: "string" },
1419
+ { id: 5, name: "repo_owner", type: "string" },
1420
+ { id: 6, name: "is_tracked", type: "bool" },
1421
+ { id: 7, name: "is_local", type: "bool" },
1422
+ { id: 9, name: "workspace_uri", type: "string" },
1423
+ ])
1424
+
1425
+ addType(root, "GitRepoInfo", [
1426
+ { id: 1, name: "path", type: "string" },
1427
+ { id: 2, name: "status", type: "string" },
1428
+ { id: 3, name: "branch_name", type: "string" },
1429
+ { id: 4, name: "remote_url", type: "string" },
1430
+ ])
1431
+
1432
+ addType(root, "AgentSkill", [
1433
+ { id: 1, name: "full_path", type: "string" },
1434
+ { id: 2, name: "content", type: "string" },
1435
+ { id: 3, name: "description", type: "string" },
1436
+ ])
1437
+
1438
+ addType(root, "CustomSubagent", [
1439
+ { id: 1, name: "full_path", type: "string" },
1440
+ { id: 2, name: "name", type: "string" },
1441
+ { id: 3, name: "description", type: "string" },
1442
+ { id: 6, name: "prompt", type: "string" },
1443
+ ])
1444
+
1445
+ // Nested MCP filesystem / meta-tool shapes (agent.v1). Must be defined
1446
+ // before RequestContextPayload / RequestContext reference them.
1447
+ addType(root, "McpFsToolDescriptor", [
1448
+ { id: 1, name: "tool_name", type: "string" },
1449
+ { id: 3, name: "description", type: "string" },
1450
+ { id: 4, name: "input_schema", type: "bytes" },
1451
+ ])
1452
+
1453
+ addType(root, "McpDescriptor", [
1454
+ { id: 1, name: "server_name", type: "string" },
1455
+ { id: 2, name: "server_identifier", type: "string" },
1456
+ { id: 5, name: "tools", type: "McpFsToolDescriptor", repeated: true },
1457
+ ])
1458
+
1459
+ addType(root, "McpFileSystemOptions", [
1460
+ { id: 1, name: "enabled", type: "bool" },
1461
+ { id: 2, name: "workspace_project_dir", type: "string" },
1462
+ { id: 3, name: "mcp_descriptors", type: "McpDescriptor", repeated: true },
1463
+ ])
1464
+
1465
+ addType(root, "McpMetaToolOptions", [
1466
+ { id: 1, name: "enabled", type: "bool" },
1467
+ { id: 2, name: "mcp_descriptors", type: "McpDescriptor", repeated: true },
1468
+ ])
1469
+
1470
+ addType(root, "PermissionsAutoRunInstructions", [
1471
+ { id: 1, name: "allow_instructions", type: "string", repeated: true },
1472
+ { id: 2, name: "block_instructions", type: "string", repeated: true },
1473
+ ])
1474
+
1475
+ addType(root, "RequestContextPayload", [
1476
+ { id: 2, name: "rules", type: "CursorRule", repeated: true },
1477
+ { id: 4, name: "env", type: "RequestContextEnv" },
1478
+ { id: 6, name: "repository_info", type: "RepositoryIndexingInfo", repeated: true },
1479
+ { id: 7, name: "tools", type: "McpToolDefinition", repeated: true },
1480
+ { id: 11, name: "git_repos", type: "GitRepoInfo", repeated: true },
1481
+ { id: 13, name: "project_layouts", type: "LsDirectoryTreeNode", repeated: true },
1482
+ { id: 17, name: "web_search_enabled", type: "bool" },
1483
+ { id: 22, name: "custom_subagents", type: "CustomSubagent", repeated: true },
1484
+ { id: 23, name: "mcp_file_system_options", type: "McpFileSystemOptions" },
1485
+ { id: 24, name: "web_fetch_enabled", type: "bool" },
1486
+ { id: 25, name: "hooks_additional_context", type: "string" },
1487
+ { id: 29, name: "agent_skills", type: "AgentSkill", repeated: true },
1488
+ { id: 33, name: "git_repo_info_complete", type: "bool" },
1489
+ { id: 34, name: "mcp_meta_tool_options", type: "McpMetaToolOptions" },
1490
+ { id: 36, name: "mcp_info_complete", type: "bool" },
1491
+ { id: 39, name: "rules_info_complete", type: "bool" },
1492
+ { id: 40, name: "env_info_complete", type: "bool" },
1493
+ { id: 41, name: "repository_info_complete", type: "bool" },
1494
+ { id: 42, name: "custom_subagents_info_complete", type: "bool" },
1495
+ { id: 43, name: "agent_skills_info_complete", type: "bool" },
1496
+ { id: 44, name: "mcp_file_system_info_complete", type: "bool" },
1497
+ { id: 45, name: "git_status_info_complete", type: "bool" },
1498
+ { id: 46, name: "user_permissions_auto_run", type: "PermissionsAutoRunInstructions" },
1499
+ { id: 47, name: "project_permissions_auto_run", type: "PermissionsAutoRunInstructions" },
1500
+ ])
1501
+
1502
+ addType(root, "RequestContextSuccess", [
1503
+ { id: 1, name: "request_context", type: "RequestContextPayload" },
1504
+ ])
1505
+
1506
+ addType(root, "RequestContextResult", [
1507
+ { id: 1, name: "success", type: "RequestContextSuccess" },
1508
+ ])
1509
+
1510
+ // Cursor probes MCP server availability before emitting an MCP-backed tool
1511
+ // call. OpenCode owns those servers, so answer from the live host catalog
1512
+ // rather than surfacing this as a user tool.
1513
+ addType(root, "McpStateExecArgs", [
1514
+ { id: 1, name: "server_identifiers", type: "string", repeated: true },
1515
+ { id: 2, name: "kick_only", type: "bool" },
1516
+ ])
1517
+ addType(root, "McpInstructions", [
1518
+ { id: 1, name: "server_name", type: "string" },
1519
+ { id: 2, name: "instructions", type: "string" },
1520
+ { id: 3, name: "server_identifier", type: "string" },
1521
+ ])
1522
+ addType(root, "McpStateServer", [
1523
+ { id: 1, name: "server_name", type: "string" },
1524
+ { id: 2, name: "server_identifier", type: "string" },
1525
+ { id: 3, name: "plugin", type: "string" },
1526
+ { id: 4, name: "marketplace", type: "string" },
1527
+ // Unlike McpDescriptor (#23/#34), exec #36 returns the full canonical
1528
+ // McpToolDefinition shape, including composite name and provider identity.
1529
+ { id: 5, name: "tools", type: "McpToolDefinition", repeated: true },
1530
+ { id: 6, name: "instructions", type: "McpInstructions", repeated: true },
1531
+ { id: 7, name: "status", type: "string" },
1532
+ ])
1533
+ addType(root, "McpStateSuccess", [
1534
+ { id: 1, name: "servers", type: "McpStateServer", repeated: true },
1535
+ ])
1536
+ addType(root, "McpStateError", [{ id: 1, name: "error", type: "string" }])
1537
+ addType(root, "McpStateRejected", [{ id: 1, name: "reason", type: "string" }])
1538
+ addType(
1539
+ root,
1540
+ "McpStateExecResult",
1541
+ [
1542
+ { id: 1, name: "success", type: "McpStateSuccess" },
1543
+ { id: 2, name: "error", type: "McpStateError" },
1544
+ { id: 3, name: "rejected", type: "McpStateRejected" },
1545
+ ],
1546
+ [{ name: "result", fields: ["success", "error", "rejected"] }],
1547
+ )
1548
+
1549
+ // ExecServerMessage — server asks us to execute a tool
1550
+ addType(
1551
+ root,
1552
+ "ExecServerMessage",
1553
+ [
1554
+ { id: 1, name: "id", type: "uint32" },
1555
+ { id: 15, name: "exec_id", type: "string" },
1556
+ { id: 19, name: "span", type: "string" },
1557
+ { id: 2, name: "shell_args", type: "ShellArgs" },
1558
+ { id: 3, name: "write_args", type: "WriteArgs" },
1559
+ { id: 4, name: "delete_args", type: "DeleteArgs" },
1560
+ { id: 5, name: "grep_args", type: "GrepArgs" },
1561
+ { id: 7, name: "read_args", type: "ReadArgs" },
1562
+ { id: 8, name: "ls_args", type: "LsArgs" },
1563
+ { id: 10, name: "request_context_args", type: "RequestContextArgs" },
1564
+ { id: 11, name: "mcp_args", type: "McpArgs" },
1565
+ { id: 14, name: "shell_stream_args", type: "ShellArgs" },
1566
+ { id: 16, name: "background_shell_spawn_args", type: "BackgroundShellSpawnArgs" },
1567
+ { id: 17, name: "list_mcp_resources_exec_args", type: "ListMcpResourcesExecArgs" },
1568
+ { id: 18, name: "read_mcp_resource_exec_args", type: "ReadMcpResourceExecArgs" },
1569
+ { id: 28, name: "subagent_args", type: "SubagentArgs" },
1570
+ { id: 36, name: "mcp_state_exec_args", type: "McpStateExecArgs" },
1571
+ { id: 44, name: "git_diff_request", type: "GetDiffRequest" },
1572
+ { id: 45, name: "pi_read_args", type: "PiReadToolArgs" },
1573
+ { id: 46, name: "pi_bash_args", type: "PiBashToolArgs" },
1574
+ { id: 47, name: "pi_edit_args", type: "PiEditToolArgs" },
1575
+ { id: 48, name: "pi_write_args", type: "PiWriteArgs" },
1576
+ { id: 49, name: "pi_grep_args", type: "PiGrepToolArgs" },
1577
+ { id: 50, name: "pi_find_args", type: "PiFindToolArgs" },
1578
+ { id: 51, name: "pi_ls_args", type: "PiLsToolArgs" },
1579
+ { id: 55, name: "accept_hook_additional_contexts", type: "bool" },
1580
+ ],
1581
+ [{ name: "args", fields: [
1582
+ "shell_args", "write_args", "delete_args", "grep_args", "read_args", "ls_args",
1583
+ "request_context_args", "mcp_args", "shell_stream_args", "background_shell_spawn_args",
1584
+ "list_mcp_resources_exec_args", "read_mcp_resource_exec_args", "mcp_state_exec_args",
1585
+ "subagent_args", "git_diff_request",
1586
+ "pi_read_args", "pi_bash_args", "pi_edit_args", "pi_write_args",
1587
+ "pi_grep_args", "pi_find_args", "pi_ls_args",
1588
+ ] }],
1589
+ )
1590
+
1591
+ // ExecClientMessage — client sends tool result back
1592
+ addType(
1593
+ root,
1594
+ "ExecClientMessage",
1595
+ [
1596
+ { id: 1, name: "id", type: "uint32" },
1597
+ { id: 15, name: "exec_id", type: "string" },
1598
+ { id: 39, name: "local_execution_time_ms", type: "uint64" },
1599
+ { id: 45, name: "hook_additional_contexts", type: "HookAdditionalContext", repeated: true },
1600
+ { id: 2, name: "shell_result", type: "ShellResult" },
1601
+ { id: 3, name: "write_result", type: "WriteResult" },
1602
+ { id: 4, name: "delete_result", type: "DeleteResult" },
1603
+ { id: 5, name: "grep_result", type: "GrepResult" },
1604
+ { id: 7, name: "read_result", type: "ReadResult" },
1605
+ { id: 8, name: "ls_result", type: "LsResult" },
1606
+ { id: 9, name: "diagnostics_result", type: "DiagnosticsResult" },
1607
+ { id: 10, name: "request_context_result", type: "RequestContextResult" },
1608
+ { id: 11, name: "mcp_result", type: "McpResult" },
1609
+ { id: 14, name: "shell_stream", type: "ShellStream" },
1610
+ { id: 16, name: "background_shell_spawn_result", type: "BackgroundShellSpawnResult" },
1611
+ { id: 17, name: "list_mcp_resources_exec_result", type: "ListMcpResourcesExecResult" },
1612
+ { id: 18, name: "read_mcp_resource_exec_result", type: "ReadMcpResourceExecResult" },
1613
+ { id: 20, name: "fetch_result", type: "FetchResult" },
1614
+ { id: 21, name: "record_screen_result", type: "RecordScreenResult" },
1615
+ { id: 22, name: "computer_use_result", type: "ComputerUseResult" },
1616
+ { id: 23, name: "write_shell_stdin_result", type: "WriteShellStdinResult" },
1617
+ { id: 28, name: "subagent_result", type: "SubagentResult" },
1618
+ { id: 29, name: "redacted_read_result", type: "ReadResult" },
1619
+ { id: 30, name: "force_background_shell_result", type: "ForceBackgroundShellResult" },
1620
+ { id: 31, name: "force_background_subagent_result", type: "ForceBackgroundSubagentResult" },
1621
+ { id: 36, name: "mcp_state_exec_result", type: "McpStateExecResult" },
1622
+ { id: 37, name: "subagent_await_result", type: "SubagentAwaitResult" },
1623
+ { id: 38, name: "smart_mode_classifier_result", type: "SmartModeClassifierResult" },
1624
+ { id: 40, name: "canvas_diagnostics_result", type: "CanvasDiagnosticsResult" },
1625
+ { id: 41, name: "shell_allowlist_precheck_result", type: "ShellAllowlistPrecheckResult" },
1626
+ { id: 42, name: "mcp_allowlist_precheck_result", type: "McpAllowlistPrecheckResult" },
1627
+ { id: 43, name: "web_fetch_allowlist_precheck_result", type: "WebFetchAllowlistPrecheckResult" },
1628
+ { id: 44, name: "git_diff_response", type: "GetDiffResponse" },
1629
+ { id: 46, name: "pi_read_result", type: "PiReadExecResult" },
1630
+ { id: 47, name: "pi_bash_result", type: "PiBashExecResult" },
1631
+ { id: 48, name: "pi_edit_result", type: "PiEditExecResult" },
1632
+ { id: 49, name: "pi_write_result", type: "PiWriteResult" },
1633
+ { id: 50, name: "pi_grep_result", type: "PiGrepExecResult" },
1634
+ { id: 51, name: "pi_find_result", type: "PiFindExecResult" },
1635
+ { id: 52, name: "pi_ls_result", type: "PiLsExecResult" },
1636
+ { id: 53, name: "conversation_search_result", type: "ConversationSearchResult" },
1637
+ { id: 54, name: "agent_store_conflict_result", type: "AgentStoreConflictResult" },
1638
+ { id: 55, name: "mini_swe_agent_bash_result", type: "ShellResult" },
1639
+ { id: 56, name: "adopt_result", type: "AdoptResult" },
1640
+ ],
1641
+ [{ name: "result", fields: [
1642
+ "shell_result", "write_result", "delete_result", "grep_result", "read_result", "ls_result",
1643
+ "diagnostics_result", "request_context_result", "mcp_result", "shell_stream", "background_shell_spawn_result",
1644
+ "list_mcp_resources_exec_result", "read_mcp_resource_exec_result",
1645
+ "fetch_result", "record_screen_result", "computer_use_result", "write_shell_stdin_result",
1646
+ "subagent_result", "redacted_read_result",
1647
+ "force_background_shell_result", "force_background_subagent_result",
1648
+ "mcp_state_exec_result",
1649
+ "subagent_await_result", "smart_mode_classifier_result", "canvas_diagnostics_result",
1650
+ "shell_allowlist_precheck_result", "mcp_allowlist_precheck_result", "web_fetch_allowlist_precheck_result",
1651
+ "git_diff_response",
1652
+ "pi_read_result", "pi_bash_result", "pi_edit_result", "pi_write_result",
1653
+ "pi_grep_result", "pi_find_result", "pi_ls_result",
1654
+ "conversation_search_result", "agent_store_conflict_result",
1655
+ "mini_swe_agent_bash_result", "adopt_result",
1656
+ ] }],
1657
+ )
1658
+
1659
+ addType(root, "ExecServerControlMessage", [
1660
+ { id: 1, name: "abort", type: "ExecServerAbort" },
1661
+ ])
1662
+
1663
+ addType(root, "ExecServerAbort", [
1664
+ { id: 1, name: "id", type: "uint32" },
1665
+ ])
1666
+
1667
+ // Client→server control (ACM #5). Distinct from ExecServerControlMessage (ASM #5).
1668
+ // After every exec result (especially multi-frame shell_stream), the real CLI
1669
+ // sends stream_close{id} — without it the cloud waits forever on shell execs.
1670
+ addType(root, "ExecClientStreamClose", [{ id: 1, name: "id", type: "uint32" }])
1671
+ addType(root, "ExecClientThrow", [
1672
+ { id: 1, name: "id", type: "uint32" },
1673
+ { id: 2, name: "error", type: "string" },
1674
+ ])
1675
+ addType(root, "ExecClientHeartbeat", [{ id: 1, name: "id", type: "uint32" }])
1676
+ addType(
1677
+ root,
1678
+ "ExecClientControlMessage",
1679
+ [
1680
+ { id: 1, name: "stream_close", type: "ExecClientStreamClose" },
1681
+ { id: 2, name: "throw", type: "ExecClientThrow" },
1682
+ { id: 3, name: "heartbeat", type: "ExecClientHeartbeat" },
1683
+ ],
1684
+ [{ name: "message", fields: ["stream_close", "throw", "heartbeat"] }],
1685
+ )
1686
+
1687
+ // ── Run request types ──
1688
+
1689
+ addType(root, "ParameterValue", [
1690
+ { id: 1, name: "id", type: "string" },
1691
+ { id: 2, name: "value", type: "string" },
1692
+ ])
1693
+
1694
+ addType(root, "RequestedModel", [
1695
+ { id: 1, name: "model_id", type: "string" },
1696
+ { id: 2, name: "max_mode", type: "bool" },
1697
+ { id: 3, name: "parameters", type: "ParameterValue", repeated: true },
1698
+ ])
1699
+
1700
+ addType(root, "SelectedImageDimension", [
1701
+ { id: 1, name: "width", type: "int32" },
1702
+ { id: 2, name: "height", type: "int32" },
1703
+ ])
1704
+ addType(root, "SelectedImageBlobIdWithData", [
1705
+ { id: 1, name: "blob_id", type: "bytes" },
1706
+ { id: 2, name: "data", type: "bytes" },
1707
+ ])
1708
+ addType(
1709
+ root,
1710
+ "SelectedImage",
1711
+ [
1712
+ { id: 1, name: "blob_id", type: "bytes" },
1713
+ { id: 8, name: "data", type: "bytes" },
1714
+ { id: 9, name: "blob_id_with_data", type: "SelectedImageBlobIdWithData" },
1715
+ { id: 2, name: "uuid", type: "string" },
1716
+ { id: 3, name: "path", type: "string" },
1717
+ { id: 4, name: "dimension", type: "SelectedImageDimension" },
1718
+ { id: 7, name: "mime_type", type: "string" },
1719
+ ],
1720
+ [{ name: "data_or_blob_id", fields: ["blob_id", "data", "blob_id_with_data"] }],
1721
+ )
1722
+ addType(root, "SelectedContext", [
1723
+ { id: 1, name: "selected_images", type: "SelectedImage", repeated: true },
1724
+ ])
1725
+
1726
+ // agent.v1.AgentMode — the client's current mode, sent on every user message.
1727
+ root.add(new protobuf.Enum("AgentMode", {
1728
+ AGENT_MODE_UNSPECIFIED: 0,
1729
+ AGENT_MODE_AGENT: 1,
1730
+ AGENT_MODE_ASK: 2,
1731
+ AGENT_MODE_PLAN: 3,
1732
+ AGENT_MODE_DEBUG: 4,
1733
+ AGENT_MODE_TRIAGE: 5,
1734
+ AGENT_MODE_PROJECT: 6,
1735
+ AGENT_MODE_MULTITASK: 7,
1736
+ AGENT_MODE_CUSTOM: 8,
1737
+ }))
1738
+
1739
+ addType(root, "UserMessage", [
1740
+ { id: 1, name: "text", type: "string" },
1741
+ { id: 2, name: "message_id", type: "string" },
1742
+ { id: 3, name: "selected_context", type: "SelectedContext" },
1743
+ { id: 4, name: "mode", type: "AgentMode" },
1744
+ ])
1745
+
1746
+ // RequestContext — UserMessageAction #2. Slim mcp_meta_tool_options names
1747
+ // the advertised catalog; AgentRunRequest.mcp_tools (#4) is empty on real turns.
1748
+ addType(root, "RequestContext", [
1749
+ { id: 2, name: "rules", type: "CursorRule", repeated: true },
1750
+ { id: 4, name: "env", type: "RequestContextEnv" },
1751
+ { id: 6, name: "repository_info", type: "RepositoryIndexingInfo", repeated: true },
1752
+ { id: 7, name: "tools", type: "McpToolDefinition", repeated: true },
1753
+ { id: 11, name: "git_repos", type: "GitRepoInfo", repeated: true },
1754
+ { id: 13, name: "project_layouts", type: "LsDirectoryTreeNode", repeated: true },
1755
+ { id: 17, name: "web_search_enabled", type: "bool" },
1756
+ { id: 22, name: "custom_subagents", type: "CustomSubagent", repeated: true },
1757
+ { id: 23, name: "mcp_file_system_options", type: "McpFileSystemOptions" },
1758
+ { id: 24, name: "web_fetch_enabled", type: "bool" },
1759
+ { id: 25, name: "hooks_additional_context", type: "string" },
1760
+ { id: 29, name: "agent_skills", type: "AgentSkill", repeated: true },
1761
+ { id: 33, name: "git_repo_info_complete", type: "bool" },
1762
+ { id: 34, name: "mcp_meta_tool_options", type: "McpMetaToolOptions" },
1763
+ { id: 36, name: "mcp_info_complete", type: "bool" },
1764
+ { id: 39, name: "rules_info_complete", type: "bool" },
1765
+ { id: 40, name: "env_info_complete", type: "bool" },
1766
+ { id: 41, name: "repository_info_complete", type: "bool" },
1767
+ { id: 42, name: "custom_subagents_info_complete", type: "bool" },
1768
+ { id: 43, name: "agent_skills_info_complete", type: "bool" },
1769
+ { id: 44, name: "mcp_file_system_info_complete", type: "bool" },
1770
+ { id: 45, name: "git_status_info_complete", type: "bool" },
1771
+ { id: 46, name: "user_permissions_auto_run", type: "PermissionsAutoRunInstructions" },
1772
+ { id: 47, name: "project_permissions_auto_run", type: "PermissionsAutoRunInstructions" },
1773
+ ])
1774
+
1775
+ addType(root, "UserMessageAction", [
1776
+ { id: 1, name: "user_message", type: "UserMessage" },
1777
+ { id: 2, name: "request_context", type: "RequestContext" },
1778
+ ])
1779
+
1780
+ addType(root, "ResumeAction", [
1781
+ // Cursor CLI sends an empty ResumeAction. Field #2 is available for a
1782
+ // refreshed RequestContext; the conversation id belongs to AgentRunRequest.
1783
+ { id: 2, name: "request_context", type: "RequestContext" },
1784
+ ])
1785
+
1786
+ addType(root, "CancelAction", [
1787
+ // Cursor CLI CancelAction field #1 is the interruption reason, not an id.
1788
+ { id: 1, name: "reason", type: "string" },
1789
+ ])
1790
+
1791
+ // Deferred answers for an AskQuestion the client already replied to with
1792
+ // `async`. `original_args` is kept as raw bytes so the exact AskQuestionArgs
1793
+ // Cursor sent — including fields this schema does not model — is echoed back
1794
+ // verbatim rather than re-encoded from a lossy decode.
1795
+ addType(root, "AsyncAskQuestionCompletionAction", [
1796
+ { id: 1, name: "original_tool_call_id", type: "string" },
1797
+ { id: 2, name: "original_args", type: "bytes" },
1798
+ { id: 3, name: "result", type: "AskQuestionResult" },
1799
+ ])
1800
+
1801
+ // Cursor CLI 2026.10.01 descriptors: system context is
1802
+ // injected into the current Run without submitting another user turn.
1803
+ addType(root, "SystemContextInjection", [
1804
+ { id: 1, name: "producer", type: "string" },
1805
+ { id: 2, name: "content", type: "string" },
1806
+ ])
1807
+ // Cursor SDK `Run.steer` / CLI steering payload: a user message added to the
1808
+ // running turn. `request_context` is optional and unused by the SDK.
1809
+ addType(root, "UserContextInjection", [
1810
+ { id: 1, name: "user_message", type: "UserMessage" },
1811
+ { id: 2, name: "request_context", type: "RequestContext" },
1812
+ ])
1813
+ addType(root, "InjectContextAction", [
1814
+ { id: 1, name: "injection_id", type: "string" },
1815
+ { id: 2, name: "expected_run_id", type: "string" },
1816
+ { id: 3, name: "user_context", type: "UserContextInjection" },
1817
+ { id: 4, name: "system_context", type: "SystemContextInjection" },
1818
+ ])
1819
+
1820
+ addType(
1821
+ root,
1822
+ "ConversationAction",
1823
+ [
1824
+ { id: 1, name: "user_message_action", type: "UserMessageAction" },
1825
+ { id: 2, name: "resume_action", type: "ResumeAction" },
1826
+ { id: 3, name: "cancel_action", type: "CancelAction" },
1827
+ { id: 8, name: "async_ask_question_completion_action", type: "AsyncAskQuestionCompletionAction" },
1828
+ { id: 19, name: "inject_context_action", type: "InjectContextAction" },
1829
+ ],
1830
+ [{
1831
+ name: "action",
1832
+ fields: [
1833
+ "user_message_action",
1834
+ "resume_action",
1835
+ "cancel_action",
1836
+ "async_ask_question_completion_action",
1837
+ "inject_context_action",
1838
+ ],
1839
+ }],
1840
+ )
1841
+
1842
+ // Seed ConversationStateStructure for turn 1 (system prompt as JSON strings
1843
+ // in #1). After the first conversation_checkpoint_update we echo opaque
1844
+ // server bytes instead — CLI's live structure uses blob-id bytes in #1/#8.
1845
+ addType(root, "AssistantMessage", [
1846
+ { id: 1, name: "text", type: "string" },
1847
+ ])
1848
+
1849
+ addType(
1850
+ root,
1851
+ "ConversationStep",
1852
+ [
1853
+ { id: 1, name: "assistant_message", type: "AssistantMessage" },
1854
+ ],
1855
+ [{ name: "message", fields: ["assistant_message"] }],
1856
+ )
1857
+
1858
+ addType(root, "AgentConversationTurn", [
1859
+ { id: 1, name: "user_message", type: "UserMessage" },
1860
+ { id: 2, name: "steps", type: "ConversationStep", repeated: true },
1861
+ ])
1862
+
1863
+ addType(
1864
+ root,
1865
+ "ConversationTurn",
1866
+ [
1867
+ { id: 1, name: "agent_conversation_turn", type: "AgentConversationTurn" },
1868
+ ],
1869
+ [{ name: "turn", fields: ["agent_conversation_turn"] }],
1870
+ )
1871
+
1872
+ // Cursor checkpoints carry authoritative context occupancy in field #5. The
1873
+ // provider still transports the complete checkpoint as opaque bytes; these
1874
+ // declarations support targeted diagnostics/tests without a re-encode.
1875
+ addType(root, "PromptTokenBreakdownCategory", [
1876
+ { id: 1, name: "id", type: "string" },
1877
+ { id: 2, name: "label", type: "string" },
1878
+ { id: 3, name: "estimated_tokens", type: "uint32" },
1879
+ { id: 4, name: "character_count", type: "uint32" },
1880
+ ])
1881
+ addType(root, "PromptTokenBreakdownSnapshot", [
1882
+ { id: 1, name: "total_used_tokens", type: "uint32" },
1883
+ { id: 2, name: "max_tokens", type: "uint32" },
1884
+ { id: 3, name: "categories", type: "PromptTokenBreakdownCategory", repeated: true },
1885
+ ])
1886
+ addType(root, "ConversationTokenDetails", [
1887
+ { id: 1, name: "used_tokens", type: "uint32" },
1888
+ { id: 2, name: "max_tokens", type: "uint32" },
1889
+ { id: 3, name: "breakdown", type: "PromptTokenBreakdownSnapshot" },
1890
+ ])
1891
+
1892
+ // Seed schema (JSON strings). AgentRunRequest.conversation_state remains
1893
+ // bytes, so live checkpoints are never decoded/re-encoded on transport.
1894
+ addType(root, "ConversationStateStructure", [
1895
+ { id: 1, name: "root_prompt_messages_json", type: "string", repeated: true },
1896
+ { id: 5, name: "token_details", type: "ConversationTokenDetails" },
1897
+ { id: 8, name: "turns", type: "ConversationTurn", repeated: true },
1898
+ ])
1899
+
1900
+ addType(root, "ModelDetails", [
1901
+ { id: 1, name: "model_id", type: "string" },
1902
+ ])
1903
+
1904
+ addType(root, "McpTools", [
1905
+ { id: 1, name: "mcp_tools", type: "McpToolDefinition", repeated: true },
1906
+ ])
1907
+
1908
+ addType(root, "AgentRunRequest", [
1909
+ { id: 1, name: "conversation_state", type: "bytes" },
1910
+ { id: 2, name: "action", type: "ConversationAction" },
1911
+ { id: 4, name: "mcp_tools", type: "McpTools" },
1912
+ { id: 5, name: "conversation_id", type: "string" },
1913
+ { id: 8, name: "custom_system_prompt", type: "string" },
1914
+ { id: 9, name: "requested_model", type: "RequestedModel" },
1915
+ { id: 10, name: "unknown_flag", type: "uint32" },
1916
+ { id: 12, name: "field_12", type: "uint32" },
1917
+ { id: 14, name: "selected_subagent_models", type: "RequestedModel", repeated: true },
1918
+ { id: 16, name: "conversation_group_id", type: "string" },
1919
+ { id: 25, name: "run_id", type: "string" },
1920
+ ])
1921
+
1922
+ // ── Client heartbeat ──
1923
+
1924
+ addType(root, "ClientHeartbeat", [])
1925
+
1926
+ // ── Interaction query/response channel ──
1927
+ // Cursor sends UI/integration requests outside the exec tool channel. Query
1928
+ // bodies stay opaque: this headless provider only needs their id + variant
1929
+ // to return a conservative typed response on the same Run stream.
1930
+ addType(
1931
+ root,
1932
+ "InteractionQuery",
1933
+ [
1934
+ { id: 1, name: "id", type: "uint32" },
1935
+ { id: 2, name: "web_search_request_query", type: "bytes" },
1936
+ { id: 3, name: "ask_question_interaction_query", type: "bytes" },
1937
+ { id: 4, name: "switch_mode_request_query", type: "bytes" },
1938
+ { id: 7, name: "create_plan_request_query", type: "bytes" },
1939
+ { id: 8, name: "setup_vm_environment_args", type: "bytes" },
1940
+ { id: 9, name: "web_fetch_request_query", type: "bytes" },
1941
+ { id: 10, name: "pr_management_request_query", type: "bytes" },
1942
+ { id: 11, name: "mcp_auth_request_query", type: "bytes" },
1943
+ { id: 12, name: "generate_image_request_query", type: "bytes" },
1944
+ { id: 13, name: "replace_env_args", type: "bytes" },
1945
+ { id: 14, name: "connect_scm_request_query", type: "bytes" },
1946
+ ],
1947
+ [{
1948
+ name: "query",
1949
+ fields: [
1950
+ "web_search_request_query", "ask_question_interaction_query",
1951
+ "switch_mode_request_query", "create_plan_request_query",
1952
+ "setup_vm_environment_args", "web_fetch_request_query",
1953
+ "pr_management_request_query", "mcp_auth_request_query",
1954
+ "generate_image_request_query", "replace_env_args",
1955
+ "connect_scm_request_query",
1956
+ ],
1957
+ }],
1958
+ )
1959
+
1960
+ addType(root, "WebSearchRequestApproved", [])
1961
+ addType(root, "WebSearchRequestRejected", [{ id: 1, name: "reason", type: "string" }])
1962
+ addType(root, "WebSearchRequestResponse", [
1963
+ { id: 1, name: "approved", type: "WebSearchRequestApproved" },
1964
+ { id: 2, name: "rejected", type: "WebSearchRequestRejected" },
1965
+ ], [{ name: "result", fields: ["approved", "rejected"] }])
1966
+
1967
+ addType(root, "AskQuestionRejected", [{ id: 1, name: "reason", type: "string" }])
1968
+ addType(root, "AskQuestionError", [{ id: 1, name: "error_message", type: "string" }])
1969
+ addType(root, "AskQuestionAsync", [])
1970
+ addType(root, "AskQuestionSuccessAnswer", [
1971
+ { id: 1, name: "question_id", type: "string" },
1972
+ { id: 2, name: "selected_option_ids", type: "string", repeated: true },
1973
+ { id: 3, name: "freeform_text", type: "string" },
1974
+ ])
1975
+ addType(root, "AskQuestionSuccess", [
1976
+ { id: 1, name: "answers", type: "AskQuestionSuccessAnswer", repeated: true },
1977
+ ])
1978
+ addType(root, "AskQuestionResult", [
1979
+ { id: 1, name: "success", type: "AskQuestionSuccess" },
1980
+ { id: 2, name: "error", type: "AskQuestionError" },
1981
+ { id: 3, name: "rejected", type: "AskQuestionRejected" },
1982
+ { id: 4, name: "async", type: "AskQuestionAsync" },
1983
+ ], [{ name: "result", fields: ["success", "error", "rejected", "async"] }])
1984
+ addType(root, "AskQuestionInteractionResponse", [
1985
+ { id: 1, name: "result", type: "AskQuestionResult" },
1986
+ ])
1987
+ // InteractionQuery keeps query bodies opaque (see the InteractionQuery
1988
+ // comment); this type decodes only the ask-question body on demand.
1989
+ addType(root, "AskQuestionInteractionQuery", [
1990
+ { id: 1, name: "args", type: "AskQuestionArgs" },
1991
+ { id: 2, name: "tool_call_id", type: "string" },
1992
+ ])
1993
+
1994
+ addType(root, "SwitchModeRequestApproved", [])
1995
+ addType(root, "SwitchModeRequestRejected", [{ id: 1, name: "reason", type: "string" }])
1996
+ addType(root, "SwitchModeRequestResponse", [
1997
+ { id: 1, name: "approved", type: "SwitchModeRequestApproved" },
1998
+ { id: 2, name: "rejected", type: "SwitchModeRequestRejected" },
1999
+ ], [{ name: "result", fields: ["approved", "rejected"] }])
2000
+ // InteractionQuery keeps query bodies opaque; decoded on demand like
2001
+ // AskQuestionInteractionQuery / CreatePlanRequestQuery.
2002
+ addType(root, "SwitchModeRequestQuery", [
2003
+ { id: 1, name: "args", type: "SwitchModeToolArgs" },
2004
+ ])
2005
+
2006
+ addType(root, "CreatePlanSuccess", [])
2007
+ addType(root, "CreatePlanError", [{ id: 1, name: "error", type: "string" }])
2008
+ addType(root, "CreatePlanResult", [
2009
+ { id: 1, name: "success", type: "CreatePlanSuccess" },
2010
+ { id: 2, name: "error", type: "CreatePlanError" },
2011
+ { id: 3, name: "plan_uri", type: "string" },
2012
+ ], [{ name: "result", fields: ["success", "error"] }])
2013
+ addType(root, "CreatePlanRequestResponse", [
2014
+ { id: 1, name: "result", type: "CreatePlanResult" },
2015
+ ])
2016
+ // InteractionQuery keeps query bodies opaque; decoded on demand like
2017
+ // AskQuestionInteractionQuery / GenerateImageRequestQuery.
2018
+ addType(root, "CreatePlanRequestQuery", [
2019
+ { id: 1, name: "args", type: "CreatePlanArgs" },
2020
+ { id: 2, name: "tool_call_id", type: "string" },
2021
+ ])
2022
+
2023
+ addType(root, "SetupVmEnvironmentSuccess", [])
2024
+ addType(root, "SetupVmEnvironmentResult", [
2025
+ { id: 1, name: "success", type: "SetupVmEnvironmentSuccess" },
2026
+ ], [{ name: "result", fields: ["success"] }])
2027
+
2028
+ addType(root, "WebFetchRequestApproved", [])
2029
+ addType(root, "WebFetchRequestRejected", [{ id: 1, name: "reason", type: "string" }])
2030
+ addType(root, "WebFetchRequestResponse", [
2031
+ { id: 1, name: "approved", type: "WebFetchRequestApproved" },
2032
+ { id: 2, name: "rejected", type: "WebFetchRequestRejected" },
2033
+ ], [{ name: "result", fields: ["approved", "rejected"] }])
2034
+
2035
+ addType(root, "PrManagementRejected", [{ id: 1, name: "reason", type: "string" }])
2036
+ addType(root, "PrManagementResult", [
2037
+ { id: 3, name: "rejected", type: "PrManagementRejected" },
2038
+ ], [{ name: "result", fields: ["rejected"] }])
2039
+
2040
+ addType(root, "McpAuthRequestApproved", [])
2041
+ addType(root, "McpAuthRequestRejected", [{ id: 1, name: "reason", type: "string" }])
2042
+ addType(root, "McpAuthRequestResponse", [
2043
+ { id: 1, name: "approved", type: "McpAuthRequestApproved" },
2044
+ { id: 2, name: "rejected", type: "McpAuthRequestRejected" },
2045
+ ], [{ name: "result", fields: ["approved", "rejected"] }])
2046
+
2047
+ addType(root, "GenerateImageRequestApproved", [{ id: 1, name: "description", type: "string" }])
2048
+ addType(root, "GenerateImageRequestRejected", [{ id: 1, name: "reason", type: "string" }])
2049
+ addType(root, "GenerateImageRequestResponse", [
2050
+ { id: 1, name: "approved", type: "GenerateImageRequestApproved" },
2051
+ { id: 2, name: "rejected", type: "GenerateImageRequestRejected" },
2052
+ ], [{ name: "result", fields: ["approved", "rejected"] }])
2053
+
2054
+ addType(root, "ReplaceEnvSuccess", [])
2055
+ addType(root, "ReplaceEnvFailure", [
2056
+ { id: 1, name: "error_message", type: "string" },
2057
+ { id: 2, name: "setup_logs", type: "string" },
2058
+ ])
2059
+ addType(root, "ReplaceEnvResult", [
2060
+ { id: 1, name: "success", type: "ReplaceEnvSuccess" },
2061
+ { id: 2, name: "failure", type: "ReplaceEnvFailure" },
2062
+ ], [{ name: "result", fields: ["success", "failure"] }])
2063
+
2064
+ addType(root, "ConnectScmRequestApproved", [])
2065
+ addType(root, "ConnectScmRequestRejected", [{ id: 1, name: "reason", type: "string" }])
2066
+ addType(root, "ConnectScmRequestFailed", [{ id: 1, name: "error", type: "string" }])
2067
+ addType(root, "ConnectScmRequestResponse", [
2068
+ { id: 1, name: "approved", type: "ConnectScmRequestApproved" },
2069
+ { id: 2, name: "rejected", type: "ConnectScmRequestRejected" },
2070
+ { id: 3, name: "failed", type: "ConnectScmRequestFailed" },
2071
+ ], [{ name: "result", fields: ["approved", "rejected", "failed"] }])
2072
+
2073
+ addType(
2074
+ root,
2075
+ "InteractionResponse",
2076
+ [
2077
+ { id: 1, name: "id", type: "uint32" },
2078
+ { id: 2, name: "web_search_request_response", type: "WebSearchRequestResponse" },
2079
+ { id: 3, name: "ask_question_interaction_response", type: "AskQuestionInteractionResponse" },
2080
+ { id: 4, name: "switch_mode_request_response", type: "SwitchModeRequestResponse" },
2081
+ { id: 7, name: "create_plan_request_response", type: "CreatePlanRequestResponse" },
2082
+ { id: 8, name: "setup_vm_environment_result", type: "SetupVmEnvironmentResult" },
2083
+ { id: 9, name: "web_fetch_request_response", type: "WebFetchRequestResponse" },
2084
+ { id: 10, name: "pr_management_result", type: "PrManagementResult" },
2085
+ { id: 11, name: "mcp_auth_request_response", type: "McpAuthRequestResponse" },
2086
+ { id: 12, name: "generate_image_request_response", type: "GenerateImageRequestResponse" },
2087
+ { id: 13, name: "replace_env_result", type: "ReplaceEnvResult" },
2088
+ { id: 14, name: "connect_scm_request_response", type: "ConnectScmRequestResponse" },
2089
+ ],
2090
+ [{
2091
+ name: "result",
2092
+ fields: [
2093
+ "web_search_request_response", "ask_question_interaction_response",
2094
+ "switch_mode_request_response", "create_plan_request_response",
2095
+ "setup_vm_environment_result", "web_fetch_request_response",
2096
+ "pr_management_result", "mcp_auth_request_response",
2097
+ "generate_image_request_response", "replace_env_result",
2098
+ "connect_scm_request_response",
2099
+ ],
2100
+ }],
2101
+ )
2102
+
2103
+ // ── KV blob store (cursor moves large payloads out-of-band via this channel) ──
2104
+ // Server sends KvServerMessage (AgentServerMessage #4); client MUST reply with
2105
+ // KvClientMessage (AgentClientMessage #3) on the same Run stream, echoing `id`.
2106
+ // If we don't ack set_blob / answer get_blob, the server hangs (endless
2107
+ // heartbeats, no response) — this was the "no response" root cause.
2108
+
2109
+ addType(root, "GetBlobArgs", [
2110
+ { id: 1, name: "blob_id", type: "bytes" },
2111
+ ])
2112
+ addType(root, "GetBlobResult", [
2113
+ { id: 1, name: "blob_data", type: "bytes" },
2114
+ ])
2115
+ addType(root, "SetBlobArgs", [
2116
+ { id: 1, name: "blob_id", type: "bytes" },
2117
+ { id: 2, name: "blob_data", type: "bytes" },
2118
+ ])
2119
+ addType(root, "SetBlobResult", [
2120
+ { id: 1, name: "error", type: "string" },
2121
+ ])
2122
+ addType(
2123
+ root,
2124
+ "KvServerMessage",
2125
+ [
2126
+ { id: 1, name: "id", type: "uint32" },
2127
+ { id: 2, name: "get_blob_args", type: "GetBlobArgs" },
2128
+ { id: 3, name: "set_blob_args", type: "SetBlobArgs" },
2129
+ ],
2130
+ [{ name: "message", fields: ["get_blob_args", "set_blob_args"] }],
2131
+ )
2132
+ addType(
2133
+ root,
2134
+ "KvClientMessage",
2135
+ [
2136
+ { id: 1, name: "id", type: "uint32" },
2137
+ { id: 2, name: "get_blob_result", type: "GetBlobResult" },
2138
+ { id: 3, name: "set_blob_result", type: "SetBlobResult" },
2139
+ ],
2140
+ [{ name: "message", fields: ["get_blob_result", "set_blob_result"] }],
2141
+ )
2142
+
2143
+ // ── AgentClientMessage ──
2144
+
2145
+ addType(
2146
+ root,
2147
+ "AgentClientMessage",
2148
+ [
2149
+ { id: 1, name: "run_request", type: "AgentRunRequest" },
2150
+ { id: 2, name: "exec_client_message", type: "ExecClientMessage" },
2151
+ { id: 3, name: "kv_client_message", type: "KvClientMessage" },
2152
+ { id: 4, name: "conversation_action", type: "ConversationAction" },
2153
+ { id: 5, name: "exec_client_control_message", type: "ExecClientControlMessage" },
2154
+ { id: 6, name: "interaction_response", type: "InteractionResponse" },
2155
+ { id: 7, name: "client_heartbeat", type: "ClientHeartbeat" },
2156
+ ],
2157
+ [{
2158
+ name: "message",
2159
+ fields: [
2160
+ "run_request",
2161
+ "exec_client_message",
2162
+ "kv_client_message",
2163
+ "conversation_action",
2164
+ "exec_client_control_message",
2165
+ "interaction_response",
2166
+ "client_heartbeat",
2167
+ ],
2168
+ }],
2169
+ )
2170
+
2171
+ // ── AgentServerMessage ──
2172
+
2173
+ addType(
2174
+ root,
2175
+ "AgentServerMessage",
2176
+ [
2177
+ { id: 1, name: "interaction_update", type: "InteractionUpdate" },
2178
+ { id: 2, name: "exec_server_message", type: "ExecServerMessage" },
2179
+ { id: 3, name: "conversation_checkpoint_update", type: "bytes" },
2180
+ { id: 4, name: "kv_server_message", type: "KvServerMessage" },
2181
+ { id: 5, name: "exec_server_control_message", type: "ExecServerControlMessage" },
2182
+ { id: 7, name: "interaction_query", type: "InteractionQuery" },
2183
+ ],
2184
+ [{ name: "message", fields: ["interaction_update", "exec_server_message", "conversation_checkpoint_update", "kv_server_message", "exec_server_control_message", "interaction_query"] }],
2185
+ )
2186
+
2187
+ // ── AvailableModels types ──
2188
+
2189
+ addType(root, "AvailableModelsRequest", [])
2190
+
2191
+ addType(root, "AvailableModelParameterDefinition", [
2192
+ { id: 1, name: "id", type: "string" },
2193
+ { id: 2, name: "values", type: "string", repeated: true },
2194
+ ])
2195
+
2196
+ addType(root, "AvailableModelParameterValue", [
2197
+ { id: 1, name: "id", type: "string" },
2198
+ { id: 2, name: "value", type: "string" },
2199
+ ])
2200
+
2201
+ addType(root, "AvailableModelVariant", [
2202
+ { id: 1, name: "parameter_values", type: "AvailableModelParameterValue", repeated: true },
2203
+ { id: 2, name: "display_name", type: "string" },
2204
+ { id: 3, name: "is_max_mode", type: "bool" },
2205
+ { id: 4, name: "is_default_max_config", type: "bool" },
2206
+ { id: 5, name: "is_default_non_max_config", type: "bool" },
2207
+ ])
2208
+
2209
+ addType(root, "AvailableModelEntry", [
2210
+ { id: 1, name: "name", type: "string" },
2211
+ { id: 2, name: "default_on", type: "bool" },
2212
+ { id: 5, name: "supports_agent", type: "bool" },
2213
+ { id: 9, name: "supports_thinking", type: "bool" },
2214
+ { id: 10, name: "supports_images", type: "bool" },
2215
+ { id: 14, name: "supports_max_mode", type: "bool" },
2216
+ { id: 15, name: "context_token_limit", type: "int32" },
2217
+ { id: 16, name: "context_token_limit_for_max_mode", type: "int32" },
2218
+ { id: 17, name: "client_display_name", type: "string" },
2219
+ { id: 18, name: "server_model_name", type: "string" },
2220
+ { id: 29, name: "parameter_definitions", type: "AvailableModelParameterDefinition", repeated: true },
2221
+ { id: 30, name: "variants", type: "AvailableModelVariant", repeated: true },
2222
+ ])
2223
+
2224
+ addType(root, "AvailableModelsResponse", [
2225
+ { id: 1, name: "model_names", type: "string", repeated: true },
2226
+ { id: 2, name: "models", type: "AvailableModelEntry", repeated: true },
2227
+ ])
2228
+
2229
+ return root
2230
+ }
2231
+
2232
+ // ── Singleton root ──
2233
+
2234
+ let _root: protobuf.Root | null = null
2235
+
2236
+ export function getMessageTypes(): protobuf.Root {
2237
+ if (!_root) {
2238
+ _root = createMessageTypes()
2239
+ }
2240
+ return _root
2241
+ }
2242
+
2243
+ export function encodeMessage(typeName: string, message: Record<string, unknown>): Uint8Array {
2244
+ const root = getMessageTypes()
2245
+ const type = root.lookupType(typeName)
2246
+ const err = type.verify(message)
2247
+ if (err) throw new Error(`Invalid message for ${typeName}: ${err}`)
2248
+ return type.encode(type.fromObject(message)).finish()
2249
+ }
2250
+
2251
+ export function decodeMessage<T = Record<string, unknown>>(
2252
+ typeName: string,
2253
+ data: Uint8Array,
2254
+ ): T {
2255
+ const root = getMessageTypes()
2256
+ const type = root.lookupType(typeName)
2257
+ const decoded = type.decode(data)
2258
+ return type.toObject(decoded, { defaults: true, json: true, longs: Number }) as T
2259
+ }
2260
+
2261
+ /** Decode without inventing absent proto defaults (used for byte-stable snapshots). */
2262
+ export function decodeMessageSparse<T = Record<string, unknown>>(
2263
+ typeName: string,
2264
+ data: Uint8Array,
2265
+ ): T {
2266
+ const root = getMessageTypes()
2267
+ const type = root.lookupType(typeName)
2268
+ const decoded = type.decode(data)
2269
+ return type.toObject(decoded, { json: true, longs: Number }) as T
2270
+ }
2271
+
2272
+ type RawField = {
2273
+ field: number
2274
+ wireType: number
2275
+ varint?: string
2276
+ fixed?: number | string
2277
+ bytes?: Uint8Array
2278
+ }
2279
+
2280
+ /** Schema-free walk of one message's top-level wire fields (no nested descent). */
2281
+ function readRawFields(buf: Uint8Array): RawField[] {
2282
+ const reader = protobuf.Reader.create(buf)
2283
+ const fields: RawField[] = []
2284
+ while (reader.pos < reader.len) {
2285
+ const tag = reader.uint32()
2286
+ const field = tag >>> 3
2287
+ const wireType = tag & 7
2288
+ switch (wireType) {
2289
+ case 0:
2290
+ fields.push({ field, wireType, varint: reader.uint64().toString() })
2291
+ break
2292
+ case 1:
2293
+ fields.push({ field, wireType, fixed: reader.fixed64().toString() })
2294
+ break
2295
+ case 2:
2296
+ fields.push({ field, wireType, bytes: reader.bytes() })
2297
+ break
2298
+ case 5:
2299
+ fields.push({ field, wireType, fixed: reader.fixed32() })
2300
+ break
2301
+ default:
2302
+ // Groups (3/4) aren't used on this wire; bail rather than desync the reader.
2303
+ return fields
2304
+ }
2305
+ }
2306
+ return fields
2307
+ }
2308
+
2309
+ /**
2310
+ * Diagnostic-only: walk AgentServerMessage.interaction_update(1).turn_ended(14)
2311
+ * without going through our hand-written TurnEnded schema, so a `cache_write`/
2312
+ * `reasoning_tokens` question can be checked against the raw wire instead of
2313
+ * guessed. Confirmed field ids 1-5 (input/output/cache_read/cache_write/
2314
+ * reasoning) decode correctly. Live captures routinely include `f4` explicitly
2315
+ * as `0` while `f3` (cache_read) and `f5` (reasoning) are non-zero — Cursor's
2316
+ * agent TurnEnded populates the field but does not report write counts here.
2317
+ */
2318
+ export function debugWalkTurnEnded(payload: Uint8Array): string {
2319
+ try {
2320
+ const top = readRawFields(payload)
2321
+ const iuField = top.find((f) => f.field === 1 && f.wireType === 2)
2322
+ if (!iuField?.bytes) return "(no interaction_update field)"
2323
+ const iu = readRawFields(iuField.bytes)
2324
+ const teField = iu.find((f) => f.field === 14 && f.wireType === 2)
2325
+ if (!teField?.bytes) return "(no turn_ended field in interaction_update)"
2326
+ const te = readRawFields(teField.bytes)
2327
+ return te
2328
+ .map(
2329
+ (f) =>
2330
+ `f${f.field}:wt${f.wireType}=${f.varint ?? f.fixed ?? (f.bytes ? `bytes[${f.bytes.length}]` : "?")}`,
2331
+ )
2332
+ .join(" ")
2333
+ } catch (e) {
2334
+ return `(walk failed: ${(e as Error).message})`
2335
+ }
2336
+ }
2337
+
2338
+ /**
2339
+ * Decode a protobuf sub-message from a frame payload that wraps it in
2340
+ * a top-level field key + length varint. Skips the outer wrapper and
2341
+ * decodes the inner body as `typeName`.
2342
+ */
2343
+ export function decodeWrappedMessage<T = Record<string, unknown>>(
2344
+ typeName: string,
2345
+ data: Uint8Array,
2346
+ ): T {
2347
+ let offset = 1 // skip field key
2348
+ // skip varint length
2349
+ while (offset < data.length) {
2350
+ const b = data[offset] ?? 0
2351
+ offset++
2352
+ if (!(b & 0x80)) break
2353
+ }
2354
+ return decodeMessage<T>(typeName, data.subarray(offset))
2355
+ }