@iislee/opencodex 2.11.0 → 2.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (675) hide show
  1. package/AGENTS_INSTALL.md +109 -0
  2. package/README.md +114 -19
  3. package/bin/ocx.mjs +164 -36
  4. package/bin/package-main.mjs +1 -1
  5. package/gui/dist/assets/index-BF38heuV.js +104 -0
  6. package/gui/dist/assets/index-DMiI18Kv.css +1 -0
  7. package/gui/dist/index.html +2 -2
  8. package/gui/dist/provider-icons/alibaba-color.svg +1 -1
  9. package/gui/dist/provider-icons/antigravity-color.svg +1 -1
  10. package/gui/dist/provider-icons/claude-color.svg +1 -1
  11. package/gui/dist/provider-icons/cline-color.svg +16 -0
  12. package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -1
  13. package/gui/dist/provider-icons/commandcode-color.svg +1 -0
  14. package/gui/dist/provider-icons/copilot-color.svg +1 -1
  15. package/gui/dist/provider-icons/cursor-color.svg +1 -1
  16. package/gui/dist/provider-icons/deepseek-color.svg +1 -1
  17. package/gui/dist/provider-icons/firepass-color.svg +1 -1
  18. package/gui/dist/provider-icons/fireworks-color.svg +1 -1
  19. package/gui/dist/provider-icons/gemini-color.svg +1 -1
  20. package/gui/dist/provider-icons/github-copilot-color.svg +1 -1
  21. package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -1
  22. package/gui/dist/provider-icons/grok.svg +1 -1
  23. package/gui/dist/provider-icons/groq-color.svg +1 -1
  24. package/gui/dist/provider-icons/huggingface-color.svg +1 -1
  25. package/gui/dist/provider-icons/kimi-color.svg +1 -1
  26. package/gui/dist/provider-icons/kiro-color.svg +2 -2
  27. package/gui/dist/provider-icons/lm-studio-color.svg +1 -1
  28. package/gui/dist/provider-icons/mistral-color.svg +1 -1
  29. package/gui/dist/provider-icons/moonshot-color.svg +1 -1
  30. package/gui/dist/provider-icons/nvidia-color.svg +1 -1
  31. package/gui/dist/provider-icons/ollama-color.svg +1 -1
  32. package/gui/dist/provider-icons/openai.svg +1 -1
  33. package/gui/dist/provider-icons/opencode.svg +2 -1
  34. package/gui/dist/provider-icons/openrouter-color.svg +1 -1
  35. package/gui/dist/provider-icons/pi.svg +2 -2
  36. package/gui/dist/provider-icons/qianfan-color.svg +1 -1
  37. package/gui/dist/provider-icons/qwen-portal-color.svg +1 -1
  38. package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -1
  39. package/gui/dist/provider-icons/vllm-color.svg +1 -1
  40. package/gui/dist/provider-icons/xiaomi-color.svg +1 -1
  41. package/package.json +19 -10
  42. package/src/adapters/anthropic-output-schema.ts +137 -0
  43. package/src/adapters/anthropic.ts +376 -52
  44. package/src/adapters/base.ts +54 -7
  45. package/src/adapters/client-fingerprint.ts +18 -12
  46. package/src/adapters/cline-pass-deepseek-v4-tool-replay.ts +69 -0
  47. package/src/adapters/command-code.ts +601 -0
  48. package/src/adapters/cursor/checkpoint-store.ts +303 -0
  49. package/src/adapters/cursor/cursor-errors.ts +129 -6
  50. package/src/adapters/cursor/discovery.ts +61 -4
  51. package/src/adapters/cursor/effort-map.ts +27 -3
  52. package/src/adapters/cursor/framing.ts +39 -0
  53. package/src/adapters/cursor/h2-pool.ts +123 -0
  54. package/src/adapters/cursor/http1-bidi.ts +361 -0
  55. package/src/adapters/cursor/images.ts +704 -0
  56. package/src/adapters/cursor/live-models.ts +174 -58
  57. package/src/adapters/cursor/live-transport.ts +609 -170
  58. package/src/adapters/cursor/native-exec-common.ts +23 -2
  59. package/src/adapters/cursor/native-exec-fs.ts +10 -7
  60. package/src/adapters/cursor/native-exec-network.ts +1 -1
  61. package/src/adapters/cursor/native-exec-shell.ts +0 -1
  62. package/src/adapters/cursor/native-exec.ts +101 -14
  63. package/src/adapters/cursor/protobuf-events.ts +829 -11
  64. package/src/adapters/cursor/protobuf-request.ts +383 -65
  65. package/src/adapters/cursor/request-builder.ts +237 -31
  66. package/src/adapters/cursor/tool-definitions.ts +242 -12
  67. package/src/adapters/cursor/tool-result-normalize.ts +92 -0
  68. package/src/adapters/cursor/transport.ts +22 -0
  69. package/src/adapters/cursor/types.ts +28 -1
  70. package/src/adapters/cursor.ts +133 -7
  71. package/src/adapters/google-antigravity-replay.ts +558 -34
  72. package/src/adapters/google-antigravity-wire.ts +43 -10
  73. package/src/adapters/google-http.ts +38 -10
  74. package/src/adapters/google-tool-schema.ts +80 -15
  75. package/src/adapters/google-truncation.ts +11 -0
  76. package/src/adapters/google.ts +618 -74
  77. package/src/adapters/identity.ts +39 -6
  78. package/src/adapters/kiro-errors.ts +11 -0
  79. package/src/adapters/kiro-events.ts +19 -1
  80. package/src/adapters/kiro-thinking.ts +18 -2
  81. package/src/adapters/kiro-tools.ts +10 -1
  82. package/src/adapters/kiro.ts +92 -54
  83. package/src/adapters/mimo-free.ts +17 -0
  84. package/src/adapters/openai-chat-url.ts +11 -0
  85. package/src/adapters/openai-chat.ts +1311 -336
  86. package/src/adapters/openai-responses-url.ts +16 -0
  87. package/src/adapters/openai-responses.ts +830 -56
  88. package/src/adapters/registry.ts +175 -0
  89. package/src/adapters/responses-tool-schema.ts +67 -0
  90. package/src/adapters/tool-call-id.ts +119 -0
  91. package/src/adapters/tool-catalog-nudge.ts +104 -21
  92. package/src/adapters/xai-web-search.ts +185 -0
  93. package/src/bridge.ts +428 -61
  94. package/src/chat/inbound.ts +43 -19
  95. package/src/chat/outbound.ts +82 -26
  96. package/src/claude/agents-inject.ts +32 -9
  97. package/src/claude/context-windows.ts +21 -5
  98. package/src/claude/desktop-3p.ts +243 -9
  99. package/src/claude/gateway-cache.ts +41 -4
  100. package/src/claude/inbound.ts +72 -3
  101. package/src/claude/model-info.ts +38 -15
  102. package/src/claude/outbound.ts +70 -16
  103. package/src/cli/account-api.ts +35 -1
  104. package/src/cli/account-auth.ts +33 -6
  105. package/src/cli/account-catalog-refresh.ts +14 -0
  106. package/src/cli/account-extended.ts +389 -2
  107. package/src/cli/account-main.ts +317 -0
  108. package/src/cli/account.ts +30 -6
  109. package/src/cli/agent.ts +45 -1
  110. package/src/cli/claude-agent-startup-sync.ts +73 -0
  111. package/src/cli/claude-desktop.ts +29 -4
  112. package/src/cli/claude.ts +103 -34
  113. package/src/cli/codex-log-guard-doctor.ts +103 -0
  114. package/src/cli/codex-shim-autorestore.ts +2 -0
  115. package/src/cli/codex-shim-readiness.ts +76 -0
  116. package/src/cli/combo.ts +8 -0
  117. package/src/cli/config-command.ts +74 -10
  118. package/src/cli/dispatch.ts +593 -0
  119. package/src/cli/doctor.ts +315 -43
  120. package/src/cli/ensure-desired-integrations.ts +152 -0
  121. package/src/cli/export-command.ts +46 -20
  122. package/src/cli/help.ts +20 -271
  123. package/src/cli/index.ts +378 -519
  124. package/src/cli/init.ts +4 -17
  125. package/src/cli/integrations.ts +120 -2
  126. package/src/cli/lab.ts +607 -0
  127. package/src/cli/launcher-context.ts +77 -0
  128. package/src/cli/minimax.ts +497 -0
  129. package/src/cli/models-runtime.ts +35 -2
  130. package/src/cli/models.ts +100 -14
  131. package/src/cli/observe.ts +92 -3
  132. package/src/cli/opencode.ts +4 -2
  133. package/src/cli/provider-runtime.ts +18 -1
  134. package/src/cli/provider.ts +24 -3
  135. package/src/cli/ready.ts +301 -0
  136. package/src/cli/registry.ts +437 -0
  137. package/src/cli/root.ts +86 -0
  138. package/src/cli/route-policy.ts +92 -0
  139. package/src/cli/runtime-api.ts +6 -3
  140. package/src/cli/star-prompt.ts +71 -15
  141. package/src/cli/status.ts +10 -3
  142. package/src/cli/system-restart-client.ts +146 -0
  143. package/src/cli/tray-proxy.ts +153 -6
  144. package/src/cli/v2.ts +105 -10
  145. package/src/cli.ts +1 -1
  146. package/src/clients/config-export.ts +1358 -21
  147. package/src/codex/account-label.ts +14 -1
  148. package/src/codex/account-lifecycle.ts +130 -13
  149. package/src/codex/account-namespaces.ts +49 -3
  150. package/src/codex/account-priority.ts +83 -0
  151. package/src/codex/account-store.ts +29 -2
  152. package/src/codex/account-usability.ts +25 -2
  153. package/src/codex/admission.ts +256 -0
  154. package/src/codex/affinity-debug.ts +162 -0
  155. package/src/codex/app-server-processes.ts +493 -106
  156. package/src/codex/app-server-restart-service.ts +232 -0
  157. package/src/codex/auth-api.ts +849 -242
  158. package/src/codex/auth-collision.ts +5 -3
  159. package/src/codex/auth-context.ts +345 -32
  160. package/src/codex/autostart-health.ts +8 -1
  161. package/src/codex/catalog/account-models.ts +67 -0
  162. package/src/codex/catalog/aggregation.ts +68 -10
  163. package/src/codex/catalog/bundled.ts +331 -33
  164. package/src/codex/catalog/effort.ts +121 -30
  165. package/src/codex/catalog/filesystem-evidence.ts +302 -0
  166. package/src/codex/catalog/kinds.ts +2 -0
  167. package/src/codex/catalog/metadata.ts +529 -45
  168. package/src/codex/catalog/native-models.ts +72 -0
  169. package/src/codex/catalog/parsing.ts +224 -30
  170. package/src/codex/catalog/provider-fetch.ts +1460 -134
  171. package/src/codex/catalog/sync.ts +1449 -186
  172. package/src/codex/catalog-admission.ts +199 -0
  173. package/src/codex/catalog-refresh-status.ts +105 -0
  174. package/src/codex/catalog-write-serialization.ts +242 -0
  175. package/src/codex/catalog.ts +6 -3
  176. package/src/codex/codex-write-lock.ts +384 -0
  177. package/src/codex/convergence-types.ts +614 -0
  178. package/src/codex/convergence.ts +651 -0
  179. package/src/codex/coordinator-doctor.ts +332 -0
  180. package/src/codex/custom-model-catalog-migration.ts +176 -0
  181. package/src/codex/desired-state.ts +230 -0
  182. package/src/codex/features.ts +636 -39
  183. package/src/codex/generation.ts +202 -0
  184. package/src/codex/history-job.ts +407 -0
  185. package/src/codex/history-lock.ts +242 -0
  186. package/src/codex/history-migration-guardian.ts +26 -20
  187. package/src/codex/history-provider.ts +231 -28
  188. package/src/codex/history-transition.ts +105 -0
  189. package/src/codex/history-worker.ts +220 -0
  190. package/src/codex/inject-coordination.ts +290 -0
  191. package/src/codex/inject.ts +1073 -152
  192. package/src/codex/injected-marker.ts +37 -3
  193. package/src/codex/integration-record.ts +266 -0
  194. package/src/codex/internal/catalog-writer.ts +203 -0
  195. package/src/codex/internal/history-writer.ts +80 -0
  196. package/src/codex/journal.ts +66 -4
  197. package/src/codex/log-guard/inspect.ts +506 -0
  198. package/src/codex/log-guard/lock.ts +150 -0
  199. package/src/codex/log-guard/maintenance.ts +403 -0
  200. package/src/codex/log-guard/path-safety.ts +88 -0
  201. package/src/codex/log-guard/policy.ts +44 -0
  202. package/src/codex/log-guard/processes.ts +205 -0
  203. package/src/codex/log-guard/protection.ts +489 -0
  204. package/src/codex/log-guard/sqlite-errors.ts +9 -0
  205. package/src/codex/main-account-cache.ts +24 -0
  206. package/src/codex/main-account.ts +29 -1
  207. package/src/codex/management-convergence.ts +167 -0
  208. package/src/codex/model-cache.ts +56 -10
  209. package/src/codex/model-entitlements.ts +353 -0
  210. package/src/codex/native-main-admission.ts +47 -0
  211. package/src/codex/native-main-auth-temp.ts +187 -0
  212. package/src/codex/native-main-claim.ts +178 -0
  213. package/src/codex/native-main-lock-file.ts +162 -0
  214. package/src/codex/native-main-owner.ts +329 -0
  215. package/src/codex/native-profile-api.ts +247 -0
  216. package/src/codex/native-profile-manager.ts +1531 -0
  217. package/src/codex/native-profile-processes.ts +121 -0
  218. package/src/codex/native-profile-recovery.ts +99 -0
  219. package/src/codex/native-profile-stage-store.ts +387 -0
  220. package/src/codex/native-profile-startup.ts +492 -0
  221. package/src/codex/native-profile-store.ts +855 -0
  222. package/src/codex/native-profile-types.ts +120 -0
  223. package/src/codex/native-residue.ts +682 -0
  224. package/src/codex/paths.ts +80 -1
  225. package/src/codex/plan-from-token.ts +140 -0
  226. package/src/codex/plan.ts +40 -0
  227. package/src/codex/plugins-doctor.ts +1 -1
  228. package/src/codex/pool-rotation.ts +74 -4
  229. package/src/codex/project-config-warnings.ts +20 -6
  230. package/src/codex/prompt-journal.ts +352 -0
  231. package/src/codex/prompt-layers.ts +967 -0
  232. package/src/codex/prompt-lock.ts +143 -0
  233. package/src/codex/quota-rejection.ts +298 -0
  234. package/src/codex/quota.ts +175 -13
  235. package/src/codex/refresh.ts +11 -2
  236. package/src/codex/reset-credit-recovery.ts +1044 -0
  237. package/src/codex/routing.ts +505 -94
  238. package/src/codex/runtime.ts +159 -38
  239. package/src/codex/shim.ts +1009 -28
  240. package/src/codex/subagent-model-fallback.ts +350 -35
  241. package/src/codex/sync.ts +191 -2
  242. package/src/codex/transition-state.ts +612 -0
  243. package/src/codex/upstream-host-health.ts +368 -0
  244. package/src/codex/user-identity.ts +557 -0
  245. package/src/codex/warmup.ts +187 -81
  246. package/src/codex/write-coordination.ts +114 -0
  247. package/src/combos/failover.ts +20 -0
  248. package/src/combos/index.ts +4 -0
  249. package/src/combos/request.ts +32 -0
  250. package/src/combos/types.ts +81 -9
  251. package/src/config/provider-name.ts +24 -0
  252. package/src/config.ts +1762 -140
  253. package/src/generated/compatibility-version.json +3164 -0
  254. package/src/generated/{jawcode-model-metadata.ts → model-metadata.ts} +19 -17
  255. package/src/grok/inject.ts +16 -5
  256. package/src/grok/inspect.ts +45 -0
  257. package/src/grok/sync.ts +2 -2
  258. package/src/images/loop.ts +152 -29
  259. package/src/images/plan.ts +23 -13
  260. package/src/integrations/config-io.ts +269 -0
  261. package/src/integrations/journal.ts +315 -0
  262. package/src/integrations/merge.ts +135 -0
  263. package/src/integrations/mutation-flight.ts +71 -0
  264. package/src/integrations/native/ownership-preflight.ts +202 -0
  265. package/src/integrations/omp-yaml-source.ts +358 -0
  266. package/src/integrations/owned-refresh.ts +74 -0
  267. package/src/integrations/ownership.ts +111 -0
  268. package/src/integrations/registry.ts +159 -0
  269. package/src/integrations/serialize.ts +314 -0
  270. package/src/integrations/state.ts +361 -0
  271. package/src/integrations/store.ts +103 -0
  272. package/src/integrations/writer-lock.ts +98 -0
  273. package/src/integrations/writer.ts +691 -0
  274. package/src/lab/artifacts/sanitize.ts +586 -0
  275. package/src/lab/artifacts/secure-fs.ts +475 -0
  276. package/src/lab/artifacts/store.ts +310 -0
  277. package/src/lab/automation/budgets.ts +78 -0
  278. package/src/lab/automation/config-persistence.ts +256 -0
  279. package/src/lab/automation/constants.ts +39 -0
  280. package/src/lab/automation/cooldown.ts +103 -0
  281. package/src/lab/automation/dispatch.ts +211 -0
  282. package/src/lab/automation/index.ts +13 -0
  283. package/src/lab/automation/orchestrator.ts +499 -0
  284. package/src/lab/automation/persistence.ts +512 -0
  285. package/src/lab/automation/planner.ts +371 -0
  286. package/src/lab/automation/policy.ts +136 -0
  287. package/src/lab/automation/queue.ts +191 -0
  288. package/src/lab/automation/recovery.ts +24 -0
  289. package/src/lab/automation/route-context.ts +21 -0
  290. package/src/lab/automation/run-key.ts +44 -0
  291. package/src/lab/automation/runs-query.ts +34 -0
  292. package/src/lab/automation/types.ts +160 -0
  293. package/src/lab/conformance/assertion.ts +325 -0
  294. package/src/lab/conformance/digest.ts +22 -0
  295. package/src/lab/conformance/executor.ts +741 -0
  296. package/src/lab/conformance/fixture-provider.ts +27 -0
  297. package/src/lab/conformance/fixtures/live-v1-cases.json +175 -0
  298. package/src/lab/conformance/fixtures/protocol-v1-cases.json +461 -0
  299. package/src/lab/conformance/harness-budget.ts +47 -0
  300. package/src/lab/conformance/index.ts +5 -0
  301. package/src/lab/conformance/jcs.ts +64 -0
  302. package/src/lab/conformance/json-pointer.ts +39 -0
  303. package/src/lab/conformance/manifest.ts +180 -0
  304. package/src/lab/conformance/mcp-stub.ts +179 -0
  305. package/src/lab/conformance/negative-controls.ts +164 -0
  306. package/src/lab/conformance/observation.ts +355 -0
  307. package/src/lab/conformance/runner.ts +68 -0
  308. package/src/lab/conformance/sse-normalize.ts +59 -0
  309. package/src/lab/conformance/suite-manifest.ts +78 -0
  310. package/src/lab/conformance/types.ts +214 -0
  311. package/src/lab/constants.ts +126 -0
  312. package/src/lab/digest.ts +64 -0
  313. package/src/lab/events/errors.ts +9 -0
  314. package/src/lab/events/limits.ts +117 -0
  315. package/src/lab/events/types.ts +229 -0
  316. package/src/lab/events/validate.ts +781 -0
  317. package/src/lab/fabric/constants.ts +40 -0
  318. package/src/lab/fabric/executor.ts +492 -0
  319. package/src/lab/fabric/index.ts +80 -0
  320. package/src/lab/fabric/manifest.ts +222 -0
  321. package/src/lab/fabric/observe.ts +489 -0
  322. package/src/lab/fabric/patch.ts +79 -0
  323. package/src/lab/fabric/producer-child.ts +139 -0
  324. package/src/lab/fabric/producer-isolate.ts +276 -0
  325. package/src/lab/fabric/producer-protocol.ts +61 -0
  326. package/src/lab/fabric/scratch.ts +439 -0
  327. package/src/lab/fabric/subject.ts +106 -0
  328. package/src/lab/fabric/types.ts +134 -0
  329. package/src/lab/fabric/verifier.ts +98 -0
  330. package/src/lab/index.ts +54 -0
  331. package/src/lab/ledger/artifact-refs.ts +127 -0
  332. package/src/lab/ledger/invalidation.ts +136 -0
  333. package/src/lab/ledger/purge.ts +310 -0
  334. package/src/lab/ledger/store.ts +532 -0
  335. package/src/lab/live/credential-lease.ts +53 -0
  336. package/src/lab/live/destination.ts +155 -0
  337. package/src/lab/live/executor.ts +336 -0
  338. package/src/lab/live/inert-tools.ts +56 -0
  339. package/src/lab/live/manifest.ts +85 -0
  340. package/src/lab/live/mcp-loopback.ts +57 -0
  341. package/src/lab/live/runner.ts +19 -0
  342. package/src/lab/live/sandbox.ts +61 -0
  343. package/src/lab/live/suite-manifest.ts +41 -0
  344. package/src/lab/live/transport.ts +118 -0
  345. package/src/lab/live/types.ts +197 -0
  346. package/src/lab/observe/from-conformance.ts +301 -0
  347. package/src/lab/observe/from-live.ts +117 -0
  348. package/src/lab/paths.ts +153 -0
  349. package/src/lab/projection/rebuild.ts +495 -0
  350. package/src/lab/projection/schema.ts +135 -0
  351. package/src/lab/projection/verdicts.ts +474 -0
  352. package/src/lab/projection/verification.ts +412 -0
  353. package/src/lab/public/bundle.ts +217 -0
  354. package/src/lab/public/community-authority.ts +175 -0
  355. package/src/lab/public/community-files.ts +29 -0
  356. package/src/lab/public/community.ts +479 -0
  357. package/src/lab/public/file-safety.ts +155 -0
  358. package/src/lab/public/ids.ts +26 -0
  359. package/src/lab/public/index.ts +16 -0
  360. package/src/lab/public/mutation-lock.ts +424 -0
  361. package/src/lab/public/operator.ts +353 -0
  362. package/src/lab/public/origin-purge.ts +79 -0
  363. package/src/lab/public/origin.ts +203 -0
  364. package/src/lab/public/privacy.ts +143 -0
  365. package/src/lab/public/private-file.ts +261 -0
  366. package/src/lab/public/project.ts +124 -0
  367. package/src/lab/public/purge-test-fault.ts +21 -0
  368. package/src/lab/public/purge.ts +223 -0
  369. package/src/lab/public/registry.ts +44 -0
  370. package/src/lab/public/revocation.ts +252 -0
  371. package/src/lab/public/signature.ts +243 -0
  372. package/src/lab/public/storage.ts +105 -0
  373. package/src/lab/public/strict-json.ts +206 -0
  374. package/src/lab/public/time.ts +26 -0
  375. package/src/lab/public/types.ts +172 -0
  376. package/src/lab/public/validate.ts +391 -0
  377. package/src/lab/query/catalog.ts +101 -0
  378. package/src/lab/query/connection.ts +107 -0
  379. package/src/lab/query/constants.ts +4 -0
  380. package/src/lab/query/cursor.ts +132 -0
  381. package/src/lab/query/dto-map.ts +277 -0
  382. package/src/lab/query/errors.ts +22 -0
  383. package/src/lab/query/freshness.ts +53 -0
  384. package/src/lab/query/index.ts +45 -0
  385. package/src/lab/query/latest-observation.ts +59 -0
  386. package/src/lab/query/passive-production.ts +159 -0
  387. package/src/lab/query/queries.ts +444 -0
  388. package/src/lab/query/types.ts +266 -0
  389. package/src/lab/subject/behavior-fingerprint.ts +77 -0
  390. package/src/lab/subject/installation-salt.ts +112 -0
  391. package/src/lab/subject/protocol-subject.ts +80 -0
  392. package/src/lab/subject/route-subject.ts +74 -0
  393. package/src/lib/app-owned-memory-stores.ts +22 -0
  394. package/src/lib/bounded-body.ts +153 -9
  395. package/src/lib/bun-runtime.ts +125 -12
  396. package/src/lib/bun-stream-caps.ts +13 -9
  397. package/src/lib/codex-restart-contract.ts +120 -0
  398. package/src/lib/config-ownership.ts +6 -2
  399. package/src/lib/destination-policy.ts +65 -1
  400. package/src/lib/errors.ts +44 -2
  401. package/src/lib/fabric-task-execution-authority.ts +7 -0
  402. package/src/lib/fabric-task-host.ts +29 -0
  403. package/src/lib/lab-activation.ts +223 -0
  404. package/src/lib/lab-live-execution-authority.ts +13 -0
  405. package/src/lib/lab-live-host.ts +30 -0
  406. package/src/lib/lab-live-pinned-sender.ts +56 -0
  407. package/src/lib/lab-live-route-production.ts +130 -0
  408. package/src/lib/lab-passive-linker-registration.ts +26 -0
  409. package/src/lib/local-management-attestation.ts +51 -0
  410. package/src/lib/local-management-capability.ts +100 -0
  411. package/src/lib/local-provider-reload-contract.ts +100 -0
  412. package/src/lib/optional-shutdown-hooks.ts +57 -0
  413. package/src/lib/pinned-http.ts +145 -26
  414. package/src/lib/process-control.ts +4 -1
  415. package/src/lib/provider-outbound.ts +49 -9
  416. package/src/lib/redact.ts +419 -3
  417. package/src/lib/self-launch-argv.ts +15 -0
  418. package/src/lib/server-resource-ownership.ts +71 -0
  419. package/src/lib/shadow-call.ts +35 -4
  420. package/src/lib/sse-decoder.ts +41 -0
  421. package/src/lib/state-store-registrations.ts +10 -2
  422. package/src/lib/system-restart-contract.ts +73 -0
  423. package/src/lib/token-estimate.ts +19 -2
  424. package/src/lib/tool-argument-integers.ts +202 -0
  425. package/src/lib/translator-budget.ts +44 -0
  426. package/src/lib/upstream-http-version.ts +57 -0
  427. package/src/lib/upstream-reachability.ts +95 -0
  428. package/src/lib/upstream-retry.ts +156 -3
  429. package/src/lib/windows-atomic-replace.ts +155 -0
  430. package/src/lib/windows-elevation.ts +70 -2
  431. package/src/lib/windows-secret-acl.ts +409 -69
  432. package/src/lib/windows-service-wrappers.ts +72 -0
  433. package/src/lib/windows-text.ts +106 -0
  434. package/src/lib/windows-user-principal.ts +341 -0
  435. package/src/lib/winsw.ts +33 -5
  436. package/src/oauth/account-import/google-antigravity-adapter.ts +74 -0
  437. package/src/oauth/account-import/index.ts +15 -0
  438. package/src/oauth/account-import/parser.ts +83 -0
  439. package/src/oauth/account-import/registry.ts +18 -0
  440. package/src/oauth/account-import/service.ts +75 -0
  441. package/src/oauth/account-import/types.ts +91 -0
  442. package/src/oauth/anthropic.ts +12 -1
  443. package/src/oauth/callback-server.ts +8 -2
  444. package/src/oauth/chatgpt.ts +12 -1
  445. package/src/oauth/command-code.ts +239 -0
  446. package/src/oauth/cursor.ts +46 -5
  447. package/src/oauth/google-antigravity.ts +35 -3
  448. package/src/oauth/health.ts +20 -12
  449. package/src/oauth/index.ts +398 -66
  450. package/src/oauth/key-providers.ts +16 -0
  451. package/src/oauth/kimi.ts +16 -2
  452. package/src/oauth/kiro.ts +50 -6
  453. package/src/oauth/local-token-detect.ts +11 -2
  454. package/src/oauth/log.ts +3 -1
  455. package/src/oauth/login-cli.ts +88 -28
  456. package/src/oauth/nous.ts +798 -0
  457. package/src/oauth/store.ts +119 -21
  458. package/src/oauth/token-guardian.ts +9 -3
  459. package/src/pi/models.ts +2 -2
  460. package/src/providers/alibaba-region-migration.ts +1 -1
  461. package/src/providers/antigravity-models.ts +521 -31
  462. package/src/providers/base-url-choices.ts +10 -0
  463. package/src/providers/codex-capacity.ts +292 -0
  464. package/src/providers/command-code-efforts.ts +144 -0
  465. package/src/providers/context-cap.ts +22 -5
  466. package/src/providers/cursor-pool.ts +72 -0
  467. package/src/providers/derive.ts +253 -6
  468. package/src/providers/fastwire.ts +501 -0
  469. package/src/providers/free-directory.ts +10 -7
  470. package/src/providers/google-vertex-location.ts +14 -0
  471. package/src/providers/key-failover.ts +71 -3
  472. package/src/providers/label.ts +1 -1
  473. package/src/providers/model-discovery-limits.ts +16 -0
  474. package/src/providers/model-discovery.ts +115 -22
  475. package/src/providers/model-rename-migration.ts +255 -0
  476. package/src/providers/model-rename-startup.ts +28 -0
  477. package/src/providers/openai-sidecar.ts +72 -4
  478. package/src/providers/openai-tier-startup.ts +31 -2
  479. package/src/providers/openai-tiers.ts +119 -4
  480. package/src/providers/openai-virtual-models.ts +1 -0
  481. package/src/providers/opencode-zen-rate-limit.ts +102 -0
  482. package/src/providers/provider-id-rewrite.ts +29 -0
  483. package/src/providers/quota.ts +1319 -38
  484. package/src/providers/registry.ts +1429 -111
  485. package/src/providers/request-pacing.ts +310 -0
  486. package/src/providers/service-tier.ts +277 -0
  487. package/src/providers/slug-codec.ts +42 -6
  488. package/src/providers/static-model-discovery.ts +86 -0
  489. package/src/providers/xai-responses-opt-in.ts +15 -0
  490. package/src/providers/xai-transport.ts +11 -4
  491. package/src/reasoning-effort.ts +49 -1
  492. package/src/responses/compaction.ts +26 -1
  493. package/src/responses/custom-tool-compat.ts +266 -0
  494. package/src/responses/hosted-tool-policy.ts +9 -0
  495. package/src/responses/namespace-tool-compat.ts +355 -0
  496. package/src/responses/parser.ts +220 -38
  497. package/src/responses/provider-continuation.ts +98 -0
  498. package/src/responses/provider-opaque-metadata.ts +73 -0
  499. package/src/responses/reasoning-envelope.ts +9 -1
  500. package/src/responses/reasoning-replay-cache.ts +426 -0
  501. package/src/responses/schema.ts +7 -1
  502. package/src/responses/spill-store.ts +75 -10
  503. package/src/responses/state.ts +565 -27
  504. package/src/responses/thought-signature-replay.ts +347 -0
  505. package/src/responses/tool-search-compat.ts +301 -0
  506. package/src/responses/truncated-stop-reason.ts +60 -0
  507. package/src/router.ts +366 -30
  508. package/src/routing/analytics.ts +378 -0
  509. package/src/routing/capability.ts +244 -0
  510. package/src/routing/compatibility/assemble.ts +73 -0
  511. package/src/routing/compatibility/behavior.ts +278 -0
  512. package/src/routing/compatibility/catalog.ts +99 -0
  513. package/src/routing/compatibility/endpoint.ts +52 -0
  514. package/src/routing/compatibility/lab-evidence-provider.ts +130 -0
  515. package/src/routing/compatibility/policy.ts +181 -0
  516. package/src/routing/compatibility/provider-slot.ts +56 -0
  517. package/src/routing/compatibility/reader.ts +110 -0
  518. package/src/routing/compatibility/subject.ts +191 -0
  519. package/src/routing/compatibility/types.ts +64 -0
  520. package/src/routing/compatibility/version.ts +104 -0
  521. package/src/routing/cost.ts +77 -0
  522. package/src/routing/evaluator.ts +495 -0
  523. package/src/routing/health.ts +412 -0
  524. package/src/routing/history/cursor.ts +43 -0
  525. package/src/routing/history/indexer.ts +605 -0
  526. package/src/routing/history/schema.ts +72 -0
  527. package/src/routing/profile-namespace.ts +15 -0
  528. package/src/routing/profile.ts +547 -0
  529. package/src/routing/quota.ts +145 -0
  530. package/src/routing/request-evidence.ts +45 -0
  531. package/src/routing/trace.ts +776 -0
  532. package/src/server/adapter-resolve.ts +2 -29
  533. package/src/server/auth-cors.ts +267 -46
  534. package/src/server/background-lifecycle.ts +182 -0
  535. package/src/server/chat-completions.ts +130 -56
  536. package/src/server/chat-native-sse.ts +331 -0
  537. package/src/server/chat-native.ts +426 -0
  538. package/src/server/claude-messages.ts +159 -43
  539. package/src/server/direct-local-http.ts +347 -0
  540. package/src/server/effort-policy.ts +18 -0
  541. package/src/server/github-copilot-responses-repair.ts +338 -0
  542. package/src/server/gui-static.ts +39 -10
  543. package/src/server/images.ts +94 -12
  544. package/src/server/index.ts +865 -181
  545. package/src/server/lifecycle.ts +284 -13
  546. package/src/server/live.ts +136 -17
  547. package/src/server/local-management-read-client.ts +90 -0
  548. package/src/server/local-provider-reload-client.ts +137 -0
  549. package/src/server/management/agent-settings-routes.ts +398 -103
  550. package/src/server/management/api-key-usage.ts +31 -5
  551. package/src/server/management/body.ts +6 -0
  552. package/src/server/management/combo-routes.ts +62 -24
  553. package/src/server/management/config-routes.ts +464 -51
  554. package/src/server/management/context.ts +80 -2
  555. package/src/server/management/integration-routes.ts +498 -0
  556. package/src/server/management/lab-automation-routes.ts +206 -0
  557. package/src/server/management/lab-routes.ts +563 -0
  558. package/src/server/management/logs-usage-routes.ts +101 -32
  559. package/src/server/management/model-routes.ts +189 -131
  560. package/src/server/management/model-rows.ts +163 -0
  561. package/src/server/management/native-integration-routes.ts +769 -0
  562. package/src/server/management/oauth-account-routes.ts +80 -4
  563. package/src/server/management/provider-capability-config.ts +48 -0
  564. package/src/server/management/provider-routes.ts +764 -157
  565. package/src/server/management/request-history-routes.ts +191 -0
  566. package/src/server/management/routing-analytics-routes.ts +74 -0
  567. package/src/server/management/routing-profile-routes.ts +380 -0
  568. package/src/server/management/shared.ts +27 -11
  569. package/src/server/management/sidebar-routes.ts +47 -31
  570. package/src/server/management/storage-log-guard-routes.ts +186 -0
  571. package/src/server/management/sync-response.ts +69 -0
  572. package/src/server/management/system-restart.ts +288 -32
  573. package/src/server/management/system-routes.ts +77 -0
  574. package/src/server/management/usage-summary-cache.ts +9 -1
  575. package/src/server/management/vision-sidecar-options.ts +167 -0
  576. package/src/server/management/web-search-sidecar-options.ts +120 -0
  577. package/src/server/management-api.ts +115 -14
  578. package/src/server/management-auth.ts +220 -5
  579. package/src/server/passive-route-linker.ts +66 -0
  580. package/src/server/ports.ts +41 -1
  581. package/src/server/proxy-liveness.ts +132 -5
  582. package/src/server/readiness.ts +99 -0
  583. package/src/server/relay-eager.ts +82 -42
  584. package/src/server/relay.ts +236 -76
  585. package/src/server/request-decompress.ts +113 -6
  586. package/src/server/request-log.ts +235 -22
  587. package/src/server/responses/agent-task-recovery-cache.ts +143 -0
  588. package/src/server/responses/agent-task-recovery.ts +465 -0
  589. package/src/server/responses/collaboration.ts +204 -35
  590. package/src/server/responses/compact.ts +442 -55
  591. package/src/server/responses/core.ts +2872 -331
  592. package/src/server/responses/empty-completion-guard.ts +276 -0
  593. package/src/server/responses/encrypted-payload.ts +62 -39
  594. package/src/server/responses/fetch-helpers.ts +79 -4
  595. package/src/server/responses/input-admission.ts +185 -0
  596. package/src/server/responses/pacing-overload.ts +13 -0
  597. package/src/server/responses/policy-fallback.ts +178 -0
  598. package/src/server/responses/responses-field-backfill.ts +251 -0
  599. package/src/server/responses/terminal-guard.ts +26 -5
  600. package/src/server/responses/upstream-error.ts +5 -0
  601. package/src/server/responses/ws-upstream.ts +308 -0
  602. package/src/server/responses-custom-tool-repair.ts +282 -0
  603. package/src/server/responses-item-id-repair.ts +54 -6
  604. package/src/server/responses-json-events.ts +90 -0
  605. package/src/server/responses-model-rewrite.ts +29 -0
  606. package/src/server/responses-reasoning-summary-rewrite.ts +178 -0
  607. package/src/server/responses-snapshot-repair.ts +621 -0
  608. package/src/server/responses-terminal-repair.ts +342 -0
  609. package/src/server/responses-tool-search-repair.ts +267 -0
  610. package/src/server/responses-undeclared-tool-guard.ts +153 -0
  611. package/src/server/responses.ts +18 -2
  612. package/src/server/search.ts +78 -13
  613. package/src/server/sse-frame-buffer.ts +292 -0
  614. package/src/server/sse-payload-rewrite.ts +110 -22
  615. package/src/server/startup-action-control.ts +8 -1
  616. package/src/server/startup-health-cache.ts +19 -1
  617. package/src/server/system-env.ts +80 -9
  618. package/src/server/ws-bridge.ts +39 -38
  619. package/src/service-manager-probe.ts +892 -0
  620. package/src/service.ts +1111 -90
  621. package/src/sidecar/auth.ts +92 -0
  622. package/src/sidecar/candidates.ts +83 -0
  623. package/src/storage/cleanup.ts +2 -2
  624. package/src/storage/scanner.ts +1 -1
  625. package/src/storage/worker-lifecycle.ts +14 -14
  626. package/src/tray/windows-tray.ps1 +83 -9
  627. package/src/tray/windows.ts +43 -16
  628. package/src/types/accounts.ts +37 -0
  629. package/src/types/config.ts +845 -0
  630. package/src/types/provider.ts +545 -0
  631. package/src/types/request.ts +384 -0
  632. package/src/types/tools.ts +131 -0
  633. package/src/types/wire.ts +80 -0
  634. package/src/types.ts +104 -1236
  635. package/src/update/index.ts +32 -19
  636. package/src/update/job.ts +442 -67
  637. package/src/update/notify.ts +12 -6
  638. package/src/update/npm-cache-preflight.d.mts +47 -0
  639. package/src/update/npm-cache-preflight.mjs +201 -0
  640. package/src/update/transactional-install.d.mts +22 -0
  641. package/src/update/transactional-install.mjs +259 -0
  642. package/src/usage/cost.ts +0 -0
  643. package/src/usage/expected-prices.ts +268 -16
  644. package/src/usage/log.ts +606 -41
  645. package/src/usage/summary.ts +177 -9
  646. package/src/usage/user-cost-overlay-reconciler.ts +313 -0
  647. package/src/usage/user-cost-overlays.ts +314 -0
  648. package/src/vision/anthropic-describe.ts +10 -6
  649. package/src/vision/backends.ts +97 -0
  650. package/src/vision/describe.ts +9 -3
  651. package/src/vision/eligibility.ts +250 -0
  652. package/src/vision/index.ts +238 -24
  653. package/src/vision/reasoning.ts +55 -0
  654. package/src/vision/routed-describe.ts +175 -0
  655. package/src/vision/timeout-bounds.ts +9 -0
  656. package/src/web-search/anthropic-executor.ts +13 -7
  657. package/src/web-search/backends.ts +108 -0
  658. package/src/web-search/exa-executor.ts +88 -0
  659. package/src/web-search/executor.ts +11 -3
  660. package/src/web-search/gemini-executor.ts +141 -0
  661. package/src/web-search/index.ts +150 -15
  662. package/src/web-search/loop.ts +279 -50
  663. package/src/web-search/parse.ts +125 -30
  664. package/src/web-search/sources.ts +60 -0
  665. package/src/web-search/xai-executor.ts +219 -0
  666. package/gui/dist/assets/index-DTpMHS4F.js +0 -67
  667. package/gui/dist/assets/index-ZNVDE3C7.css +0 -1
  668. package/gui/dist/provider-icons/antigravity.svg +0 -1
  669. package/gui/dist/provider-icons/claude.svg +0 -1
  670. package/gui/dist/provider-icons/copilot.svg +0 -1
  671. package/gui/dist/provider-icons/cursor.svg +0 -2
  672. package/gui/dist/provider-icons/gemini.svg +0 -1
  673. package/gui/dist/provider-icons/grok-color.svg +0 -1
  674. package/gui/dist/provider-icons/kiro.svg +0 -14
  675. package/src/cli/internal-dispatch.ts +0 -20
