@bitkyc08/opencodex 2.59.0 → 2.61.0-preview.20260922

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 (374) hide show
  1. package/AGENTS_INSTALL.md +64 -0
  2. package/README.md +28 -1
  3. package/bin/ocx.mjs +382 -209
  4. package/gui/dist/assets/App-E64Rzjap.js +50 -0
  5. package/gui/dist/assets/Tray-_nfzD8k4.js +1 -0
  6. package/gui/dist/assets/index-DpdfZWMK.js +86 -0
  7. package/gui/dist/assets/index-_bpvxJu0.css +1 -0
  8. package/gui/dist/assets/usage-companion-chart-DtoK7T6h.js +1 -0
  9. package/gui/dist/favicon.png +0 -0
  10. package/gui/dist/index.html +2 -2
  11. package/gui/dist/provider-icons/stepfun-color.svg +1 -0
  12. package/package.json +8 -1
  13. package/src/adapters/anthropic-image-codec.ts +16 -2
  14. package/src/adapters/anthropic-image-normalize.ts +49 -2
  15. package/src/adapters/anthropic.ts +20 -1
  16. package/src/adapters/base.ts +23 -0
  17. package/src/adapters/coding-agent/protocol.ts +36 -6
  18. package/src/adapters/coding-agent/turn.ts +32 -4
  19. package/src/adapters/command-code.ts +52 -4
  20. package/src/adapters/cursor/catalog.ts +51 -7
  21. package/src/adapters/cursor/checkpoint-store.ts +3 -0
  22. package/src/adapters/cursor/discovery.ts +11 -8
  23. package/src/adapters/cursor/live-transport.ts +26 -9
  24. package/src/adapters/cursor/protobuf-request.ts +6 -3
  25. package/src/adapters/cursor/request-builder.ts +20 -4
  26. package/src/adapters/cursor/transport.ts +19 -0
  27. package/src/adapters/cursor.ts +14 -3
  28. package/src/adapters/declaration-carrier.ts +45 -0
  29. package/src/adapters/devin/cloud-direct/chat.ts +3 -1
  30. package/src/adapters/devin/cloud-direct/stated-reset-retry.ts +42 -5
  31. package/src/adapters/devin.ts +125 -36
  32. package/src/adapters/google-antigravity-replay.ts +1 -1
  33. package/src/adapters/google-antigravity-wire.ts +34 -7
  34. package/src/adapters/google-errors.ts +7 -1
  35. package/src/adapters/google-http.ts +49 -10
  36. package/src/adapters/google-tool-schema.ts +595 -31
  37. package/src/adapters/google-wire-compiler.ts +93 -10
  38. package/src/adapters/google-wire-shape.ts +461 -0
  39. package/src/adapters/google.ts +66 -11
  40. package/src/adapters/image.ts +4 -1
  41. package/src/adapters/input-media-guard.ts +21 -9
  42. package/src/adapters/kiro/usage.ts +3 -2
  43. package/src/adapters/kiro-tool-fallback.ts +1 -1
  44. package/src/adapters/ollama-native.ts +6 -0
  45. package/src/adapters/openai-chat/developer-role.ts +61 -0
  46. package/src/adapters/openai-chat/messages.ts +46 -27
  47. package/src/adapters/openai-chat/parallel-tool-calls.ts +32 -0
  48. package/src/adapters/openai-chat/passthrough.ts +33 -9
  49. package/src/adapters/openai-chat/reasoning-wire.ts +89 -0
  50. package/src/adapters/openai-chat-images.ts +3 -1
  51. package/src/adapters/openai-chat.ts +23 -58
  52. package/src/adapters/openai-responses/image-gen.ts +8 -6
  53. package/src/adapters/openai-responses/passthrough.ts +17 -3
  54. package/src/adapters/openai-responses/reasoning.ts +7 -0
  55. package/src/adapters/opencode-go-additional-tools.ts +12 -2
  56. package/src/adapters/registry.ts +3 -2
  57. package/src/adapters/run-turn-queue.ts +178 -29
  58. package/src/adapters/xai-web-search.ts +16 -1
  59. package/src/bridge/errors.ts +8 -2
  60. package/src/bridge/response-json.ts +9 -1
  61. package/src/bridge/sse.ts +13 -151
  62. package/src/chat/inbound.ts +141 -5
  63. package/src/claude/desktop-3p.ts +7 -1
  64. package/src/claude/desktop-first-party.ts +183 -0
  65. package/src/claude/desktop-gateway-state.ts +41 -0
  66. package/src/claude/inbound-content-options.ts +6 -0
  67. package/src/claude/inbound.ts +32 -6
  68. package/src/claude/intercept/connect-proxy.ts +179 -0
  69. package/src/claude/intercept/listener.ts +122 -0
  70. package/src/claude/intercept/local-ca.ts +298 -0
  71. package/src/claude/intercept/runtime.ts +98 -0
  72. package/src/claude/intercept/settings.ts +189 -0
  73. package/src/cli/access.ts +87 -0
  74. package/src/cli/account-auth.ts +19 -0
  75. package/src/cli/account-extended.ts +4 -4
  76. package/src/cli/capabilities.ts +31 -0
  77. package/src/cli/claude-desktop.ts +206 -16
  78. package/src/cli/codex-shim-autorestore.ts +3 -0
  79. package/src/cli/companion.ts +56 -0
  80. package/src/cli/dispatch.ts +46 -7
  81. package/src/cli/doctor.ts +28 -9
  82. package/src/cli/ensure-desired-integrations.ts +43 -5
  83. package/src/cli/help.ts +7 -9
  84. package/src/cli/hub.ts +3 -2
  85. package/src/cli/index.ts +203 -59
  86. package/src/cli/init.ts +8 -0
  87. package/src/cli/integrations.ts +7 -1
  88. package/src/cli/opencode.ts +2 -2
  89. package/src/cli/provider.ts +13 -1
  90. package/src/cli/registry.ts +41 -2
  91. package/src/cli/resolve.ts +230 -0
  92. package/src/cli/root.ts +24 -1
  93. package/src/cli/start-ownership-publication.ts +56 -0
  94. package/src/cli/status-probes.ts +2 -18
  95. package/src/cli/status.ts +62 -0
  96. package/src/cli/stop-report.ts +143 -0
  97. package/src/cli/uninstall-plan.ts +9 -0
  98. package/src/client/machine-api.ts +2 -2
  99. package/src/client/machine-listener.ts +4 -7
  100. package/src/client/runtime.ts +26 -2
  101. package/src/clients/aside-profiles.ts +4 -0
  102. package/src/clients/config-export/zcode-store.ts +157 -0
  103. package/src/clients/config-export.ts +36 -0
  104. package/src/codex/account-store.ts +65 -0
  105. package/src/codex/app-server-processes.ts +72 -40
  106. package/src/codex/auth-api/account-list.ts +19 -11
  107. package/src/codex/auth-api/login-flow.ts +6 -1
  108. package/src/codex/auth-api/pool-quota-probe.ts +30 -7
  109. package/src/codex/autostart-health.ts +28 -0
  110. package/src/codex/catalog/build-entries.ts +2 -2
  111. package/src/codex/catalog/effort.ts +3 -3
  112. package/src/codex/catalog/gather-capture.ts +21 -2
  113. package/src/codex/catalog/model-hints.ts +29 -28
  114. package/src/codex/catalog/parsing.ts +7 -0
  115. package/src/codex/catalog/provider-models.ts +43 -17
  116. package/src/codex/catalog/retained-sync.ts +24 -28
  117. package/src/codex/catalog/routed-gather.ts +19 -0
  118. package/src/codex/context-compat.ts +5 -2
  119. package/src/codex/convergence.ts +2 -2
  120. package/src/codex/desired-state.ts +4 -1
  121. package/src/codex/history-job.ts +6 -6
  122. package/src/codex/history-provider.ts +31 -166
  123. package/src/codex/history-rollout-read.ts +174 -0
  124. package/src/codex/inject/config-toml.ts +41 -6
  125. package/src/codex/inject/paginated-openai-compat.ts +90 -0
  126. package/src/codex/inject.ts +18 -15
  127. package/src/codex/injected-marker.ts +18 -0
  128. package/src/codex/internal/catalog-writer.ts +33 -1
  129. package/src/codex/main-account.ts +6 -0
  130. package/src/codex/model-cache.ts +99 -6
  131. package/src/codex/model-entitlement-admission.ts +59 -0
  132. package/src/codex/model-entitlements.ts +116 -54
  133. package/src/codex/native-main-admission.ts +83 -0
  134. package/src/codex/observed-model-denials.ts +101 -8
  135. package/src/codex/prompt-text-probe.ts +9 -6
  136. package/src/codex/routing/health-store.ts +39 -0
  137. package/src/codex/routing/selection.ts +37 -1
  138. package/src/codex/routing.ts +12 -42
  139. package/src/codex/shim-templates.ts +29 -3
  140. package/src/codex/shim.ts +1 -1
  141. package/src/codex/subagent-model-fallback.ts +22 -4
  142. package/src/combos/failover.ts +3 -0
  143. package/src/companion/settings.ts +132 -0
  144. package/src/config/admitted-identity.ts +222 -0
  145. package/src/config/atomic-write.ts +117 -5
  146. package/src/config/diagnostics.ts +22 -1
  147. package/src/config/feature-flags.ts +5 -0
  148. package/src/config/load-degrade.ts +52 -7
  149. package/src/config/process-state.ts +1 -1
  150. package/src/config/proxy-env.ts +8 -2
  151. package/src/config/schema/compaction-triggers.ts +11 -0
  152. package/src/config/schema/config-schema.ts +31 -1
  153. package/src/config/schema/leaf-validators.ts +59 -0
  154. package/src/config.ts +3 -3
  155. package/src/generated/compatibility-version.json +604 -280
  156. package/src/grok/reset-coupons.ts +38 -19
  157. package/src/images/loop.ts +6 -1
  158. package/src/integrations/aside-profile-context.ts +37 -3
  159. package/src/integrations/aside-profile-journal.ts +68 -3
  160. package/src/integrations/aside-profiles.ts +128 -3
  161. package/src/integrations/config-io.ts +44 -10
  162. package/src/integrations/merge.ts +120 -13
  163. package/src/integrations/mutation-plan.ts +921 -0
  164. package/src/integrations/registry.ts +38 -0
  165. package/src/integrations/state.ts +78 -45
  166. package/src/integrations/target.ts +208 -0
  167. package/src/integrations/writer.ts +134 -110
  168. package/src/lab/conformance/fixture-provider.ts +5 -0
  169. package/src/lab/live/transport.ts +4 -0
  170. package/src/lab/live/types.ts +5 -0
  171. package/src/lab/subject/behavior-fingerprint.ts +1 -1
  172. package/src/lib/admin-secrets.ts +9 -1
  173. package/src/lib/browser-launch-notice.ts +59 -0
  174. package/src/lib/bun-runtime.ts +6 -2
  175. package/src/lib/debug-log-buffer.ts +6 -1
  176. package/src/lib/debug.ts +63 -0
  177. package/src/lib/errors.ts +79 -0
  178. package/src/lib/http-response-semantics.ts +57 -0
  179. package/src/lib/lab-live-pinned-sender.ts +26 -12
  180. package/src/lib/open-url.ts +51 -7
  181. package/src/lib/package-tree-integrity.ts +2 -1
  182. package/src/lib/package-version.ts +8 -0
  183. package/src/lib/pinned-http.ts +142 -2
  184. package/src/lib/plain-data.ts +103 -0
  185. package/src/lib/process-control.ts +13 -5
  186. package/src/lib/provider-egress.ts +310 -0
  187. package/src/lib/provider-outbound.ts +109 -16
  188. package/src/lib/proxy-env.ts +82 -7
  189. package/src/lib/request-execution-budget.ts +72 -0
  190. package/src/lib/request-failure-attribution.ts +183 -0
  191. package/src/lib/request-failure-model.ts +236 -0
  192. package/src/lib/request-resend-gate.ts +138 -0
  193. package/src/lib/socks5-fetch.ts +136 -26
  194. package/src/lib/spend-ledger-owner.ts +364 -0
  195. package/src/lib/spend-reservation-ledger.ts +218 -27
  196. package/src/lib/standalone.ts +16 -0
  197. package/src/lib/upstream-retry.ts +167 -16
  198. package/src/lib/windows-system-proxy.ts +16 -11
  199. package/src/lib/winsw.ts +2 -2
  200. package/src/oauth/callback-server.ts +4 -3
  201. package/src/oauth/generic-account-failover.ts +1 -0
  202. package/src/oauth/health.ts +12 -1
  203. package/src/oauth/index.ts +27 -108
  204. package/src/oauth/login-cli.ts +80 -29
  205. package/src/oauth/login-flow-state.ts +127 -0
  206. package/src/providers/api-key-resolve.ts +133 -0
  207. package/src/providers/api-key-selection.ts +5 -1
  208. package/src/providers/derive.ts +34 -17
  209. package/src/providers/devin-cli-authmode-migration.ts +14 -10
  210. package/src/providers/key-failover.ts +97 -19
  211. package/src/providers/key-store.ts +34 -110
  212. package/src/providers/model-rename-fields.ts +147 -0
  213. package/src/providers/model-rename-migration.ts +179 -38
  214. package/src/providers/model-rename-startup.ts +7 -5
  215. package/src/providers/openai-virtual-models.ts +42 -2
  216. package/src/providers/quota/antigravity.ts +22 -2
  217. package/src/providers/quota/vendor-probes-key.ts +38 -23
  218. package/src/providers/reasoning-metadata.ts +43 -18
  219. package/src/providers/registry/entries-core.ts +47 -20
  220. package/src/providers/registry/entries-extended.ts +63 -4
  221. package/src/providers/registry/model-ids.ts +168 -0
  222. package/src/providers/registry/model-seeds.ts +56 -10
  223. package/src/providers/registry/types.ts +2 -0
  224. package/src/providers/resolved-model-policy-merge.ts +167 -0
  225. package/src/providers/resolved-model-policy.ts +406 -0
  226. package/src/providers/stale-vision-classification-migration.ts +137 -0
  227. package/src/providers/xai-transport.ts +12 -1
  228. package/src/reasoning-effort.ts +8 -0
  229. package/src/responses/apply-patch-envelope.ts +0 -12
  230. package/src/responses/freeform-wrapper-scan.ts +279 -0
  231. package/src/responses/function-call-compat.ts +38 -1
  232. package/src/responses/inline-document.ts +65 -0
  233. package/src/responses/input-media.ts +42 -8
  234. package/src/responses/legacy-dotted-tool-name-repair.ts +134 -0
  235. package/src/responses/muse-tool-name-alias.ts +19 -0
  236. package/src/responses/parser-content.ts +8 -2
  237. package/src/responses/parser-tools.ts +3 -0
  238. package/src/responses/parser.ts +3 -1
  239. package/src/responses/progressive-freeform-input.ts +130 -0
  240. package/src/responses/reasoning-envelope.ts +30 -0
  241. package/src/responses/schema.ts +3 -0
  242. package/src/responses/state.ts +5 -12
  243. package/src/responses/tool-name-aliases.ts +15 -1
  244. package/src/router.ts +108 -117
  245. package/src/routing/compatibility/behavior.ts +9 -0
  246. package/src/routing/compatibility/subject.ts +16 -1
  247. package/src/server/adapter-resolve.ts +9 -0
  248. package/src/server/admission-model-scope.ts +219 -0
  249. package/src/server/audio-live.ts +9 -3
  250. package/src/server/audio-upstream.ts +18 -0
  251. package/src/server/auth-cors.ts +29 -0
  252. package/src/server/chat-completions.ts +60 -4
  253. package/src/server/chat-native.ts +19 -4
  254. package/src/server/claude-messages.ts +61 -20
  255. package/src/server/effort-row.ts +11 -3
  256. package/src/server/grok-responses-control-frame.ts +160 -1
  257. package/src/server/grok-responses-snapshot-repair.ts +113 -11
  258. package/src/server/gui-freshness.ts +103 -0
  259. package/src/server/gui-static.ts +7 -9
  260. package/src/server/images.ts +59 -6
  261. package/src/server/index/claude-intercept-lifecycle.ts +49 -0
  262. package/src/server/index/serve-options.ts +142 -39
  263. package/src/server/index/spend-ledger-lifecycle.ts +92 -0
  264. package/src/server/index/startup-warnings.ts +24 -0
  265. package/src/server/index/websocket-handler.ts +6 -1
  266. package/src/server/index.ts +34 -38
  267. package/src/server/lifecycle.ts +4 -4
  268. package/src/server/live-call-bindings.ts +6 -0
  269. package/src/server/live.ts +88 -3
  270. package/src/server/management/agent-settings-routes.ts +121 -36
  271. package/src/server/management/aside-profile-routes.ts +266 -7
  272. package/src/server/management/companion-routes.ts +77 -0
  273. package/src/server/management/config-routes.ts +18 -2
  274. package/src/server/management/context.ts +3 -0
  275. package/src/server/management/integration-routes.ts +287 -5
  276. package/src/server/management/logs-usage-routes.ts +19 -0
  277. package/src/server/management/metrics-routes.ts +20 -0
  278. package/src/server/management/model-rows.ts +224 -12
  279. package/src/server/management/native-integration-routes.ts +103 -6
  280. package/src/server/management/oauth-account-routes.ts +45 -7
  281. package/src/server/management/route-registry.ts +20 -0
  282. package/src/server/management/shared.ts +28 -4
  283. package/src/server/management/system-restart.ts +7 -2
  284. package/src/server/management/system-routes.ts +2 -0
  285. package/src/server/management/usage-aggregate-cache.ts +4 -0
  286. package/src/server/management/usage-timeline-routes.ts +44 -0
  287. package/src/server/management-api.ts +10 -9
  288. package/src/server/management-auth.ts +15 -1
  289. package/src/server/proxy-liveness.ts +75 -0
  290. package/src/server/readiness.ts +29 -10
  291. package/src/server/relay-eager.ts +24 -2
  292. package/src/server/relay.ts +138 -12
  293. package/src/server/request-log-failure-attribution.ts +99 -0
  294. package/src/server/request-log.ts +169 -2
  295. package/src/server/request-metrics.ts +298 -0
  296. package/src/server/responses/adapter-continuation.ts +3 -3
  297. package/src/server/responses/adapter-dispatch.ts +11 -6
  298. package/src/server/responses/codex-ws-wire.ts +34 -8
  299. package/src/server/responses/combo-stream-preflight.ts +168 -6
  300. package/src/server/responses/compact.ts +43 -10
  301. package/src/server/responses/compaction-routing.ts +111 -0
  302. package/src/server/responses/core-codex-account.ts +8 -3
  303. package/src/server/responses/core-combo.ts +7 -7
  304. package/src/server/responses/core-normalize.ts +6 -12
  305. package/src/server/responses/core-opaque-recovery.ts +91 -0
  306. package/src/server/responses/core-options.ts +4 -0
  307. package/src/server/responses/encrypted-payload.ts +20 -2
  308. package/src/server/responses/fetch-helpers.ts +124 -8
  309. package/src/server/responses/input-admission.ts +10 -0
  310. package/src/server/responses/passthrough-delivery.ts +45 -15
  311. package/src/server/responses/passthrough-dispatch.ts +215 -44
  312. package/src/server/responses/passthrough-error.ts +27 -8
  313. package/src/server/responses/policy-fallback.ts +5 -13
  314. package/src/server/responses/request-prepare.ts +109 -18
  315. package/src/server/responses/request-send-budget.ts +17 -1
  316. package/src/server/responses/request-sidecar-auth.ts +1 -1
  317. package/src/server/responses/request-transport.ts +26 -6
  318. package/src/server/responses/reset-replay.ts +108 -0
  319. package/src/server/responses/run-turn-execution.ts +25 -3
  320. package/src/server/responses/sidecar-execution.ts +17 -2
  321. package/src/server/responses/ws-upstream.ts +14 -27
  322. package/src/server/responses-custom-tool-repair.ts +27 -54
  323. package/src/server/responses-request-tool-scope.ts +214 -0
  324. package/src/server/responses-undeclared-tool-guard.ts +35 -2
  325. package/src/server/search.ts +25 -1
  326. package/src/server/sse-payload-rewrite.ts +1 -1
  327. package/src/server/usage-ledger-retention.ts +73 -0
  328. package/src/service/cli.ts +48 -2
  329. package/src/service/health.ts +3 -2
  330. package/src/service/install-state-contract.d.mts +27 -0
  331. package/src/service/install-state-contract.mjs +34 -0
  332. package/src/service/launchd.ts +1 -1
  333. package/src/service/orchestration.ts +2 -4
  334. package/src/service/ownership-compatibility.ts +164 -0
  335. package/src/service/ownership-mutation-lease.d.mts +32 -0
  336. package/src/service/ownership-mutation-lease.mjs +211 -0
  337. package/src/service/repair.ts +45 -1
  338. package/src/service/state-lock.ts +269 -0
  339. package/src/service/state-record.d.mts +36 -0
  340. package/src/service/state-record.mjs +138 -0
  341. package/src/service/state.ts +582 -68
  342. package/src/service/windows-taskxml.ts +11 -10
  343. package/src/service.ts +7 -3
  344. package/src/tray/windows-tray.ps1 +156 -4
  345. package/src/types/config.ts +48 -3
  346. package/src/types/provider.ts +91 -0
  347. package/src/types/request.ts +30 -2
  348. package/src/types/tools.ts +33 -0
  349. package/src/types.ts +4 -0
  350. package/src/update/index.ts +207 -63
  351. package/src/update/job.ts +9 -5
  352. package/src/update/ownership-transaction.ts +47 -0
  353. package/src/update/restart-ownership.ts +54 -0
  354. package/src/update/runtime-ownership.d.mts +40 -0
  355. package/src/update/runtime-ownership.mjs +122 -0
  356. package/src/usage/attempt-delivery.ts +198 -0
  357. package/src/usage/cache-diagnostic.ts +305 -0
  358. package/src/usage/failure-fingerprint.ts +118 -0
  359. package/src/usage/failure-projection-cache.ts +174 -0
  360. package/src/usage/failure-projection.ts +174 -0
  361. package/src/usage/ledger-retention.ts +165 -0
  362. package/src/usage/log.ts +126 -79
  363. package/src/usage/request-outcome.ts +150 -0
  364. package/src/usage/retention-contract.ts +28 -0
  365. package/src/usage/summary.ts +2 -2
  366. package/src/usage/telemetry-contract.ts +237 -0
  367. package/src/usage/timeline.ts +236 -0
  368. package/src/vision/eligibility.ts +88 -9
  369. package/src/vision/plan.ts +34 -10
  370. package/src/web-search/alpha-search.ts +21 -1
  371. package/src/web-search/executor.ts +41 -2
  372. package/src/web-search/loop.ts +6 -1
  373. package/gui/dist/assets/index-C5IebErG.js +0 -136
  374. package/gui/dist/assets/index-OESInAjC.css +0 -1
