@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
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Indexed request-history reads: page the derived ledger, or fetch one canonical row.
3
+ *
4
+ * Distinct from `ocx logs` (the recent ring) and `ocx logs explain` (route-decision).
5
+ */
6
+ import { REQUEST_HISTORY_DEFAULT_PAGE_SIZE, REQUEST_HISTORY_MAX_PAGE_SIZE } from "../routing/history/indexer";
7
+ import { parseUsageTimeWindow } from "../usage/time-range";
8
+ import {
9
+ CliUsageError,
10
+ printData,
11
+ rejectArgs,
12
+ runtimeRequest,
13
+ takeFlag,
14
+ takeIntegerOption,
15
+ takeOption,
16
+ type RuntimeApiDeps,
17
+ } from "./runtime-api";
18
+
19
+ type LogRow = Record<string, unknown>;
20
+
21
+ export const LOG_HISTORY_USAGE = `Usage:
22
+ ocx logs history [--provider <name>] [--model <id>] [--requested-model <id>]
23
+ [--status <code>] [--conversation <id>] [--surface <name>] [--protocol <responses|chat|messages>]
24
+ [--api-key-id <id>] [--profile <id>] [--fallback <true|false>]
25
+ [--from <epoch-ms|ISO-datetime>] [--to <epoch-ms|ISO-datetime>]
26
+ [--cursor <token>] [--limit <1-${REQUEST_HISTORY_MAX_PAGE_SIZE}>] [--json|--jsonl]
27
+ ocx logs get <request-id> [--json]`;
28
+
29
+ const GET_USAGE = "Usage: ocx logs get <request-id> [--json]";
30
+ const PROTOCOLS = ["responses", "chat", "messages"] as const;
31
+
32
+ function query(params: Record<string, string | number | boolean | undefined>): string {
33
+ const search = new URLSearchParams();
34
+ for (const [key, value] of Object.entries(params)) {
35
+ if (value !== undefined) search.set(key, String(value));
36
+ }
37
+ const encoded = search.toString();
38
+ return encoded ? `?${encoded}` : "";
39
+ }
40
+
41
+ function timestampOption(args: string[], flag: string): number | undefined {
42
+ const raw = takeOption(args, flag);
43
+ if (raw === undefined) return undefined;
44
+ try {
45
+ return parseUsageTimeWindow(raw, raw)!.since;
46
+ } catch (error) {
47
+ throw new CliUsageError(error instanceof Error ? `${flag}: ${error.message}` : `${flag} is invalid`, LOG_HISTORY_USAGE);
48
+ }
49
+ }
50
+
51
+ function record(value: unknown): value is Record<string, unknown> {
52
+ return value !== null && typeof value === "object" && !Array.isArray(value);
53
+ }
54
+
55
+ function formatCost(row: Record<string, unknown>): string {
56
+ const metrics = record(row.displayMetrics) ? row.displayMetrics : undefined;
57
+ const cost = metrics && record(metrics.cost) ? metrics.cost : undefined;
58
+ if (!cost || cost.kind !== "value" || !record(cost.estimate) || !record(cost.estimate.cost)) return "";
59
+ const total = cost.estimate.cost.total;
60
+ return typeof total === "number" && Number.isFinite(total) ? `~$${total.toFixed(4)}` : "";
61
+ }
62
+
63
+ function formatHistoryRow(row: LogRow, formatRow: (row: LogRow) => string): string {
64
+ const tokens = typeof row.totalTokens === "number" && Number.isFinite(row.totalTokens)
65
+ ? `${row.totalTokens}tok`
66
+ : "";
67
+ return [formatRow(row), tokens, formatCost(row)].filter(Boolean).join(" ");
68
+ }
69
+
70
+ function historyPage(raw: unknown): {
71
+ entries: Record<string, unknown>[];
72
+ nextCursor?: string;
73
+ hasMore: boolean;
74
+ index?: Record<string, unknown>;
75
+ } {
76
+ if (!record(raw) || !Array.isArray(raw.entries) || typeof raw.hasMore !== "boolean") {
77
+ throw new Error("Invalid request-history page. Upgrade the proxy and retry.");
78
+ }
79
+ const entries = raw.entries;
80
+ if (!entries.every(record)) throw new Error("Invalid request-history page. Upgrade the proxy and retry.");
81
+ const nextCursor = typeof raw.nextCursor === "string" && raw.nextCursor.length > 0 ? raw.nextCursor : undefined;
82
+ const index = record(raw.index) ? raw.index : undefined;
83
+ return { entries, nextCursor, hasMore: raw.hasMore, index };
84
+ }
85
+
86
+ /** Page the derived request-history index through GET /api/request-history. */
87
+ export async function handleLogHistoryCommand(
88
+ argv: string[],
89
+ deps: RuntimeApiDeps,
90
+ formatRow: (row: LogRow) => string,
91
+ ): Promise<void> {
92
+ const args = [...argv];
93
+ const wantsJson = takeFlag(args, "--json");
94
+ const wantsJsonl = takeFlag(args, "--jsonl");
95
+ const provider = takeOption(args, "--provider");
96
+ const model = takeOption(args, "--model");
97
+ const requestedModel = takeOption(args, "--requested-model");
98
+ const conversationId = takeOption(args, "--conversation") ?? takeOption(args, "--conversationId");
99
+ const surface = takeOption(args, "--surface");
100
+ const protocol = takeOption(args, "--protocol");
101
+ const apiKeyId = takeOption(args, "--api-key-id");
102
+ const profileId = takeOption(args, "--profile");
103
+ const fallbackRaw = takeOption(args, "--fallback");
104
+ const cursor = takeOption(args, "--cursor");
105
+ const status = takeIntegerOption(args, "--status", { min: 100 });
106
+ const limit = takeIntegerOption(args, "--limit", { min: 1 }) ?? REQUEST_HISTORY_DEFAULT_PAGE_SIZE;
107
+ const from = timestampOption(args, "--from");
108
+ const to = timestampOption(args, "--to");
109
+ rejectArgs(args, LOG_HISTORY_USAGE);
110
+ if (wantsJson && wantsJsonl) throw new CliUsageError("--json and --jsonl cannot be combined", LOG_HISTORY_USAGE);
111
+ if (status !== undefined && status > 599) throw new CliUsageError("--status must be an integer from 100 to 599", LOG_HISTORY_USAGE);
112
+ if (limit > REQUEST_HISTORY_MAX_PAGE_SIZE) {
113
+ throw new CliUsageError(`--limit must be between 1 and ${REQUEST_HISTORY_MAX_PAGE_SIZE}`, LOG_HISTORY_USAGE);
114
+ }
115
+ if (protocol !== undefined && !PROTOCOLS.includes(protocol as (typeof PROTOCOLS)[number])) {
116
+ throw new CliUsageError(`--protocol must be one of ${PROTOCOLS.join(", ")}`, LOG_HISTORY_USAGE);
117
+ }
118
+ let fallback: boolean | undefined;
119
+ if (fallbackRaw !== undefined) {
120
+ if (fallbackRaw !== "true" && fallbackRaw !== "false") {
121
+ throw new CliUsageError("--fallback must be true or false", LOG_HISTORY_USAGE);
122
+ }
123
+ fallback = fallbackRaw === "true";
124
+ }
125
+ if (from !== undefined && to !== undefined && from > to) {
126
+ throw new CliUsageError("--from must not be after --to", LOG_HISTORY_USAGE);
127
+ }
128
+ const data = await runtimeRequest(`/api/request-history${query({
129
+ provider, model, requestedModel, status, conversationId, surface,
130
+ inboundProtocol: protocol, apiKeyId, profileId, fallback, from, to, cursor, limit,
131
+ })}`, {}, deps);
132
+ const page = historyPage(data);
133
+ if (wantsJson) {
134
+ printData(data, true);
135
+ return;
136
+ }
137
+ if (wantsJsonl) {
138
+ for (const row of page.entries) console.log(JSON.stringify(row));
139
+ if (page.hasMore && page.nextCursor) console.error(`nextCursor=${page.nextCursor}`);
140
+ return;
141
+ }
142
+ const indexed = typeof page.index?.indexedRows === "number" ? page.index.indexedRows : undefined;
143
+ if (page.entries.length === 0) {
144
+ printData(data, false, [
145
+ "No request-history row matched the filters.",
146
+ ...(indexed !== undefined ? [`indexedRows=${indexed}`] : []),
147
+ ]);
148
+ return;
149
+ }
150
+ const footer = [
151
+ ...(indexed !== undefined ? [`indexedRows=${indexed}`] : []),
152
+ `hasMore=${page.hasMore}`,
153
+ ...(page.nextCursor ? [`nextCursor=${page.nextCursor}`] : []),
154
+ ];
155
+ printData(data, false, [...page.entries.map(row => formatHistoryRow(row, formatRow)), ...footer]);
156
+ }
157
+
158
+ /** Read one canonical request-history row through GET /api/request-history/{id}. */
159
+ export async function handleLogGetCommand(
160
+ argv: string[],
161
+ deps: RuntimeApiDeps,
162
+ formatRow: (row: LogRow) => string,
163
+ ): Promise<void> {
164
+ const args = [...argv];
165
+ const requestId = args.shift();
166
+ const wantsJson = takeFlag(args, "--json");
167
+ if (!requestId) throw new CliUsageError("request id is required", GET_USAGE);
168
+ rejectArgs(args, GET_USAGE);
169
+ const result = await runtimeRequest(`/api/request-history/${encodeURIComponent(requestId)}`, {}, deps);
170
+ if (!record(result)) throw new Error("Invalid request-history row. Upgrade the proxy and retry.");
171
+ printData(result, wantsJson, wantsJson ? undefined : [formatHistoryRow(result, formatRow)]);
172
+ }
@@ -28,6 +28,7 @@ export const MODELS_RUNTIME_SUBCOMMANDS = [
28
28
  "new-arrivals",
29
29
  "context",
30
30
  "shadow",
31
+ "auto-review",
31
32
  "order",
32
33
  "display-name",
33
34
  ] as const;
