@bitkyc08/opencodex 2.80.0 → 2.82.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 (376) hide show
  1. package/README.md +3 -3
  2. package/bin/ocx.mjs +166 -73
  3. package/gui/dist/assets/App-Ds_qL7o8.js +54 -0
  4. package/gui/dist/assets/Tray-BqHF5Trd.js +1 -0
  5. package/gui/dist/assets/{index-Brk6F3fn.css → index-BAbcj51J.css} +1 -1
  6. package/gui/dist/assets/index-D3FBCNiP.js +94 -0
  7. package/gui/dist/assets/quota-summary-DTBC8n7-.js +1 -0
  8. package/gui/dist/index.html +2 -2
  9. package/gui/dist/provider-icons/claude-green.svg +1 -0
  10. package/package.json +3 -2
  11. package/src/adapters/anthropic-model-contract.ts +8 -2
  12. package/src/adapters/anthropic.ts +8 -3
  13. package/src/adapters/codebuddy/mcp-server.ts +2 -25
  14. package/src/adapters/codebuddy/tool-bridge.ts +1 -7
  15. package/src/adapters/coding-agent/mcp-server.ts +33 -0
  16. package/src/adapters/coding-agent/protocol.ts +122 -17
  17. package/src/adapters/coding-agent/tool-catalog.ts +75 -0
  18. package/src/adapters/coding-agent/turn.ts +101 -44
  19. package/src/adapters/cursor/catalog.ts +8 -0
  20. package/src/adapters/cursor/effort-map.ts +2 -0
  21. package/src/adapters/devin/live-models.ts +2 -0
  22. package/src/adapters/kiro-retry.ts +9 -4
  23. package/src/adapters/openai-chat/messages.ts +7 -6
  24. package/src/adapters/openai-responses/compaction-search-history.ts +109 -0
  25. package/src/adapters/openai-responses/passthrough.ts +9 -4
  26. package/src/adapters/openai-responses/tool-output-recovery.ts +20 -0
  27. package/src/adapters/physical-send.ts +8 -5
  28. package/src/adapters/qoder/adapter.ts +41 -6
  29. package/src/adapters/qoder/scaffold-guard.ts +2 -3
  30. package/src/adapters/zed.ts +16 -1
  31. package/src/claude/agents-inject.ts +14 -3
  32. package/src/claude/context-windows.ts +19 -17
  33. package/src/claude/desktop-3p.ts +88 -12
  34. package/src/claude/desktop-profile.ts +2 -1
  35. package/src/claude/gateway-cache.ts +18 -1
  36. package/src/claude/inbound-cache-stabilize.ts +4 -9
  37. package/src/claude/inbound.ts +78 -3
  38. package/src/claude/intercept/cli-catalog.ts +3 -0
  39. package/src/claude/intercept/model-bindings.ts +1 -0
  40. package/src/claude/intercept/picker-ca-persistence.ts +7 -6
  41. package/src/claude/intercept/picker-listener.ts +71 -4
  42. package/src/claude/intercept/picker-models.ts +14 -6
  43. package/src/claude/intercept/settings.ts +3 -0
  44. package/src/claude/long-context.ts +66 -0
  45. package/src/claude/model-info.ts +19 -16
  46. package/src/claude/outbound.ts +94 -9
  47. package/src/claude/subagent-model.ts +40 -11
  48. package/src/cli/account-anthropic-threshold.ts +14 -5
  49. package/src/cli/account-api.ts +3 -1
  50. package/src/cli/account-extended.ts +13 -9
  51. package/src/cli/account-policy-dto.ts +1 -1
  52. package/src/cli/account-policy.ts +13 -4
  53. package/src/cli/account.ts +3 -3
  54. package/src/cli/agent.ts +9 -5
  55. package/src/cli/aside-profile-recovery.ts +33 -0
  56. package/src/cli/capabilities-accounts.ts +2 -2
  57. package/src/cli/capabilities-agents-routing.ts +24 -0
  58. package/src/cli/capabilities-base.ts +5 -5
  59. package/src/cli/capabilities-integrations.ts +18 -2
  60. package/src/cli/cli-path-diagnostics.ts +132 -0
  61. package/src/cli/codex-shim-autorestore.ts +3 -0
  62. package/src/cli/desktop-runtime-guidance.ts +65 -0
  63. package/src/cli/dispatch.ts +15 -1
  64. package/src/cli/doctor.ts +16 -3
  65. package/src/cli/help.ts +4 -1
  66. package/src/cli/index.ts +25 -14
  67. package/src/cli/integration-aside-sync.ts +2 -1
  68. package/src/cli/integration-plan-dto.ts +1 -0
  69. package/src/cli/integration-preview.ts +8 -1
  70. package/src/cli/integrations.ts +48 -6
  71. package/src/cli/message-args.ts +34 -0
  72. package/src/cli/message-command.ts +43 -0
  73. package/src/cli/message-runtime.ts +6 -0
  74. package/src/cli/observe.ts +3 -1
  75. package/src/cli/provider.ts +29 -6
  76. package/src/cli/registry.ts +24 -2
  77. package/src/cli/resolve.ts +25 -2
  78. package/src/cli/root.ts +4 -2
  79. package/src/cli/status.ts +64 -12
  80. package/src/cli/update-restart-child.ts +4 -2
  81. package/src/cli/update-restart-home.ts +28 -10
  82. package/src/cli/update-restart-service-record.ts +116 -0
  83. package/src/cli/update-restart-supervision.ts +96 -0
  84. package/src/cli/update-restart.ts +59 -13
  85. package/src/cli/v2.ts +27 -20
  86. package/src/cli/version-skew-notice.ts +77 -0
  87. package/src/clients/config-export/commandcode.ts +131 -0
  88. package/src/clients/config-export/contracts.ts +12 -0
  89. package/src/clients/config-export.ts +64 -1
  90. package/src/clients/lazycodex.ts +1 -1
  91. package/src/clients/omo-role-models.ts +32 -7
  92. package/src/codex/auth-api/account-list.ts +11 -3
  93. package/src/codex/auth-api/account-selection.ts +107 -0
  94. package/src/codex/auth-api/main-account-probe.ts +25 -8
  95. package/src/codex/auth-api/pool-mode-gate.ts +33 -9
  96. package/src/codex/auth-api/pool-quota-probe.ts +15 -1
  97. package/src/codex/auth-api/routes.ts +11 -49
  98. package/src/codex/auth-context.ts +20 -1
  99. package/src/codex/autostart-health.ts +12 -3
  100. package/src/codex/catalog/auto-review.ts +13 -6
  101. package/src/codex/catalog/build-entries.ts +33 -7
  102. package/src/codex/catalog/bundled.ts +155 -26
  103. package/src/codex/catalog/combo-member.ts +3 -2
  104. package/src/codex/catalog/control-plane.ts +45 -0
  105. package/src/codex/catalog/effort.ts +37 -6
  106. package/src/codex/catalog/gather-capture.ts +10 -3
  107. package/src/codex/catalog/model-hints.ts +15 -8
  108. package/src/codex/catalog/model-visibility.ts +3 -1
  109. package/src/codex/catalog/operator-tiers.ts +38 -0
  110. package/src/codex/catalog/parsing.ts +2 -1
  111. package/src/codex/catalog/provider-models.ts +58 -44
  112. package/src/codex/catalog/retained-sync.ts +7 -5
  113. package/src/codex/catalog/routed-gather.ts +15 -1
  114. package/src/codex/catalog-auto-refresh-sources.ts +3 -4
  115. package/src/codex/catalog-auto-refresh.ts +19 -0
  116. package/src/codex/catalog.ts +1 -1
  117. package/src/codex/codex-home-owner.ts +3 -0
  118. package/src/codex/config-write-lock.ts +333 -0
  119. package/src/codex/control-plane-models.ts +6 -0
  120. package/src/codex/convergence.ts +2 -1
  121. package/src/codex/features.ts +257 -200
  122. package/src/codex/inject/config-write-section.ts +34 -0
  123. package/src/codex/inject/multi-agent-v2.ts +14 -6
  124. package/src/codex/inject/remove.ts +36 -11
  125. package/src/codex/inject/restore.ts +85 -20
  126. package/src/codex/inject-coordination.ts +15 -6
  127. package/src/codex/inject.ts +62 -20
  128. package/src/codex/journal.ts +62 -17
  129. package/src/codex/main-account-cache.ts +43 -0
  130. package/src/codex/paths.ts +2 -0
  131. package/src/codex/prepared-home.ts +18 -0
  132. package/src/codex/prompt-journal.ts +25 -12
  133. package/src/codex/prompt-layers.ts +49 -26
  134. package/src/codex/prompt-lock-claim.ts +134 -0
  135. package/src/codex/prompt-lock-evidence.ts +26 -0
  136. package/src/codex/prompt-lock-io.ts +16 -0
  137. package/src/codex/prompt-lock-owner.ts +130 -0
  138. package/src/codex/prompt-lock.ts +84 -53
  139. package/src/codex/routing/failure-window.ts +146 -0
  140. package/src/codex/routing/selection.ts +4 -1
  141. package/src/codex/routing.ts +13 -17
  142. package/src/codex/runtime.ts +106 -18
  143. package/src/codex/shim.ts +45 -19
  144. package/src/combos/jev-decision-contract.ts +25 -2
  145. package/src/combos/jev-service-exchange.ts +281 -0
  146. package/src/combos/jev.ts +34 -219
  147. package/src/combos/types.ts +1 -1
  148. package/src/config/atomic-write.ts +1 -1
  149. package/src/config/codex-ws-reuse-setting.ts +10 -0
  150. package/src/config/diagnostics.ts +27 -16
  151. package/src/config/live-reconcile.ts +17 -0
  152. package/src/config/load-degrade.ts +42 -0
  153. package/src/config/rebase-provenance.ts +11 -0
  154. package/src/config/schema/anthropic-account-pool.ts +143 -0
  155. package/src/config/schema/config-schema.ts +11 -1
  156. package/src/config/schema/leaf-validators.ts +4 -0
  157. package/src/config.ts +2 -0
  158. package/src/generated/compatibility-version.json +566 -298
  159. package/src/generated/model-metadata.ts +7 -6
  160. package/src/grok/inject.ts +50 -4
  161. package/src/grok/sync.ts +2 -1
  162. package/src/images/loop.ts +30 -11
  163. package/src/integrations/aside-profiles.ts +10 -3
  164. package/src/integrations/catalog-refresh.ts +19 -3
  165. package/src/integrations/mutation-plan.ts +7 -0
  166. package/src/integrations/registry.ts +8 -0
  167. package/src/integrations/state.ts +9 -2
  168. package/src/integrations/writer.ts +17 -5
  169. package/src/lib/bun-path-runtime.d.mts +32 -0
  170. package/src/lib/bun-path-runtime.mjs +95 -0
  171. package/src/lib/bun-runtime-preflight.ts +140 -0
  172. package/src/lib/desktop-cli-handoff.d.mts +20 -0
  173. package/src/lib/desktop-cli-handoff.mjs +92 -0
  174. package/src/lib/desktop-cli-record.d.mts +29 -0
  175. package/src/lib/desktop-cli-record.mjs +102 -0
  176. package/src/lib/lab-live-route-production.ts +9 -1
  177. package/src/lib/request-execution-budget.ts +244 -58
  178. package/src/lib/spend-pool-alias-validation.ts +79 -0
  179. package/src/lib/spend-pool-continuity.ts +34 -0
  180. package/src/lib/spend-reservation-ledger.ts +412 -50
  181. package/src/lib/state-store-registrations.ts +20 -3
  182. package/src/lib/synced-state-location.ts +46 -6
  183. package/src/lib/test-home-guard.ts +87 -1
  184. package/src/lib/translator-budget.ts +17 -4
  185. package/src/lib/upstream-retry.ts +17 -5
  186. package/src/lib/windows-atomic-replace.ts +38 -16
  187. package/src/lib/windows-elevation.ts +6 -0
  188. package/src/lib/windows-secret-acl.ts +92 -25
  189. package/src/lib/winsw.ts +2 -3
  190. package/src/lib/workflow-budget.ts +53 -11
  191. package/src/messaging/budget.ts +45 -0
  192. package/src/messaging/discovery.ts +57 -0
  193. package/src/messaging/envelope.ts +49 -0
  194. package/src/messaging/input.ts +37 -0
  195. package/src/messaging/rpc.ts +196 -0
  196. package/src/messaging/send.ts +58 -0
  197. package/src/messaging/socket.ts +72 -0
  198. package/src/messaging/types.ts +29 -0
  199. package/src/oauth/anthropic-account-refusal.ts +90 -18
  200. package/src/oauth/anthropic-account-threshold.ts +8 -2
  201. package/src/oauth/anthropic-continuity.ts +15 -1
  202. package/src/oauth/anthropic-model-quota.ts +120 -48
  203. package/src/oauth/anthropic-model-routes.ts +11 -3
  204. package/src/oauth/anthropic-oauth-definitions.ts +98 -0
  205. package/src/oauth/anthropic-pool-config.ts +30 -0
  206. package/src/oauth/anthropic-rate-limit-policy.ts +64 -9
  207. package/src/oauth/anthropic-routing.ts +1202 -866
  208. package/src/oauth/anthropic-send-ownership.ts +41 -0
  209. package/src/oauth/anthropic.ts +4 -1
  210. package/src/oauth/chatgpt.ts +113 -41
  211. package/src/oauth/generic-account-failover.ts +3 -1
  212. package/src/oauth/health.ts +8 -6
  213. package/src/oauth/index.ts +96 -175
  214. package/src/oauth/kiro.ts +22 -9
  215. package/src/oauth/login-cli.ts +2 -0
  216. package/src/oauth/model-discovery-auth.ts +43 -0
  217. package/src/oauth/pool-kernel.ts +11 -5
  218. package/src/oauth/pool-settings-capability.ts +5 -3
  219. package/src/oauth/store-anthropic-instance.ts +87 -0
  220. package/src/oauth/store.ts +68 -10
  221. package/src/oauth/token-guardian.ts +2 -0
  222. package/src/oauth/types.ts +2 -0
  223. package/src/protocols/plan-snapshot.ts +5 -0
  224. package/src/protocols/settings.ts +20 -5
  225. package/src/providers/anthropic-instance-id.ts +47 -0
  226. package/src/providers/anthropic-instance.ts +48 -0
  227. package/src/providers/anthropic-reset-grant-ledger.ts +11 -1
  228. package/src/providers/azure-model-metadata.ts +115 -0
  229. package/src/providers/derive.ts +23 -0
  230. package/src/providers/kiro-models.ts +3 -0
  231. package/src/providers/label.ts +1 -1
  232. package/src/providers/model-rename-fields.ts +2 -0
  233. package/src/providers/quota/account-cache.ts +37 -11
  234. package/src/providers/quota/anthropic-account-quota.ts +93 -0
  235. package/src/providers/quota/anthropic-cooldown-recovery.ts +222 -111
  236. package/src/providers/quota/report-cache.ts +24 -1
  237. package/src/providers/quota/vendor-probes-key.ts +127 -17
  238. package/src/providers/quota/vendor-probes-oauth.ts +46 -14
  239. package/src/providers/quota.ts +23 -33
  240. package/src/providers/registry/entries-core.ts +35 -30
  241. package/src/providers/registry/model-ids.ts +1 -0
  242. package/src/providers/registry/model-seeds.ts +7 -4
  243. package/src/providers/registry/types.ts +3 -0
  244. package/src/providers/registry.ts +3 -3
  245. package/src/responses/reasoning-envelope.ts +29 -1
  246. package/src/responses/reasoning-replay-cache.ts +17 -1
  247. package/src/responses/spill-store.ts +20 -3
  248. package/src/responses/state/metrics.ts +95 -0
  249. package/src/responses/state/snapshot-codec.ts +6 -0
  250. package/src/responses/state/spill-failure.ts +12 -0
  251. package/src/responses/state/spill-queue.ts +13 -5
  252. package/src/responses/state/unforced-store-false.ts +55 -0
  253. package/src/responses/state.ts +68 -76
  254. package/src/responses/task-input.ts +17 -0
  255. package/src/router.ts +28 -4
  256. package/src/routing/compatibility/assemble.ts +1 -1
  257. package/src/routing/quota.ts +7 -3
  258. package/src/server/auth-cors.ts +5 -0
  259. package/src/server/background-lifecycle.ts +27 -0
  260. package/src/server/chat-completions.ts +7 -1
  261. package/src/server/chat-native.ts +64 -28
  262. package/src/server/claude-messages.ts +59 -8
  263. package/src/server/gui-static.ts +38 -4
  264. package/src/server/inbound-body-admission.ts +1 -0
  265. package/src/server/index/claude-intercept-lifecycle.ts +3 -1
  266. package/src/server/index/serve-options.ts +10 -2
  267. package/src/server/index/spend-ledger-lifecycle.ts +12 -5
  268. package/src/server/index/startup-warnings.ts +19 -0
  269. package/src/server/index.ts +5 -2
  270. package/src/server/inference/context.ts +1 -1
  271. package/src/server/lifecycle.ts +1 -1
  272. package/src/server/management/agent-settings-routes.ts +123 -38
  273. package/src/server/management/anthropic-account-threshold.ts +12 -9
  274. package/src/server/management/anthropic-pool-settings.ts +72 -0
  275. package/src/server/management/anthropic-reset-grant-routes.ts +98 -39
  276. package/src/server/management/codex-agent-role-routes.ts +4 -2
  277. package/src/server/management/codex-prompt-routes.ts +1 -0
  278. package/src/server/management/codex-role-auto-assign.ts +13 -2
  279. package/src/server/management/config-routes.ts +85 -14
  280. package/src/server/management/context.ts +2 -2
  281. package/src/server/management/decision-routes.ts +2 -1
  282. package/src/server/management/integration-routes.ts +25 -2
  283. package/src/server/management/oauth-account-routes.ts +79 -98
  284. package/src/server/management/provider-instance-ownership.ts +44 -0
  285. package/src/server/management/provider-routes.ts +21 -28
  286. package/src/server/management/route-registry.ts +3 -1
  287. package/src/server/management/routing-profile-routes.ts +4 -4
  288. package/src/server/management/shared.ts +3 -3
  289. package/src/server/management/system-restart.ts +44 -14
  290. package/src/server/management/system-routes.ts +24 -2
  291. package/src/server/management/vision-sidecar-options.ts +9 -6
  292. package/src/server/management/web-search-sidecar-options.ts +51 -2
  293. package/src/server/management-auth.ts +6 -0
  294. package/src/server/messages-native-eligibility.ts +3 -2
  295. package/src/server/messages-native-oauth.ts +91 -45
  296. package/src/server/messages-native-selector.ts +39 -0
  297. package/src/server/messages-native.ts +133 -38
  298. package/src/server/messages-response-headers.ts +14 -0
  299. package/src/server/request-log-conversation.ts +48 -5
  300. package/src/server/request-log.ts +36 -2
  301. package/src/server/responses/adapter-continuation.ts +31 -19
  302. package/src/server/responses/adapter-dispatch.ts +75 -24
  303. package/src/server/responses/antigravity-validation-refusal.ts +20 -6
  304. package/src/server/responses/codex-ws-exchange.ts +17 -2
  305. package/src/server/responses/codex-ws-pool.ts +100 -13
  306. package/src/server/responses/codex-ws-wire.ts +9 -0
  307. package/src/server/responses/combo-requested-effort.ts +3 -1
  308. package/src/server/responses/compact.ts +25 -8
  309. package/src/server/responses/compaction-recovery.ts +1 -1
  310. package/src/server/responses/core-codex-account.ts +22 -1
  311. package/src/server/responses/core-combo-native.ts +24 -4
  312. package/src/server/responses/core-combo.ts +38 -25
  313. package/src/server/responses/core-lifetime.ts +3 -36
  314. package/src/server/responses/core-normalize.ts +1 -0
  315. package/src/server/responses/core-options.ts +8 -1
  316. package/src/server/responses/core-replay.ts +78 -0
  317. package/src/server/responses/core.ts +3 -3
  318. package/src/server/responses/fetch-helpers.ts +26 -3
  319. package/src/server/responses/passthrough-delivery.ts +30 -4
  320. package/src/server/responses/passthrough-dispatch.ts +39 -9
  321. package/src/server/responses/request-prepare.ts +41 -5
  322. package/src/server/responses/request-send-budget.ts +150 -50
  323. package/src/server/responses/request-spend.ts +325 -33
  324. package/src/server/responses/request-transport.ts +132 -52
  325. package/src/server/responses/response-effects.ts +1 -0
  326. package/src/server/responses/run-turn-execution.ts +13 -3
  327. package/src/server/responses/sidecar-execution.ts +113 -22
  328. package/src/server/responses/sidecar-send-budget.ts +58 -0
  329. package/src/server/responses/ws-upstream.ts +19 -6
  330. package/src/server/responses-undeclared-tool-guard.ts +5 -1
  331. package/src/server/startup-health-cache.ts +2 -1
  332. package/src/server/workflow-refusal.ts +33 -0
  333. package/src/service/cli.ts +20 -4
  334. package/src/service/desktop-command-guard.ts +32 -0
  335. package/src/service/desktop-startup.ts +66 -40
  336. package/src/service/desktop-supervision.d.mts +26 -0
  337. package/src/service/desktop-supervision.mjs +140 -0
  338. package/src/service/managing-cli.ts +1 -0
  339. package/src/service/orchestration.ts +46 -20
  340. package/src/service/ownership-mutation-lease.d.mts +1 -1
  341. package/src/service/ownership-mutation-lease.mjs +5 -7
  342. package/src/service/repair.ts +25 -9
  343. package/src/service/state.ts +4 -3
  344. package/src/service/systemd.ts +17 -8
  345. package/src/service/windows-ops.ts +61 -22
  346. package/src/sidecar/anthropic-binding.ts +79 -0
  347. package/src/sidecar/auth.ts +76 -2
  348. package/src/storage/policy-job.ts +5 -1
  349. package/src/storage/policy-worker.ts +3 -1
  350. package/src/storage/policy.ts +9 -0
  351. package/src/types/anthropic-account-pool.ts +33 -0
  352. package/src/types/config.ts +33 -28
  353. package/src/types/provider.ts +5 -0
  354. package/src/types/request.ts +5 -0
  355. package/src/types/tools.ts +7 -0
  356. package/src/types/wire.ts +1 -0
  357. package/src/types.ts +4 -0
  358. package/src/update/index.ts +57 -9
  359. package/src/update/restart-ownership.ts +10 -3
  360. package/src/update/runtime-ownership.d.mts +6 -0
  361. package/src/update/runtime-ownership.mjs +23 -7
  362. package/src/usage/cost.ts +3 -2
  363. package/src/usage/expected-prices.ts +66 -14
  364. package/src/vision/anthropic-describe.ts +16 -3
  365. package/src/vision/index.ts +3 -0
  366. package/src/vision/plan.ts +19 -6
  367. package/src/web-search/alpha-search.ts +7 -1
  368. package/src/web-search/anthropic-executor.ts +16 -4
  369. package/src/web-search/index.ts +7 -3
  370. package/src/web-search/loop.ts +32 -7
  371. package/src/web-search/passthrough-bridge.ts +4 -1
  372. package/src/web-search/sidecar-providers.ts +4 -3
  373. package/gui/dist/assets/App-MbDVfUeC.js +0 -54
  374. package/gui/dist/assets/Tray-CzkxK82A.js +0 -1
  375. package/gui/dist/assets/index-UJt6npXk.js +0 -94
  376. package/gui/dist/assets/quota-summary-DU3sD6Z-.js +0 -1
