@iislee/opencodex 2.11.0 → 2.31.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 (675) hide show
  1. package/AGENTS_INSTALL.md +109 -0
  2. package/README.md +114 -19
  3. package/bin/ocx.mjs +164 -36
  4. package/bin/package-main.mjs +1 -1
  5. package/gui/dist/assets/index-BF38heuV.js +104 -0
  6. package/gui/dist/assets/index-DMiI18Kv.css +1 -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 +19 -10
  42. package/src/adapters/anthropic-output-schema.ts +137 -0
  43. package/src/adapters/anthropic.ts +376 -52
  44. package/src/adapters/base.ts +54 -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 +601 -0
  48. package/src/adapters/cursor/checkpoint-store.ts +303 -0
  49. package/src/adapters/cursor/cursor-errors.ts +129 -6
  50. package/src/adapters/cursor/discovery.ts +61 -4
  51. package/src/adapters/cursor/effort-map.ts +27 -3
  52. package/src/adapters/cursor/framing.ts +39 -0
  53. package/src/adapters/cursor/h2-pool.ts +123 -0
  54. package/src/adapters/cursor/http1-bidi.ts +361 -0
  55. package/src/adapters/cursor/images.ts +704 -0
  56. package/src/adapters/cursor/live-models.ts +174 -58
  57. package/src/adapters/cursor/live-transport.ts +609 -170
  58. package/src/adapters/cursor/native-exec-common.ts +23 -2
  59. package/src/adapters/cursor/native-exec-fs.ts +10 -7
  60. package/src/adapters/cursor/native-exec-network.ts +1 -1
  61. package/src/adapters/cursor/native-exec-shell.ts +0 -1
  62. package/src/adapters/cursor/native-exec.ts +101 -14
  63. package/src/adapters/cursor/protobuf-events.ts +829 -11
  64. package/src/adapters/cursor/protobuf-request.ts +383 -65
  65. package/src/adapters/cursor/request-builder.ts +237 -31
  66. package/src/adapters/cursor/tool-definitions.ts +242 -12
  67. package/src/adapters/cursor/tool-result-normalize.ts +92 -0
  68. package/src/adapters/cursor/transport.ts +22 -0
  69. package/src/adapters/cursor/types.ts +28 -1
  70. package/src/adapters/cursor.ts +133 -7
  71. package/src/adapters/google-antigravity-replay.ts +558 -34
  72. package/src/adapters/google-antigravity-wire.ts +43 -10
  73. package/src/adapters/google-http.ts +38 -10
  74. package/src/adapters/google-tool-schema.ts +80 -15
  75. package/src/adapters/google-truncation.ts +11 -0
  76. package/src/adapters/google.ts +618 -74
  77. package/src/adapters/identity.ts +39 -6
  78. package/src/adapters/kiro-errors.ts +11 -0
  79. package/src/adapters/kiro-events.ts +19 -1
  80. package/src/adapters/kiro-thinking.ts +18 -2
  81. package/src/adapters/kiro-tools.ts +10 -1
  82. package/src/adapters/kiro.ts +92 -54
  83. package/src/adapters/mimo-free.ts +17 -0
  84. package/src/adapters/openai-chat-url.ts +11 -0
  85. package/src/adapters/openai-chat.ts +1311 -336
  86. package/src/adapters/openai-responses-url.ts +16 -0
  87. package/src/adapters/openai-responses.ts +830 -56
  88. package/src/adapters/registry.ts +175 -0
  89. package/src/adapters/responses-tool-schema.ts +67 -0
  90. package/src/adapters/tool-call-id.ts +119 -0
  91. package/src/adapters/tool-catalog-nudge.ts +104 -21
  92. package/src/adapters/xai-web-search.ts +185 -0
  93. package/src/bridge.ts +428 -61
  94. package/src/chat/inbound.ts +43 -19
  95. package/src/chat/outbound.ts +82 -26
  96. package/src/claude/agents-inject.ts +32 -9
  97. package/src/claude/context-windows.ts +21 -5
  98. package/src/claude/desktop-3p.ts +243 -9
  99. package/src/claude/gateway-cache.ts +41 -4
  100. package/src/claude/inbound.ts +72 -3
  101. package/src/claude/model-info.ts +38 -15
  102. package/src/claude/outbound.ts +70 -16
  103. package/src/cli/account-api.ts +35 -1
  104. package/src/cli/account-auth.ts +33 -6
  105. package/src/cli/account-catalog-refresh.ts +14 -0
  106. package/src/cli/account-extended.ts +389 -2
  107. package/src/cli/account-main.ts +317 -0
  108. package/src/cli/account.ts +30 -6
  109. package/src/cli/agent.ts +45 -1
  110. package/src/cli/claude-agent-startup-sync.ts +73 -0
  111. package/src/cli/claude-desktop.ts +29 -4
  112. package/src/cli/claude.ts +103 -34
  113. package/src/cli/codex-log-guard-doctor.ts +103 -0
  114. package/src/cli/codex-shim-autorestore.ts +2 -0
  115. package/src/cli/codex-shim-readiness.ts +76 -0
  116. package/src/cli/combo.ts +8 -0
  117. package/src/cli/config-command.ts +74 -10
  118. package/src/cli/dispatch.ts +593 -0
  119. package/src/cli/doctor.ts +315 -43
  120. package/src/cli/ensure-desired-integrations.ts +152 -0
  121. package/src/cli/export-command.ts +46 -20
  122. package/src/cli/help.ts +20 -271
  123. package/src/cli/index.ts +378 -519
  124. package/src/cli/init.ts +4 -17
  125. package/src/cli/integrations.ts +120 -2
  126. package/src/cli/lab.ts +607 -0
  127. package/src/cli/launcher-context.ts +77 -0
  128. package/src/cli/minimax.ts +497 -0
  129. package/src/cli/models-runtime.ts +35 -2
  130. package/src/cli/models.ts +100 -14
  131. package/src/cli/observe.ts +92 -3
  132. package/src/cli/opencode.ts +4 -2
  133. package/src/cli/provider-runtime.ts +18 -1
  134. package/src/cli/provider.ts +24 -3
  135. package/src/cli/ready.ts +301 -0
  136. package/src/cli/registry.ts +437 -0
  137. package/src/cli/root.ts +86 -0
  138. package/src/cli/route-policy.ts +92 -0
  139. package/src/cli/runtime-api.ts +6 -3
  140. package/src/cli/star-prompt.ts +71 -15
  141. package/src/cli/status.ts +10 -3
  142. package/src/cli/system-restart-client.ts +146 -0
  143. package/src/cli/tray-proxy.ts +153 -6
  144. package/src/cli/v2.ts +105 -10
  145. package/src/cli.ts +1 -1
  146. package/src/clients/config-export.ts +1358 -21
  147. package/src/codex/account-label.ts +14 -1
  148. package/src/codex/account-lifecycle.ts +130 -13
  149. package/src/codex/account-namespaces.ts +49 -3
  150. package/src/codex/account-priority.ts +83 -0
  151. package/src/codex/account-store.ts +29 -2
  152. package/src/codex/account-usability.ts +25 -2
  153. package/src/codex/admission.ts +256 -0
  154. package/src/codex/affinity-debug.ts +162 -0
  155. package/src/codex/app-server-processes.ts +493 -106
  156. package/src/codex/app-server-restart-service.ts +232 -0
  157. package/src/codex/auth-api.ts +849 -242
  158. package/src/codex/auth-collision.ts +5 -3
  159. package/src/codex/auth-context.ts +345 -32
  160. package/src/codex/autostart-health.ts +8 -1
  161. package/src/codex/catalog/account-models.ts +67 -0
  162. package/src/codex/catalog/aggregation.ts +68 -10
  163. package/src/codex/catalog/bundled.ts +331 -33
  164. package/src/codex/catalog/effort.ts +121 -30
  165. package/src/codex/catalog/filesystem-evidence.ts +302 -0
  166. package/src/codex/catalog/kinds.ts +2 -0
  167. package/src/codex/catalog/metadata.ts +529 -45
  168. package/src/codex/catalog/native-models.ts +72 -0
  169. package/src/codex/catalog/parsing.ts +224 -30
  170. package/src/codex/catalog/provider-fetch.ts +1460 -134
  171. package/src/codex/catalog/sync.ts +1449 -186
  172. package/src/codex/catalog-admission.ts +199 -0
  173. package/src/codex/catalog-refresh-status.ts +105 -0
  174. package/src/codex/catalog-write-serialization.ts +242 -0
  175. package/src/codex/catalog.ts +6 -3
  176. package/src/codex/codex-write-lock.ts +384 -0
  177. package/src/codex/convergence-types.ts +614 -0
  178. package/src/codex/convergence.ts +651 -0
  179. package/src/codex/coordinator-doctor.ts +332 -0
  180. package/src/codex/custom-model-catalog-migration.ts +176 -0
  181. package/src/codex/desired-state.ts +230 -0
  182. package/src/codex/features.ts +636 -39
  183. package/src/codex/generation.ts +202 -0
  184. package/src/codex/history-job.ts +407 -0
  185. package/src/codex/history-lock.ts +242 -0
  186. package/src/codex/history-migration-guardian.ts +26 -20
  187. package/src/codex/history-provider.ts +231 -28
  188. package/src/codex/history-transition.ts +105 -0
  189. package/src/codex/history-worker.ts +220 -0
  190. package/src/codex/inject-coordination.ts +290 -0
  191. package/src/codex/inject.ts +1073 -152
  192. package/src/codex/injected-marker.ts +37 -3
  193. package/src/codex/integration-record.ts +266 -0
  194. package/src/codex/internal/catalog-writer.ts +203 -0
  195. package/src/codex/internal/history-writer.ts +80 -0
  196. package/src/codex/journal.ts +66 -4
  197. package/src/codex/log-guard/inspect.ts +506 -0
  198. package/src/codex/log-guard/lock.ts +150 -0
  199. package/src/codex/log-guard/maintenance.ts +403 -0
  200. package/src/codex/log-guard/path-safety.ts +88 -0
  201. package/src/codex/log-guard/policy.ts +44 -0
  202. package/src/codex/log-guard/processes.ts +205 -0
  203. package/src/codex/log-guard/protection.ts +489 -0
  204. package/src/codex/log-guard/sqlite-errors.ts +9 -0
  205. package/src/codex/main-account-cache.ts +24 -0
  206. package/src/codex/main-account.ts +29 -1
  207. package/src/codex/management-convergence.ts +167 -0
  208. package/src/codex/model-cache.ts +56 -10
  209. package/src/codex/model-entitlements.ts +353 -0
  210. package/src/codex/native-main-admission.ts +47 -0
  211. package/src/codex/native-main-auth-temp.ts +187 -0
  212. package/src/codex/native-main-claim.ts +178 -0
  213. package/src/codex/native-main-lock-file.ts +162 -0
  214. package/src/codex/native-main-owner.ts +329 -0
  215. package/src/codex/native-profile-api.ts +247 -0
  216. package/src/codex/native-profile-manager.ts +1531 -0
  217. package/src/codex/native-profile-processes.ts +121 -0
  218. package/src/codex/native-profile-recovery.ts +99 -0
  219. package/src/codex/native-profile-stage-store.ts +387 -0
  220. package/src/codex/native-profile-startup.ts +492 -0
  221. package/src/codex/native-profile-store.ts +855 -0
  222. package/src/codex/native-profile-types.ts +120 -0
  223. package/src/codex/native-residue.ts +682 -0
  224. package/src/codex/paths.ts +80 -1
  225. package/src/codex/plan-from-token.ts +140 -0
  226. package/src/codex/plan.ts +40 -0
  227. package/src/codex/plugins-doctor.ts +1 -1
  228. package/src/codex/pool-rotation.ts +74 -4
  229. package/src/codex/project-config-warnings.ts +20 -6
  230. package/src/codex/prompt-journal.ts +352 -0
  231. package/src/codex/prompt-layers.ts +967 -0
  232. package/src/codex/prompt-lock.ts +143 -0
  233. package/src/codex/quota-rejection.ts +298 -0
  234. package/src/codex/quota.ts +175 -13
  235. package/src/codex/refresh.ts +11 -2
  236. package/src/codex/reset-credit-recovery.ts +1044 -0
  237. package/src/codex/routing.ts +505 -94
  238. package/src/codex/runtime.ts +159 -38
  239. package/src/codex/shim.ts +1009 -28
  240. package/src/codex/subagent-model-fallback.ts +350 -35
  241. package/src/codex/sync.ts +191 -2
  242. package/src/codex/transition-state.ts +612 -0
  243. package/src/codex/upstream-host-health.ts +368 -0
  244. package/src/codex/user-identity.ts +557 -0
  245. package/src/codex/warmup.ts +187 -81
  246. package/src/codex/write-coordination.ts +114 -0
  247. package/src/combos/failover.ts +20 -0
  248. package/src/combos/index.ts +4 -0
  249. package/src/combos/request.ts +32 -0
  250. package/src/combos/types.ts +81 -9
  251. package/src/config/provider-name.ts +24 -0
  252. package/src/config.ts +1762 -140
  253. package/src/generated/compatibility-version.json +3164 -0
  254. package/src/generated/{jawcode-model-metadata.ts → model-metadata.ts} +19 -17
  255. package/src/grok/inject.ts +16 -5
  256. package/src/grok/inspect.ts +45 -0
  257. package/src/grok/sync.ts +2 -2
  258. package/src/images/loop.ts +152 -29
  259. package/src/images/plan.ts +23 -13
  260. package/src/integrations/config-io.ts +269 -0
  261. package/src/integrations/journal.ts +315 -0
  262. package/src/integrations/merge.ts +135 -0
  263. package/src/integrations/mutation-flight.ts +71 -0
  264. package/src/integrations/native/ownership-preflight.ts +202 -0
  265. package/src/integrations/omp-yaml-source.ts +358 -0
  266. package/src/integrations/owned-refresh.ts +74 -0
  267. package/src/integrations/ownership.ts +111 -0
  268. package/src/integrations/registry.ts +159 -0
  269. package/src/integrations/serialize.ts +314 -0
  270. package/src/integrations/state.ts +361 -0
  271. package/src/integrations/store.ts +103 -0
  272. package/src/integrations/writer-lock.ts +98 -0
  273. package/src/integrations/writer.ts +691 -0
  274. package/src/lab/artifacts/sanitize.ts +586 -0
  275. package/src/lab/artifacts/secure-fs.ts +475 -0
  276. package/src/lab/artifacts/store.ts +310 -0
  277. package/src/lab/automation/budgets.ts +78 -0
  278. package/src/lab/automation/config-persistence.ts +256 -0
  279. package/src/lab/automation/constants.ts +39 -0
  280. package/src/lab/automation/cooldown.ts +103 -0
  281. package/src/lab/automation/dispatch.ts +211 -0
  282. package/src/lab/automation/index.ts +13 -0
  283. package/src/lab/automation/orchestrator.ts +499 -0
  284. package/src/lab/automation/persistence.ts +512 -0
  285. package/src/lab/automation/planner.ts +371 -0
  286. package/src/lab/automation/policy.ts +136 -0
  287. package/src/lab/automation/queue.ts +191 -0
  288. package/src/lab/automation/recovery.ts +24 -0
  289. package/src/lab/automation/route-context.ts +21 -0
  290. package/src/lab/automation/run-key.ts +44 -0
  291. package/src/lab/automation/runs-query.ts +34 -0
  292. package/src/lab/automation/types.ts +160 -0
  293. package/src/lab/conformance/assertion.ts +325 -0
  294. package/src/lab/conformance/digest.ts +22 -0
  295. package/src/lab/conformance/executor.ts +741 -0
  296. package/src/lab/conformance/fixture-provider.ts +27 -0
  297. package/src/lab/conformance/fixtures/live-v1-cases.json +175 -0
  298. package/src/lab/conformance/fixtures/protocol-v1-cases.json +461 -0
  299. package/src/lab/conformance/harness-budget.ts +47 -0
  300. package/src/lab/conformance/index.ts +5 -0
  301. package/src/lab/conformance/jcs.ts +64 -0
  302. package/src/lab/conformance/json-pointer.ts +39 -0
  303. package/src/lab/conformance/manifest.ts +180 -0
  304. package/src/lab/conformance/mcp-stub.ts +179 -0
  305. package/src/lab/conformance/negative-controls.ts +164 -0
  306. package/src/lab/conformance/observation.ts +355 -0
  307. package/src/lab/conformance/runner.ts +68 -0
  308. package/src/lab/conformance/sse-normalize.ts +59 -0
  309. package/src/lab/conformance/suite-manifest.ts +78 -0
  310. package/src/lab/conformance/types.ts +214 -0
  311. package/src/lab/constants.ts +126 -0
  312. package/src/lab/digest.ts +64 -0
  313. package/src/lab/events/errors.ts +9 -0
  314. package/src/lab/events/limits.ts +117 -0
  315. package/src/lab/events/types.ts +229 -0
  316. package/src/lab/events/validate.ts +781 -0
  317. package/src/lab/fabric/constants.ts +40 -0
  318. package/src/lab/fabric/executor.ts +492 -0
  319. package/src/lab/fabric/index.ts +80 -0
  320. package/src/lab/fabric/manifest.ts +222 -0
  321. package/src/lab/fabric/observe.ts +489 -0
  322. package/src/lab/fabric/patch.ts +79 -0
  323. package/src/lab/fabric/producer-child.ts +139 -0
  324. package/src/lab/fabric/producer-isolate.ts +276 -0
  325. package/src/lab/fabric/producer-protocol.ts +61 -0
  326. package/src/lab/fabric/scratch.ts +439 -0
  327. package/src/lab/fabric/subject.ts +106 -0
  328. package/src/lab/fabric/types.ts +134 -0
  329. package/src/lab/fabric/verifier.ts +98 -0
  330. package/src/lab/index.ts +54 -0
  331. package/src/lab/ledger/artifact-refs.ts +127 -0
  332. package/src/lab/ledger/invalidation.ts +136 -0
  333. package/src/lab/ledger/purge.ts +310 -0
  334. package/src/lab/ledger/store.ts +532 -0
  335. package/src/lab/live/credential-lease.ts +53 -0
  336. package/src/lab/live/destination.ts +155 -0
  337. package/src/lab/live/executor.ts +336 -0
  338. package/src/lab/live/inert-tools.ts +56 -0
  339. package/src/lab/live/manifest.ts +85 -0
  340. package/src/lab/live/mcp-loopback.ts +57 -0
  341. package/src/lab/live/runner.ts +19 -0
  342. package/src/lab/live/sandbox.ts +61 -0
  343. package/src/lab/live/suite-manifest.ts +41 -0
  344. package/src/lab/live/transport.ts +118 -0
  345. package/src/lab/live/types.ts +197 -0
  346. package/src/lab/observe/from-conformance.ts +301 -0
  347. package/src/lab/observe/from-live.ts +117 -0
  348. package/src/lab/paths.ts +153 -0
  349. package/src/lab/projection/rebuild.ts +495 -0
  350. package/src/lab/projection/schema.ts +135 -0
  351. package/src/lab/projection/verdicts.ts +474 -0
  352. package/src/lab/projection/verification.ts +412 -0
  353. package/src/lab/public/bundle.ts +217 -0
  354. package/src/lab/public/community-authority.ts +175 -0
  355. package/src/lab/public/community-files.ts +29 -0
  356. package/src/lab/public/community.ts +479 -0
  357. package/src/lab/public/file-safety.ts +155 -0
  358. package/src/lab/public/ids.ts +26 -0
  359. package/src/lab/public/index.ts +16 -0
  360. package/src/lab/public/mutation-lock.ts +424 -0
  361. package/src/lab/public/operator.ts +353 -0
  362. package/src/lab/public/origin-purge.ts +79 -0
  363. package/src/lab/public/origin.ts +203 -0
  364. package/src/lab/public/privacy.ts +143 -0
  365. package/src/lab/public/private-file.ts +261 -0
  366. package/src/lab/public/project.ts +124 -0
  367. package/src/lab/public/purge-test-fault.ts +21 -0
  368. package/src/lab/public/purge.ts +223 -0
  369. package/src/lab/public/registry.ts +44 -0
  370. package/src/lab/public/revocation.ts +252 -0
  371. package/src/lab/public/signature.ts +243 -0
  372. package/src/lab/public/storage.ts +105 -0
  373. package/src/lab/public/strict-json.ts +206 -0
  374. package/src/lab/public/time.ts +26 -0
  375. package/src/lab/public/types.ts +172 -0
  376. package/src/lab/public/validate.ts +391 -0
  377. package/src/lab/query/catalog.ts +101 -0
  378. package/src/lab/query/connection.ts +107 -0
  379. package/src/lab/query/constants.ts +4 -0
  380. package/src/lab/query/cursor.ts +132 -0
  381. package/src/lab/query/dto-map.ts +277 -0
  382. package/src/lab/query/errors.ts +22 -0
  383. package/src/lab/query/freshness.ts +53 -0
  384. package/src/lab/query/index.ts +45 -0
  385. package/src/lab/query/latest-observation.ts +59 -0
  386. package/src/lab/query/passive-production.ts +159 -0
  387. package/src/lab/query/queries.ts +444 -0
  388. package/src/lab/query/types.ts +266 -0
  389. package/src/lab/subject/behavior-fingerprint.ts +77 -0
  390. package/src/lab/subject/installation-salt.ts +112 -0
  391. package/src/lab/subject/protocol-subject.ts +80 -0
  392. package/src/lab/subject/route-subject.ts +74 -0
  393. package/src/lib/app-owned-memory-stores.ts +22 -0
  394. package/src/lib/bounded-body.ts +153 -9
  395. package/src/lib/bun-runtime.ts +125 -12
  396. package/src/lib/bun-stream-caps.ts +13 -9
  397. package/src/lib/codex-restart-contract.ts +120 -0
  398. package/src/lib/config-ownership.ts +6 -2
  399. package/src/lib/destination-policy.ts +65 -1
  400. package/src/lib/errors.ts +44 -2
  401. package/src/lib/fabric-task-execution-authority.ts +7 -0
  402. package/src/lib/fabric-task-host.ts +29 -0
  403. package/src/lib/lab-activation.ts +223 -0
  404. package/src/lib/lab-live-execution-authority.ts +13 -0
  405. package/src/lib/lab-live-host.ts +30 -0
  406. package/src/lib/lab-live-pinned-sender.ts +56 -0
  407. package/src/lib/lab-live-route-production.ts +130 -0
  408. package/src/lib/lab-passive-linker-registration.ts +26 -0
  409. package/src/lib/local-management-attestation.ts +51 -0
  410. package/src/lib/local-management-capability.ts +100 -0
  411. package/src/lib/local-provider-reload-contract.ts +100 -0
  412. package/src/lib/optional-shutdown-hooks.ts +57 -0
  413. package/src/lib/pinned-http.ts +145 -26
  414. package/src/lib/process-control.ts +4 -1
  415. package/src/lib/provider-outbound.ts +49 -9
  416. package/src/lib/redact.ts +419 -3
  417. package/src/lib/self-launch-argv.ts +15 -0
  418. package/src/lib/server-resource-ownership.ts +71 -0
  419. package/src/lib/shadow-call.ts +35 -4
  420. package/src/lib/sse-decoder.ts +41 -0
  421. package/src/lib/state-store-registrations.ts +10 -2
  422. package/src/lib/system-restart-contract.ts +73 -0
  423. package/src/lib/token-estimate.ts +19 -2
  424. package/src/lib/tool-argument-integers.ts +202 -0
  425. package/src/lib/translator-budget.ts +44 -0
  426. package/src/lib/upstream-http-version.ts +57 -0
  427. package/src/lib/upstream-reachability.ts +95 -0
  428. package/src/lib/upstream-retry.ts +156 -3
  429. package/src/lib/windows-atomic-replace.ts +155 -0
  430. package/src/lib/windows-elevation.ts +70 -2
  431. package/src/lib/windows-secret-acl.ts +409 -69
  432. package/src/lib/windows-service-wrappers.ts +72 -0
  433. package/src/lib/windows-text.ts +106 -0
  434. package/src/lib/windows-user-principal.ts +341 -0
  435. package/src/lib/winsw.ts +33 -5
  436. package/src/oauth/account-import/google-antigravity-adapter.ts +74 -0
  437. package/src/oauth/account-import/index.ts +15 -0
  438. package/src/oauth/account-import/parser.ts +83 -0
  439. package/src/oauth/account-import/registry.ts +18 -0
  440. package/src/oauth/account-import/service.ts +75 -0
  441. package/src/oauth/account-import/types.ts +91 -0
  442. package/src/oauth/anthropic.ts +12 -1
  443. package/src/oauth/callback-server.ts +8 -2
  444. package/src/oauth/chatgpt.ts +12 -1
  445. package/src/oauth/command-code.ts +239 -0
  446. package/src/oauth/cursor.ts +46 -5
  447. package/src/oauth/google-antigravity.ts +35 -3
  448. package/src/oauth/health.ts +20 -12
  449. package/src/oauth/index.ts +398 -66
  450. package/src/oauth/key-providers.ts +16 -0
  451. package/src/oauth/kimi.ts +16 -2
  452. package/src/oauth/kiro.ts +50 -6
  453. package/src/oauth/local-token-detect.ts +11 -2
  454. package/src/oauth/log.ts +3 -1
  455. package/src/oauth/login-cli.ts +88 -28
  456. package/src/oauth/nous.ts +798 -0
  457. package/src/oauth/store.ts +119 -21
  458. package/src/oauth/token-guardian.ts +9 -3
  459. package/src/pi/models.ts +2 -2
  460. package/src/providers/alibaba-region-migration.ts +1 -1
  461. package/src/providers/antigravity-models.ts +521 -31
  462. package/src/providers/base-url-choices.ts +10 -0
  463. package/src/providers/codex-capacity.ts +292 -0
  464. package/src/providers/command-code-efforts.ts +144 -0
  465. package/src/providers/context-cap.ts +22 -5
  466. package/src/providers/cursor-pool.ts +72 -0
  467. package/src/providers/derive.ts +253 -6
  468. package/src/providers/fastwire.ts +501 -0
  469. package/src/providers/free-directory.ts +10 -7
  470. package/src/providers/google-vertex-location.ts +14 -0
  471. package/src/providers/key-failover.ts +71 -3
  472. package/src/providers/label.ts +1 -1
  473. package/src/providers/model-discovery-limits.ts +16 -0
  474. package/src/providers/model-discovery.ts +115 -22
  475. package/src/providers/model-rename-migration.ts +255 -0
  476. package/src/providers/model-rename-startup.ts +28 -0
  477. package/src/providers/openai-sidecar.ts +72 -4
  478. package/src/providers/openai-tier-startup.ts +31 -2
  479. package/src/providers/openai-tiers.ts +119 -4
  480. package/src/providers/openai-virtual-models.ts +1 -0
  481. package/src/providers/opencode-zen-rate-limit.ts +102 -0
  482. package/src/providers/provider-id-rewrite.ts +29 -0
  483. package/src/providers/quota.ts +1319 -38
  484. package/src/providers/registry.ts +1429 -111
  485. package/src/providers/request-pacing.ts +310 -0
  486. package/src/providers/service-tier.ts +277 -0
  487. package/src/providers/slug-codec.ts +42 -6
  488. package/src/providers/static-model-discovery.ts +86 -0
  489. package/src/providers/xai-responses-opt-in.ts +15 -0
  490. package/src/providers/xai-transport.ts +11 -4
  491. package/src/reasoning-effort.ts +49 -1
  492. package/src/responses/compaction.ts +26 -1
  493. package/src/responses/custom-tool-compat.ts +266 -0
  494. package/src/responses/hosted-tool-policy.ts +9 -0
  495. package/src/responses/namespace-tool-compat.ts +355 -0
  496. package/src/responses/parser.ts +220 -38
  497. package/src/responses/provider-continuation.ts +98 -0
  498. package/src/responses/provider-opaque-metadata.ts +73 -0
  499. package/src/responses/reasoning-envelope.ts +9 -1
  500. package/src/responses/reasoning-replay-cache.ts +426 -0
  501. package/src/responses/schema.ts +7 -1
  502. package/src/responses/spill-store.ts +75 -10
  503. package/src/responses/state.ts +565 -27
  504. package/src/responses/thought-signature-replay.ts +347 -0
  505. package/src/responses/tool-search-compat.ts +301 -0
  506. package/src/responses/truncated-stop-reason.ts +60 -0
  507. package/src/router.ts +366 -30
  508. package/src/routing/analytics.ts +378 -0
  509. package/src/routing/capability.ts +244 -0
  510. package/src/routing/compatibility/assemble.ts +73 -0
  511. package/src/routing/compatibility/behavior.ts +278 -0
  512. package/src/routing/compatibility/catalog.ts +99 -0
  513. package/src/routing/compatibility/endpoint.ts +52 -0
  514. package/src/routing/compatibility/lab-evidence-provider.ts +130 -0
  515. package/src/routing/compatibility/policy.ts +181 -0
  516. package/src/routing/compatibility/provider-slot.ts +56 -0
  517. package/src/routing/compatibility/reader.ts +110 -0
  518. package/src/routing/compatibility/subject.ts +191 -0
  519. package/src/routing/compatibility/types.ts +64 -0
  520. package/src/routing/compatibility/version.ts +104 -0
  521. package/src/routing/cost.ts +77 -0
  522. package/src/routing/evaluator.ts +495 -0
  523. package/src/routing/health.ts +412 -0
  524. package/src/routing/history/cursor.ts +43 -0
  525. package/src/routing/history/indexer.ts +605 -0
  526. package/src/routing/history/schema.ts +72 -0
  527. package/src/routing/profile-namespace.ts +15 -0
  528. package/src/routing/profile.ts +547 -0
  529. package/src/routing/quota.ts +145 -0
  530. package/src/routing/request-evidence.ts +45 -0
  531. package/src/routing/trace.ts +776 -0
  532. package/src/server/adapter-resolve.ts +2 -29
  533. package/src/server/auth-cors.ts +267 -46
  534. package/src/server/background-lifecycle.ts +182 -0
  535. package/src/server/chat-completions.ts +130 -56
  536. package/src/server/chat-native-sse.ts +331 -0
  537. package/src/server/chat-native.ts +426 -0
  538. package/src/server/claude-messages.ts +159 -43
  539. package/src/server/direct-local-http.ts +347 -0
  540. package/src/server/effort-policy.ts +18 -0
  541. package/src/server/github-copilot-responses-repair.ts +338 -0
  542. package/src/server/gui-static.ts +39 -10
  543. package/src/server/images.ts +94 -12
  544. package/src/server/index.ts +865 -181
  545. package/src/server/lifecycle.ts +284 -13
  546. package/src/server/live.ts +136 -17
  547. package/src/server/local-management-read-client.ts +90 -0
  548. package/src/server/local-provider-reload-client.ts +137 -0
  549. package/src/server/management/agent-settings-routes.ts +398 -103
  550. package/src/server/management/api-key-usage.ts +31 -5
  551. package/src/server/management/body.ts +6 -0
  552. package/src/server/management/combo-routes.ts +62 -24
  553. package/src/server/management/config-routes.ts +464 -51
  554. package/src/server/management/context.ts +80 -2
  555. package/src/server/management/integration-routes.ts +498 -0
  556. package/src/server/management/lab-automation-routes.ts +206 -0
  557. package/src/server/management/lab-routes.ts +563 -0
  558. package/src/server/management/logs-usage-routes.ts +101 -32
  559. package/src/server/management/model-routes.ts +189 -131
  560. package/src/server/management/model-rows.ts +163 -0
  561. package/src/server/management/native-integration-routes.ts +769 -0
  562. package/src/server/management/oauth-account-routes.ts +80 -4
  563. package/src/server/management/provider-capability-config.ts +48 -0
  564. package/src/server/management/provider-routes.ts +764 -157
  565. package/src/server/management/request-history-routes.ts +191 -0
  566. package/src/server/management/routing-analytics-routes.ts +74 -0
  567. package/src/server/management/routing-profile-routes.ts +380 -0
  568. package/src/server/management/shared.ts +27 -11
  569. package/src/server/management/sidebar-routes.ts +47 -31
  570. package/src/server/management/storage-log-guard-routes.ts +186 -0
  571. package/src/server/management/sync-response.ts +69 -0
  572. package/src/server/management/system-restart.ts +288 -32
  573. package/src/server/management/system-routes.ts +77 -0
  574. package/src/server/management/usage-summary-cache.ts +9 -1
  575. package/src/server/management/vision-sidecar-options.ts +167 -0
  576. package/src/server/management/web-search-sidecar-options.ts +120 -0
  577. package/src/server/management-api.ts +115 -14
  578. package/src/server/management-auth.ts +220 -5
  579. package/src/server/passive-route-linker.ts +66 -0
  580. package/src/server/ports.ts +41 -1
  581. package/src/server/proxy-liveness.ts +132 -5
  582. package/src/server/readiness.ts +99 -0
  583. package/src/server/relay-eager.ts +82 -42
  584. package/src/server/relay.ts +236 -76
  585. package/src/server/request-decompress.ts +113 -6
  586. package/src/server/request-log.ts +235 -22
  587. package/src/server/responses/agent-task-recovery-cache.ts +143 -0
  588. package/src/server/responses/agent-task-recovery.ts +465 -0
  589. package/src/server/responses/collaboration.ts +204 -35
  590. package/src/server/responses/compact.ts +442 -55
  591. package/src/server/responses/core.ts +2872 -331
  592. package/src/server/responses/empty-completion-guard.ts +276 -0
  593. package/src/server/responses/encrypted-payload.ts +62 -39
  594. package/src/server/responses/fetch-helpers.ts +79 -4
  595. package/src/server/responses/input-admission.ts +185 -0
  596. package/src/server/responses/pacing-overload.ts +13 -0
  597. package/src/server/responses/policy-fallback.ts +178 -0
  598. package/src/server/responses/responses-field-backfill.ts +251 -0
  599. package/src/server/responses/terminal-guard.ts +26 -5
  600. package/src/server/responses/upstream-error.ts +5 -0
  601. package/src/server/responses/ws-upstream.ts +308 -0
  602. package/src/server/responses-custom-tool-repair.ts +282 -0
  603. package/src/server/responses-item-id-repair.ts +54 -6
  604. package/src/server/responses-json-events.ts +90 -0
  605. package/src/server/responses-model-rewrite.ts +29 -0
  606. package/src/server/responses-reasoning-summary-rewrite.ts +178 -0
  607. package/src/server/responses-snapshot-repair.ts +621 -0
  608. package/src/server/responses-terminal-repair.ts +342 -0
  609. package/src/server/responses-tool-search-repair.ts +267 -0
  610. package/src/server/responses-undeclared-tool-guard.ts +153 -0
  611. package/src/server/responses.ts +18 -2
  612. package/src/server/search.ts +78 -13
  613. package/src/server/sse-frame-buffer.ts +292 -0
  614. package/src/server/sse-payload-rewrite.ts +110 -22
  615. package/src/server/startup-action-control.ts +8 -1
  616. package/src/server/startup-health-cache.ts +19 -1
  617. package/src/server/system-env.ts +80 -9
  618. package/src/server/ws-bridge.ts +39 -38
  619. package/src/service-manager-probe.ts +892 -0
  620. package/src/service.ts +1111 -90
  621. package/src/sidecar/auth.ts +92 -0
  622. package/src/sidecar/candidates.ts +83 -0
  623. package/src/storage/cleanup.ts +2 -2
  624. package/src/storage/scanner.ts +1 -1
  625. package/src/storage/worker-lifecycle.ts +14 -14
  626. package/src/tray/windows-tray.ps1 +83 -9
  627. package/src/tray/windows.ts +43 -16
  628. package/src/types/accounts.ts +37 -0
  629. package/src/types/config.ts +845 -0
  630. package/src/types/provider.ts +545 -0
  631. package/src/types/request.ts +384 -0
  632. package/src/types/tools.ts +131 -0
  633. package/src/types/wire.ts +80 -0
  634. package/src/types.ts +104 -1236
  635. package/src/update/index.ts +32 -19
  636. package/src/update/job.ts +442 -67
  637. package/src/update/notify.ts +12 -6
  638. package/src/update/npm-cache-preflight.d.mts +47 -0
  639. package/src/update/npm-cache-preflight.mjs +201 -0
  640. package/src/update/transactional-install.d.mts +22 -0
  641. package/src/update/transactional-install.mjs +259 -0
  642. package/src/usage/cost.ts +0 -0
  643. package/src/usage/expected-prices.ts +268 -16
  644. package/src/usage/log.ts +606 -41
  645. package/src/usage/summary.ts +177 -9
  646. package/src/usage/user-cost-overlay-reconciler.ts +313 -0
  647. package/src/usage/user-cost-overlays.ts +314 -0
  648. package/src/vision/anthropic-describe.ts +10 -6
  649. package/src/vision/backends.ts +97 -0
  650. package/src/vision/describe.ts +9 -3
  651. package/src/vision/eligibility.ts +250 -0
  652. package/src/vision/index.ts +238 -24
  653. package/src/vision/reasoning.ts +55 -0
  654. package/src/vision/routed-describe.ts +175 -0
  655. package/src/vision/timeout-bounds.ts +9 -0
  656. package/src/web-search/anthropic-executor.ts +13 -7
  657. package/src/web-search/backends.ts +108 -0
  658. package/src/web-search/exa-executor.ts +88 -0
  659. package/src/web-search/executor.ts +11 -3
  660. package/src/web-search/gemini-executor.ts +141 -0
  661. package/src/web-search/index.ts +150 -15
  662. package/src/web-search/loop.ts +279 -50
  663. package/src/web-search/parse.ts +125 -30
  664. package/src/web-search/sources.ts +60 -0
  665. package/src/web-search/xai-executor.ts +219 -0
  666. package/gui/dist/assets/index-DTpMHS4F.js +0 -67
  667. package/gui/dist/assets/index-ZNVDE3C7.css +0 -1
  668. package/gui/dist/provider-icons/antigravity.svg +0 -1
  669. package/gui/dist/provider-icons/claude.svg +0 -1
  670. package/gui/dist/provider-icons/copilot.svg +0 -1
  671. package/gui/dist/provider-icons/cursor.svg +0 -2
  672. package/gui/dist/provider-icons/gemini.svg +0 -1
  673. package/gui/dist/provider-icons/grok-color.svg +0 -1
  674. package/gui/dist/provider-icons/kiro.svg +0 -14
  675. package/src/cli/internal-dispatch.ts +0 -20
