@iislee/opencodex 2.11.0 → 2.35.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 (733) hide show
  1. package/AGENTS_INSTALL.md +109 -0
  2. package/README.md +117 -22
  3. package/bin/ocx.mjs +245 -88
  4. package/bin/package-main.mjs +1 -1
  5. package/gui/dist/assets/index-Be1sDpWw.css +1 -0
  6. package/gui/dist/assets/index-D4OKgUV4.js +114 -0
  7. package/gui/dist/index.html +2 -2
  8. package/gui/dist/provider-icons/alibaba-color.svg +1 -1
  9. package/gui/dist/provider-icons/antigravity-color.svg +1 -1
  10. package/gui/dist/provider-icons/claude-color.svg +1 -1
  11. package/gui/dist/provider-icons/cline-color.svg +16 -0
  12. package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -1
  13. package/gui/dist/provider-icons/commandcode-color.svg +1 -0
  14. package/gui/dist/provider-icons/copilot-color.svg +1 -1
  15. package/gui/dist/provider-icons/cursor-color.svg +1 -1
  16. package/gui/dist/provider-icons/deepseek-color.svg +1 -1
  17. package/gui/dist/provider-icons/firepass-color.svg +1 -1
  18. package/gui/dist/provider-icons/fireworks-color.svg +1 -1
  19. package/gui/dist/provider-icons/gemini-color.svg +1 -1
  20. package/gui/dist/provider-icons/github-copilot-color.svg +1 -1
  21. package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -1
  22. package/gui/dist/provider-icons/grok.svg +1 -1
  23. package/gui/dist/provider-icons/groq-color.svg +1 -1
  24. package/gui/dist/provider-icons/huggingface-color.svg +1 -1
  25. package/gui/dist/provider-icons/kimi-color.svg +1 -1
  26. package/gui/dist/provider-icons/kiro-color.svg +2 -2
  27. package/gui/dist/provider-icons/lm-studio-color.svg +1 -1
  28. package/gui/dist/provider-icons/mistral-color.svg +1 -1
  29. package/gui/dist/provider-icons/moonshot-color.svg +1 -1
  30. package/gui/dist/provider-icons/nvidia-color.svg +1 -1
  31. package/gui/dist/provider-icons/ollama-color.svg +1 -1
  32. package/gui/dist/provider-icons/openai.svg +1 -1
  33. package/gui/dist/provider-icons/opencode.svg +2 -1
  34. package/gui/dist/provider-icons/openrouter-color.svg +1 -1
  35. package/gui/dist/provider-icons/pi.svg +2 -2
  36. package/gui/dist/provider-icons/qianfan-color.svg +1 -1
  37. package/gui/dist/provider-icons/qwen-portal-color.svg +1 -1
  38. package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -1
  39. package/gui/dist/provider-icons/vllm-color.svg +1 -1
  40. package/gui/dist/provider-icons/xiaomi-color.svg +1 -1
  41. package/package.json +21 -10
  42. package/src/adapters/anthropic-output-schema.ts +137 -0
  43. package/src/adapters/anthropic.ts +475 -62
  44. package/src/adapters/base.ts +82 -7
  45. package/src/adapters/client-fingerprint.ts +18 -12
  46. package/src/adapters/cline-pass-deepseek-v4-tool-replay.ts +69 -0
  47. package/src/adapters/command-code.ts +637 -0
  48. package/src/adapters/cursor/call-id.ts +44 -0
  49. package/src/adapters/cursor/catalog.ts +541 -0
  50. package/src/adapters/cursor/checkpoint-store.ts +308 -0
  51. package/src/adapters/cursor/cursor-errors.ts +144 -6
  52. package/src/adapters/cursor/discovery.ts +122 -14
  53. package/src/adapters/cursor/effort-map.ts +106 -4
  54. package/src/adapters/cursor/envelope-echo.ts +290 -0
  55. package/src/adapters/cursor/framing.ts +39 -0
  56. package/src/adapters/cursor/h2-pool.ts +123 -0
  57. package/src/adapters/cursor/http1-bidi.ts +361 -0
  58. package/src/adapters/cursor/images.ts +704 -0
  59. package/src/adapters/cursor/live-models.ts +180 -59
  60. package/src/adapters/cursor/live-transport.ts +623 -170
  61. package/src/adapters/cursor/message-mapper.ts +4 -1
  62. package/src/adapters/cursor/native-exec-common.ts +23 -2
  63. package/src/adapters/cursor/native-exec-desktop.ts +23 -0
  64. package/src/adapters/cursor/native-exec-fs.ts +10 -7
  65. package/src/adapters/cursor/native-exec-network.ts +1 -1
  66. package/src/adapters/cursor/native-exec-shell.ts +5 -3
  67. package/src/adapters/cursor/native-exec.ts +121 -14
  68. package/src/adapters/cursor/protobuf-events.ts +829 -11
  69. package/src/adapters/cursor/protobuf-request.ts +447 -75
  70. package/src/adapters/cursor/request-builder.ts +271 -35
  71. package/src/adapters/cursor/tool-definitions.ts +252 -12
  72. package/src/adapters/cursor/tool-result-normalize.ts +115 -0
  73. package/src/adapters/cursor/transport.ts +22 -0
  74. package/src/adapters/cursor/types.ts +48 -1
  75. package/src/adapters/cursor.ts +336 -39
  76. package/src/adapters/exec-tool-result-normalize.ts +99 -0
  77. package/src/adapters/google-antigravity-replay.ts +713 -41
  78. package/src/adapters/google-antigravity-wire.ts +48 -10
  79. package/src/adapters/google-errors.ts +44 -12
  80. package/src/adapters/google-http.ts +38 -10
  81. package/src/adapters/google-tool-schema.ts +80 -15
  82. package/src/adapters/google-truncation.ts +11 -0
  83. package/src/adapters/google.ts +742 -86
  84. package/src/adapters/identity.ts +39 -6
  85. package/src/adapters/image.ts +1 -1
  86. package/src/adapters/kiro-constants.ts +27 -0
  87. package/src/adapters/kiro-errors.ts +11 -0
  88. package/src/adapters/kiro-events.ts +19 -1
  89. package/src/adapters/kiro-thinking.ts +18 -2
  90. package/src/adapters/kiro-tools.ts +65 -17
  91. package/src/adapters/kiro.ts +270 -73
  92. package/src/adapters/mimo-free.ts +17 -0
  93. package/src/adapters/openai-chat-url.ts +11 -0
  94. package/src/adapters/openai-chat.ts +1377 -344
  95. package/src/adapters/openai-responses-url.ts +16 -0
  96. package/src/adapters/openai-responses.ts +1164 -64
  97. package/src/adapters/registry.ts +175 -0
  98. package/src/adapters/responses-tool-schema.ts +67 -0
  99. package/src/adapters/run-turn-queue.ts +36 -1
  100. package/src/adapters/tool-call-id.ts +119 -0
  101. package/src/adapters/tool-catalog-nudge.ts +105 -21
  102. package/src/adapters/xai-tool-schema.ts +436 -0
  103. package/src/adapters/xai-web-search.ts +186 -0
  104. package/src/bridge.ts +512 -92
  105. package/src/chat/inbound.ts +57 -20
  106. package/src/chat/outbound.ts +97 -33
  107. package/src/claude/agents-inject.ts +40 -10
  108. package/src/claude/context-windows.ts +37 -14
  109. package/src/claude/desktop-3p.ts +243 -9
  110. package/src/claude/gateway-cache.ts +41 -4
  111. package/src/claude/inbound.ts +72 -3
  112. package/src/claude/model-info.ts +38 -15
  113. package/src/claude/outbound.ts +88 -21
  114. package/src/cli/access.ts +46 -3
  115. package/src/cli/account-api.ts +150 -19
  116. package/src/cli/account-auth.ts +33 -6
  117. package/src/cli/account-catalog-refresh.ts +14 -0
  118. package/src/cli/account-extended.ts +648 -28
  119. package/src/cli/account-main.ts +317 -0
  120. package/src/cli/account.ts +97 -19
  121. package/src/cli/agent.ts +53 -2
  122. package/src/cli/alias.ts +66 -0
  123. package/src/cli/capabilities-command.ts +94 -0
  124. package/src/cli/capabilities.ts +496 -0
  125. package/src/cli/claude-agent-startup-sync.ts +73 -0
  126. package/src/cli/claude-desktop.ts +60 -15
  127. package/src/cli/claude.ts +129 -35
  128. package/src/cli/codex-log-guard-doctor.ts +103 -0
  129. package/src/cli/codex-shim-autorestore.ts +2 -0
  130. package/src/cli/codex-shim-readiness.ts +76 -0
  131. package/src/cli/combo.ts +8 -0
  132. package/src/cli/config-command.ts +74 -10
  133. package/src/cli/dispatch.ts +821 -0
  134. package/src/cli/doctor.ts +440 -56
  135. package/src/cli/ensure-desired-integrations.ts +152 -0
  136. package/src/cli/export-command.ts +46 -20
  137. package/src/cli/help.ts +34 -274
  138. package/src/cli/index.ts +417 -528
  139. package/src/cli/init.ts +5 -17
  140. package/src/cli/inspect.ts +230 -0
  141. package/src/cli/integrations.ts +120 -2
  142. package/src/cli/lab.ts +607 -0
  143. package/src/cli/launcher-context.ts +77 -0
  144. package/src/cli/minimax.ts +497 -0
  145. package/src/cli/models-runtime.ts +130 -2
  146. package/src/cli/models.ts +118 -16
  147. package/src/cli/observe.ts +123 -11
  148. package/src/cli/opencode.ts +4 -2
  149. package/src/cli/provider-runtime.ts +34 -3
  150. package/src/cli/provider.ts +25 -3
  151. package/src/cli/ready.ts +301 -0
  152. package/src/cli/registry.ts +476 -0
  153. package/src/cli/root.ts +86 -0
  154. package/src/cli/route-policy.ts +92 -0
  155. package/src/cli/runtime-api.ts +57 -10
  156. package/src/cli/star-prompt.ts +71 -15
  157. package/src/cli/status.ts +51 -4
  158. package/src/cli/storage.ts +234 -0
  159. package/src/cli/system-command.ts +16 -0
  160. package/src/cli/system-restart-client.ts +146 -0
  161. package/src/cli/tray-proxy.ts +153 -6
  162. package/src/cli/usage-report.ts +184 -0
  163. package/src/cli/v2.ts +137 -18
  164. package/src/cli/version-skew.ts +46 -0
  165. package/src/cli.ts +1 -1
  166. package/src/clients/config-export.ts +1442 -23
  167. package/src/clients/effective-status.ts +30 -2
  168. package/src/clients/probes/cline.ts +81 -0
  169. package/src/codex/account-label.ts +35 -1
  170. package/src/codex/account-lifecycle.ts +130 -13
  171. package/src/codex/account-namespaces.ts +49 -3
  172. package/src/codex/account-pause.ts +2 -1
  173. package/src/codex/account-priority.ts +84 -0
  174. package/src/codex/account-store.ts +29 -2
  175. package/src/codex/account-usability.ts +25 -2
  176. package/src/codex/admission.ts +256 -0
  177. package/src/codex/affinity-debug.ts +162 -0
  178. package/src/codex/app-server-processes.ts +570 -107
  179. package/src/codex/app-server-restart-service.ts +232 -0
  180. package/src/codex/auth-api.ts +893 -246
  181. package/src/codex/auth-collision.ts +5 -3
  182. package/src/codex/auth-context.ts +348 -32
  183. package/src/codex/autostart-health.ts +24 -1
  184. package/src/codex/catalog/account-models.ts +67 -0
  185. package/src/codex/catalog/aggregation.ts +86 -10
  186. package/src/codex/catalog/bundled.ts +331 -33
  187. package/src/codex/catalog/effort.ts +138 -32
  188. package/src/codex/catalog/filesystem-evidence.ts +302 -0
  189. package/src/codex/catalog/kinds.ts +2 -0
  190. package/src/codex/catalog/metadata.ts +555 -45
  191. package/src/codex/catalog/native-models.ts +75 -0
  192. package/src/codex/catalog/parsing.ts +269 -30
  193. package/src/codex/catalog/provider-fetch.ts +1626 -144
  194. package/src/codex/catalog/sync.ts +1576 -187
  195. package/src/codex/catalog-admission.ts +199 -0
  196. package/src/codex/catalog-refresh-status.ts +105 -0
  197. package/src/codex/catalog-write-serialization.ts +242 -0
  198. package/src/codex/catalog.ts +6 -3
  199. package/src/codex/codex-write-lock.ts +386 -0
  200. package/src/codex/convergence-types.ts +614 -0
  201. package/src/codex/convergence.ts +676 -0
  202. package/src/codex/coordinator-doctor.ts +332 -0
  203. package/src/codex/custom-model-catalog-migration.ts +176 -0
  204. package/src/codex/desired-state.ts +230 -0
  205. package/src/codex/desktop-app-restart.ts +355 -0
  206. package/src/codex/features.ts +636 -39
  207. package/src/codex/generation.ts +202 -0
  208. package/src/codex/history-job.ts +436 -0
  209. package/src/codex/history-lock.ts +242 -0
  210. package/src/codex/history-manifest.ts +112 -0
  211. package/src/codex/history-migration-guardian.ts +30 -24
  212. package/src/codex/history-provider.ts +1016 -235
  213. package/src/codex/history-transition.ts +105 -0
  214. package/src/codex/history-worker.ts +223 -0
  215. package/src/codex/inject-coordination.ts +373 -0
  216. package/src/codex/inject.ts +1114 -152
  217. package/src/codex/injected-marker.ts +37 -3
  218. package/src/codex/integration-record.ts +266 -0
  219. package/src/codex/internal/catalog-writer.ts +203 -0
  220. package/src/codex/internal/history-writer.ts +81 -0
  221. package/src/codex/journal.ts +66 -4
  222. package/src/codex/log-guard/inspect.ts +524 -0
  223. package/src/codex/log-guard/lock.ts +150 -0
  224. package/src/codex/log-guard/maintenance.ts +403 -0
  225. package/src/codex/log-guard/path-safety.ts +88 -0
  226. package/src/codex/log-guard/policy.ts +44 -0
  227. package/src/codex/log-guard/processes.ts +205 -0
  228. package/src/codex/log-guard/protection.ts +489 -0
  229. package/src/codex/log-guard/sqlite-errors.ts +9 -0
  230. package/src/codex/main-account-cache.ts +24 -0
  231. package/src/codex/main-account.ts +29 -1
  232. package/src/codex/management-convergence.ts +167 -0
  233. package/src/codex/model-cache.ts +56 -10
  234. package/src/codex/model-entitlements.ts +360 -0
  235. package/src/codex/native-main-admission.ts +47 -0
  236. package/src/codex/native-main-auth-temp.ts +187 -0
  237. package/src/codex/native-main-claim.ts +178 -0
  238. package/src/codex/native-main-lock-file.ts +162 -0
  239. package/src/codex/native-main-owner.ts +329 -0
  240. package/src/codex/native-profile-api.ts +247 -0
  241. package/src/codex/native-profile-manager.ts +1531 -0
  242. package/src/codex/native-profile-processes.ts +121 -0
  243. package/src/codex/native-profile-recovery.ts +99 -0
  244. package/src/codex/native-profile-stage-store.ts +387 -0
  245. package/src/codex/native-profile-startup.ts +622 -0
  246. package/src/codex/native-profile-store.ts +855 -0
  247. package/src/codex/native-profile-types.ts +120 -0
  248. package/src/codex/native-residue.ts +675 -0
  249. package/src/codex/paths.ts +80 -1
  250. package/src/codex/plan-from-token.ts +140 -0
  251. package/src/codex/plan.ts +40 -0
  252. package/src/codex/plugins-doctor.ts +1 -1
  253. package/src/codex/pool-rotation.ts +74 -4
  254. package/src/codex/project-config-warnings.ts +20 -6
  255. package/src/codex/prompt-journal.ts +352 -0
  256. package/src/codex/prompt-layers.ts +1313 -0
  257. package/src/codex/prompt-lock.ts +143 -0
  258. package/src/codex/prompt-text-probe.ts +238 -0
  259. package/src/codex/quota-rejection.ts +298 -0
  260. package/src/codex/quota.ts +264 -21
  261. package/src/codex/refresh.ts +11 -2
  262. package/src/codex/reset-credit-recovery.ts +1044 -0
  263. package/src/codex/routing.ts +514 -94
  264. package/src/codex/runtime.ts +159 -38
  265. package/src/codex/shim.ts +1065 -31
  266. package/src/codex/subagent-model-fallback.ts +437 -43
  267. package/src/codex/sync.ts +191 -2
  268. package/src/codex/transition-state.ts +720 -0
  269. package/src/codex/upstream-host-health.ts +368 -0
  270. package/src/codex/user-identity.ts +557 -0
  271. package/src/codex/warmup.ts +187 -81
  272. package/src/codex/write-coordination.ts +114 -0
  273. package/src/combos/failover.ts +47 -0
  274. package/src/combos/index.ts +4 -0
  275. package/src/combos/request.ts +32 -0
  276. package/src/combos/types.ts +91 -9
  277. package/src/compatibility/index.ts +26 -0
  278. package/src/compatibility/manifest.ts +253 -0
  279. package/src/compatibility/openai-responses.ts +121 -0
  280. package/src/config/atomic-write.ts +219 -0
  281. package/src/config/paths.ts +40 -0
  282. package/src/config/process-state.ts +309 -0
  283. package/src/config/provider-name.ts +24 -0
  284. package/src/config/provider-validation.ts +177 -0
  285. package/src/config/rebase-provenance.ts +68 -0
  286. package/src/config.ts +1713 -709
  287. package/src/generated/compatibility-version.json +3324 -0
  288. package/src/generated/{jawcode-model-metadata.ts → model-metadata.ts} +19 -17
  289. package/src/grok/inject.ts +16 -5
  290. package/src/grok/inspect.ts +45 -0
  291. package/src/grok/sync.ts +2 -2
  292. package/src/images/loop.ts +157 -33
  293. package/src/images/plan.ts +24 -13
  294. package/src/integrations/config-io.ts +269 -0
  295. package/src/integrations/journal.ts +315 -0
  296. package/src/integrations/merge.ts +135 -0
  297. package/src/integrations/mutation-flight.ts +71 -0
  298. package/src/integrations/native/ownership-preflight.ts +202 -0
  299. package/src/integrations/omp-yaml-source.ts +358 -0
  300. package/src/integrations/owned-refresh.ts +74 -0
  301. package/src/integrations/ownership-policy.ts +160 -0
  302. package/src/integrations/ownership.ts +155 -0
  303. package/src/integrations/registry.ts +166 -0
  304. package/src/integrations/serialize.ts +314 -0
  305. package/src/integrations/state.ts +433 -0
  306. package/src/integrations/store.ts +103 -0
  307. package/src/integrations/writer-lock.ts +98 -0
  308. package/src/integrations/writer.ts +715 -0
  309. package/src/lab/artifacts/sanitize.ts +586 -0
  310. package/src/lab/artifacts/secure-fs.ts +475 -0
  311. package/src/lab/artifacts/store.ts +310 -0
  312. package/src/lab/automation/budgets.ts +78 -0
  313. package/src/lab/automation/config-persistence.ts +256 -0
  314. package/src/lab/automation/constants.ts +39 -0
  315. package/src/lab/automation/cooldown.ts +103 -0
  316. package/src/lab/automation/dispatch.ts +211 -0
  317. package/src/lab/automation/index.ts +13 -0
  318. package/src/lab/automation/orchestrator.ts +499 -0
  319. package/src/lab/automation/persistence.ts +512 -0
  320. package/src/lab/automation/planner.ts +371 -0
  321. package/src/lab/automation/policy.ts +136 -0
  322. package/src/lab/automation/queue.ts +191 -0
  323. package/src/lab/automation/recovery.ts +24 -0
  324. package/src/lab/automation/route-context.ts +21 -0
  325. package/src/lab/automation/run-key.ts +44 -0
  326. package/src/lab/automation/runs-query.ts +34 -0
  327. package/src/lab/automation/types.ts +160 -0
  328. package/src/lab/conformance/assertion.ts +325 -0
  329. package/src/lab/conformance/digest.ts +22 -0
  330. package/src/lab/conformance/executor.ts +741 -0
  331. package/src/lab/conformance/fixture-provider.ts +27 -0
  332. package/src/lab/conformance/fixtures/live-v1-cases.json +175 -0
  333. package/src/lab/conformance/fixtures/protocol-v1-cases.json +461 -0
  334. package/src/lab/conformance/harness-budget.ts +47 -0
  335. package/src/lab/conformance/index.ts +5 -0
  336. package/src/lab/conformance/jcs.ts +64 -0
  337. package/src/lab/conformance/json-pointer.ts +39 -0
  338. package/src/lab/conformance/manifest.ts +180 -0
  339. package/src/lab/conformance/mcp-stub.ts +179 -0
  340. package/src/lab/conformance/negative-controls.ts +164 -0
  341. package/src/lab/conformance/observation.ts +355 -0
  342. package/src/lab/conformance/runner.ts +68 -0
  343. package/src/lab/conformance/sse-normalize.ts +59 -0
  344. package/src/lab/conformance/suite-manifest.ts +78 -0
  345. package/src/lab/conformance/types.ts +214 -0
  346. package/src/lab/constants.ts +126 -0
  347. package/src/lab/digest.ts +64 -0
  348. package/src/lab/events/errors.ts +9 -0
  349. package/src/lab/events/limits.ts +117 -0
  350. package/src/lab/events/types.ts +229 -0
  351. package/src/lab/events/validate.ts +781 -0
  352. package/src/lab/fabric/constants.ts +40 -0
  353. package/src/lab/fabric/executor.ts +492 -0
  354. package/src/lab/fabric/index.ts +80 -0
  355. package/src/lab/fabric/manifest.ts +222 -0
  356. package/src/lab/fabric/observe.ts +489 -0
  357. package/src/lab/fabric/patch.ts +79 -0
  358. package/src/lab/fabric/producer-child.ts +139 -0
  359. package/src/lab/fabric/producer-isolate.ts +276 -0
  360. package/src/lab/fabric/producer-protocol.ts +61 -0
  361. package/src/lab/fabric/scratch.ts +439 -0
  362. package/src/lab/fabric/subject.ts +106 -0
  363. package/src/lab/fabric/types.ts +134 -0
  364. package/src/lab/fabric/verifier.ts +98 -0
  365. package/src/lab/index.ts +54 -0
  366. package/src/lab/ledger/artifact-refs.ts +127 -0
  367. package/src/lab/ledger/invalidation.ts +136 -0
  368. package/src/lab/ledger/purge.ts +310 -0
  369. package/src/lab/ledger/store.ts +532 -0
  370. package/src/lab/live/credential-lease.ts +53 -0
  371. package/src/lab/live/destination.ts +155 -0
  372. package/src/lab/live/executor.ts +336 -0
  373. package/src/lab/live/inert-tools.ts +56 -0
  374. package/src/lab/live/manifest.ts +85 -0
  375. package/src/lab/live/mcp-loopback.ts +57 -0
  376. package/src/lab/live/runner.ts +19 -0
  377. package/src/lab/live/sandbox.ts +61 -0
  378. package/src/lab/live/suite-manifest.ts +41 -0
  379. package/src/lab/live/transport.ts +118 -0
  380. package/src/lab/live/types.ts +197 -0
  381. package/src/lab/observe/from-conformance.ts +301 -0
  382. package/src/lab/observe/from-live.ts +117 -0
  383. package/src/lab/paths.ts +153 -0
  384. package/src/lab/projection/rebuild.ts +495 -0
  385. package/src/lab/projection/schema.ts +135 -0
  386. package/src/lab/projection/verdicts.ts +474 -0
  387. package/src/lab/projection/verification.ts +412 -0
  388. package/src/lab/public/bundle.ts +217 -0
  389. package/src/lab/public/community-authority.ts +175 -0
  390. package/src/lab/public/community-files.ts +29 -0
  391. package/src/lab/public/community.ts +479 -0
  392. package/src/lab/public/file-safety.ts +155 -0
  393. package/src/lab/public/ids.ts +26 -0
  394. package/src/lab/public/index.ts +16 -0
  395. package/src/lab/public/mutation-lock.ts +424 -0
  396. package/src/lab/public/operator.ts +353 -0
  397. package/src/lab/public/origin-purge.ts +79 -0
  398. package/src/lab/public/origin.ts +203 -0
  399. package/src/lab/public/privacy.ts +143 -0
  400. package/src/lab/public/private-file.ts +261 -0
  401. package/src/lab/public/project.ts +124 -0
  402. package/src/lab/public/purge-test-fault.ts +21 -0
  403. package/src/lab/public/purge.ts +223 -0
  404. package/src/lab/public/registry.ts +44 -0
  405. package/src/lab/public/revocation.ts +252 -0
  406. package/src/lab/public/signature.ts +243 -0
  407. package/src/lab/public/storage.ts +105 -0
  408. package/src/lab/public/strict-json.ts +206 -0
  409. package/src/lab/public/time.ts +26 -0
  410. package/src/lab/public/types.ts +172 -0
  411. package/src/lab/public/validate.ts +391 -0
  412. package/src/lab/query/catalog.ts +101 -0
  413. package/src/lab/query/connection.ts +107 -0
  414. package/src/lab/query/constants.ts +4 -0
  415. package/src/lab/query/cursor.ts +132 -0
  416. package/src/lab/query/dto-map.ts +277 -0
  417. package/src/lab/query/errors.ts +22 -0
  418. package/src/lab/query/freshness.ts +53 -0
  419. package/src/lab/query/index.ts +45 -0
  420. package/src/lab/query/latest-observation.ts +59 -0
  421. package/src/lab/query/passive-production.ts +159 -0
  422. package/src/lab/query/queries.ts +444 -0
  423. package/src/lab/query/types.ts +266 -0
  424. package/src/lab/subject/behavior-fingerprint.ts +77 -0
  425. package/src/lab/subject/installation-salt.ts +112 -0
  426. package/src/lab/subject/protocol-subject.ts +80 -0
  427. package/src/lab/subject/route-subject.ts +74 -0
  428. package/src/lib/admin-secrets.ts +24 -0
  429. package/src/lib/app-owned-memory-stores.ts +22 -0
  430. package/src/lib/bounded-body.ts +167 -11
  431. package/src/lib/bun-runtime.ts +125 -12
  432. package/src/lib/bun-stream-caps.ts +13 -9
  433. package/src/lib/codex-restart-contract.ts +120 -0
  434. package/src/lib/config-ownership.ts +26 -2
  435. package/src/lib/destination-policy.ts +65 -1
  436. package/src/lib/errors.ts +80 -5
  437. package/src/lib/fabric-task-execution-authority.ts +7 -0
  438. package/src/lib/fabric-task-host.ts +29 -0
  439. package/src/lib/lab-activation.ts +223 -0
  440. package/src/lib/lab-live-execution-authority.ts +13 -0
  441. package/src/lib/lab-live-host.ts +30 -0
  442. package/src/lib/lab-live-pinned-sender.ts +56 -0
  443. package/src/lib/lab-live-route-production.ts +130 -0
  444. package/src/lib/lab-passive-linker-registration.ts +26 -0
  445. package/src/lib/local-management-attestation.ts +51 -0
  446. package/src/lib/local-management-capability.ts +100 -0
  447. package/src/lib/local-provider-reload-contract.ts +100 -0
  448. package/src/lib/optional-shutdown-hooks.ts +57 -0
  449. package/src/lib/package-tree-integrity.ts +101 -0
  450. package/src/lib/pinned-http.ts +145 -26
  451. package/src/lib/process-control.ts +6 -2
  452. package/src/lib/provider-outbound.ts +49 -9
  453. package/src/lib/redact.ts +419 -3
  454. package/src/lib/self-launch-argv.ts +15 -0
  455. package/src/lib/server-resource-ownership.ts +71 -0
  456. package/src/lib/service-secrets.ts +15 -0
  457. package/src/lib/shadow-call.ts +35 -4
  458. package/src/lib/sse-decoder.ts +41 -0
  459. package/src/lib/state-store-registrations.ts +10 -2
  460. package/src/lib/system-restart-contract.ts +73 -0
  461. package/src/lib/token-estimate.ts +19 -2
  462. package/src/lib/tool-argument-integers.ts +253 -0
  463. package/src/lib/translator-budget.ts +44 -0
  464. package/src/lib/upstream-http-version.ts +57 -0
  465. package/src/lib/upstream-reachability.ts +95 -0
  466. package/src/lib/upstream-retry.ts +156 -3
  467. package/src/lib/windows-atomic-replace.ts +155 -0
  468. package/src/lib/windows-elevation.ts +70 -2
  469. package/src/lib/windows-secret-acl.ts +409 -69
  470. package/src/lib/windows-service-wrappers.ts +72 -0
  471. package/src/lib/windows-text.ts +106 -0
  472. package/src/lib/windows-user-principal.ts +341 -0
  473. package/src/lib/winsw.ts +33 -5
  474. package/src/oauth/account-import/google-antigravity-adapter.ts +74 -0
  475. package/src/oauth/account-import/index.ts +15 -0
  476. package/src/oauth/account-import/parser.ts +83 -0
  477. package/src/oauth/account-import/registry.ts +18 -0
  478. package/src/oauth/account-import/service.ts +75 -0
  479. package/src/oauth/account-import/types.ts +91 -0
  480. package/src/oauth/anthropic.ts +12 -1
  481. package/src/oauth/callback-server.ts +30 -4
  482. package/src/oauth/chatgpt.ts +12 -1
  483. package/src/oauth/cline.ts +203 -0
  484. package/src/oauth/command-code.ts +239 -0
  485. package/src/oauth/cursor.ts +46 -5
  486. package/src/oauth/generic-account-failover.ts +231 -0
  487. package/src/oauth/google-antigravity.ts +35 -3
  488. package/src/oauth/health.ts +20 -12
  489. package/src/oauth/index.ts +462 -71
  490. package/src/oauth/key-providers.ts +25 -0
  491. package/src/oauth/kimi.ts +25 -3
  492. package/src/oauth/kiro.ts +95 -6
  493. package/src/oauth/local-token-detect.ts +13 -2
  494. package/src/oauth/log.ts +3 -1
  495. package/src/oauth/login-cli.ts +88 -28
  496. package/src/oauth/nous.ts +798 -0
  497. package/src/oauth/open-browser-choice.ts +26 -0
  498. package/src/oauth/store.ts +133 -26
  499. package/src/oauth/token-guardian.ts +9 -3
  500. package/src/oauth/types.ts +15 -0
  501. package/src/pi/models.ts +2 -2
  502. package/src/providers/alibaba-region-migration.ts +1 -1
  503. package/src/providers/antigravity-models.ts +521 -31
  504. package/src/providers/auto-compact-budget.ts +65 -0
  505. package/src/providers/base-url-choices.ts +10 -0
  506. package/src/providers/codex-capacity.ts +292 -0
  507. package/src/providers/command-code-efforts.ts +176 -0
  508. package/src/providers/context-cap.ts +26 -8
  509. package/src/providers/cursor-pool.ts +72 -0
  510. package/src/providers/default-aliases.ts +65 -0
  511. package/src/providers/derive.ts +281 -6
  512. package/src/providers/fastwire.ts +507 -0
  513. package/src/providers/free-directory.ts +10 -7
  514. package/src/providers/google-vertex-location.ts +14 -0
  515. package/src/providers/key-failover.ts +71 -3
  516. package/src/providers/label.ts +35 -2
  517. package/src/providers/model-discovery-limits.ts +16 -0
  518. package/src/providers/model-discovery.ts +115 -22
  519. package/src/providers/model-presets.ts +119 -0
  520. package/src/providers/model-rename-migration.ts +255 -0
  521. package/src/providers/model-rename-startup.ts +28 -0
  522. package/src/providers/new-model-policy.ts +146 -0
  523. package/src/providers/openai-sidecar.ts +72 -4
  524. package/src/providers/openai-tier-startup.ts +31 -2
  525. package/src/providers/openai-tiers.ts +119 -4
  526. package/src/providers/openai-virtual-models.ts +1 -0
  527. package/src/providers/opencode-zen-rate-limit.ts +102 -0
  528. package/src/providers/provider-id-rewrite.ts +30 -0
  529. package/src/providers/quota.ts +1379 -40
  530. package/src/providers/registry.ts +1545 -112
  531. package/src/providers/request-pacing.ts +310 -0
  532. package/src/providers/service-tier.ts +277 -0
  533. package/src/providers/slug-codec.ts +94 -6
  534. package/src/providers/static-model-discovery.ts +86 -0
  535. package/src/providers/xai-responses-opt-in.ts +15 -0
  536. package/src/providers/xai-transport.ts +32 -4
  537. package/src/reasoning-effort.ts +68 -3
  538. package/src/responses/apply-patch-envelope.ts +63 -0
  539. package/src/responses/code-mode-helper-compat.ts +50 -0
  540. package/src/responses/compaction.ts +26 -1
  541. package/src/responses/custom-tool-compat.ts +384 -0
  542. package/src/responses/hosted-tool-policy.ts +9 -0
  543. package/src/responses/namespace-tool-compat.ts +435 -0
  544. package/src/responses/parser.ts +225 -38
  545. package/src/responses/provider-continuation.ts +98 -0
  546. package/src/responses/provider-opaque-metadata.ts +73 -0
  547. package/src/responses/reasoning-envelope.ts +9 -1
  548. package/src/responses/reasoning-replay-cache.ts +504 -0
  549. package/src/responses/schema.ts +12 -2
  550. package/src/responses/spill-store.ts +75 -10
  551. package/src/responses/state.ts +659 -31
  552. package/src/responses/thought-signature-replay.ts +364 -0
  553. package/src/responses/tool-search-compat.ts +301 -0
  554. package/src/responses/truncated-stop-reason.ts +60 -0
  555. package/src/responses/turn-termination.ts +107 -0
  556. package/src/router.ts +405 -31
  557. package/src/routing/analytics.ts +379 -0
  558. package/src/routing/capability.ts +244 -0
  559. package/src/routing/compatibility/assemble.ts +73 -0
  560. package/src/routing/compatibility/behavior.ts +278 -0
  561. package/src/routing/compatibility/catalog.ts +99 -0
  562. package/src/routing/compatibility/endpoint.ts +52 -0
  563. package/src/routing/compatibility/lab-evidence-provider.ts +130 -0
  564. package/src/routing/compatibility/policy.ts +181 -0
  565. package/src/routing/compatibility/provider-slot.ts +56 -0
  566. package/src/routing/compatibility/reader.ts +110 -0
  567. package/src/routing/compatibility/subject.ts +191 -0
  568. package/src/routing/compatibility/types.ts +64 -0
  569. package/src/routing/compatibility/version.ts +104 -0
  570. package/src/routing/cost.ts +77 -0
  571. package/src/routing/evaluator.ts +495 -0
  572. package/src/routing/health.ts +412 -0
  573. package/src/routing/history/cursor.ts +43 -0
  574. package/src/routing/history/indexer.ts +605 -0
  575. package/src/routing/history/schema.ts +72 -0
  576. package/src/routing/profile-namespace.ts +15 -0
  577. package/src/routing/profile.ts +547 -0
  578. package/src/routing/quota.ts +155 -0
  579. package/src/routing/request-evidence.ts +45 -0
  580. package/src/routing/trace.ts +776 -0
  581. package/src/server/adapter-resolve.ts +2 -29
  582. package/src/server/auth-cors.ts +289 -48
  583. package/src/server/background-lifecycle.ts +182 -0
  584. package/src/server/chat-completions.ts +154 -72
  585. package/src/server/chat-native-sse.ts +331 -0
  586. package/src/server/chat-native.ts +445 -0
  587. package/src/server/claude-messages.ts +160 -44
  588. package/src/server/direct-local-http.ts +347 -0
  589. package/src/server/effort-policy.ts +18 -0
  590. package/src/server/github-copilot-responses-repair.ts +338 -0
  591. package/src/server/gui-static.ts +39 -10
  592. package/src/server/images.ts +94 -12
  593. package/src/server/index.ts +1021 -190
  594. package/src/server/lifecycle.ts +336 -14
  595. package/src/server/live.ts +136 -17
  596. package/src/server/local-management-read-client.ts +90 -0
  597. package/src/server/local-provider-reload-client.ts +137 -0
  598. package/src/server/management/agent-settings-routes.ts +433 -116
  599. package/src/server/management/api-key-usage.ts +31 -5
  600. package/src/server/management/body.ts +6 -0
  601. package/src/server/management/codex-prompt-routes.ts +570 -0
  602. package/src/server/management/combo-routes.ts +64 -25
  603. package/src/server/management/config-routes.ts +511 -51
  604. package/src/server/management/context.ts +89 -2
  605. package/src/server/management/integration-routes.ts +498 -0
  606. package/src/server/management/lab-automation-routes.ts +206 -0
  607. package/src/server/management/lab-routes.ts +563 -0
  608. package/src/server/management/logs-usage-routes.ts +127 -52
  609. package/src/server/management/model-routes.ts +461 -133
  610. package/src/server/management/model-rows.ts +167 -0
  611. package/src/server/management/native-integration-routes.ts +770 -0
  612. package/src/server/management/oauth-account-routes.ts +90 -8
  613. package/src/server/management/provider-capability-config.ts +48 -0
  614. package/src/server/management/provider-routes.ts +836 -159
  615. package/src/server/management/request-history-routes.ts +191 -0
  616. package/src/server/management/route-registry.ts +332 -0
  617. package/src/server/management/routing-analytics-routes.ts +74 -0
  618. package/src/server/management/routing-profile-routes.ts +380 -0
  619. package/src/server/management/shared.ts +27 -11
  620. package/src/server/management/sidebar-routes.ts +47 -31
  621. package/src/server/management/storage-log-guard-routes.ts +186 -0
  622. package/src/server/management/sync-response.ts +69 -0
  623. package/src/server/management/system-restart.ts +289 -33
  624. package/src/server/management/system-routes.ts +77 -0
  625. package/src/server/management/usage-summary-cache.ts +9 -1
  626. package/src/server/management/vision-sidecar-options.ts +167 -0
  627. package/src/server/management/web-search-sidecar-options.ts +120 -0
  628. package/src/server/management-api.ts +126 -23
  629. package/src/server/management-auth.ts +220 -5
  630. package/src/server/passive-route-linker.ts +66 -0
  631. package/src/server/port-reclaim.ts +1 -1
  632. package/src/server/ports.ts +41 -1
  633. package/src/server/proxy-liveness.ts +161 -10
  634. package/src/server/readiness.ts +99 -0
  635. package/src/server/relay-eager.ts +221 -54
  636. package/src/server/relay.ts +479 -87
  637. package/src/server/request-decompress.ts +113 -6
  638. package/src/server/request-log-conversation.ts +51 -0
  639. package/src/server/request-log.ts +298 -31
  640. package/src/server/responses/agent-task-recovery-cache.ts +143 -0
  641. package/src/server/responses/agent-task-recovery.ts +465 -0
  642. package/src/server/responses/codex-auth-error.ts +55 -0
  643. package/src/server/responses/collaboration.ts +239 -36
  644. package/src/server/responses/combo-stream-preflight.ts +178 -0
  645. package/src/server/responses/compact.ts +444 -72
  646. package/src/server/responses/core.ts +3579 -436
  647. package/src/server/responses/empty-completion-guard.ts +333 -0
  648. package/src/server/responses/encrypted-payload.ts +62 -39
  649. package/src/server/responses/fetch-helpers.ts +89 -99
  650. package/src/server/responses/input-admission.ts +187 -0
  651. package/src/server/responses/pacing-overload.ts +13 -0
  652. package/src/server/responses/passthrough-error.ts +33 -9
  653. package/src/server/responses/policy-fallback.ts +178 -0
  654. package/src/server/responses/responses-field-backfill.ts +343 -0
  655. package/src/server/responses/terminal-guard.ts +26 -5
  656. package/src/server/responses/upstream-error.ts +5 -0
  657. package/src/server/responses/ws-upstream.ts +381 -0
  658. package/src/server/responses-custom-tool-repair.ts +363 -0
  659. package/src/server/responses-item-id-repair.ts +54 -6
  660. package/src/server/responses-json-events.ts +90 -0
  661. package/src/server/responses-model-rewrite.ts +29 -0
  662. package/src/server/responses-reasoning-summary-rewrite.ts +178 -0
  663. package/src/server/responses-snapshot-repair.ts +621 -0
  664. package/src/server/responses-terminal-repair.ts +363 -0
  665. package/src/server/responses-tool-search-repair.ts +267 -0
  666. package/src/server/responses-undeclared-tool-guard.ts +376 -0
  667. package/src/server/responses.ts +18 -2
  668. package/src/server/search.ts +78 -13
  669. package/src/server/sse-frame-buffer.ts +319 -0
  670. package/src/server/sse-payload-rewrite.ts +110 -22
  671. package/src/server/startup-action-control.ts +8 -1
  672. package/src/server/startup-health-cache.ts +19 -1
  673. package/src/server/system-env.ts +80 -9
  674. package/src/server/ws-bridge.ts +53 -40
  675. package/src/service-manager-probe.ts +892 -0
  676. package/src/service.ts +1153 -94
  677. package/src/sidecar/auth.ts +92 -0
  678. package/src/sidecar/candidates.ts +83 -0
  679. package/src/storage/cleanup.ts +2 -2
  680. package/src/storage/policy-job.ts +14 -4
  681. package/src/storage/policy.ts +88 -23
  682. package/src/storage/scanner.ts +1 -1
  683. package/src/storage/worker-lifecycle.ts +14 -14
  684. package/src/tray/windows-tray.ps1 +83 -9
  685. package/src/tray/windows.ts +43 -16
  686. package/src/types/accounts.ts +37 -0
  687. package/src/types/config.ts +911 -0
  688. package/src/types/provider.ts +614 -0
  689. package/src/types/request.ts +397 -0
  690. package/src/types/tools.ts +236 -0
  691. package/src/types/wire.ts +80 -0
  692. package/src/types.ts +107 -1237
  693. package/src/update/index.ts +37 -23
  694. package/src/update/job.ts +445 -68
  695. package/src/update/notify.ts +12 -6
  696. package/src/update/npm-cache-preflight.d.mts +47 -0
  697. package/src/update/npm-cache-preflight.mjs +201 -0
  698. package/src/update/transactional-install.d.mts +22 -0
  699. package/src/update/transactional-install.mjs +266 -0
  700. package/src/usage/cost.ts +0 -0
  701. package/src/usage/expected-prices.ts +287 -16
  702. package/src/usage/log.ts +666 -50
  703. package/src/usage/summary.ts +388 -17
  704. package/src/usage/user-cost-overlay-reconciler.ts +313 -0
  705. package/src/usage/user-cost-overlays.ts +314 -0
  706. package/src/vision/anthropic-describe.ts +10 -6
  707. package/src/vision/backends.ts +97 -0
  708. package/src/vision/describe.ts +27 -16
  709. package/src/vision/eligibility.ts +250 -0
  710. package/src/vision/index.ts +238 -24
  711. package/src/vision/reasoning.ts +55 -0
  712. package/src/vision/routed-describe.ts +175 -0
  713. package/src/vision/timeout-bounds.ts +9 -0
  714. package/src/web-search/anthropic-executor.ts +13 -7
  715. package/src/web-search/backends.ts +108 -0
  716. package/src/web-search/exa-executor.ts +119 -0
  717. package/src/web-search/executor.ts +21 -6
  718. package/src/web-search/gemini-executor.ts +141 -0
  719. package/src/web-search/index.ts +150 -15
  720. package/src/web-search/loop.ts +284 -54
  721. package/src/web-search/parse.ts +125 -30
  722. package/src/web-search/sources.ts +60 -0
  723. package/src/web-search/xai-executor.ts +219 -0
  724. package/gui/dist/assets/index-DTpMHS4F.js +0 -67
  725. package/gui/dist/assets/index-ZNVDE3C7.css +0 -1
  726. package/gui/dist/provider-icons/antigravity.svg +0 -1
  727. package/gui/dist/provider-icons/claude.svg +0 -1
  728. package/gui/dist/provider-icons/copilot.svg +0 -1
  729. package/gui/dist/provider-icons/cursor.svg +0 -2
  730. package/gui/dist/provider-icons/gemini.svg +0 -1
  731. package/gui/dist/provider-icons/grok-color.svg +0 -1
  732. package/gui/dist/provider-icons/kiro.svg +0 -14
  733. package/src/cli/internal-dispatch.ts +0 -20
