@bitkyc08/opencodex 2.80.0 → 2.82.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (376) hide show
  1. package/README.md +3 -3
  2. package/bin/ocx.mjs +166 -73
  3. package/gui/dist/assets/App-Ds_qL7o8.js +54 -0
  4. package/gui/dist/assets/Tray-BqHF5Trd.js +1 -0
  5. package/gui/dist/assets/{index-Brk6F3fn.css → index-BAbcj51J.css} +1 -1
  6. package/gui/dist/assets/index-D3FBCNiP.js +94 -0
  7. package/gui/dist/assets/quota-summary-DTBC8n7-.js +1 -0
  8. package/gui/dist/index.html +2 -2
  9. package/gui/dist/provider-icons/claude-green.svg +1 -0
  10. package/package.json +3 -2
  11. package/src/adapters/anthropic-model-contract.ts +8 -2
  12. package/src/adapters/anthropic.ts +8 -3
  13. package/src/adapters/codebuddy/mcp-server.ts +2 -25
  14. package/src/adapters/codebuddy/tool-bridge.ts +1 -7
  15. package/src/adapters/coding-agent/mcp-server.ts +33 -0
  16. package/src/adapters/coding-agent/protocol.ts +122 -17
  17. package/src/adapters/coding-agent/tool-catalog.ts +75 -0
  18. package/src/adapters/coding-agent/turn.ts +101 -44
  19. package/src/adapters/cursor/catalog.ts +8 -0
  20. package/src/adapters/cursor/effort-map.ts +2 -0
  21. package/src/adapters/devin/live-models.ts +2 -0
  22. package/src/adapters/kiro-retry.ts +9 -4
  23. package/src/adapters/openai-chat/messages.ts +7 -6
  24. package/src/adapters/openai-responses/compaction-search-history.ts +109 -0
  25. package/src/adapters/openai-responses/passthrough.ts +9 -4
  26. package/src/adapters/openai-responses/tool-output-recovery.ts +20 -0
  27. package/src/adapters/physical-send.ts +8 -5
  28. package/src/adapters/qoder/adapter.ts +41 -6
  29. package/src/adapters/qoder/scaffold-guard.ts +2 -3
  30. package/src/adapters/zed.ts +16 -1
  31. package/src/claude/agents-inject.ts +14 -3
  32. package/src/claude/context-windows.ts +19 -17
  33. package/src/claude/desktop-3p.ts +88 -12
  34. package/src/claude/desktop-profile.ts +2 -1
  35. package/src/claude/gateway-cache.ts +18 -1
  36. package/src/claude/inbound-cache-stabilize.ts +4 -9
  37. package/src/claude/inbound.ts +78 -3
  38. package/src/claude/intercept/cli-catalog.ts +3 -0
  39. package/src/claude/intercept/model-bindings.ts +1 -0
  40. package/src/claude/intercept/picker-ca-persistence.ts +7 -6
  41. package/src/claude/intercept/picker-listener.ts +71 -4
  42. package/src/claude/intercept/picker-models.ts +14 -6
  43. package/src/claude/intercept/settings.ts +3 -0
  44. package/src/claude/long-context.ts +66 -0
  45. package/src/claude/model-info.ts +19 -16
  46. package/src/claude/outbound.ts +94 -9
  47. package/src/claude/subagent-model.ts +40 -11
  48. package/src/cli/account-anthropic-threshold.ts +14 -5
  49. package/src/cli/account-api.ts +3 -1
  50. package/src/cli/account-extended.ts +13 -9
  51. package/src/cli/account-policy-dto.ts +1 -1
  52. package/src/cli/account-policy.ts +13 -4
  53. package/src/cli/account.ts +3 -3
  54. package/src/cli/agent.ts +9 -5
  55. package/src/cli/aside-profile-recovery.ts +33 -0
  56. package/src/cli/capabilities-accounts.ts +2 -2
  57. package/src/cli/capabilities-agents-routing.ts +24 -0
  58. package/src/cli/capabilities-base.ts +5 -5
  59. package/src/cli/capabilities-integrations.ts +18 -2
  60. package/src/cli/cli-path-diagnostics.ts +132 -0
  61. package/src/cli/codex-shim-autorestore.ts +3 -0
  62. package/src/cli/desktop-runtime-guidance.ts +65 -0
  63. package/src/cli/dispatch.ts +15 -1
  64. package/src/cli/doctor.ts +16 -3
  65. package/src/cli/help.ts +4 -1
  66. package/src/cli/index.ts +25 -14
  67. package/src/cli/integration-aside-sync.ts +2 -1
  68. package/src/cli/integration-plan-dto.ts +1 -0
  69. package/src/cli/integration-preview.ts +8 -1
  70. package/src/cli/integrations.ts +48 -6
  71. package/src/cli/message-args.ts +34 -0
  72. package/src/cli/message-command.ts +43 -0
  73. package/src/cli/message-runtime.ts +6 -0
  74. package/src/cli/observe.ts +3 -1
  75. package/src/cli/provider.ts +29 -6
  76. package/src/cli/registry.ts +24 -2
  77. package/src/cli/resolve.ts +25 -2
  78. package/src/cli/root.ts +4 -2
  79. package/src/cli/status.ts +64 -12
  80. package/src/cli/update-restart-child.ts +4 -2
  81. package/src/cli/update-restart-home.ts +28 -10
  82. package/src/cli/update-restart-service-record.ts +116 -0
  83. package/src/cli/update-restart-supervision.ts +96 -0
  84. package/src/cli/update-restart.ts +59 -13
  85. package/src/cli/v2.ts +27 -20
  86. package/src/cli/version-skew-notice.ts +77 -0
  87. package/src/clients/config-export/commandcode.ts +131 -0
  88. package/src/clients/config-export/contracts.ts +12 -0
  89. package/src/clients/config-export.ts +64 -1
  90. package/src/clients/lazycodex.ts +1 -1
  91. package/src/clients/omo-role-models.ts +32 -7
  92. package/src/codex/auth-api/account-list.ts +11 -3
  93. package/src/codex/auth-api/account-selection.ts +107 -0
  94. package/src/codex/auth-api/main-account-probe.ts +25 -8
  95. package/src/codex/auth-api/pool-mode-gate.ts +33 -9
  96. package/src/codex/auth-api/pool-quota-probe.ts +15 -1
  97. package/src/codex/auth-api/routes.ts +11 -49
  98. package/src/codex/auth-context.ts +20 -1
  99. package/src/codex/autostart-health.ts +12 -3
  100. package/src/codex/catalog/auto-review.ts +13 -6
  101. package/src/codex/catalog/build-entries.ts +33 -7
  102. package/src/codex/catalog/bundled.ts +155 -26
  103. package/src/codex/catalog/combo-member.ts +3 -2
  104. package/src/codex/catalog/control-plane.ts +45 -0
  105. package/src/codex/catalog/effort.ts +37 -6
  106. package/src/codex/catalog/gather-capture.ts +10 -3
  107. package/src/codex/catalog/model-hints.ts +15 -8
  108. package/src/codex/catalog/model-visibility.ts +3 -1
  109. package/src/codex/catalog/operator-tiers.ts +38 -0
  110. package/src/codex/catalog/parsing.ts +2 -1
  111. package/src/codex/catalog/provider-models.ts +58 -44
  112. package/src/codex/catalog/retained-sync.ts +7 -5
  113. package/src/codex/catalog/routed-gather.ts +15 -1
  114. package/src/codex/catalog-auto-refresh-sources.ts +3 -4
  115. package/src/codex/catalog-auto-refresh.ts +19 -0
  116. package/src/codex/catalog.ts +1 -1
  117. package/src/codex/codex-home-owner.ts +3 -0
  118. package/src/codex/config-write-lock.ts +333 -0
  119. package/src/codex/control-plane-models.ts +6 -0
  120. package/src/codex/convergence.ts +2 -1
  121. package/src/codex/features.ts +257 -200
  122. package/src/codex/inject/config-write-section.ts +34 -0
  123. package/src/codex/inject/multi-agent-v2.ts +14 -6
  124. package/src/codex/inject/remove.ts +36 -11
  125. package/src/codex/inject/restore.ts +85 -20
  126. package/src/codex/inject-coordination.ts +15 -6
  127. package/src/codex/inject.ts +62 -20
  128. package/src/codex/journal.ts +62 -17
  129. package/src/codex/main-account-cache.ts +43 -0
  130. package/src/codex/paths.ts +2 -0
  131. package/src/codex/prepared-home.ts +18 -0
  132. package/src/codex/prompt-journal.ts +25 -12
  133. package/src/codex/prompt-layers.ts +49 -26
  134. package/src/codex/prompt-lock-claim.ts +134 -0
  135. package/src/codex/prompt-lock-evidence.ts +26 -0
  136. package/src/codex/prompt-lock-io.ts +16 -0
  137. package/src/codex/prompt-lock-owner.ts +130 -0
  138. package/src/codex/prompt-lock.ts +84 -53
  139. package/src/codex/routing/failure-window.ts +146 -0
  140. package/src/codex/routing/selection.ts +4 -1
  141. package/src/codex/routing.ts +13 -17
  142. package/src/codex/runtime.ts +106 -18
  143. package/src/codex/shim.ts +45 -19
  144. package/src/combos/jev-decision-contract.ts +25 -2
  145. package/src/combos/jev-service-exchange.ts +281 -0
  146. package/src/combos/jev.ts +34 -219
  147. package/src/combos/types.ts +1 -1
  148. package/src/config/atomic-write.ts +1 -1
  149. package/src/config/codex-ws-reuse-setting.ts +10 -0
  150. package/src/config/diagnostics.ts +27 -16
  151. package/src/config/live-reconcile.ts +17 -0
  152. package/src/config/load-degrade.ts +42 -0
  153. package/src/config/rebase-provenance.ts +11 -0
  154. package/src/config/schema/anthropic-account-pool.ts +143 -0
  155. package/src/config/schema/config-schema.ts +11 -1
  156. package/src/config/schema/leaf-validators.ts +4 -0
  157. package/src/config.ts +2 -0
  158. package/src/generated/compatibility-version.json +566 -298
  159. package/src/generated/model-metadata.ts +7 -6
  160. package/src/grok/inject.ts +50 -4
  161. package/src/grok/sync.ts +2 -1
  162. package/src/images/loop.ts +30 -11
  163. package/src/integrations/aside-profiles.ts +10 -3
  164. package/src/integrations/catalog-refresh.ts +19 -3
  165. package/src/integrations/mutation-plan.ts +7 -0
  166. package/src/integrations/registry.ts +8 -0
  167. package/src/integrations/state.ts +9 -2
  168. package/src/integrations/writer.ts +17 -5
  169. package/src/lib/bun-path-runtime.d.mts +32 -0
  170. package/src/lib/bun-path-runtime.mjs +95 -0
  171. package/src/lib/bun-runtime-preflight.ts +140 -0
  172. package/src/lib/desktop-cli-handoff.d.mts +20 -0
  173. package/src/lib/desktop-cli-handoff.mjs +92 -0
  174. package/src/lib/desktop-cli-record.d.mts +29 -0
  175. package/src/lib/desktop-cli-record.mjs +102 -0
  176. package/src/lib/lab-live-route-production.ts +9 -1
  177. package/src/lib/request-execution-budget.ts +244 -58
  178. package/src/lib/spend-pool-alias-validation.ts +79 -0
  179. package/src/lib/spend-pool-continuity.ts +34 -0
  180. package/src/lib/spend-reservation-ledger.ts +412 -50
  181. package/src/lib/state-store-registrations.ts +20 -3
  182. package/src/lib/synced-state-location.ts +46 -6
  183. package/src/lib/test-home-guard.ts +87 -1
  184. package/src/lib/translator-budget.ts +17 -4
  185. package/src/lib/upstream-retry.ts +17 -5
  186. package/src/lib/windows-atomic-replace.ts +38 -16
  187. package/src/lib/windows-elevation.ts +6 -0
  188. package/src/lib/windows-secret-acl.ts +92 -25
  189. package/src/lib/winsw.ts +2 -3
  190. package/src/lib/workflow-budget.ts +53 -11
  191. package/src/messaging/budget.ts +45 -0
  192. package/src/messaging/discovery.ts +57 -0
  193. package/src/messaging/envelope.ts +49 -0
  194. package/src/messaging/input.ts +37 -0
  195. package/src/messaging/rpc.ts +196 -0
  196. package/src/messaging/send.ts +58 -0
  197. package/src/messaging/socket.ts +72 -0
  198. package/src/messaging/types.ts +29 -0
  199. package/src/oauth/anthropic-account-refusal.ts +90 -18
  200. package/src/oauth/anthropic-account-threshold.ts +8 -2
  201. package/src/oauth/anthropic-continuity.ts +15 -1
  202. package/src/oauth/anthropic-model-quota.ts +120 -48
  203. package/src/oauth/anthropic-model-routes.ts +11 -3
  204. package/src/oauth/anthropic-oauth-definitions.ts +98 -0
  205. package/src/oauth/anthropic-pool-config.ts +30 -0
  206. package/src/oauth/anthropic-rate-limit-policy.ts +64 -9
  207. package/src/oauth/anthropic-routing.ts +1202 -866
  208. package/src/oauth/anthropic-send-ownership.ts +41 -0
  209. package/src/oauth/anthropic.ts +4 -1
  210. package/src/oauth/chatgpt.ts +113 -41
  211. package/src/oauth/generic-account-failover.ts +3 -1
  212. package/src/oauth/health.ts +8 -6
  213. package/src/oauth/index.ts +96 -175
  214. package/src/oauth/kiro.ts +22 -9
  215. package/src/oauth/login-cli.ts +2 -0
  216. package/src/oauth/model-discovery-auth.ts +43 -0
  217. package/src/oauth/pool-kernel.ts +11 -5
  218. package/src/oauth/pool-settings-capability.ts +5 -3
  219. package/src/oauth/store-anthropic-instance.ts +87 -0
  220. package/src/oauth/store.ts +68 -10
  221. package/src/oauth/token-guardian.ts +2 -0
  222. package/src/oauth/types.ts +2 -0
  223. package/src/protocols/plan-snapshot.ts +5 -0
  224. package/src/protocols/settings.ts +20 -5
  225. package/src/providers/anthropic-instance-id.ts +47 -0
  226. package/src/providers/anthropic-instance.ts +48 -0
  227. package/src/providers/anthropic-reset-grant-ledger.ts +11 -1
  228. package/src/providers/azure-model-metadata.ts +115 -0
  229. package/src/providers/derive.ts +23 -0
  230. package/src/providers/kiro-models.ts +3 -0
  231. package/src/providers/label.ts +1 -1
  232. package/src/providers/model-rename-fields.ts +2 -0
  233. package/src/providers/quota/account-cache.ts +37 -11
  234. package/src/providers/quota/anthropic-account-quota.ts +93 -0
  235. package/src/providers/quota/anthropic-cooldown-recovery.ts +222 -111
  236. package/src/providers/quota/report-cache.ts +24 -1
  237. package/src/providers/quota/vendor-probes-key.ts +127 -17
  238. package/src/providers/quota/vendor-probes-oauth.ts +46 -14
  239. package/src/providers/quota.ts +23 -33
  240. package/src/providers/registry/entries-core.ts +35 -30
  241. package/src/providers/registry/model-ids.ts +1 -0
  242. package/src/providers/registry/model-seeds.ts +7 -4
  243. package/src/providers/registry/types.ts +3 -0
  244. package/src/providers/registry.ts +3 -3
  245. package/src/responses/reasoning-envelope.ts +29 -1
  246. package/src/responses/reasoning-replay-cache.ts +17 -1
  247. package/src/responses/spill-store.ts +20 -3
  248. package/src/responses/state/metrics.ts +95 -0
  249. package/src/responses/state/snapshot-codec.ts +6 -0
  250. package/src/responses/state/spill-failure.ts +12 -0
  251. package/src/responses/state/spill-queue.ts +13 -5
  252. package/src/responses/state/unforced-store-false.ts +55 -0
  253. package/src/responses/state.ts +68 -76
  254. package/src/responses/task-input.ts +17 -0
  255. package/src/router.ts +28 -4
  256. package/src/routing/compatibility/assemble.ts +1 -1
  257. package/src/routing/quota.ts +7 -3
  258. package/src/server/auth-cors.ts +5 -0
  259. package/src/server/background-lifecycle.ts +27 -0
  260. package/src/server/chat-completions.ts +7 -1
  261. package/src/server/chat-native.ts +64 -28
  262. package/src/server/claude-messages.ts +59 -8
  263. package/src/server/gui-static.ts +38 -4
  264. package/src/server/inbound-body-admission.ts +1 -0
  265. package/src/server/index/claude-intercept-lifecycle.ts +3 -1
  266. package/src/server/index/serve-options.ts +10 -2
  267. package/src/server/index/spend-ledger-lifecycle.ts +12 -5
  268. package/src/server/index/startup-warnings.ts +19 -0
  269. package/src/server/index.ts +5 -2
  270. package/src/server/inference/context.ts +1 -1
  271. package/src/server/lifecycle.ts +1 -1
  272. package/src/server/management/agent-settings-routes.ts +123 -38
  273. package/src/server/management/anthropic-account-threshold.ts +12 -9
  274. package/src/server/management/anthropic-pool-settings.ts +72 -0
  275. package/src/server/management/anthropic-reset-grant-routes.ts +98 -39
  276. package/src/server/management/codex-agent-role-routes.ts +4 -2
  277. package/src/server/management/codex-prompt-routes.ts +1 -0
  278. package/src/server/management/codex-role-auto-assign.ts +13 -2
  279. package/src/server/management/config-routes.ts +85 -14
  280. package/src/server/management/context.ts +2 -2
  281. package/src/server/management/decision-routes.ts +2 -1
  282. package/src/server/management/integration-routes.ts +25 -2
  283. package/src/server/management/oauth-account-routes.ts +79 -98
  284. package/src/server/management/provider-instance-ownership.ts +44 -0
  285. package/src/server/management/provider-routes.ts +21 -28
  286. package/src/server/management/route-registry.ts +3 -1
  287. package/src/server/management/routing-profile-routes.ts +4 -4
  288. package/src/server/management/shared.ts +3 -3
  289. package/src/server/management/system-restart.ts +44 -14
  290. package/src/server/management/system-routes.ts +24 -2
  291. package/src/server/management/vision-sidecar-options.ts +9 -6
  292. package/src/server/management/web-search-sidecar-options.ts +51 -2
  293. package/src/server/management-auth.ts +6 -0
  294. package/src/server/messages-native-eligibility.ts +3 -2
  295. package/src/server/messages-native-oauth.ts +91 -45
  296. package/src/server/messages-native-selector.ts +39 -0
  297. package/src/server/messages-native.ts +133 -38
  298. package/src/server/messages-response-headers.ts +14 -0
  299. package/src/server/request-log-conversation.ts +48 -5
  300. package/src/server/request-log.ts +36 -2
  301. package/src/server/responses/adapter-continuation.ts +31 -19
  302. package/src/server/responses/adapter-dispatch.ts +75 -24
  303. package/src/server/responses/antigravity-validation-refusal.ts +20 -6
  304. package/src/server/responses/codex-ws-exchange.ts +17 -2
  305. package/src/server/responses/codex-ws-pool.ts +100 -13
  306. package/src/server/responses/codex-ws-wire.ts +9 -0
  307. package/src/server/responses/combo-requested-effort.ts +3 -1
  308. package/src/server/responses/compact.ts +25 -8
  309. package/src/server/responses/compaction-recovery.ts +1 -1
  310. package/src/server/responses/core-codex-account.ts +22 -1
  311. package/src/server/responses/core-combo-native.ts +24 -4
  312. package/src/server/responses/core-combo.ts +38 -25
  313. package/src/server/responses/core-lifetime.ts +3 -36
  314. package/src/server/responses/core-normalize.ts +1 -0
  315. package/src/server/responses/core-options.ts +8 -1
  316. package/src/server/responses/core-replay.ts +78 -0
  317. package/src/server/responses/core.ts +3 -3
  318. package/src/server/responses/fetch-helpers.ts +26 -3
  319. package/src/server/responses/passthrough-delivery.ts +30 -4
  320. package/src/server/responses/passthrough-dispatch.ts +39 -9
  321. package/src/server/responses/request-prepare.ts +41 -5
  322. package/src/server/responses/request-send-budget.ts +150 -50
  323. package/src/server/responses/request-spend.ts +325 -33
  324. package/src/server/responses/request-transport.ts +132 -52
  325. package/src/server/responses/response-effects.ts +1 -0
  326. package/src/server/responses/run-turn-execution.ts +13 -3
  327. package/src/server/responses/sidecar-execution.ts +113 -22
  328. package/src/server/responses/sidecar-send-budget.ts +58 -0
  329. package/src/server/responses/ws-upstream.ts +19 -6
  330. package/src/server/responses-undeclared-tool-guard.ts +5 -1
  331. package/src/server/startup-health-cache.ts +2 -1
  332. package/src/server/workflow-refusal.ts +33 -0
  333. package/src/service/cli.ts +20 -4
  334. package/src/service/desktop-command-guard.ts +32 -0
  335. package/src/service/desktop-startup.ts +66 -40
  336. package/src/service/desktop-supervision.d.mts +26 -0
  337. package/src/service/desktop-supervision.mjs +140 -0
  338. package/src/service/managing-cli.ts +1 -0
  339. package/src/service/orchestration.ts +46 -20
  340. package/src/service/ownership-mutation-lease.d.mts +1 -1
  341. package/src/service/ownership-mutation-lease.mjs +5 -7
  342. package/src/service/repair.ts +25 -9
  343. package/src/service/state.ts +4 -3
  344. package/src/service/systemd.ts +17 -8
  345. package/src/service/windows-ops.ts +61 -22
  346. package/src/sidecar/anthropic-binding.ts +79 -0
  347. package/src/sidecar/auth.ts +76 -2
  348. package/src/storage/policy-job.ts +5 -1
  349. package/src/storage/policy-worker.ts +3 -1
  350. package/src/storage/policy.ts +9 -0
  351. package/src/types/anthropic-account-pool.ts +33 -0
  352. package/src/types/config.ts +33 -28
  353. package/src/types/provider.ts +5 -0
  354. package/src/types/request.ts +5 -0
  355. package/src/types/tools.ts +7 -0
  356. package/src/types/wire.ts +1 -0
  357. package/src/types.ts +4 -0
  358. package/src/update/index.ts +57 -9
  359. package/src/update/restart-ownership.ts +10 -3
  360. package/src/update/runtime-ownership.d.mts +6 -0
  361. package/src/update/runtime-ownership.mjs +23 -7
  362. package/src/usage/cost.ts +3 -2
  363. package/src/usage/expected-prices.ts +66 -14
  364. package/src/vision/anthropic-describe.ts +16 -3
  365. package/src/vision/index.ts +3 -0
  366. package/src/vision/plan.ts +19 -6
  367. package/src/web-search/alpha-search.ts +7 -1
  368. package/src/web-search/anthropic-executor.ts +16 -4
  369. package/src/web-search/index.ts +7 -3
  370. package/src/web-search/loop.ts +32 -7
  371. package/src/web-search/passthrough-bridge.ts +4 -1
  372. package/src/web-search/sidecar-providers.ts +4 -3
  373. package/gui/dist/assets/App-MbDVfUeC.js +0 -54
  374. package/gui/dist/assets/Tray-CzkxK82A.js +0 -1
  375. package/gui/dist/assets/index-UJt6npXk.js +0 -94
  376. package/gui/dist/assets/quota-summary-DU3sD6Z-.js +0 -1
