@remodex/rmx 1.0.2

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 (588) hide show
  1. package/AGENTS_INSTALL.md +91 -0
  2. package/LICENSE +21 -0
  3. package/README.md +242 -0
  4. package/assets/architecture.png +0 -0
  5. package/assets/banner.png +0 -0
  6. package/assets/claude-code-models.gif +0 -0
  7. package/assets/codex-app-picker.png +0 -0
  8. package/bin/ocx.mjs +584 -0
  9. package/bin/package-main.mjs +9 -0
  10. package/gui/dist/assets/index-CZqebSPQ.css +1 -0
  11. package/gui/dist/assets/index-CkETtt7P.js +71 -0
  12. package/gui/dist/favicon.png +0 -0
  13. package/gui/dist/fonts/google-sans-cyrillic.woff2 +0 -0
  14. package/gui/dist/fonts/google-sans-latin.woff2 +0 -0
  15. package/gui/dist/icons.svg +24 -0
  16. package/gui/dist/index.html +25 -0
  17. package/gui/dist/logo.png +0 -0
  18. package/gui/dist/provider-icons/alibaba-color.svg +1 -0
  19. package/gui/dist/provider-icons/antigravity-color.svg +1 -0
  20. package/gui/dist/provider-icons/claude-color.svg +1 -0
  21. package/gui/dist/provider-icons/cline-color.svg +16 -0
  22. package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -0
  23. package/gui/dist/provider-icons/commandcode-color.svg +1 -0
  24. package/gui/dist/provider-icons/copilot-color.svg +1 -0
  25. package/gui/dist/provider-icons/cursor-color.svg +2 -0
  26. package/gui/dist/provider-icons/deepseek-color.svg +1 -0
  27. package/gui/dist/provider-icons/discord.svg +1 -0
  28. package/gui/dist/provider-icons/firepass-color.svg +1 -0
  29. package/gui/dist/provider-icons/fireworks-color.svg +1 -0
  30. package/gui/dist/provider-icons/gemini-color.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.svg +1 -0
  34. package/gui/dist/provider-icons/groq-color.svg +1 -0
  35. package/gui/dist/provider-icons/huggingface-color.svg +1 -0
  36. package/gui/dist/provider-icons/kimi-color.svg +1 -0
  37. package/gui/dist/provider-icons/kiro-color.svg +15 -0
  38. package/gui/dist/provider-icons/lm-studio-color.svg +1 -0
  39. package/gui/dist/provider-icons/mistral-color.svg +1 -0
  40. package/gui/dist/provider-icons/moonshot-color.svg +1 -0
  41. package/gui/dist/provider-icons/nvidia-color.svg +1 -0
  42. package/gui/dist/provider-icons/ollama-color.svg +1 -0
  43. package/gui/dist/provider-icons/openai.svg +1 -0
  44. package/gui/dist/provider-icons/opencode.svg +2 -0
  45. package/gui/dist/provider-icons/openrouter-color.svg +1 -0
  46. package/gui/dist/provider-icons/pi.svg +21 -0
  47. package/gui/dist/provider-icons/qianfan-color.svg +1 -0
  48. package/gui/dist/provider-icons/qwen-portal-color.svg +1 -0
  49. package/gui/dist/provider-icons/telegram.svg +1 -0
  50. package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -0
  51. package/gui/dist/provider-icons/vllm-color.svg +1 -0
  52. package/gui/dist/provider-icons/xiaomi-color.svg +1 -0
  53. package/package.json +118 -0
  54. package/src/AGENTS.md +28 -0
  55. package/src/adapters/anthropic-image-guard.ts +251 -0
  56. package/src/adapters/anthropic-image-normalize.ts +518 -0
  57. package/src/adapters/anthropic.ts +1205 -0
  58. package/src/adapters/azure.ts +36 -0
  59. package/src/adapters/base.ts +83 -0
  60. package/src/adapters/client-fingerprint.ts +59 -0
  61. package/src/adapters/command-code.ts +453 -0
  62. package/src/adapters/cursor/arg-codec.ts +38 -0
  63. package/src/adapters/cursor/arg-normalize.ts +104 -0
  64. package/src/adapters/cursor/cursor-errors.ts +165 -0
  65. package/src/adapters/cursor/discovery.ts +276 -0
  66. package/src/adapters/cursor/effort-map.ts +139 -0
  67. package/src/adapters/cursor/exec-policy.ts +88 -0
  68. package/src/adapters/cursor/framing.ts +250 -0
  69. package/src/adapters/cursor/gen/agent_pb.ts +15274 -0
  70. package/src/adapters/cursor/kv-store.ts +52 -0
  71. package/src/adapters/cursor/live-models.ts +153 -0
  72. package/src/adapters/cursor/live-smoke-gate.ts +41 -0
  73. package/src/adapters/cursor/live-transport.ts +1235 -0
  74. package/src/adapters/cursor/mcp-config.ts +42 -0
  75. package/src/adapters/cursor/mcp-manager.ts +333 -0
  76. package/src/adapters/cursor/message-mapper.ts +49 -0
  77. package/src/adapters/cursor/native-exec-common.ts +59 -0
  78. package/src/adapters/cursor/native-exec-desktop.ts +184 -0
  79. package/src/adapters/cursor/native-exec-fs.ts +332 -0
  80. package/src/adapters/cursor/native-exec-mcp.ts +153 -0
  81. package/src/adapters/cursor/native-exec-network.ts +43 -0
  82. package/src/adapters/cursor/native-exec-shell.ts +548 -0
  83. package/src/adapters/cursor/native-exec-tools.ts +118 -0
  84. package/src/adapters/cursor/native-exec.ts +604 -0
  85. package/src/adapters/cursor/protobuf-events.ts +735 -0
  86. package/src/adapters/cursor/protobuf-request.ts +719 -0
  87. package/src/adapters/cursor/request-builder.ts +280 -0
  88. package/src/adapters/cursor/thread-continuity.ts +67 -0
  89. package/src/adapters/cursor/tool-definitions.ts +621 -0
  90. package/src/adapters/cursor/transport-retry.ts +132 -0
  91. package/src/adapters/cursor/transport.ts +57 -0
  92. package/src/adapters/cursor/types.ts +59 -0
  93. package/src/adapters/cursor.ts +196 -0
  94. package/src/adapters/google-antigravity-replay.ts +520 -0
  95. package/src/adapters/google-antigravity-wire.ts +140 -0
  96. package/src/adapters/google-errors.ts +85 -0
  97. package/src/adapters/google-http.ts +100 -0
  98. package/src/adapters/google-tool-schema.ts +173 -0
  99. package/src/adapters/google-truncation.ts +24 -0
  100. package/src/adapters/google-wire-compiler.ts +232 -0
  101. package/src/adapters/google.ts +859 -0
  102. package/src/adapters/identity.ts +77 -0
  103. package/src/adapters/image.ts +23 -0
  104. package/src/adapters/kiro-constants.ts +16 -0
  105. package/src/adapters/kiro-errors.ts +208 -0
  106. package/src/adapters/kiro-events.ts +197 -0
  107. package/src/adapters/kiro-images.ts +129 -0
  108. package/src/adapters/kiro-retry.ts +312 -0
  109. package/src/adapters/kiro-thinking.ts +104 -0
  110. package/src/adapters/kiro-tool-fallback.ts +36 -0
  111. package/src/adapters/kiro-tools.ts +224 -0
  112. package/src/adapters/kiro-truncation.ts +33 -0
  113. package/src/adapters/kiro-wire.ts +129 -0
  114. package/src/adapters/kiro.ts +1924 -0
  115. package/src/adapters/mimo-free.ts +263 -0
  116. package/src/adapters/openai-chat.ts +1265 -0
  117. package/src/adapters/openai-responses.ts +1309 -0
  118. package/src/adapters/run-turn-queue.ts +114 -0
  119. package/src/adapters/tool-catalog-nudge.ts +71 -0
  120. package/src/adapters/upstream-http-error.ts +48 -0
  121. package/src/android-remote/assets.ts +218 -0
  122. package/src/android-remote/attachments.ts +168 -0
  123. package/src/android-remote/auth.ts +237 -0
  124. package/src/android-remote/cloudflare-provisioning.ts +409 -0
  125. package/src/android-remote/cloudflare-secret.ts +106 -0
  126. package/src/android-remote/cloudflare-tunnel.ts +488 -0
  127. package/src/android-remote/cloudflared.ts +286 -0
  128. package/src/android-remote/codex-app-server.ts +565 -0
  129. package/src/android-remote/desktop-history-page.ts +936 -0
  130. package/src/android-remote/desktop-ipc.ts +3643 -0
  131. package/src/android-remote/desktop-ownership-store.ts +98 -0
  132. package/src/android-remote/desktop-project-registration.ts +129 -0
  133. package/src/android-remote/desktop-session-stream.ts +1110 -0
  134. package/src/android-remote/desktop-workspace-state.ts +443 -0
  135. package/src/android-remote/file-change-parser.ts +112 -0
  136. package/src/android-remote/gateway.ts +9108 -0
  137. package/src/android-remote/mutation-store.ts +299 -0
  138. package/src/android-remote/projection.ts +1780 -0
  139. package/src/android-remote/queued-turn-store.ts +248 -0
  140. package/src/android-remote/session-command-recovery.ts +1384 -0
  141. package/src/android-remote/store.ts +466 -0
  142. package/src/android-remote/thread-reconciliation.ts +133 -0
  143. package/src/android-remote/thread-source-paths.ts +307 -0
  144. package/src/android-remote/thread-stream.ts +546 -0
  145. package/src/android-remote/turn-activity.ts +235 -0
  146. package/src/android-remote/user-message-identity.ts +94 -0
  147. package/src/bridge.ts +1793 -0
  148. package/src/chat/inbound.ts +295 -0
  149. package/src/chat/outbound.ts +821 -0
  150. package/src/claude/agents-inject.ts +267 -0
  151. package/src/claude/alias.ts +149 -0
  152. package/src/claude/auth-detect.ts +229 -0
  153. package/src/claude/auth-mode-migration.ts +32 -0
  154. package/src/claude/auth-mode.ts +62 -0
  155. package/src/claude/context-windows.ts +189 -0
  156. package/src/claude/desktop-3p-guard.ts +35 -0
  157. package/src/claude/desktop-3p-paths.ts +84 -0
  158. package/src/claude/desktop-3p.ts +601 -0
  159. package/src/claude/desktop-health.ts +26 -0
  160. package/src/claude/desktop-profile.ts +263 -0
  161. package/src/claude/gateway-cache.ts +70 -0
  162. package/src/claude/inbound-debug.ts +163 -0
  163. package/src/claude/inbound.ts +519 -0
  164. package/src/claude/model-info.ts +154 -0
  165. package/src/claude/outbound.ts +898 -0
  166. package/src/cli/access.ts +108 -0
  167. package/src/cli/account-api.ts +296 -0
  168. package/src/cli/account-auth.ts +250 -0
  169. package/src/cli/account-catalog-refresh.ts +14 -0
  170. package/src/cli/account-extended.ts +476 -0
  171. package/src/cli/account-main.ts +317 -0
  172. package/src/cli/account.ts +297 -0
  173. package/src/cli/agent-driven.ts +70 -0
  174. package/src/cli/agent.ts +184 -0
  175. package/src/cli/catalog-prewarm.ts +27 -0
  176. package/src/cli/claude-desktop.ts +211 -0
  177. package/src/cli/claude.ts +302 -0
  178. package/src/cli/codex-shim-autorestore.ts +45 -0
  179. package/src/cli/codex-shim-readiness.ts +69 -0
  180. package/src/cli/combo.ts +124 -0
  181. package/src/cli/config-command.ts +183 -0
  182. package/src/cli/debug.ts +228 -0
  183. package/src/cli/desktop-first-run.ts +25 -0
  184. package/src/cli/doctor.ts +1022 -0
  185. package/src/cli/export-command.ts +201 -0
  186. package/src/cli/help.ts +370 -0
  187. package/src/cli/index.ts +1565 -0
  188. package/src/cli/init.ts +224 -0
  189. package/src/cli/integrations.ts +225 -0
  190. package/src/cli/interactive-confirm.ts +133 -0
  191. package/src/cli/internal-dispatch.ts +35 -0
  192. package/src/cli/launcher-context.ts +77 -0
  193. package/src/cli/models-runtime.ts +224 -0
  194. package/src/cli/models.ts +340 -0
  195. package/src/cli/observe.ts +170 -0
  196. package/src/cli/opencode.ts +587 -0
  197. package/src/cli/provider-runtime.ts +179 -0
  198. package/src/cli/provider.ts +476 -0
  199. package/src/cli/ready.ts +301 -0
  200. package/src/cli/route-policy.ts +92 -0
  201. package/src/cli/runtime-api.ts +328 -0
  202. package/src/cli/star-prompt.ts +211 -0
  203. package/src/cli/status-oauth.ts +78 -0
  204. package/src/cli/status.ts +321 -0
  205. package/src/cli/system-command.ts +196 -0
  206. package/src/cli/system-restart-client.ts +146 -0
  207. package/src/cli/tray-proxy.ts +205 -0
  208. package/src/cli/v2.ts +200 -0
  209. package/src/cli.ts +10 -0
  210. package/src/clients/config-export.ts +1109 -0
  211. package/src/codex/account-id.ts +34 -0
  212. package/src/codex/account-label.ts +34 -0
  213. package/src/codex/account-lifecycle.ts +172 -0
  214. package/src/codex/account-namespace-match.ts +63 -0
  215. package/src/codex/account-namespaces.ts +195 -0
  216. package/src/codex/account-pause.ts +20 -0
  217. package/src/codex/account-priority.ts +83 -0
  218. package/src/codex/account-runtime-state.ts +31 -0
  219. package/src/codex/account-store.ts +517 -0
  220. package/src/codex/account-usability.ts +40 -0
  221. package/src/codex/admission.ts +263 -0
  222. package/src/codex/app-server-processes.ts +799 -0
  223. package/src/codex/auth-api.ts +2098 -0
  224. package/src/codex/auth-collision.ts +107 -0
  225. package/src/codex/auth-context.ts +480 -0
  226. package/src/codex/autostart-health.ts +156 -0
  227. package/src/codex/catalog/account-models.ts +67 -0
  228. package/src/codex/catalog/aggregation.ts +471 -0
  229. package/src/codex/catalog/bundled.ts +533 -0
  230. package/src/codex/catalog/effort.ts +432 -0
  231. package/src/codex/catalog/filesystem-evidence.ts +302 -0
  232. package/src/codex/catalog/kinds.ts +2 -0
  233. package/src/codex/catalog/metadata.ts +287 -0
  234. package/src/codex/catalog/native-models.ts +7 -0
  235. package/src/codex/catalog/parsing.ts +503 -0
  236. package/src/codex/catalog/provider-fetch.ts +2267 -0
  237. package/src/codex/catalog/sync.ts +1606 -0
  238. package/src/codex/catalog-admission.ts +197 -0
  239. package/src/codex/catalog-refresh-status.ts +87 -0
  240. package/src/codex/catalog-write-serialization.ts +242 -0
  241. package/src/codex/catalog.ts +15 -0
  242. package/src/codex/codex-write-lock.ts +384 -0
  243. package/src/codex/convergence-types.ts +593 -0
  244. package/src/codex/convergence.ts +580 -0
  245. package/src/codex/custom-model-catalog-migration.ts +176 -0
  246. package/src/codex/data/upstream-models.json +830 -0
  247. package/src/codex/desired-state.ts +230 -0
  248. package/src/codex/desktop-client-processes.ts +521 -0
  249. package/src/codex/exec-invocation.ts +22 -0
  250. package/src/codex/features.ts +1091 -0
  251. package/src/codex/generation.ts +202 -0
  252. package/src/codex/history-job.ts +347 -0
  253. package/src/codex/history-lock.ts +242 -0
  254. package/src/codex/history-migration-guardian.ts +115 -0
  255. package/src/codex/history-provider.ts +1075 -0
  256. package/src/codex/history-transition.ts +105 -0
  257. package/src/codex/history-worker.ts +204 -0
  258. package/src/codex/home.ts +206 -0
  259. package/src/codex/inject-coordination.ts +257 -0
  260. package/src/codex/inject.ts +1857 -0
  261. package/src/codex/injected-marker.ts +79 -0
  262. package/src/codex/integration-record.ts +266 -0
  263. package/src/codex/internal/catalog-writer.ts +203 -0
  264. package/src/codex/internal/history-writer.ts +105 -0
  265. package/src/codex/journal.ts +172 -0
  266. package/src/codex/main-account-cache.ts +56 -0
  267. package/src/codex/main-account.ts +40 -0
  268. package/src/codex/management-convergence.ts +114 -0
  269. package/src/codex/model-cache.ts +267 -0
  270. package/src/codex/native-main-admission.ts +47 -0
  271. package/src/codex/native-main-auth-temp.ts +187 -0
  272. package/src/codex/native-main-claim.ts +167 -0
  273. package/src/codex/native-main-lock-file.ts +162 -0
  274. package/src/codex/native-main-owner.ts +329 -0
  275. package/src/codex/native-profile-api.ts +247 -0
  276. package/src/codex/native-profile-manager.ts +1531 -0
  277. package/src/codex/native-profile-processes.ts +121 -0
  278. package/src/codex/native-profile-recovery.ts +99 -0
  279. package/src/codex/native-profile-stage-store.ts +387 -0
  280. package/src/codex/native-profile-startup.ts +348 -0
  281. package/src/codex/native-profile-store.ts +855 -0
  282. package/src/codex/native-profile-types.ts +120 -0
  283. package/src/codex/native-residue.ts +691 -0
  284. package/src/codex/paths.ts +78 -0
  285. package/src/codex/plugins-doctor.ts +242 -0
  286. package/src/codex/pool-rotation.ts +295 -0
  287. package/src/codex/project-config-warnings.ts +426 -0
  288. package/src/codex/prompt-journal.ts +311 -0
  289. package/src/codex/prompt-layers.ts +967 -0
  290. package/src/codex/prompt-lock.ts +143 -0
  291. package/src/codex/provider-adoption.ts +242 -0
  292. package/src/codex/quota-rejection.ts +224 -0
  293. package/src/codex/quota.ts +494 -0
  294. package/src/codex/refresh.ts +60 -0
  295. package/src/codex/routing.ts +1855 -0
  296. package/src/codex/runtime.ts +659 -0
  297. package/src/codex/shim.ts +1215 -0
  298. package/src/codex/subagent-defaults.ts +557 -0
  299. package/src/codex/subagent-model-fallback.ts +560 -0
  300. package/src/codex/sync.ts +238 -0
  301. package/src/codex/transition-state.ts +612 -0
  302. package/src/codex/upstream-host-health.ts +368 -0
  303. package/src/codex/user-identity.ts +374 -0
  304. package/src/codex/warmup.ts +192 -0
  305. package/src/codex/websocket-registry.ts +100 -0
  306. package/src/codex/write-coordination.ts +114 -0
  307. package/src/combos/failover.ts +140 -0
  308. package/src/combos/index.ts +44 -0
  309. package/src/combos/request.ts +64 -0
  310. package/src/combos/resolve.ts +232 -0
  311. package/src/combos/types.ts +392 -0
  312. package/src/config.ts +3270 -0
  313. package/src/generated/model-metadata.ts +144 -0
  314. package/src/github/star-state.ts +203 -0
  315. package/src/grok/inject.ts +540 -0
  316. package/src/grok/inspect.ts +45 -0
  317. package/src/grok/status.ts +127 -0
  318. package/src/grok/sync.ts +66 -0
  319. package/src/images/artifacts.ts +516 -0
  320. package/src/images/fulfill-video.ts +163 -0
  321. package/src/images/fulfill.ts +149 -0
  322. package/src/images/index.ts +4 -0
  323. package/src/images/loop.ts +922 -0
  324. package/src/images/plan.ts +133 -0
  325. package/src/images/synthetic-tool.ts +133 -0
  326. package/src/images/types.ts +41 -0
  327. package/src/images/xai-client.ts +141 -0
  328. package/src/images/xai-video-client.ts +163 -0
  329. package/src/index.ts +22 -0
  330. package/src/integrations/config-io.ts +151 -0
  331. package/src/integrations/journal.ts +315 -0
  332. package/src/integrations/merge.ts +135 -0
  333. package/src/integrations/native/ownership-preflight.ts +202 -0
  334. package/src/integrations/ownership.ts +111 -0
  335. package/src/integrations/registry.ts +108 -0
  336. package/src/integrations/serialize.ts +235 -0
  337. package/src/integrations/state.ts +290 -0
  338. package/src/integrations/store.ts +103 -0
  339. package/src/integrations/writer.ts +492 -0
  340. package/src/lib/abort.ts +146 -0
  341. package/src/lib/admin-secrets.ts +25 -0
  342. package/src/lib/admission.ts +83 -0
  343. package/src/lib/app-owned-memory-stores.ts +173 -0
  344. package/src/lib/app-owned-memory.ts +265 -0
  345. package/src/lib/bounded-body.ts +242 -0
  346. package/src/lib/bun-binary-validator.d.mts +3 -0
  347. package/src/lib/bun-binary-validator.mjs +18 -0
  348. package/src/lib/bun-runtime.ts +184 -0
  349. package/src/lib/bun-stream-caps.ts +127 -0
  350. package/src/lib/config-ownership.ts +438 -0
  351. package/src/lib/crash-guard.ts +344 -0
  352. package/src/lib/debug-log-buffer.ts +83 -0
  353. package/src/lib/debug-settings.ts +108 -0
  354. package/src/lib/debug.ts +31 -0
  355. package/src/lib/destination-policy.ts +316 -0
  356. package/src/lib/errors.ts +364 -0
  357. package/src/lib/eventstream-decoder.ts +253 -0
  358. package/src/lib/gcp-adc.ts +341 -0
  359. package/src/lib/injection-debug-log.ts +58 -0
  360. package/src/lib/local-management-attestation.ts +51 -0
  361. package/src/lib/open-url.ts +25 -0
  362. package/src/lib/pinned-http.ts +182 -0
  363. package/src/lib/privacy.ts +20 -0
  364. package/src/lib/process-control.ts +168 -0
  365. package/src/lib/provider-environment.ts +470 -0
  366. package/src/lib/provider-outbound.ts +203 -0
  367. package/src/lib/provider-url.ts +14 -0
  368. package/src/lib/proxy-env.ts +18 -0
  369. package/src/lib/redact.ts +510 -0
  370. package/src/lib/remodex-home.ts +616 -0
  371. package/src/lib/retry-after.ts +55 -0
  372. package/src/lib/service-secrets.ts +178 -0
  373. package/src/lib/shadow-call.ts +54 -0
  374. package/src/lib/sidecar-tracker.ts +52 -0
  375. package/src/lib/sse-decoder.ts +364 -0
  376. package/src/lib/state-store-registrations.ts +109 -0
  377. package/src/lib/state-store-sweeper.ts +184 -0
  378. package/src/lib/system-restart-contract.ts +73 -0
  379. package/src/lib/test-home-guard.ts +98 -0
  380. package/src/lib/token-estimate.ts +69 -0
  381. package/src/lib/translator-budget.ts +366 -0
  382. package/src/lib/upstream-reachability.ts +91 -0
  383. package/src/lib/upstream-retry.ts +508 -0
  384. package/src/lib/win-exec.ts +115 -0
  385. package/src/lib/win-paths.ts +68 -0
  386. package/src/lib/windows-elevation.ts +705 -0
  387. package/src/lib/windows-secret-acl.ts +817 -0
  388. package/src/lib/windows-user-principal.ts +283 -0
  389. package/src/lib/winsw.ts +402 -0
  390. package/src/model-sources.ts +73 -0
  391. package/src/oauth/anthropic-routing.ts +594 -0
  392. package/src/oauth/anthropic.ts +177 -0
  393. package/src/oauth/callback-server.ts +294 -0
  394. package/src/oauth/chatgpt.ts +150 -0
  395. package/src/oauth/command-code.ts +239 -0
  396. package/src/oauth/cursor.ts +231 -0
  397. package/src/oauth/github-copilot.ts +428 -0
  398. package/src/oauth/google-antigravity.ts +230 -0
  399. package/src/oauth/health.ts +443 -0
  400. package/src/oauth/index.ts +1280 -0
  401. package/src/oauth/key-providers.ts +128 -0
  402. package/src/oauth/kimi.ts +213 -0
  403. package/src/oauth/kiro-credentials.ts +726 -0
  404. package/src/oauth/kiro.ts +621 -0
  405. package/src/oauth/local-token-detect.ts +121 -0
  406. package/src/oauth/log.ts +48 -0
  407. package/src/oauth/login-cli.ts +163 -0
  408. package/src/oauth/pkce.ts +15 -0
  409. package/src/oauth/store.ts +655 -0
  410. package/src/oauth/token-guardian.ts +309 -0
  411. package/src/oauth/types.ts +62 -0
  412. package/src/oauth/xai.ts +241 -0
  413. package/src/providers/alibaba-region-backup.ts +75 -0
  414. package/src/providers/alibaba-region-migration.ts +156 -0
  415. package/src/providers/alibaba-region-startup.ts +36 -0
  416. package/src/providers/antigravity-models.ts +317 -0
  417. package/src/providers/api-keys.ts +140 -0
  418. package/src/providers/base-url-choices.ts +64 -0
  419. package/src/providers/codex-capacity.ts +288 -0
  420. package/src/providers/command-code-efforts.ts +85 -0
  421. package/src/providers/context-cap.ts +73 -0
  422. package/src/providers/derive.ts +451 -0
  423. package/src/providers/free-directory.ts +187 -0
  424. package/src/providers/github-copilot-transport.ts +56 -0
  425. package/src/providers/google-vertex-location.ts +14 -0
  426. package/src/providers/key-failover.ts +271 -0
  427. package/src/providers/kiro-models.ts +67 -0
  428. package/src/providers/label.ts +19 -0
  429. package/src/providers/model-discovery-limits.ts +16 -0
  430. package/src/providers/model-discovery.ts +361 -0
  431. package/src/providers/openai-sidecar.ts +235 -0
  432. package/src/providers/openai-tier-startup.ts +27 -0
  433. package/src/providers/openai-tiers.ts +301 -0
  434. package/src/providers/openai-virtual-models.ts +83 -0
  435. package/src/providers/openrouter-routing.ts +102 -0
  436. package/src/providers/provider-id-rewrite.ts +179 -0
  437. package/src/providers/quota.ts +1942 -0
  438. package/src/providers/reasoning-capabilities.ts +336 -0
  439. package/src/providers/registry.ts +2375 -0
  440. package/src/providers/slug-codec.ts +74 -0
  441. package/src/providers/xai-transport.ts +149 -0
  442. package/src/reasoning-effort.ts +243 -0
  443. package/src/responses/compaction.ts +124 -0
  444. package/src/responses/hosted-tool-policy.ts +9 -0
  445. package/src/responses/parser.ts +714 -0
  446. package/src/responses/reasoning-envelope.ts +60 -0
  447. package/src/responses/reasoning-replay-cache.ts +106 -0
  448. package/src/responses/schema.ts +159 -0
  449. package/src/responses/spill-store.ts +431 -0
  450. package/src/responses/state.ts +1039 -0
  451. package/src/responses/tool-groups.ts +19 -0
  452. package/src/router.ts +802 -0
  453. package/src/routing/analytics.ts +377 -0
  454. package/src/routing/capability.ts +205 -0
  455. package/src/routing/cost.ts +77 -0
  456. package/src/routing/evaluator.ts +444 -0
  457. package/src/routing/health.ts +401 -0
  458. package/src/routing/history/cursor.ts +43 -0
  459. package/src/routing/history/indexer.ts +605 -0
  460. package/src/routing/history/schema.ts +72 -0
  461. package/src/routing/profile-namespace.ts +15 -0
  462. package/src/routing/profile.ts +424 -0
  463. package/src/routing/quota.ts +145 -0
  464. package/src/routing/request-evidence.ts +45 -0
  465. package/src/routing/trace.ts +686 -0
  466. package/src/server/adapter-resolve.ts +83 -0
  467. package/src/server/auth-cors.ts +606 -0
  468. package/src/server/chat-completions.ts +379 -0
  469. package/src/server/claude-messages.ts +980 -0
  470. package/src/server/effort-policy.ts +251 -0
  471. package/src/server/github-copilot-responses-repair.ts +338 -0
  472. package/src/server/gui-static.ts +152 -0
  473. package/src/server/image-retry.ts +42 -0
  474. package/src/server/images.ts +485 -0
  475. package/src/server/index.ts +1633 -0
  476. package/src/server/lifecycle.ts +482 -0
  477. package/src/server/live.ts +609 -0
  478. package/src/server/management/agent-settings-routes.ts +1180 -0
  479. package/src/server/management/android-remote-routes.ts +390 -0
  480. package/src/server/management/api-access.ts +141 -0
  481. package/src/server/management/api-key-usage.ts +167 -0
  482. package/src/server/management/body.ts +35 -0
  483. package/src/server/management/combo-routes.ts +244 -0
  484. package/src/server/management/config-routes.ts +602 -0
  485. package/src/server/management/context.ts +88 -0
  486. package/src/server/management/integration-routes.ts +538 -0
  487. package/src/server/management/logs-usage-routes.ts +516 -0
  488. package/src/server/management/model-routes.ts +519 -0
  489. package/src/server/management/model-rows.ts +143 -0
  490. package/src/server/management/native-integration-routes.ts +781 -0
  491. package/src/server/management/oauth-account-routes.ts +573 -0
  492. package/src/server/management/provider-routes.ts +781 -0
  493. package/src/server/management/request-history-routes.ts +191 -0
  494. package/src/server/management/routing-analytics-routes.ts +74 -0
  495. package/src/server/management/routing-profile-routes.ts +384 -0
  496. package/src/server/management/shared.ts +277 -0
  497. package/src/server/management/sidebar-routes.ts +106 -0
  498. package/src/server/management/sync-response.ts +69 -0
  499. package/src/server/management/system-restart.ts +433 -0
  500. package/src/server/management/system-routes.ts +141 -0
  501. package/src/server/management/usage-summary-cache.ts +86 -0
  502. package/src/server/management-api.ts +269 -0
  503. package/src/server/management-auth.ts +353 -0
  504. package/src/server/memory-watchdog.ts +156 -0
  505. package/src/server/port-reclaim.ts +307 -0
  506. package/src/server/ports.ts +156 -0
  507. package/src/server/proxy-liveness.ts +326 -0
  508. package/src/server/proxy-stop.ts +92 -0
  509. package/src/server/readiness.ts +99 -0
  510. package/src/server/relay-eager.ts +353 -0
  511. package/src/server/relay.ts +1179 -0
  512. package/src/server/request-decompress.ts +132 -0
  513. package/src/server/request-log-conversation.ts +168 -0
  514. package/src/server/request-log.ts +1072 -0
  515. package/src/server/responses/collaboration.ts +409 -0
  516. package/src/server/responses/compact.ts +710 -0
  517. package/src/server/responses/core.ts +3561 -0
  518. package/src/server/responses/encrypted-payload.ts +308 -0
  519. package/src/server/responses/fetch-helpers.ts +171 -0
  520. package/src/server/responses/passthrough-error.ts +78 -0
  521. package/src/server/responses/policy-fallback.ts +152 -0
  522. package/src/server/responses/terminal-guard.ts +230 -0
  523. package/src/server/responses/upstream-error.ts +48 -0
  524. package/src/server/responses-image-gen-repair.ts +132 -0
  525. package/src/server/responses-item-id-repair.ts +272 -0
  526. package/src/server/responses-json-events.ts +52 -0
  527. package/src/server/responses-model-rewrite.ts +29 -0
  528. package/src/server/responses-snapshot-repair.ts +621 -0
  529. package/src/server/responses.ts +10 -0
  530. package/src/server/search.ts +181 -0
  531. package/src/server/sse-frame-buffer.ts +292 -0
  532. package/src/server/sse-payload-rewrite.ts +263 -0
  533. package/src/server/startup-action-control.ts +308 -0
  534. package/src/server/startup-health-cache.ts +119 -0
  535. package/src/server/system-env.ts +418 -0
  536. package/src/server/windows-tcp-drop.ts +184 -0
  537. package/src/server/windows-tray-control.ts +41 -0
  538. package/src/server/ws-bridge.ts +470 -0
  539. package/src/service-manager-probe.ts +824 -0
  540. package/src/service.ts +3011 -0
  541. package/src/stall-timeout.ts +20 -0
  542. package/src/storage/cleanup-job.ts +57 -0
  543. package/src/storage/cleanup.ts +3085 -0
  544. package/src/storage/policy-job.ts +457 -0
  545. package/src/storage/policy-scheduler.ts +40 -0
  546. package/src/storage/policy-worker.ts +59 -0
  547. package/src/storage/policy.ts +527 -0
  548. package/src/storage/restore-job.ts +299 -0
  549. package/src/storage/restore-worker.ts +58 -0
  550. package/src/storage/scanner.ts +238 -0
  551. package/src/storage/storage-mutation-coordinator.ts +139 -0
  552. package/src/storage/worker-lifecycle.ts +215 -0
  553. package/src/tray/assets/opencodex-tray-offline.ico +0 -0
  554. package/src/tray/assets/opencodex-tray-online.ico +0 -0
  555. package/src/tray/assets/opencodex-tray-warning.ico +0 -0
  556. package/src/tray/assets/opencodex-tray.png +0 -0
  557. package/src/tray/windows-tray.ps1 +364 -0
  558. package/src/tray/windows.ts +738 -0
  559. package/src/types.ts +1531 -0
  560. package/src/update/badge.ts +72 -0
  561. package/src/update/desktop-release.ts +1620 -0
  562. package/src/update/index.ts +402 -0
  563. package/src/update/job.ts +1906 -0
  564. package/src/update/notify.ts +261 -0
  565. package/src/update/npm-cache-preflight.d.mts +47 -0
  566. package/src/update/npm-cache-preflight.mjs +201 -0
  567. package/src/update/npm-invocation.d.mts +23 -0
  568. package/src/update/npm-invocation.mjs +94 -0
  569. package/src/update/tray-update-plan.d.mts +18 -0
  570. package/src/update/tray-update-plan.mjs +38 -0
  571. package/src/usage/cost.ts +0 -0
  572. package/src/usage/debug.ts +97 -0
  573. package/src/usage/expected-prices.ts +283 -0
  574. package/src/usage/log.ts +695 -0
  575. package/src/usage/summary.ts +585 -0
  576. package/src/usage/totals.ts +14 -0
  577. package/src/vision/anthropic-describe.ts +185 -0
  578. package/src/vision/describe.ts +127 -0
  579. package/src/vision/index.ts +558 -0
  580. package/src/vision/reasoning.ts +55 -0
  581. package/src/web-search/anthropic-executor.ts +189 -0
  582. package/src/web-search/executor.ts +105 -0
  583. package/src/web-search/format-result.ts +89 -0
  584. package/src/web-search/index.ts +196 -0
  585. package/src/web-search/loop.ts +791 -0
  586. package/src/web-search/parse.ts +235 -0
  587. package/src/web-search/progress-stream.ts +342 -0
  588. package/src/web-search/synthetic-tool.ts +47 -0