@@ -1,3 +1,4 @@
1
+ import { readExistingSpendSalt, spendPoolAliasesError, validatePoolAliasOwners } from "../lib/spend-pool-alias-validation";
1
2
  import { isSubagentModelEntry, rawSubagentModelForce } from "./subagent-models";
2
3
  import { protocolConfigSchema } from "./schema/config-schema";
3
4
  import { createHash } from "node:crypto";
@@ -7,13 +8,13 @@ import * as z from "zod/v4";
7
8
  import { compactionRecoveryConfigError } from "./schema/compaction-recovery";
8
9
  import { blockedModelRedirectsError } from "./schema/blocked-model-redirects";
9
10
  import type { OcxConfig } from "../types";
10
- import { parseAnthropicModelRoutes } from "../oauth/anthropic-model-routes";
11
+ import { anthropicAccountPoolConfigError, anthropicOAuthInstanceConfigError, anthropicSidecarConfigError } from "./schema/anthropic-account-pool";
11
12
  import { configReasoningPinsConfigError } from "./provider-validation";
12
13
  import { loopbackCompanionAllowed } from "../codex/loopback-target";
13
14
  import { UPSTREAM_HOST_CIRCUIT_MAX_THRESHOLD } from "../codex/upstream-host-health";
14
15
  import { MAX_APP_OWNED_MEMORY_BUDGET_MB, MIN_APP_OWNED_MEMORY_BUDGET_MB } from "../lib/app-owned-memory";