@@ -1,9 +1,9 @@
1
1
  import { createHash } from "node:crypto";
2
- import { closeSync, existsSync, fsyncSync, mkdirSync, openSync, readFileSync, readSync, unlinkSync, writeSync } from "node:fs";
2
+ import { closeSync, existsSync, fsyncSync, mkdirSync, openSync, readFileSync, readSync, statSync, unlinkSync, writeSync } from "node:fs";
3
3
  import { dirname, join, resolve } from "node:path";
4
4
  import { zstdDecompressSync } from "node:zlib";
5
5
  import { Database } from "bun:sqlite";
6
- import { CODEX_HOME } from "./paths";
6
+ import { resolveCodexStateDbPath } from "./paths";
7
7
  import { atomicWriteFile, getConfigDir } from "../config";
8
8
 
9
9
  /**
@@ -13,13 +13,18 @@ import { atomicWriteFile, getConfigDir } from "../config";
13
13
  */
14
14
  export const MAX_ROLLOUT_ZST_DECOMPRESSED_BYTES = 64 * 1024 * 1024;
15
15
 
16
- const STATE_DB_PATH = join(CODEX_HOME, "state_5.sqlite");
17
- function historyBackupPathFor(stateDbPath: string): string {
16
+ /**
17
+ * The manifest that shadows one state database.
18
+ *
19
+ * Exported because the history job must resolve it at CALL time for a Worker
20
+ * that does not inherit this module's load-time constants — and must resolve it
21
+ * the same way, since a manifest addressed differently is a different manifest.
22
+ */
23
+ export function historyBackupPathFor(stateDbPath: string): string {
18
24
  const normalized = process.platform === "win32" ? resolve(stateDbPath).toLowerCase() : resolve(stateDbPath);
19
25
  const id = createHash("sha256").update(normalized).digest("hex").slice(0, 16);
20
26
  return join(getConfigDir(), `codex-history-backup-${id}.json`);
21
27
  }
22
- const HISTORY_BACKUP_PATH = historyBackupPathFor(STATE_DB_PATH);
23
28
  const RESUMABLE_SOURCES = ["cli", "vscode"] as const;
24
29
 
25
30
  /**
@@ -157,7 +162,9 @@ function patchFirstLineProviderInPlace(path: string, expectedId: string, provide
157
162
  }
158
163
  }
159
164
 
160
- type CodexHistoryProvider = "openai" | "opencodex";
165
+ export type CodexHistoryProvider = "openai" | "opencodex";
166
+
167
+ export type CodexHistoryFailureReason = "busy" | "permission";
161
168
 
162
169
  export interface CodexHistorySyncResult {
163
170
  rows: number;
@@ -165,6 +172,8 @@ export interface CodexHistorySyncResult {
165
172
  ejectedRows?: number;
166
173
  /** Set when a lock/busy error survived retries and the sync was SKIPPED, not empty. */
167
174
  failed?: true;
175
+ /** Why the retry budget was exhausted when `failed` is set. */
176
+ failureReason?: CodexHistoryFailureReason;
168
177
  }
