@iislee/opencodex 2.11.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 (476) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +225 -0
  3. package/assets/architecture.png +0 -0
  4. package/assets/banner.png +0 -0
  5. package/assets/claude-code-models.gif +0 -0
  6. package/assets/codex-app-picker.png +0 -0
  7. package/bin/ocx.mjs +451 -0
  8. package/bin/package-main.mjs +9 -0
  9. package/gui/dist/assets/index-DTpMHS4F.js +67 -0
  10. package/gui/dist/assets/index-ZNVDE3C7.css +1 -0
  11. package/gui/dist/favicon.png +0 -0
  12. package/gui/dist/icons.svg +24 -0
  13. package/gui/dist/index.html +25 -0
  14. package/gui/dist/logo.png +0 -0
  15. package/gui/dist/provider-icons/alibaba-color.svg +1 -0
  16. package/gui/dist/provider-icons/antigravity-color.svg +1 -0
  17. package/gui/dist/provider-icons/antigravity.svg +1 -0
  18. package/gui/dist/provider-icons/claude-color.svg +1 -0
  19. package/gui/dist/provider-icons/claude.svg +1 -0
  20. package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -0
  21. package/gui/dist/provider-icons/copilot-color.svg +1 -0
  22. package/gui/dist/provider-icons/copilot.svg +1 -0
  23. package/gui/dist/provider-icons/cursor-color.svg +2 -0
  24. package/gui/dist/provider-icons/cursor.svg +2 -0
  25. package/gui/dist/provider-icons/deepseek-color.svg +1 -0
  26. package/gui/dist/provider-icons/discord.svg +1 -0
  27. package/gui/dist/provider-icons/firepass-color.svg +1 -0
  28. package/gui/dist/provider-icons/fireworks-color.svg +1 -0
  29. package/gui/dist/provider-icons/gemini-color.svg +1 -0
  30. package/gui/dist/provider-icons/gemini.svg +1 -0
  31. package/gui/dist/provider-icons/github-copilot-color.svg +1 -0
  32. package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -0
  33. package/gui/dist/provider-icons/grok-color.svg +1 -0
  34. package/gui/dist/provider-icons/grok.svg +1 -0
  35. package/gui/dist/provider-icons/groq-color.svg +1 -0
  36. package/gui/dist/provider-icons/huggingface-color.svg +1 -0
  37. package/gui/dist/provider-icons/kimi-color.svg +1 -0
  38. package/gui/dist/provider-icons/kiro-color.svg +15 -0
  39. package/gui/dist/provider-icons/kiro.svg +14 -0
  40. package/gui/dist/provider-icons/lm-studio-color.svg +1 -0
  41. package/gui/dist/provider-icons/mistral-color.svg +1 -0
  42. package/gui/dist/provider-icons/moonshot-color.svg +1 -0
  43. package/gui/dist/provider-icons/nvidia-color.svg +1 -0
  44. package/gui/dist/provider-icons/ollama-color.svg +1 -0
  45. package/gui/dist/provider-icons/openai.svg +1 -0
  46. package/gui/dist/provider-icons/opencode.svg +1 -0
  47. package/gui/dist/provider-icons/openrouter-color.svg +1 -0
  48. package/gui/dist/provider-icons/pi.svg +21 -0
  49. package/gui/dist/provider-icons/qianfan-color.svg +1 -0
  50. package/gui/dist/provider-icons/qwen-portal-color.svg +1 -0
  51. package/gui/dist/provider-icons/telegram.svg +1 -0
  52. package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -0
  53. package/gui/dist/provider-icons/vllm-color.svg +1 -0
  54. package/gui/dist/provider-icons/xiaomi-color.svg +1 -0
  55. package/package.json +102 -0
  56. package/src/AGENTS.md +28 -0
  57. package/src/adapters/anthropic-image-guard.ts +251 -0
  58. package/src/adapters/anthropic-image-normalize.ts +518 -0
  59. package/src/adapters/anthropic.ts +1003 -0
  60. package/src/adapters/azure.ts +36 -0
  61. package/src/adapters/base.ts +72 -0
  62. package/src/adapters/client-fingerprint.ts +59 -0
  63. package/src/adapters/cursor/arg-codec.ts +38 -0
  64. package/src/adapters/cursor/arg-normalize.ts +104 -0
  65. package/src/adapters/cursor/cursor-errors.ts +165 -0
  66. package/src/adapters/cursor/discovery.ts +276 -0
  67. package/src/adapters/cursor/effort-map.ts +127 -0
  68. package/src/adapters/cursor/exec-policy.ts +88 -0
  69. package/src/adapters/cursor/framing.ts +211 -0
  70. package/src/adapters/cursor/gen/agent_pb.ts +15274 -0
  71. package/src/adapters/cursor/kv-store.ts +52 -0
  72. package/src/adapters/cursor/live-models.ts +153 -0
  73. package/src/adapters/cursor/live-smoke-gate.ts +41 -0
  74. package/src/adapters/cursor/live-transport.ts +1214 -0
  75. package/src/adapters/cursor/mcp-config.ts +42 -0
  76. package/src/adapters/cursor/mcp-manager.ts +333 -0
  77. package/src/adapters/cursor/message-mapper.ts +49 -0
  78. package/src/adapters/cursor/native-exec-common.ts +55 -0
  79. package/src/adapters/cursor/native-exec-desktop.ts +184 -0
  80. package/src/adapters/cursor/native-exec-fs.ts +329 -0
  81. package/src/adapters/cursor/native-exec-mcp.ts +153 -0
  82. package/src/adapters/cursor/native-exec-network.ts +43 -0
  83. package/src/adapters/cursor/native-exec-shell.ts +548 -0
  84. package/src/adapters/cursor/native-exec-tools.ts +118 -0
  85. package/src/adapters/cursor/native-exec.ts +576 -0
  86. package/src/adapters/cursor/protobuf-events.ts +563 -0
  87. package/src/adapters/cursor/protobuf-request.ts +714 -0
  88. package/src/adapters/cursor/request-builder.ts +255 -0
  89. package/src/adapters/cursor/thread-continuity.ts +67 -0
  90. package/src/adapters/cursor/tool-definitions.ts +505 -0
  91. package/src/adapters/cursor/transport-retry.ts +132 -0
  92. package/src/adapters/cursor/transport.ts +57 -0
  93. package/src/adapters/cursor/types.ts +52 -0
  94. package/src/adapters/cursor.ts +196 -0
  95. package/src/adapters/google-antigravity-replay.ts +303 -0
  96. package/src/adapters/google-antigravity-wire.ts +108 -0
  97. package/src/adapters/google-errors.ts +85 -0
  98. package/src/adapters/google-http.ts +100 -0
  99. package/src/adapters/google-tool-schema.ts +173 -0
  100. package/src/adapters/google-truncation.ts +13 -0
  101. package/src/adapters/google-wire-compiler.ts +232 -0
  102. package/src/adapters/google.ts +758 -0
  103. package/src/adapters/identity.ts +44 -0
  104. package/src/adapters/image.ts +23 -0
  105. package/src/adapters/kiro-constants.ts +16 -0
  106. package/src/adapters/kiro-errors.ts +197 -0
  107. package/src/adapters/kiro-events.ts +179 -0
  108. package/src/adapters/kiro-images.ts +129 -0
  109. package/src/adapters/kiro-retry.ts +312 -0
  110. package/src/adapters/kiro-thinking.ts +96 -0
  111. package/src/adapters/kiro-tool-fallback.ts +36 -0
  112. package/src/adapters/kiro-tools.ts +215 -0
  113. package/src/adapters/kiro-truncation.ts +33 -0
  114. package/src/adapters/kiro-wire.ts +129 -0
  115. package/src/adapters/kiro.ts +1898 -0
  116. package/src/adapters/mimo-free.ts +263 -0
  117. package/src/adapters/openai-chat.ts +1005 -0
  118. package/src/adapters/openai-responses.ts +1137 -0
  119. package/src/adapters/run-turn-queue.ts +114 -0
  120. package/src/adapters/tool-catalog-nudge.ts +71 -0
  121. package/src/adapters/upstream-http-error.ts +48 -0
  122. package/src/bridge.ts +1619 -0
  123. package/src/chat/inbound.ts +295 -0
  124. package/src/chat/outbound.ts +765 -0
  125. package/src/claude/agents-inject.ts +243 -0
  126. package/src/claude/alias.ts +149 -0
  127. package/src/claude/auth-detect.ts +229 -0
  128. package/src/claude/auth-mode-migration.ts +32 -0
  129. package/src/claude/auth-mode.ts +62 -0
  130. package/src/claude/context-windows.ts +189 -0
  131. package/src/claude/desktop-3p-guard.ts +35 -0
  132. package/src/claude/desktop-3p-paths.ts +84 -0
  133. package/src/claude/desktop-3p.ts +381 -0
  134. package/src/claude/desktop-health.ts +26 -0
  135. package/src/claude/desktop-profile.ts +263 -0
  136. package/src/claude/gateway-cache.ts +70 -0
  137. package/src/claude/inbound-debug.ts +163 -0
  138. package/src/claude/inbound.ts +509 -0
  139. package/src/claude/model-info.ts +151 -0
  140. package/src/claude/outbound.ts +872 -0
  141. package/src/cli/access.ts +108 -0
  142. package/src/cli/account-api.ts +268 -0
  143. package/src/cli/account-auth.ts +223 -0
  144. package/src/cli/account-extended.ts +350 -0
  145. package/src/cli/account.ts +275 -0
  146. package/src/cli/agent-driven.ts +70 -0
  147. package/src/cli/agent.ts +184 -0
  148. package/src/cli/catalog-prewarm.ts +27 -0
  149. package/src/cli/claude-desktop.ts +188 -0
  150. package/src/cli/claude.ts +286 -0
  151. package/src/cli/codex-shim-autorestore.ts +45 -0
  152. package/src/cli/combo.ts +119 -0
  153. package/src/cli/config-command.ts +145 -0
  154. package/src/cli/debug.ts +228 -0
  155. package/src/cli/doctor.ts +930 -0
  156. package/src/cli/export-command.ts +187 -0
  157. package/src/cli/help.ts +354 -0
  158. package/src/cli/index.ts +1113 -0
  159. package/src/cli/init.ts +224 -0
  160. package/src/cli/integrations.ts +142 -0
  161. package/src/cli/interactive-confirm.ts +133 -0
  162. package/src/cli/internal-dispatch.ts +20 -0
  163. package/src/cli/models-runtime.ts +212 -0
  164. package/src/cli/models.ts +336 -0
  165. package/src/cli/observe.ts +117 -0
  166. package/src/cli/opencode.ts +586 -0
  167. package/src/cli/pi.ts +188 -0
  168. package/src/cli/provider-runtime.ts +162 -0
  169. package/src/cli/provider.ts +463 -0
  170. package/src/cli/runtime-api.ts +325 -0
  171. package/src/cli/star-prompt.ts +155 -0
  172. package/src/cli/status-oauth.ts +78 -0
  173. package/src/cli/status.ts +321 -0
  174. package/src/cli/sync-cloud.ts +283 -0
  175. package/src/cli/system-command.ts +112 -0
  176. package/src/cli/tray-proxy.ts +52 -0
  177. package/src/cli/v2.ts +173 -0
  178. package/src/cli.ts +10 -0
  179. package/src/clients/config-export.ts +377 -0
  180. package/src/clients/effective-status.ts +385 -0
  181. package/src/clients/probes/agy.ts +55 -0
  182. package/src/clients/probes/cc-switch.ts +110 -0
  183. package/src/clients/probes/claude.ts +90 -0
  184. package/src/clients/probes/codex.ts +125 -0
  185. package/src/clients/probes/grok.ts +29 -0
  186. package/src/clients/probes/opencode.ts +109 -0
  187. package/src/clients/probes/paseo.ts +55 -0
  188. package/src/clients/probes/pi.ts +55 -0
  189. package/src/cloud/onedrive-auth.ts +666 -0
  190. package/src/cloud/onedrive-graph.ts +108 -0
  191. package/src/cloud/settings.ts +75 -0
  192. package/src/cloud/sync.ts +212 -0
  193. package/src/cloud/types.ts +56 -0
  194. package/src/cloud/vault.ts +89 -0
  195. package/src/codex/account-id.ts +34 -0
  196. package/src/codex/account-label.ts +34 -0
  197. package/src/codex/account-lifecycle.ts +55 -0
  198. package/src/codex/account-namespace-match.ts +63 -0
  199. package/src/codex/account-namespaces.ts +149 -0
  200. package/src/codex/account-pause.ts +20 -0
  201. package/src/codex/account-runtime-state.ts +31 -0
  202. package/src/codex/account-store.ts +517 -0
  203. package/src/codex/account-usability.ts +20 -0
  204. package/src/codex/app-server-processes.ts +756 -0
  205. package/src/codex/auth-api.ts +1540 -0
  206. package/src/codex/auth-collision.ts +107 -0
  207. package/src/codex/auth-context.ts +352 -0
  208. package/src/codex/autostart-health.ts +149 -0
  209. package/src/codex/catalog/aggregation.ts +378 -0
  210. package/src/codex/catalog/bundled.ts +251 -0
  211. package/src/codex/catalog/effort.ts +355 -0
  212. package/src/codex/catalog/metadata.ts +180 -0
  213. package/src/codex/catalog/parsing.ts +456 -0
  214. package/src/codex/catalog/provider-fetch.ts +902 -0
  215. package/src/codex/catalog/sync.ts +620 -0
  216. package/src/codex/catalog.ts +12 -0
  217. package/src/codex/data/upstream-models.json +830 -0
  218. package/src/codex/exec-invocation.ts +22 -0
  219. package/src/codex/features.ts +969 -0
  220. package/src/codex/history-migration-guardian.ts +102 -0
  221. package/src/codex/history-provider.ts +776 -0
  222. package/src/codex/home.ts +206 -0
  223. package/src/codex/inject.ts +799 -0
  224. package/src/codex/injected-marker.ts +72 -0
  225. package/src/codex/journal.ts +163 -0
  226. package/src/codex/main-account-cache.ts +32 -0
  227. package/src/codex/main-account.ts +40 -0
  228. package/src/codex/model-cache.ts +227 -0
  229. package/src/codex/paths.ts +65 -0
  230. package/src/codex/plugins-doctor.ts +242 -0
  231. package/src/codex/pool-rotation.ts +225 -0
  232. package/src/codex/project-config-warnings.ts +411 -0
  233. package/src/codex/quota.ts +411 -0
  234. package/src/codex/refresh.ts +53 -0
  235. package/src/codex/routing.ts +1477 -0
  236. package/src/codex/runtime.ts +538 -0
  237. package/src/codex/shim.ts +1189 -0
  238. package/src/codex/subagent-defaults.ts +550 -0
  239. package/src/codex/subagent-model-fallback.ts +469 -0
  240. package/src/codex/sync.ts +130 -0
  241. package/src/codex/warmup.ts +192 -0
  242. package/src/codex/websocket-registry.ts +100 -0
  243. package/src/combos/failover.ts +140 -0
  244. package/src/combos/index.ts +41 -0
  245. package/src/combos/request.ts +62 -0
  246. package/src/combos/resolve.ts +232 -0
  247. package/src/combos/types.ts +326 -0
  248. package/src/config.ts +2356 -0
  249. package/src/generated/jawcode-model-metadata.ts +104 -0
  250. package/src/github/star-state.ts +203 -0
  251. package/src/grok/inject.ts +545 -0
  252. package/src/grok/status.ts +121 -0
  253. package/src/grok/sync.ts +103 -0
  254. package/src/grok/usage-hook/report.mjs +348 -0
  255. package/src/grok/usage-hook.ts +278 -0
  256. package/src/images/artifacts.ts +516 -0
  257. package/src/images/fulfill-video.ts +163 -0
  258. package/src/images/fulfill.ts +149 -0
  259. package/src/images/index.ts +4 -0
  260. package/src/images/loop.ts +829 -0
  261. package/src/images/plan.ts +133 -0
  262. package/src/images/synthetic-tool.ts +133 -0
  263. package/src/images/types.ts +41 -0
  264. package/src/images/xai-client.ts +141 -0
  265. package/src/images/xai-video-client.ts +163 -0
  266. package/src/index.ts +22 -0
  267. package/src/lib/abort.ts +146 -0
  268. package/src/lib/admin-secrets.ts +25 -0
  269. package/src/lib/admission.ts +83 -0
  270. package/src/lib/app-owned-memory-stores.ts +173 -0
  271. package/src/lib/app-owned-memory.ts +265 -0
  272. package/src/lib/bounded-body.ts +202 -0
  273. package/src/lib/bun-binary-validator.d.mts +3 -0
  274. package/src/lib/bun-binary-validator.mjs +18 -0
  275. package/src/lib/bun-runtime.ts +71 -0
  276. package/src/lib/bun-stream-caps.ts +126 -0
  277. package/src/lib/config-ownership.ts +360 -0
  278. package/src/lib/crash-guard.ts +344 -0
  279. package/src/lib/debug-log-buffer.ts +83 -0
  280. package/src/lib/debug-settings.ts +108 -0
  281. package/src/lib/debug.ts +31 -0
  282. package/src/lib/destination-policy.ts +316 -0
  283. package/src/lib/errors.ts +364 -0
  284. package/src/lib/eventstream-decoder.ts +253 -0
  285. package/src/lib/gcp-adc.ts +341 -0
  286. package/src/lib/injection-debug-log.ts +58 -0
  287. package/src/lib/open-url.ts +25 -0
  288. package/src/lib/pinned-http.ts +151 -0
  289. package/src/lib/privacy.ts +20 -0
  290. package/src/lib/process-control.ts +165 -0
  291. package/src/lib/provider-outbound.ts +170 -0
  292. package/src/lib/provider-url.ts +14 -0
  293. package/src/lib/proxy-env.ts +18 -0
  294. package/src/lib/redact.ts +105 -0
  295. package/src/lib/retry-after.ts +55 -0
  296. package/src/lib/service-secrets.ts +25 -0
  297. package/src/lib/shadow-call.ts +30 -0
  298. package/src/lib/sidecar-tracker.ts +52 -0
  299. package/src/lib/sse-decoder.ts +323 -0
  300. package/src/lib/state-store-registrations.ts +109 -0
  301. package/src/lib/state-store-sweeper.ts +184 -0
  302. package/src/lib/test-home-guard.ts +90 -0
  303. package/src/lib/token-estimate.ts +69 -0
  304. package/src/lib/translator-budget.ts +356 -0
  305. package/src/lib/upstream-retry.ts +239 -0
  306. package/src/lib/win-exec.ts +115 -0
  307. package/src/lib/win-paths.ts +68 -0
  308. package/src/lib/windows-elevation.ts +705 -0
  309. package/src/lib/windows-secret-acl.ts +514 -0
  310. package/src/lib/winsw.ts +375 -0
  311. package/src/oauth/anthropic-routing.ts +594 -0
  312. package/src/oauth/anthropic.ts +177 -0
  313. package/src/oauth/callback-server.ts +294 -0
  314. package/src/oauth/chatgpt.ts +150 -0
  315. package/src/oauth/cursor.ts +211 -0
  316. package/src/oauth/github-copilot.ts +428 -0
  317. package/src/oauth/google-antigravity.ts +230 -0
  318. package/src/oauth/health.ts +399 -0
  319. package/src/oauth/index.ts +1174 -0
  320. package/src/oauth/key-providers.ts +108 -0
  321. package/src/oauth/kimi.ts +213 -0
  322. package/src/oauth/kiro-credentials.ts +726 -0
  323. package/src/oauth/kiro.ts +577 -0
  324. package/src/oauth/local-token-detect.ts +121 -0
  325. package/src/oauth/log.ts +48 -0
  326. package/src/oauth/login-cli.ts +163 -0
  327. package/src/oauth/pkce.ts +15 -0
  328. package/src/oauth/store.ts +630 -0
  329. package/src/oauth/token-guardian.ts +303 -0
  330. package/src/oauth/types.ts +62 -0
  331. package/src/oauth/xai.ts +241 -0
  332. package/src/pi/extensions.ts +72 -0
  333. package/src/pi/home.ts +42 -0
  334. package/src/pi/index.ts +40 -0
  335. package/src/pi/models.ts +278 -0
  336. package/src/pi/packages.ts +219 -0
  337. package/src/pi/settings.ts +365 -0
  338. package/src/pi/status.ts +68 -0
  339. package/src/pi/sync.ts +75 -0
  340. package/src/providers/alibaba-region-backup.ts +75 -0
  341. package/src/providers/alibaba-region-migration.ts +156 -0
  342. package/src/providers/alibaba-region-startup.ts +36 -0
  343. package/src/providers/antigravity-models.ts +205 -0
  344. package/src/providers/api-keys.ts +140 -0
  345. package/src/providers/base-url-choices.ts +64 -0
  346. package/src/providers/context-cap.ts +65 -0
  347. package/src/providers/derive.ts +339 -0
  348. package/src/providers/free-directory.ts +184 -0
  349. package/src/providers/github-copilot-transport.ts +56 -0
  350. package/src/providers/key-failover.ts +203 -0
  351. package/src/providers/kiro-models.ts +67 -0
  352. package/src/providers/label.ts +19 -0
  353. package/src/providers/model-discovery.ts +356 -0
  354. package/src/providers/openai-sidecar.ts +175 -0
  355. package/src/providers/openai-tier-startup.ts +27 -0
  356. package/src/providers/openai-tiers.ts +301 -0
  357. package/src/providers/openai-virtual-models.ts +82 -0
  358. package/src/providers/openrouter-routing.ts +102 -0
  359. package/src/providers/provider-id-rewrite.ts +150 -0
  360. package/src/providers/quota.ts +1260 -0
  361. package/src/providers/registry.ts +1600 -0
  362. package/src/providers/slug-codec.ts +67 -0
  363. package/src/providers/xai-transport.ts +141 -0
  364. package/src/reasoning-effort.ts +135 -0
  365. package/src/responses/compaction.ts +117 -0
  366. package/src/responses/parser.ts +656 -0
  367. package/src/responses/reasoning-envelope.ts +52 -0
  368. package/src/responses/schema.ts +159 -0
  369. package/src/responses/spill-store.ts +394 -0
  370. package/src/responses/state.ts +895 -0
  371. package/src/responses/tool-groups.ts +19 -0
  372. package/src/router.ts +425 -0
  373. package/src/server/adapter-resolve.ts +80 -0
  374. package/src/server/auth-cors.ts +530 -0
  375. package/src/server/chat-completions.ts +368 -0
  376. package/src/server/claude-messages.ts +914 -0
  377. package/src/server/effort-policy.ts +172 -0
  378. package/src/server/gui-static.ts +123 -0
  379. package/src/server/image-retry.ts +42 -0
  380. package/src/server/images.ts +476 -0
  381. package/src/server/index.ts +1126 -0
  382. package/src/server/lifecycle.ts +227 -0
  383. package/src/server/live.ts +598 -0
  384. package/src/server/management/agent-settings-routes.ts +1169 -0
  385. package/src/server/management/api-access.ts +141 -0
  386. package/src/server/management/api-key-usage.ts +167 -0
  387. package/src/server/management/body.ts +35 -0
  388. package/src/server/management/clients-routes.ts +63 -0
  389. package/src/server/management/cloud-sync-routes.ts +266 -0
  390. package/src/server/management/combo-routes.ts +220 -0
  391. package/src/server/management/config-routes.ts +422 -0
  392. package/src/server/management/context.ts +31 -0
  393. package/src/server/management/logs-usage-routes.ts +707 -0
  394. package/src/server/management/model-routes.ts +525 -0
  395. package/src/server/management/oauth-account-routes.ts +563 -0
  396. package/src/server/management/provider-routes.ts +556 -0
  397. package/src/server/management/shared.ts +277 -0
  398. package/src/server/management/sidebar-routes.ts +90 -0
  399. package/src/server/management/system-restart.ts +179 -0
  400. package/src/server/management/system-routes.ts +117 -0
  401. package/src/server/management/usage-summary-cache.ts +86 -0
  402. package/src/server/management-api.ts +215 -0
  403. package/src/server/management-auth.ts +267 -0
  404. package/src/server/memory-watchdog.ts +156 -0
  405. package/src/server/port-reclaim.ts +307 -0
  406. package/src/server/ports.ts +116 -0
  407. package/src/server/proxy-liveness.ts +201 -0
  408. package/src/server/relay-eager.ts +313 -0
  409. package/src/server/relay.ts +1049 -0
  410. package/src/server/request-decompress.ts +132 -0
  411. package/src/server/request-log-conversation.ts +168 -0
  412. package/src/server/request-log.ts +1046 -0
  413. package/src/server/responses/collaboration.ts +354 -0
  414. package/src/server/responses/compact.ts +384 -0
  415. package/src/server/responses/core.ts +2758 -0
  416. package/src/server/responses/encrypted-payload.ts +308 -0
  417. package/src/server/responses/fetch-helpers.ts +157 -0
  418. package/src/server/responses/passthrough-error.ts +78 -0
  419. package/src/server/responses/terminal-guard.ts +230 -0
  420. package/src/server/responses/upstream-error.ts +48 -0
  421. package/src/server/responses-image-gen-repair.ts +132 -0
  422. package/src/server/responses-item-id-repair.ts +224 -0
  423. package/src/server/responses.ts +9 -0
  424. package/src/server/search.ts +136 -0
  425. package/src/server/sse-payload-rewrite.ts +175 -0
  426. package/src/server/startup-action-control.ts +308 -0
  427. package/src/server/startup-health-cache.ts +113 -0
  428. package/src/server/system-env.ts +413 -0
  429. package/src/server/windows-tcp-drop.ts +184 -0
  430. package/src/server/windows-tray-control.ts +41 -0
  431. package/src/server/ws-bridge.ts +471 -0
  432. package/src/service.ts +2554 -0
  433. package/src/stall-timeout.ts +20 -0
  434. package/src/storage/cleanup-job.ts +57 -0
  435. package/src/storage/cleanup.ts +3085 -0
  436. package/src/storage/policy-job.ts +457 -0
  437. package/src/storage/policy-scheduler.ts +40 -0
  438. package/src/storage/policy-worker.ts +59 -0
  439. package/src/storage/policy.ts +527 -0
  440. package/src/storage/restore-job.ts +299 -0
  441. package/src/storage/restore-worker.ts +58 -0
  442. package/src/storage/scanner.ts +238 -0
  443. package/src/storage/storage-mutation-coordinator.ts +139 -0
  444. package/src/storage/worker-lifecycle.ts +215 -0
  445. package/src/tray/assets/opencodex-tray-offline.ico +0 -0
  446. package/src/tray/assets/opencodex-tray-online.ico +0 -0
  447. package/src/tray/assets/opencodex-tray-warning.ico +0 -0
  448. package/src/tray/assets/opencodex-tray.png +0 -0
  449. package/src/tray/windows-tray.ps1 +290 -0
  450. package/src/tray/windows.ts +730 -0
  451. package/src/types.ts +1237 -0
  452. package/src/update/badge.ts +72 -0
  453. package/src/update/index.ts +407 -0
  454. package/src/update/job.ts +1520 -0
  455. package/src/update/notify.ts +257 -0
  456. package/src/update/npm-invocation.d.mts +23 -0
  457. package/src/update/npm-invocation.mjs +94 -0
  458. package/src/update/tray-update-plan.d.mts +18 -0
  459. package/src/update/tray-update-plan.mjs +38 -0
  460. package/src/usage/cost.ts +0 -0
  461. package/src/usage/debug.ts +97 -0
  462. package/src/usage/expected-prices.ts +164 -0
  463. package/src/usage/log.ts +658 -0
  464. package/src/usage/summary.ts +585 -0
  465. package/src/usage/totals.ts +14 -0
  466. package/src/vision/anthropic-describe.ts +185 -0
  467. package/src/vision/describe.ts +125 -0
  468. package/src/vision/index.ts +467 -0
  469. package/src/web-search/anthropic-executor.ts +189 -0
  470. package/src/web-search/executor.ts +105 -0
  471. package/src/web-search/format-result.ts +89 -0
  472. package/src/web-search/index.ts +196 -0
  473. package/src/web-search/loop.ts +664 -0
  474. package/src/web-search/parse.ts +220 -0
  475. package/src/web-search/progress-stream.ts +342 -0
  476. package/src/web-search/synthetic-tool.ts +47 -0