@@ -21,7 +21,7 @@ import { redactSecretString } from "../lib/redact";
21
21
  import type { ProviderCostOverlay } from "../types";
22
22
  import { resolveMatchedPrice } from "../usage/cost";
23
23
  import { MAX_COST4_RATE } from "../usage/expected-prices";
24
- import { isValidCost4Rate } from "../usage/user-cost-overlays";
24
+ import { isValidCost4Rate, validCost4 } from "../usage/user-cost-overlays";
25
25
 
26
26
  const USAGE = `Usage:
27
27
  ocx models display-name <provider/raw-model> (--set <text> | --clear) [--json]
@@ -48,6 +48,7 @@ const USAGE = `Usage:
48
48
  ocx models new-arrivals [--json]
49
49
  ${MODELS_CONTEXT_USAGE}
50
50
  ocx models shadow <status|set> [model|-] [--enabled <on|off>] [--json]
51
+ ocx models auto-review <status|set> [model|-] [--enabled <on|off>] [--json]
51
52
 
52
53
  Prices are USD per 1M tokens. Omitted cache rates default to 0.
53
54
  Price selectors use the exact upstream model ID after the first slash.`;
@@ -89,8 +90,8 @@ function priceRecord(value: unknown): value is Record<string, unknown> {
89
90
  const PRICE_RATE_KEYS = ["input", "output", "cacheRead", "cacheWrite"] as const;
90
91
 
91
92
  function validPriceCost(value: unknown): value is ProviderCostOverlay {
92
- return priceRecord(value) && Object.keys(value).length === PRICE_RATE_KEYS.length
93
- && PRICE_RATE_KEYS.every(key => Object.hasOwn(value, key) && isValidCost4Rate(value[key]));
93
+ return priceRecord(value) && validCost4(value)
94
+ && Object.keys(value).every(key => key === "promptLengthPricing" || (PRICE_RATE_KEYS as readonly string[]).includes(key));
94
95
  }
95
96
 
96
97
  async function price(write: boolean, argv: string[], deps: RuntimeApiDeps): Promise<void> {
@@ -135,7 +136,9 @@ async function priceRequest(write: boolean, argv: string[], deps: RuntimeApiDeps
135
136
  }
136
137
  // The API map owns manual overrides; bundled defaults remain derived rather
137
138
  // than being persisted as overrides that would mask later catalog updates.
138
- const effectiveCost = cost ?? resolveMatchedPrice(provider, modelId, undefined, [])?.cost4 ?? null;
139
+ const effectiveCost = cost
140
+ ? { input: cost.input, output: cost.output, cacheRead: cost.cacheRead, cacheWrite: cost.cacheWrite }
141
+ : resolveMatchedPrice(provider, modelId, undefined, [])?.cost4 ?? null;
139
142
  printData({ provider, modelId, cost, effectiveCost }, wantsJson, [
140
143
  effectiveCost === null ? `${selector}: automatic pricing (unknown)`
141
144
  : `${selector}: ${JSON.stringify(effectiveCost)} USD per 1M tokens${cost === null ? " (automatic estimate)" : ""}`,
@@ -161,17 +164,42 @@ async function priceRequest(write: boolean, argv: string[], deps: RuntimeApiDeps
161
164
  }
162
165
  return value;
163
166
  };
164
- const cost: ProviderCostOverlay | null = auto ? null : {
167
+ // Validate every rate before any request, so a bad flag never reaches the management plane.
168
+ const rates: ProviderCostOverlay | undefined = auto ? undefined : {
165
169
  input: rate(input!, "--input"),
166
170
  output: rate(output!, "--output"),
167
171
  cacheRead: rate(cacheRead ?? "0", "--cache-read"),
168
172
  cacheWrite: rate(cacheWrite ?? "0", "--cache-write"),
169
173
  };
174
+ // A base-rate write replaces the whole row, so read the current row first and carry the
175
+ // stored prompt-length policy for exactly this model forward instead of silently deleting it.
176
+ let carriedPromptLengthPricing: ProviderCostOverlay["promptLengthPricing"];
177
+ if (rates) {
178
+ const current = await runtimeRequest<unknown>(path, {}, deps);
179
+ if (!priceRecord(current) || current.provider !== provider || !priceRecord(current.modelCosts)
180
+ || !Object.values(current.modelCosts).every(validPriceCost)) {
181
+ throw new Error("Invalid model price response");
182
+ }
183
+ if (Object.hasOwn(current.modelCosts, modelId)) {
184
+ carriedPromptLengthPricing = (current.modelCosts[modelId] as ProviderCostOverlay).promptLengthPricing;
185
+ }
186
+ }
187
+ const cost: ProviderCostOverlay | null = rates
188
+ ? { ...rates, ...(carriedPromptLengthPricing ? { promptLengthPricing: carriedPromptLengthPricing } : {}) }
189
+ : null;
170
190
  const result = await runtimeRequest(path, { method: "PUT", body: JSON.stringify({ modelId, cost }) }, deps);
191
+ // Absent and { mode: "automatic" } are the same policy (the server stores automatic as
192
+ // absent), and key order carries no meaning in a JSON receipt, so compare canonically.
193
+ const canonicalPolicy = (policy: ProviderCostOverlay["promptLengthPricing"]): string =>
194
+ policy === undefined || policy.mode === "automatic" ? `{"mode":"automatic"}`
195
+ : JSON.stringify(policy, (_key, item: unknown) => (item && typeof item === "object" && !Array.isArray(item)
196
+ ? Object.fromEntries(Object.entries(item as Record<string, unknown>).sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)))
197
+ : item));
171
198
  const receivedCost = priceRecord(result) ? result.cost : undefined;
172
199
  if (!priceRecord(result) || result.ok !== true || result.provider !== provider || result.modelId !== modelId
173
200
  || (cost === null ? receivedCost !== null : !validPriceCost(receivedCost)
174
- || !PRICE_RATE_KEYS.every(key => receivedCost[key] === cost[key]))) {
201
+ || !PRICE_RATE_KEYS.every(key => receivedCost[key] === cost[key])
202
+ || canonicalPolicy(receivedCost.promptLengthPricing) !== canonicalPolicy(cost.promptLengthPricing))) {
175
203
  throw new Error("Invalid model price persistence receipt");
176
204
  }
177
205
  // Project the acknowledged fields only; unrelated response fields are not CLI output.
@@ -566,6 +594,39 @@ async function shadow(argv: string[], deps: RuntimeApiDeps): Promise<void> {
566
594
  printData(result, wantsJson, ["Shadow-call settings updated."]);
567
595
  }
568
596
 
597
+ async function autoReview(argv: string[], deps: RuntimeApiDeps): Promise<number | void> {
598
+ const args = [...argv];
599
+ const action = (args.shift() ?? "status").toLowerCase();
600
+ const wantsJson = takeFlag(args, "--json");
601
+ if (action === "status") {
602
+ rejectArgs(args, USAGE);
603
+ const result = await runtimeRequest("/api/auto-review-settings", {}, deps);
604
+ printData(result, wantsJson);
605
+ return;
606
+ }
607
+ if (action !== "set") throw new CliUsageError("unknown auto-review action " + action, USAGE);
608
+ const modelRaw = args[0] && !args[0].startsWith("--") ? args.shift() : undefined;
609
+ const enabled = takeBooleanOption(args, "--enabled");
610
+ rejectArgs(args, USAGE);
611
+ const body: Record<string, unknown> = {};
612
+ if (modelRaw !== undefined) body.model = modelRaw === "-" ? "" : modelRaw;
613
+ if (enabled !== undefined) body.enabled = enabled;
614
+ if (Object.keys(body).length === 0) throw new CliUsageError("model and/or --enabled is required", USAGE);
615
+ const result = await runtimeRequest<{ catalogRefresh?: { status?: string; retryable?: boolean } }>(
616
+ "/api/auto-review-settings", { method: "PUT", body: JSON.stringify(body) }, deps,
617
+ );
618
+ const refresh = result.catalogRefresh;
619
+ printData(result, wantsJson, [
620
+ "Auto-review settings updated.",
621
+ ...(refresh?.status === "failed"
622
+ ? ["Settings saved, but the Codex model catalog refresh failed. Resolve the refresh issue before running ocx sync."]
623
+ : refresh?.status === "skipped" && refresh.retryable === true
624
+ ? ["Settings saved, but the Codex model catalog refresh is pending. Run ocx sync to retry."]
625
+ : []),
626
+ ]);
627
+ if (refresh?.status === "failed") return 1;
628
+ }
629
+
569
630
  export async function handleModelsRuntimeCommand(sub: string, argv: string[], deps: RuntimeApiDeps = {}): Promise<number | null> {
570
631
  if (sub === "order" || sub === "display-name") {
571
632
  const { handleModelsOrderCommand, handleModelsDisplayNameCommand } = await import("./models-order");
@@ -574,7 +635,7 @@ export async function handleModelsRuntimeCommand(sub: string, argv: string[], de
574
635
  // The dispatch below and MODELS_RUNTIME_SUBCOMMANDS must name the same set;
575
636
  // tests/cli/cli-models-runtime-dispatch.test.ts fails if they drift (#3094).
576
637
  if (!isModelsRuntimeSubcommand(sub)) return null;
577
- let action: (() => Promise<void>) | undefined;
638
+ let action: (() => Promise<number | void>) | undefined;
578
639
  if (sub === "live") action = () => live(argv, deps);
579
640
  else if (sub === "price") action = () => price(false, argv, deps);
580
641
  else if (sub === "set-price") action = () => price(true, argv, deps);
@@ -589,8 +650,11 @@ export async function handleModelsRuntimeCommand(sub: string, argv: string[], de
589
650
  else if (sub === "new-arrivals") action = () => newArrivals(argv, deps);
590
651
  else if (sub === "context") action = () => context(argv, deps);
591
652
  else if (sub === "shadow") action = () => shadow(argv, deps);
653
+ else if (sub === "auto-review") action = () => autoReview(argv, deps);
592
654
  if (!action) return null;
593
- return runCliAction(action);
655
+ let outcome: number | void = 0;
656
+ const exit = await runCliAction(async () => { outcome = await action(); });
657
+ return exit || outcome || 0;
594
658
  }
595
659
 
596
660
  export const MODELS_RUNTIME_USAGE = USAGE;
@@ -14,6 +14,8 @@ export interface ObserveStreamDeps extends RuntimeApiDeps {
14
14
  /** Reduced timings for isolated tests only; never command-line options. */
15
15
  pollIntervalMs?: number;
16
16
  requestTimeoutMs?: number;
17
+ /** Frozen clock for usage-compare tests; never a command-line option. */
18
+ now?: () => number;
17
19
  }
18
20
 
19
21
  export class ObservationError extends Error {}
@@ -14,9 +14,11 @@ import {
14
14
  } from "./runtime-api";
15
15
  import { followLogs } from "./log-follow";
16
16
  import { handleLogFilterCommand } from "./log-view-filter";
17
+ import { handleLogGetCommand, handleLogHistoryCommand } from "./log-history";
17
18
  import { followInjection } from "./injection-follow";
18
19
  import type { ObserveStreamDeps } from "./observe-stream";
19
20
  import { formatUsageReport } from "./usage-report";
21
+ import { handleUsageCompareCommand } from "./usage-compare";
20
22
  import { selectUsageModelView, takeUsageSearchOption } from "./usage-model-search";
21
23
  import { USAGE_RANGES, USAGE_SURFACES, type UsageSummary, type UsageFilterEcho } from "../usage/summary";
22
24
  import { parseUsageTimeWindow, type UsageTimeWindow } from "../usage/time-range";
@@ -30,12 +32,16 @@ const USAGE = `Usage:
30
32
  ocx observe logs [--provider <name>] [--model <id>] [--status <code>]