@@ -1,12 +1,8 @@
1
1
  import type { OcxProviderConfig } from "./provider";
2
2
  import type { CodexAccount } from "./accounts";
3
-
4
- export interface AnthropicModelRoute {
5
- name: string;
6
- match: string;
7
- accounts: string[];
8
- fallback?: boolean;
9
- }
3
+ import type { AnthropicAccountPoolConfig, OcxAccountPoolRotationStrategy } from "./anthropic-account-pool";
4
+ import type { AnthropicInstanceId } from "../providers/anthropic-instance-id";
5
+ export type { AnthropicAccountPoolConfig, AnthropicModelRoute, OcxAccountPoolRotationStrategy, OcxAccountPoolQuotaWindow } from "./anthropic-account-pool";
10
6
 
11
7
  /** Public inference API exposure. Responses and Chat Completions are always served. */
12
8
  export interface OcxApiSurfacesConfig {
@@ -178,6 +174,15 @@ export interface OcxClaudeCodeConfig {
178
174
  autoContext?: boolean;
179
175
  /** Compact-window tokens for auto-context. Default 829_800 (AUTO_COMPACT_WINDOW_DEFAULT). */
180
176
  autoCompactWindow?: number;
177
+ /**
178
+ * Context accounting on Claude surfaces (devlog/_plan/261009_claude_1m_default/030). Absent
179
+ * (the default) = "1m": long-window models are offered at 1M wherever opencodex picks the
180
+ * default (launch env slots, Desktop pickers, Desktop 3P prefer1m, generated subagents).
181
+ * "200k" is the opt-in: nothing is marked [1m] automatically and no compact window is injected;
182
+ * a selector the user marks [1m] keeps it, and discovery and Desktop 3P keep offering 1M as a
183
+ * choice. The only stored value; "1m" deletes the key.
184
+ */
185
+ contextAccounting?: "200k";
181
186
  /**
182
187
  * Local CONNECT proxy + TLS listener that intercepts Claude Code's own `api.anthropic.com`
183
188
  * traffic without any `ANTHROPIC_BASE_URL` rewrite (src/claude/intercept). Claude Code reaches
@@ -222,9 +227,9 @@ export interface OcxClaudeCodeConfig {
222
227
  /** Optional roster-style model forced on subagents at the next routed Claude Code launch. */
223
228
  subagentModelForce?: string;
224
229
  /** Claude-originated web-search override. Unset fields inherit the global sidecar settings. */
225
- webSearchSidecar?: { backend?: "openai" | "anthropic" | "xai" | "gemini" | "exa"; model?: string };
230
+ webSearchSidecar?: { backend?: "openai" | "anthropic" | "xai" | "gemini" | "exa"; model?: string; anthropicInstance?: AnthropicInstanceId };
226
231
  /** Claude-originated vision override. Unset fields inherit the global sidecar settings. */
227
- visionSidecar?: { backend?: "openai" | "anthropic" | "routed"; model?: string };
232
+ visionSidecar?: { backend?: "openai" | "anthropic" | "routed"; model?: string; anthropicInstance?: AnthropicInstanceId };
228
233
  /** Persisted Claude Desktop four-family routing profile. */
229
234
  desktopProfile?: OcxClaudeDesktopProfile;
230
235
  /**
@@ -1052,6 +1057,8 @@ export interface OcxConfig {
1052
1057
  * upgrade against a number nobody chose.
1053
1058
  */
1054
1059
  spend?: OcxSpendConfig;
1060
+ /** Historical salted pool aliases; h(pool,P) cannot map to Q != P for any configured provider P. */
1061
+ spendPoolAliases?: Record<string, string>;
1055
1062
  /** Opt-in per-account activation of newly reset Codex quota windows. */
1056
1063
  codexQuotaAutoRefresh?: Record<string, {
1057
1064
  fiveHour?: boolean;
@@ -1176,6 +1183,18 @@ export interface OcxConfig {
1176
1183
  accountPoolStickyLimit?: number;
1177
1184
  /** Consecutive non-2xx upstream responses before switching future new threads. Default 3. 0 = disabled. */
1178
1185
  upstreamFailoverThreshold?: number;
1186
+ /**
1187
+ * Sliding 60s transient-failure ratio for Codex pool placement. Default on.
1188
+ * Set false to steer new threads from the consecutive counter only.
1189
+ */
1190
+ codexFailureWindow?: boolean;
1191
+ /**
1192
+ * What a manual pin does while its failure window is degraded.
1193
+ * `hold` keeps using it and logs a warning. `detour-new-threads` places only new threads elsewhere.
1194
+ */
1195
+ codexPinnedTransientPolicy?: "hold" | "detour-new-threads";
1196
+ /** Opt-in: retain one Codex WebSocket per account and thread across turns. Default off. */
1197
+ codexWsReuseAcrossTurns?: boolean;
1179
1198
  /**
1180
1199
  * Opt-in provider-origin circuit threshold for proven pre-connection reachability failures.
1181
1200
  * Default 0 (disabled); range 0..20. The circuit never counts timeouts or HTTP responses.
@@ -1216,21 +1235,7 @@ export interface OcxConfig {
1216
1235
  * upstream has just rate-limited only ever runs after a refusal, so stranding it while a
1217
1236
  * second logged-in account sits idle is a defect rather than a configuration choice.
1218
1237
  */
1219
- anthropicAccountPool?: {
1220
- enabled?: boolean;
1221
- /** Preserve native Claude Messages while the pool is enabled. Default true; false selects legacy translation. */
1222
- nativeMessages?: boolean;
1223
- /** Usage % threshold for new-session auto-pick. Default 80. 0 = disabled (affinity/active only). */
1224
- autoSwitchThreshold?: number;
1225
- /** New-session rotation strategy. Default quota (today's behaviour). */
1226
- strategy?: OcxAccountPoolRotationStrategy;
1227
- /** Successful new-session binds retained on one round-robin selection. Default 1; range 1..100. */
1228
- stickyLimit?: number;
1229
- /** Usage window for quota-based scoring. Default "five-hour" (today's behaviour). */
1230
- quotaWindow?: OcxAccountPoolQuotaWindow;
1231
- /** Ordered model allowlists; inactive while the pool is disabled. Stored account IDs only. */
1232
- routes?: AnthropicModelRoute[];
1233
- };
1238
+ anthropicAccountPool?: AnthropicAccountPoolConfig;
1234
1239
  /**
1235
1240
  * Generic OAuth multi-account PROACTIVE account preference (#2568, #695).
1236
1241
  *
@@ -1262,10 +1267,6 @@ export interface OcxConfig {
1262
1267
  corsAllowOrigins?: string[];
1263
1268
  }
1264
1269
 
1265
- export type OcxAccountPoolRotationStrategy = "quota" | "round-robin" | "fill-first";
1266
-
1267
- export type OcxAccountPoolQuotaWindow = "five-hour" | "weekly" | "max-utilization";
1268
-
1269
1270
  export type OcxComboStrategy = "failover" | "round-robin" | "random" | "least-used" | "reset-window" | "jev";
1270
1271
  export type OcxComboDefaultEffort = "low" | "medium" | "high" | "xhigh" | "max" | "ultra";
1271
1272
  export type OcxComboDefaultEffortMode = "fallback" | "force";
@@ -1526,6 +1527,8 @@ export interface OcxSearchConfig {
1526
1527
  }
1527
1528
 
1528
1529
  export interface OcxVisionSidecarConfig {
1530
+ /** Explicit Anthropic account pool; unset inherits the request's instance. */
1531
+ anthropicInstance?: AnthropicInstanceId;
1529
1532
  /** Master switch. Default: enabled when the selected backend has a usable credential. */
1530
1533
  enabled?: boolean;
1531
1534
  /**
@@ -1545,6 +1548,8 @@ export interface OcxVisionSidecarConfig {
1545
1548
  }
1546
1549
 
1547
1550
  export interface OcxWebSearchSidecarConfig {
1551
+ /** Explicit Anthropic account pool; unset inherits the request's instance. */
1552
+ anthropicInstance?: AnthropicInstanceId;
1548
1553
  /** Master switch. Default: enabled when a forward (ChatGPT) provider exists and the caller is logged in. */
1549
1554
  enabled?: boolean;
1550
1555
  /**
@@ -1,4 +1,5 @@
1
1
  import type { UpstreamHttpVersion, ReasoningSummaryDelivery, CodexAccountMode } from "./wire";
2
+ import type { AnthropicAccountPoolConfig } from "./anthropic-account-pool";
2
3
 
3
4
  /**
4
5
  * Per-provider proactive-refresh policy. The guardian only ever touches a provider whose EFFECTIVE
@@ -274,6 +275,10 @@ export interface ModelCapabilities {
274
275
  }
275
276
 
276
277
  export interface OcxProviderConfig {
278
+ /** Explicit builtin Pool 2 provenance; endpoints never imply ownership. */
279
+ anthropicOAuthInstance?: "anthropic2";
280
+ /** Independent Anthropic pool settings; valid only on providers.anthropic2. */
281
+ anthropicAccountPool?: AnthropicAccountPoolConfig;
277
282
  /** Optional browser-compatible outbound TLS profile; disabled by default. */
278
283
  tlsProfile?: "antigravity-browser";
279
284
  /** Optional short provider namespace used only at request/catalog presentation time. */
@@ -1,4 +1,5 @@
1
1
  import type { KiroOAuthMetadata } from "../oauth/types";
2
+ import type { NativeReasoningOwner } from "../responses/reasoning-replay-cache";
2
3
  import type { OcxTool, OcxToolChoice } from "./tools";
3
4
  import type { TierDecision, TierObservationContext } from "./provider";
4
5
 
@@ -57,6 +58,10 @@ export interface OcxParsedRequest {
57
58
  stream: boolean;
58
59
  options: OcxRequestOptions;
59
60
  _rawBody?: unknown;
61
+ /** Claude replay tags, retained only until each route binding verifies them. */
62
+ _nativeReasoningReplay?: ReadonlyMap<string, string>;
63
+ _nativeReasoningBoundOwner?: NativeReasoningOwner;
64
+ _nativeReasoningMint?: { owner?: NativeReasoningOwner };
60
65
  /**
61
66
  * Boundary between replayed history and this turn's newly appended input. Usually the
62
67
  * items the proxy restored from local previous_response_id state; also set when the
@@ -399,6 +399,13 @@ export function isAllowedToolChoice(value: OcxToolChoice | undefined): value is
399
399
  return typeof value === "object" && value !== null && "allowedTools" in value;
400
400
  }
401
401
 
402
+ export function requiresToolCall(choice: OcxToolChoice | undefined): boolean {
403
+ return choice === "required"
404
+ || (typeof choice === "object" && choice !== null && (
405
+ "name" in choice || ("mode" in choice && choice.mode === "required")
406
+ ));
407
+ }
408
+
402
409
  /** Compile the request's tool-choice policy into a reusable advertisement/restoration predicate. */
403
410
  export function toolChoiceToolPredicate(
404
411
  choice: OcxToolChoice | undefined,
package/src/types/wire.ts CHANGED
@@ -47,6 +47,7 @@ export const MODEL_ADAPTER_OVERRIDE_ALLOWED: ReadonlySet<string> = new Set([
47
47
  */
48
48
  const ANTHROPIC_WIRE_MODELS: Record<string, ReadonlySet<string>> = {
49
49
  "opencode-go": new Set([
50
+ "claude-haiku-5-5",
50
51
  "minimax-m2.5",
51
52
  "minimax-m2.7",
52
53
  "minimax-m3",
package/src/types.ts CHANGED
@@ -16,6 +16,7 @@ export {
16
16
  resolveToolChoiceWireName,
17
17
  modelInList,
18
18
  isAllowedToolChoice,
19
+ requiresToolCall,
19
20
  toolChoiceToolPredicate,
20
21
  declaresCodeModeExec,
21
22
  toolRestrictsCallers,
@@ -23,6 +24,9 @@ export {
23
24
  } from "./types/tools";
24
25
 
25
26
  export type { UpstreamHttpVersion, ReasoningSummaryDelivery, CodexAccountMode } from "./types/wire";
27
+ export type { AnthropicInstanceId } from "./providers/anthropic-instance-id";
28
+ export { ANTHROPIC_INSTANCE_IDS, ANTHROPIC_PRIMARY_INSTANCE, ANTHROPIC_POOL2_INSTANCE, isAnthropicInstanceId } from "./providers/anthropic-instance-id";
29
+ export type { AnthropicAccountPoolConfig, AnthropicModelRoute } from "./types/anthropic-account-pool";
26
30
  export {
27
31
  UPSTREAM_HTTP_VERSION_VALUES,
28
32
  REASONING_SUMMARY_DELIVERY_VALUES,
@@ -1,4 +1,5 @@
1
1
  import { spawn, spawnSync } from "node:child_process";
2
+ import { createSupervisionLatch, inspectDesktopSupervision } from "../service/desktop-supervision.mjs";
2
3
  import { manualUpdateFailureGuidance } from "./update-failure-guidance.mjs";
3
4
  import { STOP_HISTORY_INCOMPLETE_EXIT_CODE } from "./stop-contract.mjs";
4
5
  import { proxyIdentityAt } from "../server/proxy-liveness";
@@ -484,14 +485,17 @@ export async function runUpdate(): Promise<void> {
484
485
  } catch { /* best-effort */ }
485
486
  // What this update may do to the runtime. A desktop takeover vetoes both the stop and the
486
487
  // service refresh below; see `planUpdateRuntimeHandling` for why each half is wrong.
488
+ const supervisionLatch = createSupervisionLatch();
489
+ const observeSupervision = () => supervisionLatch.observe(inspectDesktopSupervision());
487
490
  const initialOwnership = await resolvedRuntimeOwnership();
488
491
  const runtimePlan = planUpdateRuntimeHandling({
489
492
  ...initialOwnership,
490
493
  serviceInstalled: serviceWasInstalled,
494
+ supervision: observeSupervision(),
491
495
  });
492
496
  if (runtimePlan.notice) console.log(runtimePlan.notice);
493
497
  if (!runtimePlan.mayReplacePackage) {
494
- console.error("⚠️ Update stopped before tray handoff, runtime stop, or package replacement because runtime ownership is unknown.");
498
+ console.error("⚠️ Update stopped before tray handoff, runtime stop, or package replacement because runtime authority does not permit it.");
495
499
  return 1;
496
500
  }
497
501
  let trayWasInstalled = false;
@@ -548,6 +552,15 @@ export async function runUpdate(): Promise<void> {
548
552
  && before?.consentGeneration === after?.consentGeneration;
549
553
  };
550
554
  const startProxyDirectly = async (): Promise<boolean> => {
555
+ const ownership = await resolvedRuntimeOwnership();
556
+ const supervision = observeSupervision();
557
+ const plan = planUpdateRuntimeHandling({ ...ownership, serviceInstalled: false, supervision });
558
+ if (!plan.mayStopRuntime) {
559
+ console.warn(supervision
560
+ ? "OpenCodex Desktop supervises the proxy; no CLI runtime was restored."
561
+ : plan.notice);
562
+ return false;
563
+ }
551
564
  if (!postUpdateLauncherUsable || !existsSync(postUpdateLauncher)) return false;
552
565
  // An ordinary owner: a stray sibling marker would otherwise mark it before any probe.
553
566
  const env = mutation.controlEnvironment(withoutSiblingMarker(process.env));
@@ -574,7 +587,7 @@ export async function runUpdate(): Promise<void> {
574
587
  const planRecovery = async () => {
575
588
  const current = await resolvedRuntimeOwnership();
576
589
  return planStoppedRuntimeRecovery({
577
- stopAttempted, ...current, sameOwner: sameOwner(current),
590
+ stopAttempted, ...current, sameOwner: sameOwner(current), supervision: observeSupervision(),
578
591
  liveness: currentPackageRuntimeLiveness(), serviceInstalled: serviceWasInstalled,
579
592
  launcherUsable: postUpdateLauncherUsable && existsSync(postUpdateLauncher), hadRuntimeState,
580
593
  });
@@ -588,10 +601,17 @@ export async function runUpdate(): Promise<void> {
588
601
  mutation.release();
589
602
  recovery = await planRecovery();
590
603
  }
591
- if (recovery.action === "manual") {
604
+ if (recovery.reason === "desktop-supervised") {
605
+ console.log("OpenCodex Desktop supervises the proxy; no CLI runtime was restored.");
606
+ } else if (recovery.action === "manual") {
592
607
  console.warn(`⚠️ ${reason}; runtime recovery requires manual review (${recovery.reason}).`);
593
608
  } else if (recovery.action === "service") {
594
609
  const { serviceReinstallArgs, isServiceViable } = await import("../service");
610
+ recovery = await planRecovery();
611
+ if (recovery.action !== "service") {
612
+ console.warn("Runtime authority changed before service recovery; no CLI runtime was restored.");
613
+ return;
614
+ }
595
615
  const service = spawnSync(process.execPath, [postUpdateLauncher, ...serviceReinstallArgs()], {
596
616
  stdio: updateChildStdio(), windowsHide: true,
597
617
  env: mutation.controlEnvironment({ ...process.env, OCX_BAKE_PORT: String(capturedListen.port) }),
@@ -602,7 +622,7 @@ export async function runUpdate(): Promise<void> {
602
622
  mutation.reacquire();
603
623
  const nowOwned = await resolvedRuntimeOwnership();
604
624
  const fallback = planStoppedRuntimeRecovery({
605
- stopAttempted, ...nowOwned, sameOwner: sameOwner(nowOwned),
625
+ stopAttempted, ...nowOwned, sameOwner: sameOwner(nowOwned), supervision: observeSupervision(),
606
626
  liveness: currentPackageRuntimeLiveness(), serviceInstalled: false,
607
627
  launcherUsable: postUpdateLauncherUsable && existsSync(postUpdateLauncher), hadRuntimeState,
608
628
  });
@@ -632,6 +652,15 @@ export async function runUpdate(): Promise<void> {
632
652
  // Full `ocx stop` semantics (drain, service stop, restore).
633
653
 
634
654
  if (runtimePlan.mayStopRuntime && (serviceWasInstalled || readPid() || readRuntimePort() || pendingTeardownOutstanding())) {
655
+ const preStopPlan = planUpdateRuntimeHandling({
656
+ ...(await resolvedRuntimeOwnership()),
657
+ serviceInstalled: serviceWasInstalled,
658
+ supervision: supervisionLatch.observe(inspectDesktopSupervision({ targetPid: runtimeTrusted ? livePid : undefined })),
659
+ });
660
+ if (!preStopPlan.mayStopRuntime) {
661
+ console.error(preStopPlan.notice);
662
+ return 1;
663
+ }
635
664
  stopAttempted = true;
636
665
  console.log("⏹ Stopping the running proxy before updating...");
637
666
  const stopStdio = updateChildStdio();
@@ -701,13 +730,14 @@ export async function runUpdate(): Promise<void> {
701
730
  stderr?: string | Buffer | null;
702
731
  } | null = null;
703
732
  let replacementRefusal: string | null = null;
704
- // Ownership can change while registry work is in flight. Unknown at this exact
705
- // boundary blocks replacement; a confirmed desktop claim still permits updating the idle
706
- // npm installation while leaving the bundled sidecar alone.
733
+ // Re-read durable ownership and live supervision before package replacement.
734
+ // Desktop supervision and foreign/unknown ownership veto replacement.
735
+ // Plain unknown supervision preserves the existing ownership/liveness decision.
707
736
  const replacementOwnership = await resolvedRuntimeOwnership();
708
737
  const replacementPlan = planUpdateRuntimeHandling({
709
738
  ...replacementOwnership,
710
739
  serviceInstalled: serviceWasInstalled,
740
+ supervision: observeSupervision(),
711
741
  });
712
742
  const replacementLiveness = currentPackageRuntimeLiveness();
713
743
  if (replacementOwnership.subjectToken !== initialOwnership.subjectToken
@@ -786,9 +816,11 @@ export async function runUpdate(): Promise<void> {
786
816
  const postInstallPlan = planUpdateRuntimeHandling({
787
817
  ...(await resolvedRuntimeOwnership()),
788
818
  serviceInstalled: serviceWasInstalled,
819
+ supervision: observeSupervision(),
789
820
  });
790
821
  if (r.status === 0) {
791
822
  console.log(`\n✅ Updated${latest ? ` to v${latest}` : ""}.`);
823
+ if (!postInstallPlan.mayStopRuntime) console.warn("Runtime authority does not permit CLI recovery; no service was refreshed or proxy started.");
792
824
  // Re-enter through the verified active package launcher. This keeps the Codex
793
825
  // shim, tray, service and proxy recovery paths on the same package/group that
794
826
  // pnpm selected, including when the update changed the global link target.
@@ -819,6 +851,16 @@ export async function runUpdate(): Promise<void> {
819
851
  // (spawn the fresh cli.ts so updated code writes the baked paths) so a
820
852
  // launchd/schtasks/systemd user isn't left with the background proxy down.
821
853
  if (postInstallPlan.mayRestoreService) {
854
+ const mayRefresh = async () => {
855
+ const ownership = await resolvedRuntimeOwnership();
856
+ const supervision = observeSupervision();
857
+ const plan = planUpdateRuntimeHandling({ ...ownership, serviceInstalled: true, supervision });
858
+ if (!plan.mayRestoreService) console.warn(supervision
859
+ ? "OpenCodex Desktop supervises the proxy; CLI recovery was skipped. Use the app's updater (tray → Check for Updates)."
860
+ : plan.notice);
861
+ return plan.mayRestoreService;
862
+ };
863
+ if (!await mayRefresh()) return;
822
864
  console.log("🔁 Refreshing the background service with the updated files...");
823
865
  const { serviceReinstallArgs } = await import("../service");
824
866
  const { reclaimListenPort } = await import("../server/port-reclaim");
@@ -840,6 +882,7 @@ export async function runUpdate(): Promise<void> {
840
882
  const prevBake = process.env.OCX_BAKE_PORT;
841
883
  process.env.OCX_BAKE_PORT = String(capturedListen.port);
842
884
  try {
885
+ if (!await mayRefresh()) return;
843
886
  const svcStdio = updateChildStdio();
844
887
  const svc = spawnSync(process.execPath, [postUpdateLauncher, ...serviceReinstallArgs()], {
845
888
  env: mutation.controlEnvironment(),
@@ -889,12 +932,17 @@ export async function runUpdate(): Promise<void> {
889
932
  console.warn(` Run 'ocx service repair', then 'ocx start --port ${capturedListen.port}'.`);
890
933
  return 1;
891
934
  }
935
+ const fallbackOwnership = await resolvedRuntimeOwnership();
936
+ const supervision = observeSupervision();
892
937
  const nowOwned = planUpdateRuntimeHandling({
893
- ...(await resolvedRuntimeOwnership()),
938
+ ...fallbackOwnership,
894
939
  serviceInstalled: true,
940
+ supervision,
895
941
  });
896
942
  if (!nowOwned.mayStopRuntime) {
897
- console.warn(nowOwned.notice ?? "⚠️ The background runtime is owned elsewhere; not starting a second proxy.");
943
+ console.warn(supervision
944
+ ? "OpenCodex Desktop supervises the proxy; CLI recovery was skipped. Use the app's updater (tray → Check for Updates)."
945
+ : nowOwned.notice ?? "⚠️ The background runtime is owned elsewhere; not starting a second proxy.");
898
946
  return;
899
947
  }
900
948
  console.warn(
@@ -6,6 +6,8 @@ import {
6
6
  OWNERSHIP_MUTATION_LEASE_TOKEN_ENV,
7
7
  } from "../service/ownership-mutation-lease.mjs";
8
8
  import { planUpdateRuntimeHandling } from "./runtime-ownership.mjs";
9
+ import { createSupervisionLatch, inspectDesktopSupervision } from "../service/desktop-supervision.mjs";
10
+ type SupervisionInspector = typeof inspectDesktopSupervision;
9
11
 
10
12
  export type { ServiceOwnershipResolution };
11
13
 
@@ -24,6 +26,8 @@ export type { ServiceOwnershipResolution };
24
26
  */
25
27
  export function updateRestartVeto(
26
28
  resolve: () => ServiceOwnershipResolution = resolveServiceOwnership,
29
+ inspect: SupervisionInspector = inspectDesktopSupervision,
30
+ latch = createSupervisionLatch(),
27
31
  ): string | null {
28
32
  const owner = resolve();
29
33
  const plan = planUpdateRuntimeHandling({
@@ -31,6 +35,7 @@ export function updateRestartVeto(
31
35
  ownershipUnknown: owner.kind === "unknown",
32
36
  // The restart decision does not refresh the service; only the stop veto is read here.
33
37
  serviceInstalled: false,
38
+ supervision: latch.observe(inspect()),
34
39
  });
35
40
  if (plan.mayStopRuntime) return null;
36
41
  return plan.notice ?? "The background runtime is owned elsewhere; it was left running.";
@@ -78,7 +83,9 @@ const REACQUIRE_WAIT_MS = 10_000;
78
83
  export async function runUpdateRestartWithOwnershipLease<T>(
79
84
  resolve: (() => ServiceOwnershipResolution) | undefined,
80
85
  restart: (lease: UpdateRestartLeaseControl) => Promise<T>,
86
+ inspect: SupervisionInspector = inspectDesktopSupervision,
81
87
  ): Promise<{ readonly kind: "veto"; readonly notice: string } | { readonly kind: "ran"; readonly value: T }> {
88
+ const latch = createSupervisionLatch();
82
89
  let lease = acquireOwnershipMutationLease(serviceStatePaths());
83
90
  const previous = process.env[OWNERSHIP_MUTATION_LEASE_TOKEN_ENV];
84
91
  process.env[OWNERSHIP_MUTATION_LEASE_TOKEN_ENV] = lease.token;
@@ -107,11 +114,11 @@ export async function runUpdateRestartWithOwnershipLease<T>(
107
114
  heldNow = true;
108
115
  process.env[OWNERSHIP_MUTATION_LEASE_TOKEN_ENV] = lease.token;
109
116
  }
110
- const veto = updateRestartVeto(resolve);
117
+ const veto = updateRestartVeto(resolve, inspect, latch);
111
118
  return veto ? { notice: veto, failed: false } : null;
112
119
  };
113
120
  try {
114
- const veto = updateRestartVeto(resolve);
121
+ const veto = updateRestartVeto(resolve, inspect, latch);
115
122
  return veto
116
123
  ? { kind: "veto", notice: veto }
117
124
  : {
@@ -119,7 +126,7 @@ export async function runUpdateRestartWithOwnershipLease<T>(
119
126
  value: await restart({
120
127
  releaseForServiceManager: release,
121
128
  reacquireForDirectStart,
122
- vetoAgain: () => updateRestartVeto(resolve),
129
+ vetoAgain: () => updateRestartVeto(resolve, inspect, latch),
123
130
  }),
124
131
  };
125
132
  } finally {
@@ -1,6 +1,10 @@
1
+ import type { SupervisionEvidence } from "../service/desktop-supervision.mjs";
2
+
1
3
  export declare function planUpdateRuntimeHandling(input: {
2
4
  ownership: { owner: string; installId: string; consentGeneration: number } | null;
3
5
  ownershipUnknown?: boolean;
6
+ /** Fresh evidence or the operation's supervision latch verdict. */
7
+ supervision?: SupervisionEvidence | boolean;
4
8
  serviceInstalled: boolean;
5
9
  }): {
6
10
  mayReplacePackage: boolean;
@@ -13,6 +17,8 @@ export declare function planStoppedRuntimeRecovery(input: {
13
17
  stopAttempted: boolean;
14
18
  ownership: { owner: string; installId: string; consentGeneration: number } | null;
15
19
  ownershipUnknown?: boolean;
20
+ /** Fresh evidence or the operation's supervision latch verdict. */
21
+ supervision?: SupervisionEvidence | boolean;
16
22
  sameOwner: boolean;
17
23
  liveness: "live" | "dead" | "unknown";
18
24
  serviceInstalled: boolean;
@@ -7,6 +7,11 @@
7
7
  * situation separately is how a fix ships on one side only.
8
8
  */
9
9
 
10
+ function desktopSupervisionBlocked(supervision) {
11
+ return supervision === true || supervision?.kind === "desktop"
12
+ || (supervision?.kind === "unknown" && supervision.desktopSeen);
13
+ }
14
+
10
15
  /**
11
16
  * Decide how an update treats a runtime it may not own.
12
17
  *
@@ -21,11 +26,11 @@
21
26
  * The service registration itself is untouched in every case. It is kept by decision, not by
22
27
  * accident, so a user who later runs `ocx service install` gets their npm service back.
23
28
  *
24
- * THE COST OF A STALE MARKER. This reads the recorded claim, not liveness. An app deleted
25
- * without releasing ownership leaves a marker behind, and an update then declines to stop or
26
- * refresh a runtime no app is managing any more. That is the orphan-recovery cost the
27
- * two-record ownership design accepted; `ocx service install` clears the marker and restores
28
- * the ordinary path.
29
+ * Durable ownership and live supervision are separate. Desktop supervision denies package
30
+ * replacement, stop and restoration even without a claim. A latch retains that veto through
31
+ * inconclusive probes until a positive none. Plain unknown supervision alone keeps existing
32
+ * behavior; unknown durable ownership still vetoes. Explicit service install recovers a stale
33
+ * durable claim after Desktop has quit.
29
34
  *
30
35
  * The three returned flags are separate authorities, not commands. In particular, leaving
31
36
  * a runtime running is not permission to replace the package it may be executing from.
@@ -34,10 +39,19 @@
34
39
  * carries installation identity, it therefore blocks package replacement as well as stop and
35
40
  * restoration; the notice tells a stale-marker user how to take ownership back explicitly.
36
41
  *
37
- * @param {{ ownership: { owner: string, installId: string, consentGeneration: number } | null, ownershipUnknown?: boolean, serviceInstalled: boolean }} input
42
+ * @param {{ ownership: { owner: string, installId: string, consentGeneration: number } | null, ownershipUnknown?: boolean, serviceInstalled: boolean, supervision?: boolean | ReturnType<typeof import('../service/desktop-supervision.mjs').inspectDesktopSupervision> }} input
38
43
  * @returns {{ mayReplacePackage: boolean, mayStopRuntime: boolean, mayRestoreService: boolean, notice: string | null }}
39
44
  */
40
- export function planUpdateRuntimeHandling({ ownership, ownershipUnknown = false, serviceInstalled }) {
45
+ export function planUpdateRuntimeHandling({ ownership, ownershipUnknown = false, serviceInstalled, supervision }) {
46
+ if (desktopSupervisionBlocked(supervision)) {
47
+ return {
48
+ mayReplacePackage: false,
49
+ mayStopRuntime: false,
50
+ mayRestoreService: false,
51
+ notice: "OpenCodex Desktop runs this proxy from its own bundle; use the app's updater (tray → Check for Updates). "
52
+ + "This npm/Bun install was left unchanged; quit OpenCodex first to update it.",
53
+ };
54
+ }
41
55
  // Unreadable, malformed or contradictory is not "nobody owns it". Reading it that way is
42
56
  // how a permissions error reactivates the npm launcher over a consented takeover.
43
57
  if (ownershipUnknown) {
@@ -77,6 +91,7 @@ export function planUpdateRuntimeHandling({ ownership, ownershipUnknown = false,
77
91
  /** Decide recovery after this updater already stopped the prior CLI-owned runtime. */
78
92
  export function planStoppedRuntimeRecovery({
79
93
  stopAttempted,
94
+ supervision,
80
95
  ownership,
81
96
  ownershipUnknown = false,
82
97
  sameOwner,
@@ -86,6 +101,7 @@ export function planStoppedRuntimeRecovery({
86
101
  hadRuntimeState,
87
102
  }) {
88
103
  if (!stopAttempted) return { action: "none", reason: "not-stopped" };
104
+ if (desktopSupervisionBlocked(supervision)) return { action: "none", reason: "desktop-supervised" };
89
105
  if (ownershipUnknown) return { action: "manual", reason: "ownership-unknown" };
90
106
  if (!sameOwner || (ownership && ownership.owner !== "cli")) {
91
107
  return { action: "none", reason: "ownership-transferred" };
package/src/usage/cost.ts CHANGED
@@ -30,6 +30,7 @@ import {
30
30
  cursorFastPriceSupported,
31
31
  findContextTier,
32
32
  isLongContext,
33
+ pricingFamilyProvider,
33
34
  type Cost4,
34
35
  type ExpectedPriceOverlay,
35
36
  type ExpectedPriceStatus,
@@ -262,7 +263,7 @@ function resolveMatchedPriceExact(
262
263
  if (userOverlay) return userOverlay;
263
264
  if (!cursorFastPriceSupported(provider, modelId)) return null;
264
265
  const verifiedOverride = overlays === EXPECTED_PRICE_OVERLAYS
265
- ? findVerifiedPriceOverride(provider, modelId)
266
+ ? findVerifiedPriceOverride(pricingFamilyProvider(provider), modelId)
266
267
  : undefined;
267
268
  if (verifiedOverride && verifiedOverride.status !== "unverified" && validCost4(verifiedOverride.cost4) && hasNonZeroCost(verifiedOverride.cost4)) {
268
269
  return {
@@ -291,7 +292,7 @@ function resolveMatchedPriceExact(
291
292
  ...cursorFastPriceProvenance(provider, modelId),
292
293
  };
293
294
  }
294
- const overlay = findExpectedPriceOverlay(provider, modelId, overlays);
295
+ const overlay = findExpectedPriceOverlay(overlays === EXPECTED_PRICE_OVERLAYS ? pricingFamilyProvider(provider) : provider, modelId, overlays);
295
296
  if (!overlay || !validCost4(overlay.cost4) || !hasNonZeroCost(overlay.cost4)) {
296
297
  if (options.allowModelLevelFallback === false) return null;
297
298
  const fallback = resolveModelLevelPrice(provider, modelId);