@iislee/opencodex 2.11.0 → 2.35.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (733) hide show
  1. package/AGENTS_INSTALL.md +109 -0
  2. package/README.md +117 -22
  3. package/bin/ocx.mjs +245 -88
  4. package/bin/package-main.mjs +1 -1
  5. package/gui/dist/assets/index-Be1sDpWw.css +1 -0
  6. package/gui/dist/assets/index-D4OKgUV4.js +114 -0
  7. package/gui/dist/index.html +2 -2
  8. package/gui/dist/provider-icons/alibaba-color.svg +1 -1
  9. package/gui/dist/provider-icons/antigravity-color.svg +1 -1
  10. package/gui/dist/provider-icons/claude-color.svg +1 -1
  11. package/gui/dist/provider-icons/cline-color.svg +16 -0
  12. package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -1
  13. package/gui/dist/provider-icons/commandcode-color.svg +1 -0
  14. package/gui/dist/provider-icons/copilot-color.svg +1 -1
  15. package/gui/dist/provider-icons/cursor-color.svg +1 -1
  16. package/gui/dist/provider-icons/deepseek-color.svg +1 -1
  17. package/gui/dist/provider-icons/firepass-color.svg +1 -1
  18. package/gui/dist/provider-icons/fireworks-color.svg +1 -1
  19. package/gui/dist/provider-icons/gemini-color.svg +1 -1
  20. package/gui/dist/provider-icons/github-copilot-color.svg +1 -1
  21. package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -1
  22. package/gui/dist/provider-icons/grok.svg +1 -1
  23. package/gui/dist/provider-icons/groq-color.svg +1 -1
  24. package/gui/dist/provider-icons/huggingface-color.svg +1 -1
  25. package/gui/dist/provider-icons/kimi-color.svg +1 -1
  26. package/gui/dist/provider-icons/kiro-color.svg +2 -2
  27. package/gui/dist/provider-icons/lm-studio-color.svg +1 -1
  28. package/gui/dist/provider-icons/mistral-color.svg +1 -1
  29. package/gui/dist/provider-icons/moonshot-color.svg +1 -1
  30. package/gui/dist/provider-icons/nvidia-color.svg +1 -1
  31. package/gui/dist/provider-icons/ollama-color.svg +1 -1
  32. package/gui/dist/provider-icons/openai.svg +1 -1
  33. package/gui/dist/provider-icons/opencode.svg +2 -1
  34. package/gui/dist/provider-icons/openrouter-color.svg +1 -1
  35. package/gui/dist/provider-icons/pi.svg +2 -2
  36. package/gui/dist/provider-icons/qianfan-color.svg +1 -1
  37. package/gui/dist/provider-icons/qwen-portal-color.svg +1 -1
  38. package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -1
  39. package/gui/dist/provider-icons/vllm-color.svg +1 -1
  40. package/gui/dist/provider-icons/xiaomi-color.svg +1 -1
  41. package/package.json +21 -10
  42. package/src/adapters/anthropic-output-schema.ts +137 -0
  43. package/src/adapters/anthropic.ts +475 -62
  44. package/src/adapters/base.ts +82 -7
  45. package/src/adapters/client-fingerprint.ts +18 -12
  46. package/src/adapters/cline-pass-deepseek-v4-tool-replay.ts +69 -0
  47. package/src/adapters/command-code.ts +637 -0
  48. package/src/adapters/cursor/call-id.ts +44 -0
  49. package/src/adapters/cursor/catalog.ts +541 -0
  50. package/src/adapters/cursor/checkpoint-store.ts +308 -0
  51. package/src/adapters/cursor/cursor-errors.ts +144 -6
  52. package/src/adapters/cursor/discovery.ts +122 -14
  53. package/src/adapters/cursor/effort-map.ts +106 -4
  54. package/src/adapters/cursor/envelope-echo.ts +290 -0
  55. package/src/adapters/cursor/framing.ts +39 -0
  56. package/src/adapters/cursor/h2-pool.ts +123 -0
  57. package/src/adapters/cursor/http1-bidi.ts +361 -0
  58. package/src/adapters/cursor/images.ts +704 -0
  59. package/src/adapters/cursor/live-models.ts +180 -59
  60. package/src/adapters/cursor/live-transport.ts +623 -170
  61. package/src/adapters/cursor/message-mapper.ts +4 -1
  62. package/src/adapters/cursor/native-exec-common.ts +23 -2
  63. package/src/adapters/cursor/native-exec-desktop.ts +23 -0
  64. package/src/adapters/cursor/native-exec-fs.ts +10 -7
  65. package/src/adapters/cursor/native-exec-network.ts +1 -1
  66. package/src/adapters/cursor/native-exec-shell.ts +5 -3
  67. package/src/adapters/cursor/native-exec.ts +121 -14
  68. package/src/adapters/cursor/protobuf-events.ts +829 -11
  69. package/src/adapters/cursor/protobuf-request.ts +447 -75
  70. package/src/adapters/cursor/request-builder.ts +271 -35
  71. package/src/adapters/cursor/tool-definitions.ts +252 -12
  72. package/src/adapters/cursor/tool-result-normalize.ts +115 -0
  73. package/src/adapters/cursor/transport.ts +22 -0
  74. package/src/adapters/cursor/types.ts +48 -1
  75. package/src/adapters/cursor.ts +336 -39
  76. package/src/adapters/exec-tool-result-normalize.ts +99 -0
  77. package/src/adapters/google-antigravity-replay.ts +713 -41
  78. package/src/adapters/google-antigravity-wire.ts +48 -10
  79. package/src/adapters/google-errors.ts +44 -12
  80. package/src/adapters/google-http.ts +38 -10
  81. package/src/adapters/google-tool-schema.ts +80 -15
  82. package/src/adapters/google-truncation.ts +11 -0
  83. package/src/adapters/google.ts +742 -86
  84. package/src/adapters/identity.ts +39 -6
  85. package/src/adapters/image.ts +1 -1
  86. package/src/adapters/kiro-constants.ts +27 -0
  87. package/src/adapters/kiro-errors.ts +11 -0
  88. package/src/adapters/kiro-events.ts +19 -1
  89. package/src/adapters/kiro-thinking.ts +18 -2
  90. package/src/adapters/kiro-tools.ts +65 -17
  91. package/src/adapters/kiro.ts +270 -73
  92. package/src/adapters/mimo-free.ts +17 -0
  93. package/src/adapters/openai-chat-url.ts +11 -0
  94. package/src/adapters/openai-chat.ts +1377 -344
  95. package/src/adapters/openai-responses-url.ts +16 -0
  96. package/src/adapters/openai-responses.ts +1164 -64
  97. package/src/adapters/registry.ts +175 -0
  98. package/src/adapters/responses-tool-schema.ts +67 -0
  99. package/src/adapters/run-turn-queue.ts +36 -1
  100. package/src/adapters/tool-call-id.ts +119 -0
  101. package/src/adapters/tool-catalog-nudge.ts +105 -21
  102. package/src/adapters/xai-tool-schema.ts +436 -0
  103. package/src/adapters/xai-web-search.ts +186 -0
  104. package/src/bridge.ts +512 -92
  105. package/src/chat/inbound.ts +57 -20
  106. package/src/chat/outbound.ts +97 -33
  107. package/src/claude/agents-inject.ts +40 -10
  108. package/src/claude/context-windows.ts +37 -14
  109. package/src/claude/desktop-3p.ts +243 -9
  110. package/src/claude/gateway-cache.ts +41 -4
  111. package/src/claude/inbound.ts +72 -3
  112. package/src/claude/model-info.ts +38 -15
  113. package/src/claude/outbound.ts +88 -21
  114. package/src/cli/access.ts +46 -3
  115. package/src/cli/account-api.ts +150 -19
  116. package/src/cli/account-auth.ts +33 -6
  117. package/src/cli/account-catalog-refresh.ts +14 -0
  118. package/src/cli/account-extended.ts +648 -28
  119. package/src/cli/account-main.ts +317 -0
  120. package/src/cli/account.ts +97 -19
  121. package/src/cli/agent.ts +53 -2
  122. package/src/cli/alias.ts +66 -0
  123. package/src/cli/capabilities-command.ts +94 -0
  124. package/src/cli/capabilities.ts +496 -0
  125. package/src/cli/claude-agent-startup-sync.ts +73 -0
  126. package/src/cli/claude-desktop.ts +60 -15
  127. package/src/cli/claude.ts +129 -35
  128. package/src/cli/codex-log-guard-doctor.ts +103 -0
  129. package/src/cli/codex-shim-autorestore.ts +2 -0
  130. package/src/cli/codex-shim-readiness.ts +76 -0
  131. package/src/cli/combo.ts +8 -0
  132. package/src/cli/config-command.ts +74 -10
  133. package/src/cli/dispatch.ts +821 -0
  134. package/src/cli/doctor.ts +440 -56
  135. package/src/cli/ensure-desired-integrations.ts +152 -0
  136. package/src/cli/export-command.ts +46 -20
  137. package/src/cli/help.ts +34 -274
  138. package/src/cli/index.ts +417 -528
  139. package/src/cli/init.ts +5 -17
  140. package/src/cli/inspect.ts +230 -0
  141. package/src/cli/integrations.ts +120 -2
  142. package/src/cli/lab.ts +607 -0
  143. package/src/cli/launcher-context.ts +77 -0
  144. package/src/cli/minimax.ts +497 -0
  145. package/src/cli/models-runtime.ts +130 -2
  146. package/src/cli/models.ts +118 -16
  147. package/src/cli/observe.ts +123 -11
  148. package/src/cli/opencode.ts +4 -2
  149. package/src/cli/provider-runtime.ts +34 -3
  150. package/src/cli/provider.ts +25 -3
  151. package/src/cli/ready.ts +301 -0
  152. package/src/cli/registry.ts +476 -0
  153. package/src/cli/root.ts +86 -0
  154. package/src/cli/route-policy.ts +92 -0
  155. package/src/cli/runtime-api.ts +57 -10
  156. package/src/cli/star-prompt.ts +71 -15
  157. package/src/cli/status.ts +51 -4
  158. package/src/cli/storage.ts +234 -0
  159. package/src/cli/system-command.ts +16 -0
  160. package/src/cli/system-restart-client.ts +146 -0
  161. package/src/cli/tray-proxy.ts +153 -6
  162. package/src/cli/usage-report.ts +184 -0
  163. package/src/cli/v2.ts +137 -18
  164. package/src/cli/version-skew.ts +46 -0
  165. package/src/cli.ts +1 -1
  166. package/src/clients/config-export.ts +1442 -23
  167. package/src/clients/effective-status.ts +30 -2
  168. package/src/clients/probes/cline.ts +81 -0
  169. package/src/codex/account-label.ts +35 -1
  170. package/src/codex/account-lifecycle.ts +130 -13
  171. package/src/codex/account-namespaces.ts +49 -3
  172. package/src/codex/account-pause.ts +2 -1
  173. package/src/codex/account-priority.ts +84 -0
  174. package/src/codex/account-store.ts +29 -2
  175. package/src/codex/account-usability.ts +25 -2
  176. package/src/codex/admission.ts +256 -0
  177. package/src/codex/affinity-debug.ts +162 -0
  178. package/src/codex/app-server-processes.ts +570 -107
  179. package/src/codex/app-server-restart-service.ts +232 -0
  180. package/src/codex/auth-api.ts +893 -246
  181. package/src/codex/auth-collision.ts +5 -3
  182. package/src/codex/auth-context.ts +348 -32
  183. package/src/codex/autostart-health.ts +24 -1
  184. package/src/codex/catalog/account-models.ts +67 -0
  185. package/src/codex/catalog/aggregation.ts +86 -10
  186. package/src/codex/catalog/bundled.ts +331 -33
  187. package/src/codex/catalog/effort.ts +138 -32
  188. package/src/codex/catalog/filesystem-evidence.ts +302 -0
  189. package/src/codex/catalog/kinds.ts +2 -0
  190. package/src/codex/catalog/metadata.ts +555 -45
  191. package/src/codex/catalog/native-models.ts +75 -0
  192. package/src/codex/catalog/parsing.ts +269 -30
  193. package/src/codex/catalog/provider-fetch.ts +1626 -144
  194. package/src/codex/catalog/sync.ts +1576 -187
  195. package/src/codex/catalog-admission.ts +199 -0
  196. package/src/codex/catalog-refresh-status.ts +105 -0
  197. package/src/codex/catalog-write-serialization.ts +242 -0
  198. package/src/codex/catalog.ts +6 -3
  199. package/src/codex/codex-write-lock.ts +386 -0
  200. package/src/codex/convergence-types.ts +614 -0
  201. package/src/codex/convergence.ts +676 -0
  202. package/src/codex/coordinator-doctor.ts +332 -0
  203. package/src/codex/custom-model-catalog-migration.ts +176 -0
  204. package/src/codex/desired-state.ts +230 -0
  205. package/src/codex/desktop-app-restart.ts +355 -0
  206. package/src/codex/features.ts +636 -39
  207. package/src/codex/generation.ts +202 -0
  208. package/src/codex/history-job.ts +436 -0
  209. package/src/codex/history-lock.ts +242 -0
  210. package/src/codex/history-manifest.ts +112 -0
  211. package/src/codex/history-migration-guardian.ts +30 -24
  212. package/src/codex/history-provider.ts +1016 -235
  213. package/src/codex/history-transition.ts +105 -0
  214. package/src/codex/history-worker.ts +223 -0
  215. package/src/codex/inject-coordination.ts +373 -0
  216. package/src/codex/inject.ts +1114 -152
  217. package/src/codex/injected-marker.ts +37 -3
  218. package/src/codex/integration-record.ts +266 -0
  219. package/src/codex/internal/catalog-writer.ts +203 -0
  220. package/src/codex/internal/history-writer.ts +81 -0
  221. package/src/codex/journal.ts +66 -4
  222. package/src/codex/log-guard/inspect.ts +524 -0
  223. package/src/codex/log-guard/lock.ts +150 -0
  224. package/src/codex/log-guard/maintenance.ts +403 -0
  225. package/src/codex/log-guard/path-safety.ts +88 -0
  226. package/src/codex/log-guard/policy.ts +44 -0
  227. package/src/codex/log-guard/processes.ts +205 -0
  228. package/src/codex/log-guard/protection.ts +489 -0
  229. package/src/codex/log-guard/sqlite-errors.ts +9 -0
  230. package/src/codex/main-account-cache.ts +24 -0
  231. package/src/codex/main-account.ts +29 -1
  232. package/src/codex/management-convergence.ts +167 -0
  233. package/src/codex/model-cache.ts +56 -10
  234. package/src/codex/model-entitlements.ts +360 -0
  235. package/src/codex/native-main-admission.ts +47 -0
  236. package/src/codex/native-main-auth-temp.ts +187 -0
  237. package/src/codex/native-main-claim.ts +178 -0
  238. package/src/codex/native-main-lock-file.ts +162 -0
  239. package/src/codex/native-main-owner.ts +329 -0
  240. package/src/codex/native-profile-api.ts +247 -0
  241. package/src/codex/native-profile-manager.ts +1531 -0
  242. package/src/codex/native-profile-processes.ts +121 -0
  243. package/src/codex/native-profile-recovery.ts +99 -0
  244. package/src/codex/native-profile-stage-store.ts +387 -0
  245. package/src/codex/native-profile-startup.ts +622 -0
  246. package/src/codex/native-profile-store.ts +855 -0
  247. package/src/codex/native-profile-types.ts +120 -0
  248. package/src/codex/native-residue.ts +675 -0
  249. package/src/codex/paths.ts +80 -1
  250. package/src/codex/plan-from-token.ts +140 -0
  251. package/src/codex/plan.ts +40 -0
  252. package/src/codex/plugins-doctor.ts +1 -1
  253. package/src/codex/pool-rotation.ts +74 -4
  254. package/src/codex/project-config-warnings.ts +20 -6
  255. package/src/codex/prompt-journal.ts +352 -0
  256. package/src/codex/prompt-layers.ts +1313 -0
  257. package/src/codex/prompt-lock.ts +143 -0
  258. package/src/codex/prompt-text-probe.ts +238 -0
  259. package/src/codex/quota-rejection.ts +298 -0
  260. package/src/codex/quota.ts +264 -21
  261. package/src/codex/refresh.ts +11 -2
  262. package/src/codex/reset-credit-recovery.ts +1044 -0
  263. package/src/codex/routing.ts +514 -94
  264. package/src/codex/runtime.ts +159 -38
  265. package/src/codex/shim.ts +1065 -31
  266. package/src/codex/subagent-model-fallback.ts +437 -43
  267. package/src/codex/sync.ts +191 -2
  268. package/src/codex/transition-state.ts +720 -0
  269. package/src/codex/upstream-host-health.ts +368 -0
  270. package/src/codex/user-identity.ts +557 -0
  271. package/src/codex/warmup.ts +187 -81
  272. package/src/codex/write-coordination.ts +114 -0
  273. package/src/combos/failover.ts +47 -0
  274. package/src/combos/index.ts +4 -0
  275. package/src/combos/request.ts +32 -0
  276. package/src/combos/types.ts +91 -9
  277. package/src/compatibility/index.ts +26 -0
  278. package/src/compatibility/manifest.ts +253 -0
  279. package/src/compatibility/openai-responses.ts +121 -0
  280. package/src/config/atomic-write.ts +219 -0
  281. package/src/config/paths.ts +40 -0
  282. package/src/config/process-state.ts +309 -0
  283. package/src/config/provider-name.ts +24 -0
  284. package/src/config/provider-validation.ts +177 -0
  285. package/src/config/rebase-provenance.ts +68 -0
  286. package/src/config.ts +1713 -709
  287. package/src/generated/compatibility-version.json +3324 -0
  288. package/src/generated/{jawcode-model-metadata.ts → model-metadata.ts} +19 -17
  289. package/src/grok/inject.ts +16 -5
  290. package/src/grok/inspect.ts +45 -0
  291. package/src/grok/sync.ts +2 -2
  292. package/src/images/loop.ts +157 -33
  293. package/src/images/plan.ts +24 -13
  294. package/src/integrations/config-io.ts +269 -0
  295. package/src/integrations/journal.ts +315 -0
  296. package/src/integrations/merge.ts +135 -0
  297. package/src/integrations/mutation-flight.ts +71 -0
  298. package/src/integrations/native/ownership-preflight.ts +202 -0
  299. package/src/integrations/omp-yaml-source.ts +358 -0
  300. package/src/integrations/owned-refresh.ts +74 -0
  301. package/src/integrations/ownership-policy.ts +160 -0
  302. package/src/integrations/ownership.ts +155 -0
  303. package/src/integrations/registry.ts +166 -0
  304. package/src/integrations/serialize.ts +314 -0
  305. package/src/integrations/state.ts +433 -0
  306. package/src/integrations/store.ts +103 -0
  307. package/src/integrations/writer-lock.ts +98 -0
  308. package/src/integrations/writer.ts +715 -0
  309. package/src/lab/artifacts/sanitize.ts +586 -0
  310. package/src/lab/artifacts/secure-fs.ts +475 -0
  311. package/src/lab/artifacts/store.ts +310 -0
  312. package/src/lab/automation/budgets.ts +78 -0
  313. package/src/lab/automation/config-persistence.ts +256 -0
  314. package/src/lab/automation/constants.ts +39 -0
  315. package/src/lab/automation/cooldown.ts +103 -0
  316. package/src/lab/automation/dispatch.ts +211 -0
  317. package/src/lab/automation/index.ts +13 -0
  318. package/src/lab/automation/orchestrator.ts +499 -0
  319. package/src/lab/automation/persistence.ts +512 -0
  320. package/src/lab/automation/planner.ts +371 -0
  321. package/src/lab/automation/policy.ts +136 -0
  322. package/src/lab/automation/queue.ts +191 -0
  323. package/src/lab/automation/recovery.ts +24 -0
  324. package/src/lab/automation/route-context.ts +21 -0
  325. package/src/lab/automation/run-key.ts +44 -0
  326. package/src/lab/automation/runs-query.ts +34 -0
  327. package/src/lab/automation/types.ts +160 -0
  328. package/src/lab/conformance/assertion.ts +325 -0
  329. package/src/lab/conformance/digest.ts +22 -0
  330. package/src/lab/conformance/executor.ts +741 -0
  331. package/src/lab/conformance/fixture-provider.ts +27 -0
  332. package/src/lab/conformance/fixtures/live-v1-cases.json +175 -0
  333. package/src/lab/conformance/fixtures/protocol-v1-cases.json +461 -0
  334. package/src/lab/conformance/harness-budget.ts +47 -0
  335. package/src/lab/conformance/index.ts +5 -0
  336. package/src/lab/conformance/jcs.ts +64 -0
  337. package/src/lab/conformance/json-pointer.ts +39 -0
  338. package/src/lab/conformance/manifest.ts +180 -0
  339. package/src/lab/conformance/mcp-stub.ts +179 -0
  340. package/src/lab/conformance/negative-controls.ts +164 -0
  341. package/src/lab/conformance/observation.ts +355 -0
  342. package/src/lab/conformance/runner.ts +68 -0
  343. package/src/lab/conformance/sse-normalize.ts +59 -0
  344. package/src/lab/conformance/suite-manifest.ts +78 -0
  345. package/src/lab/conformance/types.ts +214 -0
  346. package/src/lab/constants.ts +126 -0
  347. package/src/lab/digest.ts +64 -0
  348. package/src/lab/events/errors.ts +9 -0
  349. package/src/lab/events/limits.ts +117 -0
  350. package/src/lab/events/types.ts +229 -0
  351. package/src/lab/events/validate.ts +781 -0
  352. package/src/lab/fabric/constants.ts +40 -0
  353. package/src/lab/fabric/executor.ts +492 -0
  354. package/src/lab/fabric/index.ts +80 -0
  355. package/src/lab/fabric/manifest.ts +222 -0
  356. package/src/lab/fabric/observe.ts +489 -0
  357. package/src/lab/fabric/patch.ts +79 -0
  358. package/src/lab/fabric/producer-child.ts +139 -0
  359. package/src/lab/fabric/producer-isolate.ts +276 -0
  360. package/src/lab/fabric/producer-protocol.ts +61 -0
  361. package/src/lab/fabric/scratch.ts +439 -0
  362. package/src/lab/fabric/subject.ts +106 -0
  363. package/src/lab/fabric/types.ts +134 -0
  364. package/src/lab/fabric/verifier.ts +98 -0
  365. package/src/lab/index.ts +54 -0
  366. package/src/lab/ledger/artifact-refs.ts +127 -0
  367. package/src/lab/ledger/invalidation.ts +136 -0
  368. package/src/lab/ledger/purge.ts +310 -0
  369. package/src/lab/ledger/store.ts +532 -0
  370. package/src/lab/live/credential-lease.ts +53 -0
  371. package/src/lab/live/destination.ts +155 -0
  372. package/src/lab/live/executor.ts +336 -0
  373. package/src/lab/live/inert-tools.ts +56 -0
  374. package/src/lab/live/manifest.ts +85 -0
  375. package/src/lab/live/mcp-loopback.ts +57 -0
  376. package/src/lab/live/runner.ts +19 -0
  377. package/src/lab/live/sandbox.ts +61 -0
  378. package/src/lab/live/suite-manifest.ts +41 -0
  379. package/src/lab/live/transport.ts +118 -0
  380. package/src/lab/live/types.ts +197 -0
  381. package/src/lab/observe/from-conformance.ts +301 -0
  382. package/src/lab/observe/from-live.ts +117 -0
  383. package/src/lab/paths.ts +153 -0
  384. package/src/lab/projection/rebuild.ts +495 -0
  385. package/src/lab/projection/schema.ts +135 -0
  386. package/src/lab/projection/verdicts.ts +474 -0
  387. package/src/lab/projection/verification.ts +412 -0
  388. package/src/lab/public/bundle.ts +217 -0
  389. package/src/lab/public/community-authority.ts +175 -0
  390. package/src/lab/public/community-files.ts +29 -0
  391. package/src/lab/public/community.ts +479 -0
  392. package/src/lab/public/file-safety.ts +155 -0
  393. package/src/lab/public/ids.ts +26 -0
  394. package/src/lab/public/index.ts +16 -0
  395. package/src/lab/public/mutation-lock.ts +424 -0
  396. package/src/lab/public/operator.ts +353 -0
  397. package/src/lab/public/origin-purge.ts +79 -0
  398. package/src/lab/public/origin.ts +203 -0
  399. package/src/lab/public/privacy.ts +143 -0
  400. package/src/lab/public/private-file.ts +261 -0
  401. package/src/lab/public/project.ts +124 -0
  402. package/src/lab/public/purge-test-fault.ts +21 -0
  403. package/src/lab/public/purge.ts +223 -0
  404. package/src/lab/public/registry.ts +44 -0
  405. package/src/lab/public/revocation.ts +252 -0
  406. package/src/lab/public/signature.ts +243 -0
  407. package/src/lab/public/storage.ts +105 -0
  408. package/src/lab/public/strict-json.ts +206 -0
  409. package/src/lab/public/time.ts +26 -0
  410. package/src/lab/public/types.ts +172 -0
  411. package/src/lab/public/validate.ts +391 -0
  412. package/src/lab/query/catalog.ts +101 -0
  413. package/src/lab/query/connection.ts +107 -0
  414. package/src/lab/query/constants.ts +4 -0
  415. package/src/lab/query/cursor.ts +132 -0
  416. package/src/lab/query/dto-map.ts +277 -0
  417. package/src/lab/query/errors.ts +22 -0
  418. package/src/lab/query/freshness.ts +53 -0
  419. package/src/lab/query/index.ts +45 -0
  420. package/src/lab/query/latest-observation.ts +59 -0
  421. package/src/lab/query/passive-production.ts +159 -0
  422. package/src/lab/query/queries.ts +444 -0
  423. package/src/lab/query/types.ts +266 -0
  424. package/src/lab/subject/behavior-fingerprint.ts +77 -0
  425. package/src/lab/subject/installation-salt.ts +112 -0
  426. package/src/lab/subject/protocol-subject.ts +80 -0
  427. package/src/lab/subject/route-subject.ts +74 -0
  428. package/src/lib/admin-secrets.ts +24 -0
  429. package/src/lib/app-owned-memory-stores.ts +22 -0
  430. package/src/lib/bounded-body.ts +167 -11
  431. package/src/lib/bun-runtime.ts +125 -12
  432. package/src/lib/bun-stream-caps.ts +13 -9
  433. package/src/lib/codex-restart-contract.ts +120 -0
  434. package/src/lib/config-ownership.ts +26 -2
  435. package/src/lib/destination-policy.ts +65 -1
  436. package/src/lib/errors.ts +80 -5
  437. package/src/lib/fabric-task-execution-authority.ts +7 -0
  438. package/src/lib/fabric-task-host.ts +29 -0
  439. package/src/lib/lab-activation.ts +223 -0
  440. package/src/lib/lab-live-execution-authority.ts +13 -0
  441. package/src/lib/lab-live-host.ts +30 -0
  442. package/src/lib/lab-live-pinned-sender.ts +56 -0
  443. package/src/lib/lab-live-route-production.ts +130 -0
  444. package/src/lib/lab-passive-linker-registration.ts +26 -0
  445. package/src/lib/local-management-attestation.ts +51 -0
  446. package/src/lib/local-management-capability.ts +100 -0
  447. package/src/lib/local-provider-reload-contract.ts +100 -0
  448. package/src/lib/optional-shutdown-hooks.ts +57 -0
  449. package/src/lib/package-tree-integrity.ts +101 -0
  450. package/src/lib/pinned-http.ts +145 -26
  451. package/src/lib/process-control.ts +6 -2
  452. package/src/lib/provider-outbound.ts +49 -9
  453. package/src/lib/redact.ts +419 -3
  454. package/src/lib/self-launch-argv.ts +15 -0
  455. package/src/lib/server-resource-ownership.ts +71 -0
  456. package/src/lib/service-secrets.ts +15 -0
  457. package/src/lib/shadow-call.ts +35 -4
  458. package/src/lib/sse-decoder.ts +41 -0
  459. package/src/lib/state-store-registrations.ts +10 -2
  460. package/src/lib/system-restart-contract.ts +73 -0
  461. package/src/lib/token-estimate.ts +19 -2
  462. package/src/lib/tool-argument-integers.ts +253 -0
  463. package/src/lib/translator-budget.ts +44 -0
  464. package/src/lib/upstream-http-version.ts +57 -0
  465. package/src/lib/upstream-reachability.ts +95 -0
  466. package/src/lib/upstream-retry.ts +156 -3
  467. package/src/lib/windows-atomic-replace.ts +155 -0
  468. package/src/lib/windows-elevation.ts +70 -2
  469. package/src/lib/windows-secret-acl.ts +409 -69
  470. package/src/lib/windows-service-wrappers.ts +72 -0
  471. package/src/lib/windows-text.ts +106 -0
  472. package/src/lib/windows-user-principal.ts +341 -0
  473. package/src/lib/winsw.ts +33 -5
  474. package/src/oauth/account-import/google-antigravity-adapter.ts +74 -0
  475. package/src/oauth/account-import/index.ts +15 -0
  476. package/src/oauth/account-import/parser.ts +83 -0
  477. package/src/oauth/account-import/registry.ts +18 -0
  478. package/src/oauth/account-import/service.ts +75 -0
  479. package/src/oauth/account-import/types.ts +91 -0
  480. package/src/oauth/anthropic.ts +12 -1
  481. package/src/oauth/callback-server.ts +30 -4
  482. package/src/oauth/chatgpt.ts +12 -1
  483. package/src/oauth/cline.ts +203 -0
  484. package/src/oauth/command-code.ts +239 -0
  485. package/src/oauth/cursor.ts +46 -5
  486. package/src/oauth/generic-account-failover.ts +231 -0
  487. package/src/oauth/google-antigravity.ts +35 -3
  488. package/src/oauth/health.ts +20 -12
  489. package/src/oauth/index.ts +462 -71
  490. package/src/oauth/key-providers.ts +25 -0
  491. package/src/oauth/kimi.ts +25 -3
  492. package/src/oauth/kiro.ts +95 -6
  493. package/src/oauth/local-token-detect.ts +13 -2
  494. package/src/oauth/log.ts +3 -1
  495. package/src/oauth/login-cli.ts +88 -28
  496. package/src/oauth/nous.ts +798 -0
  497. package/src/oauth/open-browser-choice.ts +26 -0
  498. package/src/oauth/store.ts +133 -26
  499. package/src/oauth/token-guardian.ts +9 -3
  500. package/src/oauth/types.ts +15 -0
  501. package/src/pi/models.ts +2 -2
  502. package/src/providers/alibaba-region-migration.ts +1 -1
  503. package/src/providers/antigravity-models.ts +521 -31
  504. package/src/providers/auto-compact-budget.ts +65 -0
  505. package/src/providers/base-url-choices.ts +10 -0
  506. package/src/providers/codex-capacity.ts +292 -0
  507. package/src/providers/command-code-efforts.ts +176 -0
  508. package/src/providers/context-cap.ts +26 -8
  509. package/src/providers/cursor-pool.ts +72 -0
  510. package/src/providers/default-aliases.ts +65 -0
  511. package/src/providers/derive.ts +281 -6
  512. package/src/providers/fastwire.ts +507 -0
  513. package/src/providers/free-directory.ts +10 -7
  514. package/src/providers/google-vertex-location.ts +14 -0
  515. package/src/providers/key-failover.ts +71 -3
  516. package/src/providers/label.ts +35 -2
  517. package/src/providers/model-discovery-limits.ts +16 -0
  518. package/src/providers/model-discovery.ts +115 -22
  519. package/src/providers/model-presets.ts +119 -0
  520. package/src/providers/model-rename-migration.ts +255 -0
  521. package/src/providers/model-rename-startup.ts +28 -0
  522. package/src/providers/new-model-policy.ts +146 -0
  523. package/src/providers/openai-sidecar.ts +72 -4
  524. package/src/providers/openai-tier-startup.ts +31 -2
  525. package/src/providers/openai-tiers.ts +119 -4
  526. package/src/providers/openai-virtual-models.ts +1 -0
  527. package/src/providers/opencode-zen-rate-limit.ts +102 -0
  528. package/src/providers/provider-id-rewrite.ts +30 -0
  529. package/src/providers/quota.ts +1379 -40
  530. package/src/providers/registry.ts +1545 -112
  531. package/src/providers/request-pacing.ts +310 -0
  532. package/src/providers/service-tier.ts +277 -0
  533. package/src/providers/slug-codec.ts +94 -6
  534. package/src/providers/static-model-discovery.ts +86 -0
  535. package/src/providers/xai-responses-opt-in.ts +15 -0
  536. package/src/providers/xai-transport.ts +32 -4
  537. package/src/reasoning-effort.ts +68 -3
  538. package/src/responses/apply-patch-envelope.ts +63 -0
  539. package/src/responses/code-mode-helper-compat.ts +50 -0
  540. package/src/responses/compaction.ts +26 -1
  541. package/src/responses/custom-tool-compat.ts +384 -0
  542. package/src/responses/hosted-tool-policy.ts +9 -0
  543. package/src/responses/namespace-tool-compat.ts +435 -0
  544. package/src/responses/parser.ts +225 -38
  545. package/src/responses/provider-continuation.ts +98 -0
  546. package/src/responses/provider-opaque-metadata.ts +73 -0
  547. package/src/responses/reasoning-envelope.ts +9 -1
  548. package/src/responses/reasoning-replay-cache.ts +504 -0
  549. package/src/responses/schema.ts +12 -2
  550. package/src/responses/spill-store.ts +75 -10
  551. package/src/responses/state.ts +659 -31
  552. package/src/responses/thought-signature-replay.ts +364 -0
  553. package/src/responses/tool-search-compat.ts +301 -0
  554. package/src/responses/truncated-stop-reason.ts +60 -0
  555. package/src/responses/turn-termination.ts +107 -0
  556. package/src/router.ts +405 -31
  557. package/src/routing/analytics.ts +379 -0
  558. package/src/routing/capability.ts +244 -0
  559. package/src/routing/compatibility/assemble.ts +73 -0
  560. package/src/routing/compatibility/behavior.ts +278 -0
  561. package/src/routing/compatibility/catalog.ts +99 -0
  562. package/src/routing/compatibility/endpoint.ts +52 -0
  563. package/src/routing/compatibility/lab-evidence-provider.ts +130 -0
  564. package/src/routing/compatibility/policy.ts +181 -0
  565. package/src/routing/compatibility/provider-slot.ts +56 -0
  566. package/src/routing/compatibility/reader.ts +110 -0
  567. package/src/routing/compatibility/subject.ts +191 -0
  568. package/src/routing/compatibility/types.ts +64 -0
  569. package/src/routing/compatibility/version.ts +104 -0
  570. package/src/routing/cost.ts +77 -0
  571. package/src/routing/evaluator.ts +495 -0
  572. package/src/routing/health.ts +412 -0
  573. package/src/routing/history/cursor.ts +43 -0
  574. package/src/routing/history/indexer.ts +605 -0
  575. package/src/routing/history/schema.ts +72 -0
  576. package/src/routing/profile-namespace.ts +15 -0
  577. package/src/routing/profile.ts +547 -0
  578. package/src/routing/quota.ts +155 -0
  579. package/src/routing/request-evidence.ts +45 -0
  580. package/src/routing/trace.ts +776 -0
  581. package/src/server/adapter-resolve.ts +2 -29
  582. package/src/server/auth-cors.ts +289 -48
  583. package/src/server/background-lifecycle.ts +182 -0
  584. package/src/server/chat-completions.ts +154 -72
  585. package/src/server/chat-native-sse.ts +331 -0
  586. package/src/server/chat-native.ts +445 -0
  587. package/src/server/claude-messages.ts +160 -44
  588. package/src/server/direct-local-http.ts +347 -0
  589. package/src/server/effort-policy.ts +18 -0
  590. package/src/server/github-copilot-responses-repair.ts +338 -0
  591. package/src/server/gui-static.ts +39 -10
  592. package/src/server/images.ts +94 -12
  593. package/src/server/index.ts +1021 -190
  594. package/src/server/lifecycle.ts +336 -14
  595. package/src/server/live.ts +136 -17
  596. package/src/server/local-management-read-client.ts +90 -0
  597. package/src/server/local-provider-reload-client.ts +137 -0
  598. package/src/server/management/agent-settings-routes.ts +433 -116
  599. package/src/server/management/api-key-usage.ts +31 -5
  600. package/src/server/management/body.ts +6 -0
  601. package/src/server/management/codex-prompt-routes.ts +570 -0
  602. package/src/server/management/combo-routes.ts +64 -25
  603. package/src/server/management/config-routes.ts +511 -51
  604. package/src/server/management/context.ts +89 -2
  605. package/src/server/management/integration-routes.ts +498 -0
  606. package/src/server/management/lab-automation-routes.ts +206 -0
  607. package/src/server/management/lab-routes.ts +563 -0
  608. package/src/server/management/logs-usage-routes.ts +127 -52
  609. package/src/server/management/model-routes.ts +461 -133
  610. package/src/server/management/model-rows.ts +167 -0
  611. package/src/server/management/native-integration-routes.ts +770 -0
  612. package/src/server/management/oauth-account-routes.ts +90 -8
  613. package/src/server/management/provider-capability-config.ts +48 -0
  614. package/src/server/management/provider-routes.ts +836 -159
  615. package/src/server/management/request-history-routes.ts +191 -0
  616. package/src/server/management/route-registry.ts +332 -0
  617. package/src/server/management/routing-analytics-routes.ts +74 -0
  618. package/src/server/management/routing-profile-routes.ts +380 -0
  619. package/src/server/management/shared.ts +27 -11
  620. package/src/server/management/sidebar-routes.ts +47 -31
  621. package/src/server/management/storage-log-guard-routes.ts +186 -0
  622. package/src/server/management/sync-response.ts +69 -0
  623. package/src/server/management/system-restart.ts +289 -33
  624. package/src/server/management/system-routes.ts +77 -0
  625. package/src/server/management/usage-summary-cache.ts +9 -1
  626. package/src/server/management/vision-sidecar-options.ts +167 -0
  627. package/src/server/management/web-search-sidecar-options.ts +120 -0
  628. package/src/server/management-api.ts +126 -23
  629. package/src/server/management-auth.ts +220 -5
  630. package/src/server/passive-route-linker.ts +66 -0
  631. package/src/server/port-reclaim.ts +1 -1
  632. package/src/server/ports.ts +41 -1
  633. package/src/server/proxy-liveness.ts +161 -10
  634. package/src/server/readiness.ts +99 -0
  635. package/src/server/relay-eager.ts +221 -54
  636. package/src/server/relay.ts +479 -87
  637. package/src/server/request-decompress.ts +113 -6
  638. package/src/server/request-log-conversation.ts +51 -0
  639. package/src/server/request-log.ts +298 -31
  640. package/src/server/responses/agent-task-recovery-cache.ts +143 -0
  641. package/src/server/responses/agent-task-recovery.ts +465 -0
  642. package/src/server/responses/codex-auth-error.ts +55 -0
  643. package/src/server/responses/collaboration.ts +239 -36
  644. package/src/server/responses/combo-stream-preflight.ts +178 -0
  645. package/src/server/responses/compact.ts +444 -72
  646. package/src/server/responses/core.ts +3579 -436
  647. package/src/server/responses/empty-completion-guard.ts +333 -0
  648. package/src/server/responses/encrypted-payload.ts +62 -39
  649. package/src/server/responses/fetch-helpers.ts +89 -99
  650. package/src/server/responses/input-admission.ts +187 -0
  651. package/src/server/responses/pacing-overload.ts +13 -0
  652. package/src/server/responses/passthrough-error.ts +33 -9
  653. package/src/server/responses/policy-fallback.ts +178 -0
  654. package/src/server/responses/responses-field-backfill.ts +343 -0
  655. package/src/server/responses/terminal-guard.ts +26 -5
  656. package/src/server/responses/upstream-error.ts +5 -0
  657. package/src/server/responses/ws-upstream.ts +381 -0
  658. package/src/server/responses-custom-tool-repair.ts +363 -0
  659. package/src/server/responses-item-id-repair.ts +54 -6
  660. package/src/server/responses-json-events.ts +90 -0
  661. package/src/server/responses-model-rewrite.ts +29 -0
  662. package/src/server/responses-reasoning-summary-rewrite.ts +178 -0
  663. package/src/server/responses-snapshot-repair.ts +621 -0
  664. package/src/server/responses-terminal-repair.ts +363 -0
  665. package/src/server/responses-tool-search-repair.ts +267 -0
  666. package/src/server/responses-undeclared-tool-guard.ts +376 -0
  667. package/src/server/responses.ts +18 -2
  668. package/src/server/search.ts +78 -13
  669. package/src/server/sse-frame-buffer.ts +319 -0
  670. package/src/server/sse-payload-rewrite.ts +110 -22
  671. package/src/server/startup-action-control.ts +8 -1
  672. package/src/server/startup-health-cache.ts +19 -1
  673. package/src/server/system-env.ts +80 -9
  674. package/src/server/ws-bridge.ts +53 -40
  675. package/src/service-manager-probe.ts +892 -0
  676. package/src/service.ts +1153 -94
  677. package/src/sidecar/auth.ts +92 -0
  678. package/src/sidecar/candidates.ts +83 -0
  679. package/src/storage/cleanup.ts +2 -2
  680. package/src/storage/policy-job.ts +14 -4
  681. package/src/storage/policy.ts +88 -23
  682. package/src/storage/scanner.ts +1 -1
  683. package/src/storage/worker-lifecycle.ts +14 -14
  684. package/src/tray/windows-tray.ps1 +83 -9
  685. package/src/tray/windows.ts +43 -16
  686. package/src/types/accounts.ts +37 -0
  687. package/src/types/config.ts +911 -0
  688. package/src/types/provider.ts +614 -0
  689. package/src/types/request.ts +397 -0
  690. package/src/types/tools.ts +236 -0
  691. package/src/types/wire.ts +80 -0
  692. package/src/types.ts +107 -1237
  693. package/src/update/index.ts +37 -23
  694. package/src/update/job.ts +445 -68
  695. package/src/update/notify.ts +12 -6
  696. package/src/update/npm-cache-preflight.d.mts +47 -0
  697. package/src/update/npm-cache-preflight.mjs +201 -0
  698. package/src/update/transactional-install.d.mts +22 -0
  699. package/src/update/transactional-install.mjs +266 -0
  700. package/src/usage/cost.ts +0 -0
  701. package/src/usage/expected-prices.ts +287 -16
  702. package/src/usage/log.ts +666 -50
  703. package/src/usage/summary.ts +388 -17
  704. package/src/usage/user-cost-overlay-reconciler.ts +313 -0
  705. package/src/usage/user-cost-overlays.ts +314 -0
  706. package/src/vision/anthropic-describe.ts +10 -6
  707. package/src/vision/backends.ts +97 -0
  708. package/src/vision/describe.ts +27 -16
  709. package/src/vision/eligibility.ts +250 -0
  710. package/src/vision/index.ts +238 -24
  711. package/src/vision/reasoning.ts +55 -0
  712. package/src/vision/routed-describe.ts +175 -0
  713. package/src/vision/timeout-bounds.ts +9 -0
  714. package/src/web-search/anthropic-executor.ts +13 -7
  715. package/src/web-search/backends.ts +108 -0
  716. package/src/web-search/exa-executor.ts +119 -0
  717. package/src/web-search/executor.ts +21 -6
  718. package/src/web-search/gemini-executor.ts +141 -0
  719. package/src/web-search/index.ts +150 -15
  720. package/src/web-search/loop.ts +284 -54
  721. package/src/web-search/parse.ts +125 -30
  722. package/src/web-search/sources.ts +60 -0
  723. package/src/web-search/xai-executor.ts +219 -0
  724. package/gui/dist/assets/index-DTpMHS4F.js +0 -67
  725. package/gui/dist/assets/index-ZNVDE3C7.css +0 -1
  726. package/gui/dist/provider-icons/antigravity.svg +0 -1
  727. package/gui/dist/provider-icons/claude.svg +0 -1
  728. package/gui/dist/provider-icons/copilot.svg +0 -1
  729. package/gui/dist/provider-icons/cursor.svg +0 -2
  730. package/gui/dist/provider-icons/gemini.svg +0 -1
  731. package/gui/dist/provider-icons/grok-color.svg +0 -1
  732. package/gui/dist/provider-icons/kiro.svg +0 -14
  733. package/src/cli/internal-dispatch.ts +0 -20
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Per-server readiness gate for the opencodex proxy.
3
+ *
4
+ * `GET /healthz` answers "is the process alive and serving HTTP?" the instant the
5
+ * listener binds. Readiness is stricter: the proxy is "ready" only after the
6
+ * post-startup Codex catalog/config sync (`syncModelsToCodex`) has settled with
7
+ * `ok=true` and no catalog-sync warning. Until then the process is live (Codex can
8
+ * open a socket) but not ready (a request would race the sync or hit a stale
9
+ * catalog), so clients should back off.
10
+ *
11
+ * Design contract (per P1 review):
12
+ * - NO module-global mutable state. Each `startServer` invocation gets its own
13
+ * private gate via `createReadinessGate()`, captured by that listener's
14
+ * closure. Starting/failing a second server in the same process can never
15
+ * reset or mutate the first server's gate.
16
+ * - Only the fixed sanitized status enum `pending | ready | failed` is stored
17
+ * and exposed. There is no `changedAt`, no free-form failure reason, no sync
18
+ * message, no warning text, no catalog path, no provider output, and no
19
+ * account data — those are private diagnostic data and are never exposed by
20
+ * `/readyz`.
21
+ */
22
+
23
+ /** Sanitized readiness state. Exactly these three values, nothing else. */
24
+ export type ReadinessStatus = "pending" | "ready" | "failed";
25
+
26
+ /**
27
+ * Private per-server readiness controller. The status starts at `pending` and
28
+ * transitions at most once (to `ready` or `failed`) when the post-startup sync
29
+ * settles. The gate is owned by the listener closure that requested it.
30
+ */
31
+ export interface ReadinessGate {
32
+ /** Current sanitized status. */
33
+ getStatus(): ReadinessStatus;
34
+ /** Mark the proxy ready (post-startup sync settled cleanly). */
35
+ markReady(): void;
36
+ /** Mark the proxy failed. No reason is stored or exposed. */
37
+ markFailed(): void;
38
+ }
39
+
40
+ /**
41
+ * Create a fresh private gate for one `startServer` invocation. The returned
42
+ * gate is the only way to read or mutate this server's readiness.
43
+ */
44
+ export function createReadinessGate(): ReadinessGate {
45
+ let status: ReadinessStatus = "pending";
46
+ return {
47
+ getStatus: () => status,
48
+ markReady: () => {
49
+ if (status === "pending") status = "ready";
50
+ },
51
+ markFailed: () => {
52
+ if (status === "pending") status = "failed";
53
+ },
54
+ };
55
+ }
56
+
57
+ /** Minimal shape of the post-startup sync outcome the gate cares about. */
58
+ export interface SyncOutcomeLike {
59
+ ok?: boolean;
60
+ warning?: string;
61
+ /** #1046: whether the sync actually rewrote the on-disk catalog/cache. */
62
+ catalogWritten?: boolean;
63
+ cacheSynced?: boolean;
64
+ }
65
+
66
+ /**
67
+ * Drive the gate from the post-startup sync. Awaits `syncFn`; the gate goes to
68
+ * `ready` ONLY on `ok=true` with no nonempty warning. A throw, `null`, `ok=false`,
69
+ * or a nonempty warning transitions to `failed`. Used directly by `handleStart`
70
+ * so the startup transition is unit-testable without spawning the proxy. Returns
71
+ * the raw sync outcome so a caller that also needs the #1046 write flags (did the
72
+ * sync actually write the catalog/cache?) can keep them without a second call.
73
+ */
74
+ export async function runStartupReadinessSync(
75
+ gate: ReadinessGate,
76
+ syncFn: () => Promise<SyncOutcomeLike | null>,
77
+ ): Promise<SyncOutcomeLike | null> {
78
+ let result: SyncOutcomeLike | null;
79
+ try {
80
+ result = await syncFn();
81
+ } catch {
82
+ gate.markFailed();
83
+ return null;
84
+ }
85
+ if (result === null) {
86
+ gate.markFailed();
87
+ return null;
88
+ }
89
+ if (result.ok !== true) {
90
+ gate.markFailed();
91
+ return result;
92
+ }
93
+ if (result.warning !== undefined && result.warning !== "") {
94
+ gate.markFailed();
95
+ return result;
96
+ }
97
+ gate.markReady();
98
+ return result;
99
+ }
@@ -24,11 +24,18 @@
24
24
  * up to the drain window.