@@ -3,16 +3,30 @@ import { ValueSchema } from "@bufbuild/protobuf/wkt";
3
3
  import type { OcxRequestOptions, OcxTool } from "../../types";
4
4
  import { namespacedToolName, toolChoiceAliases } from "../../types";
5
5
  import { McpToolDefinitionSchema, McpToolsSchema, type McpToolDefinition } from "./gen/agent_pb";
6
+ import { CODE_MODE_RESULT_ECHO_SENTENCE } from "../exec-tool-result-normalize";
6
7
 
7
8
  export const OCX_RESPONSES_TOOL_PROVIDER = "opencodex-responses";
8
9
  export const CODEX_EXEC_COMMAND_TOOL = "exec_command";
9
10
  export const CODEX_SHELL_COMMAND_TOOL = "shell_command";
11
+ /** Codex Desktop unified-exec client tool. Companion of `wait`; not an `exec_command` schema alias. */
12
+ export const CODEX_UNIFIED_EXEC_TOOL = "exec";
13
+ export const CODEX_WAIT_TOOL = "wait";
10
14
  export const CODEX_APPLY_PATCH_TOOL = "apply_patch";
15
+ export const CURSOR_EDIT_FILE_TOOL = "edit_file";
16
+ export const CURSOR_MULTI_EDIT_TOOL = "multi_edit";
17
+ export const CURSOR_STRUCTURED_EDIT_TOOLS = [CURSOR_EDIT_FILE_TOOL, CURSOR_MULTI_EDIT_TOOL] as const;
11
18
  export const CURSOR_EXEC_COMMAND_TOOL = CODEX_EXEC_COMMAND_TOOL;
