@bitkyc08/opencodex 2.84.0 → 2.87.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 (518) hide show
  1. package/README.md +0 -4
  2. package/bin/ocx.mjs +61 -3
  3. package/gui/dist/assets/App-ZfYbLHkB.js +58 -0
  4. package/gui/dist/assets/App-wT3mXqFz.css +1 -0
  5. package/gui/dist/assets/{Tray-C9TGtwad.js → Tray-DCd-A1az.js} +1 -1
  6. package/gui/dist/assets/index-CfYDMj34.js +94 -0
  7. package/gui/dist/assets/index-DPeB9HpV.css +1 -0
  8. package/gui/dist/assets/quota-summary-ChvmKGOk.js +1 -0
  9. package/gui/dist/index.html +2 -2
  10. package/package.json +1 -2
  11. package/src/adapters/anthropic/beta-allowlist.ts +91 -11
  12. package/src/adapters/anthropic/beta-body-pairs.ts +93 -0
  13. package/src/adapters/anthropic/client-identity.ts +1 -1
  14. package/src/adapters/anthropic/passthrough.ts +16 -3
  15. package/src/adapters/anthropic-progress.ts +84 -0
  16. package/src/adapters/anthropic.ts +108 -21
  17. package/src/adapters/azure.ts +19 -1
  18. package/src/adapters/base.ts +2 -0
  19. package/src/adapters/claude-cli/adapter.ts +111 -23
  20. package/src/adapters/claude-cli/profiles.ts +2 -1
  21. package/src/adapters/claude-cli/stable-replay.ts +108 -0
  22. package/src/adapters/claude-cli/usage-admission.ts +230 -0
  23. package/src/adapters/client-fingerprint.ts +24 -0
  24. package/src/adapters/coding-agent/protocol.ts +1 -1
  25. package/src/adapters/coding-agent/turn.ts +40 -11
  26. package/src/adapters/cursor/arg-codec.ts +17 -5
  27. package/src/adapters/cursor/catalog.ts +8 -0
  28. package/src/adapters/cursor/effort-map.ts +3 -0
  29. package/src/adapters/cursor/freeform-args.ts +75 -0
  30. package/src/adapters/cursor/protobuf-events.ts +36 -23
  31. package/src/adapters/dsh-account.ts +97 -0
  32. package/src/adapters/google-antigravity-wire.ts +22 -1
  33. package/src/adapters/google.ts +37 -10
  34. package/src/adapters/openai-chat/messages.ts +4 -3
  35. package/src/adapters/openai-chat/passthrough.ts +8 -2
  36. package/src/adapters/openai-chat/reasoning-replay.ts +52 -0
  37. package/src/adapters/openai-chat/response-events.ts +59 -1
  38. package/src/adapters/openai-chat.ts +8 -5
  39. package/src/adapters/openai-responses/compaction-search-history.ts +14 -7
  40. package/src/adapters/openai-responses/passthrough.ts +57 -125
  41. package/src/adapters/openai-responses/request-strips.ts +25 -3
  42. package/src/adapters/openai-responses/transport.ts +81 -0
  43. package/src/adapters/qoder/adapter.ts +44 -3
  44. package/src/adapters/registry.ts +5 -0
  45. package/src/adapters/zed.ts +26 -1
  46. package/src/advisor/activity.ts +55 -0
  47. package/src/advisor/budget.ts +62 -0
  48. package/src/advisor/consult.ts +223 -0
  49. package/src/advisor/context.ts +238 -0
  50. package/src/advisor/disclosure.ts +20 -0
  51. package/src/advisor/evidence-tool.ts +21 -0
  52. package/src/advisor/evidence.ts +117 -0
  53. package/src/advisor/runtime.ts +353 -0
  54. package/src/advisor/settings.ts +144 -0
  55. package/src/advisor/state.ts +369 -0
  56. package/src/advisor/synthetic-tool.ts +33 -0
  57. package/src/bridge/errors.ts +24 -1
  58. package/src/bridge/internal.ts +3 -1
  59. package/src/bridge/response-json.ts +18 -3
  60. package/src/bridge/sse.ts +58 -8
  61. package/src/bridge/terminal-refusal.ts +59 -0
  62. package/src/chat/inbound.ts +30 -6
  63. package/src/chat/outbound.ts +5 -0
  64. package/src/claude/desktop-3p-library.ts +72 -7
  65. package/src/claude/desktop-3p.ts +75 -19
  66. package/src/claude/desktop-first-party.ts +1 -1
  67. package/src/claude/desktop-picker-platform.ts +4 -0
  68. package/src/claude/desktop-picker-profile.ts +11 -4
  69. package/src/claude/desktop-picker.ts +15 -8
  70. package/src/claude/desktop-profile.ts +10 -1
  71. package/src/claude/desktop-remote-store-io.ts +5 -3
  72. package/src/claude/desktop-system-proxy.ts +50 -4
  73. package/src/claude/inbound-content-options.ts +11 -0
  74. package/src/claude/inbound.ts +154 -50
  75. package/src/claude/intercept/local-ca.ts +8 -1
  76. package/src/claude/intercept/picker-ca-startup.ts +2 -1
  77. package/src/claude/intercept/picker-runtime.ts +6 -5
  78. package/src/claude/intercept/picker-trust-windows.ts +338 -0
  79. package/src/claude/intercept/picker-trust.ts +19 -0
  80. package/src/claude/intercept/port-policy.ts +30 -0
  81. package/src/claude/intercept/runtime.ts +97 -94
  82. package/src/claude/model-default-settings.ts +154 -0
  83. package/src/claude/model-info.ts +7 -7
  84. package/src/claude/outbound.ts +51 -19
  85. package/src/cli/account-api.ts +1 -0
  86. package/src/cli/account-policy-dto.ts +6 -0
  87. package/src/cli/account-policy.ts +34 -5
  88. package/src/cli/account-preservation.ts +44 -0
  89. package/src/cli/account.ts +8 -2
  90. package/src/cli/advisor.ts +165 -0
  91. package/src/cli/auxiliary-listener-preflight.ts +37 -0
  92. package/src/cli/capabilities-accounts.ts +20 -1
  93. package/src/cli/capabilities-agents-routing.ts +23 -2
  94. package/src/cli/capabilities-base.ts +39 -11
  95. package/src/cli/capabilities-observe-system.ts +63 -3
  96. package/src/cli/capabilities-provider-models.ts +11 -0
  97. package/src/cli/chatgpt-command.ts +35 -14
  98. package/src/cli/claude.ts +46 -6
  99. package/src/cli/codex-cli-update.ts +151 -41
  100. package/src/cli/codex-provider.ts +44 -0
  101. package/src/cli/combo-input.ts +10 -1
  102. package/src/cli/combo-result.ts +1 -1
  103. package/src/cli/combo.ts +2 -1
  104. package/src/cli/cross-home-owner.ts +17 -14
  105. package/src/cli/dispatch.ts +30 -5
  106. package/src/cli/doctor.ts +15 -1
  107. package/src/cli/ensure-desktop-cold-start.ts +382 -0
  108. package/src/cli/export-command.ts +1 -1
  109. package/src/cli/help.ts +4 -2
  110. package/src/cli/index.ts +14 -5
  111. package/src/cli/integration-plan-dto.ts +3 -0
  112. package/src/cli/log-history.ts +172 -0
  113. package/src/cli/models-runtime-subcommands.ts +1 -0
  114. package/src/cli/models-runtime.ts +72 -8
  115. package/src/cli/observe-stream.ts +2 -0
  116. package/src/cli/observe.ts +16 -4
  117. package/src/cli/provider.ts +27 -5
  118. package/src/cli/registry.ts +41 -9
  119. package/src/cli/restart-scope.ts +3 -1
  120. package/src/cli/runtime-api.ts +5 -3
  121. package/src/cli/system-command.ts +40 -8
  122. package/src/cli/uninstall-client-state.ts +32 -0
  123. package/src/cli/usage-compare.ts +309 -0
  124. package/src/cli/usage-model-search.ts +4 -4
  125. package/src/cli/usage-report.ts +2 -2
  126. package/src/cli/v2.ts +1 -1
  127. package/src/client/machine-listener.ts +1 -3
  128. package/src/client/runtime.ts +1 -0
  129. package/src/clients/client-path.ts +51 -0
  130. package/src/clients/config-export/contracts.ts +3 -1
  131. package/src/clients/config-export/model-metadata.ts +3 -2
  132. package/src/clients/config-export/qoder.ts +93 -0
  133. package/src/clients/config-export.ts +35 -48
  134. package/src/clients/gentle-shell-path.ts +87 -0
  135. package/src/codex/account-auto-switch.ts +2 -0
  136. package/src/codex/account-identity.ts +29 -0
  137. package/src/codex/account-label.ts +1 -1
  138. package/src/codex/account-lifecycle.ts +21 -5
  139. package/src/codex/account-preservation.ts +28 -0
  140. package/src/codex/account-use-remaining.ts +23 -0
  141. package/src/codex/app-server-processes.ts +97 -7
  142. package/src/codex/app-server-restart-service.ts +55 -4
  143. package/src/codex/auth-api/account-list.ts +4 -0
  144. package/src/codex/auth-api/account-pause-group.ts +6 -50
  145. package/src/codex/auth-api/account-preservation.ts +57 -0
  146. package/src/codex/auth-api/pool-mode-gate.ts +5 -2
  147. package/src/codex/auth-api/routes.ts +8 -0
  148. package/src/codex/auth-api/use-remaining-route.ts +36 -0
  149. package/src/codex/auth-api.ts +0 -1
  150. package/src/codex/auth-context.ts +81 -7
  151. package/src/codex/autostart-health.ts +4 -0
  152. package/src/codex/catalog/auto-review.ts +20 -3
  153. package/src/codex/catalog/build-entries.ts +19 -2
  154. package/src/codex/catalog/combo-member.ts +14 -5
  155. package/src/codex/catalog/configured-tiers.ts +50 -0
  156. package/src/codex/catalog/effort.ts +4 -1
  157. package/src/codex/catalog/gather-capture.ts +2 -0
  158. package/src/codex/catalog/metadata.ts +11 -9
  159. package/src/codex/catalog/model-hints.ts +42 -19
  160. package/src/codex/catalog/model-visibility.ts +3 -1
  161. package/src/codex/catalog/native-ultrafast.ts +106 -0
  162. package/src/codex/catalog/parsing.ts +35 -86
  163. package/src/codex/catalog/provider-models.ts +40 -34
  164. package/src/codex/catalog/retained-sync.ts +2 -0
  165. package/src/codex/catalog/routed-gather.ts +33 -16
  166. package/src/codex/catalog/vendor-context.ts +82 -0
  167. package/src/codex/cli-install-provenance.ts +105 -17
  168. package/src/codex/cli-update-plan.ts +545 -0
  169. package/src/codex/config-write-lock.ts +63 -4
  170. package/src/codex/convergence.ts +2 -0
  171. package/src/codex/desktop-app/picker-freshness.ts +96 -0
  172. package/src/codex/desktop-app/types.ts +2 -0
  173. package/src/codex/desktop-app/windows.ts +29 -16
  174. package/src/codex/desktop-app-restart.ts +25 -2
  175. package/src/codex/desktop-compatibility/certificate-service.ts +99 -0
  176. package/src/codex/desktop-compatibility/certificate-store.ts +193 -0
  177. package/src/codex/desktop-compatibility/connection-store.ts +87 -0
  178. package/src/codex/desktop-compatibility/installed-build.ts +73 -0
  179. package/src/codex/desktop-compatibility/json-body.ts +29 -0
  180. package/src/codex/desktop-compatibility/native-identity.ts +62 -0
  181. package/src/codex/desktop-compatibility/relay-listener.ts +93 -0
  182. package/src/codex/desktop-compatibility/routing-binding.ts +10 -0
  183. package/src/codex/desktop-compatibility/routing-preflight.ts +69 -0
  184. package/src/codex/desktop-compatibility/runtime-ownership.ts +28 -0
  185. package/src/codex/desktop-compatibility/runtime.ts +182 -0
  186. package/src/codex/desktop-compatibility/service.ts +30 -0
  187. package/src/codex/desktop-compatibility/startup-settings.ts +50 -0
  188. package/src/codex/desktop-compatibility/usage-activation.ts +86 -0
  189. package/src/codex/desktop-compatibility/usage-controlled-fetch.ts +59 -0
  190. package/src/codex/desktop-compatibility/usage-controller.ts +107 -0
  191. package/src/codex/desktop-compatibility/usage-policy.ts +59 -0
  192. package/src/codex/desktop-compatibility/usage-refresh.ts +33 -0
  193. package/src/codex/desktop-compatibility/usage-sse-controller.ts +86 -0
  194. package/src/codex/desktop-compatibility/windows-activation-source.ts +44 -0
  195. package/src/codex/desktop-compatibility/windows-certificate-trust.ts +81 -0
  196. package/src/codex/desktop-compatibility/windows-key-protection.ts +165 -0
  197. package/src/codex/desktop-compatibility/windows-package-command.ts +86 -0
  198. package/src/codex/desktop-compatibility/windows-package-launch.ts +28 -0
  199. package/src/codex/features.ts +85 -45
  200. package/src/codex/history-provider.ts +1 -1
  201. package/src/codex/inject/config-write-section.ts +4 -1
  202. package/src/codex/inject/history-failure.ts +27 -0
  203. package/src/codex/inject/remove.ts +18 -6
  204. package/src/codex/inject/restore.ts +24 -2
  205. package/src/codex/inject/routing-classify.ts +4 -3
  206. package/src/codex/inject.ts +18 -27
  207. package/src/codex/journal.ts +16 -1
  208. package/src/codex/main-account-hard-lock.ts +30 -1
  209. package/src/codex/main-account.ts +99 -15
  210. package/src/codex/native-main-refresh-mode.ts +217 -0
  211. package/src/codex/native-profile-startup.ts +1 -1
  212. package/src/codex/ocx-compaction-history.ts +12 -10
  213. package/src/codex/paths.ts +86 -1
  214. package/src/codex/provider-routing.ts +174 -0
  215. package/src/codex/refresh.ts +2 -2
  216. package/src/codex/routing/health-store.ts +2 -2
  217. package/src/codex/routing/pool-recovery.ts +79 -0
  218. package/src/codex/routing/selection.ts +4 -3
  219. package/src/codex/routing/thread-affinity.ts +1 -1
  220. package/src/codex/shim-diagnostics.ts +6 -0
  221. package/src/codex/shim-overlay.ts +7 -2
  222. package/src/codex/signed-in-identity.ts +43 -0
  223. package/src/codex/subagent-model-fallback.ts +1 -1
  224. package/src/codex/sync.ts +6 -1
  225. package/src/codex/user-identity.ts +16 -5
  226. package/src/codex/windows-local-appdata.ts +84 -0
  227. package/src/combos/failover.ts +6 -1
  228. package/src/combos/index.ts +1 -0
  229. package/src/combos/resolve.ts +46 -10
  230. package/src/combos/types.ts +15 -0
  231. package/src/config/diagnostics.ts +35 -7
  232. package/src/config/live-reconcile.ts +51 -2
  233. package/src/config/load-degrade.ts +23 -1
  234. package/src/config/opencode-wire-upgrade.ts +54 -0
  235. package/src/config/opencode-zen-upgrade.ts +52 -0
  236. package/src/config/owner-registry.ts +22 -17
  237. package/src/config/paths.ts +10 -3
  238. package/src/config/provider-validation.ts +45 -2
  239. package/src/config/schema/config-schema.ts +39 -0
  240. package/src/config/schema/desktop-compatibility.ts +9 -0
  241. package/src/config/schema/leaf-validators.ts +39 -9
  242. package/src/config/schema/main-account-hard-lock-fallback.ts +26 -0
  243. package/src/config/schema/native-reasoning-retention.ts +26 -0
  244. package/src/config.ts +2 -0
  245. package/src/generated/compatibility-version.json +962 -350
  246. package/src/generated/model-metadata.ts +1 -1
  247. package/src/grok/sync.ts +1 -1
  248. package/src/images/loop.ts +46 -8
  249. package/src/integrations/catalog-refresh.ts +1 -1
  250. package/src/integrations/config-io.ts +20 -2
  251. package/src/integrations/journal.ts +15 -1
  252. package/src/integrations/mutation-plan.ts +2 -0
  253. package/src/integrations/registry.ts +15 -0
  254. package/src/integrations/store.ts +3 -0
  255. package/src/integrations/writer.ts +10 -1
  256. package/src/lib/advisor-activation.ts +16 -0
  257. package/src/lib/background-work.ts +65 -0
  258. package/src/lib/bounded-file-read.ts +58 -0
  259. package/src/lib/bun-path-runtime.d.mts +10 -1
  260. package/src/lib/bun-path-runtime.mjs +62 -3
  261. package/src/lib/codex-restart-contract.ts +15 -0
  262. package/src/lib/desktop-proxy-route.ts +30 -0
  263. package/src/lib/desktop-upstream-tunnel.ts +72 -0
  264. package/src/lib/empty-tool-catalog.ts +62 -0
  265. package/src/lib/errors.ts +26 -3
  266. package/src/lib/gcp-adc.ts +96 -9
  267. package/src/lib/gcp-credential-input.ts +12 -0
  268. package/src/lib/lab-live-route-production.ts +5 -0
  269. package/src/lib/local-internal-call-capability.ts +55 -0
  270. package/src/lib/opaque-proxy-tunnel.ts +217 -0
  271. package/src/lib/package-tree-integrity.ts +2 -2
  272. package/src/lib/redact.ts +2 -2
  273. package/src/lib/socks5-fetch.ts +48 -71
  274. package/src/lib/socks5-handshake.ts +112 -0
  275. package/src/lib/translator-budget.ts +7 -1
  276. package/src/oauth/account-quota-rank.ts +69 -2
  277. package/src/oauth/anthropic-account-refusal.ts +20 -2
  278. package/src/oauth/anthropic-oauth-definitions.ts +3 -1
  279. package/src/oauth/anthropic-routing.ts +1 -21
  280. package/src/oauth/anthropic.ts +38 -7
  281. package/src/oauth/callback-server.ts +27 -1
  282. package/src/oauth/chatgpt-device.ts +1 -1
  283. package/src/oauth/chatgpt-shared.ts +83 -0
  284. package/src/oauth/chatgpt.ts +8 -72
  285. package/src/oauth/dsh.ts +203 -0
  286. package/src/oauth/generic-account-failover.ts +62 -12
  287. package/src/oauth/generic-session-affinity.ts +125 -0
  288. package/src/oauth/index.ts +188 -111
  289. package/src/oauth/kiro-device-login.ts +2 -1
  290. package/src/oauth/kiro.ts +7 -1
  291. package/src/oauth/local-token-detect.ts +21 -1
  292. package/src/oauth/login-cli-errors.ts +44 -0
  293. package/src/oauth/login-cli.ts +69 -7
  294. package/src/oauth/login-flow-state.ts +371 -23
  295. package/src/oauth/meta-muse-errors.ts +41 -0
  296. package/src/oauth/meta-muse-keychain.ts +52 -0
  297. package/src/oauth/meta-muse.ts +51 -84
  298. package/src/oauth/model-discovery-auth.ts +3 -0
  299. package/src/oauth/pool-settings-capability.ts +4 -2
  300. package/src/oauth/refresh-flight-retirement.ts +48 -0
  301. package/src/oauth/session-affinity-key.ts +23 -0
  302. package/src/oauth/store-anthropic-instance.ts +9 -2
  303. package/src/oauth/store.ts +12 -5
  304. package/src/protocols/codecs/chat-ir.ts +467 -0
  305. package/src/protocols/codecs/chat.ts +10 -1
  306. package/src/protocols/codecs/messages-ir.ts +500 -0
  307. package/src/protocols/encoders/adapter-events.ts +5 -4
  308. package/src/protocols/encoders/messages.ts +9 -6
  309. package/src/protocols/features.ts +10 -2
  310. package/src/protocols/path.ts +11 -1
  311. package/src/protocols/plan-snapshot.ts +39 -16
  312. package/src/protocols/plan.ts +9 -1
  313. package/src/protocols/provider-summary.ts +2 -1
  314. package/src/protocols/settings.ts +8 -0
  315. package/src/providers/antigravity-account-roster.ts +102 -0
  316. package/src/providers/antigravity-models.ts +85 -7
  317. package/src/providers/api-key-cooldowns.ts +49 -0
  318. package/src/providers/api-key-resolve.ts +11 -6
  319. package/src/providers/api-key-response-ownership.ts +57 -0
  320. package/src/providers/api-key-selection.ts +31 -6
  321. package/src/providers/api-keys.ts +214 -3
  322. package/src/providers/claude-cli-usage.ts +96 -0
  323. package/src/providers/dsh-account-destination.ts +31 -0
  324. package/src/providers/dsh-account-models.ts +41 -0
  325. package/src/providers/gcp-credential-cleanup.ts +59 -0
  326. package/src/providers/key-failover.ts +54 -50
  327. package/src/providers/key-store.ts +7 -2
  328. package/src/providers/model-rename-fields.ts +5 -0
  329. package/src/providers/model-rename-migration.ts +7 -5
  330. package/src/providers/openai-tiers-destination.ts +11 -2
  331. package/src/providers/openai-tiers.ts +5 -12
  332. package/src/providers/opencode-go-transport.ts +3 -1
  333. package/src/providers/quota/account-cache.ts +6 -5
  334. package/src/providers/quota/account-row.ts +34 -0
  335. package/src/providers/quota/antigravity.ts +28 -7
  336. package/src/providers/quota/dsh-account.ts +70 -0
  337. package/src/providers/quota/vendor-probes-oauth.ts +1 -93
  338. package/src/providers/quota-types.ts +2 -0
  339. package/src/providers/quota.ts +14 -20
  340. package/src/providers/registry/entries-core.ts +44 -14
  341. package/src/providers/registry/entries-extended.ts +19 -0
  342. package/src/providers/registry/types.ts +1 -1
  343. package/src/providers/request-pacing.ts +77 -19
  344. package/src/providers/routed-config.ts +339 -0
  345. package/src/providers/service-tier.ts +2 -1
  346. package/src/quota/window-mapping.ts +5 -2
  347. package/src/responses/anthropic-progress.ts +34 -0
  348. package/src/responses/assistant-replay.ts +35 -0
  349. package/src/responses/compaction-history-framing.ts +65 -0
  350. package/src/responses/compaction.ts +6 -1
  351. package/src/responses/incomplete-reason.ts +31 -0
  352. package/src/responses/parser.ts +78 -22
  353. package/src/responses/reasoning-envelope.ts +4 -0
  354. package/src/responses/reasoning-replay-cache.ts +24 -2
  355. package/src/responses/reasoning-retention.ts +173 -0
  356. package/src/responses/retained-compaction.ts +46 -0
  357. package/src/responses/schema.ts +23 -0
  358. package/src/responses/state.ts +32 -29
  359. package/src/router.ts +8 -321
  360. package/src/routing/health.ts +37 -22
  361. package/src/routing/history/build-file.ts +92 -0
  362. package/src/routing/history/indexer.ts +254 -221
  363. package/src/routing/history/ingest.ts +242 -0
  364. package/src/routing/history/rebuild-job.ts +111 -0
  365. package/src/routing/history/rebuild-protocol.ts +15 -0
  366. package/src/routing/history/rebuild-worker.ts +34 -0
  367. package/src/routing/profile.ts +1 -1
  368. package/src/server/admission-model-scope.ts +21 -1
  369. package/src/server/antigravity-direct-eligibility.ts +208 -0
  370. package/src/server/auth-cors.ts +15 -0
  371. package/src/server/chat-completions.ts +82 -10
  372. package/src/server/chat-native-reasoning.ts +123 -0
  373. package/src/server/chat-native-sse.ts +110 -7
  374. package/src/server/chat-native.ts +76 -17
  375. package/src/server/claude-messages.ts +164 -433
  376. package/src/server/effort-policy.ts +1 -1
  377. package/src/server/images.ts +15 -2
  378. package/src/server/index/desktop-compatibility-startup.ts +56 -0
  379. package/src/server/index/model-alias-id.ts +36 -0
  380. package/src/server/index/optional-listeners.ts +2 -0
  381. package/src/server/index/serve-options.ts +11 -3
  382. package/src/server/index/startup-warnings.ts +11 -0
  383. package/src/server/index/websocket-handler.ts +9 -0
  384. package/src/server/index.ts +14 -11
  385. package/src/server/inference/advisor-diagnostics.ts +31 -0
  386. package/src/server/inference/client-encoder-delivery.ts +6 -5
  387. package/src/server/login-shell-path.ts +146 -0
  388. package/src/server/management/advisor-routes.ts +202 -0
  389. package/src/server/management/agent-settings-routes.ts +22 -4
  390. package/src/server/management/claude-desktop-picker-routes.ts +1 -1
  391. package/src/server/management/combo-routes.ts +176 -50
  392. package/src/server/management/companion-routes.ts +4 -0
  393. package/src/server/management/config-routes.ts +77 -6
  394. package/src/server/management/context.ts +4 -0
  395. package/src/server/management/cursor-integration-routes.ts +1 -1
  396. package/src/server/management/desktop-compatibility-routes.ts +46 -0
  397. package/src/server/management/desktop-compatibility-runtime-routes.ts +46 -0
  398. package/src/server/management/desktop-compatibility-settings-routes.ts +27 -0
  399. package/src/server/management/model-routes.ts +13 -8
  400. package/src/server/management/model-rows.ts +14 -0
  401. package/src/server/management/native-integration-routes.ts +2 -7
  402. package/src/server/management/native-reasoning-retention-routes.ts +41 -0
  403. package/src/server/management/oauth-account-routes.ts +87 -14
  404. package/src/server/management/protocol-settings-patch.ts +1 -0
  405. package/src/server/management/provider-gcp-credential-routes.ts +29 -0
  406. package/src/server/management/provider-key-pacing-routes.ts +31 -0
  407. package/src/server/management/provider-overwrite-carry.ts +7 -0
  408. package/src/server/management/provider-routes.ts +25 -30
  409. package/src/server/management/route-registry.ts +21 -1
  410. package/src/server/management/sibling-guard.ts +1 -0
  411. package/src/server/management-api.ts +9 -1
  412. package/src/server/messages-antigravity-direct.ts +195 -0
  413. package/src/server/messages-native-tool-guard.ts +185 -0
  414. package/src/server/messages-native.ts +106 -22
  415. package/src/server/messages-shared.ts +431 -0
  416. package/src/server/relay.ts +1 -1
  417. package/src/server/request-log-terminal-status.ts +1 -1
  418. package/src/server/request-log.ts +13 -1
  419. package/src/server/responses/account-change-state.ts +8 -2
  420. package/src/server/responses/adapter-continuation.ts +48 -19
  421. package/src/server/responses/adapter-delivery.ts +43 -8
  422. package/src/server/responses/adapter-dispatch.ts +48 -4
  423. package/src/server/responses/advisor-plan-slot.ts +27 -0
  424. package/src/server/responses/advisor-retention.ts +117 -0
  425. package/src/server/responses/advisor-slot.ts +368 -0
  426. package/src/server/responses/code-mode-collab-surface.ts +116 -8
  427. package/src/server/responses/codex-ws-wire.ts +15 -8
  428. package/src/server/responses/compact.ts +303 -125
  429. package/src/server/responses/compaction-recovery.ts +18 -10
  430. package/src/server/responses/compaction-retention.ts +61 -0
  431. package/src/server/responses/context-overflow.ts +11 -6
  432. package/src/server/responses/core-auth.ts +6 -0
  433. package/src/server/responses/core-codex-account.ts +11 -1
  434. package/src/server/responses/core-combo-failure.ts +12 -1
  435. package/src/server/responses/core-combo.ts +141 -36
  436. package/src/server/responses/core-errors.ts +3 -3
  437. package/src/server/responses/core-lifetime.ts +7 -2
  438. package/src/server/responses/core-normalize.ts +11 -0
  439. package/src/server/responses/core-opaque-recovery.ts +35 -0
  440. package/src/server/responses/core-options.ts +51 -0
  441. package/src/server/responses/core-pipeline.ts +141 -0
  442. package/src/server/responses/core-replay.ts +25 -6
  443. package/src/server/responses/core.ts +3 -116
  444. package/src/server/responses/fetch-helpers.ts +73 -19
  445. package/src/server/responses/main-hard-lock-routing.ts +109 -0
  446. package/src/server/responses/native-response-control.ts +4 -2
  447. package/src/server/responses/passthrough-delivery.ts +19 -11
  448. package/src/server/responses/passthrough-dispatch.ts +29 -16
  449. package/src/server/responses/request-prepare.ts +144 -17
  450. package/src/server/responses/request-sidecar-auth.ts +2 -2
  451. package/src/server/responses/request-transport.ts +120 -27
  452. package/src/server/responses/response-effects.ts +1 -0
  453. package/src/server/responses/run-turn-execution.ts +166 -38
  454. package/src/server/responses/sidecar-execution.ts +98 -5
  455. package/src/server/responses/terminal-guard.ts +4 -17
  456. package/src/server/responses-undeclared-tool-guard.ts +30 -9
  457. package/src/server/startup-action-control.ts +16 -2
  458. package/src/server/startup-health-cache.ts +1 -0
  459. package/src/service/auth-preflight.ts +71 -0
  460. package/src/service/cli.ts +4 -2
  461. package/src/service/definition.ts +97 -0
  462. package/src/service/desktop-startup.ts +14 -0
  463. package/src/service/guards.ts +1 -61
  464. package/src/service/health-sentinel-linux.ts +112 -0
  465. package/src/service/health-sentinel-main.ts +99 -61
  466. package/src/service/health-sentinel-probe.ts +24 -7
  467. package/src/service/health.ts +5 -89
  468. package/src/service/launchd.ts +27 -7
  469. package/src/service/logging.ts +135 -0
  470. package/src/service/repair.ts +2 -1
  471. package/src/service/state.ts +7 -8
  472. package/src/service/systemd.ts +1 -1
  473. package/src/service/windows-guarded-manager.ts +2 -1
  474. package/src/service/windows-ops.ts +1 -1
  475. package/src/service/windows-scheduler.ts +2 -7
  476. package/src/service/windows-taskxml.ts +2 -2
  477. package/src/service/windows-wscript.ts +14 -0
  478. package/src/service.ts +4 -2
  479. package/src/sidecar/auth.ts +2 -0
  480. package/src/tray/windows-tray.ps1 +43 -24
  481. package/src/types/config.ts +124 -6
  482. package/src/types/opencode-go.ts +61 -0
  483. package/src/types/opencode-zen.ts +29 -0
  484. package/src/types/provider.ts +39 -6
  485. package/src/types/request.ts +38 -2
  486. package/src/types/tools.ts +2 -0
  487. package/src/types/wire.ts +29 -37
  488. package/src/types.ts +1 -0
  489. package/src/update/async-check.ts +1 -1
  490. package/src/update/badge.ts +2 -2
  491. package/src/update/index.ts +88 -15
  492. package/src/update/job-supervised-restart.ts +107 -0
  493. package/src/update/job.ts +32 -32
  494. package/src/update/notify.ts +1 -1
  495. package/src/update/npm-invocation.mjs +12 -2
  496. package/src/update/refresh-scheduler.ts +2 -2
  497. package/src/update/supervised-recovery.d.mts +27 -0
  498. package/src/update/supervised-recovery.mjs +157 -0
  499. package/src/usage/cache-diagnostic.ts +2 -0
  500. package/src/usage/cost.ts +48 -12
  501. package/src/usage/expected-prices.ts +15 -0
  502. package/src/usage/ledger-retention.ts +2 -1
  503. package/src/usage/ledger-scanner.ts +6 -5
  504. package/src/usage/log.ts +17 -8
  505. package/src/usage/summary.ts +22 -9
  506. package/src/usage/user-cost-overlays.ts +14 -19
  507. package/src/usage/user-cost-validation.ts +38 -0
  508. package/src/vision/eligibility.ts +13 -0
  509. package/src/web-search/gemini-executor.ts +2 -2
  510. package/src/web-search/loop.ts +55 -5
  511. package/src/web-search/progress-stream.ts +4 -1
  512. package/src/web-search/run-turn-loop.ts +9 -1
  513. package/assets/sponsors/packycode.png +0 -0
  514. package/gui/dist/assets/App-CSJvmjNs.css +0 -1
  515. package/gui/dist/assets/App-CZtqiGcw.js +0 -56
  516. package/gui/dist/assets/index-BB6uK6tU.css +0 -1
  517. package/gui/dist/assets/index-CTm4l-HQ.js +0 -94
  518. package/gui/dist/assets/quota-summary-BbEeRfPY.js +0 -1
