@iislee/opencodex 2.11.0 → 2.35.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (733) hide show
  1. package/AGENTS_INSTALL.md +109 -0
  2. package/README.md +117 -22
  3. package/bin/ocx.mjs +245 -88
  4. package/bin/package-main.mjs +1 -1
  5. package/gui/dist/assets/index-Be1sDpWw.css +1 -0
  6. package/gui/dist/assets/index-D4OKgUV4.js +114 -0
  7. package/gui/dist/index.html +2 -2
  8. package/gui/dist/provider-icons/alibaba-color.svg +1 -1
  9. package/gui/dist/provider-icons/antigravity-color.svg +1 -1
  10. package/gui/dist/provider-icons/claude-color.svg +1 -1
  11. package/gui/dist/provider-icons/cline-color.svg +16 -0
  12. package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -1
  13. package/gui/dist/provider-icons/commandcode-color.svg +1 -0
  14. package/gui/dist/provider-icons/copilot-color.svg +1 -1
  15. package/gui/dist/provider-icons/cursor-color.svg +1 -1
  16. package/gui/dist/provider-icons/deepseek-color.svg +1 -1
  17. package/gui/dist/provider-icons/firepass-color.svg +1 -1
  18. package/gui/dist/provider-icons/fireworks-color.svg +1 -1
  19. package/gui/dist/provider-icons/gemini-color.svg +1 -1
  20. package/gui/dist/provider-icons/github-copilot-color.svg +1 -1
  21. package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -1
  22. package/gui/dist/provider-icons/grok.svg +1 -1
  23. package/gui/dist/provider-icons/groq-color.svg +1 -1
  24. package/gui/dist/provider-icons/huggingface-color.svg +1 -1
  25. package/gui/dist/provider-icons/kimi-color.svg +1 -1
  26. package/gui/dist/provider-icons/kiro-color.svg +2 -2
  27. package/gui/dist/provider-icons/lm-studio-color.svg +1 -1
  28. package/gui/dist/provider-icons/mistral-color.svg +1 -1
  29. package/gui/dist/provider-icons/moonshot-color.svg +1 -1
  30. package/gui/dist/provider-icons/nvidia-color.svg +1 -1
  31. package/gui/dist/provider-icons/ollama-color.svg +1 -1
  32. package/gui/dist/provider-icons/openai.svg +1 -1
  33. package/gui/dist/provider-icons/opencode.svg +2 -1
  34. package/gui/dist/provider-icons/openrouter-color.svg +1 -1
  35. package/gui/dist/provider-icons/pi.svg +2 -2
  36. package/gui/dist/provider-icons/qianfan-color.svg +1 -1
  37. package/gui/dist/provider-icons/qwen-portal-color.svg +1 -1
  38. package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -1
  39. package/gui/dist/provider-icons/vllm-color.svg +1 -1
  40. package/gui/dist/provider-icons/xiaomi-color.svg +1 -1
  41. package/package.json +21 -10
  42. package/src/adapters/anthropic-output-schema.ts +137 -0
  43. package/src/adapters/anthropic.ts +475 -62
  44. package/src/adapters/base.ts +82 -7
  45. package/src/adapters/client-fingerprint.ts +18 -12
  46. package/src/adapters/cline-pass-deepseek-v4-tool-replay.ts +69 -0
  47. package/src/adapters/command-code.ts +637 -0
  48. package/src/adapters/cursor/call-id.ts +44 -0
  49. package/src/adapters/cursor/catalog.ts +541 -0
  50. package/src/adapters/cursor/checkpoint-store.ts +308 -0
  51. package/src/adapters/cursor/cursor-errors.ts +144 -6
  52. package/src/adapters/cursor/discovery.ts +122 -14
  53. package/src/adapters/cursor/effort-map.ts +106 -4
  54. package/src/adapters/cursor/envelope-echo.ts +290 -0
  55. package/src/adapters/cursor/framing.ts +39 -0
  56. package/src/adapters/cursor/h2-pool.ts +123 -0
  57. package/src/adapters/cursor/http1-bidi.ts +361 -0
  58. package/src/adapters/cursor/images.ts +704 -0
  59. package/src/adapters/cursor/live-models.ts +180 -59
  60. package/src/adapters/cursor/live-transport.ts +623 -170
  61. package/src/adapters/cursor/message-mapper.ts +4 -1
  62. package/src/adapters/cursor/native-exec-common.ts +23 -2
  63. package/src/adapters/cursor/native-exec-desktop.ts +23 -0
  64. package/src/adapters/cursor/native-exec-fs.ts +10 -7
  65. package/src/adapters/cursor/native-exec-network.ts +1 -1
  66. package/src/adapters/cursor/native-exec-shell.ts +5 -3
  67. package/src/adapters/cursor/native-exec.ts +121 -14
  68. package/src/adapters/cursor/protobuf-events.ts +829 -11
  69. package/src/adapters/cursor/protobuf-request.ts +447 -75
  70. package/src/adapters/cursor/request-builder.ts +271 -35
  71. package/src/adapters/cursor/tool-definitions.ts +252 -12
  72. package/src/adapters/cursor/tool-result-normalize.ts +115 -0
  73. package/src/adapters/cursor/transport.ts +22 -0
  74. package/src/adapters/cursor/types.ts +48 -1
  75. package/src/adapters/cursor.ts +336 -39
  76. package/src/adapters/exec-tool-result-normalize.ts +99 -0
  77. package/src/adapters/google-antigravity-replay.ts +713 -41
  78. package/src/adapters/google-antigravity-wire.ts +48 -10
  79. package/src/adapters/google-errors.ts +44 -12
  80. package/src/adapters/google-http.ts +38 -10
  81. package/src/adapters/google-tool-schema.ts +80 -15
  82. package/src/adapters/google-truncation.ts +11 -0
  83. package/src/adapters/google.ts +742 -86
  84. package/src/adapters/identity.ts +39 -6
  85. package/src/adapters/image.ts +1 -1
  86. package/src/adapters/kiro-constants.ts +27 -0
  87. package/src/adapters/kiro-errors.ts +11 -0
  88. package/src/adapters/kiro-events.ts +19 -1
  89. package/src/adapters/kiro-thinking.ts +18 -2
  90. package/src/adapters/kiro-tools.ts +65 -17
  91. package/src/adapters/kiro.ts +270 -73
  92. package/src/adapters/mimo-free.ts +17 -0
  93. package/src/adapters/openai-chat-url.ts +11 -0
  94. package/src/adapters/openai-chat.ts +1377 -344
  95. package/src/adapters/openai-responses-url.ts +16 -0
  96. package/src/adapters/openai-responses.ts +1164 -64
  97. package/src/adapters/registry.ts +175 -0
  98. package/src/adapters/responses-tool-schema.ts +67 -0
  99. package/src/adapters/run-turn-queue.ts +36 -1
  100. package/src/adapters/tool-call-id.ts +119 -0
  101. package/src/adapters/tool-catalog-nudge.ts +105 -21
  102. package/src/adapters/xai-tool-schema.ts +436 -0
  103. package/src/adapters/xai-web-search.ts +186 -0
  104. package/src/bridge.ts +512 -92
  105. package/src/chat/inbound.ts +57 -20
  106. package/src/chat/outbound.ts +97 -33
  107. package/src/claude/agents-inject.ts +40 -10
  108. package/src/claude/context-windows.ts +37 -14
  109. package/src/claude/desktop-3p.ts +243 -9
  110. package/src/claude/gateway-cache.ts +41 -4
  111. package/src/claude/inbound.ts +72 -3
  112. package/src/claude/model-info.ts +38 -15
  113. package/src/claude/outbound.ts +88 -21
  114. package/src/cli/access.ts +46 -3
  115. package/src/cli/account-api.ts +150 -19
  116. package/src/cli/account-auth.ts +33 -6
  117. package/src/cli/account-catalog-refresh.ts +14 -0
  118. package/src/cli/account-extended.ts +648 -28
  119. package/src/cli/account-main.ts +317 -0
  120. package/src/cli/account.ts +97 -19
  121. package/src/cli/agent.ts +53 -2
  122. package/src/cli/alias.ts +66 -0
  123. package/src/cli/capabilities-command.ts +94 -0
  124. package/src/cli/capabilities.ts +496 -0
  125. package/src/cli/claude-agent-startup-sync.ts +73 -0
  126. package/src/cli/claude-desktop.ts +60 -15
  127. package/src/cli/claude.ts +129 -35
  128. package/src/cli/codex-log-guard-doctor.ts +103 -0
  129. package/src/cli/codex-shim-autorestore.ts +2 -0
  130. package/src/cli/codex-shim-readiness.ts +76 -0
  131. package/src/cli/combo.ts +8 -0
  132. package/src/cli/config-command.ts +74 -10
  133. package/src/cli/dispatch.ts +821 -0
  134. package/src/cli/doctor.ts +440 -56
  135. package/src/cli/ensure-desired-integrations.ts +152 -0
  136. package/src/cli/export-command.ts +46 -20
  137. package/src/cli/help.ts +34 -274
  138. package/src/cli/index.ts +417 -528
  139. package/src/cli/init.ts +5 -17
  140. package/src/cli/inspect.ts +230 -0
  141. package/src/cli/integrations.ts +120 -2
  142. package/src/cli/lab.ts +607 -0
  143. package/src/cli/launcher-context.ts +77 -0
  144. package/src/cli/minimax.ts +497 -0
  145. package/src/cli/models-runtime.ts +130 -2
  146. package/src/cli/models.ts +118 -16
  147. package/src/cli/observe.ts +123 -11
  148. package/src/cli/opencode.ts +4 -2
  149. package/src/cli/provider-runtime.ts +34 -3
  150. package/src/cli/provider.ts +25 -3
  151. package/src/cli/ready.ts +301 -0
  152. package/src/cli/registry.ts +476 -0
  153. package/src/cli/root.ts +86 -0
  154. package/src/cli/route-policy.ts +92 -0
  155. package/src/cli/runtime-api.ts +57 -10
  156. package/src/cli/star-prompt.ts +71 -15
  157. package/src/cli/status.ts +51 -4
  158. package/src/cli/storage.ts +234 -0
  159. package/src/cli/system-command.ts +16 -0
  160. package/src/cli/system-restart-client.ts +146 -0
  161. package/src/cli/tray-proxy.ts +153 -6
  162. package/src/cli/usage-report.ts +184 -0
  163. package/src/cli/v2.ts +137 -18
  164. package/src/cli/version-skew.ts +46 -0
  165. package/src/cli.ts +1 -1
  166. package/src/clients/config-export.ts +1442 -23
  167. package/src/clients/effective-status.ts +30 -2
  168. package/src/clients/probes/cline.ts +81 -0
  169. package/src/codex/account-label.ts +35 -1
  170. package/src/codex/account-lifecycle.ts +130 -13
  171. package/src/codex/account-namespaces.ts +49 -3
  172. package/src/codex/account-pause.ts +2 -1
  173. package/src/codex/account-priority.ts +84 -0
  174. package/src/codex/account-store.ts +29 -2
  175. package/src/codex/account-usability.ts +25 -2
  176. package/src/codex/admission.ts +256 -0
  177. package/src/codex/affinity-debug.ts +162 -0
  178. package/src/codex/app-server-processes.ts +570 -107
  179. package/src/codex/app-server-restart-service.ts +232 -0
  180. package/src/codex/auth-api.ts +893 -246
  181. package/src/codex/auth-collision.ts +5 -3
  182. package/src/codex/auth-context.ts +348 -32
  183. package/src/codex/autostart-health.ts +24 -1
  184. package/src/codex/catalog/account-models.ts +67 -0
  185. package/src/codex/catalog/aggregation.ts +86 -10
  186. package/src/codex/catalog/bundled.ts +331 -33
  187. package/src/codex/catalog/effort.ts +138 -32
  188. package/src/codex/catalog/filesystem-evidence.ts +302 -0
  189. package/src/codex/catalog/kinds.ts +2 -0
  190. package/src/codex/catalog/metadata.ts +555 -45
  191. package/src/codex/catalog/native-models.ts +75 -0
  192. package/src/codex/catalog/parsing.ts +269 -30
  193. package/src/codex/catalog/provider-fetch.ts +1626 -144
  194. package/src/codex/catalog/sync.ts +1576 -187
  195. package/src/codex/catalog-admission.ts +199 -0
  196. package/src/codex/catalog-refresh-status.ts +105 -0
  197. package/src/codex/catalog-write-serialization.ts +242 -0
  198. package/src/codex/catalog.ts +6 -3
  199. package/src/codex/codex-write-lock.ts +386 -0
  200. package/src/codex/convergence-types.ts +614 -0
  201. package/src/codex/convergence.ts +676 -0
  202. package/src/codex/coordinator-doctor.ts +332 -0
  203. package/src/codex/custom-model-catalog-migration.ts +176 -0
  204. package/src/codex/desired-state.ts +230 -0
  205. package/src/codex/desktop-app-restart.ts +355 -0
  206. package/src/codex/features.ts +636 -39
  207. package/src/codex/generation.ts +202 -0
  208. package/src/codex/history-job.ts +436 -0
  209. package/src/codex/history-lock.ts +242 -0
  210. package/src/codex/history-manifest.ts +112 -0
  211. package/src/codex/history-migration-guardian.ts +30 -24
  212. package/src/codex/history-provider.ts +1016 -235
  213. package/src/codex/history-transition.ts +105 -0
  214. package/src/codex/history-worker.ts +223 -0
  215. package/src/codex/inject-coordination.ts +373 -0
  216. package/src/codex/inject.ts +1114 -152
  217. package/src/codex/injected-marker.ts +37 -3
  218. package/src/codex/integration-record.ts +266 -0
  219. package/src/codex/internal/catalog-writer.ts +203 -0
  220. package/src/codex/internal/history-writer.ts +81 -0
  221. package/src/codex/journal.ts +66 -4
  222. package/src/codex/log-guard/inspect.ts +524 -0
  223. package/src/codex/log-guard/lock.ts +150 -0
  224. package/src/codex/log-guard/maintenance.ts +403 -0
  225. package/src/codex/log-guard/path-safety.ts +88 -0
  226. package/src/codex/log-guard/policy.ts +44 -0
  227. package/src/codex/log-guard/processes.ts +205 -0
  228. package/src/codex/log-guard/protection.ts +489 -0
  229. package/src/codex/log-guard/sqlite-errors.ts +9 -0
  230. package/src/codex/main-account-cache.ts +24 -0
  231. package/src/codex/main-account.ts +29 -1
  232. package/src/codex/management-convergence.ts +167 -0
  233. package/src/codex/model-cache.ts +56 -10
  234. package/src/codex/model-entitlements.ts +360 -0
  235. package/src/codex/native-main-admission.ts +47 -0
  236. package/src/codex/native-main-auth-temp.ts +187 -0
  237. package/src/codex/native-main-claim.ts +178 -0
  238. package/src/codex/native-main-lock-file.ts +162 -0
  239. package/src/codex/native-main-owner.ts +329 -0
  240. package/src/codex/native-profile-api.ts +247 -0
  241. package/src/codex/native-profile-manager.ts +1531 -0
  242. package/src/codex/native-profile-processes.ts +121 -0
  243. package/src/codex/native-profile-recovery.ts +99 -0
  244. package/src/codex/native-profile-stage-store.ts +387 -0
  245. package/src/codex/native-profile-startup.ts +622 -0
  246. package/src/codex/native-profile-store.ts +855 -0
  247. package/src/codex/native-profile-types.ts +120 -0
  248. package/src/codex/native-residue.ts +675 -0
  249. package/src/codex/paths.ts +80 -1
  250. package/src/codex/plan-from-token.ts +140 -0
  251. package/src/codex/plan.ts +40 -0
  252. package/src/codex/plugins-doctor.ts +1 -1
  253. package/src/codex/pool-rotation.ts +74 -4
  254. package/src/codex/project-config-warnings.ts +20 -6
  255. package/src/codex/prompt-journal.ts +352 -0
  256. package/src/codex/prompt-layers.ts +1313 -0
  257. package/src/codex/prompt-lock.ts +143 -0
  258. package/src/codex/prompt-text-probe.ts +238 -0
  259. package/src/codex/quota-rejection.ts +298 -0
  260. package/src/codex/quota.ts +264 -21
  261. package/src/codex/refresh.ts +11 -2
  262. package/src/codex/reset-credit-recovery.ts +1044 -0
  263. package/src/codex/routing.ts +514 -94
  264. package/src/codex/runtime.ts +159 -38
  265. package/src/codex/shim.ts +1065 -31
  266. package/src/codex/subagent-model-fallback.ts +437 -43
  267. package/src/codex/sync.ts +191 -2
  268. package/src/codex/transition-state.ts +720 -0
  269. package/src/codex/upstream-host-health.ts +368 -0
  270. package/src/codex/user-identity.ts +557 -0
  271. package/src/codex/warmup.ts +187 -81
  272. package/src/codex/write-coordination.ts +114 -0
  273. package/src/combos/failover.ts +47 -0
  274. package/src/combos/index.ts +4 -0
  275. package/src/combos/request.ts +32 -0
  276. package/src/combos/types.ts +91 -9
  277. package/src/compatibility/index.ts +26 -0
  278. package/src/compatibility/manifest.ts +253 -0
  279. package/src/compatibility/openai-responses.ts +121 -0
  280. package/src/config/atomic-write.ts +219 -0
  281. package/src/config/paths.ts +40 -0
  282. package/src/config/process-state.ts +309 -0
  283. package/src/config/provider-name.ts +24 -0
  284. package/src/config/provider-validation.ts +177 -0
  285. package/src/config/rebase-provenance.ts +68 -0
  286. package/src/config.ts +1713 -709
  287. package/src/generated/compatibility-version.json +3324 -0
  288. package/src/generated/{jawcode-model-metadata.ts → model-metadata.ts} +19 -17
  289. package/src/grok/inject.ts +16 -5
  290. package/src/grok/inspect.ts +45 -0
  291. package/src/grok/sync.ts +2 -2
  292. package/src/images/loop.ts +157 -33
  293. package/src/images/plan.ts +24 -13
  294. package/src/integrations/config-io.ts +269 -0
  295. package/src/integrations/journal.ts +315 -0
  296. package/src/integrations/merge.ts +135 -0
  297. package/src/integrations/mutation-flight.ts +71 -0
  298. package/src/integrations/native/ownership-preflight.ts +202 -0
  299. package/src/integrations/omp-yaml-source.ts +358 -0
  300. package/src/integrations/owned-refresh.ts +74 -0
  301. package/src/integrations/ownership-policy.ts +160 -0
  302. package/src/integrations/ownership.ts +155 -0
  303. package/src/integrations/registry.ts +166 -0
  304. package/src/integrations/serialize.ts +314 -0
  305. package/src/integrations/state.ts +433 -0
  306. package/src/integrations/store.ts +103 -0
  307. package/src/integrations/writer-lock.ts +98 -0
  308. package/src/integrations/writer.ts +715 -0
  309. package/src/lab/artifacts/sanitize.ts +586 -0
  310. package/src/lab/artifacts/secure-fs.ts +475 -0
  311. package/src/lab/artifacts/store.ts +310 -0
  312. package/src/lab/automation/budgets.ts +78 -0
  313. package/src/lab/automation/config-persistence.ts +256 -0
  314. package/src/lab/automation/constants.ts +39 -0
  315. package/src/lab/automation/cooldown.ts +103 -0
  316. package/src/lab/automation/dispatch.ts +211 -0
  317. package/src/lab/automation/index.ts +13 -0
  318. package/src/lab/automation/orchestrator.ts +499 -0
  319. package/src/lab/automation/persistence.ts +512 -0
  320. package/src/lab/automation/planner.ts +371 -0
  321. package/src/lab/automation/policy.ts +136 -0
  322. package/src/lab/automation/queue.ts +191 -0
  323. package/src/lab/automation/recovery.ts +24 -0
  324. package/src/lab/automation/route-context.ts +21 -0
  325. package/src/lab/automation/run-key.ts +44 -0
  326. package/src/lab/automation/runs-query.ts +34 -0
  327. package/src/lab/automation/types.ts +160 -0
  328. package/src/lab/conformance/assertion.ts +325 -0
  329. package/src/lab/conformance/digest.ts +22 -0
  330. package/src/lab/conformance/executor.ts +741 -0
  331. package/src/lab/conformance/fixture-provider.ts +27 -0
  332. package/src/lab/conformance/fixtures/live-v1-cases.json +175 -0
  333. package/src/lab/conformance/fixtures/protocol-v1-cases.json +461 -0
  334. package/src/lab/conformance/harness-budget.ts +47 -0
  335. package/src/lab/conformance/index.ts +5 -0
  336. package/src/lab/conformance/jcs.ts +64 -0
  337. package/src/lab/conformance/json-pointer.ts +39 -0
  338. package/src/lab/conformance/manifest.ts +180 -0
  339. package/src/lab/conformance/mcp-stub.ts +179 -0
  340. package/src/lab/conformance/negative-controls.ts +164 -0
  341. package/src/lab/conformance/observation.ts +355 -0
  342. package/src/lab/conformance/runner.ts +68 -0
  343. package/src/lab/conformance/sse-normalize.ts +59 -0
  344. package/src/lab/conformance/suite-manifest.ts +78 -0
  345. package/src/lab/conformance/types.ts +214 -0
  346. package/src/lab/constants.ts +126 -0
  347. package/src/lab/digest.ts +64 -0
  348. package/src/lab/events/errors.ts +9 -0
  349. package/src/lab/events/limits.ts +117 -0
  350. package/src/lab/events/types.ts +229 -0
  351. package/src/lab/events/validate.ts +781 -0
  352. package/src/lab/fabric/constants.ts +40 -0
  353. package/src/lab/fabric/executor.ts +492 -0
  354. package/src/lab/fabric/index.ts +80 -0
  355. package/src/lab/fabric/manifest.ts +222 -0
  356. package/src/lab/fabric/observe.ts +489 -0
  357. package/src/lab/fabric/patch.ts +79 -0
  358. package/src/lab/fabric/producer-child.ts +139 -0
  359. package/src/lab/fabric/producer-isolate.ts +276 -0
  360. package/src/lab/fabric/producer-protocol.ts +61 -0
  361. package/src/lab/fabric/scratch.ts +439 -0
  362. package/src/lab/fabric/subject.ts +106 -0
  363. package/src/lab/fabric/types.ts +134 -0
  364. package/src/lab/fabric/verifier.ts +98 -0
  365. package/src/lab/index.ts +54 -0
  366. package/src/lab/ledger/artifact-refs.ts +127 -0
  367. package/src/lab/ledger/invalidation.ts +136 -0
  368. package/src/lab/ledger/purge.ts +310 -0
  369. package/src/lab/ledger/store.ts +532 -0
  370. package/src/lab/live/credential-lease.ts +53 -0
  371. package/src/lab/live/destination.ts +155 -0
  372. package/src/lab/live/executor.ts +336 -0
  373. package/src/lab/live/inert-tools.ts +56 -0
  374. package/src/lab/live/manifest.ts +85 -0
  375. package/src/lab/live/mcp-loopback.ts +57 -0
  376. package/src/lab/live/runner.ts +19 -0
  377. package/src/lab/live/sandbox.ts +61 -0
  378. package/src/lab/live/suite-manifest.ts +41 -0
  379. package/src/lab/live/transport.ts +118 -0
  380. package/src/lab/live/types.ts +197 -0
  381. package/src/lab/observe/from-conformance.ts +301 -0
  382. package/src/lab/observe/from-live.ts +117 -0
  383. package/src/lab/paths.ts +153 -0
  384. package/src/lab/projection/rebuild.ts +495 -0
  385. package/src/lab/projection/schema.ts +135 -0
  386. package/src/lab/projection/verdicts.ts +474 -0
  387. package/src/lab/projection/verification.ts +412 -0
  388. package/src/lab/public/bundle.ts +217 -0
  389. package/src/lab/public/community-authority.ts +175 -0
  390. package/src/lab/public/community-files.ts +29 -0
  391. package/src/lab/public/community.ts +479 -0
  392. package/src/lab/public/file-safety.ts +155 -0
  393. package/src/lab/public/ids.ts +26 -0
  394. package/src/lab/public/index.ts +16 -0
  395. package/src/lab/public/mutation-lock.ts +424 -0
  396. package/src/lab/public/operator.ts +353 -0
  397. package/src/lab/public/origin-purge.ts +79 -0
  398. package/src/lab/public/origin.ts +203 -0
  399. package/src/lab/public/privacy.ts +143 -0
  400. package/src/lab/public/private-file.ts +261 -0
  401. package/src/lab/public/project.ts +124 -0
  402. package/src/lab/public/purge-test-fault.ts +21 -0
  403. package/src/lab/public/purge.ts +223 -0
  404. package/src/lab/public/registry.ts +44 -0
  405. package/src/lab/public/revocation.ts +252 -0
  406. package/src/lab/public/signature.ts +243 -0
  407. package/src/lab/public/storage.ts +105 -0
  408. package/src/lab/public/strict-json.ts +206 -0
  409. package/src/lab/public/time.ts +26 -0
  410. package/src/lab/public/types.ts +172 -0
  411. package/src/lab/public/validate.ts +391 -0
  412. package/src/lab/query/catalog.ts +101 -0
  413. package/src/lab/query/connection.ts +107 -0
  414. package/src/lab/query/constants.ts +4 -0
  415. package/src/lab/query/cursor.ts +132 -0
  416. package/src/lab/query/dto-map.ts +277 -0
  417. package/src/lab/query/errors.ts +22 -0
  418. package/src/lab/query/freshness.ts +53 -0
  419. package/src/lab/query/index.ts +45 -0
  420. package/src/lab/query/latest-observation.ts +59 -0
  421. package/src/lab/query/passive-production.ts +159 -0
  422. package/src/lab/query/queries.ts +444 -0
  423. package/src/lab/query/types.ts +266 -0
  424. package/src/lab/subject/behavior-fingerprint.ts +77 -0
  425. package/src/lab/subject/installation-salt.ts +112 -0
  426. package/src/lab/subject/protocol-subject.ts +80 -0
  427. package/src/lab/subject/route-subject.ts +74 -0
  428. package/src/lib/admin-secrets.ts +24 -0
  429. package/src/lib/app-owned-memory-stores.ts +22 -0
  430. package/src/lib/bounded-body.ts +167 -11
  431. package/src/lib/bun-runtime.ts +125 -12
  432. package/src/lib/bun-stream-caps.ts +13 -9
  433. package/src/lib/codex-restart-contract.ts +120 -0
  434. package/src/lib/config-ownership.ts +26 -2
  435. package/src/lib/destination-policy.ts +65 -1
  436. package/src/lib/errors.ts +80 -5
  437. package/src/lib/fabric-task-execution-authority.ts +7 -0
  438. package/src/lib/fabric-task-host.ts +29 -0
  439. package/src/lib/lab-activation.ts +223 -0
  440. package/src/lib/lab-live-execution-authority.ts +13 -0
  441. package/src/lib/lab-live-host.ts +30 -0
  442. package/src/lib/lab-live-pinned-sender.ts +56 -0
  443. package/src/lib/lab-live-route-production.ts +130 -0
  444. package/src/lib/lab-passive-linker-registration.ts +26 -0
  445. package/src/lib/local-management-attestation.ts +51 -0
  446. package/src/lib/local-management-capability.ts +100 -0
  447. package/src/lib/local-provider-reload-contract.ts +100 -0
  448. package/src/lib/optional-shutdown-hooks.ts +57 -0
  449. package/src/lib/package-tree-integrity.ts +101 -0
  450. package/src/lib/pinned-http.ts +145 -26
  451. package/src/lib/process-control.ts +6 -2
  452. package/src/lib/provider-outbound.ts +49 -9
  453. package/src/lib/redact.ts +419 -3
  454. package/src/lib/self-launch-argv.ts +15 -0
  455. package/src/lib/server-resource-ownership.ts +71 -0
  456. package/src/lib/service-secrets.ts +15 -0
  457. package/src/lib/shadow-call.ts +35 -4
  458. package/src/lib/sse-decoder.ts +41 -0
  459. package/src/lib/state-store-registrations.ts +10 -2
  460. package/src/lib/system-restart-contract.ts +73 -0
  461. package/src/lib/token-estimate.ts +19 -2
  462. package/src/lib/tool-argument-integers.ts +253 -0
  463. package/src/lib/translator-budget.ts +44 -0
  464. package/src/lib/upstream-http-version.ts +57 -0
  465. package/src/lib/upstream-reachability.ts +95 -0
  466. package/src/lib/upstream-retry.ts +156 -3
  467. package/src/lib/windows-atomic-replace.ts +155 -0
  468. package/src/lib/windows-elevation.ts +70 -2
  469. package/src/lib/windows-secret-acl.ts +409 -69
  470. package/src/lib/windows-service-wrappers.ts +72 -0
  471. package/src/lib/windows-text.ts +106 -0
  472. package/src/lib/windows-user-principal.ts +341 -0
  473. package/src/lib/winsw.ts +33 -5
  474. package/src/oauth/account-import/google-antigravity-adapter.ts +74 -0
  475. package/src/oauth/account-import/index.ts +15 -0
  476. package/src/oauth/account-import/parser.ts +83 -0
  477. package/src/oauth/account-import/registry.ts +18 -0
  478. package/src/oauth/account-import/service.ts +75 -0
  479. package/src/oauth/account-import/types.ts +91 -0
  480. package/src/oauth/anthropic.ts +12 -1
  481. package/src/oauth/callback-server.ts +30 -4
  482. package/src/oauth/chatgpt.ts +12 -1
  483. package/src/oauth/cline.ts +203 -0
  484. package/src/oauth/command-code.ts +239 -0
  485. package/src/oauth/cursor.ts +46 -5
  486. package/src/oauth/generic-account-failover.ts +231 -0
  487. package/src/oauth/google-antigravity.ts +35 -3
  488. package/src/oauth/health.ts +20 -12
  489. package/src/oauth/index.ts +462 -71
  490. package/src/oauth/key-providers.ts +25 -0
  491. package/src/oauth/kimi.ts +25 -3
  492. package/src/oauth/kiro.ts +95 -6
  493. package/src/oauth/local-token-detect.ts +13 -2
  494. package/src/oauth/log.ts +3 -1
  495. package/src/oauth/login-cli.ts +88 -28
  496. package/src/oauth/nous.ts +798 -0
  497. package/src/oauth/open-browser-choice.ts +26 -0
  498. package/src/oauth/store.ts +133 -26
  499. package/src/oauth/token-guardian.ts +9 -3
  500. package/src/oauth/types.ts +15 -0
  501. package/src/pi/models.ts +2 -2
  502. package/src/providers/alibaba-region-migration.ts +1 -1
  503. package/src/providers/antigravity-models.ts +521 -31
  504. package/src/providers/auto-compact-budget.ts +65 -0
  505. package/src/providers/base-url-choices.ts +10 -0
  506. package/src/providers/codex-capacity.ts +292 -0
  507. package/src/providers/command-code-efforts.ts +176 -0
  508. package/src/providers/context-cap.ts +26 -8
  509. package/src/providers/cursor-pool.ts +72 -0
  510. package/src/providers/default-aliases.ts +65 -0
  511. package/src/providers/derive.ts +281 -6
  512. package/src/providers/fastwire.ts +507 -0
  513. package/src/providers/free-directory.ts +10 -7
  514. package/src/providers/google-vertex-location.ts +14 -0
  515. package/src/providers/key-failover.ts +71 -3
  516. package/src/providers/label.ts +35 -2
  517. package/src/providers/model-discovery-limits.ts +16 -0
  518. package/src/providers/model-discovery.ts +115 -22
  519. package/src/providers/model-presets.ts +119 -0
  520. package/src/providers/model-rename-migration.ts +255 -0
  521. package/src/providers/model-rename-startup.ts +28 -0
  522. package/src/providers/new-model-policy.ts +146 -0
  523. package/src/providers/openai-sidecar.ts +72 -4
  524. package/src/providers/openai-tier-startup.ts +31 -2
  525. package/src/providers/openai-tiers.ts +119 -4
  526. package/src/providers/openai-virtual-models.ts +1 -0
  527. package/src/providers/opencode-zen-rate-limit.ts +102 -0
  528. package/src/providers/provider-id-rewrite.ts +30 -0
  529. package/src/providers/quota.ts +1379 -40
  530. package/src/providers/registry.ts +1545 -112
  531. package/src/providers/request-pacing.ts +310 -0
  532. package/src/providers/service-tier.ts +277 -0
  533. package/src/providers/slug-codec.ts +94 -6
  534. package/src/providers/static-model-discovery.ts +86 -0
  535. package/src/providers/xai-responses-opt-in.ts +15 -0
  536. package/src/providers/xai-transport.ts +32 -4
  537. package/src/reasoning-effort.ts +68 -3
  538. package/src/responses/apply-patch-envelope.ts +63 -0
  539. package/src/responses/code-mode-helper-compat.ts +50 -0
  540. package/src/responses/compaction.ts +26 -1
  541. package/src/responses/custom-tool-compat.ts +384 -0
  542. package/src/responses/hosted-tool-policy.ts +9 -0
  543. package/src/responses/namespace-tool-compat.ts +435 -0
  544. package/src/responses/parser.ts +225 -38
  545. package/src/responses/provider-continuation.ts +98 -0
  546. package/src/responses/provider-opaque-metadata.ts +73 -0
  547. package/src/responses/reasoning-envelope.ts +9 -1
  548. package/src/responses/reasoning-replay-cache.ts +504 -0
  549. package/src/responses/schema.ts +12 -2
  550. package/src/responses/spill-store.ts +75 -10
  551. package/src/responses/state.ts +659 -31
  552. package/src/responses/thought-signature-replay.ts +364 -0
  553. package/src/responses/tool-search-compat.ts +301 -0
  554. package/src/responses/truncated-stop-reason.ts +60 -0
  555. package/src/responses/turn-termination.ts +107 -0
  556. package/src/router.ts +405 -31
  557. package/src/routing/analytics.ts +379 -0
  558. package/src/routing/capability.ts +244 -0
  559. package/src/routing/compatibility/assemble.ts +73 -0
  560. package/src/routing/compatibility/behavior.ts +278 -0
  561. package/src/routing/compatibility/catalog.ts +99 -0
  562. package/src/routing/compatibility/endpoint.ts +52 -0
  563. package/src/routing/compatibility/lab-evidence-provider.ts +130 -0
  564. package/src/routing/compatibility/policy.ts +181 -0
  565. package/src/routing/compatibility/provider-slot.ts +56 -0
  566. package/src/routing/compatibility/reader.ts +110 -0
  567. package/src/routing/compatibility/subject.ts +191 -0
  568. package/src/routing/compatibility/types.ts +64 -0
  569. package/src/routing/compatibility/version.ts +104 -0
  570. package/src/routing/cost.ts +77 -0
  571. package/src/routing/evaluator.ts +495 -0
  572. package/src/routing/health.ts +412 -0
  573. package/src/routing/history/cursor.ts +43 -0
  574. package/src/routing/history/indexer.ts +605 -0
  575. package/src/routing/history/schema.ts +72 -0
  576. package/src/routing/profile-namespace.ts +15 -0
  577. package/src/routing/profile.ts +547 -0
  578. package/src/routing/quota.ts +155 -0
  579. package/src/routing/request-evidence.ts +45 -0
  580. package/src/routing/trace.ts +776 -0
  581. package/src/server/adapter-resolve.ts +2 -29
  582. package/src/server/auth-cors.ts +289 -48
  583. package/src/server/background-lifecycle.ts +182 -0
  584. package/src/server/chat-completions.ts +154 -72
  585. package/src/server/chat-native-sse.ts +331 -0
  586. package/src/server/chat-native.ts +445 -0
  587. package/src/server/claude-messages.ts +160 -44
  588. package/src/server/direct-local-http.ts +347 -0
  589. package/src/server/effort-policy.ts +18 -0
  590. package/src/server/github-copilot-responses-repair.ts +338 -0
  591. package/src/server/gui-static.ts +39 -10
  592. package/src/server/images.ts +94 -12
  593. package/src/server/index.ts +1021 -190
  594. package/src/server/lifecycle.ts +336 -14
  595. package/src/server/live.ts +136 -17
  596. package/src/server/local-management-read-client.ts +90 -0
  597. package/src/server/local-provider-reload-client.ts +137 -0
  598. package/src/server/management/agent-settings-routes.ts +433 -116
  599. package/src/server/management/api-key-usage.ts +31 -5
  600. package/src/server/management/body.ts +6 -0
  601. package/src/server/management/codex-prompt-routes.ts +570 -0
  602. package/src/server/management/combo-routes.ts +64 -25
  603. package/src/server/management/config-routes.ts +511 -51
  604. package/src/server/management/context.ts +89 -2
  605. package/src/server/management/integration-routes.ts +498 -0
  606. package/src/server/management/lab-automation-routes.ts +206 -0
  607. package/src/server/management/lab-routes.ts +563 -0
  608. package/src/server/management/logs-usage-routes.ts +127 -52
  609. package/src/server/management/model-routes.ts +461 -133
  610. package/src/server/management/model-rows.ts +167 -0
  611. package/src/server/management/native-integration-routes.ts +770 -0
  612. package/src/server/management/oauth-account-routes.ts +90 -8
  613. package/src/server/management/provider-capability-config.ts +48 -0
  614. package/src/server/management/provider-routes.ts +836 -159
  615. package/src/server/management/request-history-routes.ts +191 -0
  616. package/src/server/management/route-registry.ts +332 -0
  617. package/src/server/management/routing-analytics-routes.ts +74 -0
  618. package/src/server/management/routing-profile-routes.ts +380 -0
  619. package/src/server/management/shared.ts +27 -11
  620. package/src/server/management/sidebar-routes.ts +47 -31
  621. package/src/server/management/storage-log-guard-routes.ts +186 -0
  622. package/src/server/management/sync-response.ts +69 -0
  623. package/src/server/management/system-restart.ts +289 -33
  624. package/src/server/management/system-routes.ts +77 -0
  625. package/src/server/management/usage-summary-cache.ts +9 -1
  626. package/src/server/management/vision-sidecar-options.ts +167 -0
  627. package/src/server/management/web-search-sidecar-options.ts +120 -0
  628. package/src/server/management-api.ts +126 -23
  629. package/src/server/management-auth.ts +220 -5
  630. package/src/server/passive-route-linker.ts +66 -0
  631. package/src/server/port-reclaim.ts +1 -1
  632. package/src/server/ports.ts +41 -1
  633. package/src/server/proxy-liveness.ts +161 -10
  634. package/src/server/readiness.ts +99 -0
  635. package/src/server/relay-eager.ts +221 -54
  636. package/src/server/relay.ts +479 -87
  637. package/src/server/request-decompress.ts +113 -6
  638. package/src/server/request-log-conversation.ts +51 -0
  639. package/src/server/request-log.ts +298 -31
  640. package/src/server/responses/agent-task-recovery-cache.ts +143 -0
  641. package/src/server/responses/agent-task-recovery.ts +465 -0
  642. package/src/server/responses/codex-auth-error.ts +55 -0
  643. package/src/server/responses/collaboration.ts +239 -36
  644. package/src/server/responses/combo-stream-preflight.ts +178 -0
  645. package/src/server/responses/compact.ts +444 -72
  646. package/src/server/responses/core.ts +3579 -436
  647. package/src/server/responses/empty-completion-guard.ts +333 -0
  648. package/src/server/responses/encrypted-payload.ts +62 -39
  649. package/src/server/responses/fetch-helpers.ts +89 -99
  650. package/src/server/responses/input-admission.ts +187 -0
  651. package/src/server/responses/pacing-overload.ts +13 -0
  652. package/src/server/responses/passthrough-error.ts +33 -9
  653. package/src/server/responses/policy-fallback.ts +178 -0
  654. package/src/server/responses/responses-field-backfill.ts +343 -0
  655. package/src/server/responses/terminal-guard.ts +26 -5
  656. package/src/server/responses/upstream-error.ts +5 -0
  657. package/src/server/responses/ws-upstream.ts +381 -0
  658. package/src/server/responses-custom-tool-repair.ts +363 -0
  659. package/src/server/responses-item-id-repair.ts +54 -6
  660. package/src/server/responses-json-events.ts +90 -0
  661. package/src/server/responses-model-rewrite.ts +29 -0
  662. package/src/server/responses-reasoning-summary-rewrite.ts +178 -0
  663. package/src/server/responses-snapshot-repair.ts +621 -0
  664. package/src/server/responses-terminal-repair.ts +363 -0
  665. package/src/server/responses-tool-search-repair.ts +267 -0
  666. package/src/server/responses-undeclared-tool-guard.ts +376 -0
  667. package/src/server/responses.ts +18 -2
  668. package/src/server/search.ts +78 -13
  669. package/src/server/sse-frame-buffer.ts +319 -0
  670. package/src/server/sse-payload-rewrite.ts +110 -22
  671. package/src/server/startup-action-control.ts +8 -1
  672. package/src/server/startup-health-cache.ts +19 -1
  673. package/src/server/system-env.ts +80 -9
  674. package/src/server/ws-bridge.ts +53 -40
  675. package/src/service-manager-probe.ts +892 -0
  676. package/src/service.ts +1153 -94
  677. package/src/sidecar/auth.ts +92 -0
  678. package/src/sidecar/candidates.ts +83 -0
  679. package/src/storage/cleanup.ts +2 -2
  680. package/src/storage/policy-job.ts +14 -4
  681. package/src/storage/policy.ts +88 -23
  682. package/src/storage/scanner.ts +1 -1
  683. package/src/storage/worker-lifecycle.ts +14 -14
  684. package/src/tray/windows-tray.ps1 +83 -9
  685. package/src/tray/windows.ts +43 -16
  686. package/src/types/accounts.ts +37 -0
  687. package/src/types/config.ts +911 -0
  688. package/src/types/provider.ts +614 -0
  689. package/src/types/request.ts +397 -0
  690. package/src/types/tools.ts +236 -0
  691. package/src/types/wire.ts +80 -0
  692. package/src/types.ts +107 -1237
  693. package/src/update/index.ts +37 -23
  694. package/src/update/job.ts +445 -68
  695. package/src/update/notify.ts +12 -6
  696. package/src/update/npm-cache-preflight.d.mts +47 -0
  697. package/src/update/npm-cache-preflight.mjs +201 -0
  698. package/src/update/transactional-install.d.mts +22 -0
  699. package/src/update/transactional-install.mjs +266 -0
  700. package/src/usage/cost.ts +0 -0
  701. package/src/usage/expected-prices.ts +287 -16
  702. package/src/usage/log.ts +666 -50
  703. package/src/usage/summary.ts +388 -17
  704. package/src/usage/user-cost-overlay-reconciler.ts +313 -0
  705. package/src/usage/user-cost-overlays.ts +314 -0
  706. package/src/vision/anthropic-describe.ts +10 -6
  707. package/src/vision/backends.ts +97 -0
  708. package/src/vision/describe.ts +27 -16
  709. package/src/vision/eligibility.ts +250 -0
  710. package/src/vision/index.ts +238 -24
  711. package/src/vision/reasoning.ts +55 -0
  712. package/src/vision/routed-describe.ts +175 -0
  713. package/src/vision/timeout-bounds.ts +9 -0
  714. package/src/web-search/anthropic-executor.ts +13 -7
  715. package/src/web-search/backends.ts +108 -0
  716. package/src/web-search/exa-executor.ts +119 -0
  717. package/src/web-search/executor.ts +21 -6
  718. package/src/web-search/gemini-executor.ts +141 -0
  719. package/src/web-search/index.ts +150 -15
  720. package/src/web-search/loop.ts +284 -54
  721. package/src/web-search/parse.ts +125 -30
  722. package/src/web-search/sources.ts +60 -0
  723. package/src/web-search/xai-executor.ts +219 -0
  724. package/gui/dist/assets/index-DTpMHS4F.js +0 -67
  725. package/gui/dist/assets/index-ZNVDE3C7.css +0 -1
  726. package/gui/dist/provider-icons/antigravity.svg +0 -1
  727. package/gui/dist/provider-icons/claude.svg +0 -1
  728. package/gui/dist/provider-icons/copilot.svg +0 -1
  729. package/gui/dist/provider-icons/cursor.svg +0 -2
  730. package/gui/dist/provider-icons/gemini.svg +0 -1
  731. package/gui/dist/provider-icons/grok-color.svg +0 -1
  732. package/gui/dist/provider-icons/kiro.svg +0 -14
  733. package/src/cli/internal-dispatch.ts +0 -20
