@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,319 @@
1
+ import { isCyberPolicyCode, isCyberPolicyMessage } from "../lib/errors";
2
+
3
+ export const MAX_CLIENT_SSE_FRAME_BYTES = 4 * 1024 * 1024;
4
+
5
+ const LF_LF = Uint8Array.of(10, 10);
6
+ const LF_CR_LF = Uint8Array.of(10, 13, 10);
7
+ const CR_LF_LF = Uint8Array.of(13, 10, 10);
8
+ const CR_LF_CR_LF = Uint8Array.of(13, 10, 13, 10);
9
+
10
+ export class SseFrameTooLargeError extends Error {
11
+ readonly maxBytes: number;
12
+
13
+ constructor(maxBytes: number) {
14
+ super(`upstream SSE frame exceeded ${maxBytes} bytes`);
15
+ this.name = "SseFrameTooLargeError";
16
+ this.maxBytes = maxBytes;
17
+ }
18
+ }
19
+
20
+ export class SseFrameCountLimitError extends Error {
21
+ readonly maxFrames: number;
22
+
23
+ constructor(maxFrames: number) {
24
+ super(`upstream SSE chunk exceeded ${maxFrames} frame limit`);
25
+ this.name = "SseFrameCountLimitError";
26
+ this.maxFrames = maxFrames;
27
+ }
28
+ }
29
+
30
+ export type BoundedSseFrame = {
31
+ block: Uint8Array;
32
+ delimiter: Uint8Array;
33
+ };
34
+
35
+ /**
36
+ * Classify the bytes at `index` as an SSE block delimiter.
37
+ *
38
+ * Returns the delimiter length in bytes, `0` when `index` does not start a
39
+ * delimiter, and `undefined` when more bytes are required to decide.
40
+ */
41
+ function delimiterLengthAt(
42
+ index: number,
43
+ length: number,
44
+ byteAt: (index: number) => number,
45
+ ): number | undefined {
46
+ const first = byteAt(index);
47
+ if (first === 10) {
48
+ if (index + 1 >= length) return undefined;
49
+ const second = byteAt(index + 1);
50
+ if (second === 10) return 2;
51
+ if (second !== 13) return 0;
52
+ if (index + 2 >= length) return undefined;
53
+ return byteAt(index + 2) === 10 ? 3 : 0;
54
+ }
55
+ if (first !== 13) return 0;
56
+ if (index + 1 >= length) return undefined;
57
+ if (byteAt(index + 1) !== 10) return 0;
58
+ if (index + 2 >= length) return undefined;
59
+ const third = byteAt(index + 2);
60
+ if (third === 10) return 3;
61
+ if (third !== 13) return 0;
62
+ if (index + 3 >= length) return undefined;
63
+ return byteAt(index + 3) === 10 ? 4 : 0;
64
+ }
65
+
66
+ function delimiterBytesAt(
67
+ index: number,
68
+ delimiterLength: number,
69
+ byteAt: (index: number) => number,
70
+ ): Uint8Array {
71
+ if (delimiterLength === 2) return LF_LF;
72
+ if (delimiterLength === 4) return CR_LF_CR_LF;
73
+ return byteAt(index) === 10 ? LF_CR_LF : CR_LF_LF;
74
+ }
75
+
76
+ function copyRange(
77
+ start: number,
78
+ end: number,
79
+ tailLength: number,
80
+ previousTail: Uint8Array,
81
+ chunk: Uint8Array,
82
+ ): Uint8Array {
83
+ const out = new Uint8Array(end - start);
84
+ for (let index = start; index < end; index += 1) {
85
+ out[index - start] = index < tailLength
86
+ ? previousTail[index]!
87
+ : chunk[index - tailLength]!;
88
+ }
89
+ return out;
90
+ }
91
+
92
+ /**
93
+ * True when a complete SSE block already commits a Responses terminal event.
94
+ *
95
+ * Framing errors in bytes *after* such a block must not retroactively turn an
96
+ * already-completed/failed/incomplete model turn into a transport failure. This
97
+ * helper is used only on the exceptional path, so decoding/JSON parsing has no
98
+ * cost on ordinary framing.
99
+ */
100
+ function isResponsesTerminalFrame(block: Uint8Array): boolean {
101
+ const data: string[] = [];
102
+ for (const line of new TextDecoder().decode(block).split(/\r?\n/)) {
103
+ if (!line.startsWith("data:")) continue;
104
+ const value = line.slice(5);
105
+ data.push(value.startsWith(" ") ? value.slice(1) : value);
106
+ }
107
+ if (data.length === 0) return false;
108
+ const payload = data.join("\n");
109
+ if (payload === "[DONE]") return false;
110
+ try {
111
+ const parsed = JSON.parse(payload) as {
112
+ type?: unknown;
113
+ code?: unknown;
114
+ message?: unknown;
115
+ error?: unknown;
116
+ last_error?: unknown;
117
+ response?: { error?: unknown; incomplete_details?: unknown };
118
+ };
119
+ if (parsed.type === "response.completed"
120
+ || parsed.type === "response.failed"
121
+ || parsed.type === "response.incomplete") return true;
122
+ if (parsed.type !== "error") return false;
123
+ // A top-level error is terminal for this boundary only when it carries the
124
+ // same high-confidence cyber-policy evidence used by relay.ts. Ordinary
125
+ // upstream errors remain transport failures and still become a bounded 502.
126
+ const candidates = [
127
+ parsed,
128
+ parsed.error,
129
+ parsed.last_error,
130
+ parsed.response?.error,
131
+ parsed.response?.incomplete_details,
132
+ ];
133
+ for (const candidate of candidates) {
134
+ if (!candidate || typeof candidate !== "object" || Array.isArray(candidate)) continue;
135
+ const record = candidate as { code?: unknown; message?: unknown };
136
+ if (isCyberPolicyCode(typeof record.code === "string" ? record.code : undefined)) return true;
137
+ if (typeof record.message === "string" && isCyberPolicyMessage(record.message)) return true;
138
+ }
139
+ return false;
140
+ } catch {
141
+ return false;
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Byte-bounded SSE block framer for client-facing protocol paths.
147
+ *
148
+ * The delimiter scanner works on raw bytes, so fragmented UTF-8 cannot change
149
+ * accounting and a hostile upstream cannot grow an unterminated JS string
150
+ * without limit. Candidate bytes live in one geometrically grown buffer rather
151
+ * than one allocation per upstream chunk, bounding both bytes and object count.
152
+ * Complete blocks are returned without their delimiter; the exact delimiter
153
+ * bytes are returned separately so callers can relay bytes unchanged.
154
+ */
155
+ export class BoundedSseFrameBuffer {
156
+ private readonly maxFrameBytes: number;
157
+ private readonly maxFramesPerFeed: number;
158
+ private delimiterTail: Uint8Array = new Uint8Array(0);
159
+ private candidate: Uint8Array = new Uint8Array(0);
160
+ private candidateBytes = 0;
161
+ private disposed = false;
162
+
163
+ constructor(maxFrameBytes = MAX_CLIENT_SSE_FRAME_BYTES) {
164
+ if (!Number.isSafeInteger(maxFrameBytes) || maxFrameBytes <= 0) {
165
+ throw new RangeError("maxFrameBytes must be a positive safe integer");
166
+ }
167
+ this.maxFrameBytes = maxFrameBytes;
168
+ // Delimiter-only input otherwise creates an object-amplification path that
169
+ // is independent of candidate bytes. Keep frame count proportional to the
170
+ // configured byte budget while leaving ample room for real Responses events.
171
+ this.maxFramesPerFeed = Math.max(1, Math.ceil(maxFrameBytes / 1024));
172
+ }
173
+
174
+ private clear(): void {
175
+ this.delimiterTail = new Uint8Array(0);
176
+ this.candidate = new Uint8Array(0);
177
+ this.candidateBytes = 0;
178
+ }
179
+
180
+ private ensureCapacity(requiredBytes: number): void {
181
+ if (this.candidate.byteLength >= requiredBytes) return;
182
+ if (requiredBytes > this.maxFrameBytes) {
183
+ throw new SseFrameTooLargeError(this.maxFrameBytes);
184
+ }
185
+ let capacity = this.candidate.byteLength === 0
186
+ ? Math.min(this.maxFrameBytes, Math.max(requiredBytes, 4096))
187
+ : this.candidate.byteLength;
188
+ while (capacity < requiredBytes) {
189
+ capacity = Math.min(this.maxFrameBytes, Math.max(requiredBytes, capacity * 2));
190
+ }
191
+ const grown = new Uint8Array(capacity);
192
+ if (this.candidateBytes > 0) {
193
+ grown.set(this.candidate.subarray(0, this.candidateBytes));
194
+ }
195
+ this.candidate = grown;
196
+ }
197
+
198
+ private retain(slice: Uint8Array): void {
199
+ if (slice.byteLength === 0) return;
200
+ const nextBytes = this.candidateBytes + slice.byteLength;
201
+ if (nextBytes > this.maxFrameBytes) {
202
+ this.clear();
203
+ this.disposed = true;
204
+ throw new SseFrameTooLargeError(this.maxFrameBytes);
205
+ }
206
+ this.ensureCapacity(nextBytes);
207
+ this.candidate.set(slice, this.candidateBytes);
208
+ this.candidateBytes = nextBytes;
209
+ }
210
+
211
+ private takeCandidate(): Uint8Array {
212
+ if (this.candidateBytes === 0) return new Uint8Array(0);
213
+ const block = this.candidate.slice(0, this.candidateBytes);
214
+ // Release the working allocation after each complete frame. This avoids
215
+ // retaining a rare multi-MiB frame allocation for the rest of a long-lived
216
+ // stream; normal small-frame allocation remains bounded by feed's frame cap.
217
+ this.candidate = new Uint8Array(0);
218
+ this.candidateBytes = 0;
219
+ return block;
220
+ }
221
+
222
+ feed(chunk: Uint8Array): BoundedSseFrame[] {
223
+ if (this.disposed) return [];
224
+ if (chunk.byteLength === 0) return [];
225
+
226
+ const frames: BoundedSseFrame[] = [];
227
+ const previousTail = this.delimiterTail;
228
+ this.delimiterTail = new Uint8Array(0);
229
+ const tailLength = previousTail.byteLength;
230
+ const totalLength = tailLength + chunk.byteLength;
231
+ const byteAt = (index: number): number => index < tailLength
232
+ ? previousTail[index]!
233
+ : chunk[index - tailLength]!;
234
+ const retainRange = (start: number, end: number): void => {
235
+ if (end <= start) return;
236
+ if (start < tailLength) {
237
+ this.retain(previousTail.subarray(start, Math.min(end, tailLength)));
238
+ }
239
+ if (end > tailLength) {
240
+ this.retain(chunk.subarray(Math.max(0, start - tailLength), end - tailLength));
241
+ }
242
+ };
243
+
244
+ try {
245
+ let index = 0;
246
+ let retainedThrough = 0;
247
+ while (index < totalLength) {
248
+ const delimiterLength = delimiterLengthAt(index, totalLength, byteAt);
249
+ if (delimiterLength === undefined) break;
250
+ if (delimiterLength > 0) {
251
+ if (frames.length >= this.maxFramesPerFeed) {
252
+ this.clear();
253
+ this.disposed = true;
254
+ throw new SseFrameCountLimitError(this.maxFramesPerFeed);
255
+ }
256
+ retainRange(retainedThrough, index);
257
+ const block = this.takeCandidate();
258
+ const delimiter = delimiterBytesAt(index, delimiterLength, byteAt);
259
+ frames.push({ block, delimiter });
260
+ index += delimiterLength;
261
+ retainedThrough = index;
262
+ continue;
263
+ }
264
+ index += 1;
265
+ }
266
+
267
+ retainRange(retainedThrough, index);
268
+ if (index < totalLength) {
269
+ this.delimiterTail = copyRange(index, totalLength, tailLength, previousTail, chunk);
270
+ }
271
+ return frames;
272
+ } catch (err) {
273
+ const framingError = err instanceof SseFrameTooLargeError
274
+ || err instanceof SseFrameCountLimitError;
275
+ if (framingError && frames.some(frame => isResponsesTerminalFrame(frame.block))) {
276
+ // A terminal frame is the Responses protocol boundary. Ignore malformed
277
+ // or oversized bytes that occur later in the same upstream chunk rather
278
+ // than retroactively replacing the committed terminal with a 502.
279
+ this.clear();
280
+ this.disposed = true;
281
+ return frames;
282
+ }
283
+ throw err;
284
+ }
285
+ }
286
+
287
+ /** Return the final unterminated block bytes and release all retained state. */
288
+ finish(): Uint8Array {
289
+ if (this.disposed) return new Uint8Array(0);
290
+ try {
291
+ this.retain(this.delimiterTail);
292
+ this.delimiterTail = new Uint8Array(0);
293
+ return this.takeCandidate();
294
+ } finally {
295
+ this.clear();
296
+ this.disposed = true;
297
+ }
298
+ }
299
+
300
+ dispose(): void {
301
+ if (this.disposed) return;
302
+ this.clear();
303
+ this.disposed = true;
304
+ }
305
+ }
306
+
307
+ export function joinSseFrameBytes(parts: readonly Uint8Array[]): Uint8Array {
308
+ let byteLength = 0;
309
+ for (const part of parts) byteLength += part.byteLength;
310
+ if (byteLength === 0) return new Uint8Array(0);
311
+ if (parts.length === 1 && parts[0]!.byteLength === byteLength) return parts[0]!;
312
+ const joined = new Uint8Array(byteLength);
313
+ let offset = 0;
314
+ for (const part of parts) {
315
+ joined.set(part, offset);
316
+ offset += part.byteLength;
317
+ }
318
+ return joined;
319
+ }
@@ -9,6 +9,56 @@ import type { TranslatorBudget } from "../lib/translator-budget";
9
9
 
10
10
  export type SsePayloadRewrite = (payload: string) => string;
11
11
 
12
+ /**
13
+ * Block-level SSE rewrite: maps one complete SSE event block (without its
14
+ * blank-line delimiter) to zero or more replacement blocks. This is the
15
+ * contract lifecycle repair needs: injecting missing canonical events
16
+ * (#893) is impossible in the one-payload-in/one-payload-out model.
17
+ *
18
+ * `dispose` releases any retained state (budget-charged collectors) when the
19
+ * relay tears down — terminal, EOF, cancel, or error. Relays call it exactly
20
+ * once per teardown path.
21
+ */
22
+ export type SseBlockRewrite = ((block: string) => readonly string[]) & {
23
+ dispose?: () => void;
24
+ };
25
+
26
+ /** Adapt a payload rewrite to the block contract (replace only on change). */
27
+ export function payloadRewriteAsBlockRewrite(rewrite: SsePayloadRewrite): SseBlockRewrite {
28
+ return (block) => {
29
+ const payload = sseDataPayload(block);
30
+ if (payload === null) return [block];
31
+ const rewritten = rewrite(payload);
32
+ return rewritten !== payload ? [replaceSseDataPayload(block, rewritten)] : [block];
33
+ };
34
+ }
35
+
36
+ /** Chain block rewrites: every block stage N emits feeds stage N+1. */
37
+ export function composeSseBlockRewrites(...rewrites: SseBlockRewrite[]): SseBlockRewrite {
38
+ const active = rewrites.filter(Boolean);
39
+ if (active.length === 0) return Object.assign((block: string) => [block], {});
40
+ const composed: SseBlockRewrite = (block: string) => {
41
+ let blocks: readonly string[] = [block];
42
+ for (const rewrite of active) {
43
+ const next: string[] = [];
44
+ for (const current of blocks) next.push(...rewrite(current));
45
+ blocks = next;
46
+ }
47
+ return blocks;
48
+ };
49
+ // Child disposal is part of the contract: one idempotent disposer for the
50
+ // whole chain, so relay teardown never leaks a nested collector.
51
+ let disposed = false;
52
+ composed.dispose = () => {
53
+ if (disposed) return;
54
+ disposed = true;
55
+ for (const rewrite of active) {
56
+ try { rewrite.dispose?.(); } catch { /* teardown must not throw */ }
57
+ }
58
+ };
59
+ return composed;
60
+ }
61
+
12
62
  /** Split one complete SSE event block while retaining its original blank-line delimiter. */
13
63
  export function nextSseBlock(buffer: string): { block: string; delimiter: string; rest: string } | null {
14
64
  const match = buffer.match(/\r?\n\r?\n/);
@@ -69,12 +119,34 @@ export function relaySseWithPayloadRewrite(
69
119
  body: ReadableStream<Uint8Array>,
70
120
  rewrite: SsePayloadRewrite,
71
121
  translatorBudget: TranslatorBudget,
122
+ ): ReadableStream<Uint8Array> {
123
+ return relaySseWithBlockRewrite(body, payloadRewriteAsBlockRewrite(rewrite), translatorBudget);
124
+ }
125
+
126
+ /**
127
+ * Relay an SSE body through a single JS pull wrapper, applying a block-level
128
+ * rewrite that may emit zero or more blocks per upstream event (lifecycle
129
+ * event injection, #893). The original stream's delimiter style is preserved
130
+ * for every emitted block.
131
+ */
132
+ export function relaySseWithBlockRewrite(
133
+ body: ReadableStream<Uint8Array>,
134
+ rewrite: SseBlockRewrite,
135
+ translatorBudget: TranslatorBudget,
72
136
  ): ReadableStream<Uint8Array> {
73
137
  const reader = body.getReader();
74
138
  const decoder = new TextDecoder();
75
139
  const encoder = new TextEncoder();
76
140
  let buffer = "";
77
141
  let bufferBytes = 0;
142
+ // Relays have several independent teardown paths; disposal is exactly once.
143
+ let disposed = false;
144
+ let cancelled = false;
145
+ const disposeRewrite = (): void => {
146
+ if (disposed) return;
147
+ disposed = true;
148
+ try { rewrite.dispose?.(); } catch { /* teardown must not throw */ }
149
+ };
78
150
 
79
151
  const appendBuffer = (fragment: string): void => {
80
152
  if (!fragment) return;
@@ -126,49 +198,65 @@ export function relaySseWithPayloadRewrite(
126
198
  const emitProcessedBlocks = (
127
199
  controller: ReadableStreamDefaultController<Uint8Array>,
128
200
  flushFinal = false,
129
- ): void => {
201
+ ): number => {
202
+ let emitted = 0;
130
203
  let next: { block: string; delimiter: string; rest: string } | null;
131
204
  while ((next = nextSseBlock(buffer))) {
132
205
  replaceBuffer(next.rest);
133
- const payload = sseDataPayload(next.block);
134
- const rewrittenPayload = payload ? rewrite(payload) : undefined;
135
- const block = payload && rewrittenPayload !== undefined && rewrittenPayload !== payload
136
- ? replaceSseDataPayload(next.block, rewrittenPayload)
137
- : next.block;
138
- enqueueText(controller, block + next.delimiter);
206
+ for (const outBlock of rewrite(next.block)) {
207
+ enqueueText(controller, outBlock + next.delimiter);
208
+ emitted += 1;
209
+ }
139
210
  }
140
211
  if (flushFinal && buffer.length > 0) {
141
- const payload = sseDataPayload(buffer);
142
- const rewrittenPayload = payload ? rewrite(payload) : undefined;
143
- const block = payload && rewrittenPayload !== undefined && rewrittenPayload !== payload
144
- ? replaceSseDataPayload(buffer, rewrittenPayload)
145
- : buffer;
146
- enqueueText(controller, block);
212
+ const tailBlocks = rewrite(buffer);
213
+ // A trailing fragment has no delimiter of its own; multiple emitted
214
+ // blocks must still be framed as separate events (#893 review).
215
+ const tailDelimiter = buffer.includes("\r\n") ? "\r\n\r\n" : "\n\n";
216
+ for (let i = 0; i < tailBlocks.length; i++) {
217
+ enqueueText(controller, tailBlocks[i]! + (i < tailBlocks.length - 1 ? tailDelimiter : ""));
218
+ emitted += 1;
219
+ }
147
220
  releaseBuffer();
148
221
  }
222
+ return emitted;
149
223
  };
150
224
 
151
225
  return new ReadableStream<Uint8Array>({
152
226
  async pull(controller) {
153
227
  try {
154
- const { done, value } = await reader.read();
155
- if (done) {
156
- appendBuffer(decoder.decode());
157
- emitProcessedBlocks(controller, true);
158
- releaseBuffer();
159
- controller.close();
160
- return;
228
+ // A network chunk is not an SSE-event boundary. Bun may not issue a
229
+ // second pull after a fulfilled pull enqueues nothing, so keep reading
230
+ // until at least one complete rewritten block is available or EOF is
231
+ // reached. This also handles block rewrites that intentionally drop an
232
+ // event without parking the client stream.
233
+ for (;;) {
234
+ const { done, value } = await reader.read();
235
+ // A cancel raced this pending read: never feed the rewriter again
236
+ // after its disposal (#893 review).
237
+ if (cancelled) return;
238
+ if (done) {
239
+ appendBuffer(decoder.decode());
240
+ emitProcessedBlocks(controller, true);
241
+ releaseBuffer();
242
+ disposeRewrite();
243
+ controller.close();
244
+ return;
245
+ }
246
+ appendBuffer(decoder.decode(value, { stream: true }));
247
+ if (emitProcessedBlocks(controller) > 0) return;
161
248
  }
162
- appendBuffer(decoder.decode(value, { stream: true }));
163
- emitProcessedBlocks(controller);
164
249
  } catch (error) {
165
250
  releaseBuffer();
251
+ disposeRewrite();
166
252
  try { await reader.cancel(error); } catch { /* already closed */ }
167
253
  controller.error(error);
168
254
  }
169
255
  },
170
256
  cancel(reason) {
257
+ cancelled = true;
171
258
  releaseBuffer();
259
+ disposeRewrite();
172
260
  reader.cancel(reason).catch(() => {});
173
261
  },
174
262
  });
@@ -164,10 +164,17 @@ function runCliInstall(
164
164
  const cli = join(import.meta.dir, "..", "cli", "index.ts");
165
165
  const argv = [cli, ...startupInstallArgv(action, options)];
166
166
  return new Promise((resolve, reject) => {
167
+ const timeout = process.platform === "win32" && action === "install-service"
168
+ ? 0
169
+ : 60_000;
167
170
  execFile(bun, argv, {
168
171
  encoding: "utf8",
169
172
  env: process.env,
170
- timeout: 60_000,
173
+ // A fresh Windows scheduler install now owns its UAC prompt inside this CLI
174
+ // transaction. Killing only the CLI at 60s can orphan its elevated schtasks child,
175
+ // which may register the task after the Dashboard has reported failure. Keep the
176
+ // async request/attempt lock alive until Windows returns approval or cancellation.
177
+ timeout,
171
178
  windowsHide: true,
172
179
  maxBuffer: 256 * 1024,
173
180
  }, (error, stdout, stderr) => {
@@ -10,6 +10,7 @@ import { truncateRetainedUtf8 } from "../lib/admission";
10
10
 
11
11
  const CACHE_TTL_MS = 30_000;
12
12
  const PROBE_TIMEOUT_MS = 5_000;
13
+ const INITIAL_PROBE_WAIT_MS = 5_500;
13
14
  const MAX_DIAGNOSTIC_VALUE_BYTES = 8 * 1024;
14
15
  let cached: { timestamp: number; value: StartupHealth } | null = null;
15
16
  let inflight: Promise<StartupHealth> | null = null;
@@ -23,9 +24,14 @@ export function markStartupHealthDiagnosticStale(value: StartupHealth): StartupH
23
24
  rebootSafe: false,
24
25
  protection: "none",
25
26
  diagnosticStale: true,
27
+ // Mirror deriveStartupHealth's choice: an already-registered service is refreshed in
28
+ // place. Hardcoding installService here silently undid that for every stale-cache
29
+ // read, which is the path the dashboard hits while a probe is revalidating.
26
30
  recommendedCommand: value.routingKind === "custom-local" || value.routingKind === "unknown"
27
31
  ? value.commands.restoreNative
28
- : value.commands.installService,
32
+ : value.serviceInstalled && !value.serviceConflict
33
+ ? value.commands.repairService
34
+ : value.commands.installService,
29
35
  };
30
36
  }
31
37
 
@@ -72,6 +78,7 @@ function runProbe(config: Pick<OcxConfig, "codexAutoStart">): Promise<StartupHea
72
78
  : truncateRetainedUtf8(parsed.recommendedCommand, MAX_DIAGNOSTIC_VALUE_BYTES),
73
79
  commands: {
74
80
  installService: truncateRetainedUtf8(parsed.commands.installService, MAX_DIAGNOSTIC_VALUE_BYTES),
81
+ repairService: truncateRetainedUtf8(parsed.commands.repairService, MAX_DIAGNOSTIC_VALUE_BYTES),
75
82
  installShim: truncateRetainedUtf8(parsed.commands.installShim, MAX_DIAGNOSTIC_VALUE_BYTES),
76
83
  restoreNative: truncateRetainedUtf8(parsed.commands.restoreNative, MAX_DIAGNOSTIC_VALUE_BYTES),
77
84
  },
@@ -103,6 +110,17 @@ function refreshInBackground(config: Pick<OcxConfig, "codexAutoStart">): void {
103
110
  export async function getCachedStartupHealth(config: Pick<OcxConfig, "codexAutoStart">): Promise<StartupHealth> {
104
111
  if (cached && Date.now() - cached.timestamp < CACHE_TTL_MS) return cached.value;
105
112
  refreshInBackground(config);
113
+ // An expired or empty read is an explicit protection check. Wait for the
114
+ // isolated probe instead of presenting a synthetic failure while that probe
115
+ // is still running. The probe remains child-process isolated and hard-capped
116
+ // at 5s; stale state is returned only if that bounded probe cannot settle.
117
+ if (inflight) {
118
+ const settled = await Promise.race([
119
+ inflight,
120
+ new Promise<null>(resolve => setTimeout(() => resolve(null), INITIAL_PROBE_WAIT_MS)),
121
+ ]);
122
+ if (settled) return settled;
123
+ }
106
124
  return cached ? markStartupHealthDiagnosticStale(cached.value) : conservativeFallback(config);
107
125
  }
108
126