@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,181 @@
1
+ /**
2
+ * /v1/alpha/search relay.
3
+ *
4
+ * codex-rs's built-in search client executes CLIENT-SIDE: it POSTs `alpha/search` against the
5
+ * configured base_url with the same ChatGPT bearer auth used for model requests. Under Design B
6
+ * injection base_url is this proxy, so the request otherwise dies on the /v1/* JSON-404 guard.
7
+ * The endpoint is private to the ChatGPT Codex backend, so routed providers and OpenAI API-key
8
+ * providers cannot serve it. Relay the JSON request and response verbatim through the configured
9
+ * ChatGPT forward provider.
10
+ */
11
+ import { formatErrorResponse } from "../bridge";
12
+ import {
13
+ CodexAccountCooldownError,
14
+ codexMainProfileDrainingResponse,
15
+ cooldownErrorResponse,
16
+ CodexAuthContextError,
17
+ CodexMainProfileDrainingError,
18
+ CodexPoolAuthenticationError,
19
+ CodexThreadAffinityExpiredError,
20
+ } from "../codex/auth-context";
21
+ import { codexAccountNamespaceForModel } from "../codex/account-namespace-match";
22
+ import { formatCodexProviderForLog } from "../codex/routing";
23
+ import { signalWithTimeout } from "../lib/abort";
24
+ import { sidecarEnter } from "../lib/sidecar-tracker";
25
+ import type { OcxConfig } from "../types";
26
+ import {
27
+ listOpenAiForwardSidecarCandidates,
28
+ resolveFirstUsableOpenAiSidecar,
29
+ type ExactOpenAiSidecarAccount,
30
+ } from "../providers/openai-sidecar";
31
+ import { routeModel } from "../router";
32
+ import { readJsonRequestBody } from "./request-decompress";
33
+ import { ForwardAdmissionCredentialError, validateForwardAdmissionCredential } from "./auth-cors";
34
+ import type { RequestLogContext } from "./request-log";
35
+ import { codexLogAccountId, decodeRequestErrorResponse } from "./responses";
36
+ import type { AdmissionLease } from "../lib/admission";
37
+ import { codexAccountSelectionForTurn } from "./lifecycle";
38
+
39
+ /**
40
+ * Default TOTAL deadline for one search relay. alpha/search is non-streaming JSON — response
41
+ * headers arrive only when the search finishes — so the budget must cover the whole request.
42
+ * Overridable via config.search.timeoutMs; never config.connectTimeoutMs, whose documented
43
+ * contract is the DNS/TCP/TLS/header-arrival budget (a 10s connect budget would kill every
44
+ * long-running search).
45
+ */
46
+ const SEARCH_UPSTREAM_TIMEOUT_MS = 200_000;
47
+ const SEARCH_RESPONSE_MAX_BYTES = 16 * 1024 * 1024;
48
+
49
+ export async function handleSearch(
50
+ req: Request,
51
+ config: OcxConfig,
52
+ logCtx: RequestLogContext,
53
+ turnAdmissionLease?: AdmissionLease,
54
+ ): Promise<Response> {
55
+ try { validateForwardAdmissionCredential(req.headers, config); }
56
+ catch (err) {
57
+ if (err instanceof ForwardAdmissionCredentialError) return formatErrorResponse(401, "authentication_error", err.message);
58
+ throw err;
59
+ }
60
+ let body: unknown;
61
+ try {
62
+ body = await readJsonRequestBody(req);
63
+ } catch (err) {
64
+ return decodeRequestErrorResponse(err, "search");
65
+ }
66
+ const model = (body as { model?: unknown } | null)?.model;
67
+ if (typeof model === "string" && model) logCtx.model = model;
68
+
69
+ let exactAccount: ExactOpenAiSidecarAccount | undefined;
70
+ let relayBody = body;
71
+ const accountNamespace = typeof model === "string"
72
+ ? codexAccountNamespaceForModel(config.codexAccountNamespaces, model)
73
+ : undefined;
74
+ if (accountNamespace && typeof model === "string") {
75
+ try {
76
+ const route = routeModel(config, model);
77
+ if (!route.codexAccountId || route.codexAccountNamespace !== accountNamespace) {
78
+ return formatErrorResponse(400, "invalid_request_error", "Invalid Codex account-qualified search model");
79
+ }
80
+ exactAccount = { accountId: route.codexAccountId, modelId: route.modelId };
81
+ logCtx.provider = `${route.providerName}-${accountNamespace}`;
82
+ logCtx.routeDecision = route.routeDecision;
83
+ // The ChatGPT search endpoint only understands the native model slug. The
84
+ // account namespace is proxy routing syntax and must not cross the wire.
85
+ relayBody = { ...(body as Record<string, unknown>), model: route.modelId };
86
+ } catch (err) {
87
+ return formatErrorResponse(
88
+ 400,
89
+ "invalid_request_error",
90
+ err instanceof Error ? err.message : "Invalid Codex account-qualified search model",
91
+ );
92
+ }
93
+ }
94
+
95
+ const candidates = listOpenAiForwardSidecarCandidates(config);
96
+ if (candidates.length === 0) {
97
+ return formatErrorResponse(
98
+ 400,
99
+ "invalid_request_error",
100
+ "Built-in web search needs a ChatGPT forward provider, but none is configured in Remodex. "
101
+ + "Routed and OpenAI API-key providers cannot serve /v1/alpha/search.",
102
+ );
103
+ }
104
+
105
+ let upstream: Awaited<ReturnType<typeof resolveFirstUsableOpenAiSidecar>>;
106
+ try {
107
+ upstream = await resolveFirstUsableOpenAiSidecar(candidates, req.headers, config, {
108
+ exactAccount,
109
+ beginCodexAccountSelection: codexAccountSelectionForTurn(turnAdmissionLease),
110
+ });
111
+ if (!upstream) {
112
+ return formatErrorResponse(
113
+ 401,
114
+ "authentication_error",
115
+ "web search relay needs ChatGPT auth (Authorization header)",
116
+ );
117
+ }
118
+ logCtx.provider = accountNamespace
119
+ ? `${upstream.providerName}-${accountNamespace}`
120
+ : formatCodexProviderForLog(upstream.providerName, codexLogAccountId(upstream.authContext), config);
121
+ } catch (err) {
122
+ if (err instanceof CodexAccountCooldownError) {
123
+ return cooldownErrorResponse(err, Date.now(), accountNamespace);
124
+ }
125
+ if (err instanceof CodexMainProfileDrainingError) return codexMainProfileDrainingResponse();
126
+ if (err instanceof CodexThreadAffinityExpiredError) {
127
+ return formatErrorResponse(409, "invalid_request_error", "Codex thread account affinity expired; start a new session");
128
+ }
129
+ if (err instanceof CodexAuthContextError) {
130
+ const safeAccountLabel = accountNamespace
131
+ ? `openai-${accountNamespace}`
132
+ : formatCodexProviderForLog("openai", err.accountId, config);
133
+ console.error(`[search] Pool account ${safeAccountLabel} token failed; reauthentication required`);
134
+ return formatErrorResponse(401, "authentication_error", "Selected Codex account needs reauthentication");
135
+ }
136
+ if (err instanceof CodexPoolAuthenticationError) return formatErrorResponse(401, "authentication_error", err.message);
137
+ throw err;
138
+ }
139
+
140
+ const headers: Record<string, string> = { "content-type": "application/json" };
141
+ if (upstream.provider.headers) Object.assign(headers, upstream.provider.headers);
142
+ for (const [name, value] of upstream.headers) headers[name] = value;
143
+ const url = `${upstream.provider.baseUrl}/alpha/search`;
144
+ const timeoutMs = config.search?.timeoutMs ?? SEARCH_UPSTREAM_TIMEOUT_MS;
145
+ const linkedSignal = signalWithTimeout(timeoutMs, req.signal);
146
+ const sidecarExit = sidecarEnter("search");
147
+ try {
148
+ const upstreamResponse = await fetch(url, {
149
+ method: "POST",
150
+ headers,
151
+ body: JSON.stringify(relayBody),
152
+ signal: linkedSignal.signal,
153
+ });
154
+ const payload = await upstreamResponse.arrayBuffer();
155
+ if (payload.byteLength > SEARCH_RESPONSE_MAX_BYTES) {
156
+ return formatErrorResponse(502, "upstream_error", `search response too large (${payload.byteLength} bytes)`);
157
+ }
158
+ upstream.recordOutcome?.(upstreamResponse.status);
159
+ const relayHeaders: Record<string, string> = {};
160
+ const contentType = upstreamResponse.headers.get("content-type");
161
+ if (contentType) relayHeaders["content-type"] = contentType;
162
+ return new Response(payload, { status: upstreamResponse.status, headers: relayHeaders });
163
+ } catch (err) {
164
+ if (req.signal.aborted) {
165
+ return formatErrorResponse(499, "client_closed_request", "search request canceled by client");
166
+ }
167
+ if (err instanceof Error && err.name === "TimeoutError") {
168
+ upstream.recordOutcome?.("timeout");
169
+ return formatErrorResponse(504, "upstream_error", "search upstream timed out");
170
+ }
171
+ upstream.recordOutcome?.("connect_error");
172
+ return formatErrorResponse(
173
+ 502,
174
+ "upstream_error",
175
+ `search relay failed: ${err instanceof Error ? err.message : String(err)}`,
176
+ );
177
+ } finally {
178
+ sidecarExit();
179
+ linkedSignal.cleanup();
180
+ }
181
+ }
@@ -0,0 +1,292 @@
1
+ export const MAX_CLIENT_SSE_FRAME_BYTES = 4 * 1024 * 1024;
2
+
3
+ const LF_LF = Uint8Array.of(10, 10);
4
+ const LF_CR_LF = Uint8Array.of(10, 13, 10);
5
+ const CR_LF_LF = Uint8Array.of(13, 10, 10);
6
+ const CR_LF_CR_LF = Uint8Array.of(13, 10, 13, 10);
7
+
8
+ export class SseFrameTooLargeError extends Error {
9
+ readonly maxBytes: number;
10
+
11
+ constructor(maxBytes: number) {
12
+ super(`upstream SSE frame exceeded ${maxBytes} bytes`);
13
+ this.name = "SseFrameTooLargeError";
14
+ this.maxBytes = maxBytes;
15
+ }
16
+ }
17
+
18
+ export class SseFrameCountLimitError extends Error {
19
+ readonly maxFrames: number;
20
+
21
+ constructor(maxFrames: number) {
22
+ super(`upstream SSE chunk exceeded ${maxFrames} frame limit`);
23
+ this.name = "SseFrameCountLimitError";
24
+ this.maxFrames = maxFrames;
25
+ }
26
+ }
27
+
28
+ export type BoundedSseFrame = {
29
+ block: Uint8Array;
30
+ delimiter: Uint8Array;
31
+ };
32
+
33
+ /**
34
+ * Classify the bytes at `index` as an SSE block delimiter.
35
+ *
36
+ * Returns the delimiter length in bytes, `0` when `index` does not start a
37
+ * delimiter, and `undefined` when more bytes are required to decide.
38
+ */
39
+ function delimiterLengthAt(
40
+ index: number,
41
+ length: number,
42
+ byteAt: (index: number) => number,
43
+ ): number | undefined {
44
+ const first = byteAt(index);
45
+ if (first === 10) {
46
+ if (index + 1 >= length) return undefined;
47
+ const second = byteAt(index + 1);
48
+ if (second === 10) return 2;
49
+ if (second !== 13) return 0;
50
+ if (index + 2 >= length) return undefined;
51
+ return byteAt(index + 2) === 10 ? 3 : 0;
52
+ }
53
+ if (first !== 13) return 0;
54
+ if (index + 1 >= length) return undefined;
55
+ if (byteAt(index + 1) !== 10) return 0;
56
+ if (index + 2 >= length) return undefined;
57
+ const third = byteAt(index + 2);
58
+ if (third === 10) return 3;
59
+ if (third !== 13) return 0;
60
+ if (index + 3 >= length) return undefined;
61
+ return byteAt(index + 3) === 10 ? 4 : 0;
62
+ }
63
+
64
+ function delimiterBytesAt(
65
+ index: number,
66
+ delimiterLength: number,
67
+ byteAt: (index: number) => number,
68
+ ): Uint8Array {
69
+ if (delimiterLength === 2) return LF_LF;
70
+ if (delimiterLength === 4) return CR_LF_CR_LF;
71
+ return byteAt(index) === 10 ? LF_CR_LF : CR_LF_LF;
72
+ }
73
+
74
+ function copyRange(
75
+ start: number,
76
+ end: number,
77
+ tailLength: number,
78
+ previousTail: Uint8Array,
79
+ chunk: Uint8Array,
80
+ ): Uint8Array {
81
+ const out = new Uint8Array(end - start);
82
+ for (let index = start; index < end; index += 1) {
83
+ out[index - start] = index < tailLength
84
+ ? previousTail[index]!
85
+ : chunk[index - tailLength]!;
86
+ }
87
+ return out;
88
+ }
89
+
90
+ /**
91
+ * True when a complete SSE block already commits a Responses terminal event.
92
+ *
93
+ * Framing errors in bytes *after* such a block must not retroactively turn an
94
+ * already-completed/failed/incomplete model turn into a transport failure. This
95
+ * helper is used only on the exceptional path, so decoding/JSON parsing has no
96
+ * cost on ordinary framing.
97
+ */
98
+ function isResponsesTerminalFrame(block: Uint8Array): boolean {
99
+ const data: string[] = [];
100
+ for (const line of new TextDecoder().decode(block).split(/\r?\n/)) {
101
+ if (!line.startsWith("data:")) continue;
102
+ const value = line.slice(5);
103
+ data.push(value.startsWith(" ") ? value.slice(1) : value);
104
+ }
105
+ if (data.length === 0) return false;
106
+ const payload = data.join("\n");
107
+ if (payload === "[DONE]") return false;
108
+ try {
109
+ const parsed = JSON.parse(payload) as { type?: unknown };
110
+ return parsed.type === "response.completed"
111
+ || parsed.type === "response.failed"
112
+ || parsed.type === "response.incomplete";
113
+ } catch {
114
+ return false;
115
+ }
116
+ }
117
+
118
+ /**
119
+ * Byte-bounded SSE block framer for client-facing protocol paths.
120
+ *
121
+ * The delimiter scanner works on raw bytes, so fragmented UTF-8 cannot change
122
+ * accounting and a hostile upstream cannot grow an unterminated JS string
123
+ * without limit. Candidate bytes live in one geometrically grown buffer rather
124
+ * than one allocation per upstream chunk, bounding both bytes and object count.
125
+ * Complete blocks are returned without their delimiter; the exact delimiter
126
+ * bytes are returned separately so callers can relay bytes unchanged.
127
+ */
128
+ export class BoundedSseFrameBuffer {
129
+ private readonly maxFrameBytes: number;
130
+ private readonly maxFramesPerFeed: number;
131
+ private delimiterTail: Uint8Array = new Uint8Array(0);
132
+ private candidate: Uint8Array = new Uint8Array(0);
133
+ private candidateBytes = 0;
134
+ private disposed = false;
135
+
136
+ constructor(maxFrameBytes = MAX_CLIENT_SSE_FRAME_BYTES) {
137
+ if (!Number.isSafeInteger(maxFrameBytes) || maxFrameBytes <= 0) {
138
+ throw new RangeError("maxFrameBytes must be a positive safe integer");
139
+ }
140
+ this.maxFrameBytes = maxFrameBytes;
141
+ // Delimiter-only input otherwise creates an object-amplification path that
142
+ // is independent of candidate bytes. Keep frame count proportional to the
143
+ // configured byte budget while leaving ample room for real Responses events.
144
+ this.maxFramesPerFeed = Math.max(1, Math.ceil(maxFrameBytes / 1024));
145
+ }
146
+
147
+ private clear(): void {
148
+ this.delimiterTail = new Uint8Array(0);
149
+ this.candidate = new Uint8Array(0);
150
+ this.candidateBytes = 0;
151
+ }
152
+
153
+ private ensureCapacity(requiredBytes: number): void {
154
+ if (this.candidate.byteLength >= requiredBytes) return;
155
+ if (requiredBytes > this.maxFrameBytes) {
156
+ throw new SseFrameTooLargeError(this.maxFrameBytes);
157
+ }
158
+ let capacity = this.candidate.byteLength === 0
159
+ ? Math.min(this.maxFrameBytes, Math.max(requiredBytes, 4096))
160
+ : this.candidate.byteLength;
161
+ while (capacity < requiredBytes) {
162
+ capacity = Math.min(this.maxFrameBytes, Math.max(requiredBytes, capacity * 2));
163
+ }
164
+ const grown = new Uint8Array(capacity);
165
+ if (this.candidateBytes > 0) {
166
+ grown.set(this.candidate.subarray(0, this.candidateBytes));
167
+ }
168
+ this.candidate = grown;
169
+ }
170
+
171
+ private retain(slice: Uint8Array): void {
172
+ if (slice.byteLength === 0) return;
173
+ const nextBytes = this.candidateBytes + slice.byteLength;
174
+ if (nextBytes > this.maxFrameBytes) {
175
+ this.clear();
176
+ this.disposed = true;
177
+ throw new SseFrameTooLargeError(this.maxFrameBytes);
178
+ }
179
+ this.ensureCapacity(nextBytes);
180
+ this.candidate.set(slice, this.candidateBytes);
181
+ this.candidateBytes = nextBytes;
182
+ }
183
+
184
+ private takeCandidate(): Uint8Array {
185
+ if (this.candidateBytes === 0) return new Uint8Array(0);
186
+ const block = this.candidate.slice(0, this.candidateBytes);
187
+ // Release the working allocation after each complete frame. This avoids
188
+ // retaining a rare multi-MiB frame allocation for the rest of a long-lived
189
+ // stream; normal small-frame allocation remains bounded by feed's frame cap.
190
+ this.candidate = new Uint8Array(0);
191
+ this.candidateBytes = 0;
192
+ return block;
193
+ }
194
+
195
+ feed(chunk: Uint8Array): BoundedSseFrame[] {
196
+ if (this.disposed) return [];
197
+ if (chunk.byteLength === 0) return [];
198
+
199
+ const frames: BoundedSseFrame[] = [];
200
+ const previousTail = this.delimiterTail;
201
+ this.delimiterTail = new Uint8Array(0);
202
+ const tailLength = previousTail.byteLength;
203
+ const totalLength = tailLength + chunk.byteLength;
204
+ const byteAt = (index: number): number => index < tailLength
205
+ ? previousTail[index]!
206
+ : chunk[index - tailLength]!;
207
+ const retainRange = (start: number, end: number): void => {
208
+ if (end <= start) return;
209
+ if (start < tailLength) {
210
+ this.retain(previousTail.subarray(start, Math.min(end, tailLength)));
211
+ }
212
+ if (end > tailLength) {
213
+ this.retain(chunk.subarray(Math.max(0, start - tailLength), end - tailLength));
214
+ }
215
+ };
216
+
217
+ try {
218
+ let index = 0;
219
+ let retainedThrough = 0;
220
+ while (index < totalLength) {
221
+ const delimiterLength = delimiterLengthAt(index, totalLength, byteAt);
222
+ if (delimiterLength === undefined) break;
223
+ if (delimiterLength > 0) {
224
+ if (frames.length >= this.maxFramesPerFeed) {
225
+ this.clear();
226
+ this.disposed = true;
227
+ throw new SseFrameCountLimitError(this.maxFramesPerFeed);
228
+ }
229
+ retainRange(retainedThrough, index);
230
+ const block = this.takeCandidate();
231
+ const delimiter = delimiterBytesAt(index, delimiterLength, byteAt);
232
+ frames.push({ block, delimiter });
233
+ index += delimiterLength;
234
+ retainedThrough = index;
235
+ continue;
236
+ }
237
+ index += 1;
238
+ }
239
+
240
+ retainRange(retainedThrough, index);
241
+ if (index < totalLength) {
242
+ this.delimiterTail = copyRange(index, totalLength, tailLength, previousTail, chunk);
243
+ }
244
+ return frames;
245
+ } catch (err) {
246
+ const framingError = err instanceof SseFrameTooLargeError
247
+ || err instanceof SseFrameCountLimitError;
248
+ if (framingError && frames.some(frame => isResponsesTerminalFrame(frame.block))) {
249
+ // A terminal frame is the Responses protocol boundary. Ignore malformed
250
+ // or oversized bytes that occur later in the same upstream chunk rather
251
+ // than retroactively replacing the committed terminal with a 502.
252
+ this.clear();
253
+ this.disposed = true;
254
+ return frames;
255
+ }
256
+ throw err;
257
+ }
258
+ }
259
+
260
+ /** Return the final unterminated block bytes and release all retained state. */
261
+ finish(): Uint8Array {
262
+ if (this.disposed) return new Uint8Array(0);
263
+ try {
264
+ this.retain(this.delimiterTail);
265
+ this.delimiterTail = new Uint8Array(0);
266
+ return this.takeCandidate();
267
+ } finally {
268
+ this.clear();
269
+ this.disposed = true;
270
+ }
271
+ }
272
+
273
+ dispose(): void {
274
+ if (this.disposed) return;
275
+ this.clear();
276
+ this.disposed = true;
277
+ }
278
+ }
279
+
280
+ export function joinSseFrameBytes(parts: readonly Uint8Array[]): Uint8Array {
281
+ let byteLength = 0;
282
+ for (const part of parts) byteLength += part.byteLength;
283
+ if (byteLength === 0) return new Uint8Array(0);
284
+ if (parts.length === 1 && parts[0]!.byteLength === byteLength) return parts[0]!;
285
+ const joined = new Uint8Array(byteLength);
286
+ let offset = 0;
287
+ for (const part of parts) {
288
+ joined.set(part, offset);
289
+ offset += part.byteLength;
290
+ }
291
+ return joined;
292
+ }