31
33
  [--conversation <id>] [--account <label>] [--limit <n>] [--follow] [--json|--jsonl] [--events]
32
34
  ocx logs explain <request-id> [--json]
35
+ ocx logs history [selectors] [--cursor <token>] [--limit <1-100>] [--json|--jsonl]
36
+ ocx logs get <request-id> [--json]
33
37
  ocx logs filter [selectors] [--scan-limit <1..2000>] [--limit <1..2000>] [--json|--jsonl]
34
38
  ocx logs rebuild-index
35
39
  ocx logs index-status
36
40
  ocx observe usage [--range <today|1d|7d|30d|all>] [--surface <all|codex|claude|grok>]
37
41
  [--since <epoch-ms|ISO-datetime>] [--until <epoch-ms|ISO-datetime>]
38
- [--provider <name>] [--model <id>] [--api-key-id <id>] [--search <text>] [--json]
42
+ [--provider <name>] [--model <id>] [--api-key-id <id>] [--search <text>] [--top <1-1000>] [--json]
43
+ ocx usage compare [--range <today|1d|7d|30d>] [--surface <all|codex|claude|grok>]
44
+ [--provider <name>] [--model <id>] [--api-key-id <id>] [--json]
39
45
  ocx observe storage [codex-logs [status|protect|unprotect|repair|compact] [--mode <compat|quiet>]] [--json]
