@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
@@ -2,13 +2,37 @@ import { existsSync, readFileSync, unlinkSync } from "node:fs";
2
2
  import { join } from "node:path";
3
3
  import { atomicWriteFile, getConfigDir } from "../config";
4
4
  import { captureConfigGeneration, type GenerationContext } from "../lib/state-store-sweeper";
5
+ import { isThirtyDayOnlyCodexPlan } from "./plan";
5
6
 
6
7
  export type StoredAccountQuota = {
7
8
  weeklyPercent?: number;
8
9
  monthlyPercent?: number;
9
10
  weeklyResetAt?: number;
10
11
  monthlyResetAt?: number;
12
+ /**
13
+ * A sub-day burst window, when upstream declares one (#1791).
14
+ *
15
+ * K12 and similar plans enforce a rolling 5-hour limit ALONGSIDE the weekly one.
16
+ * Not folding it into `weeklyPercent` stopped the mislabeling, but dropping it
17
+ * entirely hides a limit that genuinely blocks the account: a 429 at 100% here is
18
+ * real even while the weekly quota is untouched.
19
+ *
20
+ * `shortWindowSeconds` is retained because the duration is the only thing that makes
21
+ * this window self-describing; the slot it arrived in is not stable across plans.
22
+ */
23
+ shortPercent?: number;
24
+ shortResetAt?: number;
25
+ shortWindowSeconds?: number;
26
+ customWindows?: Array<{ label: string; percent: number; resetAt?: number }>;
11
27
  resetCredits?: number;
28
+ /**
29
+ * True when `monthlyPercent` came from an explicitly-monthly PRIMARY window —
30
+ * i.e. it is the account's governing quota reading, not a supplementary
31
+ * tertiary window. Tertiary-only monthly data lands in the same field but says
32
+ * nothing about the weekly quota that actually gates a non-Go/Free account,
33
+ * so recovery must be able to tell the two apart (#967 audit).
34
+ */
35
+ monthlyIsPrimaryWindow?: boolean;
12
36
  updatedAt: number;
13
37
  };
14
38
 
@@ -28,7 +52,7 @@ let persistTimer: ReturnType<typeof setTimeout> | null = null;
28
52
 