@@ -0,0 +1,720 @@
1
+ /**
2
+ * CODEX_HOME-keyed transition state and coordinator transaction ownership.
3
+ *
4
+ * The original JSON read/compare/replace was called a CAS while native and
5
+ * history writers held different locks. It was not one: an old Worker could
6
+ * replace N+1 with stale N. This module owns the SQLite row, the conditional
7
+ * UPDATE, and the opaque one-shot capability backed by an already-open
8
+ * `BEGIN IMMEDIATE` transaction.
9
+ *
10
+ * Design record: devlog/_fin/260804_codex_write_substrate/005_contract.md §1.
11
+ */
12
+ import { randomUUID } from "node:crypto";
13
+ import {
14
+ chmodSync,
15
+ closeSync,
16
+ fsyncSync,
17
+ linkSync,
18
+ lstatSync,
19
+ openSync,
20
+ realpathSync,
21
+ unlinkSync,
22
+ } from "node:fs";
23
+ import { basename, dirname, join } from "node:path";
24
+
25
+ import { Database } from "bun:sqlite";
26
+
27
+ import type {
28
+ BeginCodexTransition,
29
+ CodexCoordinatorTransaction,
30
+ CodexCoordinatorTransactionController,
31
+ CodexHistoryState,
32
+ CodexTransitionState,
33
+ CodexTransitionVersion,
34
+ CommitExpectation,
35
+ ReadCodexTransitionState,
36
+ TransitionStateRead,
37
+ TransitionStateUpdate,
38
+ UpdateCodexHistoryTransition,
39
+ } from "./convergence-types";
40
+ import { resolveCodexHomeDir } from "./home";
41
+ import { readIntegrationRecord } from "./integration-record";
42
+ import { classifyNativeRoutedResidue } from "./native-residue";
43
+ import {
44
+ CodexUserIdentityRefusal,
45
+ resolveCodexCoordinatorDatabasePath,
46
+ resolveEffectiveUserIdentity,
47
+ samePathIdentity,
48
+ } from "./user-identity";
49
+
50
+ export const CODEX_COORDINATOR_SCHEMA_VERSION = 1;
51
+ const DURABLE_HISTORY_STATUSES = new Set(["adoption-pending", "converged", "pending", "running", "blocked", "unknown"]);
52
+ const DURABLE_HISTORY_REASONS = new Set([
53
+ "db-busy",
54
+ "permission",
55
+ "unreadable",
56
+ "schema",
57
+ "timeout",
58
+ "shutdown-cancelled",
59
+ "worker-died",
60
+ "overtaken",
61
+ "record-write-failed",
62
+ ]);
63
+
64
+ const CREATE_TRANSITION_TABLE = `
65
+ CREATE TABLE IF NOT EXISTS codex_transition_state (
66
+ singleton INTEGER PRIMARY KEY CHECK (singleton = 1),
67
+ native_generation INTEGER NOT NULL CHECK (native_generation >= 0),
68
+ current_tx_id TEXT,
69
+ history_status TEXT NOT NULL,
70
+ history_reason TEXT,
71
+ history_attempts INTEGER NOT NULL CHECK (history_attempts >= 0),
72
+ history_next_retry_at TEXT,
73
+ history_tx_id TEXT,
74
+ history_direction TEXT CHECK (history_direction IN ('apply', 'remove')),
75
+ history_authority_snapshot_id TEXT,
76
+ history_pending_rows INTEGER,
77
+ history_backup_entries INTEGER,
78
+ updated_at TEXT NOT NULL,
79
+ CHECK (history_status IN ('adoption-pending', 'converged', 'pending', 'running', 'blocked', 'unknown')),
80
+ CHECK (history_reason IS NULL OR history_reason IN
81
+ ('db-busy', 'permission', 'unreadable', 'schema', 'timeout',
82
+ 'shutdown-cancelled', 'worker-died', 'overtaken', 'record-write-failed')),
83
+ CHECK (history_pending_rows IS NULL OR history_pending_rows >= 0),
84
+ CHECK (history_backup_entries IS NULL OR history_backup_entries >= 0),
85
+ CHECK ((native_generation = 0 AND current_tx_id IS NULL)
86
+ OR (native_generation > 0 AND length(trim(current_tx_id)) > 0)),
87
+ CHECK ((native_generation = 0
88
+ AND history_status = 'unknown'
89
+ AND history_tx_id IS NULL
90
+ AND history_direction IS NULL
91
+ AND history_authority_snapshot_id IS NULL)
92
+ OR (native_generation = 0
93
+ AND history_status = 'adoption-pending'
94
+ AND length(trim(history_tx_id)) > 0
95
+ AND history_direction IS NOT NULL
96
+ AND length(trim(history_authority_snapshot_id)) > 0)
97
+ OR (native_generation > 0
98
+ AND history_tx_id = current_tx_id
99
+ AND history_direction IS NOT NULL
100
+ AND length(trim(history_authority_snapshot_id)) > 0)),
101
+ CHECK (native_generation > 0 OR history_status = 'adoption-pending' OR
102
+ (history_status = 'unknown'
103
+ AND history_reason IS NULL
104
+ AND history_attempts = 0
105
+ AND history_next_retry_at IS NULL
106
+ AND history_pending_rows IS NULL
107
+ AND history_backup_entries IS NULL))
108
+ )`;
109
+
110
+ const INITIALIZE_TRANSITION_ROW = `
111
+ INSERT OR IGNORE INTO codex_transition_state (
112
+ singleton, native_generation, current_tx_id,
113
+ history_status, history_reason, history_attempts,
114
+ history_next_retry_at, history_tx_id, history_direction,
115
+ history_authority_snapshot_id, history_pending_rows,
116
+ history_backup_entries, updated_at
117
+ ) VALUES (1, 0, NULL, 'unknown', NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, ?)`;
118
+
119
+ const INITIALIZE_ADOPTION_ROW = `
120
+ INSERT INTO codex_transition_state (
121
+ singleton, native_generation, current_tx_id,
122
+ history_status, history_reason, history_attempts,
123
+ history_next_retry_at, history_tx_id, history_direction,
124
+ history_authority_snapshot_id, history_pending_rows,
125
+ history_backup_entries, updated_at
126
+ ) VALUES (1, 0, NULL, 'adoption-pending', NULL, 0, NULL, ?, ?, ?, NULL, NULL, ?)`;
127
+
128
+ const SELECT_TRANSITION_ROW = `
129
+ SELECT native_generation, current_tx_id,
130
+ history_status, history_reason, history_attempts,
131
+ history_next_retry_at, history_tx_id, history_direction,
132
+ history_authority_snapshot_id, history_pending_rows,
133
+ history_backup_entries
134
+ FROM codex_transition_state
135
+ WHERE singleton = 1`;
136
+
137
+ const BEGIN_TRANSITION = `
138
+ UPDATE codex_transition_state
139
+ SET native_generation = ?, current_tx_id = ?,
140
+ history_status = 'pending', history_reason = NULL,
141
+ history_attempts = 0, history_next_retry_at = ?, history_tx_id = ?,
142
+ history_direction = ?, history_authority_snapshot_id = ?,
143
+ history_pending_rows = NULL, history_backup_entries = NULL,
144
+ updated_at = ?
145
+ WHERE singleton = 1
146
+ AND native_generation = ?
147
+ AND current_tx_id IS ?`;
148
+
149
+ const UPDATE_HISTORY = `
150
+ UPDATE codex_transition_state
151
+ SET history_status = ?, history_reason = ?, history_attempts = ?,
152
+ history_next_retry_at = ?, history_tx_id = ?,
153
+ history_pending_rows = ?, history_backup_entries = ?, updated_at = ?
154
+ WHERE singleton = 1
155
+ AND native_generation = ?
156
+ AND current_tx_id IS ?
157
+ AND history_tx_id IS ?
158
+ AND (native_generation = 0 OR history_direction IS NOT NULL)`;
159
+
160
+ interface TransitionRow {
161
+ native_generation: unknown;
162
+ current_tx_id: unknown;
163
+ history_status: unknown;
164
+ history_reason: unknown;
165
+ history_attempts: unknown;
166
+ history_next_retry_at: unknown;
167
+ history_tx_id: unknown;
168
+ history_direction: unknown;
169
+ history_authority_snapshot_id: unknown;
170
+ history_pending_rows: unknown;
171
+ history_backup_entries: unknown;
172
+ }
173
+
174
+ const codexCoordinatorTransactionBrand: unique symbol = Symbol("CodexCoordinatorTransaction");
175
+
176
+ interface BrandedCodexCoordinatorTransaction extends CodexCoordinatorTransaction {
177
+ readonly [codexCoordinatorTransactionBrand]: true;
178
+ }
179
+
180
+ export class CodexCoordinatorTransactionError extends Error {
181
+ constructor(message: string, options?: ErrorOptions) {
182
+ super(message, options);
183
+ this.name = "CodexCoordinatorTransactionError";
184
+ }
185
+ }
186
+
187
+ class CodexCoordinatorLegacyAmbiguousError extends CodexCoordinatorTransactionError {
188
+ constructor(message: string) {
189
+ super(message);
190
+ this.name = "CodexCoordinatorLegacyAmbiguousError";
191
+ }
192
+ }
193
+
194
+ function errorCode(error: unknown): string {
195
+ return error && typeof error === "object" && "code" in error
196
+ ? String((error as { code?: unknown }).code)
197
+ : "";
198
+ }
199
+
200
+ function isBusy(error: unknown): boolean {
201
+ const code = errorCode(error);
202
+ const message = error instanceof Error ? error.message : String(error);
203
+ return code === "SQLITE_BUSY" || code === "SQLITE_LOCKED" || /database (?:is|table is) locked/i.test(message);
204
+ }
205
+
206
+ function isNonNegativeInteger(value: unknown): value is number {
207
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
208
+ }
209
+
210
+ function nullableString(value: unknown): value is string | null {
211
+ return value === null || typeof value === "string";
212
+ }
213
+
214
+ function nullableCount(value: unknown): value is number | null {
215
+ return value === null || isNonNegativeInteger(value);
216
+ }
217
+
218
+ function rowToState(row: TransitionRow | null): CodexTransitionState {
219
+ if (!row) throw new CodexCoordinatorTransactionError("The coordinator transition row is missing.");
220
+ if (!isNonNegativeInteger(row.native_generation)
221
+ || !nullableString(row.current_tx_id)
222
+ || typeof row.history_status !== "string"
223
+ || !DURABLE_HISTORY_STATUSES.has(row.history_status)
224
+ || !nullableString(row.history_reason)
225
+ || (row.history_reason !== null && !DURABLE_HISTORY_REASONS.has(row.history_reason))
226
+ || !isNonNegativeInteger(row.history_attempts)
227
+ || !nullableString(row.history_next_retry_at)
228
+ || !nullableString(row.history_tx_id)
229
+ || !nullableString(row.history_direction)
230
+ || !nullableString(row.history_authority_snapshot_id)
231
+ || !nullableCount(row.history_pending_rows)
232
+ || !nullableCount(row.history_backup_entries)) {
233
+ throw new CodexCoordinatorTransactionError("The coordinator transition row is malformed.");
234
+ }
235
+
236
+ const generation = row.native_generation;
237
+ if (generation === 0) {
238
+ const ordinaryInitial = row.history_status === "unknown"
239
+ && row.history_tx_id === null
240
+ && row.history_direction === null
241
+ && row.history_authority_snapshot_id === null;
242
+ const adoptionInitial = row.history_status === "adoption-pending"
243
+ && Boolean(row.history_tx_id?.trim())
244
+ && (row.history_direction === "apply" || row.history_direction === "remove")
245
+ && Boolean(row.history_authority_snapshot_id?.trim());
246
+ if (row.current_tx_id !== null || (!ordinaryInitial && !adoptionInitial)) {
247
+ throw new CodexCoordinatorTransactionError("The initial coordinator row contains transition metadata.");
248
+ }
249
+ } else if (!row.current_tx_id?.trim()
250
+ || row.history_tx_id !== row.current_tx_id
251
+ || (row.history_direction !== "apply" && row.history_direction !== "remove")
252
+ || !row.history_authority_snapshot_id?.trim()) {
253
+ throw new CodexCoordinatorTransactionError("The positive coordinator row lacks its complete history schedule.");
254
+ }
255
+
256
+ const history: CodexHistoryState = {
257
+ status: row.history_status as Exclude<CodexHistoryState["status"], "not-evaluated">,
258
+ attempts: row.history_attempts,
259
+ nextRetryAt: row.history_next_retry_at,
260
+ txId: row.history_tx_id,
261
+ pendingRows: row.history_pending_rows,
262
+ backupEntries: row.history_backup_entries,
263
+ ...(row.history_reason === null ? {} : { reason: row.history_reason as NonNullable<CodexHistoryState["reason"]> }),
264
+ };
265
+ return {
266
+ nativeGeneration: generation,
267
+ currentTxId: row.current_tx_id,
268
+ history,
269
+ historySchedule: generation === 0 && row.history_status !== "adoption-pending" ? null : {
270
+ direction: row.history_direction as "apply" | "remove",
271
+ authoritySnapshotId: row.history_authority_snapshot_id as string,
272
+ },
273
+ };
274
+ }
275
+
276
+ export type CodexCoordinatorAdoptionCheckpoint = "temp-created" | "temp-committed" | "published";
277
+
278
+ export interface CodexCoordinatorAdoptionOptions {
279
+ readonly direction: "apply" | "remove";
280
+ readonly onCheckpoint?: (checkpoint: CodexCoordinatorAdoptionCheckpoint) => void;
281
+ }
282
+
283
+ function fsyncFile(path: string): void {
284
+ // Writable fd on purpose. Windows FlushFileBuffers needs GENERIC_WRITE;
285
+ // openSync(path, "r") is GENERIC_READ only and fails with EPERM (measured on
286
+ // Windows 11 25H2 / bun 1.3.14). prompt-journal.ts uses the same "r+" open.
287
+ const fd = openSync(path, "r+");
288
+ try { fsyncSync(fd); } finally { closeSync(fd); }
289
+ }
290
+
291
+ function fsyncDir(path: string): void {
292
+ // POSIX directory fsync is O_RDONLY. O_RDWR ("r+") is EISDIR.
293
+ const fd = openSync(path, "r");
294
+ try { fsyncSync(fd); } finally { closeSync(fd); }
295
+ }
296
+
297
+ function publishAdoptionDatabase(
298
+ finalDatabasePath: string,
299
+ options: CodexCoordinatorAdoptionOptions,
300
+ ): void {
301
+ const parent = dirname(finalDatabasePath);
302
+ const tempPath = join(parent, `.${basename(finalDatabasePath)}.adopt-${process.pid}-${randomUUID()}.tmp`);
303
+ let tempPresent = false;
304
+ try {
305
+ const fd = openSync(tempPath, "wx", 0o600);
306
+ closeSync(fd);
307
+ tempPresent = true;
308
+ options.onCheckpoint?.("temp-created");
309
+
310
+ const temp = new Database(tempPath, { readwrite: true, create: false });
311
+ try {
312
+ temp.exec("PRAGMA journal_mode = DELETE; BEGIN IMMEDIATE");
313
+ temp.exec(CREATE_TRANSITION_TABLE);
314
+ temp.query(INITIALIZE_ADOPTION_ROW).run(
315
+ randomUUID(),
316
+ options.direction,
317
+ randomUUID(),
318
+ new Date().toISOString(),
319
+ );
320
+ temp.exec(`PRAGMA user_version = ${CODEX_COORDINATOR_SCHEMA_VERSION}; COMMIT`);
321
+ readCodexCoordinatorState(temp);
322
+ } catch (error) {
323
+ try { temp.exec("ROLLBACK"); } catch { /* commit may already have completed */ }
324
+ throw error;
325
+ } finally {
326
+ temp.close();
327
+ }
328
+ fsyncFile(tempPath);
329
+ options.onCheckpoint?.("temp-committed");
330
+
331
+ linkSync(tempPath, finalDatabasePath);
332
+ options.onCheckpoint?.("published");
333
+ if (process.platform !== "win32") fsyncDir(parent);
334
+ } catch (error) {
335
+ if (errorCode(error) !== "EEXIST") throw error;
336
+ } finally {
337
+ if (tempPresent) {
338
+ try { unlinkSync(tempPath); } catch (error) {
339
+ if (errorCode(error) !== "ENOENT") throw error;
340
+ }
341
+ }
342
+ }
343
+ }
344
+
345
+ export function readCodexCoordinatorState(database: Database): CodexTransitionState {
346
+ const row = database.query<TransitionRow, []>(SELECT_TRANSITION_ROW).get();
347
+ return rowToState(row);
348
+ }
349
+
350
+ function validateHistoryWrite(expected: CodexTransitionVersion, history: CodexHistoryState): void {
351
+ if (history.status === "not-evaluated" || !DURABLE_HISTORY_STATUSES.has(history.status)) {
352
+ throw new CodexCoordinatorTransactionError("Ephemeral history state cannot be persisted.");
353
+ }
354
+ if (!isNonNegativeInteger(history.attempts)
355
+ || !nullableCount(history.pendingRows)
356
+ || !nullableCount(history.backupEntries)
357
+ || (history.reason !== undefined && !DURABLE_HISTORY_REASONS.has(history.reason))) {
358
+ throw new CodexCoordinatorTransactionError("The history update is malformed.");
359
+ }
360
+ if (history.txId !== expected.currentTxId) {
361
+ throw new CodexCoordinatorTransactionError("The history update does not belong to the expected transition.");
362
+ }
363
+ }
364
+
365
+ /**
366
+ * The missing-row incident proved that absence is not authority: installing
367
+ * `{0,null}` over a legacy JSON pair or routed native bytes loses the only
368
+ * evidence that an interrupted transition still needs salvage.
369
+ */
370
+ function assertInitialStateCanBeCreated(): void {
371
+ const integration = readIntegrationRecord();
372
+ if (integration.kind === "invalid") {
373
+ throw new CodexCoordinatorLegacyAmbiguousError(
374
+ "A missing coordinator row cannot be initialized over legacy or invalid Codex integration state.",
375
+ );
376
+ }
377
+ if (classifyNativeRoutedResidue().kind !== "clean") {
378
+ throw new CodexCoordinatorLegacyAmbiguousError(
379
+ "A missing coordinator row cannot be initialized while native Codex routing residue exists.",
380
+ );
381
+ }
382
+ }
383
+
384
+ function initialize(database: Database, databaseWasAbsent: boolean): void {
385
+ const version = database.query<{ user_version: number }, []>("PRAGMA user_version").get()?.user_version;
386
+ if (version !== 0 && version !== CODEX_COORDINATOR_SCHEMA_VERSION) {
387
+ throw new CodexCoordinatorTransactionError("The coordinator database schema version is unsupported.");
388
+ }
389
+ if (!databaseWasAbsent && version === 0) {
390
+ throw new CodexCoordinatorLegacyAmbiguousError(
391
+ "An existing unversioned coordinator database cannot be adopted automatically.",
392
+ );
393
+ }
394
+ database.exec(CREATE_TRANSITION_TABLE);
395
+ const existing = database.query<TransitionRow, []>(SELECT_TRANSITION_ROW).get();
396
+ if (!existing && !databaseWasAbsent) {
397
+ throw new CodexCoordinatorLegacyAmbiguousError(
398
+ "The existing coordinator database has no authoritative transition row.",
399
+ );
400
+ }
401
+ if (!existing) {
402
+ assertInitialStateCanBeCreated();
403
+ database.query(INITIALIZE_TRANSITION_ROW).run(new Date().toISOString());
404
+ }
405
+ if (version === 0) database.exec(`PRAGMA user_version = ${CODEX_COORDINATOR_SCHEMA_VERSION}`);
406
+ readCodexCoordinatorState(database);
407
+ }
408
+
409
+ function createCapability(
410
+ database: Database,
411
+ onResult: (result: TransitionStateUpdate) => void,
412
+ ): BrandedCodexCoordinatorTransaction {
413
+ let consumed = false;
414
+ return {
415
+ [codexCoordinatorTransactionBrand]: true,
416
+ beginTransition(expected, next) {
417
+ if (consumed) {
418
+ throw new CodexCoordinatorTransactionError("The coordinator capability has already been consumed.");
419
+ }
420
+ consumed = true;
421
+ if (!isNonNegativeInteger(expected.nativeGeneration)
422
+ || (expected.currentTxId !== null && !expected.currentTxId.trim())
423
+ || !next.txId.trim()
424
+ || (next.direction !== "apply" && next.direction !== "remove")
425
+ || !next.authoritySnapshotId.trim()) {
426
+ throw new CodexCoordinatorTransactionError("The transition update is malformed.");
427
+ }
428
+
429
+ const result = database.query(BEGIN_TRANSITION).run(
430
+ expected.nativeGeneration + 1,
431
+ next.txId,
432
+ next.nextRetryAt,
433
+ next.txId,
434
+ next.direction,
435
+ next.authoritySnapshotId,
436
+ new Date().toISOString(),
437
+ expected.nativeGeneration,
438
+ expected.currentTxId,
439
+ );
440
+ const state = readCodexCoordinatorState(database);
441
+ const update: TransitionStateUpdate = result.changes === 1
442
+ ? { kind: "updated", state }
443
+ : { kind: "conflict", current: state };
444
+ onResult(update);
445
+ return update;
446
+ },
447
+ };
448
+ }
449
+
450
+ export function openCodexCoordinatorTransaction(
451
+ finalDatabasePath: string,
452
+ adoption?: CodexCoordinatorAdoptionOptions,
453
+ ): CodexCoordinatorTransactionController {
454
+ let database: Database | undefined;
455
+ let transactionOpen = false;
456
+ let closed = false;
457
+ let lastResult: TransitionStateUpdate | undefined;
458
+ let initialIdentity: string | undefined;
459
+ let databaseWasAbsent = false;
460
+ let databaseWasEmpty = false;
461
+
462
+ try {
463
+ try {
464
+ const before = lstatSync(finalDatabasePath);
465
+ if (before.isSymbolicLink() || !before.isFile()) {
466
+ throw new CodexUserIdentityRefusal("The coordinator database path is not a real file.");
467
+ }
468
+ // sqlite3_open_v2(..., SQLITE_OPEN_CREATE) makes the pathname visible
469
+ // before the first schema write. A racing process can therefore observe a
470
+ // real but zero-byte file that carries no coordinator authority yet. Treat
471
+ // that exact state like ENOENT; any non-empty unversioned database remains
472
+ // legacy-ambiguous below.
473
+ databaseWasEmpty = before.size === 0;
474
+ if (process.platform !== "win32") {
475
+ const uid = process.getuid?.();
476
+ // Ownership is decided here; MODE is not.
477
+ //
478
+ // Two processes reaching first use together both observe ENOENT, and the
479
+ // loser can lstat the winner's file in the window between its creation
480
+ // and its chmod. Refusing on mode here read as a permission problem when
481
+ // it was a schedule — a real 1-in-12 flake on a 16-core box. Our own file
482
+ // is ours to narrow, so the mode decision moves below the open, where it
483
+ // can tighten once and then judge the settled state. A file owned by
484
+ // somebody else is still refused immediately: that is not a race, and no
485
+ // amount of waiting makes it ours.
486
+ if (uid === undefined || before.uid !== uid) {
487
+ throw new CodexUserIdentityRefusal(
488
+ "The coordinator database has unsafe ownership or permissions.",
489
+ );
490
+ }
491
+ }
492
+ } catch (cause) {
493
+ if (errorCode(cause) !== "ENOENT") throw cause;
494
+ databaseWasAbsent = true;
495
+ }
496
+ if (databaseWasAbsent && adoption) {
497
+ publishAdoptionDatabase(finalDatabasePath, adoption);
498
+ databaseWasAbsent = false;
499
+ }
500
+ database = new Database(finalDatabasePath, { create: true });
501
+ if (databaseWasAbsent) {
502
+ try { chmodSync(finalDatabasePath, 0o600); } catch { /* Windows applies ACLs in WP11. */ }
503
+ }
504
+ // Re-check ownership and mode AFTER the open, not only before it.
505
+ //
506
+ // Two processes reaching first use together both see ENOENT, and the loser
507
+ // opens the winner's file in the window before the winner's chmod lands. Its
508
+ // pre-open check had already passed (the file did not exist), so without this
509
+ // the loser refused with `unsafe-path` — a real flake, reproduced 1-in-12 on
510
+ // a 16-core box, that read as a permission problem when it was a schedule.
511
+ //
512
+ // Narrowing our own descriptor's mode is safe and idempotent; a file that is
513
+ // still wrong afterwards is genuinely wrong, not merely early.
514
+ if (process.platform !== "win32") {
515
+ const uid = process.getuid?.();
516
+ let current = lstatSync(finalDatabasePath);
517
+ if ((current.mode & 0o777) !== 0o600) {
518
+ try { chmodSync(finalDatabasePath, 0o600); } catch { /* refused below */ }
519
+ current = lstatSync(finalDatabasePath);
520
+ }
521
+ if (uid === undefined || current.uid !== uid || (current.mode & 0o777) !== 0o600) {
522
+ throw new CodexUserIdentityRefusal(
523
+ "The coordinator database has unsafe ownership or permissions.",
524
+ );
525
+ }
526
+ }
527
+ const opened = lstatSync(finalDatabasePath);
528
+ if (opened.isSymbolicLink() || !opened.isFile()) {
529
+ throw new CodexUserIdentityRefusal("The coordinator database path changed during open.");
530
+ }
531
+ initialIdentity = `${opened.dev}:${opened.ino}`;
532
+ database.exec("PRAGMA busy_timeout = 0; PRAGMA locking_mode = NORMAL; BEGIN IMMEDIATE");
533
+ transactionOpen = true;
534
+ initialize(database, databaseWasAbsent || databaseWasEmpty);
535
+ } catch (cause) {
536
+ if (transactionOpen) {
537
+ try { database?.exec("ROLLBACK"); } catch { /* close releases the transaction */ }
538
+ }
539
+ try { database?.close(); } catch { /* acquisition already failed */ }
540
+ throw cause;
541
+ }
542
+
543
+ const db = database;
544
+ const requireOpen = (): void => {
545
+ if (closed || !transactionOpen) throw new CodexCoordinatorTransactionError("The coordinator transaction is closed.");
546
+ };
547
+ const assertStablePath = (): void => {
548
+ requireOpen();
549
+ const entry = lstatSync(finalDatabasePath);
550
+ if (entry.isSymbolicLink() || !entry.isFile()
551
+ || `${entry.dev}:${entry.ino}` !== initialIdentity
552
+ || !samePathIdentity(realpathSync.native(finalDatabasePath), finalDatabasePath)) {
553
+ throw new CodexUserIdentityRefusal("The coordinator database path was substituted.");
554
+ }
555
+ };
556
+
557
+ const capability = createCapability(db, result => { lastResult = result; });
558
+ return {
559
+ capability,
560
+ expectation() {
561
+ requireOpen();
562
+ const state = readCodexCoordinatorState(db);
563
+ return {
564
+ nativeBefore: state.nativeGeneration,
565
+ nativeAfter: state.nativeGeneration + 1,
566
+ txId: randomUUID(),
567
+ };
568
+ },
569
+ version() {
570
+ requireOpen();
571
+ const state = readCodexCoordinatorState(db);
572
+ return { nativeGeneration: state.nativeGeneration, currentTxId: state.currentTxId };
573
+ },
574
+ assertPublished(expectation) {
575
+ requireOpen();
576
+ if (lastResult?.kind !== "updated") {
577
+ throw new CodexCoordinatorTransactionError("The coordinator transition was not published.");
578
+ }
579
+ const state = readCodexCoordinatorState(db);
580
+ if (state.nativeGeneration !== expectation.nativeAfter || state.currentTxId !== expectation.txId) {
581
+ throw new CodexCoordinatorTransactionError("The coordinator published a different transition.");
582
+ }
583
+ },
584
+ assertStablePath,
585
+ commit() {
586
+ requireOpen();
587
+ assertStablePath();
588
+ db.exec("COMMIT");
589
+ transactionOpen = false;
590
+ },
591
+ rollback() {
592
+ if (!closed && transactionOpen) {
593
+ try { db.exec("ROLLBACK"); } finally { transactionOpen = false; }
594
+ }
595
+ },
596
+ close() {
597
+ if (closed) return;
598
+ if (transactionOpen) {
599
+ try { db.exec("ROLLBACK"); } catch { /* close still releases the lock */ }
600
+ transactionOpen = false;
601
+ }
602
+ db.close();
603
+ closed = true;
604
+ },
605
+ };
606
+ }
607
+
608
+ function currentCoordinatorDatabasePath(): string {
609
+ const canonicalCodexHome = realpathSync.native(resolveCodexHomeDir());
610
+ return resolveCodexCoordinatorDatabasePath(resolveEffectiveUserIdentity(), canonicalCodexHome);
611
+ }
612
+
613
+ function mapUnavailable(
614
+ error: unknown,
615
+ ): Extract<TransitionStateRead, { kind: "unavailable" }> {
616
+ if (error instanceof CodexUserIdentityRefusal) return { kind: "unavailable", reason: "unsafe-path" };
617
+ return { kind: "unavailable", reason: isBusy(error) ? "busy" : "database" };
618
+ }
619
+
620
+ function mapReadError(error: unknown): TransitionStateRead {
621
+ if (error instanceof CodexCoordinatorLegacyAmbiguousError) {
622
+ return { kind: "legacy-ambiguous", message: error.message };
623
+ }
624
+ return mapUnavailable(error);
625
+ }
626
+
627
+ export const readCodexTransitionState: ReadCodexTransitionState = () => {
628
+ let transaction: CodexCoordinatorTransactionController | undefined;
629
+ try {
630
+ transaction = openCodexCoordinatorTransaction(currentCoordinatorDatabasePath());
631
+ // Initialization and validation happen while N is held. Commit that setup
632
+ // before reopening read-only; the controller never leaks its Database.
633
+ transaction.commit();
634
+ transaction.close();
635
+ transaction = undefined;
636
+ return readCommittedState();
637
+ } catch (error) {
638
+ transaction?.rollback();
639
+ return mapReadError(error);
640
+ } finally {
641
+ transaction?.close();
642
+ }
643
+ };
644
+
645
+ function readCommittedState(): TransitionStateRead {
646
+ const path = currentCoordinatorDatabasePath();
647
+ let database: Database | undefined;
648
+ try {
649
+ database = new Database(path, { readonly: true });
650
+ database.exec("PRAGMA busy_timeout = 0");
651
+ return { kind: "ready", state: readCodexCoordinatorState(database) };
652
+ } catch (error) {
653
+ return mapUnavailable(error);
654
+ } finally {
655
+ try { database?.close(); } catch { /* read already completed */ }
656
+ }
657
+ }
658
+
659
+ export const beginCodexTransition: BeginCodexTransition = (expected, next) => {
660
+ let transaction: CodexCoordinatorTransactionController | undefined;
661
+ try {
662
+ transaction = openCodexCoordinatorTransaction(currentCoordinatorDatabasePath());
663
+ const result = transaction.capability.beginTransition(expected, next);
664
+ transaction.commit();
665
+ return result;
666
+ } catch (error) {
667
+ transaction?.rollback();
668
+ const unavailable = mapUnavailable(error);
669
+ return { kind: "unavailable", reason: unavailable.reason };
670
+ } finally {
671
+ transaction?.close();
672
+ }
673
+ };
674
+
675
+ export const updateCodexHistoryTransition: UpdateCodexHistoryTransition = (expected, history) => {
676
+ let database: Database | undefined;
677
+ let transactionOpen = false;
678
+ try {
679
+ validateHistoryWrite(expected, history);
680
+ // `{ create: false }` ALONE is SQLITE_MISUSE on Bun 1.3.14: the flags must
681
+ // name a read mode. Without `readwrite` every history update failed before
682
+ // reaching its conditional UPDATE and returned `unavailable/database`, so no
683
+ // terminal history state could ever be recorded — and the four tests here
684
+ // still passed, because none of them called this function.
685
+ database = new Database(currentCoordinatorDatabasePath(), { readwrite: true, create: false });
686
+ database.exec("PRAGMA busy_timeout = 0; BEGIN IMMEDIATE");
687
+ transactionOpen = true;
688
+ const current = readCodexCoordinatorState(database);
689
+ if (current.nativeGeneration > 0 && current.historySchedule === null) {
690
+ throw new CodexCoordinatorTransactionError("A positive transition cannot lose its direction.");
691
+ }
692
+ const result = database.query(UPDATE_HISTORY).run(
693
+ history.status,
694
+ history.reason ?? null,
695
+ history.attempts,
696
+ history.nextRetryAt,
697
+ history.txId,
698
+ history.pendingRows,
699
+ history.backupEntries,
700
+ new Date().toISOString(),
701
+ expected.nativeGeneration,
702
+ expected.currentTxId,
703
+ expected.currentTxId,
704
+ );
705
+ const state = readCodexCoordinatorState(database);
706
+ database.exec("COMMIT");
707
+ transactionOpen = false;
708
+ return result.changes === 1
709
+ ? { kind: "updated", state }
710
+ : { kind: "conflict", current: state };
711
+ } catch (error) {
712
+ if (transactionOpen) {
713
+ try { database?.exec("ROLLBACK"); } catch { /* close releases N */ }
714
+ }
715
+ const unavailable = mapUnavailable(error);
716
+ return { kind: "unavailable", reason: unavailable.reason };
717
+ } finally {
718
+ try { database?.close(); } catch { /* operation already completed */ }
719
+ }
720
+ };