40
46
  ocx observe memory [--json]
41
47
  ocx observe debug [--json]
@@ -174,6 +180,7 @@ async function indexStatus(argv: string[], deps: RuntimeApiDeps): Promise<void>
174
180
  async function usage(argv: string[], deps: RuntimeApiDeps): Promise<void> {
175
181
  const args = [...argv];
176
182
  const search = takeUsageSearchOption(args);
183
+ const top = takeIntegerOption(args, "--top", { min: 1, max: 1000 });
177
184
  const wantsJson = takeFlag(args, "--json");
178
185
  const range = takeOption(args, "--range") ?? "30d";
179
186
  const surface = takeOption(args, "--surface") ?? "all";
@@ -246,10 +253,10 @@ async function usage(argv: string[], deps: RuntimeApiDeps): Promise<void> {
246
253
  // the call, so passing formatUsageReport(...) inline would run the human
247
254
  // renderer during --json and let its assumptions affect a path that is meant
248
255
  // to bypass it entirely.
249
- const view = search === undefined ? undefined : selectUsageModelView(result, search);
256
+ const view = search === undefined ? undefined : selectUsageModelView(result, search, wantsJson ? undefined : top);
250
257
  const displayed = view ?? result;
251
258
  if (wantsJson) printData(displayed, true);
252
- else printData(displayed, false, formatUsageReport(displayed as Parameters<typeof formatUsageReport>[0], view ? { modelView: view.modelView } : undefined));
259
+ else printData(displayed, false, formatUsageReport(displayed as Parameters<typeof formatUsageReport>[0], { modelView: view?.modelView, modelRowLimit: top }));
253
260
  }
254
261
 
255
262
  async function simple(path: string, argv: string[], deps: RuntimeApiDeps): Promise<void> {
@@ -320,12 +327,17 @@ export async function handleObserveCommand(argv: string[], deps: ObserveStreamDe
320
327
  if (sub === "logs") {
321
328
  const action = rest[0];
322
329
  if (action === "filter") streamExit = await handleLogFilterCommand(rest.slice(1), deps, formatLog);
330
+ else if (action === "history") await handleLogHistoryCommand(rest.slice(1), deps, formatLog);
331
+ else if (action === "get") await handleLogGetCommand(rest.slice(1), deps, formatLog);
323
332
  else if (action === "explain") await explain(rest.slice(1), deps);
324
333
  else if (action === "rebuild-index") await rebuildIndex(rest.slice(1), deps);
325
334
  else if (action === "index-status") await indexStatus(rest.slice(1), deps);
326
335
  else streamExit = await logs(rest, deps);
327
336
  }
328
- else if (sub === "usage") await usage(rest, deps);
337
+ else if (sub === "usage") {
338
+ if (rest[0] === "compare") await handleUsageCompareCommand(rest.slice(1), deps);
339
+ else await usage(rest, deps);
340
+ }
329
341
  else if (sub === "storage") await storage(rest, deps);
330
342
  else if (sub === "memory") await simple("/api/system/memory", rest, deps);
331
343
  else if (sub === "debug") await simple("/api/debug", rest, deps);
@@ -8,13 +8,15 @@
8
8
  * show <name> Show provider config details (secrets masked)
9
9
  * set-default <name> Change the default provider
10
10
  */
11
- import { hasOwnProvider, isValidProviderName, loadConfig, sanitizeModelCostsForDisplay, saveConfig, validateConfigCandidate, withConfigMutationLockSync } from "../config";
11
+ import { hasOwnProvider, isValidProviderName, loadConfig, readConfigAdmissionSnapshot, sanitizeModelCostsForDisplay, saveConfig, validateConfigCandidate, withConfigMutationLockSync } from "../config";
12
12
  import { apiKeyTransportConfigError, modelCapabilitiesConfigError, mergeModelCapabilities } from "../config/provider-validation";
13
13
  import { hasHelpFlag, printSubcommandUsage } from "./help";
14
14
  import { getProviderRegistryEntry, PROVIDER_REGISTRY } from "../providers/registry";
15
15
  import { providerConfigSeed } from "../providers/derive";
16
16
  import { assertAnthropicInstanceLoginConfig } from "../oauth/store-anthropic-instance";
17
17
  import { dropProviderCustomModels } from "../providers/provider-id-rewrite";
18
+ import { cleanupRemovedGcpCredentials, commitProviderGcpCredentialRemoval, providerGcpCredentialMarkers } from "../providers/gcp-credential-cleanup";
19
+ import { providerCredentialInputError } from "../providers/api-keys";
18
20
  import type { OcxProviderConfig } from "../types";
19
21
  import { findLiveProxy } from "../server/proxy-liveness";
20
22
  import { syncModelsToCodex } from "../codex/sync";
@@ -223,6 +225,12 @@ async function handleAdd(args: string[], deps: ProviderCommandDeps): Promise<voi
223
225
  if (registryEntry) {
224
226
  provConfig = providerConfigSeed(registryEntry);
225
227
  if (apiKey) {
228
+ const candidateError = providerCredentialInputError({ apiKey });
229
+ if (candidateError) {
230
+ console.error(`Error: ${candidateError}`);
231
+ process.exitCode = 2;
232
+ return;
233
+ }
226
234
  if ((authMode ?? registryEntry.authKind) === "forward") {
227
235
  console.warn(`Warning: provider "${name}" uses ChatGPT login (forward auth); --api-key is ignored.`);
228
236
  } else if ((authMode ?? registryEntry.authKind) === "oauth") {
@@ -249,6 +257,12 @@ async function handleAdd(args: string[], deps: ProviderCommandDeps): Promise<voi
249
257
  }
250
258
 
251
259
  if (responsesPath !== undefined) provConfig.responsesPath = responsesPath;
260
+ const credentialError = providerCredentialInputError(provConfig);
261
+ if (credentialError) {
262
+ console.error(`Error: ${credentialError}`);
263
+ process.exitCode = 2;
264
+ return;
265
+ }
252
266
  if (authMode !== undefined) provConfig.authMode = authMode as OcxProviderConfig["authMode"];
253
267
  if (name === "anthropic2") {
254
268
  if (provConfig.adapter !== "anthropic" || provConfig.authMode !== "oauth") delete provConfig.anthropicOAuthInstance;
@@ -328,12 +342,17 @@ async function handleAdd(args: string[], deps: ProviderCommandDeps): Promise<voi
328
342
  }
329
343
  const { initializeProviderModelSelection } = await import("../providers/initial-model-selection");
330
344
  let markerCollision = false;
345
+ let removedCredentials: string[] = [];
331
346
  withConfigMutationLockSync(() => {
332
347
  if (provConfig.anthropicOAuthInstance) {
333
348
  try { assertAnthropicInstanceLoginConfig(config, name); }
334
349
  catch { markerCollision = true; return; }
335
350
  }
336
351
  initializeProviderModelSelection(name, provConfig, existingProvider, config);
352
+ const durable = readConfigAdmissionSnapshot();
353
+ const durableProvider = durable.kind === "read" && durable.diagnostics.source === "file"
354
+ && durable.diagnostics.error === null ? durable.diagnostics.config.providers[name] : undefined;
355
+ removedCredentials = [config.providers[name], durableProvider].flatMap(provider => provider ? providerGcpCredentialMarkers(provider) : []);
337
356
  config.providers[name] = provConfig;
338
357
  if (setDefault) config.defaultProvider = name;
339
358
  validateAndSave(config);
@@ -344,6 +363,7 @@ async function handleAdd(args: string[], deps: ProviderCommandDeps): Promise<voi
344
363
  return;
345
364
  }
346
365
 
366
+ cleanupRemovedGcpCredentials(removedCredentials);
347
367
  let sync: LocalSyncResult | undefined;
348
368
  if (wantsSync) {
349
369
  try {
@@ -440,10 +460,12 @@ function handleRemove(args: string[]): void {
440
460
  process.exit(1);
441
461
  }
442
462
 
443
- delete config.providers[name];
444
- const droppedCustomModels = dropProviderCustomModels(config, name);
445
- validateAndSave(config);
446
-
463
+ const droppedCustomModels = commitProviderGcpCredentialRemoval(config, name, () => {
464
+ delete config.providers[name];
465
+ const dropped = dropProviderCustomModels(config, name);
466
+ validateAndSave(config);
467
+ return dropped;
468
+ });
447
469
 
448
470
  if (wantsJson) {
449
471
  console.log(JSON.stringify({
@@ -8,6 +8,12 @@ export interface CliCommandEntry {
8
8
  }
9
9
 
10
10
  export const CLI_COMMANDS: CliCommandEntry[] = [
11
+ {
12
+ name: "codex-provider",
13
+ usage: "ocx codex-provider <status|allow <id> [--yes]|revoke <id>>",
14
+ summary: "Explicitly allow or revoke local routing management for a custom Codex provider.",
15
+ details: ["Consent is bound to the selected CODEX_HOME and provider ID. Only base_url is managed; transport settings and history are preserved."],
16
+ },
11
17
  {
12
18
  name: "message",
13
19
  usage: "ocx message <sessions|send> [options]",
@@ -178,7 +184,7 @@ export const CLI_COMMANDS: CliCommandEntry[] = [
178
184
  summary: "Fetch provider models and inject them into Codex config.",
179
185
  details: [
180
186
  "After writing the catalog, warns if long-lived Codex app-server processes are still running.",
181
- "--restart-codex restarts the app-servers AND fully quits and relaunches the Codex desktop app on macOS, Linux and Windows, so its model picker re-reads the catalog. It ends live conversations.",
187
+ "--restart-codex restarts the app-servers AND fully quits and relaunches the Codex desktop app on macOS, Linux and Windows, after catalog/cache writes or a committed configuration change. It ends live conversations.",
182
188
  "--restart-app-server-only keeps the narrow behaviour: SIGTERM to matching app-server / code-mode-host processes, desktop app left running. It wins over --restart-codex when both are given.",
183
189
  "--restart-desktop-app is a deprecated alias of --restart-codex and prints a notice.",
184
190
  ],
@@ -226,9 +232,10 @@ export const CLI_COMMANDS: CliCommandEntry[] = [
226
232
  },
227
233
  {
228
234
  name: "login",
229
- usage: "ocx login <provider>",
235
+ usage: "ocx login <provider> [--headless]",
230
236
  summary: "OAuth or API-key login for a provider.",
231
237
  details: [
238
+ "--headless (anthropic, anthropic2): no browser and no local port; approve in any browser and paste the displayed code.",
232
239
  "Codex/ChatGPT: ocx login codex runs the Codex account-pool login (same flow as ocx account login codex).",
233
240
  "That one needs a running proxy; the OAuth and API-key providers log in locally.",
234
241
  "'chatgpt' and 'openai' are the same route; an OpenAI platform API key is 'ocx login openai-apikey'.",
@@ -336,6 +343,7 @@ export const CLI_COMMANDS: CliCommandEntry[] = [
336
343
  "add-key <provider> [--label <label>] Add a key read only from piped stdin.",
337
344
  "pool <provider> Read/edit runtime-supported pool policy.",
338
345
  "credits openai ... Explicit paid-credit-after-limit policy; separate from displaying balances.",
346
+ "use-remaining openai <id|main> <on|off|status> Use included quota up to its limit.",
339
347
  "quota-activation openai Enable/disable one account reset-window refresh policy.",
340
348
  "anthropic-reset-grants Read grant status only; consumption remains in the dashboard.",
341
349
  "login supports explicit browser/add-account options only for applicable flows; human verification remains required.",
@@ -378,6 +386,18 @@ export const CLI_COMMANDS: CliCommandEntry[] = [
378
386
  usage: "ocx model <subcommand>",
379
387
  summary: "Alias of ocx models.",
380
388
  },
389
+ {
390
+ name: "advisor",
391
+ usage: "ocx advisor <status|on|off|consent|set> ...",
392
+ summary: "Inspect and configure the advisor sidecar (expert consultation for routed workers).",
393
+ details: [
394
+ "ocx advisor and ocx advisor status read the resolved settings; use --json for machine-readable output.",
395
+ "ocx advisor on requires current context-sharing consent. Pass --ack-context-sharing to record consent v1 and enable. ocx advisor off disables the sidecar without granting consent.",
396
+ "ocx advisor consent records consent v1 after printing the disclosure. ocx advisor consent --revoke removes it and stops task-context transfer.",
397
+ "ocx advisor set updates --model, --effort, --policy and --timeout-ms; the model may be any routable model string (bare native, provider/model, or account-qualified). set does not grant consent.",
398
+ "policy manual consults only when the worker calls the synthetic advisor tool; policy preflight also attempts one automatic consultation per task with a stable conversation identity, once the task shows orientation evidence. Without a stable identity, each eligible request may trigger another consultation. Both require current consent before any task context is sent.",
399
+ ],
400
+ },
381
401
  {
382
402
  name: "companion",
383
403
  usage: "ocx companion <show|set|reset|usage|timeline> ...",
@@ -432,11 +452,21 @@ export const CLI_COMMANDS: CliCommandEntry[] = [
432
452
  "`inspect star` reads the repository star status only. Starring uses your GitHub identity and is available from the dashboard alone.",
433
453
  ],
434
454
  },
435
- { name: "logs", usage: "ocx logs [filters] [--follow] [--json|--jsonl|--events]", summary: "Read or follow request logs." },
455
+ {
456
+ name: "logs",
457
+ usage: "ocx logs [filters] [--follow] [--json|--jsonl|--events]; ocx logs history [selectors] [--cursor <token>] [--json|--jsonl]; ocx logs get <request-id> [--json]",
458
+ summary: "Read or follow request logs.",
459
+ details: [
460
+ "Default reads the recent ring. `history` pages the derived index with a resumable cursor; `get` reads one canonical row; `explain` is the route-decision view.",
461
+ ],
462
+ },
436
463
  {
437
464
  name: "usage",
438
- usage: "ocx usage [--range <today|1d|7d|30d|all>] [--surface <all|codex|claude|grok>] [--provider <name>] [--model <id>] [--api-key-id <id>] [--search <text>] [--json]",
465
+ usage: "ocx usage [--range <today|1d|7d|30d|all>] [--surface <all|codex|claude|grok>] [--provider <name>] [--model <id>] [--api-key-id <id>] [--search <text>] [--top <1-1000>] [--json]; ocx usage compare [--range <today|1d|7d|30d>] [--json]",
439
466
  summary: "Report token usage and estimated cost (alias of ocx observe usage).",
467
+ details: [
468
+ "`compare` reads the current named range and the previous equal window; `--range all` is refused.",
469
+ ],
440
470
  },
441
471
  {
442
472
  name: "storage",
@@ -469,18 +499,19 @@ export const CLI_COMMANDS: CliCommandEntry[] = [
469
499
  "protocols [--provider <name>] Contract version, API surfaces, protocol settings and feature vocabulary.",
470
500
  "explain --model <id> --inbound <responses|chat|messages> [--feature <key>]... Preview the request path; sends nothing upstream.",
471
501
  "policy Read the protocol policy; with --messages, --unrepresentable or --rollout <switch>=<on|off> it changes config.",
472
- "Every rollout switch defaults off. `ocx api policy` writes only when a setting flag is given.",
502
+ "Every rollout switch defaults off except antigravityDirect. `ocx api policy` writes only when a setting flag is given.",
473
503
  ],
474
504
  },
475
505
  {
476
506
  name: "export",
477
- usage: "ocx export --client <opencode|pi|omp|hermes|openclaw|kimi|gajae|dsh|mcode|zcode|commandcode|prime|aside|raycast|omo|cline|kilo|droid> [--json] [--out <path>] [--force]",
478
- summary: "Print a client config (OpenCode, Pi, OMP, Hermes, OpenClaw, Kimi Code, gjc, DeepSeek Harness, MiniMax Code, ZCode, Command Code, Prime Agent, Aside, Raycast, omo, Cline, Kilo, Factory Droid) wired to the running proxy.",
507
+ usage: "ocx export --client <qoder|opencode|pi|omp|hermes|openclaw|kimi|gajae|dsh|mcode|zcode|commandcode|prime|aside|raycast|omo|cline|kilo|droid|gentle-shell> [--json] [--out <path>] [--force]",
508
+ summary: "Print a client config (OpenCode, Pi, OMP, Hermes, OpenClaw, Kimi Code, gjc, DeepSeek Harness, MiniMax Code, ZCode, Command Code, Prime Agent, Aside, Raycast, omo, Cline, Kilo, Factory Droid, Qoder, Gentle Shell) wired to the running proxy.",
479
509
  details: [
480
510
  "--json prints the generated document as JSON on stdout; use --out for the client's native format.",
481
511
  "--out <path> writes the native config there and refuses to replace an existing file without --force.",
482
512
  "Cline exports a two-document bundle: settings for providers.json and catalog for sibling models.json. Use integration client enable --client cline for a journaled write.",
483
513
  "Droid exports documented customModels for settings.json; use integration client enable --client droid for a journaled write.",
514
+ "Gentle Shell uses its persistent selected home; use integration client enable --client gentle-shell for a journaled write, or Pi for link/shared homes.",
484
515
  "The config never contains a real key; it carries a documented env reference or a non-secret loopback placeholder.",
485
516
  "The destination path is printed for merging by hand — ocx never writes your real client config.",
486
517
  ],
@@ -504,14 +535,15 @@ export const CLI_COMMANDS: CliCommandEntry[] = [
504
535
  {
505
536
  name: "system",
506
537
  usage: "ocx system <status|health|settings|startup|diagnostics|sync|codex-app-server|codex-restart|update|codex-cli-update> ...",
507
- summary: "Manage headless runtime settings, startup, sync, diagnostics, OpenCodex updates, and read-only Codex CLI inspection.",
538
+ summary: "Manage headless runtime settings, health, startup, sync, diagnostics, OpenCodex updates, and read-only Codex CLI inspection and planning.",
508
539
  details: [
509
540
  "system update manages OpenCodex itself.",
510
541
  "system health reads authenticated service and spend-ledger diagnostics; root health remains liveness.",
511
542
  "ocx system codex-cli-update check [--json]",
512
543
  "ocx system codex-cli-update attest [--json]",
513
544
  "ocx system codex-cli-update attest --candidate <absolute-path> --npm-prefix <absolute-path> --npm-cli <absolute-path> --node <absolute-path> [--json]",
514
- "The Codex CLI inspection command makes no package-registry request, does not execute Codex or npm, install or repair software, control a process, or write configuration or cache state.",
545
+ "ocx system codex-cli-update plan [--channel latest] [--json]",
546
+ "check and attest make no package-registry request, do not execute Codex or npm, and write nothing. plan adds a registry query and a process-table read and mutates no application state (temporary isolated npm files only, removed best-effort).",
515
547
  ],
516
548
  },
517
549
  {
@@ -173,6 +173,9 @@ export async function handleDesktopAppRestart(
173
173
  + "Quit and relaunch the desktop app manually to refresh the model picker.",
174
174
  );
175
175
  return result;
176
+ case "relaunch_context_failed":
177
+ log.error("Codex desktop launch options could not be preserved safely, so the app was not stopped. Review its current launch options before retrying.");
178
+ return result;
176
179
  case "no_targets":
177
180
  log.log("Codex desktop app is not running; nothing to restart.");
178
181
  return result;
@@ -189,4 +192,3 @@ export async function handleDesktopAppRestart(
189
192
  return result;
190
193
  }
191
194
  }
192
-