@@ -0,0 +1,604 @@
1
+ import { createHash } from "node:crypto";
2
+ import { enforceAppOwnedMemoryBudget } from "../../lib/app-owned-memory";
3
+ import { create } from "@bufbuild/protobuf";
4
+ import {
5
+ DiagnosticsErrorSchema,
6
+ DiagnosticsResultSchema,
7
+ ErrorSchema,
8
+ GetBlobResultSchema,
9
+ KvClientMessageSchema,
10
+ McpErrorSchema,
11
+ McpResultSchema,
12
+ RequestContextResultSchema,
13
+ RequestContextSchema,
14
+ RequestContextSuccessSchema,
15
+ SetBlobResultSchema,
16
+ type ExecServerMessage,
17
+ type KvServerMessage,
18
+ } from "./gen/agent_pb";
19
+ import {
20
+ deleteExec,
21
+ grepExec,
22
+ lsExec,
23
+ readExec,
24
+ rejectDeleteExecForApplyPatch,
25
+ rejectDeleteExecForPolicy,
26
+ rejectGrepExecForPolicy,
27
+ rejectLsExecForPolicy,
28
+ rejectReadExecForPolicy,
29
+ rejectWriteExecForApplyPatch,
30
+ rejectWriteExecForPolicy,
31
+ writeExec,
32
+ } from "./native-exec-fs";
33
+ import { debugProviderDiagnostic } from "../../lib/debug";
34
+ import { fetchExec, rejectFetchExecForPolicy, type CursorNativeNetworkDeps } from "./native-exec-network";
35
+ import {
36
+ backgroundShellSpawnExec,
37
+ rejectBackgroundShellSpawnExecForPolicy,
38
+ rejectShellExecForPolicy,
39
+ rejectShellStreamExecForPolicy,
40
+ rejectWriteShellStdinExecForPolicy,
41
+ shellExec,
42
+ shellStreamExec,
43
+ writeShellStdinExec,
44
+ } from "./native-exec-shell";
45
+ import {
46
+ computerUseExec,
47
+ listMcpResourcesExec,
48
+ mcpExec,
49
+ readMcpResourceExec,
50
+ recordScreenExec,
51
+ type CursorNativeToolDeps,
52
+ } from "./native-exec-tools";
53
+ import { clientBytes, execBytes } from "./native-exec-common";
54
+ import type { McpToolDefinition } from "./gen/agent_pb";
55
+ import { OCX_RESPONSES_TOOL_PROVIDER } from "./tool-definitions";
56
+
57
+ export type CursorNativeExecDeps = CursorNativeNetworkDeps & CursorNativeToolDeps;
58
+
59
+ /**
60
+ * Execution context for a Cursor stream: the per-call executors plus the MCP tool definitions
61
+ * advertised to the server via `requestContextResult`. Without `mcpToolDefs`, the server is
62
+ * never told any MCP tools exist, so it never sends `mcpArgs`.
63
+ */
64
+ export interface CursorNativeExecContext extends CursorNativeExecDeps {
65
+ /** Stable owner for background shells created by this transport session. */
66
+ sessionId?: string;
67
+ mcpToolDefs?: McpToolDefinition[];
68
+ clientToolDefs?: McpToolDefinition[];
69
+ /** Unsafe opt-in escape hatch for Cursor server-driven local fs/shell/fetch execution. */
70
+ unsafeAllowNativeLocalExec?: boolean;
71
+ /** apply_patch is visible for this request; Cursor-native write/delete must not bypass Codex. */
72
+ rejectNativeFileMutations?: boolean;
73
+ /** The synthetic exact-match edit tools (edit_file / multi_edit) are advertised this request. */
74
+ structuredEditAvailable?: boolean;
75
+ }
76
+
77
+ export function cursorUnsafeNativeLocalExecEnabled(input: Pick<CursorNativeExecContext, "unsafeAllowNativeLocalExec"> = {}): boolean {
78
+ return input.unsafeAllowNativeLocalExec === true;
79
+ }
80
+
81
+ /**
82
+ * Content-addressed blob store shared across streams. Bounded: without eviction a long-running
83
+ * proxy accumulates every conversation's prompt blobs forever (unbounded memory) and any stale
84
+ * blob stays servable indefinitely — a cross-conversation contamination enabler if Cursor's
85
+ * server-side state ever references old ids (devlog 260702 P0). Continuation requests re-store
86
+ * their blobs on every turn (`rootPromptMessages` → `storeCursorBlob`), so TTL + cap eviction is
87
+ * safe for live sessions: only genuinely abandoned entries age out.
88
+ */
89
+ const BLOB_TTL_MS = 15 * 60_000;
90
+ const BLOB_MAX_ENTRIES = 4_096;
91
+ const BLOB_MAX_ENTRY_BYTES = 16 * 1024 * 1024;
92
+ export const CURSOR_BLOB_MAX_TOTAL_BYTES = 64 * 1024 * 1024;
93
+
94
+ type CursorBlobProvenance = "local-regenerated" | "remote-setBlobArgs";
95
+ export type CursorBlobRequestScopeToken = symbol;
96
+
97
+ interface CursorBlobEntry {
98
+ data: Uint8Array;
99
+ storedAt: number;
100
+ sizeBytes: number;
101
+ provenance: CursorBlobProvenance;
102
+ requestPins: Set<CursorBlobRequestScopeToken>;
103
+ }
104
+
105
+ type CursorBlobRejectionReason = "entry_too_large" | "pinned_saturation" | "request_pinned_conflict";
106
+ type CursorBlobAdmission =
107
+ | { admitted: true; replaced: boolean }
108
+ | { admitted: false; reason: CursorBlobRejectionReason };
109
+
110
+ interface CursorBlobLimits {
111
+ ttlMs: number;
112
+ maxEntries: number;
113
+ maxEntryBytes: number;
114
+ maxTotalBytes: number;
115
+ }
116
+
117
+ interface CursorBlobRequestScopeState {
118
+ keys: Set<string>;
119
+ sealed: boolean;
120
+ }
121
+
122
+ const DEFAULT_BLOB_LIMITS: CursorBlobLimits = {
123
+ ttlMs: BLOB_TTL_MS,
124
+ maxEntries: BLOB_MAX_ENTRIES,
125
+ maxEntryBytes: BLOB_MAX_ENTRY_BYTES,
126
+ maxTotalBytes: CURSOR_BLOB_MAX_TOTAL_BYTES,
127
+ };
128
+
129
+ const blobs = new Map<string, CursorBlobEntry>();
130
+ const blobRequestScopes = new Map<CursorBlobRequestScopeToken, CursorBlobRequestScopeState>();
131
+ let blobLimits = { ...DEFAULT_BLOB_LIMITS };
132
+ let blobBytes = 0;
133
+ /** Retained key-string bytes (separate from the payload cap — see key()). */
134
+ let blobKeyBytes = 0;
135
+ let blobLocalBytes = 0;
136
+ let blobPinnedBytes = 0;
137
+ let blobEvictableBytes = 0;
138
+ let blobOldestEvictableAt: number | null = null;
139
+ let rejectedEntryTooLarge = 0;
140
+ let rejectedPinnedSaturation = 0;
141
+ let blobExpiryAccountingTimer: ReturnType<typeof setTimeout> | undefined;
142
+
143
+ function isExpired(entry: CursorBlobEntry, now: number): boolean {
144
+ return now - entry.storedAt >= blobLimits.ttlMs;
145
+ }
146
+
147
+ function bytesEqual(a: Uint8Array, b: Uint8Array): boolean {
148
+ if (a.byteLength !== b.byteLength) return false;
149
+ for (let i = 0; i < a.byteLength; i++) if (a[i] !== b[i]) return false;
150
+ return true;
151
+ }
152
+
153
+ function recomputeBlobClassAccounting(): void {
154
+ const now = Date.now();
155
+ let localBytes = 0;
156
+ let pinnedBytes = 0;
157
+ let evictableBytes = 0;
158
+ let oldestAt: number | null = null;
159
+ for (const [k, entry] of blobs) {
160
+ const requestPinned = entry.requestPins.size > 0;
161
+ const provenancePinned = entry.provenance === "remote-setBlobArgs" && !isExpired(entry, now);
162
+ if (entry.provenance === "local-regenerated") localBytes += entry.sizeBytes;
163
+ // Key strings classify WITH their entry: a zero-payload blob must stay
164
+ // evictable/pinned exactly as its payload would be, or the budget cannot
165
+ // select it even though the total snapshot counts its key.
166
+ if (requestPinned || provenancePinned) pinnedBytes += entry.sizeBytes + k.length;
167
+ if (!requestPinned && (entry.provenance === "local-regenerated" || isExpired(entry, now))) {
168
+ evictableBytes += entry.sizeBytes + k.length;
169
+ oldestAt = oldestAt === null ? entry.storedAt : Math.min(oldestAt, entry.storedAt);
170
+ }
171
+ }
172
+ blobLocalBytes = localBytes;
173
+ blobPinnedBytes = pinnedBytes;
174
+ blobEvictableBytes = evictableBytes;
175
+ blobOldestEvictableAt = oldestAt;
176
+ scheduleBlobExpiryAccounting(now);
177
+ }
178
+
179
+ function reconcileBlobClassAccountingAndEnforce(): void {
180
+ recomputeBlobClassAccounting();
181
+ enforceAppOwnedMemoryBudget();
182
+ }
183
+
184
+ function scheduleBlobExpiryAccounting(now: number): void {
185
+ if (blobExpiryAccountingTimer) clearTimeout(blobExpiryAccountingTimer);
186
+ blobExpiryAccountingTimer = undefined;
187
+ let nextExpiry = Number.POSITIVE_INFINITY;
188
+ for (const entry of blobs.values()) {
189
+ if (entry.provenance !== "remote-setBlobArgs" || entry.requestPins.size > 0) continue;
190
+ const expiresAt = entry.storedAt + blobLimits.ttlMs;
191
+ if (expiresAt > now) nextExpiry = Math.min(nextExpiry, expiresAt);
192
+ }
193
+ if (!Number.isFinite(nextExpiry)) return;
194
+ blobExpiryAccountingTimer = setTimeout(() => {
195
+ blobExpiryAccountingTimer = undefined;
196
+ reconcileBlobClassAccountingAndEnforce();
197
+ }, Math.max(0, nextExpiry - now));
198
+ blobExpiryAccountingTimer.unref?.();
199
+ }
200
+
201
+ function deleteBlob(k: string, recompute = true): number {
202
+ const entry = blobs.get(k);
203
+ if (!entry) return 0;
204
+ blobs.delete(k);
205
+ blobBytes -= entry.sizeBytes;
206
+ blobKeyBytes -= k.length;
207
+ for (const scope of entry.requestPins) blobRequestScopes.get(scope)?.keys.delete(k);
208
+ if (recompute) recomputeBlobClassAccounting();
209
+ // Full logical release (payload + key): the retained-store snapshot counts
210
+ // both, so budget enforcement must see both leave.
211
+ return entry.sizeBytes + k.length;
212
+ }
213
+
214
+ function releaseHydratedBlob(k: string, requestScope?: CursorBlobRequestScopeToken): void {
215
+ const entry = blobs.get(k);
216
+ if (!entry) return;
217
+ const scopes = requestScope ? [requestScope] : [...entry.requestPins];
218
+ let changed = false;
219
+ for (const scope of scopes) {
220
+ if (!entry.requestPins.delete(scope)) continue;
221
+ changed = true;
222
+ const state = blobRequestScopes.get(scope);
223
+ state?.keys.delete(k);
224
+ if (state?.sealed && state.keys.size === 0) blobRequestScopes.delete(scope);
225
+ }
226
+ if (changed) reconcileBlobClassAccountingAndEnforce();
227
+ }
228
+
229
+ function setBlob(
230
+ k: string,
231
+ data: Uint8Array,
232
+ provenance: CursorBlobProvenance,
233
+ requestScope?: CursorBlobRequestScopeToken,
234
+ ): CursorBlobAdmission {
235
+ if (data.byteLength > blobLimits.maxEntryBytes) {
236
+ rejectedEntryTooLarge++;
237
+ return { admitted: false, reason: "entry_too_large" };
238
+ }
239
+
240
+ const now = Date.now();
241
+ const existing = blobs.get(k);
242
+ const sameData = existing ? bytesEqual(existing.data, data) : false;
243
+ if (existing && !sameData && existing.requestPins.size > 0) {
244
+ return { admitted: false, reason: "request_pinned_conflict" };
245
+ }
246
+
247
+ const removals = new Set<string>();
248
+ for (const [candidateKey, entry] of blobs) {
249
+ if (candidateKey === k && sameData) continue;
250
+ if (entry.requestPins.size === 0 && isExpired(entry, now)) removals.add(candidateKey);
251
+ }
252
+
253
+ const existingRemovedByTtl = existing !== undefined && removals.has(k);
254
+ const reuseExisting = existing !== undefined && sameData && !existingRemovedByTtl;
255
+ const mergedProvenance: CursorBlobProvenance = reuseExisting && existing.provenance === "remote-setBlobArgs"
256
+ ? "remote-setBlobArgs"
257
+ : provenance;
258
+ const storedAt = reuseExisting && existing.provenance === "remote-setBlobArgs" && provenance === "local-regenerated"
259
+ ? existing.storedAt
260
+ : now;
261
+
262
+ let projectedBytes = blobBytes;
263
+ let projectedCount = blobs.size;
264
+ for (const candidateKey of removals) {
265
+ const entry = blobs.get(candidateKey);
266
+ if (!entry) continue;
267
+ projectedBytes -= entry.sizeBytes;
268
+ projectedCount--;
269
+ }
270
+ if (existing && !existingRemovedByTtl) {
271
+ projectedBytes -= existing.sizeBytes;
272
+ projectedCount--;
273
+ }
274
+ projectedBytes += data.byteLength;
275
+ projectedCount++;
276
+
277
+ if (projectedBytes > blobLimits.maxTotalBytes || projectedCount > blobLimits.maxEntries) {
278
+ const localVictims = [...blobs.entries()].sort((a, b) => a[1].storedAt - b[1].storedAt);
279
+ for (const [candidateKey, entry] of localVictims) {
280
+ if (
281
+ candidateKey === k
282
+ || removals.has(candidateKey)
283
+ || entry.requestPins.size > 0
284
+ || entry.provenance !== "local-regenerated"
285
+ ) continue;
286
+ removals.add(candidateKey);
287
+ projectedBytes -= entry.sizeBytes;
288
+ projectedCount--;
289
+ if (projectedBytes <= blobLimits.maxTotalBytes && projectedCount <= blobLimits.maxEntries) break;
290
+ }
291
+ }
292
+
293
+ if (projectedBytes > blobLimits.maxTotalBytes || projectedCount > blobLimits.maxEntries) {
294
+ rejectedPinnedSaturation++;
295
+ return { admitted: false, reason: "pinned_saturation" };
296
+ }
297
+
298
+ // Carry forward only pins whose scope still has live state; a dead scope's
299
+ // token can never be released again (review C1-1).
300
+ const requestPins = new Set<CursorBlobRequestScopeToken>();
301
+ if (reuseExisting) {
302
+ for (const scope of existing.requestPins) {
303
+ if (blobRequestScopes.has(scope)) requestPins.add(scope);
304
+ }
305
+ }
306
+ // A pin is only attached when the scope still has live UNSEALED state:
307
+ // sealing fixes the advertised key set (locked contract), so a remote
308
+ // setBlobArgs arriving after seal must not extend the pin set — and a
309
+ // sealed scope whose advertised keys have all hydrated is already deleted,
310
+ // so attaching its stale token would create a permanent untracked pin the
311
+ // terminal release could never clear (reviews C1-1/C2-1).
312
+ const scopeState = requestScope ? blobRequestScopes.get(requestScope) : undefined;
313
+ if (requestScope && scopeState && !scopeState.sealed) requestPins.add(requestScope);
314
+ const entry: CursorBlobEntry = {
315
+ data: reuseExisting ? existing.data : data.slice(),
316
+ storedAt,
317
+ sizeBytes: data.byteLength,
318
+ provenance: mergedProvenance,
319
+ requestPins,
320
+ };
321
+
322
+ for (const candidateKey of removals) deleteBlob(candidateKey, false);
323
+ if (blobs.has(k)) deleteBlob(k, false);
324
+ blobs.set(k, entry);
325
+ blobBytes += entry.sizeBytes;
326
+ blobKeyBytes += k.length;
327
+ for (const scope of entry.requestPins) blobRequestScopes.get(scope)?.keys.add(k);
328
+ reconcileBlobClassAccountingAndEnforce();
329
+ return { admitted: true, replaced: existing !== undefined };
330
+ }
331
+
332
+ function getBlob(k: string): Uint8Array | undefined {
333
+ const entry = blobs.get(k);
334
+ if (!entry) return undefined;
335
+ if (entry.requestPins.size === 0 && isExpired(entry, Date.now())) {
336
+ deleteBlob(k);
337
+ return undefined;
338
+ }
339
+ return entry.data;
340
+ }
341
+
342
+ /**
343
+ * Raw blob IDs up to this size keep their hex passthrough (every ID the live
344
+ * protocol carries is a 32-byte digest). Anything larger maps to a fixed-size
345
+ * SHA-256 hex of the raw bytes — the derivation is symmetric across
346
+ * setBlobArgs/getBlobArgs, so the round-trip still works, but a hostile or
347
+ * malformed multi-MiB ID can never become an unbounded hex Map key.
348
+ * The `h:`/`d:` prefix domain-separates the two namespaces: a digested ID's
349
+ * key can never collide with a raw 32-byte ID that happens to BE that digest.
350
+ */
351
+ const MAX_BLOB_ID_PASSTHROUGH_BYTES = 64;
352
+
353
+ function key(bytes: Uint8Array): string {
354
+ if (bytes.byteLength <= MAX_BLOB_ID_PASSTHROUGH_BYTES) return `h:${Buffer.from(bytes).toString("hex")}`;
355
+ return `d:${createHash("sha256").update(bytes).digest("hex")}`;
356
+ }
357
+
358
+ /**
359
+ * Store a blob (SHA-256 keyed) in the shared map that `handleCursorNativeKv` serves, and return its
360
+ * blob id. Cursor's `rootPromptMessagesJson`/turn entries are blob IDS, not inline content — the
361
+ * server fetches the bytes back via `getBlobArgs`. Mirrors jawcode `createBlobId`/`storeCursorBlob`.
362
+ */
363
+ export class CursorBlobAdmissionError extends Error {
364
+ readonly code = "cursor_blob_capacity";
365
+
366
+ constructor(readonly reason: CursorBlobRejectionReason) {
367
+ super("Cursor blob capacity is exhausted; retry with a smaller request.");
368
+ this.name = "CursorBlobAdmissionError";
369
+ }
370
+ }
371
+
372
+ let blobScopeSequence = 0;
373
+
374
+ export function createCursorBlobRequestScope(): CursorBlobRequestScopeToken {
375
+ // Unique description per token so debug snapshots expose exact pin
376
+ // IDENTITY, not just pin counts (review C2-2: identical descriptions made
377
+ // scope-swap bugs invisible to deep comparison).
378
+ const scope = Symbol(`cursor-blob-request-${++blobScopeSequence}`);
379
+ blobRequestScopes.set(scope, { keys: new Set(), sealed: false });
380
+ return scope;
381
+ }
382
+
383
+ export function sealCursorBlobRequestScope(scope: CursorBlobRequestScopeToken): void {
384
+ const state = blobRequestScopes.get(scope);
385
+ if (!state) return;
386
+ state.sealed = true;
387
+ if (state.keys.size === 0) blobRequestScopes.delete(scope);
388
+ }
389
+
390
+ export function releaseCursorBlobRequestScope(scope: CursorBlobRequestScopeToken): void {
391
+ const state = blobRequestScopes.get(scope);
392
+ if (!state) return;
393
+ for (const k of state.keys) blobs.get(k)?.requestPins.delete(scope);
394
+ blobRequestScopes.delete(scope);
395
+ reconcileBlobClassAccountingAndEnforce();
396
+ }
397
+
398
+ export function storeCursorBlob(data: Uint8Array, requestScope?: CursorBlobRequestScopeToken): Uint8Array {
399
+ const blobId = new Uint8Array(createHash("sha256").update(data).digest());
400
+ const admission = setBlob(key(blobId), data, "local-regenerated", requestScope);
401
+ if (!admission.admitted) throw new CursorBlobAdmissionError(admission.reason);
402
+ return blobId;
403
+ }
404
+
405
+ export interface CursorBlobMetrics {
406
+ count: number;
407
+ totalBytes: number;
408
+ keyBytes: number;
409
+ localBytes: number;
410
+ pinnedBytes: number;
411
+ rejectedEntryTooLarge: number;
412
+ rejectedPinnedSaturation: number;
413
+ oldestAt: number | null;
414
+ }
415
+
416
+ export function cursorBlobMetrics(): CursorBlobMetrics {
417
+ return {
418
+ count: blobs.size,
419
+ totalBytes: blobBytes,
420
+ keyBytes: blobKeyBytes,
421
+ localBytes: blobLocalBytes,
422
+ pinnedBytes: blobPinnedBytes,
423
+ rejectedEntryTooLarge,
424
+ rejectedPinnedSaturation,
425
+ oldestAt: blobOldestEvictableAt,
426
+ };
427
+ }
428
+
429
+ export function cursorBlobRetainedStoreSnapshot(): {
430
+ count: number;
431
+ bytes: number;
432
+ evictableBytes: number;
433
+ pinnedBytes: number;
434
+ oldestAt: number | null;
435
+ } {
436
+ return {
437
+ count: blobs.size,
438
+ // Payload + retained key strings: the framework must see everything the
439
+ // store retains. The 64 MiB admission cap stays payload-only by design.
440
+ bytes: blobBytes + blobKeyBytes,
441
+ evictableBytes: blobEvictableBytes,
442
+ pinnedBytes: blobPinnedBytes,
443
+ oldestAt: blobOldestEvictableAt,
444
+ };
445
+ }
446
+
447
+ export function evictOldestCursorBlobForBudget(): number {
448
+ const now = Date.now();
449
+ let oldest: [string, CursorBlobEntry] | undefined;
450
+ for (const candidate of blobs) {
451
+ const entry = candidate[1];
452
+ if (entry.requestPins.size > 0) continue;
453
+ if (entry.provenance !== "local-regenerated" && !isExpired(entry, now)) continue;
454
+ if (!oldest || entry.storedAt < oldest[1].storedAt) oldest = candidate;
455
+ }
456
+ return oldest ? deleteBlob(oldest[0]) : 0;
457
+ }
458
+
459
+ export function setCursorBlobLimitsForTests(limits?: Partial<CursorBlobLimits>): void {
460
+ resetCursorBlobStateForTests();
461
+ blobLimits = limits ? { ...DEFAULT_BLOB_LIMITS, ...limits } : { ...DEFAULT_BLOB_LIMITS };
462
+ }
463
+
464
+ export function resetCursorBlobStateForTests(): void {
465
+ if (blobExpiryAccountingTimer) clearTimeout(blobExpiryAccountingTimer);
466
+ blobExpiryAccountingTimer = undefined;
467
+ blobs.clear();
468
+ blobRequestScopes.clear();
469
+ blobBytes = 0;
470
+ blobKeyBytes = 0;
471
+ rejectedEntryTooLarge = 0;
472
+ rejectedPinnedSaturation = 0;
473
+ recomputeBlobClassAccounting();
474
+ }
475
+
476
+ export function cursorBlobStoreDebugSnapshotForTests(): Array<{
477
+ key: string;
478
+ sizeBytes: number;
479
+ storedAt: number;
480
+ provenance: CursorBlobProvenance;
481
+ requestPins: number;
482
+ dataDigest: string;
483
+ pinTokens: string[];
484
+ }> {
485
+ return [...blobs].map(([blobKey, entry]) => ({
486
+ key: blobKey,
487
+ sizeBytes: entry.sizeBytes,
488
+ storedAt: entry.storedAt,
489
+ provenance: entry.provenance,
490
+ requestPins: entry.requestPins.size,
491
+ // Byte-for-byte content identity + exact pin-set membership so rollback
492
+ // tests can deep-compare complete state (review C1-2).
493
+ dataDigest: createHash("sha256").update(entry.data).digest("hex"),
494
+ pinTokens: [...entry.requestPins].map(scope => String(scope.description ?? "scope")).sort(),
495
+ }));
496
+ }
497
+
498
+ export async function handleCursorNativeExec(execMsg: ExecServerMessage, deps: CursorNativeExecContext = {}): Promise<Uint8Array[]> {
499
+ const execCase = execMsg.message.case;
500
+ if (execCase === "requestContextArgs") {
501
+ const tools = [...(deps.mcpToolDefs ?? []), ...(deps.clientToolDefs ?? [])];
502
+ return [execBytes(execMsg, "requestContextResult", create(RequestContextResultSchema, {
503
+ result: { case: "success", value: create(RequestContextSuccessSchema, { requestContext: create(RequestContextSchema, { tools }) }) },
504
+ }))];
505
+ }
506
+ if (!cursorUnsafeNativeLocalExecEnabled(deps)) {
507
+ if (execCase === "readArgs") return [rejectReadExecForPolicy(execMsg)];
508
+ if (execCase === "writeArgs") return [rejectWriteExecForPolicy(execMsg)];
509
+ if (execCase === "deleteArgs") return [rejectDeleteExecForPolicy(execMsg)];
510
+ if (execCase === "lsArgs") return [rejectLsExecForPolicy(execMsg)];
511
+ if (execCase === "grepArgs") return [rejectGrepExecForPolicy(execMsg)];
512
+ if (execCase === "shellArgs") return [rejectShellExecForPolicy(execMsg)];
513
+ if (execCase === "shellStreamArgs") return rejectShellStreamExecForPolicy(execMsg);
514
+ if (execCase === "backgroundShellSpawnArgs") return [rejectBackgroundShellSpawnExecForPolicy(execMsg)];
515
+ if (execCase === "writeShellStdinArgs") return [rejectWriteShellStdinExecForPolicy(execMsg)];
516
+ if (execCase === "fetchArgs") return [rejectFetchExecForPolicy(execMsg)];
517
+ }
518
+ if (execCase === "readArgs") return [readExec(execMsg)];
519
+ if (execCase === "writeArgs") return [deps.rejectNativeFileMutations ? rejectWriteExecForApplyPatch(execMsg, deps.structuredEditAvailable === true) : writeExec(execMsg)];
520
+ if (execCase === "deleteArgs") return [deps.rejectNativeFileMutations ? rejectDeleteExecForApplyPatch(execMsg, deps.structuredEditAvailable === true) : deleteExec(execMsg)];
521
+ if (execCase === "lsArgs") return [lsExec(execMsg)];
522
+ if (execCase === "grepArgs") return [grepExec(execMsg)];
523
+ if (execCase === "shellArgs") return [shellExec(execMsg)];
524
+ if (execCase === "shellStreamArgs") return shellStreamExec(execMsg);
525
+ if (execCase === "backgroundShellSpawnArgs") return [backgroundShellSpawnExec(execMsg, deps.sessionId ?? "")];
526
+ if (execCase === "writeShellStdinArgs") return [writeShellStdinExec(execMsg, deps.sessionId ?? "")];
527
+ if (execCase === "fetchArgs") return [await fetchExec(execMsg, deps)];
528
+ if (execCase === "mcpArgs" && execMsg.message.value.providerIdentifier === OCX_RESPONSES_TOOL_PROVIDER) {
529
+ return [execBytes(execMsg, "mcpResult", create(McpResultSchema, {
530
+ result: {
531
+ case: "error",
532
+ value: create(McpErrorSchema, { error: "Cursor requested a client Responses tool through the native exec channel; bridge suspension is not implemented." }),
533
+ },
534
+ }))];
535
+ }
536
+ if (execCase === "mcpArgs") return [await mcpExec(execMsg, deps)];
537
+ if (execCase === "listMcpResourcesExecArgs") return [await listMcpResourcesExec(execMsg, deps)];
538
+ if (execCase === "readMcpResourceExecArgs") return [await readMcpResourceExec(execMsg, deps)];
539
+ if (execCase === "computerUseArgs") return [await computerUseExec(execMsg, deps)];
540
+ if (execCase === "recordScreenArgs") return [await recordScreenExec(execMsg, deps)];
541
+ if (execCase === "diagnosticsArgs") {
542
+ const path = execMsg.message.value.path;
543
+ return [execBytes(execMsg, "diagnosticsResult", create(DiagnosticsResultSchema, {
544
+ result: {
545
+ case: "error",
546
+ value: create(DiagnosticsErrorSchema, {
547
+ path,
548
+ error: "Diagnostics are not supported by the Remodex Cursor transport.",
549
+ }),
550
+ },
551
+ }))];
552
+ }
553
+ // Unknown exec case — Cursor added a new native exec type that our protobuf definition does not
554
+ // include yet. Return an empty reply so the stream stays alive instead of throwing (which kills
555
+ // the entire gRPC connection via failAndClear). Same class of bug as #116.
556
+ debugProviderDiagnostic("cursor", "unknown-exec-case", { execCase: execCase ?? "unknown", execId: execMsg.execId });
557
+ return [];
558
+ }
559
+
560
+
561
+ export function handleCursorNativeKv(
562
+ kvMsg: KvServerMessage,
563
+ requestScope?: CursorBlobRequestScopeToken,
564
+ ): Uint8Array {
565
+ if (kvMsg.message.case === "getBlobArgs") {
566
+ const blobKey = key(kvMsg.message.value.blobId);
567
+ const blobData = getBlob(blobKey);
568
+ if (blobData) releaseHydratedBlob(blobKey, requestScope);
569
+ return clientBytes({
570
+ message: {
571
+ case: "kvClientMessage",
572
+ value: create(KvClientMessageSchema, {
573
+ id: kvMsg.id,
574
+ message: { case: "getBlobResult", value: create(GetBlobResultSchema, blobData ? { blobData } : {}) },
575
+ }),
576
+ },
577
+ });
578
+ }
579
+ if (kvMsg.message.case === "setBlobArgs") {
580
+ const admission = setBlob(
581
+ key(kvMsg.message.value.blobId),
582
+ kvMsg.message.value.blobData,
583
+ "remote-setBlobArgs",
584
+ requestScope,
585
+ );
586
+ return clientBytes({
587
+ message: {
588
+ case: "kvClientMessage",
589
+ value: create(KvClientMessageSchema, {
590
+ id: kvMsg.id,
591
+ message: {
592
+ case: "setBlobResult",
593
+ value: create(SetBlobResultSchema, admission.admitted ? {} : {
594
+ error: create(ErrorSchema, {
595
+ message: "Cursor blob capacity is exhausted; the blob was not stored.",
596
+ }),
597
+ }),
598
+ },
599
+ }),
600
+ },
601
+ });
602
+ }
603
+ return clientBytes({ message: { case: "kvClientMessage", value: create(KvClientMessageSchema, { id: kvMsg.id }) } });
604
+ }