12
19
  export const CODEX_SHELL_BRIDGE_TOOL_NAMES = [CODEX_EXEC_COMMAND_TOOL, CODEX_SHELL_COMMAND_TOOL] as const;
13
20
  export const CURSOR_SHELL_ALIAS_SYSTEM_NOTE =
14
- 'Shell commands use the Codex shell bridge tool shown in this turn\'s catalog (`shell_command` or `exec_command`) with JSON arguments like {"cmd":"..."}. The long `mcp_opencodex-responses_*` display name is the same tool. Prefer it over Cursor-native Shell; never say native shell is blocked.';
21
+ 'Shell commands use the Codex shell bridge tool shown in this turn\'s catalog (`shell_command` or `exec_command`) with JSON arguments like {"cmd":"..."}. The long `mcp_opencodex-responses_*` display name is the same tool. Prefer it over Cursor-native Shell.';
15
22
  const NEIGHBOR_AGENT_TOOL_NAMES = ["Read", "Grep", "Glob", "Bash", "LS"] as const;
23
+ const NEIGHBOR_AGENT_TOOL_ALIASES: Record<(typeof NEIGHBOR_AGENT_TOOL_NAMES)[number], readonly string[]> = {
24
+ Read: ["read", "read_file"],
25
+ Grep: ["grep"],
26
+ Glob: ["glob", "find"],
27
+ Bash: ["bash", "shell"],
28
+ LS: ["ls"],
29
+ };
16
30
 
