@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
@@ -7,6 +7,8 @@
7
7
  * them here breaks that cycle. `inject.ts` imports them back and re-exports the
8
8
  * two public predicates, so external callers see no change.
9
9
  */
10
+ import { parseTomlString } from "./paths";
11
+
10
12
  export const OCX_SECTION_MARKER = "# Auto-injected by opencodex";
11
13
 
12
14
  export function isRootOpenaiBaseUrlLine(line: string): boolean {
@@ -16,7 +18,11 @@ export function isRootOpenaiBaseUrlLine(line: string): boolean {
16
18
  export function tomlStringPattern(key: string): RegExp {
17
19
  const escaped = key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
18
20
  const keyToken = `(?:${escaped}|"${escaped}"|'${escaped}')`;
19
- return new RegExp(`^\\s*${keyToken}\\s*=\\s*["']([^"']+)["']\\s*(?:#.*)?$`);
21
+ // The quoted value is captured WITH its quotes so callers can decode it as TOML.
22
+ // A basic string escapes backslashes, so a Windows path is stored doubled; reading
23
+ // the raw bytes back returned a path that matched nothing on disk and made the
24
+ // journal's recorded catalog path un-restorable (#1798).
25
+ return new RegExp(`^\\s*${keyToken}\\s*=\\s*("(?:\\\\.|[^"\\\\])*"|'[^']*')\\s*(?:#.*)?$`);
20
26
  }
21
27
 
22
28
  export function rootTomlString(content: string, key: string): string | null {
@@ -26,7 +32,7 @@ export function rootTomlString(content: string, key: string): string | null {
26
32
  const pattern = tomlStringPattern(key);
27
33
  for (const line of rootLines) {
28
34
  const match = pattern.exec(line);
29
- if (match?.[1]) return match[1].trim();
35
+ if (match?.[1]) return parseTomlString(match[1]).trim();
30
36
  }
31
37
  return null;
32
38
  }
@@ -45,11 +51,39 @@ export function providerTableString(content: string, provider: string, key: stri
45
51
  const pattern = tomlStringPattern(key);
46
52
  for (let index = start + 1; index < lines.length && !/^\s*\[/.test(lines[index]); index += 1) {
47
53
  const match = pattern.exec(lines[index]);
48
- if (match?.[1]) return match[1].trim();
54
+ if (match?.[1]) return parseTomlString(match[1]).trim();
49
55
  }
50
56
  return null;
51
57
  }
52
58
 
59
+ /**
60
+ * Drop a root `openai_base_url` whose VALUE is the one a recorded injection wrote.
61
+ *
62
+ * #1798: the marker-adjacency rule below is formatting evidence, and the Codex app
63
+ * reserializes the file -- values kept, comments dropped. This rule is value evidence
64
+ * instead, so it still recognizes our URL after that rewrite. It is deliberately an
65
+ * EXACT value match against what we recorded writing: a user gateway we never wrote
66
+ * cannot match, so restore can never delete a URL that was not ours.
67
+ */
68
+ export function stripJournaledOpenaiBaseUrl(content: string, injectedUrl: string | null): string {
69
+ if (!injectedUrl) return content;
70
+ const lines = content.split(String.fromCharCode(10));
71
+ const firstTable = lines.findIndex(l => /^\s*\[/.test(l));
72
+ const rootEnd = firstTable === -1 ? lines.length : firstTable;
73
+ const drop = new Set<number>();
74
+ for (let i = 0; i < rootEnd; i++) {
75
+ const line = lines[i]!;
76
+ if (!isRootOpenaiBaseUrlLine(line)) continue;
77
+ if (rootTomlString(line, "openai_base_url") !== injectedUrl) continue;
78
+ drop.add(i);
79
+ // Take an ownership marker directly above it too, so repeated cycles cannot
80
+ // accumulate orphaned comments.
81
+ if (i > 0 && lines[i - 1]!.includes(OCX_SECTION_MARKER)) drop.add(i - 1);
82
+ }
83
+ if (drop.size === 0) return content;
84
+ return lines.filter((_, i) => !drop.has(i)).join(String.fromCharCode(10));
85
+ }
86
+
53
87
  export function hasInjectedOpenaiBaseUrl(content: string): boolean {
54
88
  const lines = content.split("\n");
55
89
  const firstTable = lines.findIndex(l => /^\s*\[/.test(l));
@@ -0,0 +1,266 @@
1
+ /**
2
+ * The sole reader/writer for integrations/codex.json.
3
+ *
4
+ * Provenance once disappeared when a corrupt record was treated as an empty one
5
+ * (005_disable_leaves_a_broken_file.md). Reads therefore validate the complete
6
+ * known shape, and updates refuse malformed bytes instead of manufacturing a new
7
+ * baseline over evidence we can no longer trust.
8
+ */
9
+ import { mkdirSync, readFileSync } from "node:fs";
10
+ import { dirname, join } from "node:path";
11
+ import { atomicWriteFile, getConfigDir, withConfigMutationLockSync } from "../config";
12
+ import type {
13
+ CodexArtifactId,
14
+ CodexIntegrationRecord,
15
+ CodexProvenanceEntry,
16
+ CodexProvenanceLedger,
17
+ } from "./convergence-types";
18
+
19
+ const RECORD_FILENAME = "codex.json";
20
+ const LEGACY_TRANSITION_KEYS = new Set([
21
+ "nativeGeneration",
22
+ "currentTxId",
23
+ "generation",
24
+ "history",
25
+ "historySchedule",
26
+ ]);
27
+
28
+ function recordPath(): string {
29
+ return join(getConfigDir(), "integrations", RECORD_FILENAME);
30
+ }
31
+
32
+ function isPlainRecord(value: unknown): value is Record<string, unknown> {
33
+ return typeof value === "object" && value !== null && !Array.isArray(value);
34
+ }
35
+
36
+ function isMissingPathError(error: unknown): boolean {
37
+ return error instanceof Error && "code" in error && (error as NodeJS.ErrnoException).code === "ENOENT";
38
+ }
39
+
40
+ function invalid(message: string) {
41
+ return { kind: "invalid" as const, message };
42
+ }
43
+
44
+ function validateArtifact(value: unknown): value is CodexArtifactId {
45
+ if (!isPlainRecord(value) || typeof value.kind !== "string") return false;
46
+ switch (value.kind) {
47
+ case "config":
48
+ case "generated-profile":
49
+ case "models-cache":
50
+ case "injection-journal":
51
+ return true;
52
+ case "active-catalog":
53
+ case "history-manifest":
54
+ case "history-rollout":
55
+ return typeof value.canonicalPath === "string"
56
+ && (value.kind === "active-catalog" || typeof value.stateDbId === "string");
57
+ case "catalog-backup":
58
+ return (value.form === "hashed" || value.form === "legacy")
59
+ && typeof value.canonicalPath === "string";
60
+ case "history-row":
61
+ case "history-manifest-entry":
62
+ return typeof value.stateDbId === "string" && typeof value.threadId === "string";
63
+ default:
64
+ return false;
65
+ }
66
+ }
67
+
68
+ function validateBaseline(value: unknown): boolean {
69
+ if (!isPlainRecord(value)) return false;
70
+ if (value.kind === "absent") return true;
71
+ return value.kind === "present"
72
+ && typeof value.sha256 === "string"
73
+ && typeof value.bytesBase64 === "string";
74
+ }
75
+
76
+ function validateEntry(value: unknown): value is CodexProvenanceEntry {
77
+ return isPlainRecord(value)
78
+ && validateArtifact(value.artifact)
79
+ && validateBaseline(value.baseline)
80
+ && (typeof value.postImage === "string" || value.postImage === null)
81
+ && typeof value.txId === "string"
82
+ && typeof value.at === "string";
83
+ }
84
+
85
+ function validateLedger(value: unknown): value is CodexProvenanceLedger {
86
+ return isPlainRecord(value)
87
+ && Array.isArray(value.entries)
88
+ && value.entries.every(validateEntry);
89
+ }
90
+
91
+ function validateRecord(value: unknown): value is CodexIntegrationRecord {
92
+ return isPlainRecord(value)
93
+ && value.version === 1
94
+ && !Object.keys(value).some(key => LEGACY_TRANSITION_KEYS.has(key))
95
+ && (value.provenance === undefined || validateLedger(value.provenance));
96
+ }
97
+
98
+ function readIntegrationRecordUnlocked() {
99
+ let raw: string;
100
+ try {
101
+ raw = readFileSync(recordPath(), "utf8");
102
+ } catch (error) {
103
+ if (isMissingPathError(error)) return { kind: "missing" as const, record: null };
104
+ return invalid(`Codex integration record is unreadable: ${error instanceof Error ? error.message : String(error)}`);
105
+ }
106
+
107
+ let parsed: unknown;
108
+ try {
109
+ parsed = JSON.parse(raw.replace(/^\uFEFF/, ""));
110
+ } catch {
111
+ return invalid("Codex integration record contains invalid JSON");
112
+ }
113
+ if (!validateRecord(parsed)) {
114
+ return invalid("Codex integration record has an unsupported or malformed v1 shape");
115
+ }
116
+ return { kind: "ready" as const, record: parsed };
117
+ }
118
+
119
+ export const readIntegrationRecord = readIntegrationRecordUnlocked;
120
+
121
+ function copyUnknown(
122
+ previous: Record<string, unknown>,
123
+ next: Record<string, unknown>,
124
+ knownKeys: ReadonlySet<string>,
125
+ ): Record<string, unknown> {
126
+ const merged: Record<string, unknown> = {};
127
+ for (const [key, value] of Object.entries(previous)) {
128
+ if (!knownKeys.has(key)) merged[key] = value;
129
+ }
130
+ return { ...merged, ...next };
131
+ }
132
+
133
+ function artifactKnownKeys(artifact: CodexArtifactId): ReadonlySet<string> {
134
+ switch (artifact.kind) {
135
+ case "config":
136
+ case "generated-profile":
137
+ case "models-cache":
138
+ case "injection-journal":
139
+ return new Set(["kind"]);
140
+ case "active-catalog":
141
+ return new Set(["kind", "canonicalPath"]);
142
+ case "catalog-backup":
143
+ return new Set(["kind", "form", "canonicalPath"]);
144
+ case "history-row":
145
+ case "history-manifest-entry":
146
+ return new Set(["kind", "stateDbId", "threadId"]);
147
+ case "history-manifest":
148
+ case "history-rollout":
149
+ return new Set(["kind", "stateDbId", "canonicalPath"]);
150
+ }
151
+ }
152
+
153
+ function mergeArtifact(previous: CodexArtifactId, next: CodexArtifactId): CodexArtifactId {
154
+ return copyUnknown(
155
+ previous as CodexArtifactId & Record<string, unknown>,
156
+ next as CodexArtifactId & Record<string, unknown>,
157
+ artifactKnownKeys(previous),
158
+ ) as CodexArtifactId;
159
+ }
160
+
161
+ function mergeBaseline(
162
+ previous: CodexProvenanceEntry["baseline"],
163
+ next: CodexProvenanceEntry["baseline"],
164
+ ): CodexProvenanceEntry["baseline"] {
165
+ const known = previous.kind === "present"
166
+ ? new Set(["kind", "sha256", "bytesBase64"])
167
+ : new Set(["kind"]);
168
+ return copyUnknown(previous, next, known) as CodexProvenanceEntry["baseline"];
169
+ }
170
+
171
+ function knownArtifactIdentity(artifact: CodexArtifactId): string {
172
+ switch (artifact.kind) {
173
+ case "config":
174
+ case "generated-profile":
175
+ case "models-cache":
176
+ case "injection-journal":
177
+ return artifact.kind;
178
+ case "active-catalog":
179
+ return `${artifact.kind}\0${artifact.canonicalPath}`;
180
+ case "catalog-backup":
181
+ return `${artifact.kind}\0${artifact.form}\0${artifact.canonicalPath}`;
182
+ case "history-row":
183
+ case "history-manifest-entry":
184
+ return `${artifact.kind}\0${artifact.stateDbId}\0${artifact.threadId}`;
185
+ case "history-manifest":
186
+ case "history-rollout":
187
+ return `${artifact.kind}\0${artifact.stateDbId}\0${artifact.canonicalPath}`;
188
+ }
189
+ }
190
+
191
+ function mergeEntry(previous: CodexProvenanceEntry, next: CodexProvenanceEntry): CodexProvenanceEntry {
192
+ const merged = copyUnknown(
193
+ previous,
194
+ next,
195
+ new Set(["artifact", "baseline", "postImage", "txId", "at"]),
196
+ );
197
+ return {
198
+ ...merged,
199
+ artifact: mergeArtifact(previous.artifact, next.artifact),
200
+ baseline: mergeBaseline(previous.baseline, next.baseline),
201
+ } as CodexProvenanceEntry;
202
+ }
203
+
204
+ function mergeLedger(previous: CodexProvenanceLedger, next: CodexProvenanceLedger): CodexProvenanceLedger {
205
+ const unused = new Set(previous.entries.map((_, index) => index));
206
+ const entries = next.entries.map((entry, nextIndex) => {
207
+ let previousIndex = previous.entries.findIndex((candidate, index) =>
208
+ unused.has(index)
209
+ && candidate.txId === entry.txId
210
+ && candidate.at === entry.at
211
+ && knownArtifactIdentity(candidate.artifact) === knownArtifactIdentity(entry.artifact));
212
+ if (previousIndex < 0 && unused.has(nextIndex)) previousIndex = nextIndex;
213
+ if (previousIndex < 0) return entry;
214
+ unused.delete(previousIndex);
215
+ return mergeEntry(previous.entries[previousIndex]!, entry);
216
+ });
217
+ return {
218
+ ...copyUnknown(previous, next, new Set(["entries"])),
219
+ entries,
220
+ } as CodexProvenanceLedger;
221
+ }
222
+
223
+ function preserveExtensions(
224
+ previous: CodexIntegrationRecord,
225
+ next: CodexIntegrationRecord,
226
+ ): CodexIntegrationRecord {
227
+ const merged = copyUnknown(previous, next, new Set(["version", "provenance"]));
228
+ if (previous.provenance && next.provenance) {
229
+ merged.provenance = mergeLedger(previous.provenance, next.provenance);
230
+ }
231
+ return merged as CodexIntegrationRecord;
232
+ }
233
+
234
+ /**
235
+ * Keep read, extension merge, and atomic replacement inside the config mutation
236
+ * coordinator. WP12 must call this function instead of recreating the incident's
237
+ * stale read/merge/write sequence at its own call site.
238
+ */
239
+ export const updateIntegrationRecord = (
240
+ mutate: (record: CodexIntegrationRecord) => CodexIntegrationRecord,
241
+ ) => {
242
+ try {
243
+ return withConfigMutationLockSync(() => {
244
+ const read = readIntegrationRecordUnlocked();
245
+ if (read.kind === "invalid") return read;
246
+ const previous: CodexIntegrationRecord = read.kind === "ready" ? read.record : { version: 1 };
247
+ const proposed = mutate(previous);
248
+ if (!validateRecord(proposed)) {
249
+ return { kind: "invalid", message: "Codex integration record update produced a malformed v1 shape" };
250
+ }
251
+ const record = preserveExtensions(previous, proposed);
252
+ if (!validateRecord(record)) {
253
+ return { kind: "invalid", message: "Codex integration record extension merge produced a malformed v1 shape" };
254
+ }
255
+ const path = recordPath();
256
+ mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
257
+ atomicWriteFile(path, `${JSON.stringify(record, null, 2)}\n`);
258
+ return { kind: "updated", record };
259
+ });
260
+ } catch (error) {
261
+ return {
262
+ kind: "invalid",
263
+ message: `Codex integration record update failed: ${error instanceof Error ? error.message : String(error)}`,
264
+ };
265
+ }
266
+ };
@@ -0,0 +1,203 @@
1
+ import { chmodSync, linkSync, mkdirSync, truncateSync, unlinkSync, writeFileSync } from "node:fs";
2
+ import { dirname } from "node:path";
3
+
4
+ import {
5
+ AtomicWriteResidualTempError,
6
+ AtomicWriteSecretResidualError,
7
+ atomicWriteFile,
8
+ resolveWriteTarget,
9
+ type AtomicWriteIO,
10
+ } from "../../config";
11
+ import {
12
+ assertCatalogWritePermit,
13
+ type CatalogWritePermit,
14
+ } from "../catalog-write-serialization";
15
+ import {
16
+ forgetEphemeralSecretPath,
17
+ hardenSecretPath,
18
+ } from "../../lib/windows-secret-acl";
19
+
20
+ export interface PreparedCatalogFileWrite {
21
+ readonly path: string;
22
+ readonly content: string;
23
+ }
24
+
25
+ export type CatalogBackupPublication = "written" | "preserved";
26
+
27
+ export interface CatalogBackupWriteIO {
28
+ readonly resolveTarget: (path: string) => string;
29
+ readonly write: (path: string, content: string) => void;
30
+ readonly harden: (path: string) => void;
31
+ /** Must fail with EEXIST rather than replacing an existing destination. */
32
+ readonly publishNoReplace: (source: string, destination: string) => void;
33
+ readonly truncate: (path: string) => void;
34
+ readonly unlink: (path: string) => void;
35
+ }
36
+
37
+ let backupTempSequence = 0;
38
+
39
+ function isMissingPathError(error: unknown): boolean {
40
+ return (error as NodeJS.ErrnoException | undefined)?.code === "ENOENT";
41
+ }
42
+
43
+ function isExistingPathError(error: unknown): boolean {
44
+ return (error as NodeJS.ErrnoException | undefined)?.code === "EEXIST";
45
+ }
46
+
47
+ function defaultBackupWriteIO(destinationPath: string): CatalogBackupWriteIO {
48
+ return {
49
+ resolveTarget: resolveWriteTarget,
50
+ write: (path, content) => writeFileSync(path, content, { encoding: "utf8", mode: 0o600 }),
51
+ harden: path => {
52
+ try { chmodSync(path, 0o600); } catch { /* platform may ignore chmod */ }
53
+ if (process.platform === "win32") {
54
+ hardenSecretPath(path, { required: true, timeoutMemoKey: destinationPath });
55
+ }
56
+ },
57
+ publishNoReplace: linkSync,
58
+ truncate: path => truncateSync(path, 0),
59
+ unlink: unlinkSync,
60
+ };
61
+ }
62
+
63
+ function removePublishedTemp(tempPath: string, io: CatalogBackupWriteIO): void {
64
+ try {
65
+ io.unlink(tempPath);
66
+ forgetEphemeralSecretPath(tempPath);
67
+ return;
68
+ } catch (firstError) {
69
+ if (isMissingPathError(firstError)) {
70
+ forgetEphemeralSecretPath(tempPath);
71
+ return;
72
+ }
73
+ try {
74
+ io.unlink(tempPath);
75
+ forgetEphemeralSecretPath(tempPath);
76
+ return;
77
+ } catch (retryError) {
78
+ if (isMissingPathError(retryError)) {
79
+ forgetEphemeralSecretPath(tempPath);
80
+ return;
81
+ }
82
+ throw new AtomicWriteResidualTempError(tempPath, true, { cause: retryError });
83
+ }
84
+ }
85
+ }
86
+
87
+ function scrubAndRemoveUnpublishedTemp(
88
+ tempPath: string,
89
+ hardened: boolean,
90
+ io: CatalogBackupWriteIO,
91
+ cause: unknown,
92
+ ): void {
93
+ let scrubbed = false;
94
+ try {
95
+ io.truncate(tempPath);
96
+ scrubbed = true;
97
+ } catch (error) {
98
+ if (isMissingPathError(error)) scrubbed = true;
99
+ else {
100
+ try {
101
+ io.write(tempPath, "");
102
+ scrubbed = true;
103
+ } catch { /* removal may still succeed */ }
104
+ }
105
+ }
106
+
107
+ let removed = false;
108
+ try {
109
+ io.unlink(tempPath);
110
+ removed = true;
111
+ } catch (error) {
112
+ if (isMissingPathError(error)) removed = true;
113
+ else {
114
+ try {
115
+ io.unlink(tempPath);
116
+ removed = true;
117
+ } catch (retryError) {
118
+ if (isMissingPathError(retryError)) removed = true;
119
+ }
120
+ }
121
+ }
122
+
123
+ if (!removed && !scrubbed) {
124
+ throw new AtomicWriteSecretResidualError(tempPath, { cause });
125
+ }
126
+ if (!removed && !hardened) {
127
+ try {
128
+ io.harden(tempPath);
129
+ hardened = true;
130
+ } catch { /* zero-byte residual is reported honestly */ }
131
+ }
132
+ if (removed) forgetEphemeralSecretPath(tempPath);
133
+ if (!removed) throw new AtomicWriteResidualTempError(tempPath, hardened, { cause });
134
+ }
135
+
136
+ function publishCatalogBackup(
137
+ prepared: PreparedCatalogFileWrite,
138
+ suppliedIo?: CatalogBackupWriteIO,
139
+ ): CatalogBackupPublication {
140
+ const io = suppliedIo ?? defaultBackupWriteIO(prepared.path);
141
+ const target = io.resolveTarget(prepared.path);
142
+ if (!suppliedIo) mkdirSync(dirname(target), { recursive: true, mode: 0o700 });
143
+ const tempPath = `${target}.ocx.${process.pid}.backup.${++backupTempSequence}.tmp`;
144
+ let hardened = false;
145
+
146
+ try {
147
+ io.write(tempPath, prepared.content);
148
+ io.harden(tempPath);
149
+ hardened = true;
150
+ io.publishNoReplace(tempPath, target);
151
+ } catch (error) {
152
+ scrubAndRemoveUnpublishedTemp(tempPath, hardened, io, error);
153
+ if (isExistingPathError(error)) return "preserved";
154
+ throw error;
155
+ }
156
+
157
+ removePublishedTemp(tempPath, io);
158
+ return "written";
159
+ }
160
+
161
+ /** Replace the active catalog with the caller's already-prepared bytes. */
162
+ export function replaceActiveCodexCatalog(
163
+ permit: CatalogWritePermit,
164
+ owningCodexHome: string,
165
+ prepared: PreparedCatalogFileWrite,
166
+ io?: AtomicWriteIO,
167
+ ): void {
168
+ assertCatalogWritePermit(permit, owningCodexHome);
169
+ atomicWriteFile(prepared.path, prepared.content, io);
170
+ }
171
+
172
+ /** Atomically publish the catalog-path-keyed immutable backup without clobbering. */
173
+ export function publishHashedCodexCatalogBackup(
174
+ permit: CatalogWritePermit,
175
+ owningCodexHome: string,
176
+ prepared: PreparedCatalogFileWrite,
177
+ io?: CatalogBackupWriteIO,
178
+ ): CatalogBackupPublication {
179
+ assertCatalogWritePermit(permit, owningCodexHome);
180
+ return publishCatalogBackup(prepared, io);
181
+ }
182
+
183
+ /** Atomically publish the legacy immutable backup without clobbering. */
184
+ export function publishLegacyCodexCatalogBackup(
185
+ permit: CatalogWritePermit,
186
+ owningCodexHome: string,
187
+ prepared: PreparedCatalogFileWrite,
188
+ io?: CatalogBackupWriteIO,
189
+ ): CatalogBackupPublication {
190
+ assertCatalogWritePermit(permit, owningCodexHome);
191
+ return publishCatalogBackup(prepared, io);
192
+ }
193
+
194
+ /** Replace Codex's models cache with the caller's already-prepared bytes. */
195
+ export function replaceCodexModelsCache(
196
+ permit: CatalogWritePermit,
197
+ owningCodexHome: string,
198
+ prepared: PreparedCatalogFileWrite,
199
+ io?: AtomicWriteIO,
200
+ ): void {
201
+ assertCatalogWritePermit(permit, owningCodexHome);
202
+ atomicWriteFile(prepared.path, prepared.content, io);
203
+ }
@@ -0,0 +1,81 @@
1
+ /**
2
+ * The history mutation boundary. Every byte Codex history owns is written here,
3
+ * and only while H is held.
4
+ *
5
+ * This module exists because the mutations are spread across three surfaces that
6
+ * do not share a transaction: SQLite rows, the backup manifest, and the rollout
7
+ * files. `syncCodexHistoryProvider` writes the manifest BEFORE its database
8
+ * transaction and patches rollouts inside it; restore preflights every rollout,
9
+ * applies database CAS before file changes in one SQLite transaction, then consumes the
10
+ * manifest after exact readback (`src/codex/history-provider.ts`). A
11
+ * SQLite busy timeout
12
+ * serializes exactly one of those three, which is why an opposite-direction
13
+ * process could overtake through the other two.
14
+ *
15
+ * The permit argument is not decoration and not a type-level claim. Each entry
16
+ * point asks the lock owner at RUNTIME whether the permit it was handed is still
17
+ * live for the state database about to be written, because a permit leaked past
18
+ * its callback type-checks perfectly. A writer reached without H therefore fails
19
+ * closed rather than racing.
20
+ *
21
+ * Reachability: `src/codex/history-worker.ts` is the only permitted production
22
+ * root. Readers and probes stay in `history-provider.ts`; nothing in the CLI, the
23
+ * server, the guardian, `inject.ts` or `sync.ts` may reach these symbols.
24
+ *
25
+ * Design record: devlog/_fin/260804_codex_write_substrate/020_history_isolation.md.
26
+ */
27
+ import { assertHistoryWritePermit, type HistoryWritePermit } from "../history-lock";
28
+ import {
29
+ restoreLegacyOpenaiHistory,
30
+ syncCodexHistoryProvider,
31
+ type CodexHistoryProvider,
32
+ type CodexHistorySyncResult,
33
+ } from "../history-provider";
34
+
35
+ /**
36
+ * Everything a history mutation needs, with no ambient state.
37
+ *
38
+ * The paths are explicit because a Worker is a separate process: it does not
39
+ * inherit the module-load `CODEX_HOME` that `history-provider.ts` resolves at
40
+ * import time (`:16`, `:22`), so a request that relied on those constants would
41
+ * silently address the wrong home.
42
+ */
43
+ export interface HistoryWriteTarget {
44
+ /** Canonical, absolute; the same identity H was acquired for. */
45
+ readonly canonicalStateDbPath: string;
46
+ /** Canonical, absolute path of the backup manifest for that database. */
47
+ readonly canonicalBackupPath: string;
48
+ }
49
+
50
+ /**
51
+ * Apply opencodex routing to resumable history, or restore it to native.
52
+ *
53
+ * `provider` is the DURABLE operation's direction, resolved by the caller from
54
+ * the coordinator row — never a caller-supplied preference. The Worker passes
55
+ * what the row said, which is what stops a request from turning a restore into
56
+ * an apply.
57
+ */
58
+ export function writeHistoryProviderTransition(
59
+ permit: HistoryWritePermit,
60
+ target: HistoryWriteTarget,
61
+ provider: CodexHistoryProvider,
62
+ ): CodexHistorySyncResult {
63
+ assertHistoryWritePermit(permit, target.canonicalStateDbPath);
64
+ return syncCodexHistoryProvider(provider, target.canonicalStateDbPath, target.canonicalBackupPath);
65
+ }
66
+
67
+ /**
68
+ * Manifest-independent legacy ejection.
69
+ *
70
+ * Distinct from the generic restore above: it never reads, consumes, deletes or
71
+ * replaces the backup manifest. It does patch rollout metadata and returns a
72
+ * `files` count, so calling it "DB-only" would be wrong — the name says what it
73
+ * actually avoids.
74
+ */
75
+ export function writeLegacyOpenaiHistoryRecovery(
76
+ permit: HistoryWritePermit,
77
+ target: HistoryWriteTarget,
78
+ ): CodexHistorySyncResult {
79
+ assertHistoryWritePermit(permit, target.canonicalStateDbPath);
80
+ return restoreLegacyOpenaiHistory(target.canonicalStateDbPath);
81
+ }