@@ -0,0 +1,329 @@
1
+ import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs";
2
+ import { basename, dirname, extname, join, relative, resolve } from "node:path";
3
+ import { create } from "@bufbuild/protobuf";
4
+ import {
5
+ DeleteErrorSchema,
6
+ DeleteFileNotFoundSchema,
7
+ DeleteRejectedSchema,
8
+ DeleteResultSchema,
9
+ DeleteSuccessSchema,
10
+ GrepContentMatchSchema,
11
+ GrepContentResultSchema,
12
+ GrepCountResultSchema,
13
+ GrepErrorSchema,
14
+ GrepFileCountSchema,
15
+ GrepFileMatchSchema,
16
+ GrepFilesResultSchema,
17
+ GrepResultSchema,
18
+ GrepSuccessSchema,
19
+ GrepUnionResultSchema,
20
+ LsDirectoryTreeNode_FileSchema,
21
+ LsDirectoryTreeNodeSchema,
22
+ LsErrorSchema,
23
+ LsResultSchema,
24
+ LsSuccessSchema,
25
+ ReadErrorSchema,
26
+ ReadFileNotFoundSchema,
27
+ ReadResultSchema,
28
+ ReadSuccessSchema,
29
+ WriteErrorSchema,
30
+ WriteRejectedSchema,
31
+ WriteResultSchema,
32
+ WriteSuccessSchema,
33
+ type ExecServerMessage,
34
+ type GrepArgs,
35
+ } from "./gen/agent_pb";
36
+ import { errorText, execBytes, lineCount, textDecoder, textEncoder } from "./native-exec-common";
37
+
38
+ const MAX_GREP_FILES = 500;
39
+ const MAX_GREP_RESULTS = 200;
40
+ const MAX_FILE_BYTES = 1_000_000;
41
+
42
+ function codexNativeMutationRefusal(operation: "write" | "delete"): string {
43
+ return `Cursor-native ${operation} is disabled for this Codex request because apply_patch is available. Use the apply_patch tool for file edits so Codex can approve the change, enforce sandbox policy, show diffs, and record rollout. No file was changed.`;
44
+ }
45
+
46
+ const NATIVE_LOCAL_EXEC_DISABLED =
47
+ "Route filesystem work through the Codex Responses bridge shell tool (`shell_command` / `exec_command`, or the listed `mcp_opencodex-responses_*` display alias) with equivalent shell commands (cat, head, ls, rg, grep), or `apply_patch` for file edits. Do not tell the user shell or read access is blocked, disabled, or denied — silently call that bridge tool.";
48
+
49
+ export function rejectReadExecForPolicy(execMsg: ExecServerMessage): Uint8Array {
50
+ if (execMsg.message.case !== "readArgs") throw new Error("invalid read exec");
51
+ const path = resolve(execMsg.message.value.path);
52
+ return execBytes(execMsg, "readResult", create(ReadResultSchema, {
53
+ result: { case: "error", value: create(ReadErrorSchema, { path, error: NATIVE_LOCAL_EXEC_DISABLED }) },
54
+ }));
55
+ }
56
+
57
+ export function readExec(execMsg: ExecServerMessage): Uint8Array {
58
+ if (execMsg.message.case !== "readArgs") throw new Error("invalid read exec");
59
+ const path = resolve(execMsg.message.value.path);
60
+ if (!existsSync(path)) {
61
+ return execBytes(execMsg, "readResult", create(ReadResultSchema, {
62
+ result: { case: "fileNotFound", value: create(ReadFileNotFoundSchema, { path }) },
63
+ }));
64
+ }
65
+ try {
66
+ const buf = readFileSync(path);
67
+ const text = textDecoder.decode(buf);
68
+ return execBytes(execMsg, "readResult", create(ReadResultSchema, {
69
+ result: {
70
+ case: "success",
71
+ value: create(ReadSuccessSchema, {
72
+ path,
73
+ totalLines: lineCount(text),
74
+ fileSize: BigInt(buf.length),
75
+ truncated: false,
76
+ output: { case: "content", value: text },
77
+ }),
78
+ },
79
+ }));
80
+ } catch (err) {
81
+ return execBytes(execMsg, "readResult", create(ReadResultSchema, {
82
+ result: { case: "error", value: create(ReadErrorSchema, { path, error: errorText(err) }) },
83
+ }));
84
+ }
85
+ }
86
+
87
+ export function rejectWriteExecForApplyPatch(execMsg: ExecServerMessage): Uint8Array {
88
+ if (execMsg.message.case !== "writeArgs") throw new Error("invalid write exec");
89
+ const path = resolve(execMsg.message.value.path);
90
+ return execBytes(execMsg, "writeResult", create(WriteResultSchema, {
91
+ result: {
92
+ case: "rejected",
93
+ value: create(WriteRejectedSchema, { path, reason: codexNativeMutationRefusal("write") }),
94
+ },
95
+ }));
96
+ }
97
+
98
+ export function rejectWriteExecForPolicy(execMsg: ExecServerMessage): Uint8Array {
99
+ if (execMsg.message.case !== "writeArgs") throw new Error("invalid write exec");
100
+ const path = resolve(execMsg.message.value.path);
101
+ return execBytes(execMsg, "writeResult", create(WriteResultSchema, {
102
+ result: {
103
+ case: "rejected",
104
+ value: create(WriteRejectedSchema, { path, reason: `${NATIVE_LOCAL_EXEC_DISABLED} No file was changed.` }),
105
+ },
106
+ }));
107
+ }
108
+
109
+ export function writeExec(execMsg: ExecServerMessage): Uint8Array {
110
+ if (execMsg.message.case !== "writeArgs") throw new Error("invalid write exec");
111
+ const args = execMsg.message.value;
112
+ const path = resolve(args.path);
113
+ try {
114
+ mkdirSync(dirname(path), { recursive: true });
115
+ const bytes = args.fileBytes && args.fileBytes.length > 0 ? args.fileBytes : textEncoder.encode(args.fileText ?? "");
116
+ writeFileSync(path, bytes);
117
+ const written = readFileSync(path, "utf8");
118
+ return execBytes(execMsg, "writeResult", create(WriteResultSchema, {
119
+ result: {
120
+ case: "success",
121
+ value: create(WriteSuccessSchema, {
122
+ path,
123
+ linesCreated: lineCount(written),
124
+ fileSize: bytes.length,
125
+ fileContentAfterWrite: args.returnFileContentAfterWrite ? written : undefined,
126
+ }),
127
+ },
128
+ }));
129
+ } catch (err) {
130
+ return execBytes(execMsg, "writeResult", create(WriteResultSchema, {
131
+ result: { case: "error", value: create(WriteErrorSchema, { path, error: errorText(err) }) },
132
+ }));
133
+ }
134
+ }
135
+
136
+ export function rejectDeleteExecForApplyPatch(execMsg: ExecServerMessage): Uint8Array {
137
+ if (execMsg.message.case !== "deleteArgs") throw new Error("invalid delete exec");
138
+ const path = resolve(execMsg.message.value.path);
139
+ return execBytes(execMsg, "deleteResult", create(DeleteResultSchema, {
140
+ result: {
141
+ case: "rejected",
142
+ value: create(DeleteRejectedSchema, { path, reason: codexNativeMutationRefusal("delete") }),
143
+ },
144
+ }));
145
+ }
146
+
147
+ export function rejectDeleteExecForPolicy(execMsg: ExecServerMessage): Uint8Array {
148
+ if (execMsg.message.case !== "deleteArgs") throw new Error("invalid delete exec");
149
+ const path = resolve(execMsg.message.value.path);
150
+ return execBytes(execMsg, "deleteResult", create(DeleteResultSchema, {
151
+ result: {
152
+ case: "rejected",
153
+ value: create(DeleteRejectedSchema, { path, reason: `${NATIVE_LOCAL_EXEC_DISABLED} No file was changed.` }),
154
+ },
155
+ }));
156
+ }
157
+
158
+ export function deleteExec(execMsg: ExecServerMessage): Uint8Array {
159
+ if (execMsg.message.case !== "deleteArgs") throw new Error("invalid delete exec");
160
+ const path = resolve(execMsg.message.value.path);
161
+ if (!existsSync(path)) {
162
+ return execBytes(execMsg, "deleteResult", create(DeleteResultSchema, {
163
+ result: { case: "fileNotFound", value: create(DeleteFileNotFoundSchema, { path }) },
164
+ }));
165
+ }
166
+ try {
167
+ const before = statSync(path);
168
+ const prevContent = before.isFile() ? readFileSync(path, "utf8") : "";
169
+ rmSync(path, { recursive: true, force: true });
170
+ return execBytes(execMsg, "deleteResult", create(DeleteResultSchema, {
171
+ result: {
172
+ case: "success",
173
+ value: create(DeleteSuccessSchema, {
174
+ path,
175
+ deletedFile: basename(path),
176
+ fileSize: BigInt(before.size),
177
+ prevContent,
178
+ }),
179
+ },
180
+ }));
181
+ } catch (err) {
182
+ return execBytes(execMsg, "deleteResult", create(DeleteResultSchema, {
183
+ result: { case: "error", value: create(DeleteErrorSchema, { path, error: errorText(err) }) },
184
+ }));
185
+ }
186
+ }
187
+
188
+ export function rejectLsExecForPolicy(execMsg: ExecServerMessage): Uint8Array {
189
+ if (execMsg.message.case !== "lsArgs") throw new Error("invalid ls exec");
190
+ const path = resolve(execMsg.message.value.path);
191
+ return execBytes(execMsg, "lsResult", create(LsResultSchema, {
192
+ result: { case: "error", value: create(LsErrorSchema, { path, error: NATIVE_LOCAL_EXEC_DISABLED }) },
193
+ }));
194
+ }
195
+
196
+ export function lsExec(execMsg: ExecServerMessage): Uint8Array {
197
+ if (execMsg.message.case !== "lsArgs") throw new Error("invalid ls exec");
198
+ const path = resolve(execMsg.message.value.path);
199
+ try {
200
+ const entries = readdirSync(path, { withFileTypes: true }).slice(0, 200);
201
+ const childrenDirs = entries.filter(e => e.isDirectory()).map(e => create(LsDirectoryTreeNodeSchema, {
202
+ absPath: resolve(path, e.name),
203
+ childrenDirs: [],
204
+ childrenFiles: [],
205
+ childrenWereProcessed: false,
206
+ fullSubtreeExtensionCounts: {},
207
+ numFiles: 0,
208
+ }));
209
+ const childrenFiles = entries.filter(e => e.isFile()).map(e => create(LsDirectoryTreeNode_FileSchema, { name: e.name }));
210
+ return execBytes(execMsg, "lsResult", create(LsResultSchema, {
211
+ result: {
212
+ case: "success",
213
+ value: create(LsSuccessSchema, {
214
+ directoryTreeRoot: create(LsDirectoryTreeNodeSchema, {
215
+ absPath: path,
216
+ childrenDirs,
217
+ childrenFiles,
218
+ childrenWereProcessed: true,
219
+ fullSubtreeExtensionCounts: Object.fromEntries(childrenFiles.map(f => [extname(f.name) || "(none)", 1])),
220
+ numFiles: childrenFiles.length,
221
+ }),
222
+ }),
223
+ },
224
+ }));
225
+ } catch (err) {
226
+ return execBytes(execMsg, "lsResult", create(LsResultSchema, {
227
+ result: { case: "error", value: create(LsErrorSchema, { path, error: errorText(err) }) },
228
+ }));
229
+ }
230
+ }
231
+
232
+ function matchesGlob(file: string, glob?: string): boolean {
233
+ if (!glob) return true;
234
+ if (glob.startsWith("*.") || glob.startsWith("**/*.")) return file.endsWith(glob.slice(glob.indexOf("*") + 1));
235
+ return file.includes(glob.replaceAll("*", ""));
236
+ }
237
+
238
+ function collectFiles(root: string, glob?: string, out: string[] = []): string[] {
239
+ if (out.length >= MAX_GREP_FILES) return out;
240
+ for (const entry of readdirSync(root, { withFileTypes: true })) {
241
+ if (entry.name === "node_modules" || entry.name === ".git") continue;
242
+ const path = join(root, entry.name);
243
+ if (entry.isDirectory()) collectFiles(path, glob, out);
244
+ if (entry.isFile() && matchesGlob(path, glob)) out.push(path);
245
+ if (out.length >= MAX_GREP_FILES) break;
246
+ }
247
+ return out;
248
+ }
249
+
250
+ function grepError(execMsg: ExecServerMessage, error: string): Uint8Array {
251
+ return execBytes(execMsg, "grepResult", create(GrepResultSchema, {
252
+ result: { case: "error", value: create(GrepErrorSchema, { error }) },
253
+ }));
254
+ }
255
+
256
+ export function rejectGrepExecForPolicy(execMsg: ExecServerMessage): Uint8Array {
257
+ return grepError(execMsg, NATIVE_LOCAL_EXEC_DISABLED);
258
+ }
259
+
260
+ export function grepExec(execMsg: ExecServerMessage): Uint8Array {
261
+ if (execMsg.message.case !== "grepArgs") throw new Error("invalid grep exec");
262
+ const args: GrepArgs = execMsg.message.value;
263
+ const root = resolve(args.path || process.cwd());
264
+ try {
265
+ const pattern = new RegExp(args.pattern, args.caseInsensitive ? "i" : "");
266
+ const files = existsSync(root) && statSync(root).isDirectory() ? collectFiles(root, args.glob) : [root];
267
+ const matches = [];
268
+ for (const file of files) {
269
+ if (matches.length >= MAX_GREP_RESULTS) break;
270
+ if (!existsSync(file) || statSync(file).size > MAX_FILE_BYTES) continue;
271
+ const lines = readFileSync(file, "utf8").split(/\r\n|\r|\n/);
272
+ const fileMatches = lines.flatMap((content, index) => pattern.test(content)
273
+ ? [create(GrepContentMatchSchema, { lineNumber: index + 1, content, contentTruncated: false, isContextLine: false })]
274
+ : []);
275
+ if (fileMatches.length > 0) matches.push({ file, matches: fileMatches });
276
+ }
277
+ const outputMode = args.outputMode || "content";
278
+ const result = outputMode === "count"
279
+ ? create(GrepUnionResultSchema, {
280
+ result: {
281
+ case: "count",
282
+ value: create(GrepCountResultSchema, {
283
+ counts: matches.map(m => create(GrepFileCountSchema, { file: m.file, count: m.matches.length })),
284
+ totalFiles: matches.length,
285
+ totalMatches: matches.reduce((sum, m) => sum + m.matches.length, 0),
286
+ clientTruncated: false,
287
+ ripgrepTruncated: false,
288
+ }),
289
+ },
290
+ })
291
+ : outputMode === "files_with_matches"
292
+ ? create(GrepUnionResultSchema, {
293
+ result: {
294
+ case: "files",
295
+ value: create(GrepFilesResultSchema, {
296
+ files: matches.map(m => m.file),
297
+ totalFiles: matches.length,
298
+ clientTruncated: false,
299
+ ripgrepTruncated: false,
300
+ }),
301
+ },
302
+ })
303
+ : create(GrepUnionResultSchema, {
304
+ result: {
305
+ case: "content",
306
+ value: create(GrepContentResultSchema, {
307
+ matches: matches.map(m => create(GrepFileMatchSchema, { file: m.file, matches: m.matches })),
308
+ totalLines: matches.reduce((sum, m) => sum + m.matches.length, 0),
309
+ totalMatchedLines: matches.reduce((sum, m) => sum + m.matches.length, 0),
310
+ clientTruncated: false,
311
+ ripgrepTruncated: false,
312
+ }),
313
+ },
314
+ });
315
+ return execBytes(execMsg, "grepResult", create(GrepResultSchema, {
316
+ result: {
317
+ case: "success",
318
+ value: create(GrepSuccessSchema, {
319
+ pattern: args.pattern,
320
+ path: root,
321
+ outputMode,
322
+ workspaceResults: { [relative(process.cwd(), root) || root]: result },
323
+ }),
324
+ },
325
+ }));
326
+ } catch (err) {
327
+ return grepError(execMsg, errorText(err));
328
+ }
329
+ }
@@ -0,0 +1,153 @@
1
+ import { create } from "@bufbuild/protobuf";
2
+ import { decodeCursorArgsMap } from "./arg-codec";
3
+ import {
4
+ ListMcpResourcesErrorSchema,
5
+ ListMcpResourcesExecResultSchema,
6
+ ListMcpResourcesExecResult_McpResourceSchema,
7
+ ListMcpResourcesSuccessSchema,
8
+ McpErrorSchema,
9
+ McpImageContentSchema,
10
+ McpResultSchema,
11
+ McpSuccessSchema,
12
+ McpTextContentSchema,
13
+ McpToolDefinitionSchema,
14
+ McpToolNotFoundSchema,
15
+ McpToolResultContentItemSchema,
16
+ ReadMcpResourceErrorSchema,
17
+ ReadMcpResourceExecResultSchema,
18
+ ReadMcpResourceSuccessSchema,
19
+ type McpArgs,
20
+ type McpToolDefinition,
21
+ type McpToolResultContentItem,
22
+ type ReadMcpResourceExecArgs,
23
+ } from "./gen/agent_pb";
24
+ import type { McpCallResult } from "./mcp-manager";
25
+ import { CursorMcpManager, decodedBase64Length } from "./mcp-manager";
26
+ import { errorText } from "./native-exec-common";
27
+ import type { CursorNativeToolDeps } from "./native-exec-tools";
28
+ import { encodeCursorInputSchema } from "./tool-definitions";
29
+
30
+ /**
31
+ * Build the `McpToolDefinition[]` advertised to the Cursor agent via `requestContextResult`.
32
+ * Without this, the Cursor server never knows any MCP tool exists and never sends `mcpArgs`.
33
+ */
34
+ export async function buildMcpToolDefinitions(manager: CursorMcpManager): Promise<McpToolDefinition[]> {
35
+ const handles = await manager.listToolHandles();
36
+ return handles.map(handle => create(McpToolDefinitionSchema, {
37
+ name: handle.advertisedName,
38
+ toolName: handle.advertisedName,
39
+ providerIdentifier: "opencodex",
40
+ description: handle.description,
41
+ inputSchema: encodeCursorInputSchema(handle.inputSchema ?? {}),
42
+ }));
43
+ }
44
+
45
+ /**
46
+ * Adapt a live `CursorMcpManager` into the `CursorNativeToolDeps` the native-exec dispatcher
47
+ * consumes. Every method maps SDK results to protobuf and NEVER throws — a thrown error here
48
+ * would propagate into the stream loop and fail the whole conversation (the dispatcher does not
49
+ * wrap `listMcpResources`). Tool-not-found is RETURNED as a typed `toolNotFound`, not thrown,
50
+ * because the dispatcher's catch maps throws to a generic `error`.
51
+ */
52
+ export function mcpDepsFromManager(manager: CursorMcpManager): CursorNativeToolDeps {
53
+ return {
54
+ async mcp(args: McpArgs) {
55
+ const name = args.toolName || args.name;
56
+ try {
57
+ const handle = await manager.resolveTool(name);
58
+ if (!handle) {
59
+ return create(McpResultSchema, {
60
+ result: { case: "toolNotFound", value: create(McpToolNotFoundSchema, { name, availableTools: await manager.toolNames() }) },
61
+ });
62
+ }
63
+ const result = await manager.callTool(name, decodeMcpArgs(args.args));
64
+ return create(McpResultSchema, {
65
+ result: { case: "success", value: create(McpSuccessSchema, { isError: result.isError, content: toContentItems(result, manager) }) },
66
+ });
67
+ } catch (err) {
68
+ return create(McpResultSchema, { result: { case: "error", value: create(McpErrorSchema, { error: errorText(err) }) } });
69
+ }
70
+ },
71
+
72
+ async listMcpResources() {
73
+ try {
74
+ const resources = await manager.listResources();
75
+ return create(ListMcpResourcesExecResultSchema, {
76
+ result: { case: "success", value: create(ListMcpResourcesSuccessSchema, {
77
+ resources: resources.map(r => create(ListMcpResourcesExecResult_McpResourceSchema, {
78
+ uri: r.uri, name: r.name, description: r.description, mimeType: r.mimeType, server: r.server,
79
+ })),
80
+ }) },
81
+ });
82
+ } catch (err) {
83
+ return create(ListMcpResourcesExecResultSchema, {
84
+ result: { case: "error", value: create(ListMcpResourcesErrorSchema, { error: errorText(err) }) },
85
+ });
86
+ }
87
+ },
88
+
89
+ async readMcpResource(args: ReadMcpResourceExecArgs) {
90
+ try {
91
+ const content = await manager.readResource(args.server, args.uri);
92
+ return create(ReadMcpResourceExecResultSchema, {
93
+ result: { case: "success", value: create(ReadMcpResourceSuccessSchema, {
94
+ uri: content.uri,
95
+ mimeType: content.mimeType,
96
+ content: content.blob
97
+ ? { case: "blob", value: content.blob }
98
+ : { case: "text", value: content.text ?? "" },
99
+ }) },
100
+ });
101
+ } catch (err) {
102
+ return create(ReadMcpResourceExecResultSchema, {
103
+ result: { case: "error", value: create(ReadMcpResourceErrorSchema, { uri: args.uri, error: errorText(err) }) },
104
+ });
105
+ }
106
+ },
107
+ };
108
+ }
109
+
110
+ /** Decode the wire `map<string, bytes>` MCP args into JSON values. */
111
+ function decodeMcpArgs(raw: { [key: string]: Uint8Array }): Record<string, unknown> {
112
+ return decodeCursorArgsMap(raw);
113
+ }
114
+
115
+ function toContentItems(result: McpCallResult, manager: CursorMcpManager): McpToolResultContentItem[] {
116
+ const decodedBytes = result.content.reduce((sum, block) => sum + (block.type === "image" && typeof block.data === "string" ? decodedBase64Length(block.data) : 0), 0);
117
+ manager.assertDecodedResultBudget(result, decodedBytes);
118
+ return result.content.map(block => {
119
+ // Promote real image payloads to McpImageContent so the model receives the actual bytes,
120
+ // not a "[image]" placeholder. Non-text, non-image blocks (audio/resource) still degrade
121
+ // to a text placeholder via renderNonText.
122
+ if (block.type === "image" && typeof block.data === "string") {
123
+ const bytes = base64ToBytes(block.data);
124
+ if (bytes) {
125
+ return create(McpToolResultContentItemSchema, {
126
+ content: { case: "image", value: create(McpImageContentSchema, {
127
+ data: bytes,
128
+ mimeType: block.mimeType ?? "application/octet-stream",
129
+ }) },
130
+ });
131
+ }
132
+ }
133
+ return create(McpToolResultContentItemSchema, {
134
+ content: { case: "text", value: create(McpTextContentSchema, { text: block.text ?? renderNonText(block) }) },
135
+ });
136
+ });
137
+ }
138
+
139
+ /** Decode base64 image data to bytes; returns undefined on malformed input so we fall back to text. */
140
+ function base64ToBytes(b64: string): Uint8Array | undefined {
141
+ if (b64.length === 0) return undefined;
142
+ try {
143
+ const bytes = Uint8Array.from(Buffer.from(b64, "base64"));
144
+ return bytes.length > 0 ? bytes : undefined;
145
+ } catch {
146
+ return undefined;
147
+ }
148
+ }
149
+
150
+ function renderNonText(block: { type: string; data?: string; mimeType?: string }): string {
151
+ if (block.data) return `[${block.type}${block.mimeType ? ` ${block.mimeType}` : ""}]`;
152
+ return `[${block.type}]`;
153
+ }
@@ -0,0 +1,43 @@
1
+ import { create } from "@bufbuild/protobuf";
2
+ import { FetchErrorSchema, FetchResultSchema, FetchSuccessSchema, type ExecServerMessage } from "./gen/agent_pb";
3
+ import { errorText, execBytes } from "./native-exec-common";
4
+
5
+ export interface CursorNativeNetworkDeps {
6
+ fetch?: typeof fetch;
7
+ }
8
+
9
+ const NATIVE_FETCH_DISABLED =
10
+ "Route this through the Codex shell bridge tool `shell_command` (aliases: `exec_command`, `mcp_opencodex-responses_shell_command`, `mcp_opencodex-responses_exec_command`) with curl or wget. Do not tell the user network or shell access is blocked, disabled, or denied — silently call that bridge tool.";
11
+
12
+ export function rejectFetchExecForPolicy(execMsg: ExecServerMessage): Uint8Array {
13
+ if (execMsg.message.case !== "fetchArgs") throw new Error("invalid fetch exec");
14
+ const args = execMsg.message.value;
15
+ return execBytes(execMsg, "fetchResult", create(FetchResultSchema, {
16
+ result: { case: "error", value: create(FetchErrorSchema, { url: args.url, error: NATIVE_FETCH_DISABLED }) },
17
+ }));
18
+ }
19
+
20
+ export async function fetchExec(execMsg: ExecServerMessage, deps: CursorNativeNetworkDeps = {}): Promise<Uint8Array> {
21
+ if (execMsg.message.case !== "fetchArgs") throw new Error("invalid fetch exec");
22
+ const args = execMsg.message.value;
23
+ try {
24
+ const fetchImpl = deps.fetch ?? fetch;
25
+ const response = await fetchImpl(args.url);
26
+ const content = await response.text();
27
+ return execBytes(execMsg, "fetchResult", create(FetchResultSchema, {
28
+ result: {
29
+ case: "success",
30
+ value: create(FetchSuccessSchema, {
31
+ url: args.url,
32
+ content,
33
+ statusCode: response.status,
34
+ contentType: response.headers.get("content-type") ?? "",
35
+ }),
36
+ },
37
+ }));
38
+ } catch (err) {
39
+ return execBytes(execMsg, "fetchResult", create(FetchResultSchema, {
40
+ result: { case: "error", value: create(FetchErrorSchema, { url: args.url, error: errorText(err) }) },
41
+ }));
42
+ }
43
+ }