17
31
  export const CURSOR_GENERIC_TOOL_USE_USER_HINT = [
18
32
  "For generic tool-use/count demos, satisfy the request with repeated Codex shell bridge calls (`shell_command` or `exec_command`) for harmless commands.",
@@ -23,8 +37,7 @@ export const CURSOR_GENERIC_TOOL_USE_USER_HINT = [
23
37
  "The Cursor bridge may suspend after the first returned bridge tool call, so emit sibling calls together before any result is needed.",
24
38
  "If parallel emission is unavailable, continue with separate shell-bridge calls until the requested count has returned.",
25
39
  "Do not use `tool_search`, external MCP, or resource discovery just to pad the count unless explicitly asked.",
26
- "Do not suggest or switch to neighboring-agent tools such as `Grep`, `Read`, `Glob`, `Bash`, or `LS` unless this turn's catalog lists those exact names.",
27
- "Never tell the user that shell or read access is blocked, disabled, or denied unless the Codex shell bridge tool itself fails. Do not narrate Cursor-native Shell/Read routing.",
40
+ "Do not suggest or switch to neighboring-agent tools such as `Grep`, `Read`, `Glob`, `Bash`, or `LS` unless this turn's catalog lists those exact names or an equivalent listed client tool.",
28
41
  ].join(" ");
29
42
 
30
43
  export const CURSOR_EXEC_COMMAND_INPUT_SCHEMA = {
@@ -41,6 +54,47 @@ export const CURSOR_EXEC_COMMAND_INPUT_SCHEMA = {
41
54
  additionalProperties: false,
42
55
  } as const;
43
56
 
57
+ /**
58
+ * Structured single-replacement schema advertised to Cursor models in addition to the freeform
59
+ * `apply_patch` tool. Cursor-trained models reliably emit exact-match replacements (the native
60
+ * Edit shape) but cannot produce Codex's freeform patch grammar, so every file edit attempt on the
61
+ * Cursor route produced malformed `apply_patch` payloads that the Codex client rejected locally
62
+ * (#1017). Calls to this tool are converted server-side into a valid apply_patch payload.
63
+ */
64
+ export const CURSOR_EDIT_FILE_INPUT_SCHEMA = {
65
+ type: "object",
66
+ properties: {
67
+ file_path: { type: "string", description: "Path of the file to edit, relative to the workspace root." },
68
+ old_string: { type: "string", description: "Exact text to replace. Must match the current file content, including line breaks." },
69
+ new_string: { type: "string", description: "Replacement text. Empty removes the matched text." },
70
+ },
71
+ required: ["file_path", "old_string", "new_string"],
72
+ additionalProperties: false,
73
+ } as const;
74
+
75
+ /** Structured multi-replacement schema; mirrors Cursor's native MultiEdit shape. */
76
+ export const CURSOR_MULTI_EDIT_INPUT_SCHEMA = {
77
+ type: "object",
78
+ properties: {
79
+ file_path: { type: "string", description: "Path of the file to edit, relative to the workspace root." },
80
+ edits: {
81
+ type: "array",
82
+ items: {
83
+ type: "object",
84
+ properties: {
85
+ old_string: { type: "string", description: "Exact text to replace. Must match the current file content, including line breaks." },
86
+ new_string: { type: "string", description: "Replacement text. Empty removes the matched text." },
87
+ },
88
+ required: ["old_string", "new_string"],
89
+ additionalProperties: false,
90
+ },
91
+ description: "Ordered replacement edits for this file. Each old_string must match the current file content.",
92
+ },
93
+ },
94
+ required: ["file_path", "edits"],
95
+ additionalProperties: false,
96
+ } as const;
97
+
44
98
  /**
45
99
  * Responses/Codex-side schema used ONLY for arg-key normalization after Cursor returns a call.
46
100
  * Cursor models are trained to emit `cmd`; Codex `shell_command` / `exec_command` validate
@@ -123,6 +177,59 @@ export function isBareCodexShellBridgeTool(tool: Pick<OcxTool, "namespace" | "na
123
177
  return !tool.namespace && isCodexShellBridgeToolName(tool.name);
124
178
  }
125
179
 
180
+ function isCursorResponsesProvider(namespace: string | undefined): boolean {
181
+ return !namespace || namespace === OCX_RESPONSES_TOOL_PROVIDER;
182
+ }
183
+
184
+ const CURSOR_EXECUTION_PATH_TOOL_NAMES = [
185
+ CODEX_UNIFIED_EXEC_TOOL,
186
+ CODEX_EXEC_COMMAND_TOOL,
187
+ CODEX_SHELL_COMMAND_TOOL,
188
+ ] as const;
189
+
190
+ /** True for the Codex execution path that must survive Cursor transport truncation. */
191
+ export function isCursorExecutionPathTool(tool: Pick<OcxTool, "namespace" | "name">): boolean {
192
+ return isCursorResponsesProvider(tool.namespace)
193
+ && (CURSOR_EXECUTION_PATH_TOOL_NAMES as readonly string[]).includes(tool.name);
194
+ }
195
+
196
+ /** `wait` only resumes a yielded exec cell; it is unusable without an execution-path tool. */
197
+ export function isCursorWaitTool(tool: Pick<OcxTool, "namespace" | "name">): boolean {
198
+ return isCursorResponsesProvider(tool.namespace) && tool.name === CODEX_WAIT_TOOL;
199
+ }
200
+
201
+ /**
202
+ * True for Codex's unified-exec "code mode" tool: a freeform `exec` whose body is JavaScript
203
+ * evaluated in a V8 isolate, not a shell command string.
204
+ */
205
+ export function isCursorCodeModeExecTool(
206
+ tool: Pick<OcxTool, "namespace" | "name" | "freeform">,
207
+ ): boolean {
208
+ return isCursorResponsesProvider(tool.namespace)
209
+ && tool.name === CODEX_UNIFIED_EXEC_TOOL
210
+ && tool.freeform === true;
211
+ }
212
+
213
+ /**
214
+ * Codex code mode advertises ONE freeform `exec` tool and no bare shell bridge. Shell, file
215
+ * edits, and MCP calls are reachable only as nested `tools.<name>(...)` helpers described inside
216
+ * that tool's own description, so a flat catalog scan cannot see them.
217
+ *
218
+ * This matters because the shell-bridge guidance below is written for a flat catalog. Emitting
219
+ * "call \`exec_command\`" into a code-mode turn names a top-level tool that does not exist: the
220
+ * model calls it, gets nothing back, and burns turns rediscovering the real contract from error
221
+ * messages (empty output until \`text()\` is called, \`require is not defined\` because the isolate
222
+ * is not Node, \`apply_patch\` rejected because it too is only a nested helper here).
223
+ */
224
+ export function cursorRequestUsesCodeMode(
225
+ tools: readonly Pick<OcxTool, "namespace" | "name" | "freeform">[] | undefined,
226
+ toolChoice?: OcxRequestOptions["toolChoice"],
227
+ ): boolean {
228
+ const catalog = tools ?? [];
229
+ const visible = catalog.filter(tool => cursorToolAllowedByChoice(tool, toolChoice, catalog));
230
+ return visible.some(isCursorCodeModeExecTool) && !visible.some(isBareCodexShellBridgeTool);
231
+ }
232
+
126
233
  /** @deprecated Prefer isBareCodexShellBridgeTool; kept for older call sites/tests. */
127
234
  function isBareCodexExecCommandTool(tool: Pick<OcxTool, "namespace" | "name">): boolean {
128
235
  return isBareCodexShellBridgeTool(tool);
@@ -132,6 +239,12 @@ export function cursorRequestHasShellAlias(tools: readonly Pick<OcxTool, "namesp
132
239
  return tools?.some(isBareCodexExecCommandTool) ?? false;
133
240
  }
134
241
 
242
+ function cursorRequestHasExecutionPath(
243
+ tools: readonly Pick<OcxTool, "namespace" | "name">[] | undefined,
244
+ ): boolean {
245
+ return tools?.some(isCursorExecutionPathTool) ?? false;
246
+ }
247
+
135
248
  export function cursorRequestAdvertisesApplyPatch(
136
249
  tools: readonly Pick<OcxTool, "namespace" | "name" | "freeform">[] | undefined,
137
250
  toolChoice?: OcxRequestOptions["toolChoice"],
@@ -140,6 +253,73 @@ export function cursorRequestAdvertisesApplyPatch(
140
253
  return catalog.some(tool => !tool.namespace && tool.name === CODEX_APPLY_PATCH_TOOL && tool.freeform === true && cursorToolAllowedByChoice(tool, toolChoice, catalog));
141
254
  }
142
255
 
256
+ export function isCursorStructuredEditToolName(name: string): boolean {
257
+ return (CURSOR_STRUCTURED_EDIT_TOOLS as readonly string[]).includes(name);
258
+ }
259
+
260
+ /** Internal provenance gate for synthetic edits after prompt filtering and catalog budgeting. */
261
+ export function isCursorSyntheticStructuredEditTool(
262
+ tool: Pick<OcxTool, "namespace" | "name" | "cursorStructuredEdit">,
263
+ ): boolean {
264
+ return !tool.namespace && tool.cursorStructuredEdit === true && isCursorStructuredEditToolName(tool.name);
265
+ }
266
+
267
+ /**
268
+ * Synthetic structured edit tools for the Cursor route (#1017).
269
+ *
270
+ * Codex exposes `apply_patch` as a freeform custom tool whose body must be the exact Codex patch
271
+ * grammar (`*** Begin Patch` envelope, `@@` hunks, `-`/`+` prefixes). Cursor-trained models are
272
+ * trained on exact-match edit tools instead and emit malformed patch text on every attempt, which
273
+ * the Codex client then rejects locally ("invalid hunk"). When the request advertises the freeform
274
+ * `apply_patch` tool, also advertise Cursor-native-shaped `edit_file` / `multi_edit` tools; the
275
+ * adapter converts their exact-match replacements into a valid apply_patch payload (see
276
+ * protobuf-events.translateStructuredEditCall).
277
+ *
278
+ * Never widened when the caller pinned an explicit tool choice: a forced `apply_patch` selection
279
+ * must not gain sibling tools the client did not ask for.
280
+ */
281
+ export function cursorStructuredEditTools(
282
+ tools: readonly Pick<OcxTool, "namespace" | "name" | "freeform">[] | undefined,
283
+ toolChoice?: OcxRequestOptions["toolChoice"],
284
+ ): OcxTool[] {
285
+ if (!cursorRequestAdvertisesApplyPatch(tools, toolChoice)) return [];
286
+ if (toolChoice && toolChoice !== "auto" && toolChoice !== "required") return [];
287
+ // Never shadow an already-advertised bare tool with the same name (a client catalog could
288
+ // legitimately expose its own `edit_file` / `multi_edit` MCP-style tools).
289
+ const existingBareNames = new Set(
290
+ (tools ?? []).filter(tool => !tool.namespace).map(tool => tool.name),
291
+ );
292
+ const candidates: OcxTool[] = [
293
+ {
294
+ name: CURSOR_EDIT_FILE_TOOL,
295
+ cursorStructuredEdit: true,
296
+ description:
297
+ "Replace one block of text in a file. OpenCodex converts the replacement into a Codex apply_patch change. Copy old_string and new_string with their exact leading whitespace — Codex may locate a line after trimming indent, but it writes new_string verbatim, so stripped indent silently corrupts the file. An empty old_string with a non-empty new_string creates a new file (Add File). If the same text appears more than once, the first match is updated. Matching is line-based, so an edit cannot add or remove only the file's final newline, and old_string/new_string that are identical after line normalization are rejected as a no-op.",
298
+ parameters: { ...CURSOR_EDIT_FILE_INPUT_SCHEMA },
299
+ },
300
+ {
301
+ name: CURSOR_MULTI_EDIT_TOOL,
302
+ cursorStructuredEdit: true,
303
+ description:
304
+ "Apply several text replacements to one file. OpenCodex converts them into one Codex apply_patch change. Copy each old_string/new_string with exact leading whitespace. If a later edit's old_string is the text after an earlier replacement, OpenCodex folds those edits into one original-file hunk. Independent edits stay separate hunks. An empty old_string with a non-empty new_string creates a new file (Add File); do not mix that with an independent Update on the same path. If the same text appears more than once, the first match is updated. Matching is line-based, so an edit cannot add or remove only the file's final newline, and identical old/new after line normalization are rejected as a no-op.",
305
+ parameters: { ...CURSOR_MULTI_EDIT_INPUT_SCHEMA },
306
+ },
307
+ ];
308
+ return candidates.filter(tool => !existingBareNames.has(tool.name));
309
+ }
310
+
311
+ /**
312
+ * True when this request actually advertises the synthetic structured edit tools (`edit_file` /
313
+ * `multi_edit`) — i.e. a freeform `apply_patch` is advertised, no tool-choice pin blocks widening,
314
+ * and neither name is shadowed by an existing bare tool in the client catalog.
315
+ */
316
+ export function cursorRequestAdvertisesStructuredEdits(
317
+ tools: readonly Pick<OcxTool, "namespace" | "name" | "freeform">[] | undefined,
318
+ toolChoice?: OcxRequestOptions["toolChoice"],
319
+ ): boolean {
320
+ return cursorStructuredEditTools(tools, toolChoice).length > 0;
321
+ }
322
+
143
323
  export function cursorToolWireName(tool: Pick<OcxTool, "namespace" | "name">): string {
144
324
  return namespacedToolName(tool.namespace, tool.name);
145
325
  }
@@ -157,6 +337,26 @@ export function normalizeCursorWireName(name: string): string {
157
337
  return name.startsWith(CURSOR_MCP_DISPLAY_PREFIX) ? name.slice(CURSOR_MCP_DISPLAY_PREFIX.length) : name;
158
338
  }
159
339
 
340
+ /**
341
+ * #2305: some models emit a TEXTUAL pseudo tool call ("[TOOL_CALL]name[ARGS]{...}")
342
+ * instead of a real frame, using Cursor's display alias as the name. Text-mode clients
343
+ * (Pi) parse that text and then cannot dispatch the undeclared display name. Rewrite the
344
+ * display alias to the advertised wire name ONLY inside the marker pair — prose that
345
+ * merely mentions the alias stays untouched, and the scope guard is the exact
346
+ * `mcp_${OCX_RESPONSES_TOOL_PROVIDER}_` prefix, never generic `mcp_`.
347
+ * Known limit (recorded in devlog 230): a marker split across two streaming deltas is
348
+ * not rewritten; tail-buffering is deferred until a live trace shows split markers.
349
+ */
350
+ const CURSOR_TEXT_TOOL_MARKER = new RegExp(
351
+ String.raw`\[TOOL_CALL\](${CURSOR_MCP_DISPLAY_PREFIX.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}[^\[\]]+)\[ARGS\]`,
352
+ "g",
353
+ );
354
+
355
+ export function normalizeCursorTextToolMarkers(text: string): string {
356
+ if (!text.includes(CURSOR_MCP_DISPLAY_PREFIX)) return text;
357
+ return text.replace(CURSOR_TEXT_TOOL_MARKER, (_match, name: string) => `[TOOL_CALL]${normalizeCursorWireName(name)}[ARGS]`);
358
+ }
359
+
160
360
  export function responsesToolNameFromCursorWire(name: string, cursorToolNameMap?: ReadonlyMap<string, string>): string {
161
361
  const normalized = normalizeCursorWireName(name);
162
362
  if (!cursorToolNameMap) return normalized;
@@ -286,7 +486,7 @@ export function shouldUseNativeExecOnlyForGenericToolUse(
286
486
  text: string,
287
487
  ): boolean {
288
488
  const trimmed = text.trim();
289
- if (trimmed.length === 0 || !cursorRequestHasShellAlias(tools) || !isGenericToolUseCountDemoPrompt(trimmed)) return false;
489
+ if (trimmed.length === 0 || !cursorRequestHasExecutionPath(tools) || !isGenericToolUseCountDemoPrompt(trimmed)) return false;
290
490
  return !/\b(?:mcp|resource|resources|tool_search|plugin|plugins|app connector|github)\b/i.test(trimmed)
291
491
  && !/(?:리소스|플러그인|깃허브|github)/i.test(trimmed);
292
492
  }
@@ -297,7 +497,7 @@ export function cursorToolsForActivePrompt<T extends Pick<OcxTool, "namespace" |
297
497
  toolChoice?: OcxRequestOptions["toolChoice"],
298
498
  ): readonly T[] | undefined {
299
499
  if (!shouldUseNativeExecOnlyForGenericToolUse(tools, activeText)) return tools;
300
- const execTools = tools?.filter(isBareCodexExecCommandTool);
500
+ const execTools = tools?.filter(isCursorExecutionPathTool);
301
501
  const catalog = tools ?? [];
302
502
  if (execTools?.length && !execTools.some(tool => cursorToolAllowedByChoice(tool, toolChoice, catalog))) return tools;
303
503
  return execTools && execTools.length > 0 ? execTools : tools;
@@ -352,7 +552,12 @@ export function nonEmptyShellBridgeCommandFromArgs(
352
552
  }
353
553
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return undefined;
354
554
  const record = parsed as Record<string, unknown>;
355
- for (const key of shellBridgeRequiredCommandKeys(toolName, schema)) {
555
+ const requiredKeys = shellBridgeRequiredCommandKeys(toolName, schema);
556
+ const candidateKeys = new Set<"cmd" | "command">([
557
+ ...requiredKeys,
558
+ requiredKeys.includes("cmd") ? "command" : "cmd",
559
+ ]);
560
+ for (const key of candidateKeys) {
356
561
  const value = record[key];
357
562
  if (typeof value === "string" && value.trim().length > 0) return value.trim();
358
563
  }
@@ -385,9 +590,14 @@ function quotedNames(names: readonly string[]): string {
385
590
  return names.map(name => `\`${name}\``).join(", ");
386
591
  }
387
592
 
593
+ function advertisedCoversNeighbor(wireNames: readonly string[], neighbor: (typeof NEIGHBOR_AGENT_TOOL_NAMES)[number]): boolean {
594
+ const advertised = new Set(wireNames.map(name => name.toLowerCase()));
595
+ if (advertised.has(neighbor.toLowerCase())) return true;
596
+ return NEIGHBOR_AGENT_TOOL_ALIASES[neighbor].some(alias => advertised.has(alias.toLowerCase()));
597
+ }
598
+
388
599
  function unavailableNeighborAgentToolNames(wireNames: readonly string[]): string[] {
389
- const advertised = new Set(wireNames);
390
- return NEIGHBOR_AGENT_TOOL_NAMES.filter(name => !advertised.has(name));
600
+ return NEIGHBOR_AGENT_TOOL_NAMES.filter(name => !advertisedCoversNeighbor(wireNames, name));
391
601
  }
392
602
 
393
603
  function discoveryToolLabel(wireNames: readonly string[]): string | undefined {
@@ -413,14 +623,25 @@ export function buildCursorToolGuidanceSystemNote(
413
623
  const listedNames = quotedNames(wireNames);
414
624
  const shellBridgeNames = wireNames.filter(isCodexShellBridgeToolName);
415
625
  const hasBareExec = shellBridgeNames.length > 0;
626
+ const codeMode = cursorRequestUsesCodeMode(tools, toolChoice);
627
+ // Code mode describes how the freeform exec tool works; it does not suppress the rest of the
628
+ // catalog. A turn can advertise freeform `exec` AND ordinary top-level tools at once, and
629
+ // telling the model those are "not separate top-level tools" would make it refuse tools that
630
+ // are right there in its catalog. Name the ones that stay callable instead.
631
+ const codeModeOtherTopLevelNames = codeMode
632
+ ? wireNames.filter(name => name !== CODEX_UNIFIED_EXEC_TOOL && !isCodexShellBridgeToolName(name))
633
+ : [];
416
634
  const shellBridgeLabel = quotedNames(shellBridgeNames.length > 0 ? shellBridgeNames : [...CODEX_SHELL_BRIDGE_TOOL_NAMES]);
417
635
  const hasApplyPatch = cursorRequestAdvertisesApplyPatch(tools, toolChoice);
636
+ const structuredEditNames = tools
637
+ ?.filter(tool => !tool.namespace && isCursorStructuredEditToolName(tool.name))
638
+ .map(tool => tool.name) ?? [];
418
639
  const discoveryTools = discoveryToolLabel(wireNames);
419
640
  const unavailableNeighborNames = unavailableNeighborAgentToolNames(wireNames);
420
641
  // Host-shell-neutral: the Codex client executes bridge commands, and may differ from
421
642
  // the OpenCodex proxy OS (LAN/SSH remote-proxy). Always cover PowerShell 5.1 pitfalls.
422
643
  const hostShellNote = hasBareExec
423
- ? "Match shell syntax to the Codex client host that runs the bridge (not only the proxy OS). Windows PowerShell 5.1: no CMD `cd /d`, no bash heredocs (`<<EOF`); `&&`/`||` are unsupported parser errors — prefer the bridge working-directory argument for directory changes, and use `if ($?) { ... }` for success-gated follow-up steps; do not treat `;` as a substitute for `&&`. POSIX: use portable commands. After a shell failure, make at most one corrected bridge attempt, then report the error and stop — do not repeat equivalent failing commands."
644
+ ? "Match shell syntax to the Codex client host that runs the bridge (not only the proxy OS). Windows PowerShell 5.1: no CMD `cd /d`, no bash heredocs (`<<EOF`); `&&`/`||` are unsupported parser errors — prefer the bridge working-directory argument for directory changes, and use `if ($?) { ... }` for success-gated follow-up steps; do not treat `;` as a substitute for `&&`. POSIX: use portable commands (`cat`/`ls`/`rg`); never emit Get-Content or Get-ChildItem unless the host shell is PowerShell. After a shell failure, make at most one corrected bridge attempt, then report the error and stop — do not repeat equivalent failing commands."
424
645
  : undefined;
425
646
  const notes = [
426
647
  `Cursor tool calls: available tool names are exactly ${listedNames}.`,
@@ -428,6 +649,17 @@ export function buildCursorToolGuidanceSystemNote(
428
649
  unavailableNeighborNames.length > 0
429
650
  ? `This turn does not expose neighboring-agent tool names ${quotedNames(unavailableNeighborNames)}; do not call or suggest them unless the catalog lists them.`
430
651
  : undefined,
652
+ // Code mode: shell/edit/MCP live inside freeform `exec` as nested helpers. Without this the
653
+ // model probes for a top-level shell tool that is not there.
654
+ codeMode
655
+ ? `\`${CODEX_UNIFIED_EXEC_TOOL}\` is Codex code mode: its body is JavaScript evaluated in a V8 isolate, not a shell command and not Node. Shell, file edits, and MCP are nested helpers called INSIDE that body as \`await tools.<name>(...)\`, for example \`await tools.exec_command({cmd: \"ls\"})\`. Read the tool description and the isolate global \`ALL_TOOLS\` (not \`tools.ALL_TOOLS\`) for helpers this turn provides; absence from the top-level catalog or from \`exec\`'s description is not absence. Those nested helpers are not themselves top-level tools, so do not call \`exec_command\` or \`shell_command\` at the top level here${codeModeOtherTopLevelNames.length > 0 ? `; every other tool this turn lists, including ${quotedNames(codeModeOtherTopLevelNames)}, remains callable at the top level as usual` : ""}. Nested \`tools.apply_patch(input)\` is host-executed: the string must begin exactly with \`*** Begin Patch\` and end with \`*** End Patch\` (no trailing \`***\` on those lines). OpenCodex does not rewrite JavaScript inside exec, so a decorated \`*** Begin Patch ***\` envelope is rejected by Codex before the file is touched.`
656
+ : undefined,
657
+ codeMode
658
+ ? CODE_MODE_RESULT_ECHO_SENTENCE + " There is no `require`, no `module`, and no filesystem or network globals; reach the host only through the nested helpers."
659
+ : undefined,
660
+ codeMode
661
+ ? "NEVER attempt Cursor-native Shell, Read, Grep, List, or any tool absent from the catalog — they are not executed in this environment and every probe wastes a turn. The exec code cell (with its nested helpers) is the ONLY execution surface; go to it directly on the FIRST attempt and do not narrate switching surfaces."
662
+ : undefined,
431
663
  hasBareExec
432
664
  ? `${shellBridgeLabel} is the Codex Responses shell bridge for this turn, exposed through Cursor's tool protocol; it is not an external MCP server tool. \`shell_command\` and \`exec_command\` are aliases of the same bridge.`
433
665
  : undefined,
@@ -435,7 +667,10 @@ export function buildCursorToolGuidanceSystemNote(
435
667
  ? "Your tool list may display it under a longer `mcp_opencodex-responses_shell_command` / `mcp_opencodex-responses_exec_command` name; those are the SAME tool — call whichever your list shows, and do not comment on the naming difference to the user."
436
668
  : undefined,
437
669
  hasBareExec
438
- ? "Never tell the user that shell or read access is blocked, disabled, or denied unless the Codex shell bridge tool itself fails. Prefer the bridge over Cursor-native Shell/Read; do not narrate phrases like \"Native shell access is blocked\" — silently call `shell_command` / `exec_command`."
670
+ ? `NEVER attempt Cursor-native Shell, Read, Grep, List, or any tool not in the catalog above they are not executed locally in this environment and every attempt wastes a turn and can stall the session. ${shellBridgeLabel} is the ONLY shell surface; go to it directly on the FIRST attempt, never as a fallback after probing a native tool. Do not narrate switching surfaces ("native is blocked, using the bridge instead")there is exactly one surface.`
671
+ : undefined,
672
+ hasBareExec
673
+ ? "Tool-selection commentary is forbidden: for any shell, read, grep, list, or file operation, your FIRST visible action is the bridge call itself — never a sentence about which tool you will use, which tool was redirected, or switching surfaces. Words like 차단/전환/blocked/switching must not appear in your output for tool-routing reasons."
439
674
  : undefined,
440
675
  hostShellNote,
441
676
  "Cursor product features (Chronicle, screen recording, Notes, Plans, background agents) are available only if this turn's catalog lists a matching tool; do not offer or promise them otherwise.",
@@ -443,7 +678,12 @@ export function buildCursorToolGuidanceSystemNote(
443
678
  ? `For file read/search/listing, use ${shellBridgeLabel} when no more specific listed tool is available.`
444
679
  : undefined,
445
680
  hasApplyPatch
446
- ? "For file edits, use the `apply_patch` tool, not built-in file write/delete tools."
681
+ ? structuredEditNames.length > 0
682
+ ? `For file edits, prefer the structured edit tools ${quotedNames(structuredEditNames)} — they take replacements that OpenCodex converts into Codex \`apply_patch\` changes. Include exact leading whitespace in old_string/new_string. Use \`apply_patch\` directly only with a \`*** Begin Patch\` envelope and bare \`@@\` hunks (never git-style \`@@ -n,m +n,m @@\`); never emit patch-like plain text as tool arguments.`
683
+ : "For file edits, use the `apply_patch` tool, not built-in file write/delete tools."
684
+ : undefined,
685
+ hasApplyPatch
686
+ ? "Creating or modifying file CONTENT via shell redirection (`>`, `>>`, `printf`/`echo` into a file, `cat <<EOF`, `sed -i`) is forbidden while apply_patch or the structured edit tools are advertised — use those edit tools so the change is reviewable. Shell output redirection is fine for logs/scratch pipes that are not the deliverable file."
447
687
  : undefined,
448
688
  hasBareExec
449
689
  ? "For tool-count demos, each counted tool must be a separate Codex shell-bridge invocation/result; do not collapse several requested tools into one chained shell command."
@@ -457,7 +697,7 @@ export function buildCursorToolGuidanceSystemNote(
457
697
  : undefined,
458
698
  "Do not count or report a tool call unless a tool result was actually returned.",
459
699
  hasBareExec
460
- ? `If a Cursor-native file read, directory listing, grep, or shell operation is rejected by the runtime, silently use ${shellBridgeLabel} with an equivalent host-shell-safe command (POSIX: \`cat\`/\`ls\`/\`rg\`; Windows PowerShell: \`Get-Content\`/\`Get-ChildItem\`/\`Select-String\`). Do not tell the user access is blocked. For file edits, use \`apply_patch\` when available.`
700
+ ? `For every file read, directory listing, grep, or shell operation use ${shellBridgeLabel} directly with host-shell-safe commands (POSIX: \`cat\`/\`ls\`/\`rg\`; Windows PowerShell: \`Get-Content\`/\`Get-ChildItem\`/\`Select-String\`). For file edits, use ${structuredEditNames.length > 0 ? `the structured edit tools (${quotedNames(structuredEditNames)}) or ` : ""}\`apply_patch\` when available.`
461
701
  : undefined,
462
702
  ].filter((note): note is string => typeof note === "string");
463
703
  return notes.join(" ");
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Cursor tool-result normalization for Computer Use / node_repl surfaces (#1920/#1866).
3
+ *
4
+ * Scoped re-implementation of PR #1920 per the 260818 campaign disposition
5
+ * (REDESIGN-SMALL: "apply formatted.text at native toolResultPart + decode test").
6
+ * Only empty-output and known-failure-state normalization ships here; screenshot
7
+ * stripping and AXTree text compaction from the original PR are deliberately out
8
+ * of scope (the native path already bounds step size by real serialized bytes,
9
+ * dropping images oldest-first — see toolCallStep in protobuf-request.ts).
10
+ */
11
+
12
+ import {
13
+ EMPTY_EXEC_OUTPUT_MESSAGE,
14
+ EMPTY_EXEC_OUTPUT_REGEX,
15
+ FAILED_EXEC_OUTPUT_MESSAGE,
16
+ FAILED_EXEC_OUTPUT_REGEX,
17
+ isCodexExecBridgeTool,
18
+ } from "../exec-tool-result-normalize";
19
+
20
+ /**
21
+ * Cursor treats a failed-but-empty wrapper as an empty result too (its Computer Use branch marks
22
+ * such results `isError` separately). The shared success regex deliberately excludes
23
+ * `Script failed`, so restore that arm here rather than widening the shared one.
24
+ */
25
+ function isEmptyOrFailedExecWrapper(text: string): boolean {
26
+ return EMPTY_EXEC_OUTPUT_REGEX.test(text) || FAILED_EXEC_OUTPUT_REGEX.test(text);
27
+ }
28
+
29
+ const COMPUTER_USE_TOOL_NAMES = new Set([
30
+ "node_repl",
31
+ "node_repl__js",
32
+ "mcp__node_repl__js",
33
+ "get_app_state",
34
+ "list_apps",
35
+ "screenshot",
36
+ "computer_use",
37
+ ]);
38
+
39
+ function isNodeReplOrComputerUseTool(toolName?: string, toolNamespace?: string): boolean {
40
+ if (toolNamespace && (toolNamespace === "mcp__node_repl" || toolNamespace.includes("node_repl") || toolNamespace.includes("computer_use"))) {
41
+ return true;
42
+ }
43
+ if (!toolName) return false;
44
+ const lower = toolName.toLowerCase();
45
+ if (COMPUTER_USE_TOOL_NAMES.has(lower)) return true;
46
+ return lower.startsWith("mcp__node_repl") || lower.startsWith("mcp__computer_use");
47
+ }
48
+
49
+ /** Failure states the Computer Use / node_repl runtime reports as PLAIN TEXT inside a non-error result. */
50
+ const RUNTIME_FAILURE_GUIDANCE: ReadonlyArray<{ marker: string; guidance: string }> = [
51
+ {
52
+ marker: "SkyComputerUseError",
53
+ guidance: "The Computer Use runtime rejected this action. Re-check application state with get_app_state before retrying.",
54
+ },
55
+ {
56
+ marker: "sky is not defined",
57
+ guidance: "The sky binding is unavailable in this context; Computer Use calls only work inside the privileged node_repl session.",
58
+ },
59
+ {
60
+ marker: "has already been declared",
61
+ guidance: "The node_repl session keeps earlier declarations; rename the variable or use var/reassignment instead of redeclaring.",
62
+ },
63
+ {
64
+ marker: "unsupported import in exec",
65
+ guidance: "Imports are not available in this exec context; use the injected globals instead.",
66
+ },
67
+ ];
68
+
69
+ export interface NormalizedToolResultText {
70
+ text: string;
71
+ isError: boolean;
72
+ /** True when normalization changed either field (lets callers skip work on the common path). */
73
+ changed: boolean;
74
+ }
75
+
76
+ /**
77
+ * Normalize a Cursor-bound tool-result TEXT payload:
78
+ * - blank / empty-exec-wrapper output on Computer Use or node_repl tools becomes an
79
+ * actionable error instead of an empty string the model silently accepts;
80
+ * - known runtime failure states reported as plain text are marked isError with a
81
+ * one-line recovery hint appended.
82
+ * Everything else passes through byte-identical.
83
+ */
84
+ export function normalizeCursorToolResultText(
85
+ text: string,
86
+ options: { toolName?: string; toolNamespace?: string; isError?: boolean } = {},
87
+ ): NormalizedToolResultText {
88
+ const isError = options.isError === true;
89
+ const computerUse = isNodeReplOrComputerUseTool(options.toolName, options.toolNamespace);
90
+ if (computerUse && isEmptyOrFailedExecWrapper(text.trim())) {
91
+ return {
92
+ text: "[empty output: the tool ran but produced no stdout or return value. Verify application state with get_app_state, or make the script emit output.]",
93
+ isError: true,
94
+ changed: true,
95
+ };
96
+ }
97
+ if (isCodexExecBridgeTool(options.toolName, options.toolNamespace) && isEmptyOrFailedExecWrapper(text.trim())) {
98
+ return {
99
+ // A `Script failed` wrapper is empty but NOT a success: reporting it as an empty success
100
+ // would erase the only failure signal. Text classification stays separate from Cursor's
101
+ // isError policy, which the Computer Use branch above owns.
102
+ text: FAILED_EXEC_OUTPUT_REGEX.test(text.trim()) ? FAILED_EXEC_OUTPUT_MESSAGE : EMPTY_EXEC_OUTPUT_MESSAGE,
103
+ isError: false,
104
+ changed: true,
105
+ };
106
+ }
107
+ if (!isError) {
108
+ for (const { marker, guidance } of RUNTIME_FAILURE_GUIDANCE) {
109
+ if (text.includes(marker)) {
110
+ return { text: `${text}\n[recovery: ${guidance}]`, isError: true, changed: true };
111
+ }
112
+ }
113
+ }
114
+ return { text, isError, changed: false };
115
+ }
@@ -12,16 +12,33 @@ export interface CursorTransport {
12
12
  * accepted is never replayed. Absent (undefined) is treated as "committed" — safe by default.
13
13
  */
14
14
  requestCommitted?(): boolean;
15
+ /**
16
+ * Last ConversationStateStructure captured from conversationCheckpointUpdate on this transport.
17
+ * Test and adapter seams use this instead of reaching into LiveCursorTransport.
18
+ */
19
+ capturedConversationCheckpoint?(): Uint8Array | undefined;
15
20
  }
16
21
 
17
22
  export interface CursorTransportFactoryInput {
18
23
  provider: OcxProviderConfig;
19
24
  translatorBudget: TranslatorBudget;
20
25
  headers?: Headers;
26
+ /** Router-prepared fetch that preserves provider overrides and per-request pacing. */
27
+ fetch?: typeof globalThis.fetch;
21
28
  /** Pre-first-frame deadline (dial + first server frame). Defaults to 30s when omitted. */
22
29
  firstFrameTimeoutMs?: number;
23
30
  /** Grace (ms) between close() and the force-destroy fallback after a first-frame timeout. Defaults to 1s. */
24
31
  timeoutDestroyGraceMs?: number;
32
+ /**
33
+ * T04 watchdog: maximum inbound decoded-frame silence (ms) after the first frame before the
34
+ * turn is failed. Defaults to 30s.
35
+ */
36
+ streamSilenceFailMs?: number;
37
+ /**
38
+ * T04 watchdog: maximum heartbeat/checkpoint-only traffic (ms) without turn progress before
39
+ * the turn is failed. Defaults to 90s.
40
+ */
41
+ streamHeartbeatOnlyFailMs?: number;
25
42
  /**
26
43
  * Grace window (ms) before a drained client-tool turn is finalized, so a sibling tool call
27
44
  * announced in a later receive chunk can revoke a premature finalize. Defaults to 50ms.
@@ -33,6 +50,11 @@ export interface CursorTransportFactoryInput {
33
50
  * native local exec authorization because the text is caller-controlled.
34
51
  */
35
52
  requestDeclaresFullAccess?: boolean;
53
+ /**
54
+ * Stable Cursor Connect `x-session-id` across transport rebuilds for the same
55
+ * client thread. Distinct from the per-transport native-exec/shell owner.
56
+ */
57
+ sessionId?: string;
36
58
  }
37
59
 
38
60
  export type CursorTransportFactory = (input: CursorTransportFactoryInput) => CursorTransport;
@@ -1,15 +1,50 @@
1
1
  import type { OcxUsage } from "../../types";
2
2
  import type { OcxMessage, OcxRequestOptions, OcxTool } from "../../types";
3
3
  import type { CursorRoutingLevel } from "./discovery";
4
+ import type { CursorCheckpointInvalidationReason } from "./checkpoint-store";
5
+ import type { ResolvedCursorImage } from "./images";
6
+
7
+ export interface CursorRequestedModelParameter {
8
+ id: string;
9
+ value: string;
10
+ }
4
11
 
5
12
  export interface CursorRunRequest {
6
13
  modelId: string;
14
+ /** Cursor model-picker parameters encoded through AgentRunRequest.requested_model. */
15
+ requestedModelParameters?: readonly CursorRequestedModelParameter[];
7
16
  /** Cursor Router optimization parameter; valid only while modelId is the `default` wire model. */
8
17
  routingLevel?: CursorRoutingLevel;
18
+ /**
19
+ * Cursor Max Mode (ultra/big-context). Set from a synthetic `-1m` picker variant; the wire
20
+ * keeps the original model id and raises RequestedModel.maxMode + ModelDetails.maxMode
21
+ * (both fields — missing either can invalid_argument upstream). Devlog 260826 070.
22
+ */
23
+ maxMode?: boolean;
24
+ /**
25
+ * Bare API callers (no caller tools, no Codex thread identity) pay a ~10-15K input-token
26
+ * preamble because an absent AgentRunRequest.mcp_tools field makes Cursor inject its default
27
+ * native tool catalog. When true, an explicitly empty McpTools wrapper is serialized instead,
28
+ * suppressing that default. Codex-identified sessions keep the absent-field behavior.
29
+ */
30
+ suppressDefaultCursorToolCatalog?: boolean;
31
+ /**
32
+ * Corrective active-turn text for the single envelope-echo retry (devlog 260826 gap-10).
33
+ * When set on an external tool-result continuation, buildPreparedCursorRunRequest uses it as
34
+ * the userMessageAction text instead of the standard continuation text; rawMessages stay
35
+ * untouched so history replay is unchanged.
36
+ */
37
+ echoRetryContinuationText?: string;
9
38
  conversationId: string;
10
39
  system: string[];
11
40
  messages: CursorRequestMessage[];
12
- rawMessages?: OcxMessage[];
41
+ rawMessages?: readonly OcxMessage[];
42
+ /**
43
+ * Images for the active user/developer turn. Encoded as SelectedImage blobIdWithData refs under
44
+ * UserMessage.selected_context (bytes live in the request-scoped KV store for getBlobArgs
45
+ * hydration). History stays text-only. data: URLs only in this slice.
46
+ */
47
+ selectedImages?: readonly ResolvedCursorImage[];
13
48
  tools?: OcxTool[];
14
49
  toolChoice?: OcxRequestOptions["toolChoice"];
15
50
  parallelToolCalls?: boolean;
@@ -24,6 +59,18 @@ export interface CursorRunRequest {
24
59
  * pre-compaction history being summarized and must not become the next turn's carry-forward total.
25
60
  */
26
61
  contextUsageStoreCheckpoints?: boolean;
62
+ /**
63
+ * Reuse a previously captured ConversationStateStructure instead of rebuilding historical
64
+ * root/turn blobs. Absent means the existing full-replay path.
65
+ */
66
+ checkpointBytes?: Uint8Array;
67
+ continuationMode?: "full-replay" | "checkpoint";
68
+ checkpointInvalidationReason?: CursorCheckpointInvalidationReason;
69
+ /**
70
+ * When set with checkpointBytes, only this suffix of rawMessages is replayed onto the
71
+ * decoded ConversationStateStructure. Used for tool-result continuations.
72
+ */
73
+ checkpointSuffixStart?: number;
27
74
  }
28
75
 
29
76
  export interface CursorRequestMessage {