29
53
  export type WhamUsageResponse = {
30
54
  email?: string | null;
31
- plan_type?: string | null;
55
+ plan_type?: unknown;
32
56
  rate_limit?: {
33
57
  // Live WHAM payloads send explicit nulls for absent windows (issue #315 repro).
34
58
  primary_window?: WhamUsageWindow | null;
@@ -38,6 +62,16 @@ export type WhamUsageResponse = {
38
62
  rate_limit_reset_credits?: {
39
63
  available_count: number;
40
64
  } | null;
65
+ additional_rate_limits?: WhamAdditionalRateLimit[] | null;
66
+ };
67
+
68
+ type WhamAdditionalRateLimit = {
69
+ limit_name?: unknown;
70
+ metered_feature?: unknown;
71
+ rate_limit?: {
72
+ primary_window?: WhamUsageWindow | null;
73
+ secondary_window?: WhamUsageWindow | null;
74
+ } | null;
41
75
  };
42
76
 
43
77
  type WhamUsageWindow = {
@@ -47,7 +81,23 @@ type WhamUsageWindow = {
47
81
  };
48
82
 
49
83
  const MONTHLY_WINDOW_MIN_SECONDS = 28 * 24 * 60 * 60;
84
+ /**
85
+ * Shortest window still plausibly the WEEKLY quota (#1791).
86
+ *
87
+ * K12 and similar plans send a 5-hour primary window plus a 7-day secondary. Folding the
88
+ * primary into `weeklyPercent` reported the 5-hour bar as the weekly one and discarded the
89
+ * real weekly reading entirely, so the dashboard showed a window that reset every few hours
90
+ * and routing never saw the limit that actually gates the account.
91
+ *
92
+ * 24h is the discriminator: anything shorter is a burst window, not a weekly one. A window
93
+ * with no declared duration is unchanged, because older payloads omit `limit_window_seconds`
94
+ * and guessing there would break every legacy account.
95
+ */
96
+ const WEEKLY_WINDOW_MIN_SECONDS = 24 * 60 * 60;
50
97
  const MONTHLY_WINDOW_MIN_MINUTES = MONTHLY_WINDOW_MIN_SECONDS / 60;
98
+ // Derived, never written as a literal: the header parser and the WHAM parser must not be able
99
+ // to drift to different thresholds, which is the class of defect this pair exists to prevent.
100
+ const WEEKLY_WINDOW_MIN_MINUTES = WEEKLY_WINDOW_MIN_SECONDS / 60;
51
101
 
52
102
  const accountQuota = new Map<string, StoredAccountQuota>();
53
103
  let lastReconciledGeneration = 0;
@@ -63,19 +113,72 @@ export const CODEX_UNKNOWN_USAGE_SCORE = 101;
63
113
  export const CODEX_EXHAUSTED_USAGE_PERCENT = 100;
64
114
 
65
115
  export function isCodexQuotaExhausted(
66
- quota: Pick<StoredAccountQuota, "weeklyPercent" | "monthlyPercent"> | null,
67
- plan?: string | null,
116
+ quota: Pick<StoredAccountQuota, "weeklyPercent" | "monthlyPercent" | "shortPercent"> | null,
117
+ plan?: unknown,
68
118
  ): boolean {
69
119
  if (!quota) return false;
70
- const normalizedPlan = plan?.trim().toLowerCase();
71
- const values = normalizedPlan === "go" || normalizedPlan === "free"
72
- ? [quota.monthlyPercent]
73
- : [quota.weeklyPercent, quota.monthlyPercent];
120
+ // The burst window counts on EVERY plan. It is upstream-enforced independently, so an
121
+ // account at 100% there is blocked regardless of which longer window governs its plan;
122
+ // omitting it would route traffic straight into a 429 (#1791).
123
+ const values = codexQuotaWindowForPlan(plan) === "monthly"
124
+ ? [quota.monthlyPercent, quota.shortPercent]
125
+ : [quota.weeklyPercent, quota.monthlyPercent, quota.shortPercent];
74
126
  return values.some(value => typeof value === "number"
75
127
  && Number.isFinite(value)
76
128
  && value >= CODEX_EXHAUSTED_USAGE_PERCENT);
77
129
  }
78
130
 
131
+ /**
132
+ * Which usage window a plan reports in. This is the SINGLE rule shared by quota
133
+ * parsing, exhaustion, and recovery — they must not diverge.
134
+ *
135
+ * An allowlist of "known" plans was tried here and was wrong: the upstream model
136
+ * snapshot alone carries 21 distinct plan strings (`edu_plus`, `finserv`, `k12`,
137
+ * `quorum`, `self_serve_business_usage_based`, ...), and `CodexAccount.plan` is an
138
+ * unrestricted string, so any list is a list of the plans someone remembered.
139
+ * Twelve real plans would have been refused recovery and stayed cooled forever —
140
+ * the very defect this unit exists to fix, reintroduced as a typo-shaped hole.
141
+ *
142
+ * The honest rule is the parser's own: Go and Free report a 30-day window,
143
+ * everything else (including an absent plan) reports weekly. Recovery reads the
144
+ * window the parser actually wrote rather than second-guessing it.
145
+ */
146
+ export function codexQuotaWindowForPlan(plan?: unknown): "monthly" | "weekly" {
147
+ return isThirtyDayOnlyCodexPlan(plan) ? "monthly" : "weekly";
148
+ }
149
+
150
+ export function isCompleteCodexQuotaRecoverySnapshot(
151
+ quota: Pick<StoredAccountQuota, "weeklyPercent" | "monthlyPercent" | "monthlyIsPrimaryWindow" | "shortPercent"> | null,
152
+ plan?: unknown,
153
+ ): boolean {
154
+ if (!quota || isCodexQuotaExhausted(quota, plan)) return false;
155
+ // Recovery still fails closed on MISSING EVIDENCE — a credits-only or windowless payload
156
+ // carries no usage reading at all and must never clear a cooldown. What it does not do is
157
+ // fail closed on an unfamiliar plan NAME, which only ever meant "cooled forever".
158
+ //
159
+ // The parser classifies windows by DURATION, not by plan name: a Team response whose
160
+ // primary window is explicitly monthly parses to monthlyPercent only (no secondary
161
+ // window exists), so requiring weeklyPercent because the plan is not go/free would
162
+ // strand exactly those accounts until their predicted expiry. Accept whichever window(s)
163
+ // the parser actually wrote; Go/Free never carry a weekly value, so monthly-only is
164
+ // required there.
165
+ //
166
+ // Audit correction: "the parser wrote monthlyPercent" is NOT by itself evidence for a
167
+ // weekly-quota plan. A tertiary-only response also writes monthlyPercent, and it says
168
+ // nothing about the weekly quota that actually gates a Team/Plus account — accepting it
169
+ // would clear the cooldown on a reading of a different window. Only an explicitly-monthly
170
+ // PRIMARY window is the governing reading, which is what `monthlyIsPrimaryWindow` records.
171
+ if (codexQuotaWindowForPlan(plan) === "monthly") {
172
+ return finitePercent(quota.monthlyPercent);
173
+ }
174
+ if (finitePercent(quota.weeklyPercent)) return true;
175
+ return quota.monthlyIsPrimaryWindow === true && finitePercent(quota.monthlyPercent);
176
+ }
177
+
178
+ function finitePercent(value: number | undefined): boolean {
179
+ return typeof value === "number" && Number.isFinite(value);
180
+ }
181
+
79
182
  export function normalizeUsagePercent(value: unknown): number | undefined {
80
183
  const numeric = typeof value === "number"
81
184
  ? value
@@ -97,8 +200,18 @@ function normalizeResetAt(value: unknown): number | undefined {
97
200
  }
98
201
 
99
202
  function hasKnownQuotaValue(quota: Omit<StoredAccountQuota, "updatedAt">): boolean {
100
- return [quota.weeklyPercent, quota.monthlyPercent]
101
- .some(value => typeof value === "number" && Number.isFinite(value));
203
+ return [quota.weeklyPercent, quota.monthlyPercent, quota.shortPercent]
204
+ .some(value => typeof value === "number" && Number.isFinite(value))
205
+ || !!quota.customWindows?.some(window => Number.isFinite(window.percent));
206
+ }
207
+
208
+ /** True only for a window that DECLARES a duration shorter than a day. */
209
+ function isExplicitShortWindow(window: WhamUsageWindow | null | undefined): boolean {
210
+ const seconds = window?.limit_window_seconds;
211
+ return typeof seconds === "number"
212
+ && Number.isFinite(seconds)
213
+ && seconds > 0
214
+ && seconds < WEEKLY_WINDOW_MIN_SECONDS;
102
215
  }
103
216
 
104
217
  function isExplicitMonthlyWindow(window: WhamUsageWindow | null | undefined): boolean {
@@ -109,14 +222,24 @@ function isExplicitMonthlyWindow(window: WhamUsageWindow | null | undefined): bo
109
222
  }
110
223
 
111
224
  function isExplicitMonthlyWindowMinutes(windowMinutes: unknown): boolean {
112
- const minutes = typeof windowMinutes === "number"
113
- ? windowMinutes
114
- : typeof windowMinutes === "string" && windowMinutes.trim() !== ""
115
- ? Number(windowMinutes)
225
+ const minutes = windowMinutes_(windowMinutes);
226
+ return minutes !== undefined && minutes >= MONTHLY_WINDOW_MIN_MINUTES;
227
+ }
228
+
229
+ /** The header wire reports a window duration in MINUTES; WHAM reports it in seconds. */
230
+ function windowMinutes_(value: unknown): number | undefined {
231
+ const minutes = typeof value === "number"
232
+ ? value
233
+ : typeof value === "string" && value.trim() !== ""
234
+ ? Number(value)
116
235
  : undefined;
117
- return typeof minutes === "number"
118
- && Number.isFinite(minutes)
119
- && minutes >= MONTHLY_WINDOW_MIN_MINUTES;
236
+ return typeof minutes === "number" && Number.isFinite(minutes) ? minutes : undefined;
237
+ }
238
+
239
+ /** Minutes-domain twin of isExplicitShortWindow. Same strict `<`, same 24h discriminator. */
240
+ function isExplicitShortWindowMinutes(value: unknown): boolean {
241
+ const minutes = windowMinutes_(value);
242
+ return minutes !== undefined && minutes > 0 && minutes < WEEKLY_WINDOW_MIN_MINUTES;
120
243
  }
121
244
 
122
245
 
@@ -128,8 +251,18 @@ function snapshotHasMonthly(quota: Omit<StoredAccountQuota, "updatedAt">): boole
128
251
  return quota.monthlyPercent !== undefined || quota.monthlyResetAt !== undefined;
129
252
  }
130
253
 
254
+ function snapshotHasShort(quota: Omit<StoredAccountQuota, "updatedAt">): boolean {
255
+ return quota.shortPercent !== undefined
256
+ || quota.shortResetAt !== undefined
257
+ || quota.shortWindowSeconds !== undefined;
258
+ }
259
+
260
+ function snapshotHasCustom(quota: Omit<StoredAccountQuota, "updatedAt">): boolean {
261
+ return quota.customWindows !== undefined;
262
+ }
263
+
131
264
  function snapshotHasUsage(quota: Omit<StoredAccountQuota, "updatedAt">): boolean {
132
- return snapshotHasWeekly(quota) || snapshotHasMonthly(quota);
265
+ return snapshotHasWeekly(quota) || snapshotHasMonthly(quota) || snapshotHasShort(quota) || snapshotHasCustom(quota);
133
266
  }
134
267
  export function setAccountQuotaFromParsed(
135
268
  accountId: string,
@@ -147,6 +280,11 @@ export function setAccountQuotaFromParsed(
147
280
  if (existing?.weeklyResetAt !== undefined) next.weeklyResetAt = existing.weeklyResetAt;
148
281
  if (existing?.monthlyPercent !== undefined) next.monthlyPercent = existing.monthlyPercent;
149
282
  if (existing?.monthlyResetAt !== undefined) next.monthlyResetAt = existing.monthlyResetAt;
283
+ if (existing?.monthlyIsPrimaryWindow === true) next.monthlyIsPrimaryWindow = true;
284
+ if (existing?.shortPercent !== undefined) next.shortPercent = existing.shortPercent;
285
+ if (existing?.shortResetAt !== undefined) next.shortResetAt = existing.shortResetAt;
286
+ if (existing?.shortWindowSeconds !== undefined) next.shortWindowSeconds = existing.shortWindowSeconds;
287
+ if (existing?.customWindows !== undefined) next.customWindows = existing.customWindows;
150
288
  next.resetCredits = quota.resetCredits;
151
289
  accountQuota.set(accountId, next);
152
290
  schedulePersistAccountQuotas();
@@ -166,11 +304,32 @@ export function setAccountQuotaFromParsed(
166
304
  if (snapshotHasMonthly(quota)) {
167
305
  if (quota.monthlyPercent !== undefined) next.monthlyPercent = quota.monthlyPercent;
168
306
  if (quota.monthlyResetAt !== undefined) next.monthlyResetAt = quota.monthlyResetAt;
169
- } else if (snapshotHasWeekly(quota) && existing?.monthlyPercent !== undefined) {
307
+ // Carry the provenance with the value it describes. Recovery reads `freshQuota` directly,
308
+ // so this is not on its path today — but a cached snapshot that kept `monthlyPercent`
309
+ // while silently dropping `monthlyIsPrimaryWindow` would look like tertiary-only data to
310
+ // any future reader, and that failure would be invisible.
311
+ if (quota.monthlyIsPrimaryWindow === true) next.monthlyIsPrimaryWindow = true;
312
+ } else if ((snapshotHasWeekly(quota) || snapshotHasShort(quota) || snapshotHasCustom(quota))
313
+ && existing?.monthlyPercent !== undefined) {
170
314
  next.monthlyPercent = existing.monthlyPercent;
171
315
  if (existing.monthlyResetAt !== undefined) next.monthlyResetAt = existing.monthlyResetAt;
316
+ if (existing.monthlyIsPrimaryWindow === true) next.monthlyIsPrimaryWindow = true;
317
+ }
318
+
319
+ if (snapshotHasShort(quota)) {
320
+ if (quota.shortPercent !== undefined) next.shortPercent = quota.shortPercent;
321
+ if (quota.shortResetAt !== undefined) next.shortResetAt = quota.shortResetAt;
322
+ if (quota.shortWindowSeconds !== undefined) next.shortWindowSeconds = quota.shortWindowSeconds;
323
+ } else {
324
+ // Header and reset-credit updates are partial snapshots. Preserve the last full WHAM
325
+ // burst tuple when those updates do not carry enough window metadata to replace it.
326
+ if (existing?.shortPercent !== undefined) next.shortPercent = existing.shortPercent;
327
+ if (existing?.shortResetAt !== undefined) next.shortResetAt = existing.shortResetAt;
328
+ if (existing?.shortWindowSeconds !== undefined) next.shortWindowSeconds = existing.shortWindowSeconds;
172
329
  }
173
330
 
331
+ if (snapshotHasCustom(quota)) next.customWindows = quota.customWindows;
332
+
174
333
  if (quota.resetCredits !== undefined) next.resetCredits = quota.resetCredits;
175
334
  else if (existing?.resetCredits !== undefined) next.resetCredits = existing.resetCredits;
176
335
 
@@ -196,16 +355,39 @@ export function parseUpstreamQuotaHeaders(headers: Headers): Omit<StoredAccountQ
196
355
  const secondaryResetAt = normalizeResetAt(secondaryResetRaw);
197
356
  const tertiaryResetAt = normalizeResetAt(tertiaryResetRaw);
198
357
  const primaryIsMonthly = primaryRaw !== null && isExplicitMonthlyWindowMinutes(primaryWindowMinutes);
358
+ // Codex removed the 5-hour window and has now restored it for Plus and Team (Pro stays
359
+ // weekly-only). A primary window that DECLARES a sub-day duration is a burst window: folding
360
+ // it into weeklyPercent both discards the real weekly reading and leaves the account looking
361
+ // exhausted long after the burst window resets. Duration decides, exactly as parseUsageQuota
362
+ // already does for the WHAM payload — the two parsers must not disagree about the same data.
363
+ const primaryIsShort = primaryRaw !== null && isExplicitShortWindowMinutes(primaryWindowMinutes);
199
364
 
200
365
  if (primaryIsMonthly) {
201
366
  if (primaryPercent !== undefined) {
202
367
  quota.monthlyPercent = primaryPercent;
203
368
  if (primaryResetAt !== undefined) quota.monthlyResetAt = primaryResetAt;
369
+ // Same provenance rule as parseUsageQuota(): this monthly value is the governing
370
+ // primary window, not a supplementary tertiary one. Not on the recovery path today,
371
+ // but the two parsers must agree on what a bare monthlyPercent means.
372
+ quota.monthlyIsPrimaryWindow = true;
204
373
  }
205
374
  if (secondaryPercent !== undefined) {
206
375
  quota.weeklyPercent = secondaryPercent;
207
376
  if (secondaryResetAt !== undefined) quota.weeklyResetAt = secondaryResetAt;
208
377
  }
378
+ } else if (primaryIsShort) {
379
+ if (primaryPercent !== undefined) {
380
+ quota.shortPercent = primaryPercent;
381
+ if (primaryResetAt !== undefined) quota.shortResetAt = primaryResetAt;
382
+ const minutes = windowMinutes_(primaryWindowMinutes);
383
+ if (minutes !== undefined) quota.shortWindowSeconds = Math.round(minutes * 60);
384
+ }
385
+ // The burst window vacates the primary slot, so the weekly reading is the secondary — which
386
+ // is where it was all along. Without this the true weekly value is silently dropped.
387
+ if (secondaryPercent !== undefined) {
388
+ quota.weeklyPercent = secondaryPercent;
389
+ if (secondaryResetAt !== undefined) quota.weeklyResetAt = secondaryResetAt;
390
+ }
209
391
  } else {
210
392
  const weeklyPercent = primaryPercent ?? secondaryPercent;
211
393
  const weeklyResetAt = primaryPercent !== undefined
@@ -253,8 +435,17 @@ export function updateAccountQuota(
253
435
  const quota: StoredAccountQuota = {
254
436
  ...(existing?.weeklyPercent !== undefined ? { weeklyPercent: existing.weeklyPercent } : {}),
255
437
  ...(existing?.monthlyPercent !== undefined ? { monthlyPercent: existing.monthlyPercent } : {}),
438
+ // Carry provenance with the value it describes. Dropping it here would downgrade a proven
439
+ // explicit-primary reading to "unproven" on the next unrelated weekly update.
440
+ ...(existing?.monthlyPercent !== undefined && existing.monthlyIsPrimaryWindow === true
441
+ ? { monthlyIsPrimaryWindow: true }
442
+ : {}),
256
443
  ...(existing?.weeklyResetAt !== undefined ? { weeklyResetAt: existing.weeklyResetAt } : {}),
257
444
  ...(existing?.monthlyResetAt !== undefined ? { monthlyResetAt: existing.monthlyResetAt } : {}),
445
+ ...(existing?.shortPercent !== undefined ? { shortPercent: existing.shortPercent } : {}),
446
+ ...(existing?.shortResetAt !== undefined ? { shortResetAt: existing.shortResetAt } : {}),
447
+ ...(existing?.shortWindowSeconds !== undefined ? { shortWindowSeconds: existing.shortWindowSeconds } : {}),
448
+ ...(existing?.customWindows !== undefined ? { customWindows: existing.customWindows } : {}),
258
449
  ...(existing?.resetCredits !== undefined ? { resetCredits: existing.resetCredits } : {}),
259
450
  updatedAt: Date.now(),
260
451
  };
@@ -268,6 +459,10 @@ export function updateAccountQuota(
268
459
  if (nextMonthly !== undefined) {
269
460
  quota.monthlyPercent = nextMonthly;
270
461
  if (nextMonthlyResetAt !== undefined) quota.monthlyResetAt = nextMonthlyResetAt;
462
+ // A caller-supplied monthly value arrives without window provenance, so it REPLACES the
463
+ // proven reading and must not inherit its flag — otherwise an unproven number would be
464
+ // treated as governing evidence.
465
+ delete quota.monthlyIsPrimaryWindow;
271
466
  }
272
467
  if (resetCredits !== undefined) quota.resetCredits = resetCredits;
273
468
 
@@ -363,11 +558,14 @@ export function parseUsageQuota(data: WhamUsageResponse): Omit<StoredAccountQuot
363
558
  : undefined;
364
559
 
365
560
  if (!data.rate_limit) {
561
+ if (data.additional_rate_limits?.length) {
562
+ return parseUsageQuota({ ...data, rate_limit: {} });
563
+ }
366
564
  return resetCredits !== undefined ? { resetCredits } : null;
367
565
  }
368
566
 
369
567
  const quota: Omit<StoredAccountQuota, "updatedAt"> = {};
370
- const thirtyDayOnly = data.plan_type?.trim().toLowerCase() === "go" || data.plan_type?.trim().toLowerCase() === "free";
568
+ const thirtyDayOnly = codexQuotaWindowForPlan(data.plan_type) === "monthly";
371
569
  const primaryWindow = data.rate_limit.primary_window;
372
570
  const secondaryWindow = data.rate_limit.secondary_window;
373
571
  const tertiaryWindow = data.rate_limit.tertiary_window;
@@ -386,10 +584,25 @@ export function parseUsageQuota(data: WhamUsageResponse): Omit<StoredAccountQuot
386
584
  // - 선택한 방식: only an explicit primary duration of at least 28 days changes it to monthly.
387
585
  // - 다른 대안 대신 이 방식을 선택한 이유: it accepts calendar-month variance and preserves legacy payloads.
388
586
  // - 장점, 단점 및 영향: Team monthly quotas classify correctly; unknown durations remain weekly by design.
389
- const weeklyPercent = primaryIsMonthly ? secondaryPercent : primaryPercent ?? secondaryPercent;
587
+ // #1791: a primary window that declares a sub-day duration is a burst window, not the
588
+ // weekly one. Skip it so the secondary (the real 7-day window) is what lands in
589
+ // `weeklyPercent`; without this the 5-hour bar was reported as weekly and the actual
590
+ // weekly reading was dropped on the floor.
591
+ const primaryIsShort = isExplicitShortWindow(primaryWindow);
592
+ const weeklyCandidatePercent = primaryIsShort ? undefined : primaryPercent;
593
+ const weeklyCandidateResetAt = primaryIsShort ? undefined : primaryResetAt;
594
+ // Keep the burst reading instead of dropping it on the floor: it is a real limit, and
595
+ // the account is blocked when it fills even though the weekly window is fine (#1791).
596
+ if (primaryIsShort && primaryPercent !== undefined) {
597
+ quota.shortPercent = primaryPercent;
598
+ if (primaryResetAt !== undefined) quota.shortResetAt = primaryResetAt;
599
+ const seconds = primaryWindow?.limit_window_seconds;
600
+ if (typeof seconds === "number" && Number.isFinite(seconds)) quota.shortWindowSeconds = seconds;
601
+ }
602
+ const weeklyPercent = primaryIsMonthly ? secondaryPercent : weeklyCandidatePercent ?? secondaryPercent;
390
603
  const weeklyResetAt = primaryIsMonthly
391
604
  ? secondaryResetAt
392
- : primaryPercent !== undefined ? primaryResetAt : secondaryResetAt;
605
+ : weeklyCandidatePercent !== undefined ? weeklyCandidateResetAt : secondaryResetAt;
393
606
  const monthlyPercent = primaryIsMonthly ? primaryPercent ?? tertiaryPercent : tertiaryPercent;
394
607
  const monthlyResetAt = primaryIsMonthly && primaryPercent !== undefined ? primaryResetAt : tertiaryResetAt;
395
608
  if (thirtyDayOnly) {
@@ -404,6 +617,36 @@ export function parseUsageQuota(data: WhamUsageResponse): Omit<StoredAccountQuot
404
617
  if (!thirtyDayOnly && monthlyPercent !== undefined) {
405
618
  quota.monthlyPercent = monthlyPercent;
406
619
  if (monthlyResetAt !== undefined) quota.monthlyResetAt = monthlyResetAt;
620
+ // Record WHERE this reading came from. Only an explicitly-monthly primary window is the
621
+ // account's governing quota; a tertiary window lands in the same field but describes a
622
+ // different period, so recovery must not treat the two as interchangeable.
623
+ if (primaryIsMonthly && primaryPercent !== undefined) quota.monthlyIsPrimaryWindow = true;
624
+ }
625
+
626
+ const spark = data.additional_rate_limits?.find(additional => {
627
+ const name = String(additional.limit_name ?? "").toLowerCase();
628
+ const feature = String(additional.metered_feature ?? "").toLowerCase();
629
+ return feature === "codex_bengalfox" || name.includes("gpt-5.3-codex-spark");
630
+ });
631
+ const sparkWindows = [spark?.rate_limit?.primary_window, spark?.rate_limit?.secondary_window]
632
+ .filter((window): window is WhamUsageWindow => !!window);
633
+ const sparkWeekly = sparkWindows.find(window => {
634
+ const percent = normalizeUsagePercent(window.used_percent);
635
+ const seconds = window.limit_window_seconds;
636
+ return percent !== undefined
637
+ && !isExplicitShortWindow(window)
638
+ && !isExplicitMonthlyWindow(window)
639
+ && (seconds === undefined || seconds >= WEEKLY_WINDOW_MIN_SECONDS);
640
+ });
641
+ const sparkPercent = normalizeUsagePercent(sparkWeekly?.used_percent);
642
+ if (sparkPercent !== undefined) {
643
+ const sparkWindow: { label: string; percent: number; resetAt?: number } = {
644
+ label: "GPT-5.3-Codex-Spark Weekly",
645
+ percent: sparkPercent,
646
+ };
647
+ const resetAt = normalizeResetAt(sparkWeekly?.reset_at);
648
+ if (resetAt !== undefined) sparkWindow.resetAt = resetAt;
649
+ quota.customWindows = [sparkWindow];
407
650
  }
408
651
  if (resetCredits !== undefined) quota.resetCredits = resetCredits;
409
652
 
@@ -4,6 +4,7 @@ import type { ComboCatalogOmission } from "./catalog/aggregation";
4
4
  import { CODEX_MODELS_CACHE_PATH } from "./paths";
5
5
  import { atomicWriteFile } from "../config";
6
6
  import type { OcxConfig } from "../types";
7
+ import type { CodexCatalogSyncOptions } from "./catalog/sync";
7
8
 
8
9
  export interface CodexCatalogRefreshResult {
9
10
  added: number;
@@ -12,6 +13,8 @@ export interface CodexCatalogRefreshResult {
12
13
  catalogWritten: boolean;
13
14
  cacheSynced: boolean;
14
15
  comboOmissions: ComboCatalogOmission[];
16
+ /** Desired OFF observed under K during the catalog commit; no cache write either. */
17
+ skippedReason?: "desired_disabled";
15
18
  }
16
19
 
17
20
  interface RefreshDeps {
@@ -40,14 +43,20 @@ export function syncCodexModelsCacheFromCatalog(catalogPath: string): void {
40
43
  export async function refreshCodexModelCatalog(
41
44
  config: OcxConfig,
42
45
  deps: RefreshDeps = defaultDeps,
46
+ options?: CodexCatalogSyncOptions,
43
47
  ): Promise<CodexCatalogRefreshResult> {
44
- const result = await deps.syncCatalogModels(config);
48
+ const result = await deps.syncCatalogModels(config, options);
45
49
  const catalogExists = deps.existsSync(result.path);
46
50
  const catalogWritten = result.catalogWritten === true;
47
51
  const comboOmissions = result.comboOmissions ?? [];
52
+ if (result.skippedReason === "desired_disabled") {
53
+ // The commit path observed OFF under K. Invalidate nothing: rewriting the
54
+ // models cache here would be exactly the routed-cache write the skip refused.
55
+ return { ...result, catalogExists, catalogWritten: false, cacheSynced: false, comboOmissions };
56
+ }
48
57
  if (!catalogExists) {
49
58
  return { ...result, catalogExists, catalogWritten: false, cacheSynced: false, comboOmissions };
50
59
  }
51
- const cacheSynced = deps.invalidateCodexModelsCache();
60
+ const cacheSynced = deps.invalidateCodexModelsCache(options);
52
61
  return { ...result, catalogExists, catalogWritten, cacheSynced, comboOmissions };
53
62
  }