@@ -127,7 +127,7 @@ export function isOcxCommandLine(commandLine: string): boolean {
127
127
  || normalized.includes("src/cli/index.ts")
128
128
  || normalized.includes("@bitkyc08/opencodex")
129
129
  || /@bitkyc08\/\.opencodex-/.test(normalized)
130
- || /(?:^|[\s/"'])(?:ocx|opencodex)(?:\.cmd)?(?:$|[\s"'])/.test(normalized);
130
+ || /(?:^|[\s/"'])(?:ocx|opencodex)(?:\.cmd|\.exe)?(?:$|[\s"'])/.test(normalized);
131
131
  }
132
132
 
133
133
  export function isOcxStartCommandLine(commandLine: string): boolean {
@@ -143,8 +143,14 @@ export function applyProxyEnvWith(
143
143
  } else {
144
144
  const found = readWindowsSystemProxy(auto.reader, auto.platform);
145
145
  if (found.kind === "proxy") {
146
- console.log(`[opencodex] proxy "auto": using Windows system proxy ${describeProxyForLog(found.url)}`);
147
- proxy = found.url;
146
+ const origins = [
147
+ found.httpUrl && `HTTP ${describeProxyForLog(found.httpUrl)}`,
148
+ found.httpsUrl && `HTTPS ${describeProxyForLog(found.httpsUrl)}`,
149
+ ].filter(Boolean).join(", ");
150
+ console.log(`[opencodex] proxy "auto": using Windows system proxy ${origins}`);
151
+ if (found.httpUrl) process.env.HTTP_PROXY = found.httpUrl;
152
+ if (found.httpsUrl) process.env.HTTPS_PROXY = found.httpsUrl;
153
+ proxy = undefined;
148
154
  } else {
149
155
  const reason = found.kind === "unsupported"
150
156
  ? "only Windows system proxy discovery is supported; using direct egress on this OS"
@@ -0,0 +1,11 @@
1
+ /**
2
+ * The `compaction.trigger` values Codex labels a compaction turn with (`CompactionTrigger`
3
+ * in codex-rs: a manual `/compact` versus automatic compaction). `compactionRouting.triggers`
4
+ * selects which of them an override applies to.
5
+ *
6
+ * This is its own leaf module and imports nothing on purpose. The request path reads it from
7
+ * `src/server/responses/compaction-routing.ts`; importing `leaf-validators.ts` there instead
8
+ * closes a cycle with `config-schema.ts` that survives typecheck and then fails at run time
9
+ * with "Cannot access 'runtimeRoleSchema' before initialization".
10
+ */
11
+ export const COMPACTION_TRIGGERS = ["manual", "auto"] as const;
@@ -21,6 +21,7 @@ import {
21
21
  CODEX_ACCOUNT_NAMESPACE_ACCOUNT_ID_COLLISION_ERROR,
22
22
  codexAccountNamespacesSchema,
23
23
  modelPinnedEffortsSchema,
24
+ compactionRoutingSchema,
24
25
  modelPreferHostedToolsConfigError,
25
26
  providerModelCostsConfigError,
26
27
  providerRelativeSendPathConfigError,
@@ -45,6 +46,7 @@ import {
45
46
  MAIN_CODEX_ACCOUNT_NAMESPACE_TARGET,
46
47
  } from "../../codex/account-namespace-match";
47
48
  import { UPSTREAM_HOST_CIRCUIT_MAX_THRESHOLD } from "../../codex/upstream-host-health";
49
+ import { MIN_USAGE_LEDGER_MAX_BYTES } from "../../usage/retention-contract";
48
50
  import { COMBO_NAMESPACE, comboConfigIssues } from "../../combos/types";
49
51
  import { routingProfileIssues } from "../../routing/profile";
50
52
  import { POLICY_NAMESPACE } from "../../routing/profile-namespace";
@@ -73,12 +75,22 @@ export const configSchema = z.object({
73
75
  // A malformed privacy block must never be read as "unmask": .catch(undefined) drops it and
74
76
  // emailMaskingEnabled then falls back to masked, which is also what an absent block means.
75
77
  privacy: z.object({ maskEmails: z.boolean().optional() }).strict().optional().catch(undefined),
78
+ // Malformed hand edits disable this opt-in exporter. Live writes reject them in diagnostics.ts.
79
+ metricsExport: z.object({ enabled: z.boolean().optional() }).strict().optional().catch(undefined),
76
80
  // A malformed present client block must remain diagnosable from raw config and
77
81
  // fail closed through src/client/state.ts; unrelated provider state still loads.
78
82
  client: clientConnectionSchema.optional().catch(undefined),
79
83
  managementUsageMaxReadBytes: z.number().int().positive().default(64 * 1024 * 1024).describe(
80
84
  "Deprecated compatibility limit for bounded legacy usage readers; GET /api/usage always aggregates the complete ledger",
81
85
  ),
86
+ // Opt-in ledger ceiling. A hand edit below the floor, or a non-safe integer, disables only
87
+ // this limit rather than failing the config: refusing to start because history retention was
88
+ // mistyped would be a worse outcome than not trimming history.
89
+ usageLedgerMaxBytes: z.number().int()
90
+ .min(MIN_USAGE_LEDGER_MAX_BYTES)
91
+ .max(Number.MAX_SAFE_INTEGER)
92
+ .optional()
93
+ .catch(undefined),
82
94
  // Invalid hand edits disable only this opt-in circuit. Live writes remain strict.
83
95
  upstreamHostCircuitThreshold: z.number().int()
84
96
  .min(0)
@@ -125,6 +137,7 @@ export const configSchema = z.object({
125
137
  ]).optional().catch(undefined),
126
138
  providers: z.record(z.string(), providerConfigSchema),
127
139
  modelPinnedEfforts: modelPinnedEffortsSchema.optional(),
140
+ compactionRouting: compactionRoutingSchema.optional().catch(undefined),
128
141
  defaultProvider: z.string().min(1).default("openai"),
129
142
  defaultModelAliases: z.boolean().optional(),
130
143
  // Malformed hand edits disable this opt-in projection without rejecting providers.
@@ -257,7 +270,24 @@ export const configSchema = z.object({
257
270
  if (claudeCode !== undefined && (!claudeCode || typeof claudeCode !== "object" || Array.isArray(claudeCode))) {
258
271
  ctx.addIssue({ code: "custom", path: ["claudeCode"], message: "claudeCode must be an object" });
259
272
  } else if (claudeCode) {
260
- const claude = claudeCode as { desktopProfile?: unknown };
273
+ const claude = claudeCode as { desktopProfile?: unknown; desktopMode?: unknown; intercept?: unknown };
274
+ if (claude.desktopMode !== undefined && claude.desktopMode !== "first-party" && claude.desktopMode !== "gateway") {
275
+ ctx.addIssue({ code: "custom", path: ["claudeCode", "desktopMode"], message: "desktopMode must be \"first-party\" or \"gateway\"" });
276
+ }
277
+ if (claude.intercept !== undefined) {
278
+ const intercept = claude.intercept;
279
+ if (!intercept || typeof intercept !== "object" || Array.isArray(intercept)) {
280
+ ctx.addIssue({ code: "custom", path: ["claudeCode", "intercept"], message: "intercept must be an object" });
281
+ } else {
282
+ const { enabled, port } = intercept as { enabled?: unknown; port?: unknown };
283
+ if (enabled !== undefined && typeof enabled !== "boolean") {
284
+ ctx.addIssue({ code: "custom", path: ["claudeCode", "intercept", "enabled"], message: "intercept.enabled must be a boolean" });
285
+ }
286
+ if (port !== undefined && (typeof port !== "number" || !Number.isInteger(port) || port < 1 || port > 65535)) {
287
+ ctx.addIssue({ code: "custom", path: ["claudeCode", "intercept", "port"], message: "intercept.port must be an integer between 1 and 65535" });
288
+ }
289
+ }
290
+ }
261
291
  if (claude.desktopProfile !== undefined) {
262
292
  try {
263
293
  parseDesktopProfile(claude.desktopProfile);
@@ -17,6 +17,7 @@ import { isCodexAccountPriorityKey } from "../../codex/account-priority";
17
17
  import { parseAccountPriority } from "../../codex/pool-rotation";
18
18
  import { credentialGroupIssues } from "../../routing/identity-domains";
19
19
  import { providerDestinationConfigError } from "../../lib/destination-policy";
20
+ import { providerEgressConfigError } from "../../lib/provider-egress";
20
21
  import { redactSecretString } from "../../lib/redact";
21
22
  import {
22
23
  MODEL_ADAPTER_OVERRIDE_ALLOWED,
@@ -38,12 +39,21 @@ import {
38
39
  isHostedToolUnsupportedForModel,
39
40
  } from "../../responses/hosted-tool-policy";
40
41
  import { getConfigDir } from "../paths";
42
+ import { COMPACTION_TRIGGERS } from "./compaction-triggers";
41
43
 
42
44
  /** One definition of "usable secret", shared by the schema and the warnings. */
43
45
  export function isUsableApiKeySecret(value: unknown): value is string {
44
46
  return typeof value === "string" && value.length > 0 && value === value.trim();
45
47
  }
46
48
 
49
+ export const compactionRoutingSchema = z.object({
50
+ model: z.string().trim().min(1),
51
+ reasoningEffort: z.string().refine(value => pinnedReasoningEffortConfigError(value) === null).optional(),
52
+ triggers: z.array(z.enum(COMPACTION_TRIGGERS)).nonempty()
53
+ .refine(values => new Set(values).size === values.length, "triggers must not repeat a value")
54
+ .optional(),
55
+ }).strict();
56
+
47
57
  /**
48
58
  * Bounds for the opt-in same-target 429 wait-and-retry policy. Single source of truth
49
59
  * shared by the config schema, the load-time sanitizer, and the management write
@@ -71,6 +81,17 @@ const transientRetryOn5xxPolicySchema = z.object({
71
81
  attempts: z.number().int().min(1).max(10).optional(),
72
82
  }).strict();
73
83
 
84
+ /**
85
+ * `retryOnReset` accepts only these keys. `replacements` counts DUPLICATE inferences the
86
+ * operator is willing to risk for one logical request, so the ceiling is two rather than a
87
+ * send budget: this is the one send the proxy otherwise refuses outright, and a third of them
88
+ * says the connection, not the retry policy, is the problem.
89
+ */
90
+ export const retryOnResetPolicySchema = z.object({
91
+ enabled: z.boolean().optional(),
92
+ replacements: z.number().int().min(1).max(2).optional(),
93
+ }).strict();
94
+
74
95
  const requestPacingRuleSchema = z.object({
75
96
  // Keep the RPM-derived timer within the same one-hour bound as minIntervalMs.
76
97
  requestsPerMinute: z.number().min(1 / 60).max(60_000).optional(),
@@ -212,6 +233,25 @@ const modelCapabilitiesSchema = z.unknown().superRefine((value, ctx) => {
212
233
  if (error) ctx.addIssue({ code: "custom", message: error });
213
234
  }).transform(value => mergeModelCapabilities(undefined, value));
214
235
 
236
+ /**
237
+ * Per-provider egress fields, validated by the resolver the transports themselves use.
238
+ *
239
+ * Calling `providerEgressConfigError` rather than restating the accepted forms keeps one
240
+ * definition of a usable value: a proxy the config loader admits is one the transport can
241
+ * carry, and a value rejected here is rejected at request time for the identical reason.
242
+ * Each field is checked on its own because neither depends on the other's value to be
243
+ * well-formed; how they combine is decided per request against the destination.
244
+ */
245
+ const providerProxySchema = z.unknown().superRefine((value, ctx) => {
246
+ const error = providerEgressConfigError({ proxy: value as string | null | undefined });
247
+ if (error) ctx.addIssue({ code: "custom", message: error });
248
+ }).transform(value => value as string | null | undefined);
249
+
250
+ const providerNoProxySchema = z.unknown().superRefine((value, ctx) => {
251
+ const error = providerEgressConfigError({ noProxy: value as string | string[] | undefined });
252
+ if (error) ctx.addIssue({ code: "custom", message: error });
253
+ }).transform(value => value as string | string[] | undefined);
254
+
215
255
  /**
216
256
  * Zod schema for one provider entry: known fields are validated strictly while unknown
217
257
  * fields pass through (preserved for runtime extensions).
@@ -249,14 +289,21 @@ export const providerConfigSchema = z.object({
249
289
  requiresAdjacentResponsesToolResults: z.boolean().optional(),
250
290
  requiresPairedResponsesToolResults: z.boolean().optional(),
251
291
  annotateEmptyToolOutputs: z.boolean().optional(),
292
+ foldDeveloperRoleToSystem: z.boolean().optional(),
252
293
  fastWire: fastWireSchema.nullable().optional(),
253
294
  supportsServiceTier: z.boolean().optional(),
254
295
  modelSupportsServiceTier: z.record(z.string().min(1), z.boolean()).optional(),
255
296
  modelSuppressSyntheticMax: z.record(z.string().min(1), z.boolean()).optional(),
256
297
  preserveResponsesReasoningContent: z.boolean().optional(),
298
+ dropResponsesReasoningItems: z.boolean().optional(),
299
+ modelReasoningEffortsAuthoritative: z.boolean().optional(),
257
300
  decodesNativeCompactionBlobs: z.boolean().optional(),
258
301
  allowEncryptedV2AgentTasks: z.boolean().optional(),
259
302
  allowPrivateNetwork: z.boolean().optional(),
303
+ // Per-provider egress (#2894): absent inherits the global proxy decision, "direct"/null
304
+ // refuses it, and an http(s) or socks5 URL replaces it for this provider only.
305
+ proxy: providerProxySchema.optional(),
306
+ noProxy: providerNoProxySchema.optional(),
260
307
  // The management API accepts `null` as "clear this", so a config written before the POST
261
308
  // canonicalization below can hold one on disk. Rejecting it here would send the operator
262
309
  // through invalid-config recovery for a value the API told them was fine.
@@ -268,6 +315,7 @@ export const providerConfigSchema = z.object({
268
315
  // canonical ChatGPT backend WS selection is independent of this flag.
269
316
  upstreamWebsocket: z.boolean().optional(),
270
317
  directGeminiWireRenames: z.boolean().optional(),
318
+ googleToolSchemaPolicy: z.enum(["compatible", "reject-lossy"]).optional(),
271
319
  noStructuredOutputModels: z.array(z.string().min(1))
272
320
  .transform(normalizeNonBlankStringArray)
273
321
  .optional(),
@@ -294,6 +342,10 @@ export const providerConfigSchema = z.object({
294
342
  .optional(),
295
343
  retryOn429: retryOn429PolicySchema.optional(),
296
344
  transientRetryOn5xx: transientRetryOn5xxPolicySchema.optional(),
345
+ // Degrades to "absent" like `webSearchBridge`: a malformed hand edit of an opt-in feature
346
+ // that is off by default must not send the operator through invalid-config recovery. The
347
+ // management write boundary still rejects it loudly (`retryOnResetPolicyConfigError`).
348
+ retryOnReset: retryOnResetPolicySchema.optional().catch(undefined),
297
349
  codexAccountMode: z.enum(["pool", "direct"]).optional(),
298
350
  // Validated rather than passed through: this schema ends in `.passthrough()`, so an
299
351
  // undeclared key survives verbatim. A misspelled `codexToolMode` therefore used to be
@@ -637,6 +689,13 @@ export const apiKeyEntrySchema = z.object({
637
689
  createdAt: z.string().catch(""),
638
690
  // A damaged overlap record must never discard the still-authoritative key.
639
691
  pendingRotation: pendingApiKeyRotationSchema.optional().catch(undefined),
692
+ // Deliberately NOT `.catch`ed, unlike every field above. Degrading a damaged
693
+ // scope to `undefined` would silently widen the key to the whole catalog,
694
+ // which is the one direction a permission field must never fail. Letting the
695
+ // record fail instead drops the key, so a corrupted scope stops that client
696
+ // rather than promoting it.
697
+ allowedProviders: z.array(z.string().trim().min(1).max(256)).optional(),
698
+ allowedModels: z.array(z.string().trim().min(1).max(256)).optional(),
640
699
  }).passthrough();
641
700
 
642
701
  /**
package/src/config.ts CHANGED
@@ -110,7 +110,7 @@ export {
110
110
  sanitizeModelCostsForDisplay,
111
111
  modelPreferHostedToolsConfigError,
112
112
  } from "./config/schema/leaf-validators";
113
- export { hardenExistingSecret, retryOn429PolicyConfigError } from "./config/load-degrade";
113
+ export { hardenExistingSecret, retryOn429PolicyConfigError, retryOnResetPolicyConfigError } from "./config/load-degrade";
114
114
  export { backupInvalidConfig } from "./config/salvage";
115
115
  export type { ConfigDiagnostics, ConfigAdmissionSnapshot } from "./config/diagnostics";
116
116
  export {
@@ -170,7 +170,7 @@ import {
170
170
  sanitizeModelCostsForLoad,
171
171
  sanitizeCapabilityDeclarationsForLoad,
172
172
  warnInheritedFastWireConflicts,
173
- warnDegradedStreamMode,
173
+ warnDegradedTopLevelOptIns,
174
174
  warnDegradedHostname,
175
175
  warnDegradedListeners,
176
176
  warnDegradedApiKeys,
@@ -227,7 +227,7 @@ export function loadConfig(): OcxConfig {
227
227
  if (result.success) {
228
228
  const config = normalizeApiKeyIds(result.data as OcxConfig);
229
229
  warnInheritedFastWireConflicts(configPath, config);
230
- warnDegradedStreamMode(parsed, config);
230
+ warnDegradedTopLevelOptIns(parsed, config);
231
231
  warnDegradedHostname(parsed, config);
232
232
  warnDegradedListeners(parsed, config);
233
233
  warnDegradedApiKeys(parsed, config);