@@ -23,12 +23,17 @@ import {
23
23
  import {
24
24
  clearLoginState,
25
25
  getLoginStatus,
26
+ isCodeLoginFlow,
26
27
  isPublicOAuthProvider,
27
28
  listOAuthProviders,
29
+ loginFlowAccountId,
28
30
  OAUTH_PROVIDERS,
29
31
  publicOAuthAuthenticationErrorMessage,
30
32
  startLoginFlow,
33
+ submitLoginCode,
31
34
  submitManualLoginCode,
35
+ supportsCodeLoginMode,
36
+ waitForLoginSettled,
32
37
  } from "../../oauth";
33
38
  import { OAuthMutationBusyError, removeCredential } from "../../oauth/store";
34
39
  import { cancelKiroDeviceLogin, kiroDeviceConfigBaseline, startKiroDeviceLogin, statusKiroDeviceLogin, type KiroDeviceMethod } from "../../oauth/kiro-device-login";
@@ -253,9 +258,17 @@ export async function handleOauthAccountRoutes(ctx: ManagementContext): Promise<
253
258
  // the provider's loopback callback server (inside this process) captures the redirect in the
254
259
  // background, then the credential is persisted. The GUI opens the URL and polls /api/oauth/status.
255
260
  if (url.pathname === "/api/oauth/login" && req.method === "POST") {
256
- const body = await readManagementJsonBodyOr(req, {}) as { provider?: string; addAccount?: boolean; accountId?: string; reauth?: boolean; openBrowser?: unknown; method?: unknown };
261
+ const body = await readManagementJsonBodyOr(req, {}) as { provider?: string; addAccount?: boolean; accountId?: string; reauth?: boolean; openBrowser?: unknown; method?: unknown; mode?: unknown };
257
262
  const provider = (body.provider ?? "").trim().toLowerCase();
258
263
  if (!isPublicOAuthProvider(provider)) return jsonResponse({ error: "unknown oauth provider" }, 400);
264
+ // Omitted mode is the localhost-callback flow this route has always run.
265
+ if (body.mode !== undefined && body.mode !== "callback" && body.mode !== "code") {
266
+ return jsonResponse({ error: "mode must be \"callback\" or \"code\"" }, 400);
267
+ }
268
+ const codeMode = body.mode === "code";
269
+ if (codeMode && !supportsCodeLoginMode(provider)) {
270
+ return jsonResponse({ error: "code_mode_unsupported" }, 400);
271
+ }
259
272
  // Muse may import a local Keychain credential or start a device grant; add-account
260
273
  // and reauth skip the import. All management login paths require the dashboard
261
274
  // principal before credential acquisition. A raw token proves administration,
@@ -292,10 +305,15 @@ export async function handleOauthAccountRoutes(ctx: ManagementContext): Promise<
292
305
  // request may already have mutated live config and yielded before its save.
293
306
  const persistedBaseline = readConfigDiagnostics().config;
294
307
  // addAccount / reauth forces a fresh browser identity (skips local-CLI token import).
295
- const { url: authUrl, instructions, deviceCode } = await startLoginFlow(provider, {
308
+ // Only code mode gets a flow id: it is what a later paste is pinned to. The callback
309
+ // flow's lifecycle argument stays exactly as it was.
310
+ const flowId = codeMode ? randomUUID() : undefined;
311
+ const { url: authUrl, instructions, deviceCode, expiresAt } = await startLoginFlow(provider, {
296
312
  forceLogin: body.addAccount === true || reauth,
297
313
  ...(accountId ? { reauthAccountId: accountId } : {}),
314
+ ...(codeMode ? { codeMode: true } : {}),
298
315
  }, {
316
+ ...(flowId ? { flowId } : {}),
299
317
  // startLoginFlow returns the authorization URL before background persistence completes.
300
318
  // Three-way reconcile settled disk changes so a failed login cannot leave a provider
301
319
  // live-only and an in-flight management mutation cannot be erased before it saves.
@@ -322,7 +340,13 @@ export async function handleOauthAccountRoutes(ctx: ManagementContext): Promise<
322
340
  const { openUrl } = await import("../../lib/open-url");
323
341
  browserLaunch = (await openUrl(authUrl)).status === "started" ? "started" : "failed";
324
342
  }
325
- return jsonResponse({ url: authUrl, instructions, deviceCode, browserLaunch });
343
+ return jsonResponse({
344
+ url: authUrl,
345
+ instructions,
346
+ deviceCode,
347
+ browserLaunch,
348
+ ...(codeMode ? { mode: "code", flowId, expiresAt } : {}),
349
+ });
326
350
  } catch (err) {
327
351
  if (err instanceof OAuthMutationBusyError) throw err;
328
352
  const message = err instanceof Error ? err.message : String(err);
@@ -347,25 +371,69 @@ export async function handleOauthAccountRoutes(ctx: ManagementContext): Promise<
347
371
  return result ? jsonResponse(result) : jsonResponse({ error: "unknown login flow" }, 404);
348
372
  }
349
373
  const { cancelLoginFlow } = await import("../../oauth");
350
- const cancelled = cancelLoginFlow(provider);
374
+ // Without a flow id this cancels the provider's newest in-flight login, which is what the
375
+ // single-user GUI has always meant by "Cancel". A host running concurrent code logins for
376
+ // several users passes the flowId it was given at /api/oauth/login.
377
+ const cancelled = cancelLoginFlow(provider, typeof body.flowId === "string" ? body.flowId : undefined);
351
378
  return jsonResponse({ ok: true, cancelled });
352
379
  }
353
380
 
354
381
  // Manual fallback for browser OAuth: paste the final redirect URL (or authorization code)
355
382
  // when the browser cannot reach the loopback callback (remote/SSH/blocked localhost).
383
+ //
384
+ // A code-display flow (started with mode:"code", or identified by its flowId) gets the
385
+ // richer contract instead: the paste is answered with the OUTCOME of the token exchange,
386
+ // not merely with "accepted". A hosted caller has one paste box and no second channel, so
387
+ // "accepted" is indistinguishable from "worked" to the person typing.
356
388
  if (url.pathname === "/api/oauth/login/code" && req.method === "POST") {
357
- const body = await readManagementJsonBodyOr(req, {}) as { provider?: string; input?: string; code?: string };
389
+ const body = await readManagementJsonBodyOr(req, {}) as { provider?: string; input?: string; code?: string; flowId?: unknown };
358
390
  const provider = (body.provider ?? "").trim().toLowerCase();
359
391
  if (!isPublicOAuthProvider(provider)) return jsonResponse({ error: "unknown oauth provider" }, 400);
360
392
  const consentRequired = metaMuseConsentRequired(provider, principal);
361
393
  if (consentRequired) return consentRequired;
394
+ const flowId = typeof body.flowId === "string" ? body.flowId : undefined;
395
+ const maskEmails = emailMaskingEnabled(config);
396
+ // Only a code flow of THIS provider gets the outcome-waiting contract; that flow is single-use,
397
+ // so at most one request ever waits on it. A flow id naming anything else (a callback flow,
398
+ // another provider's flow, nothing) has no code login to complete.
399
+ const codeFlow = isCodeLoginFlow(provider, flowId);
400
+ if (flowId !== undefined && !codeFlow) return jsonResponse({ ok: false, error: "no_pending_login" }, 409);
362
401
  const input = typeof body.input === "string" ? body.input : typeof body.code === "string" ? body.code : "";
363
402
  // Authorization responses are measured in hundreds of bytes; never accept the
364
403
  // generic management-body allowance here.
365
- if (input.length > 4096) return jsonResponse({ error: "input too long" }, 400);
366
- const result = submitManualLoginCode(provider, input);
367
- if (!result.ok) return jsonResponse({ error: result.error }, 409);
368
- return jsonResponse({ ok: true });
404
+ if (input.length > 4096) {
405
+ return codeFlow
406
+ ? jsonResponse({ ok: false, error: "malformed_input" }, 400)
407
+ : jsonResponse({ error: "input too long" }, 400);
408
+ }
409
+ if (!codeFlow) {
410
+ const result = submitManualLoginCode(provider, input);
411
+ if (!result.ok) return jsonResponse({ error: result.error }, 409);
412
+ return jsonResponse({ ok: true });
413
+ }
414
+ const submitted = submitLoginCode(provider, input, flowId);
415
+ // Rejected before any token request: the flow stays alive so the user can paste again.
416
+ if (!submitted.ok) {
417
+ return jsonResponse({ ok: false, error: submitted.code }, submitted.code === "no_pending_login" ? 409 : 400);
418
+ }
419
+ // The exchange itself times out at 30s inside the provider client; this only has to
420
+ // outlast it so a hung socket surfaces as an answer rather than as a hung request.
421
+ // Pinned to the flow this paste actually landed in: with several code logins in flight for
422
+ // one provider, "the newest flow" by the time this resolves may be somebody else's.
423
+ const settled = await waitForLoginSettled(provider, 60_000, submitted.flowId);
424
+ const status = getLoginStatus(provider, maskEmails, submitted.flowId);
425
+ if (!settled) return jsonResponse({ ok: false, error: "provider_unreachable" }, 400);
426
+ if (status.error) {
427
+ const failure = status.errorCode ?? "invalid_or_expired_code";
428
+ return jsonResponse({ ok: false, error: failure }, failure === "no_pending_login" ? 409 : 400);
429
+ }
430
+ // A flow dropped while waiting (logout, clear) never completed, whatever the store now holds.
431
+ if (status.status !== "complete") return jsonResponse({ ok: false, error: "no_pending_login" }, 409);
432
+ // The account THIS flow wrote, which need not be the active one (reauth of an inactive account,
433
+ // or a concurrent login that finished later).
434
+ const savedId = loginFlowAccountId(provider, submitted.flowId);
435
+ const account = savedId === undefined ? undefined : status.accounts?.find(entry => entry.id === savedId);
436
+ return jsonResponse({ ok: true, ...(account ? { account: { id: account.id, email: account.email } } : {}) });
369
437
  }
370
438
 
371
439
  if (url.pathname === "/api/oauth/status" && req.method === "GET") {
@@ -597,10 +665,15 @@ export async function handleOauthAccountRoutes(ctx: ManagementContext): Promise<
597
665
  // sticky limit is refused identically whichever pool is addressed.
598
666
  let strategy: string | undefined;
599
667
  if (fields.strategy !== undefined) {
600
- const parsed = kind === "codex" ? parseCodexAccountPoolStrategy(fields.strategy) : parseGenericPoolStrategy(fields.strategy, provider);
601
- if (parsed === null) return jsonResponse({ error: kind === "codex"
602
- ? "strategy must be one of: quota, round-robin, fill-first, reset-first"
603
- : `strategy must be one of: quota, round-robin, fill-first${provider === "kiro" ? ", least-loaded" : ""}` }, 400);
668
+ // reset-first is a Codex and generic strategy. The Anthropic runtime implements only
669
+ // quota, round-robin and fill-first, so that kind keeps refusing it rather than storing
670
+ // a strategy it would silently ignore.
671
+ const parsed = kind === "codex" ? parseCodexAccountPoolStrategy(fields.strategy)
672
+ : kind === "generic" ? parseGenericPoolStrategy(fields.strategy, provider)
673
+ : parseAccountPoolStrategy(fields.strategy);
674
+ if (parsed === null) return jsonResponse({ error: kind === "anthropic"
675
+ ? "strategy must be one of: quota, round-robin, fill-first"
676
+ : `strategy must be one of: quota, round-robin, fill-first, reset-first${kind === "generic" && provider === "kiro" ? ", least-loaded" : ""}` }, 400);
604
677
  strategy = parsed;
605
678
  }
606
679
  let stickyLimit: number | undefined;
@@ -754,7 +827,7 @@ export async function handleOauthAccountRoutes(ctx: ManagementContext): Promise<
754
827
  if (body.strategy === null) delete next.strategy;
755
828
  else {
756
829
  const parsed = parseGenericPoolStrategy(body.strategy, provider);
757
- if (parsed === null) return jsonResponse({ error: `strategy must be one of: quota, round-robin, fill-first${provider === "kiro" ? ", least-loaded" : ""}` }, 400);
830
+ if (parsed === null) return jsonResponse({ error: `strategy must be one of: quota, round-robin, fill-first, reset-first${provider === "kiro" ? ", least-loaded" : ""}` }, 400);
758
831
  next.strategy = parsed;
759
832
  }
760
833
  }
@@ -31,6 +31,7 @@ export const PROTOCOL_ROLLOUT_KEYS = [
31
31
  "managedMessagesNative",
32
32
  "managedMessagesNativeOAuth",
33
33
  "directEncoders",
34
+ "antigravityDirect",
34
35
  "shadowPlan",
35
36
  ] as const satisfies readonly (keyof ProtocolRolloutSettings)[];
36
37
  const ROLLOUT_KEYS = new Set<string>(PROTOCOL_ROLLOUT_KEYS);
@@ -0,0 +1,29 @@
1
+ import { providerCredentialInputError } from "../../providers/api-keys";
2
+ import { commitProviderGcpCredentialRemoval } from "../../providers/gcp-credential-cleanup";
3
+ import { dropProviderCustomModels } from "../../providers/provider-id-rewrite";
4
+ import { forgetProviderContextCap } from "../../providers/context-cap";
5
+ import type { OcxConfig } from "../../types";
6
+ import { jsonResponse } from "../auth-cors";
7
+
8
+ /** Generic provider writes refuse credential JSON before any config mutation. */
9
+ export function providerGcpCredentialInputResponse(provider: { apiKey?: unknown; apiKeyPool?: unknown }): Response | null {
10
+ const error = providerCredentialInputError(provider);
11
+ return error ? jsonResponse({ error }, 400) : null;
12
+ }
13
+
14
+ /** Keep marker capture, provider removal and persistence in one synchronous locked operation. */
15
+ export function removeProviderWithGcpCredentials(
16
+ config: OcxConfig,
17
+ name: string,
18
+ fallbackDefault: string | undefined,
19
+ save: (config: OcxConfig) => void,
20
+ ): number {
21
+ return commitProviderGcpCredentialRemoval(config, name, () => {
22
+ if (fallbackDefault) config.defaultProvider = fallbackDefault;
23
+ delete config.providers[name];
24
+ const dropped = dropProviderCustomModels(config, name);
25
+ forgetProviderContextCap(config, name);
26
+ save(config);
27
+ return dropped;
28
+ });
29
+ }
@@ -0,0 +1,31 @@
1
+ import { hasOwnProvider, isValidProviderName } from "../../config";
2
+ import { getKeyCooldownUntil } from "../../providers/key-failover";
3
+ import { providerRequestPacingStatus } from "../../providers/request-pacing";
4
+ import type { OcxProviderConfig } from "../../types";
5
+ import { jsonResponse } from "../auth-cors";
6
+ import type { ManagementContext } from "./context";
7
+
8
+ /** Read-only provider/key pacing diagnostics; configuration writes stay in the provider PATCH owner. */
9
+ export function handleProviderKeyPacingRoutes(
10
+ { req, url, config }: Pick<ManagementContext, "req" | "url" | "config">,
11
+ ): Response | null {
12
+ if (url.pathname !== "/api/provider-request-pacing" || req.method !== "GET") return null;
13
+ const statusFor = (name: string, provider: OcxProviderConfig) => {
14
+ const status = providerRequestPacingStatus(name, provider);
15
+ if (status.keys) status.keys = status.keys.map(row => ({ ...row, cooldownUntil: getKeyCooldownUntil(name, row.id) }));
16
+ return status;
17
+ };
18
+ const name = url.searchParams.get("name")?.trim();
19
+ if (name) {
20
+ if (!isValidProviderName(name) || !hasOwnProvider(config.providers, name)) {
21
+ return jsonResponse({ error: "unknown provider" }, 404);
22
+ }
23
+ return jsonResponse(statusFor(name, config.providers[name]!));
24
+ }
25
+ return jsonResponse(Object.fromEntries(
26
+ Object.entries(config.providers).map(([providerName, provider]) => [
27
+ providerName,
28
+ statusFor(providerName, provider),
29
+ ]),
30
+ ));
31
+ }
@@ -214,6 +214,13 @@ export function applyProviderCompatPatchFields(
214
214
  else return { error: "preserveResponsesReasoningContent must be a boolean" };
215
215
  touched = true;
216
216
  }
217
+ if (Object.hasOwn(rawBody, "inferContextWindow")) {
218
+ const value = rawBody.inferContextWindow;
219
+ if (value === null) delete next.inferContextWindow;
220
+ else if (typeof value === "boolean") next.inferContextWindow = value;
221
+ else return { error: "inferContextWindow must be a boolean or null" };
222
+ touched = true;
223
+ }
217
224
  if (Object.hasOwn(rawBody, "reasoningWireFormat")) {
218
225
  const value = rawBody.reasoningWireFormat;
219
226
  if (value === null) {
@@ -1,6 +1,8 @@
1
1
  import { contextTierRecordConfigError, modelCapabilitiesConfigError, mergeModelCapabilities } from "../../config/provider-validation";
2
2
  import { DECLARABLE_HOSTED_TOOL_TYPES } from "../../responses/hosted-tool-policy";
3
3
  import { randomUUID } from "node:crypto";
4
+ import { cleanupRemovedGcpCredentials, providerGcpCredentialMarkers, snapshotProviderGcpCredentialMarkers } from "../../providers/gcp-credential-cleanup";
5
+ import { providerGcpCredentialInputResponse, removeProviderWithGcpCredentials } from "./provider-gcp-credential-routes";
4
6
  import { readFileSync } from "node:fs";
5
7
  import { isDeepStrictEqual } from "node:util";
6
8
  import type { CatalogModel } from "../../codex/catalog";
@@ -78,7 +80,7 @@ import { cachedProviderQuotaIsExhausted } from "../../combos/resolve";
78
80
  import { probeJevDecisionProvider } from "../../combos/jev";
79
81
  import { comboDependsOnProviderRoute } from "./decision-model-validation";
80
82
  import { clearKeyCooldowns, forgetApiKeyRotationCursor } from "../../providers/key-failover";
81
- import { providerRequestPacingStatus } from "../../providers/request-pacing";
83
+ import { handleProviderKeyPacingRoutes } from "./provider-key-pacing-routes";
82
84
  import { CODEX_FORWARD_BASE_URL, isCanonicalOpenAiForwardProvider } from "../../providers/openai-tiers";
83
85
  import { codexAccountNamespaceProviderCollisionError } from "../../codex/account-namespace-match";
84
86
  import { clearThreadAccountMap } from "../../codex/routing";
@@ -853,7 +855,7 @@ function providerRoutingQuota(config: OcxConfig, name: string, now: number): Pro
853
855
 
854
856
  // Removing search/MCP windows may leave only a timestamp. That is not inference evidence.
855
857
  const percentages = [quota.fiveHourPercent, quota.weeklyPercent, quota.monthlyPercent,
856
- ...(quota.customWindows ?? []).map(window => window.percent)];
858
+ ...(quota.customWindows ?? []).filter(window => window.modelId === undefined).map(window => window.percent)];
857
859
  const hasPercentage = percentages.some(value => typeof value === "number" && Number.isFinite(value) && value >= 0);
858
860
  const credits = quota.creditsUsd;
859
861
  const hasCredits = credits !== undefined && Number.isFinite(credits.percent)
@@ -864,7 +866,7 @@ function providerRoutingQuota(config: OcxConfig, name: string, now: number): Pro
864
866
  let validUntil = quota.updatedAt + PROVIDER_QUOTA_MAX_AGE_MS;
865
867
  if (state === "exhausted") {
866
868
  const resets = [quota.fiveHourResetAt, quota.weeklyResetAt, quota.monthlyResetAt,
867
- ...(quota.customWindows ?? []).map(window => window.resetAt)]
869
+ ...(quota.customWindows ?? []).filter(window => window.modelId === undefined).map(window => window.resetAt)]
868
870
  .filter((reset): reset is number => typeof reset === "number" && Number.isFinite(reset)
869
871
  && reset > now && reset < validUntil)
870
872
  .sort((left, right) => left - right);
@@ -895,21 +897,8 @@ export async function handleProviderRoutes(ctx: ManagementContext): Promise<Resp
895
897
  });
896
898
  }
897
899
 
898
- if (url.pathname === "/api/provider-request-pacing" && req.method === "GET") {
899
- const name = url.searchParams.get("name")?.trim();
900
- if (name) {
901
- if (!isValidProviderName(name) || !hasOwnProvider(config.providers, name)) {
902
- return jsonResponse({ error: "unknown provider" }, 404);
903
- }
904
- return jsonResponse(providerRequestPacingStatus(name, config.providers[name]!));
905
- }
906
- return jsonResponse(Object.fromEntries(
907
- Object.entries(config.providers).map(([providerName, provider]) => [
908
- providerName,
909
- providerRequestPacingStatus(providerName, provider),
910
- ]),
911
- ));
912
- }
900
+ const keyPacingResponse = handleProviderKeyPacingRoutes(ctx);
901
+ if (keyPacingResponse) return keyPacingResponse;
913
902
 
914
903
  if (url.pathname === "/api/providers" && req.method === "GET") {
915
904
  return jsonResponse(Object.entries(config.providers).map(([name, p]) => ({
@@ -922,6 +911,7 @@ export async function handleProviderRoutes(ctx: ManagementContext): Promise<Resp
922
911
  requestPacing: p.requestPacing,
923
912
  models: p.models ?? [],
924
913
  contextWindow: p.contextWindow,
914
+ inferContextWindow: p.inferContextWindow,
925
915
  modelContextWindows: p.modelContextWindows,
926
916
  modelContextTiers: p.modelContextTiers,
927
917
  modelCapabilities: p.modelCapabilities,
@@ -1073,6 +1063,7 @@ export async function handleProviderRoutes(ctx: ManagementContext): Promise<Resp
1073
1063
  if (resolvedError) return jsonResponse({ error: resolvedError, code: "invalid_provider_destination" }, 400);
1074
1064
  }
1075
1065
 
1066
+ let removedCredentials: string[] = [];
1076
1067
  const outcome = mutatePersistedConfig<ProviderEditorMutationValue>(persisted => {
1077
1068
  if (!isDeepStrictEqual(providerEditorConfigDTO(persisted), baselineResult.value)) {
1078
1069
  return {
@@ -1095,6 +1086,7 @@ export async function handleProviderRoutes(ctx: ManagementContext): Promise<Resp
1095
1086
  initializeProviderModelSelection(name, provider, undefined, candidate.config);
1096
1087
  }
1097
1088
  }
1089
+ removedCredentials = Object.values(persisted.providers).flatMap(providerGcpCredentialMarkers);
1098
1090
  persisted.defaultProvider = candidate.config.defaultProvider;
1099
1091
  persisted.providers = structuredClone(candidate.config.providers);
1100
1092
  persisted.disabledModels = candidate.config.disabledModels;
@@ -1120,6 +1112,7 @@ export async function handleProviderRoutes(ctx: ManagementContext): Promise<Resp
1120
1112
  return jsonResponse({ error: outcome.value.error, code: outcome.value.code }, outcome.value.status);
1121
1113
  }
1122
1114
 
1115
+ cleanupRemovedGcpCredentials(removedCredentials);
1123
1116
  adoptProviderEditorCandidate(config, outcome.value.config);
1124
1117
  reconcileLiveStateStores();
1125
1118
  refreshConfigDerivedRegistries(outcome.value.config);
@@ -1137,16 +1130,15 @@ export async function handleProviderRoutes(ctx: ManagementContext): Promise<Resp
1137
1130
  return jsonResponse({ success: true, catalogRefresh });
1138
1131
  }
1139
1132
 
1140
- // Add (or overwrite) a single provider. Merges into the live in-memory config and
1141
- // persists — existing providers' real keys are never round-tripped (unlike PUT /api/config,
1142
- // which would re-save the masked keys from GET). Live routing picks it up immediately.
1133
+ // Provider POST merges directly; existing secrets never round-trip through masked DTOs.
1143
1134
  if (url.pathname === "/api/providers" && req.method === "POST") {
1144
1135
  let body: { name?: unknown; provider?: unknown; setDefault?: boolean };
1145
1136
  try { body = await readManagementJsonBody(req); } catch (error) { rethrowManagementBodyTooLarge(error); return jsonResponse({ error: "invalid JSON body" }, 400); }
1146
1137
  const name = typeof body.name === "string" ? body.name.trim() : "";
1147
1138
  if (!isPlainRecord(body.provider)) return jsonResponse({ error: "provider must be a plain object" }, 400);
1148
- // Same prohibition as PATCH: the canonical OpenAI row never carries these fields, and a clear
1149
- // form would otherwise be normalized away before the merged-row guard could see it.
1139
+ const credentialResponse = providerGcpCredentialInputResponse(body.provider);
1140
+ if (credentialResponse) return credentialResponse;
1141
+ // Reject canonical-row clears before normalization hides their ownership.
1150
1142
  if (name === "openai" && (Object.hasOwn(body.provider, "autoReviewModel") || Object.hasOwn(body.provider, "autoReviewModelOverrides"))) {
1151
1143
  return jsonResponse({ error: "provider openai must not include autoReviewModel or autoReviewModelOverrides" }, 400);
1152
1144
  }
@@ -1357,7 +1349,7 @@ export async function handleProviderRoutes(ctx: ManagementContext): Promise<Resp
1357
1349
  const candidate = stripRegistryOnlyStaticHeaders(name, prov);
1358
1350
  const previous = Object.getOwnPropertyDescriptor(config.providers, name);
1359
1351
  const rollback = pinsOwned ? captureConfigTopLevelRollback(config, ["defaultProvider", "modelDiscovery", "disabledModels"]) : undefined;
1360
- let validationError: string | undefined;
1352
+ let validationError: string | undefined, removedCredentials: string[] = [];
1361
1353
  withConfigMutationLockSync(() => {
1362
1354
  validationError = anthropicInstancePublicationError(name, candidate, config.providers[name]);
1363
1355
  if (validationError) return;
@@ -1365,6 +1357,12 @@ export async function handleProviderRoutes(ctx: ManagementContext): Promise<Resp
1365
1357
  if (submittedModelContextTiers && liveTiers) candidate.modelContextTiers = Object.assign(Object.create(null), liveTiers, candidate.modelContextTiers ?? {});
1366
1358
  else if (!submittedModelContextTiers && liveTiers) candidate.modelContextTiers = { ...liveTiers };
1367
1359
  else if (!submittedModelContextTiers) delete candidate.modelContextTiers;
1360
+ // Full forms omit the opt-in; preserve the latest value, including a concurrent clear.
1361
+ if (!Object.hasOwn(rawProvider, "inferContextWindow")) {
1362
+ const liveInference = config.providers[name]?.inferContextWindow;
1363
+ if (liveInference === undefined) delete candidate.inferContextWindow;
1364
+ else candidate.inferContextWindow = liveInference;
1365
+ }
1368
1366
  const draft = { ...(registrationDraft ?? config), providers: { ...config.providers, [name]: candidate }, ...(body.setDefault === true ? { defaultProvider: name } : {}) };
1369
1367
  const validation = validateConfigCandidate(draft); if (!validation.ok) { validationError = validation.error; return; }
1370
1368
  try {
@@ -1375,6 +1373,7 @@ export async function handleProviderRoutes(ctx: ManagementContext): Promise<Resp
1375
1373
  });
1376
1374
  }
1377
1375
  }
1376
+ removedCredentials = snapshotProviderGcpCredentialMarkers(name, config.providers[name]);
1378
1377
  config.providers[name] = candidate;
1379
1378
  if (body.setDefault === true) config.defaultProvider = name;
1380
1379
  (deps.saveConfigPreservingClaudeCode ?? save)(config);
@@ -1388,6 +1387,7 @@ export async function handleProviderRoutes(ctx: ManagementContext): Promise<Resp
1388
1387
  }
1389
1388
  });
1390
1389
  if (validationError !== undefined) return jsonResponse({ error: validationError }, 400);
1390
+ cleanupRemovedGcpCredentials(removedCredentials);
1391
1391
  reconcileLiveStateStores();
1392
1392
  if (prov.apiKey && prov.apiKeyPool) {
1393
1393
  const { addProviderApiKey } = await import("../../providers/api-keys");
@@ -1848,12 +1848,7 @@ export async function handleProviderRoutes(ctx: ManagementContext): Promise<Resp
1848
1848
  const { saveConfigPreservingClaudeCode: save } = await import("../../config");
1849
1849
  // Deleting still succeeds; the response names the shadow-call target left without a provider.
1850
1850
  const shadowDependency = shadowInterceptProviderDependency(config, name);
1851
- if (fallbackDefault) config.defaultProvider = fallbackDefault;
1852
- delete config.providers[name];
1853
- const { dropProviderCustomModels } = await import("../../providers/provider-id-rewrite");
1854
- const droppedCustomModels = dropProviderCustomModels(config, name);
1855
- forgetProviderContextCap(config, name);
1856
- save(config);
1851
+ const droppedCustomModels = removeProviderWithGcpCredentials(config, name, fallbackDefault, save);
1857
1852
  await replaceProviderAccountSet(name, null);
1858
1853
  reconcileLiveStateStores();
1859
1854
  const { clearModelCache: clearCache } = await import("../../codex/model-cache");
@@ -97,8 +97,12 @@ export const MANAGEMENT_ROUTES: readonly ManagementRoute[] = [
97
97
  // server/management-api
98
98
  { method: "POST", path: "/api/stop", module: "server/management-api", mutates: true },
99
99
  // codex/auth-api
100
+ { method: "GET", path: "/api/codex-auth/preserve-signed-in", module: "codex/auth-api/routes", mutates: false },
101
+ { method: "PUT", path: "/api/codex-auth/preserve-signed-in", module: "codex/auth-api/routes", mutates: true },
100
102
  { method: "DELETE", path: "/api/codex-auth/accounts", module: "codex/auth-api/routes", mutates: true },
101
103
  { method: "GET", path: "/api/codex-auth/accounts", module: "codex/auth-api/routes", mutates: false },
104
+ { method: "GET", path: "/api/codex-auth/accounts/use-remaining", module: "codex/auth-api/routes", mutates: false },
105
+ { method: "PUT", path: "/api/codex-auth/accounts/use-remaining", module: "codex/auth-api/routes", mutates: true },
102
106
  { method: "GET", path: "/api/codex-auth/active", module: "codex/auth-api/routes", mutates: false },
103
107
  { method: "GET", path: "/api/codex-auth/login-status", module: "codex/auth-api/routes", mutates: false },
104
108
  { method: "GET", path: "/api/codex-auth/quota", module: "codex/auth-api/routes", mutates: false },
@@ -139,6 +143,8 @@ export const MANAGEMENT_ROUTES: readonly ManagementRoute[] = [
139
143
  { method: "POST", path: "/api/native-main-profiles/switch", module: "codex/native-profile-api", mutates: true },
140
144
  // server/management/agent-settings-routes
141
145
  { method: "GET", path: "/api/claude-code", module: "server/management/agent-settings-routes", mutates: false },
146
+ { method: "GET", path: "/api/claude-code/model-defaults", module: "server/management/agent-settings-routes", mutates: false, exempt: { reason: "interactive-preview", why: "Preview half of the GUI-only Claude Code tier-default apply; the fingerprint it returns is the only input POST accepts, and no terminal confirmation workflow exists yet." } },
147
+ { method: "POST", path: "/api/claude-code/model-defaults", module: "server/management/agent-settings-routes", mutates: true, exempt: { reason: "interactive-preview", why: "Apply half of the GUI-only Claude Code tier-default preview; it writes the shared Claude settings only for a fingerprint the dashboard preview produced." } },
142
148
  { method: "GET", path: "/api/claude-desktop", module: "server/management/agent-settings-routes", mutates: false },
143
149
  { method: "GET", path: "/api/claude-desktop/status", module: "server/management/agent-settings-routes", mutates: false },
144
150
  { method: "GET", path: "/api/codex-auth/features/default-mode-request-user-input", module: "server/management/agent-settings-routes", mutates: false },
@@ -163,6 +169,12 @@ export const MANAGEMENT_ROUTES: readonly ManagementRoute[] = [
163
169
  // server/management/claude-desktop-picker-routes
164
170
  { method: "GET", path: "/api/claude-desktop/picker", module: "server/management/claude-desktop-picker-routes", mutates: false },
165
171
  { method: "PUT", path: "/api/claude-desktop/picker", module: "server/management/claude-desktop-picker-routes", mutates: true },
172
+ { method: "GET", path: "/api/codex/desktop-compatibility/certificate", module: "server/management/desktop-compatibility-routes", mutates: false, mechanism: "path-constant", exempt: { reason: "deferred-verb", owner: "codex-desktop-compatibility", ownerDoc: "structure/clients/codex-desktop.md", why: "Certificate status is available over authenticated HTTP while the desktop compatibility runtime/CLI status contract is integrated." } },
173
+ { method: "POST", path: "/api/codex/desktop-compatibility/certificate", module: "server/management/desktop-compatibility-routes", mutates: true, mechanism: "path-constant", exempt: { reason: "session-only", why: "Certificate setup requires a confirmed local dashboard session; raw admin tokens cannot enroll or remove OS trust." } },
174
+ { method: "GET", path: "/api/codex/desktop-compatibility/runtime", module: "server/management/desktop-compatibility-runtime-routes", mutates: false, mechanism: "path-constant", exempt: { reason: "deferred-verb", owner: "codex-desktop-compatibility", ownerDoc: "structure/clients/codex-desktop.md", why: "Experimental runtime status is authenticated HTTP while the native compatibility UI and CLI contract are integrated." } },
175
+ { method: "POST", path: "/api/codex/desktop-compatibility/runtime", module: "server/management/desktop-compatibility-runtime-routes", mutates: true, mechanism: "path-constant", exempt: { reason: "session-only", why: "Native app launch and account-wide UI trial require explicit local dashboard confirmation." } },
176
+ { method: "GET", path: "/api/codex/desktop-compatibility/settings", module: "server/management/desktop-compatibility-settings-routes", mutates: false, mechanism: "path-constant", exempt: { reason: "deferred-verb", owner: "codex-desktop-compatibility", ownerDoc: "structure/clients/codex-desktop.md", why: "The persisted startup preference is currently owned by the local desktop compatibility panel." } },
177
+ { method: "POST", path: "/api/codex/desktop-compatibility/settings", module: "server/management/desktop-compatibility-settings-routes", mutates: true, mechanism: "path-constant", exempt: { reason: "session-only", why: "Saved native observation intent requires an explicit local GUI action and fresh field revision." } },
166
178
  { method: "PUT", path: "/api/codex-auth/features/default-mode-request-user-input", module: "server/management/agent-settings-routes", mutates: true },
167
179
  { method: "PUT", path: "/api/effort-caps", module: "server/management/agent-settings-routes", mutates: true },
168
180
  { method: "PUT", path: "/api/grok/selection", module: "server/management/agent-settings-routes", mutates: true },
@@ -209,8 +221,11 @@ export const MANAGEMENT_ROUTES: readonly ManagementRoute[] = [
209
221
  { method: "POST", path: "/api/combos/decision-test", module: "server/management/decision-routes", mutates: true },
210
222
  // server/management/config-routes
211
223
  { method: "GET", path: "/api/config", module: "server/management/config-routes", mutates: false },
224
+ { method: "GET", path: "/api/auto-review-settings", module: "server/management/config-routes", mutates: false },
212
225
  { method: "GET", path: "/api/diagnostics/project-config", module: "server/management/config-routes", mutates: false },
213
226
  { method: "GET", path: "/api/settings", module: "server/management/config-routes", mutates: false },
227
+ { method: "GET", path: "/api/native-reasoning-retention", module: "server/management/native-reasoning-retention-routes", mutates: false, exempt: { reason: "local-transport", why: "The CLI reads the same nativeReasoningRetention policy through ocx config get; no separate HTTP-specific settings verb is required." } },
228
+ { method: "PUT", path: "/api/native-reasoning-retention", module: "server/management/native-reasoning-retention-routes", mutates: true, exempt: { reason: "deferred-verb", why: "A dedicated live CLI verb for this policy is deferred to native-reasoning-retention-live-cli; ocx config set/unset currently edits the same block on disk without live convergence.", owner: "native-reasoning-retention-live-cli", ownerDoc: "structure/transports/native-reasoning-retention.md" } },
214
229
  { method: "GET", path: "/api/shadow-call-settings", module: "server/management/config-routes", mutates: false },
215
230
  { method: "GET", path: "/api/sidecar-settings", module: "server/management/config-routes", mutates: false },
216
231
  { method: "GET", path: "/api/startup-health", module: "server/management/config-routes", mutates: false },
@@ -223,6 +238,7 @@ export const MANAGEMENT_ROUTES: readonly ManagementRoute[] = [
223
238
  { method: "POST", path: "/api/windows-tray", module: "server/management/config-routes", mutates: true },
224
239
  { method: "PUT", path: "/api/config", module: "server/management/config-routes", mutates: true, exempt: { reason: "disabled", why: "Returns 405 by design; provider changes go through POST /api/providers." } },
225
240
  { method: "PUT", path: "/api/settings", module: "server/management/config-routes", mutates: true },
241
+ { method: "PUT", path: "/api/auto-review-settings", module: "server/management/config-routes", mutates: true },
226
242
  { method: "PUT", path: "/api/shadow-call-settings", module: "server/management/config-routes", mutates: true },
227
243
  { method: "PUT", path: "/api/sidecar-settings", module: "server/management/config-routes", mutates: true },
228
244
  // server/management/integration-routes
@@ -267,6 +283,10 @@ export const MANAGEMENT_ROUTES: readonly ManagementRoute[] = [
267
283
  { method: "GET", path: "/api/usage", module: "server/management/logs-usage-routes", mutates: false },
268
284
  // server/management/usage-timeline-routes
269
285
  { method: "GET", path: "/api/usage/timeline", module: "server/management/usage-timeline-routes", mutates: false },
286
+ // server/management/advisor-routes
287
+ { method: "GET", path: "/api/advisor/settings", module: "server/management/advisor-routes", mutates: false },
288
+ { method: "GET", path: "/api/advisor/activity", module: "server/management/advisor-routes", mutates: false },
289
+ { method: "PUT", path: "/api/advisor/settings", module: "server/management/advisor-routes", mutates: true },
270
290
  // server/management/companion-routes
271
291
  { method: "POST", path: "/api/companion/open-in-browser", module: "server/management/companion-routes", mutates: true, exempt: { reason: "browser-navigation", why: "Opens the companion's current view in the system browser under normal management admission; the CLI reads the underlying settings and usage directly." } },
272
292
  { method: "GET", path: "/api/companion/settings", module: "server/management/companion-routes", mutates: false },
@@ -349,7 +369,7 @@ export const MANAGEMENT_ROUTES: readonly ManagementRoute[] = [
349
369
  { method: "GET", path: "/api/provider-context-caps", module: "server/management/provider-routes", mutates: false },
350
370
  { method: "GET", path: "/api/provider-presets", module: "server/management/provider-routes", mutates: false },
351
371
  { method: "GET", path: "/api/provider-quotas", module: "server/management/provider-routes", mutates: false },
352
- { method: "GET", path: "/api/provider-request-pacing", module: "server/management/provider-routes", mutates: false },
372
+ { method: "GET", path: "/api/provider-request-pacing", module: "server/management/provider-key-pacing-routes", mutates: false },
353
373
  { method: "GET", path: "/api/providers", module: "server/management/provider-routes", mutates: false },
354
374
  { method: "PATCH", path: "/api/providers", module: "server/management/provider-routes", mutates: true },
355
375
  { method: "POST", path: "/api/providers", module: "server/management/provider-routes", mutates: true },
@@ -30,6 +30,7 @@ export const SIBLING_REFUSED_MANAGEMENT_PATHS: readonly { readonly path: string;
30
30
  { path: "/api/client-integrations", children: true },
31
31
  { path: "/api/native-integrations", children: true },
32
32
  { path: "/api/claude-desktop", children: true },
33
+ { path: "/api/codex/desktop-compatibility", children: true },
33
34
  { path: "/api/claude-code", children: false },
34
35
  { path: "/api/grok/apply", children: false },
35
36
  { path: "/api/grok/selection", children: false },
@@ -59,6 +59,7 @@ import { applySystemEnvToggle } from "./system-env";
59
59
 
60
60
  import type { ManagementApiDeps } from "./management/context";
61
61
  import { handleConfigRoutes } from "./management/config-routes";
62
+ import { handleNativeReasoningRetentionRoutes } from "./management/native-reasoning-retention-routes";
62
63
  import { handleLogsUsageRoutes } from "./management/logs-usage-routes";
63
64
  import { handleStorageLogGuardRoutes } from "./management/storage-log-guard-routes";
64
65
  import { handleRequestHistoryRoutes } from "./management/request-history-routes";
@@ -79,6 +80,9 @@ import { handleCodexPromptRoutes } from "./management/codex-prompt-routes";
79
80
  import { handleIntegrationRoutes } from "./management/integration-routes";
80
81
  import { handleNativeIntegrationRoutes } from "./management/native-integration-routes";
81
82
  import { handleClaudeDesktopPickerRoutes } from "./management/claude-desktop-picker-routes";
83
+ import { handleDesktopCompatibilityRoutes } from "./management/desktop-compatibility-routes";
84
+ import { handleDesktopCompatibilityRuntimeRoutes } from "./management/desktop-compatibility-runtime-routes";
85
+ import { handleDesktopCompatibilitySettingsRoutes } from "./management/desktop-compatibility-settings-routes";
82
86
  import { handleCursorIntegrationRoutes } from "./management/cursor-integration-routes";
83
87
  import type { ManagementContext } from "./management/context";
84
88
  import type { ManagementPrincipal, ManagementSessionControl } from "./management-auth";
@@ -341,6 +345,7 @@ export async function handleManagementAPI(
341
345
  ?? (await handleLinkRoutesOnDemand(ctx))
342
346
  ?? (await handleRemoteWorkspaceRoutesOnDemand(ctx))
343
347
  ?? (await handleConfigRoutes(ctx))
348
+ ?? (await handleNativeReasoningRetentionRoutes(ctx))
344
349
  ?? (await handleStorageLogGuardRoutes(ctx))
345
350
  ?? (await handleLogsUsageRoutes(ctx))
346
351
  ?? (await handleRequestHistoryRoutes(ctx))
@@ -360,6 +365,9 @@ export async function handleManagementAPI(
360
365
  ?? (await handleNativeIntegrationRoutes(ctx))
361
366
  ?? (await handleCursorIntegrationRoutes(ctx))
362
367
  ?? (await handleClaudeDesktopPickerRoutes(ctx))
368
+ ?? (await handleDesktopCompatibilityRoutes(ctx))
369
+ ?? (await handleDesktopCompatibilityRuntimeRoutes(ctx))
370
+ ?? (await handleDesktopCompatibilitySettingsRoutes(ctx))
363
371
  ?? (await handleAgentSettingsRoutes(ctx))
364
372
  ?? (await handleCodexPromptRoutes(ctx))
365
373
  ?? (await handleOauthAccountRoutes(ctx))
@@ -513,7 +521,7 @@ export async function handleManagementAPI(
513
521
  const { handleMainDeviceReauthAPI } = await import("../codex/main-device-reauth-api");
514
522
  return handleMainDeviceReauthAPI(req, url, config);
515
523
  }
516
- const { handleCodexAuthAPI } = await import("../codex/auth-api");
524
+ const { handleCodexAuthAPI } = await import("../codex/auth-api/routes");
517
525
  const { ConfigMutationLockError } = await import("../config");
518
526
  const { CodexCredentialRefreshLockTimeoutError } = await import("../codex/account-store");
519
527
  try {