15
16
  import { isMissingPathError } from "./atomic-write";
16
- import { getConfigPath } from "./paths";
17
+ import { getConfigDir, getConfigPath } from "./paths";
17
18
  import { getDefaultConfig } from "./proxy-env";
18
19
  import { salvageConfigCandidate } from "./salvage";
19
20
  import {
@@ -81,6 +82,23 @@ export type ConfigDiagnostics = {
81
82
  warnings?: string[];
82
83
  };
83
84
 
85
+ function rawPoolAliasesError(value: unknown): string | undefined {
86
+ const record = rawConfigRecord(value);
87
+ if (!record) return undefined;
88
+ const aliases = record.spendPoolAliases;
89
+ const shapeError = spendPoolAliasesError(aliases);
90
+ if (shapeError) return shapeError;
91
+ const mapping = rawConfigRecord(aliases);
92
+ if (!mapping || Object.keys(mapping).length === 0) return undefined;
93
+ const providers = rawConfigRecord(record.providers ?? {});
94
+ if (!providers) return "providers must be an object to validate spendPoolAliases";
95
+ const targetError = spendPoolAliasesError(aliases, Object.keys(providers));
96
+ if (targetError) return targetError;
97
+ const salt = readExistingSpendSalt(getConfigDir());
98
+ if (!salt) return "spendPoolAliases requires a safely readable existing spend salt";
99
+ return validatePoolAliasOwners(aliases, salt, Object.keys(providers));
100
+ }
101
+
84
102
  export type ConfigFileSnapshot = {
85
103
  diagnostics: ConfigDiagnostics;
86
104
  /** Exact file contents, including a possible BOM, used as the optimistic revision. */
@@ -145,6 +163,9 @@ function validFileConfigDiagnostics(config: OcxConfig, rawParsed: unknown): Conf
145
163
  if (codexPoolWarning) warnings.push(codexPoolWarning);
146
164
  const spendWarning = malformedSpendWarning(rawParsed);
147
165
  if (spendWarning) warnings.push(spendWarning);
166
+ if (rawPoolAliasesError(rawParsed)) {
167
+ warnings.push("spendPoolAliases invalid: configured pool admission is refused until the mapping is corrected");
168
+ }
148
169
  const plaintextWarning = malformedPlaintextV2AgentMessagesWarning(rawParsed);
149
170
  if (plaintextWarning) warnings.push(plaintextWarning);
150
171
  if (syncDisabledReason) {
@@ -153,7 +174,7 @@ function validFileConfigDiagnostics(config: OcxConfig, rawParsed: unknown): Conf
153
174
  return {
154
175
  config: normalized,
155
176
  source: "file",
156
- error: null,
177
+ error: anthropicOAuthInstanceConfigError(rawParsed) ?? anthropicAccountPoolConfigError(rawParsed) ?? anthropicSidecarConfigError(rawParsed) ?? null,
157
178
  ...(warnings.length > 0 ? { warnings } : {}),
158
179
  };
159
180
  }
@@ -655,19 +676,8 @@ export function validateConfigCandidate(value: unknown): { ok: true; config: Ocx
655
676
  if (protocols !== undefined && !protocolConfigSchema.safeParse(protocols).success) {
656
677
  return { ok: false, error: "schema_invalid: protocols: expected valid protocol policy and boolean rollout flags" };
657
678
  }
658
- const rawAnthropicPool = rawConfigRecord(value)?.anthropicAccountPool;
659
- const anthropicPool = rawConfigRecord(rawAnthropicPool);
660
- if (rawAnthropicPool !== undefined && !anthropicPool) {
661
- return { ok: false, error: "schema_invalid: anthropicAccountPool: must be an object" };
662
- }
663
- if (anthropicPool && Object.hasOwn(anthropicPool, "nativeMessages") && typeof anthropicPool.nativeMessages !== "boolean") {
664
- return { ok: false, error: "schema_invalid: anthropicAccountPool.nativeMessages: must be a boolean" };
665
- }
666
- const routeValue = anthropicPool?.routes;
667
- if (routeValue !== undefined) {
668
- const parsed = parseAnthropicModelRoutes(routeValue);
669
- if (!parsed.ok) return { ok: false, error: `schema_invalid: anthropicAccountPool.routes: ${parsed.error}` };
670
- }
679
+ const anthropicError = anthropicOAuthInstanceConfigError(value) ?? anthropicAccountPoolConfigError(value) ?? anthropicSidecarConfigError(value);
680
+ if (anthropicError) return { ok: false, error: anthropicError };
671
681
  const boundaryError = blockedModelRedirectsError(value)
672
682
  ?? compactionRecoveryConfigError(value) ?? configReasoningPinsConfigError(value)
673
683
  ?? blankHostnameError(value)
@@ -679,6 +689,7 @@ export function validateConfigCandidate(value: unknown): { ok: true; config: Ocx
679
689
  ?? agentTaskRecoveryError(value)
680
690
  ?? quotaResetNotifyError(value)
681
691
  ?? catalogAutoRefreshError(value)
692
+ ?? (rawPoolAliasesError(value) ? "schema_invalid: spendPoolAliases: invalid pool identity mapping" : null)
682
693
  ?? spendError(value)
683
694
  ?? codexPoolError(value)
684
695
  ?? googleAntigravityStaticCatalogVersionError(value)
@@ -8,6 +8,7 @@ import {
8
8
  clearPendingConfigObjectChildDeletions,
9
9
  prepareConfigObjectChildDeletionRebase,
10
10
  clearPendingConfigTopLevelDeletions,
11
+ clearConfigTopLevelDeletionIntent,
11
12
  configHasRebaseProvenance,
12
13
  configRebaseDeletionKeys,
13
14
  CONFIG_REBASE_PROVENANCE_KEY,
@@ -42,6 +43,22 @@ const claudeCodeBaseline = new WeakMap<OcxConfig, unknown>();
42
43
  */
43
44
  const liveConfigBaseline = new WeakMap<OcxConfig, OcxConfig>();
44
45
 
46
+ /** Adopt a committed manual selection without advancing unrelated live merge baselines. */
47
+ export function adoptPersistedCodexAccountSelection(
48
+ config: OcxConfig,
49
+ persisted: Pick<OcxConfig, "activeCodexAccountId" | "activeCodexAccountPinned">,
50
+ ): void {
51
+ const keys = ["activeCodexAccountId", "activeCodexAccountPinned"] as const;
52
+ const baseline = liveConfigBaseline.get(config);
53
+ for (const key of keys) {
54
+ config[key] = persisted[key];
55
+ // Retain known absent keys: a later disk-only selection is a new edit, not stale intent.
56
+ if (baseline) baseline[key] = persisted[key];
57
+ }
58
+ clearConfigTopLevelDeletionIntent(config, keys);
59
+ if (baseline) clearConfigTopLevelDeletionIntent(baseline, keys);
60
+ }
61
+
45
62
  /**
46
63
  * Adopt a committed discovery decision and its merge baseline as one synchronous step.
47
64
  * Visibility writers assign and save synchronously; any future writer yielding between
@@ -1,8 +1,10 @@
1
+ import { setCodexWsReuseAcrossTurns } from "./codex-ws-reuse-setting";
1
2
  import { isSubagentModelEntry, rawSubagentModelForce } from "./subagent-models";
2
3
  import { chmodSync, existsSync } from "node:fs";
3
4
  import { join } from "node:path";
4
5
  import { compactionRecoveryConfigError } from "./schema/compaction-recovery";
5
6
  import { blockedModelRedirectsError } from "./schema/blocked-model-redirects";
7
+ import { anthropicSidecarConfigError } from "./schema/anthropic-account-pool";
6
8
  import {
7
9
  modelPinnedEffortsConfigError,
8
10
  pinnedReasoningEffortConfigError,
@@ -25,6 +27,7 @@ import { refreshConfigDerivedRegistries } from "./derived-registries";
25
27
  import { type OcxClaudeCodeConfig, type OcxConfig } from "../types";
26
28
  import {
27
29
  agentTaskRecoverySchema,
30
+ asideProfileSyncSchema,
28
31
  catalogAutoRefreshSchema,
29
32
  clientConnectionSchema,
30
33
  isUsableApiKeySecret,
@@ -123,6 +126,7 @@ export function warnDegradedCompactionRouting(rawParsed: unknown, validated: Ocx
123
126
  * the ratchet only ever moves down: a per-block call there costs a line the file does not have.
124
127
  */
125
128
  export function warnDegradedTopLevelOptIns(rawParsed: unknown, validated: OcxConfig): void {
129
+ setCodexWsReuseAcrossTurns(validated.codexWsReuseAcrossTurns === true);
126
130
  if (compactionRecoveryConfigError(rawParsed)) console.warn("⚠️ invalid compactionRecovery disabled; the original compaction failure is preserved");
127
131
  if (blockedModelRedirectsError(rawParsed)) console.warn("⚠️ invalid blockedModelRedirects ignored; provider routing remains available");
128
132
  const chatgptDesktop = chatgptDesktopConfigIssue(rawParsed);
@@ -130,6 +134,11 @@ export function warnDegradedTopLevelOptIns(rawParsed: unknown, validated: OcxCon
130
134
  warnDegradedStreamMode(rawParsed, validated);
131
135
  warnDegradedCompactionRouting(rawParsed, validated);
132
136
  warnDegradedMemoryModels(rawParsed, validated);
137
+ // The schema replaces a malformed policy with { allProfiles: false }, which silently turns every Aside profile off (#6757).
138
+ const asidePolicy = rawParsed && typeof rawParsed === "object" ? (rawParsed as Record<string, unknown>).asideProfileSync : undefined;
139
+ if (asidePolicy !== undefined && !asideProfileSyncSchema.safeParse(asidePolicy).success) {
140
+ console.warn("⚠️ config.json asideProfileSync is invalid — Aside profile sync falls back to all profiles off; fix the block or inspect `ocx integration client status --client aside`");
141
+ }
133
142
  }
134
143
 
135
144
  /**
@@ -160,6 +169,39 @@ export function warnDegradedMemoryModels(rawParsed: unknown, validated: OcxConfi
160
169
  }
161
170
  }
162
171
 
172
+ /**
173
+ * Load-time degradation for helper `anthropicInstance` (loadConfig only). A malformed id, or one
174
+ * that conflicts with its block's backend or model, drops just that key with a warning, so the
175
+ * helper inherits the request's pool and every provider/key survives. Validated writes still
176
+ * reject the value and file diagnostics still report it from the raw document.
177
+ *
178
+ * Each location is checked in isolation, global blocks first, so a Claude override is judged
179
+ * against the already-degraded global block it inherits from. An override that owns no
180
+ * `anthropicInstance` of its own is left untouched: the conflicting key lives in the global
181
+ * block, which is valid on its own, and the inherited value is still a well-formed instance.
182
+ */
183
+ export function sanitizeAnthropicSidecarInstanceForLoad(parsed: unknown): void {
184
+ const asRecord = (value: unknown): Record<string, unknown> | undefined =>
185
+ value && typeof value === "object" && !Array.isArray(value) ? value as Record<string, unknown> : undefined;
186
+ const root = asRecord(parsed);
187
+ if (!root) return;
188
+ for (const scope of ["global", "claude"] as const) {
189
+ const owner = scope === "global" ? root : asRecord(root.claudeCode);
190
+ for (const field of ["webSearchSidecar", "visionSidecar"] as const) {
191
+ const sidecar = asRecord(owner?.[field]);
192
+ if (!sidecar || !Object.hasOwn(sidecar, "anthropicInstance")) continue;
193
+ const probe = scope === "global"
194
+ ? { [field]: sidecar }
195
+ : { [field]: root[field], claudeCode: { [field]: sidecar } };
196
+ const error = anthropicSidecarConfigError(probe);
197
+ if (!error) continue;
198
+ delete sidecar.anthropicInstance;
199
+ // The message names a static path and reason only; the hand-edited value is never echoed.
200
+ console.warn(`⚠️ config.json ${error} — ignoring that anthropicInstance; the helper inherits the request's Anthropic pool`);
201
+ }
202
+ }
203
+ }
204
+
163
205
  /**
164
206
  * Load-time degradation for `retryOn429` (loadConfig only): one hand-edited invalid optional
165
207
  * field (e.g. `attempts: 0` or a string) must not trip the whole provider schema and hide every
@@ -141,6 +141,17 @@ export function clearPendingConfigTopLevelDeletions(config: OcxConfig): void {
141
141
  pendingTopLevelDeletions.delete(config);
142
142
  }
143
143
 
144
+ /** A scoped durable adoption consumes only those fields' earlier deletion intent. */
145
+ export function clearConfigTopLevelDeletionIntent(config: OcxConfig, keys: readonly (keyof OcxConfig)[]): void {
146
+ const pending = pendingTopLevelDeletions.get(config);
147
+ for (const key of keys) pending?.delete(key);
148
+ const parsed = parsedConfigRebaseDeletionKeys(config);
149
+ if (parsed === null) return;
150
+ for (const key of keys) parsed.delete(key);
151
+ if (parsed.size === 0) delete config.configRebaseProvenance;
152
+ else config.configRebaseProvenance = { version: 1, deletedTopLevelKeys: [...parsed].sort() };
153
+ }
154
+
144
155
  export function clearPendingConfigObjectChildDeletions(config: OcxConfig): void {
145
156
  pendingObjectChildDeletions.delete(config);
146
157
  }
@@ -0,0 +1,143 @@
1
+ import * as z from "zod/v4";
2
+ import { parseAnthropicModelRoutes } from "../../oauth/anthropic-model-routes";
3
+ import { isAnthropicInstanceId } from "../../providers/anthropic-instance-id";
4
+ import { redactSecretString } from "../../lib/redact";
5
+
6
+ /** Historical A load contract, shared verbatim with B: recover only the native preference. */
7
+ export const anthropicAccountPoolSchema = z.object({
8
+ nativeMessages: z.boolean().optional().catch(false),
9
+ }).passthrough().optional().catch(undefined);
10
+
11
+ function record(value: unknown): Record<string, unknown> | undefined {
12
+ return value && typeof value === "object" && !Array.isArray(value)
13
+ ? value as Record<string, unknown> : undefined;
14
+ }
15
+
16
+ /** Write/diagnostic contract preserves A's historical nativeMessages and route validation. */
17
+ function poolError(value: unknown, path: string): string | undefined {
18
+ if (value === undefined) return undefined;
19
+ const pool = record(value);
20
+ if (!pool) return `schema_invalid: ${path}: must be an object`;
21
+ if (Object.hasOwn(pool, "nativeMessages") && typeof pool.nativeMessages !== "boolean") {
22
+ return `schema_invalid: ${path}.nativeMessages: must be a boolean`;
23
+ }
24
+ if (pool.routes !== undefined) {
25
+ const parsed = parseAnthropicModelRoutes(pool.routes);
26
+ if (!parsed.ok) return `schema_invalid: ${path}.routes: ${parsed.error}`;
27
+ }
28
+ return undefined;
29
+ }
30
+
31
+ /** Inspect raw locations before the tolerant load schema can discard a malformed field. */
32
+ export function anthropicAccountPoolConfigError(value: unknown): string | undefined {
33
+ const config = record(value);
34
+ const primaryError = poolError(config?.anthropicAccountPool, "anthropicAccountPool");
35
+ if (primaryError) return primaryError;
36
+ for (const [name, raw] of Object.entries(record(config?.providers) ?? {})) {
37
+ const provider = record(raw);
38
+ if (!provider || !Object.hasOwn(provider, "anthropicAccountPool")) continue;
39
+ const path = `providers.${redactSecretString(name)}.anthropicAccountPool`;
40
+ if (name !== "anthropic2") {
41
+ return `schema_invalid: ${path}: misplaced field; provider-local anthropicAccountPool is valid only on anthropic2 (anthropic uses the top-level field)`;
42
+ }
43
+ const error = poolError(provider.anthropicAccountPool, path);
44
+ if (error) return error;
45
+ }
46
+ return undefined;
47
+ }
48
+
49
+ /** Raw provenance validation runs before tolerant parsing and never adopts or edits a row. */
50
+ export function anthropicOAuthInstanceConfigError(value: unknown): string | undefined {
51
+ const seen = new WeakSet<object>();
52
+ const inspect = (raw: unknown, location: string[]): string | undefined => {
53
+ if (!raw || typeof raw !== "object" || seen.has(raw)) return undefined;
54
+ seen.add(raw);
55
+ for (const [field, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(raw))) {
56
+ const path = [...location, field];
57
+ if (field === "anthropicOAuthInstance") {
58
+ const label = redactSecretString(path.join("."));
59
+ if (!("value" in descriptor)) return `schema_invalid: ${label}: must be an own data property`;
60
+ if (location.length !== 2 || location[0] !== "providers" || location[1] !== "anthropic2") {
61
+ return `schema_invalid: ${label}: misplaced field; valid only on providers.anthropic2`;
62
+ }
63
+ if (descriptor.value !== "anthropic2") return `schema_invalid: ${label}: must be anthropic2`;
64
+ const row = Object.getOwnPropertyDescriptors(raw);
65
+ if (row.adapter?.value !== "anthropic" || row.authMode?.value !== "oauth") {
66
+ return `schema_invalid: ${label}: requires Anthropic adapter and OAuth authMode`;
67
+ }
68
+ }
69
+ if (!("value" in descriptor)) continue;
70
+ const error = inspect(descriptor.value, path);
71
+ if (error) return error;
72
+ }
73
+ seen.delete(raw);
74
+ return undefined;
75
+ };
76
+ return inspect(value, []);
77
+ }
78
+
79
+ /** Validate explicit helper identity without materializing an absent instance preference. */
80
+ export function anthropicSidecarConfigError(value: unknown): string | undefined {
81
+ const config = record(value);
82
+ const claude = record(config?.claudeCode);
83
+ for (const [prefix, owner] of [["", config], ["claudeCode.", claude]] as const) {
84
+ for (const field of ["webSearchSidecar", "visionSidecar"] as const) {
85
+ const rawSidecar = record(owner?.[field]);
86
+ if (!rawSidecar) continue;
87
+ // Claude overrides inherit individual global fields, just like buildClaudeReplayConfig.
88
+ const sidecar = prefix ? { ...record(config?.[field]), ...rawSidecar } : rawSidecar;
89
+ if (!Object.hasOwn(sidecar, "anthropicInstance")) continue;
90
+ const path = `${prefix}${field}.anthropicInstance`;
91
+ if (!isAnthropicInstanceId(sidecar.anthropicInstance)) {
92
+ return `schema_invalid: ${path}: must be anthropic or anthropic2`;
93
+ }
94
+ // Web search defaults to OpenAI; vision's absent backend keeps its credential-based auto mode.
95
+ const backend = sidecar.backend === undefined
96
+ ? (field === "webSearchSidecar" ? "openai" : undefined) : sidecar.backend;
97
+ // An instance inherited from the global block is inert once the override's effective backend
98
+ // leaves Anthropic (the helper resolver only reads it for the Anthropic family), so it is not
99
+ // a conflict. An instance the override sets itself is still validated in full.
100
+ if (prefix && !Object.hasOwn(rawSidecar, "anthropicInstance") && backend !== undefined && backend !== "anthropic") continue;
101
+ const modelProvider = typeof sidecar.model === "string" && sidecar.model.includes("/")
102
+ ? sidecar.model.slice(0, sidecar.model.indexOf("/")) : undefined;
103
+ if (modelProvider && isAnthropicInstanceId(modelProvider) && modelProvider !== sidecar.anthropicInstance) {
104
+ return `schema_invalid: ${path}: conflicts with the model's Anthropic instance`;
105
+ }
106
+ if (backend !== undefined && backend !== "anthropic") {
107
+ return `schema_invalid: ${path}: requires an anthropic backend`;
108
+ }
109
+ }
110
+ }
111
+ return undefined;
112
+ }
113
+
114
+ /** Validate the effective settings before either management route mutates live state. */
115
+ export function anthropicSidecarPatchError(
116
+ config: unknown,
117
+ patches: Record<string, unknown>,
118
+ claude = false,
119
+ ): string | undefined {
120
+ const source = record(config) ?? {};
121
+ const next = { ...source };
122
+ const owner = claude ? { ...record(source.claudeCode) } : next;
123
+ for (const field of ["webSearchSidecar", "visionSidecar"] as const) {
124
+ if (!Object.hasOwn(patches, field)) continue;
125
+ const patch = patches[field];
126
+ if (patch === null) { delete owner[field]; continue; }
127
+ const section = record(patch);
128
+ if (!section) continue; // Shape validation belongs to the route.
129
+ if (section.anthropicInstance !== undefined && section.anthropicInstance !== null
130
+ && !isAnthropicInstanceId(section.anthropicInstance)) {
131
+ return `${field}.anthropicInstance must be anthropic, anthropic2, or null`;
132
+ }
133
+ const settings = { ...record(owner[field]) };
134
+ for (const key of ["backend", "model", "anthropicInstance"] as const) {
135
+ if (section[key] === null || (key === "model" && section[key] === "")) delete settings[key];
136
+ else if (section[key] !== undefined) settings[key] = section[key];
137
+ }
138
+ if (claude && (Object.keys(section).length === 0 || Object.keys(settings).length === 0)) delete owner[field];
139
+ else owner[field] = settings;
140
+ }
141
+ if (claude) next.claudeCode = owner;
142
+ return anthropicSidecarConfigError(next);
143
+ }
@@ -1,5 +1,6 @@
1
1
  import { MAIN_ACCOUNT_HARD_LOCK_MIN_PERCENT } from "../../codex/quota-types";
2
2
  import * as z from "zod/v4";
3
+ import { anthropicAccountPoolSchema } from "./anthropic-account-pool";
3
4
  import { compactionRecoverySchema } from "./compaction-recovery";
4
5
  import { blockedModelRedirectsSchema } from "./blocked-model-redirects";
5
6
  import {
@@ -298,6 +299,10 @@ export const configSchema = z.object({
298
299
  codexAccountAutoSwitchThresholds: z.unknown().optional().transform(salvageCodexAccountAutoSwitchThresholds),
299
300
  // An invalid optional preference must not discard providers or credential rows.
300
301
  codexAccountPriorityFailback: z.boolean().optional().catch(false),
302
+ // Absent or invalid keeps the sliding window on. Explicit false restores consecutive-only steering.
303
+ codexFailureWindow: z.boolean().optional().catch(undefined),
304
+ codexPinnedTransientPolicy: z.enum(["hold", "detour-new-threads"]).optional().catch("hold"),
305
+ codexWsReuseAcrossTurns: z.boolean().optional().catch(false),
301
306
  activeCodexAccountPinned: z.string().regex(CODEX_ACCOUNT_PIN_PATTERN).optional().catch(undefined),
302
307
  // A malformed hand edit must degrade to false without discarding providers, accounts,
303
308
  // or the exact selector map. Live writes remain strict.
@@ -327,7 +332,7 @@ export const configSchema = z.object({
327
332
  blockedModelRedirects: blockedModelRedirectsSchema.optional().catch(undefined),
328
333
  // Degrade malformed hand edits locally; candidate writes reject them before parsing.
329
334
  // An invalid native preference retains the legacy route instead of enabling native by default.
330
- anthropicAccountPool: z.object({ nativeMessages: z.boolean().optional().catch(false) }).passthrough().optional().catch(undefined),
335
+ anthropicAccountPool: anthropicAccountPoolSchema,
331
336
  // Same degrade-don't-reject rationale as the fields above: a hand-edited
332
337
  // non-string must not trip the backup-and-defaults repair path. Unset then
333
338
  // takes the canonical sideband path (src/server/live.ts normalizeSidebandRoot).
@@ -350,6 +355,11 @@ export const configSchema = z.object({
350
355
  .map(row => apiKeyEntrySchema.parse(row) as OcxApiKeyEntry);
351
356
  }),
352
357
  }).passthrough().superRefine((config, ctx) => {
358
+ // Helper `anthropicInstance` is deliberately not refined here. A document-level issue would send
359
+ // loadConfig through salvage (which refuses pathless issues) to the backup-and-defaults path, so
360
+ // one hand-edited helper preference would hide every provider. Writes reject it explicitly in
361
+ // validateConfigCandidate, diagnostics report it from the raw file, and loadConfig drops only the
362
+ // offending key (sanitizeAnthropicSidecarInstanceForLoad).
353
363
  const claudeCode = (config as { claudeCode?: unknown }).claudeCode;
354
364
  if (claudeCode !== undefined && (!claudeCode || typeof claudeCode !== "object" || Array.isArray(claudeCode))) {
355
365
  ctx.addIssue({ code: "custom", path: ["claudeCode"], message: "claudeCode must be an object" });
@@ -1,4 +1,5 @@
1
1
  import * as z from "zod/v4";
2
+ import { anthropicAccountPoolSchema } from "./anthropic-account-pool";
2
3
  import { join } from "node:path";
3
4
  import { isValidProviderName } from "../provider-name";
4
5
  import {
@@ -285,6 +286,9 @@ const providerNoProxySchema = z.unknown().superRefine((value, ctx) => {
285
286
  * fields pass through (preserved for runtime extensions).
286
287
  */
287
288
  export const providerConfigSchema = z.object({
289
+ anthropicAccountPool: anthropicAccountPoolSchema,
290
+ // Raw diagnostics/writes reject malformed provenance; tolerant loads preserve the custom row.
291
+ anthropicOAuthInstance: z.literal("anthropic2").optional().catch(undefined),
288
292
  modelCapabilities: modelCapabilitiesSchema.optional(),
289
293
  modelContextTiers: z.unknown().superRefine((value, ctx) => {
290
294
  const error = contextTierRecordConfigError(value);
package/src/config.ts CHANGED
@@ -172,6 +172,7 @@ import {
172
172
  sanitizeModelDisplayNamesForLoad,
173
173
  sanitizeAutoReviewForLoad,
174
174
  sanitizeRetryOn429ForLoad,
175
+ sanitizeAnthropicSidecarInstanceForLoad,
175
176
  sanitizeModelCostsForLoad,
176
177
  sanitizeCapabilityDeclarationsForLoad,
177
178
  warnInheritedFastWireConflicts,
@@ -226,6 +227,7 @@ export function loadConfig(): OcxConfig {
226
227
  sanitizeModelDisplayNamesForLoad(parsed);
227
228
  sanitizeAutoReviewForLoad(parsed);
228
229
  sanitizeRetryOn429ForLoad(parsed);
230
+ sanitizeAnthropicSidecarInstanceForLoad(parsed);
229
231
  sanitizeModelCostsForLoad(parsed);
230
232
  sanitizeCapabilityDeclarationsForLoad(parsed);
231
233
  const result = configSchema.safeParse(parsed);