@@ -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
 
@@ -1,12 +1,14 @@
1
1
  import { execFileSync } from "node:child_process";
2
- import { readFileSync, writeFileSync, unlinkSync, mkdirSync } from "node:fs";
3
- import { join } from "node:path";
2
+ import { accessSync, constants, readFileSync, writeFileSync, unlinkSync, mkdirSync, statSync } from "node:fs";
3
+ import { delimiter, join } from "node:path";
4
4
  import { getConfigDir } from "../config";
5
5
  import { resolveAutoContext, type AutoContextMode } from "../claude/context-windows";
6
6
  import { PROXY_MARKER, defaultAuthDetectDeps, detectClaudeAuth, ownAdmissionTokens } from "../claude/auth-detect";
7
7
  import { resolveClaudeAuthMode } from "../claude/auth-mode";
8
8
  import type { OcxConfig } from "../types";
9
9
  import { recordOwnedConfigPath } from "../lib/config-ownership";
10
+ import { providerContextCap } from "../providers/context-cap";
11
+ import { OPENAI_CODEX_PROVIDER_ID } from "../providers/openai-tiers";
10
12
 
11
13
  /**
12
14
  * Does the opencodex dummy marker belong in the system environment?
@@ -116,15 +118,84 @@ export function uninstallShellHook(): { removed: boolean; reason?: string } {
116
118
  try {
117
119
  const content = readFileSync(zshrcPath, "utf8");
118
120
  if (!content.includes(SHELL_HOOK_MARKER)) return { removed: false, reason: "not installed" };
119
- // Remove the hook block (marker line + source line + surrounding newlines)
120
- const cleaned = content.replace(/\n?# opencodex claude-env hook\n\[.*claude-env\.sh.*\n?/g, "\n");
121
+ // Match CR?LF, not LF alone. A .zshrc with CRLF line endings ordinary on a home
122
+ // directory an editor or another OS has touched — did not match, so the file was
123
+ // rewritten unchanged and the caller was told the hook was removed. Reporting success
124
+ // while the hook still sources on every new shell is the worse of the two failures.
125
+ const cleaned = content.replace(/\r?\n?# opencodex claude-env hook\r?\n\[.*claude-env\.sh.*(?:\r?\n)?/g, "\n");
126
+ // Verify instead of assuming: if the marker survives, the block is shaped in a way this
127
+ // pattern does not own, and the honest answer is failure rather than a silent no-op.
128
+ if (cleaned.includes(SHELL_HOOK_MARKER)) {
129
+ return { removed: false, reason: "hook block present but not in the expected shape; remove it manually" };
130
+ }
121
131
  writeFileSync(zshrcPath, cleaned, { encoding: "utf8", mode: 0o644 });
122
132
  return { removed: true };
123
- } catch {
133
+ } catch (error) {
134
+ if (error && typeof error === "object" && (error as { code?: unknown }).code === "ENOENT") {
135
+ return { removed: false, reason: "not installed" };
136
+ }
124
137
  return { removed: false, reason: "read/write failed" };
125
138
  }
126
139
  }
127
140
 
141
+ /** Whether a real `claude` executable is discoverable from this process's PATH. */
142
+ export function claudeCodeCliInstalled(pathValue = process.env.PATH): boolean {
143
+ if (!pathValue) return false;
144
+ for (const directory of pathValue.split(delimiter)) {
145
+ // An empty PATH segment means the current directory. Do not let the proxy treat a
146
+ // workspace-local file as a durable user installation.
147
+ if (!directory) continue;
148
+ const candidate = join(directory, "claude");
149
+ try {
150
+ if (!statSync(candidate).isFile()) continue;
151
+ accessSync(candidate, constants.X_OK);
152
+ return true;
153
+ } catch {
154
+ // Keep scanning PATH after missing, non-file, and non-executable entries.
155
+ }
156
+ }
157
+ return false;
158
+ }
159
+
160
+ /**
161
+ * Keep the shell hook aligned with the integration that can actually consume it.
162
+ * Claude Desktop uses its own profile and does not source `.zshrc`; this hook exists
163
+ * only for plain Claude Code CLI launches.
164
+ *
165
+ * Reconciliation is PATH-sensitive by construction: "Claude Code is installed" is answered
166
+ * from the PATH of whichever process calls this. A launchd/service context with a stripped
167
+ * PATH can therefore fail to see a `claude` the user's interactive shell finds, and this will
168
+ * remove the hook. That is the intended failure direction — removing an OpenCodex-owned block
169
+ * is reversible on the next foreground `ocx start`, whereas leaving a hook pointing at an
170
+ * uninstalled CLI is the stale state this reconciliation exists to clear. Only the block
171
+ * carrying our own marker is ever touched; user lines are preserved.
172
+ */
173
+ export function reconcileShellHook(systemEnvInjected: boolean): {
174
+ changed: boolean;
175
+ state: "installed" | "absent" | "failed";
176
+ reason?: string;
177
+ } {
178
+ if (process.platform !== "darwin") return { changed: false, state: "absent", reason: "not macOS" };
179
+ if (systemEnvInjected && claudeCodeCliInstalled()) {
180
+ const result = installShellHook();
181
+ if (result.installed) return { changed: true, state: "installed" };
182
+ if (result.reason === "already installed") {
183
+ return { changed: false, state: "installed", reason: result.reason };
184
+ }
185
+ return { changed: false, state: "failed", reason: result.reason ?? "install failed" };
186
+ }
187
+
188
+ const result = uninstallShellHook();
189
+ if (!result.removed && result.reason !== "not installed") {
190
+ return { changed: false, state: "failed", reason: result.reason ?? "remove failed" };
191
+ }
192
+ return {
193
+ changed: result.removed,
194
+ state: "absent",
195
+ reason: systemEnvInjected ? "Claude Code not installed" : "system environment inactive",
196
+ };
197
+ }
198
+
128
199
  const SYSTEM_ENV_NAMES = [
129
200
  "ANTHROPIC_BASE_URL",
130
201
  "CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY",
@@ -235,12 +306,12 @@ function rollbackInjectedKeys(port: number, injectedKeys: string[]): void {
235
306
  async function computeEffectiveModelEnv(config: OcxConfig, auto?: AutoContextMode): Promise<{ modelEnv: Record<string, string>; windows: Record<string, number> }> {
236
307
  const { boundedContextWindows, buildClaudeContextWindows, effectiveModelEnv } = await import("../claude/context-windows");
237
308
  const windows = await boundedContextWindows(async () => {
238
- const { gatherRoutedModels, visibleNativeSlugs } = await import("../codex/catalog");
309
+ const { gatherRoutedModels, nativeContextLimits, visibleNativeSlugs } = await import("../codex/catalog");
239
310
  try {
240
- return buildClaudeContextWindows([...visibleNativeSlugs(config)], await gatherRoutedModels(config));
311
+ return buildClaudeContextWindows([...visibleNativeSlugs(config)], await gatherRoutedModels(config), nativeContextLimits(config));
241
312
  } catch (error) {
242
313
  if (error && typeof error === "object" && (error as { code?: unknown }).code === "catalog_busy") {
243
- return buildClaudeContextWindows([...visibleNativeSlugs(config)], []);
314
+ return buildClaudeContextWindows([...visibleNativeSlugs(config)], [], nativeContextLimits(config));
244
315
  }
245
316
  throw error;
246
317
  }
@@ -335,7 +406,7 @@ export async function injectSystemEnv(port: number, config: OcxConfig): Promise<
335
406
  // without a token — keep it in sync with this proxy's /v1/models. Best-effort.
336
407
  try {
337
408
  const { refreshGatewayModelCacheFromProxy } = await import("../claude/gateway-cache");
338
- await refreshGatewayModelCacheFromProxy(port);
409
+ await refreshGatewayModelCacheFromProxy(port, { admissionConfig: config });
339
410
  } catch { /* best-effort */ }
340
411
 
341
412
  // Roster agent definitions (devlog 070): same launch-time sync for plain `claude`.
@@ -1,10 +1,12 @@
1
1
  import type { ServerWebSocket } from "bun";
2
+ import { responsesJsonEventSequence } from "./responses-json-events";
2
3
  import { FORWARD_HEADERS } from "../adapters/openai-responses";
3
4
  import type { CodexAuthContext } from "../codex/auth-context";
4
5
  import { headersForCodexAuthContext } from "../codex/auth-context";
5
6
  import type { ResponsesTerminalStatus } from "../bridge";
6
7
  import type { DataPlaneAdmission } from "./auth-cors";
7
- import type { AdmissionReservation } from "../lib/admission";
8
+ import type { AdmissionLease, AdmissionReservation } from "../lib/admission";
9
+ import { BoundedSseFrameBuffer } from "./sse-frame-buffer";
8
10
 
9
11
  const OPEN = 1;
10
12
  type ResponsesTerminalReporter = (status: ResponsesTerminalStatus) => void;
@@ -38,7 +40,15 @@ export interface WsData {
38
40
  liveUpstreamUrl?: string;
39
41
  liveUpstreamHeaders?: Record<string, string>;
40
42
  livePending?: Array<string | Buffer>;
43
+ /** Total encoded bytes retained in livePending while the upstream connects. */
44
+ livePendingBytes?: number;
41
45
  liveOpened?: boolean;
46
+ /** Once teardown starts, ignore new client frames until the upstream closes. */
47
+ liveClosing?: boolean;
48
+ /** Schedules one bounded close retry without surrendering native-main ownership. */
49
+ liveCloseFallback?: ReturnType<typeof setTimeout>;
50
+ /** Turn/account ownership retained for the complete sideband socket lifetime. */
51
+ liveTurnAdmissionLease?: AdmissionLease;
42
52
  admissionLease?: AdmissionReservation<ServerWebSocket<WsData>>;
43
53
  }
44
54
 
@@ -156,15 +166,6 @@ function parseSseBlock(block: string): string | null {
156
166
  return data.length > 0 ? data.join("\n") : null;
157
167
  }
158
168
 
159
- function nextSseBlock(buffer: string): { block: string; rest: string } | null {
160
- const match = buffer.match(/\r?\n\r?\n/);
161
- if (!match || match.index === undefined) return null;
162
- return {
163
- block: buffer.slice(0, match.index),
164
- rest: buffer.slice(match.index + match[0].length),
165
- };
166
- }
167
-
168
169
  function payloadType(payload: string): string | null {
169
170
  try {
170
171
  const json = JSON.parse(payload) as { type?: unknown };
@@ -224,7 +225,7 @@ export async function pumpResponsesSseToWebSocket(
224
225
  ws.data.cancel = cancel;
225
226
 
226
227
  const decoder = new TextDecoder();
227
- let buffer = "";
228
+ const framer = new BoundedSseFrameBuffer();
228
229
  let terminalSeen = false;
229
230
 
230
231
  const handlePayload = (payload: string): boolean => {
@@ -259,17 +260,14 @@ export async function pumpResponsesSseToWebSocket(
259
260
  while (!terminalSeen) {
260
261
  const { done, value } = await reader.read();
261
262
  if (done) break;
262
- buffer += decoder.decode(value, { stream: true });
263
- let next: { block: string; rest: string } | null;
264
- while ((next = nextSseBlock(buffer))) {
265
- buffer = next.rest;
266
- const payload = parseSseBlock(next.block);
263
+ for (const frame of framer.feed(value)) {
264
+ const payload = parseSseBlock(decoder.decode(frame.block));
267
265
  if (payload && handlePayload(payload)) break;
268
266
  }
269
267
  }
270
- buffer += decoder.decode();
271
- if (!terminalSeen && buffer.trim()) {
272
- const payload = parseSseBlock(buffer);
268
+ const tail = framer.finish();
269
+ if (!terminalSeen && tail.byteLength > 0) {
270
+ const payload = parseSseBlock(decoder.decode(tail));
273
271
  if (payload) handlePayload(payload);
274
272
  }
275
273
  if (!terminalSeen && isCurrent() && !clientCancelled) {
@@ -277,11 +275,27 @@ export async function pumpResponsesSseToWebSocket(
277
275
  sendProtocolError(ws, 502, "Upstream stream ended before response terminal event");
278
276
  }
279
277
  } catch (err) {
280
- if (!terminalSeen && isCurrent() && ws.readyState === OPEN) {
281
- if (!(err instanceof WsSendDroppedError)) reportTerminal("incomplete");
282
- sendProtocolError(ws, 502, err instanceof Error ? err.message : String(err));
278
+ framer.dispose();
279
+ if (err instanceof WsSendDroppedError) throw err;
280
+ if (!terminalSeen
281
+ && isCurrent()
282
+ && ws.readyState === OPEN
283
+ && !(err instanceof WsSendDroppedError)) {
284
+ reportTerminal("incomplete");
285
+ try {
286
+ sendProtocolError(ws, 502, err instanceof Error ? err.message : String(err));
287
+ } catch (sendErr) {
288
+ // If delivery is already dropped, there is no useful error frame left
289
+ // to send. Swallow only that expected transport signal; other failures
290
+ // still surface to the caller after the upstream reader is released.
291
+ if (!(sendErr instanceof WsSendDroppedError)) throw sendErr;
292
+ }
283
293
  }
284
294
  } finally {
295
+ framer.dispose();
296
+ // Framing errors can occur while the upstream body is still live. Always
297
+ // release the reader, even when terminal/send paths already cancelled it.
298
+ void reader.cancel().catch(() => {});
285
299
  if (ws.data.cancel === cancel) ws.data.cancel = undefined;
286
300
  }
287
301
  }
@@ -301,25 +315,12 @@ export function sendResponsesJsonAsEvents(
301
315
  }
302
316
  sendTextFrame(ws, text);
303
317
  };
304
- const output = Array.isArray(response.output) ? response.output : [];
305
- sendObservedFrame({
306
- type: "response.created",
307
- response: { ...response, status: "in_progress", output: [] },
308
- });
309
- output.forEach((item, outputIndex) => {
310
- sendObservedFrame({
311
- type: "response.output_item.done",
312
- output_index: outputIndex,
313
- item,
314
- });
315
- });
316
318
  const finalStatus = response.status === "failed" || response.status === "incomplete"
317
319
  ? response.status
318
320
  : "completed";
319
- sendObservedFrame({
320
- type: `response.${finalStatus}` as "response.completed" | "response.failed" | "response.incomplete",
321
- response: { ...response, status: finalStatus },
322
- });
321
+ for (const frame of responsesJsonEventSequence(response)) {
322
+ sendObservedFrame(frame);
323
+ }
323
324
  onTerminal?.(finalStatus);
324
325
  }
325
326