169
178
 
170
179
  interface ThreadRow {
@@ -189,6 +198,49 @@ interface BackupManifest {
189
198
  entries: Record<string, BackupEntry>;
190
199
  }
191
200
 
201
+ export interface CodexHistoryVerifiedNoopProof {
202
+ readonly kind: "verified-noop";
203
+ readonly pendingRows: 0;
204
+ readonly backupEntries: 0;
205
+ readonly canonicalStateDbPath: string;
206
+ readonly stateDbPresent: true;
207
+ readonly canonicalBackupPath: string;
208
+ readonly backupPresent: boolean;
209
+ }
210
+
211
+ export type CodexHistoryNoopSnapshot =
212
+ | CodexHistoryVerifiedNoopProof
213
+ | {
214
+ readonly kind: "work-pending";
215
+ readonly pendingRows: number;
216
+ readonly backupEntries: number;
217
+ readonly canonicalStateDbPath: string;
218
+ readonly stateDbPresent: boolean;
219
+ readonly canonicalBackupPath: string;
220
+ readonly backupPresent: boolean;
221
+ }
222
+ | {
223
+ readonly kind: "unknown";
224
+ readonly pendingRows: null;
225
+ readonly backupEntries: null;
226
+ readonly canonicalStateDbPath: string;
227
+ readonly stateDbPresent: boolean;
228
+ readonly canonicalBackupPath: string;
229
+ readonly backupPresent: boolean;
230
+ readonly reason: "backup-path" | "database-absent" | "manifest-read" | "manifest-schema" | "manifest-foreign" | "database-query" | "snapshot-race";
231
+ };
232
+
233
+ type StrictBackupInspection =
234
+ | { readonly kind: "known"; readonly present: boolean; readonly entries: number; readonly fingerprint: string }
235
+ | { readonly kind: "unknown"; readonly present: boolean; readonly reason: "manifest-read" | "manifest-schema" | "manifest-foreign" };
236
+
237
+ let afterNoopPendingCountForTests: (() => void) | undefined;
238
+
239
+ /** Test seam: runs after the pending count and before stability validation. */
240
+ export function setAfterNoopPendingCountForTests(hook: (() => void) | undefined): void {
241
+ afterNoopPendingCountForTests = hook;
242
+ }
243
+
192
244
  interface NativeRestoreTarget {
193
245
  modelProvider: string;
194
246
  source: string;
@@ -201,6 +253,65 @@ function samePath(a: string, b: string): boolean {
201
253
  return process.platform === "win32" ? left.toLowerCase() === right.toLowerCase() : left === right;
202
254
  }
203
255
 
256
+ function inspectBackupForNoop(path: string, stateDbPath: string): StrictBackupInspection {
257
+ if (!existsSync(path)) return { kind: "known", present: false, entries: 0, fingerprint: "absent" };
258
+ let parsed: unknown;
259
+ let raw: string;
260
+ try {
261
+ raw = readFileSync(path, "utf8");
262
+ parsed = JSON.parse(raw);
263
+ } catch {
264
+ return { kind: "unknown", present: true, reason: "manifest-read" };
265
+ }
266
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
267
+ return { kind: "unknown", present: true, reason: "manifest-schema" };
268
+ }
269
+ const manifest = parsed as Partial<BackupManifest>;
270
+ if (manifest.version !== 1 || typeof manifest.stateDbPath !== "string") {
271
+ return { kind: "unknown", present: true, reason: "manifest-schema" };
272
+ }
273
+ if (!samePath(manifest.stateDbPath, stateDbPath)) {
274
+ return { kind: "unknown", present: true, reason: "manifest-foreign" };
275
+ }
276
+ if (!manifest.entries || typeof manifest.entries !== "object" || Array.isArray(manifest.entries)) {
277
+ return { kind: "unknown", present: true, reason: "manifest-schema" };
278
+ }
279
+ for (const [id, value] of Object.entries(manifest.entries)) {
280
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
281
+ return { kind: "unknown", present: true, reason: "manifest-schema" };
282
+ }
283
+ const entry = value as Partial<BackupEntry>;
284
+ if (entry.id !== id
285
+ || typeof entry.rolloutPath !== "string"
286
+ || typeof entry.modelProvider !== "string"
287
+ || typeof entry.source !== "string"
288
+ || typeof entry.hasUserEvent !== "number") {
289
+ return { kind: "unknown", present: true, reason: "manifest-schema" };
290
+ }
291
+ }
292
+ return {
293
+ kind: "known",
294
+ present: true,
295
+ entries: Object.keys(manifest.entries).length,
296
+ fingerprint: createHash("sha256").update(raw).digest("hex"),
297
+ };
298
+ }
299
+
300
+ function historyFileIdentity(path: string): string | null {
301
+ try {
302
+ const stat = statSync(path);
303
+ return [stat.dev, stat.ino, stat.size, stat.mtimeMs, stat.ctimeMs].join(":");
304
+ } catch {
305
+ return null;
306
+ }
307
+ }
308
+
309
+ function readHistoryDataVersion(db: Database): number | null {
310
+ const row = db.query<{ data_version: number }, []>("PRAGMA data_version").get();
311
+ const value = row?.data_version;
312
+ return typeof value === "number" && Number.isSafeInteger(value) ? value : null;
313
+ }
314
+
204
315
  function readBackup(path: string, stateDbPath?: string): BackupManifest {
205
316
  if (!existsSync(path)) return { version: 1, stateDbPath, entries: {} };
206
317
  try {
@@ -508,19 +619,24 @@ function ejectRemainingOpencodexHistory(db: Database): { rows: number; files: nu
508
619
  return { rows: rows.length, files };
509
620
  }
510
621
 
511
- export function isRecoverableHistoryError(error: unknown): boolean {
622
+ export function classifyRecoverableHistoryError(error: unknown): CodexHistoryFailureReason | null {
512
623
  const code = typeof error === "object" && error && "code" in error ? String((error as { code?: unknown }).code) : "";
513
624
  const message = error instanceof Error ? error.message.toLowerCase() : String(error).toLowerCase();
514
- return code === "SQLITE_BUSY"
625
+ if (code === "SQLITE_BUSY"
515
626
  || code === "SQLITE_LOCKED"
516
627
  || code === "EBUSY"
517
- || code === "EPERM"
518
- || code === "EACCES"
519
628
  || message.includes("database is locked")
520
629
  || message.includes("database is busy")
521
- || message.includes("resource busy")
630
+ || message.includes("resource busy")) return "busy";
631
+ if (code === "EPERM"
632
+ || code === "EACCES"
522
633
  || message.includes("operation not permitted")
523
- || message.includes("permission denied");
634
+ || message.includes("permission denied")) return "permission";
635
+ return null;
636
+ }
637
+
638
+ export function isRecoverableHistoryError(error: unknown): boolean {
639
+ return classifyRecoverableHistoryError(error) !== null;
524
640
  }
525
641
 
526
642
  const HISTORY_RETRY_DELAY_MS = 500;
@@ -533,21 +649,29 @@ const HISTORY_RETRY_ATTEMPTS = 2;
533
649
  * error — callers surface that as `failed: true` instead of a silent no-op. Hard errors
534
650
  * (corruption, programming bugs) still throw.
535
651
  */
536
- export function withHistoryRetry<T>(fn: () => T, io: { sleepFn?: (ms: number) => void; attempts?: number; delayMs?: number } = {}): T | null {
652
+ function withHistoryRetryResult<T>(fn: () => T, io: { sleepFn?: (ms: number) => void; attempts?: number; delayMs?: number } = {}):
653
+ | { ok: true; value: T }
654
+ | { ok: false; reason: CodexHistoryFailureReason } {
537
655
  const sleepFn = io.sleepFn ?? Bun.sleepSync;
538
656
  const attempts = Math.max(1, io.attempts ?? HISTORY_RETRY_ATTEMPTS);
539
657
  const delayMs = io.delayMs ?? HISTORY_RETRY_DELAY_MS;
540
658
  for (let attempt = 0; ; attempt++) {
541
659
  try {
542
- return fn();
660
+ return { ok: true, value: fn() };
543
661
  } catch (error) {
544
- if (!isRecoverableHistoryError(error)) throw error;
545
- if (attempt >= attempts - 1) return null;
662
+ const reason = classifyRecoverableHistoryError(error);
663
+ if (!reason) throw error;
664
+ if (attempt >= attempts - 1) return { ok: false, reason };
546
665
  try { sleepFn(delayMs); } catch { /* sleep is best-effort */ }
547
666
  }
548
667
  }
549
668
  }
550
669
 
670
+ export function withHistoryRetry<T>(fn: () => T, io: { sleepFn?: (ms: number) => void; attempts?: number; delayMs?: number } = {}): T | null {
671
+ const result = withHistoryRetryResult(fn, io);
672
+ return result.ok ? result.value : null;
673
+ }
674
+
551
675
  /**
552
676
  * True when a READONLY probe proves the openai-direction restore would be a no-op:
553
677
  * zero threads still tagged opencodex AND an empty backup manifest. Used to skip the
@@ -564,8 +688,8 @@ function openaiRestoreIsNoop(stateDbPath: string, backupPath: string): boolean {
564
688
 
565
689
  export function syncCodexHistoryProvider(
566
690
  provider: CodexHistoryProvider,
567
- stateDbPath = STATE_DB_PATH,
568
- backupPath = HISTORY_BACKUP_PATH,
691
+ stateDbPath = resolveCodexStateDbPath(),
692
+ backupPath = historyBackupPathFor(stateDbPath),
569
693
  opts: { skipWhenProvablyNoop?: boolean } = {},
570
694
  ): CodexHistorySyncResult {
571
695
  // Opt-in steady-state gate (Design B loopback callers only): default semantics of
@@ -574,8 +698,8 @@ export function syncCodexHistoryProvider(
574
698
  && openaiRestoreIsNoop(stateDbPath, backupPath)) {
575
699
  return { rows: 0, files: 0 };
576
700
  }
577
- return withHistoryRetry(() => syncCodexHistoryProviderUnsafe(provider, stateDbPath, backupPath))
578
- ?? { rows: 0, files: 0, failed: true };
701
+ const retried = withHistoryRetryResult(() => syncCodexHistoryProviderUnsafe(provider, stateDbPath, backupPath));
702
+ return retried.ok ? retried.value : { rows: 0, files: 0, failed: true, failureReason: retried.reason };
579
703
  }
580
704
 
581
705
  function syncCodexHistoryProviderUnsafe(provider: CodexHistoryProvider, stateDbPath: string, backupPath: string): CodexHistorySyncResult {
@@ -698,16 +822,17 @@ function restoreCodexHistoryProvider(stateDbPath: string, backupPath: string): C
698
822
  }
699
823
  }
700
824
 
701
- export function restoreLegacyOpenaiHistory(stateDbPath = STATE_DB_PATH): { rows: number; files: number; failed?: true } {
825
+ export function restoreLegacyOpenaiHistory(stateDbPath = resolveCodexStateDbPath()): CodexHistorySyncResult {
702
826
  if (!existsSync(stateDbPath)) return { rows: 0, files: 0 };
703
- return withHistoryRetry(() => {
827
+ const retried = withHistoryRetryResult(() => {
704
828
  const db = openStateDb(stateDbPath);
705
829
  try {
706
830
  return ejectRemainingOpencodexHistory(db);
707
831
  } finally {
708
832
  db.close();
709
833
  }
710
- }) ?? { rows: 0, files: 0, failed: true };
834
+ });
835
+ return retried.ok ? retried.value : { rows: 0, files: 0, failed: true, failureReason: retried.reason };
711
836
  }
712
837
 
713
838
  /**
@@ -717,8 +842,8 @@ export function restoreLegacyOpenaiHistory(stateDbPath = STATE_DB_PATH): { rows:
717
842
  * per tick so a locked DB never stalls the event loop beyond one sqlite busy wait.
718
843
  */
719
844
  export function migrateHistoryToOpenai(
720
- stateDbPath = STATE_DB_PATH,
721
- backupPath = HISTORY_BACKUP_PATH,
845
+ stateDbPath = resolveCodexStateDbPath(),
846
+ backupPath = historyBackupPathFor(stateDbPath),
722
847
  opts: { attempts?: number; delayMs?: number; sleepFn?: (ms: number) => void } = {},
723
848
  ): CodexHistorySyncResult {
724
849
  if (!existsSync(stateDbPath)) return { rows: 0, files: 0 };
@@ -727,8 +852,83 @@ export function migrateHistoryToOpenai(
727
852
  // nothing. A missing DB with a leftover backup manifest does NOT satisfy the gate
728
853
  // (backupEntries > 0), so the guardian's fresh-reinstall re-count protection holds.
729
854
  if (openaiRestoreIsNoop(stateDbPath, backupPath)) return { rows: 0, files: 0 };
730
- return withHistoryRetry(() => syncCodexHistoryProviderUnsafe("openai", stateDbPath, backupPath), opts)
731
- ?? { rows: 0, files: 0, failed: true };
855
+ const retried = withHistoryRetryResult(() => syncCodexHistoryProviderUnsafe("openai", stateDbPath, backupPath), opts);
856
+ return retried.ok ? retried.value : { rows: 0, files: 0, failed: true, failureReason: retried.reason };
857
+ }
858
+
859
+ /**
860
+ * Captures no-op evidence while the caller holds the history serialization
861
+ * lock H. This function does not acquire H itself. Unknown or foreign backup
862
+ * state is never collapsed into an empty manifest.
863
+ */
864
+ export function snapshotCodexHistoryNoop(
865
+ stateDbPath: string,
866
+ backupPath: string,
867
+ ): CodexHistoryNoopSnapshot {
868
+ const canonicalStateDbPath = resolve(stateDbPath);
869
+ const canonicalBackupPath = resolve(backupPath);
870
+ const stateDbPresent = existsSync(stateDbPath);
871
+ const backupPresent = existsSync(backupPath);
872
+ const base = { canonicalStateDbPath, stateDbPresent, canonicalBackupPath, backupPresent };
873
+ if (!samePath(backupPath, historyBackupPathFor(stateDbPath))) {
874
+ return { kind: "unknown", pendingRows: null, backupEntries: null, ...base, reason: "backup-path" };
875
+ }
876
+ const backup = inspectBackupForNoop(backupPath, stateDbPath);
877
+ if (backup.kind === "unknown") {
878
+ return { kind: "unknown", pendingRows: null, backupEntries: null, ...base, reason: backup.reason };
879
+ }
880
+ if (!stateDbPresent) {
881
+ return backup.entries > 0
882
+ ? { kind: "work-pending", pendingRows: 0, backupEntries: backup.entries, ...base }
883
+ : { kind: "unknown", pendingRows: null, backupEntries: null, ...base, reason: "database-absent" };
884
+ }
885
+ const stateDbIdentity = historyFileIdentity(stateDbPath);
886
+ if (stateDbIdentity === null) {
887
+ return { kind: "unknown", pendingRows: null, backupEntries: null, ...base, reason: "snapshot-race" };
888
+ }
889
+ let monitor: Database | undefined;
890
+ try {
891
+ monitor = new Database(stateDbPath, { readonly: true });
892
+ monitor.exec("PRAGMA busy_timeout = 100");
893
+ const dataVersionBefore = readHistoryDataVersion(monitor);
894
+ if (dataVersionBefore === null) {
895
+ return { kind: "unknown", pendingRows: null, backupEntries: null, ...base, reason: "database-query" };
896
+ }
897
+ const pending = countPendingOpencodexHistory(stateDbPath, backupPath);
898
+ if (pending.failed) {
899
+ return { kind: "unknown", pendingRows: null, backupEntries: null, ...base, reason: "database-query" };
900
+ }
901
+ afterNoopPendingCountForTests?.();
902
+ const backupAfter = inspectBackupForNoop(backupPath, stateDbPath);
903
+ if (backupAfter.kind === "unknown") {
904
+ return { kind: "unknown", pendingRows: null, backupEntries: null, ...base, reason: backupAfter.reason };
905
+ }
906
+ const dataVersionAfter = readHistoryDataVersion(monitor);
907
+ if (dataVersionAfter === null) {
908
+ return { kind: "unknown", pendingRows: null, backupEntries: null, ...base, reason: "database-query" };
909
+ }
910
+ if (dataVersionAfter !== dataVersionBefore
911
+ || pending.backupEntries !== backup.entries
912
+ || backupAfter.entries !== backup.entries
913
+ || backupAfter.present !== backup.present
914
+ || backupAfter.fingerprint !== backup.fingerprint
915
+ || historyFileIdentity(stateDbPath) !== stateDbIdentity
916
+ || existsSync(stateDbPath) !== stateDbPresent
917
+ || existsSync(backupPath) !== backupPresent) {
918
+ return { kind: "unknown", pendingRows: null, backupEntries: null, ...base, reason: "snapshot-race" };
919
+ }
920
+ return pending.pendingRows === 0 && backup.entries === 0
921
+ ? { kind: "verified-noop", pendingRows: 0, backupEntries: 0, ...base, stateDbPresent: true }
922
+ : { kind: "work-pending", pendingRows: pending.pendingRows, backupEntries: backup.entries, ...base };
923
+ } catch {
924
+ return { kind: "unknown", pendingRows: null, backupEntries: null, ...base, reason: "database-query" };
925
+ } finally {
926
+ try {
927
+ monitor?.close();
928
+ } catch {
929
+ // Read-only monitor cleanup cannot make an uncertain snapshot authoritative.
930
+ }
931
+ }
732
932
  }
733
933
 
734
934
  export interface PendingHistoryCount {
@@ -746,7 +946,10 @@ export interface PendingHistoryCount {
746
946
  * pending predicate mirrors ejectRemainingOpencodexHistory exactly — rows eject ignores
747
947
  * (empty first_user_message) are not counted, so 0 really means "migration done".
748
948
  */
749
- export function countPendingOpencodexHistory(stateDbPath = STATE_DB_PATH, backupPath = HISTORY_BACKUP_PATH): PendingHistoryCount {
949
+ export function countPendingOpencodexHistory(
950
+ stateDbPath = resolveCodexStateDbPath(),
951
+ backupPath = historyBackupPathFor(stateDbPath),
952
+ ): PendingHistoryCount {
750
953
  let backupEntries = 0;
751
954
  try {
752
955
  const manifest = readBackup(backupPath, stateDbPath);
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Resolve the transition a history job belongs to.
3
+ *
4
+ * `updateCodexHistoryTransition` had no production caller, so every completed or
5
+ * skipped job left the coordinator row permanently `pending` — a transition was
6
+ * published and never resolved. This is that caller.
7
+ *
8
+ * The classification is `020_history_isolation.md:564-572`, applied rather than
9
+ * reinvented. The two unions do not line up one-to-one, so each outcome is
10
+ * mapped by hand: a cast across them would compile on the words they share and
11
+ * lie about the rest.
12
+ */
13
+ import type { CodexHistoryJobOutcome } from "./history-job";
14
+ import type { CodexHistoryState, CodexTransitionVersion } from "./convergence-types";
15
+ import { updateCodexHistoryTransition } from "./transition-state";
16
+
17
+ /** The retry budget for a contended terminal CAS. Bounded; never unbounded. */
18
+ const TERMINAL_RETRY_ATTEMPTS = 3;
19
+ const TERMINAL_RETRY_DELAY_MS = 250;
20
+
21
+ function sleep(ms: number): void {
22
+ // The caller path here is synchronous after the awaited job, so a spin is the
23
+ // honest tool — awaiting would be, and this is short.
24
+ const until = Date.now() + ms;
25
+ while (Date.now() < until) { /* bounded */ }
26
+ }
27
+
28
+ function classify(outcome: CodexHistoryJobOutcome, txId: string | null): CodexHistoryState {
29
+ switch (outcome.kind) {
30
+ case "converged":
31
+ return {
32
+ status: "converged",
33
+ attempts: 1,
34
+ nextRetryAt: null,
35
+ txId,
36
+ // A zero is durable only when the worker proved the exact DB/manifest
37
+ // state while H was held. Without proof, keep the counts unknown. Keep
38
+ // `??`: `||` would discard a verified zero.
39
+ pendingRows: outcome.proof?.pendingRows ?? null,
40
+ backupEntries: outcome.proof?.backupEntries ?? null,
41
+ };
42
+ case "skipped":
43
+ // The user opting out is a completed decision, not a failure — converged
44
+ // with no reason. Marking it blocked would retry what they asked not to do.
45
+ return { status: "converged", attempts: 0, nextRetryAt: null, txId, pendingRows: null, backupEntries: null };
46
+ case "blocked":
47
+ return {
48
+ status: outcome.reason === "busy" ? "pending" : "blocked",
49
+ reason: outcome.reason === "busy" ? "db-busy"
50
+ : outcome.reason === "database" ? "unreadable"
51
+ : "permission",
52
+ attempts: 1,
53
+ // A busy unit retries; the others do not reschedule themselves.
54
+ nextRetryAt: outcome.reason === "busy"
55
+ ? new Date(Date.now() + TERMINAL_RETRY_DELAY_MS * 10).toISOString()
56
+ : null,
57
+ txId,
58
+ pendingRows: null,
59
+ backupEntries: null,
60
+ };
61
+ case "failed":
62
+ return {
63
+ status: "unknown",
64
+ reason: outcome.reason === "timeout" ? "timeout"
65
+ : outcome.reason === "worker-died" ? "worker-died"
66
+ : "record-write-failed",
67
+ attempts: 1,
68
+ nextRetryAt: null,
69
+ txId,
70
+ pendingRows: null,
71
+ backupEntries: null,
72
+ };
73
+ }
74
+ }
75
+
76
+ /**
77
+ * Publish the terminal state of a history job against the transition it belongs
78
+ * to. A `conflict` means a newer transition won and is deliberately left alone.
79
+ * A `busy` terminal CAS retries a bounded number of times; when that exhausts,
80
+ * the previously persisted `pending` schedule is left intact — the same update
81
+ * needs the lock that was busy, so it cannot record its own failure
82
+ * (`005_contract.md:277`), and the retry being out of attempts is itself a
83
+ * terminal observation.
84
+ */
85
+ export function resolveCodexHistoryTransition(
86
+ receipt: CodexTransitionVersion,
87
+ outcome: CodexHistoryJobOutcome,
88
+ ): void {
89
+ const state = classify(outcome, receipt.currentTxId);
90
+ for (let attempt = 0; attempt < TERMINAL_RETRY_ATTEMPTS; attempt += 1) {
91
+ const result = updateCodexHistoryTransition(receipt, state);
92
+ if (result.kind === "updated") return;
93
+ if (result.kind === "conflict") {
94
+ // A newer transition already owns the row. Overwriting it would be the
95
+ // overtaken job overwriting the winner.
96
+ return;
97
+ }
98
+ if (result.reason === "busy") {
99
+ if (attempt + 1 < TERMINAL_RETRY_ATTEMPTS) sleep(TERMINAL_RETRY_DELAY_MS * (attempt + 1));
100
+ continue;
101
+ }
102
+ // database / unsafe-path: retried CAS will not help.
103
+ return;
104
+ }
105
+ }