25
25
  */
26
26
 
27
- import { buildFailedTailPayload } from "./relay";
27
+ import {
28
+ adapterEofIncompleteFrame,
29
+ createSseTerminalOutputBoundary,
30
+ doneFrame,
31
+ failedTailFrame,
32
+ } from "./relay";
28
33
  import {
29
34
  nextSseBlock,
35
+ payloadRewriteAsBlockRewrite,
30
36
  replaceSseDataPayload,
31
37
  sseDataPayload,
38
+ type SseBlockRewrite,
32
39
  type SsePayloadRewrite,
33
40
  } from "./sse-payload-rewrite";
34
41
  import type { TranslatorBudget } from "../lib/translator-budget";
@@ -43,6 +50,12 @@ export type EagerRelayHooks = {
43
50
  * Bun#32111-unsafe tee()+JS-pull chain (#864).
44
51
  */
45
52
  rewritePayload?: SsePayloadRewrite;
53
+ /**
54
+ * Optional block-level rewrite (zero or more blocks out per upstream
55
+ * block) for lifecycle event injection (#893). Takes precedence over
56
+ * rewritePayload when both are set.
57
+ */
58
+ rewriteBlocks?: SseBlockRewrite;
46
59
  /** Flush inspection at upstream end (createSseInspector.finish). */
47
60
  finishInspection: () => void;
48
61
  /** Drop inspector-owned frame/item state during producer teardown. */
@@ -92,9 +105,21 @@ export function relaySseEagerBounded(
92
105
  const now = opts?.now ?? Date.now;
93
106
 
94
107
  const reader = body.getReader();
95
- const rewrite = hooks.rewritePayload;
96
- const rewriteDecoder = rewrite ? new TextDecoder() : null;
97
- const rewriteEncoder = rewrite ? new TextEncoder() : null;
108
+ const terminalEncoder = new TextEncoder();
109
+ const adapterEofFrame = adapterEofIncompleteFrame(terminalEncoder);
110
+ const terminalSentinel = doneFrame(terminalEncoder);
111
+ const terminalBoundary = createSseTerminalOutputBoundary();
112
+ const activeRewrite: SseBlockRewrite | undefined = hooks.rewriteBlocks
113
+ ?? (hooks.rewritePayload ? payloadRewriteAsBlockRewrite(hooks.rewritePayload) : undefined);
114
+ const encodeFailedTail = (error: unknown): Uint8Array | null => {
115
+ try {
116
+ return failedTailFrame(terminalEncoder, error);
117
+ } catch {
118
+ return null;
119
+ }
120
+ };
121
+ const rewriteDecoder = activeRewrite ? new TextDecoder() : null;
122
+ const rewriteEncoder = activeRewrite ? new TextEncoder() : null;
98
123
  const rewriteBudget = opts?.rewriteBudget;
99
124
  let frameBuffer = "";
100
125
  let frameBufferBytes = 0;
@@ -121,15 +146,9 @@ export function relaySseEagerBounded(
121
146
  for (;;) {
122
147
  const next = nextSseBlock(frameBuffer);
123
148
  if (!next) break;
124
- const payload = sseDataPayload(next.block);
125
- const rewrittenPayload = payload === null ? null : rewrite!(payload);
126
- // Replace only on an actual change: replaceSseDataPayload collapses
127
- // multi-data-line events and normalizes newline style even when the
128
- // payload is identical, which corrupts valid streams.
129
- const block = payload !== null && rewrittenPayload !== payload
130
- ? replaceSseDataPayload(next.block, rewrittenPayload!)
131
- : next.block;
132
- out += block + next.delimiter;
149
+ for (const outBlock of activeRewrite!(next.block)) {
150
+ out += outBlock + next.delimiter;
151
+ }
133
152
  frameBuffer = next.rest;
134
153
  }
135
154
  if (rewriteBudget) {
@@ -143,14 +162,13 @@ export function relaySseEagerBounded(
143
162
  };
144
163
  /** Flush any trailing partial block at upstream end (rewrite applied, matching the pull relay). */
145
164
  const flushRewriteTail = (): Uint8Array => {
146
- if (!rewrite) return new Uint8Array(0);
165
+ if (!activeRewrite) return new Uint8Array(0);
147
166
  // Decoder-flushed bytes logically follow everything already decoded.
148
167
  let tail = frameBuffer + rewriteDecoder!.decode();
149
- const payload = sseDataPayload(tail);
150
- if (payload !== null) {
151
- const rewrittenPayload = rewrite(payload);
152
- if (rewrittenPayload !== payload) tail = replaceSseDataPayload(tail, rewrittenPayload);
153
- }
168
+ const rewritten = activeRewrite(tail);
169
+ // Multiple emitted blocks must stay separately framed (#893 review);
170
+ // join places the delimiter only between blocks, never after the last.
171
+ tail = rewritten.join(tail.includes("\r\n") ? "\r\n\r\n" : "\n\n");
154
172
  frameBuffer = "";
155
173
  if (rewriteBudget && frameBufferBytes > 0) {
156
174
  rewriteBudget.releaseRetained(frameBufferBytes, { kind: "live_transient" });
@@ -166,7 +184,16 @@ export function relaySseEagerBounded(
166
184
  // turn unregistration stay reachable, drainAndShutdown never hangs).
167
185
  let wake: (() => void) | null = null;
168
186
  const wakeUp = () => { const w = wake; wake = null; w?.(); };
169
- const paused = () => new Promise<void>(resolve => { wake = resolve; });
187
+ const paused = () => new Promise<void>(resolve => {
188
+ wake = resolve;
189
+ // A pull, cancel, or abort can win the tiny window between the loop's
190
+ // predicate check and installing this resolver. Re-check every wake
191
+ // predicate after installation so that an already-fired wake cannot leave
192
+ // the producer parked forever.
193
+ if (queuedBytes <= maxQueueBytes || cancelled || upstream.signal.aborted) {
194
+ wakeUp();
195
+ }
196
+ });
170
197
  upstream.signal.addEventListener("abort", wakeUp, { once: true });
171
198
 
172
199
  let controllerRef: ReadableStreamDefaultController<Uint8Array> | null = null;
@@ -192,35 +219,78 @@ export function relaySseEagerBounded(
192
219
 
193
220
  const producer = async () => {
194
221
  let syntheticKind: "incomplete" | "failed" | null = null;
222
+ let deliveryFallbackSent = false;
223
+ let priorRewriteFailure = false;
224
+ let priorRewriteError: unknown;
195
225
  // reader.read() is not intrinsically tied to the upstream AbortController
196
226
  // (a fetch body usually rejects on abort, but that coupling is the fetch
197
- // implementation's, not the stream's). Race every read against the abort
198
- // signal so cancel-drain expiry and shutdown teardown ALWAYS break the
199
- // loop even on a silent upstream.
200
- const aborted: Promise<"aborted"> = new Promise(resolve => {
201
- if (upstream.signal.aborted) resolve("aborted");
202
- else upstream.signal.addEventListener("abort", () => resolve("aborted"), { once: true });
203
- });
227
+ // implementation's, not the stream's), so abort must break a parked read on
228
+ // a silent upstream. Cancelling the reader does that: the pending read
229
+ // settles and the loop observes the abort. This is deliberately NOT a
230
+ // shared `Promise.race([reader.read(), aborted])` companion racing every
231
+ // read against one never-settled promise retains a reaction per chunk, and
232
+ // that is the exact retention class relay.ts avoids at its own drain.
233
+ const wakeParkedRead = () => { reader.cancel(upstream.signal.reason).catch(() => {}); };
234
+ if (upstream.signal.aborted) wakeParkedRead();
235
+ else upstream.signal.addEventListener("abort", wakeParkedRead, { once: true });
204
236
  try {
205
237
  for (;;) {
206
- const result = await Promise.race([reader.read(), aborted]);
207
- if (result === "aborted") break;
238
+ const result = await reader.read();
208
239
  const { done: upstreamDone, value } = result;
240
+ // A chunk that already settled is INSPECTED before abort is honored. A read
241
+ // can settle with a real chunk in the same tick the signal fires (post-cancel
242
+ // drain: the terminal frame arrives, then the drain timer aborts upstream).
243
+ // Checking the signal first discarded that frame, so the terminal was never
244
+ // recorded and the turn was accounted as a plain cancel.
245
+ if (!upstreamDone && value !== undefined) hooks.inspectChunk(value);
246
+ if (upstream.signal.aborted) break;
209
247
  if (upstreamDone) {
210
248
  hooks.finishInspection();
211
- if (rewrite) {
212
- const tail = flushRewriteTail();
213
- if (tail.byteLength > 0 && !cancelled) {
214
- queuedBytes += tail.byteLength;
215
- try { controllerRef?.enqueue(tail); } catch { /* client already gone */ }
249
+ const boundedTail = terminalBoundary.finish();
250
+ let clientTail = boundedTail;
251
+ let rewriteFailed = false;
252
+ let rewriteError: unknown;
253
+ if (activeRewrite) {
254
+ try {
255
+ const rewritten = rewriteOutbound(boundedTail);
256
+ clientTail = joinUint8Arrays(rewritten, flushRewriteTail());
257
+ } catch (error) {
258
+ rewriteFailed = true;
259
+ rewriteError = error;
260
+ clientTail = new Uint8Array(0);
261
+ }
262
+ }
263
+ if (rewriteFailed) {
264
+ const safeTail = encodeFailedTail(rewriteError);
265
+ if (safeTail && !cancelled && !upstream.signal.aborted) {
266
+ if (!hooks.sawTerminal()) syntheticKind = "failed";
267
+ queuedBytes += safeTail.byteLength;
268
+ try { controllerRef?.enqueue(safeTail); } catch { /* client already torn down */ }
269
+ try { controllerRef?.close(); } catch { /* client already gone */ }
216
270
  }
271
+ break;
272
+ }
273
+ if (clientTail.byteLength > 0 && !cancelled) {
274
+ queuedBytes += clientTail.byteLength;
275
+ try { controllerRef?.enqueue(clientTail); } catch { /* client already gone */ }
217
276
  }
218
- if (!hooks.sawTerminal() && !cancelled && !upstream.signal.aborted) {
277
+ if (terminalBoundary.terminalSeen()) {
278
+ if (!terminalBoundary.doneSeen() && !cancelled) {
279
+ queuedBytes += terminalSentinel.byteLength;
280
+ try { controllerRef?.enqueue(terminalSentinel); } catch { /* client already gone */ }
281
+ }
282
+ } else if (!hooks.sawTerminal() && !cancelled && !upstream.signal.aborted) {
283
+ // A clean 200 EOF without a Responses terminal must be visible to
284
+ // Codex as one incomplete turn, followed by the normal sentinel.
285
+ queuedBytes += adapterEofFrame.byteLength + terminalSentinel.byteLength;
286
+ try {
287
+ controllerRef?.enqueue(adapterEofFrame);
288
+ controllerRef?.enqueue(terminalSentinel);
289
+ } catch { /* client already gone */ }
219
290
  syntheticKind = "incomplete";
220
291
  }
221
292
  break;
222
293
  }
223
- hooks.inspectChunk(value);
224
294
  if (cancelled) {
225
295
  // Discard-drain: inspection only, nothing queued. Stop at terminal
226
296
  // or when the bounded window expires.
@@ -230,17 +300,44 @@ export function relaySseEagerBounded(
230
300
  }
231
301
  continue;
232
302
  }
233
- const outbound = rewrite ? rewriteOutbound(value) : value;
234
- if (outbound.byteLength === 0) continue;
235
- queuedBytes += outbound.byteLength;
236
- try {
237
- controllerRef?.enqueue(outbound);
238
- } catch {
239
- // Controller already torn down (client went away without cancel()).
240
- cancelled = true;
241
- drainDeadline = now() + drainMs;
242
- armDrainTimer();
243
- continue;
303
+ const terminalBounded = terminalBoundary.feed(value);
304
+ let outbound: Uint8Array;
305
+ if (activeRewrite) {
306
+ try {
307
+ outbound = rewriteOutbound(terminalBounded);
308
+ } catch (error) {
309
+ // Preserve the first rewrite failure across the teardown flush. A
310
+ // second empty flush may succeed, but the terminal bytes still
311
+ // must not bypass the failed rewrite or become DONE-only output.
312
+ priorRewriteFailure = true;
313
+ priorRewriteError = error;
314
+ throw error;
315
+ }
316
+ } else {
317
+ outbound = terminalBounded;
318
+ }
319
+ if (outbound.byteLength > 0) {
320
+ queuedBytes += outbound.byteLength;
321
+ try {
322
+ controllerRef?.enqueue(outbound);
323
+ } catch {
324
+ // Controller already torn down (client went away without cancel()).
325
+ cancelled = true;
326
+ drainDeadline = now() + drainMs;
327
+ armDrainTimer();
328
+ continue;
329
+ }
330
+ }
331
+ if (terminalBoundary.terminalSeen()) {
332
+ // The Responses terminal event ends the turn even when a compatible
333
+ // gateway keeps its HTTP connection alive. Add the conventional
334
+ // sentinel and stop the single-reader relay at that protocol boundary.
335
+ if (!terminalBoundary.doneSeen()) {
336
+ queuedBytes += terminalSentinel.byteLength;
337
+ try { controllerRef?.enqueue(terminalSentinel); } catch { /* client already gone */ }
338
+ }
339
+ reader.cancel("Responses terminal event received").catch(() => {});
340
+ break;
244
341
  }
245
342
  while (queuedBytes > maxQueueBytes && !cancelled && !upstream.signal.aborted) {
246
343
  await paused();
@@ -249,16 +346,75 @@ export function relaySseEagerBounded(
249
346
  } catch (err) {
250
347
  // Upstream read failure. Distinguish genuine mid-stream reset from
251
348
  // abort-driven teardown (shutdown/cancel-expiry) — audit M3.
252
- if (!hooks.sawTerminal() && !cancelled && !upstream.signal.aborted) {
349
+ // A read can fail after delivering an unterminated terminal block. Flush
350
+ // both observers before deciding whether this is a synthetic reset so
351
+ // eager mode matches the tee/pull boundary semantics at EOF.
352
+ let boundedTail: Uint8Array<ArrayBufferLike> = new Uint8Array(0);
353
+ let tailTerminal = false;
354
+ let tailDone = false;
355
+ try { hooks.finishInspection(); } catch { /* preserve the original read failure */ }
356
+ try {
357
+ boundedTail = terminalBoundary.finish();
358
+ tailTerminal = terminalBoundary.terminalSeen();
359
+ tailDone = terminalBoundary.doneSeen();
360
+ } catch {
361
+ // A near-cap ambiguous delimiter tail may itself overflow at EOF.
362
+ // Preserve the original read/framing failure and continue emitting
363
+ // the bounded failed tail instead of letting cleanup throw again.
364
+ }
365
+ let clientTail: Uint8Array<ArrayBufferLike> = boundedTail;
366
+ let rewriteFailed = false;
367
+ let rewriteError: unknown;
368
+ if (priorRewriteFailure) {
369
+ rewriteFailed = true;
370
+ rewriteError = priorRewriteError;
371
+ clientTail = new Uint8Array(0);
372
+ } else if (activeRewrite) {
373
+ try {
374
+ const rewritten = rewriteOutbound(boundedTail);
375
+ clientTail = joinUint8Arrays(rewritten, flushRewriteTail());
376
+ } catch (error) {
377
+ rewriteFailed = true;
378
+ rewriteError = error;
379
+ clientTail = new Uint8Array(0);
380
+ }
381
+ }
382
+ if (clientTail.byteLength > 0 && !cancelled && !upstream.signal.aborted) {
383
+ queuedBytes += clientTail.byteLength;
384
+ try { controllerRef?.enqueue(clientTail); } catch { /* client already torn down */ }
385
+ }
386
+ if (rewriteFailed && !cancelled && !upstream.signal.aborted) {
387
+ // Never bypass a client rewrite after it fails: boundedTail can contain
388
+ // provider metadata or content that the active rewrite was required to
389
+ // remove. Emit one safe failed envelope instead. When inspection has
390
+ // already reported the real upstream terminal, this is a delivery
391
+ // fallback only and must not create a second accounting outcome.
392
+ const safeTail = encodeFailedTail(rewriteError ?? err);
393
+ if (safeTail && !cancelled && !upstream.signal.aborted) {
394
+ if (!hooks.sawTerminal()) syntheticKind = "failed";
395
+ deliveryFallbackSent = true;
396
+ queuedBytes += safeTail.byteLength;
397
+ try { controllerRef?.enqueue(safeTail); } catch { /* client already torn down */ }
398
+ try { controllerRef?.close(); } catch { /* client already gone */ }
399
+ }
400
+ } else if (tailTerminal && !cancelled && !upstream.signal.aborted) {
401
+ if (!tailDone) {
402
+ queuedBytes += terminalSentinel.byteLength;
403
+ try { controllerRef?.enqueue(terminalSentinel); } catch { /* client already gone */ }
404
+ }
405
+ } else if (!tailTerminal && !cancelled && !upstream.signal.aborted) {
253
406
  // Serializing `err` can run user-defined accessors (Error.message
254
407
  // getters, toString) that re-entrantly cancel the client or abort the
255
408
  // upstream. Build the tail FIRST, then re-check eligibility before
256
409
  // committing to the synthetic terminal (adversarial review blocker).
257
- const tail = new TextEncoder().encode(
258
- `\n\nevent: response.failed\ndata: ${buildFailedTailPayload(err)}\n\ndata: [DONE]\n\n`,
259
- );
260
- if (!hooks.sawTerminal() && !cancelled && !upstream.signal.aborted) {
261
- syntheticKind = "failed";
410
+ const tail = encodeFailedTail(err);
411
+ if (tail && !cancelled && !upstream.signal.aborted) {
412
+ // Inspection and client framing have separate bounded parsers. If
413
+ // inspection resynchronized after an oversized frame and observed a
414
+ // later real terminal, it still must not suppress a terminal delivery
415
+ // to the client. Only accounting remains tied to the inspected result.
416
+ if (!hooks.sawTerminal()) syntheticKind = "failed";
417
+ deliveryFallbackSent = true;
262
418
  queuedBytes += tail.byteLength;
263
419
  try { controllerRef?.enqueue(tail); } catch { /* client already torn down */ }
264
420
  try { controllerRef?.close(); } catch { /* client already torn down */ }
@@ -272,11 +428,12 @@ export function relaySseEagerBounded(
272
428
  try { rewriteBudget.releaseRetained(frameBufferBytes, { kind: "live_transient" }); } catch { /* teardown must not throw */ }
273
429
  frameBufferBytes = 0;
274
430
  }
431
+ terminalBoundary.dispose();
275
432
  if (syntheticKind) hooks.onSynthetic(syntheticKind);
276
433
  if (cancelled && !hooks.sawTerminal()) {
277
434
  hooks.onClientCancel();
278
435
  }
279
- if (cancelled || upstream.signal.aborted || syntheticKind === "failed") {
436
+ if (cancelled || upstream.signal.aborted || syntheticKind === "failed" || deliveryFallbackSent) {
280
437
  upstream.abort();
281
438
  reader.cancel().catch(() => {});
282
439
  }
@@ -284,6 +441,7 @@ export function relaySseEagerBounded(
284
441
  try { controllerRef?.close(); } catch { /* already closed/errored */ }
285
442
  }
286
443
  try { hooks.disposeInspection?.(); } catch { /* inspection teardown must not block lifecycle cleanup */ }
444
+ try { activeRewrite?.dispose?.(); } catch { /* rewrite teardown must not block lifecycle cleanup */ }
287
445
  fireDone();
288
446
  }
289
447
  };
@@ -311,3 +469,12 @@ export function relaySseEagerBounded(
311
469
  },
312
470
  });
313
471
  }
472
+
473
+ function joinUint8Arrays(first: Uint8Array, second: Uint8Array): Uint8Array {
474
+ if (first.byteLength === 0) return second;
475
+ if (second.byteLength === 0) return first;
476
+ const joined = new Uint8Array(first.byteLength + second.byteLength);
477
+ joined.set(first);
478
+ joined.set(second, first.byteLength);
479
+ return joined;
480
+ }