@iislee/opencodex 2.11.0 → 2.31.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 (675) hide show
  1. package/AGENTS_INSTALL.md +109 -0
  2. package/README.md +114 -19
  3. package/bin/ocx.mjs +164 -36
  4. package/bin/package-main.mjs +1 -1
  5. package/gui/dist/assets/index-BF38heuV.js +104 -0
  6. package/gui/dist/assets/index-DMiI18Kv.css +1 -0
  7. package/gui/dist/index.html +2 -2
  8. package/gui/dist/provider-icons/alibaba-color.svg +1 -1
  9. package/gui/dist/provider-icons/antigravity-color.svg +1 -1
  10. package/gui/dist/provider-icons/claude-color.svg +1 -1
  11. package/gui/dist/provider-icons/cline-color.svg +16 -0
  12. package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -1
  13. package/gui/dist/provider-icons/commandcode-color.svg +1 -0
  14. package/gui/dist/provider-icons/copilot-color.svg +1 -1
  15. package/gui/dist/provider-icons/cursor-color.svg +1 -1
  16. package/gui/dist/provider-icons/deepseek-color.svg +1 -1
  17. package/gui/dist/provider-icons/firepass-color.svg +1 -1
  18. package/gui/dist/provider-icons/fireworks-color.svg +1 -1
  19. package/gui/dist/provider-icons/gemini-color.svg +1 -1
  20. package/gui/dist/provider-icons/github-copilot-color.svg +1 -1
  21. package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -1
  22. package/gui/dist/provider-icons/grok.svg +1 -1
  23. package/gui/dist/provider-icons/groq-color.svg +1 -1
  24. package/gui/dist/provider-icons/huggingface-color.svg +1 -1
  25. package/gui/dist/provider-icons/kimi-color.svg +1 -1
  26. package/gui/dist/provider-icons/kiro-color.svg +2 -2
  27. package/gui/dist/provider-icons/lm-studio-color.svg +1 -1
  28. package/gui/dist/provider-icons/mistral-color.svg +1 -1
  29. package/gui/dist/provider-icons/moonshot-color.svg +1 -1
  30. package/gui/dist/provider-icons/nvidia-color.svg +1 -1
  31. package/gui/dist/provider-icons/ollama-color.svg +1 -1
  32. package/gui/dist/provider-icons/openai.svg +1 -1
  33. package/gui/dist/provider-icons/opencode.svg +2 -1
  34. package/gui/dist/provider-icons/openrouter-color.svg +1 -1
  35. package/gui/dist/provider-icons/pi.svg +2 -2
  36. package/gui/dist/provider-icons/qianfan-color.svg +1 -1
  37. package/gui/dist/provider-icons/qwen-portal-color.svg +1 -1
  38. package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -1
  39. package/gui/dist/provider-icons/vllm-color.svg +1 -1
  40. package/gui/dist/provider-icons/xiaomi-color.svg +1 -1
  41. package/package.json +19 -10
  42. package/src/adapters/anthropic-output-schema.ts +137 -0
  43. package/src/adapters/anthropic.ts +376 -52
  44. package/src/adapters/base.ts +54 -7
  45. package/src/adapters/client-fingerprint.ts +18 -12
  46. package/src/adapters/cline-pass-deepseek-v4-tool-replay.ts +69 -0
  47. package/src/adapters/command-code.ts +601 -0
  48. package/src/adapters/cursor/checkpoint-store.ts +303 -0
  49. package/src/adapters/cursor/cursor-errors.ts +129 -6
  50. package/src/adapters/cursor/discovery.ts +61 -4
  51. package/src/adapters/cursor/effort-map.ts +27 -3
  52. package/src/adapters/cursor/framing.ts +39 -0
  53. package/src/adapters/cursor/h2-pool.ts +123 -0
  54. package/src/adapters/cursor/http1-bidi.ts +361 -0
  55. package/src/adapters/cursor/images.ts +704 -0
  56. package/src/adapters/cursor/live-models.ts +174 -58
  57. package/src/adapters/cursor/live-transport.ts +609 -170
  58. package/src/adapters/cursor/native-exec-common.ts +23 -2
  59. package/src/adapters/cursor/native-exec-fs.ts +10 -7
  60. package/src/adapters/cursor/native-exec-network.ts +1 -1
  61. package/src/adapters/cursor/native-exec-shell.ts +0 -1
  62. package/src/adapters/cursor/native-exec.ts +101 -14
  63. package/src/adapters/cursor/protobuf-events.ts +829 -11
  64. package/src/adapters/cursor/protobuf-request.ts +383 -65
  65. package/src/adapters/cursor/request-builder.ts +237 -31
  66. package/src/adapters/cursor/tool-definitions.ts +242 -12
  67. package/src/adapters/cursor/tool-result-normalize.ts +92 -0
  68. package/src/adapters/cursor/transport.ts +22 -0
  69. package/src/adapters/cursor/types.ts +28 -1
  70. package/src/adapters/cursor.ts +133 -7
  71. package/src/adapters/google-antigravity-replay.ts +558 -34
  72. package/src/adapters/google-antigravity-wire.ts +43 -10
  73. package/src/adapters/google-http.ts +38 -10
  74. package/src/adapters/google-tool-schema.ts +80 -15
  75. package/src/adapters/google-truncation.ts +11 -0
  76. package/src/adapters/google.ts +618 -74
  77. package/src/adapters/identity.ts +39 -6
  78. package/src/adapters/kiro-errors.ts +11 -0
  79. package/src/adapters/kiro-events.ts +19 -1
  80. package/src/adapters/kiro-thinking.ts +18 -2
  81. package/src/adapters/kiro-tools.ts +10 -1
  82. package/src/adapters/kiro.ts +92 -54
  83. package/src/adapters/mimo-free.ts +17 -0
  84. package/src/adapters/openai-chat-url.ts +11 -0
  85. package/src/adapters/openai-chat.ts +1311 -336
  86. package/src/adapters/openai-responses-url.ts +16 -0
  87. package/src/adapters/openai-responses.ts +830 -56
  88. package/src/adapters/registry.ts +175 -0
  89. package/src/adapters/responses-tool-schema.ts +67 -0
  90. package/src/adapters/tool-call-id.ts +119 -0
  91. package/src/adapters/tool-catalog-nudge.ts +104 -21
  92. package/src/adapters/xai-web-search.ts +185 -0
  93. package/src/bridge.ts +428 -61
  94. package/src/chat/inbound.ts +43 -19
  95. package/src/chat/outbound.ts +82 -26
  96. package/src/claude/agents-inject.ts +32 -9
  97. package/src/claude/context-windows.ts +21 -5
  98. package/src/claude/desktop-3p.ts +243 -9
  99. package/src/claude/gateway-cache.ts +41 -4
  100. package/src/claude/inbound.ts +72 -3
  101. package/src/claude/model-info.ts +38 -15
  102. package/src/claude/outbound.ts +70 -16
  103. package/src/cli/account-api.ts +35 -1
  104. package/src/cli/account-auth.ts +33 -6
  105. package/src/cli/account-catalog-refresh.ts +14 -0
  106. package/src/cli/account-extended.ts +389 -2
  107. package/src/cli/account-main.ts +317 -0
  108. package/src/cli/account.ts +30 -6
  109. package/src/cli/agent.ts +45 -1
  110. package/src/cli/claude-agent-startup-sync.ts +73 -0
  111. package/src/cli/claude-desktop.ts +29 -4
  112. package/src/cli/claude.ts +103 -34
  113. package/src/cli/codex-log-guard-doctor.ts +103 -0
  114. package/src/cli/codex-shim-autorestore.ts +2 -0
  115. package/src/cli/codex-shim-readiness.ts +76 -0
  116. package/src/cli/combo.ts +8 -0
  117. package/src/cli/config-command.ts +74 -10
  118. package/src/cli/dispatch.ts +593 -0
  119. package/src/cli/doctor.ts +315 -43
  120. package/src/cli/ensure-desired-integrations.ts +152 -0
  121. package/src/cli/export-command.ts +46 -20
  122. package/src/cli/help.ts +20 -271
  123. package/src/cli/index.ts +378 -519
  124. package/src/cli/init.ts +4 -17
  125. package/src/cli/integrations.ts +120 -2
  126. package/src/cli/lab.ts +607 -0
  127. package/src/cli/launcher-context.ts +77 -0
  128. package/src/cli/minimax.ts +497 -0
  129. package/src/cli/models-runtime.ts +35 -2
  130. package/src/cli/models.ts +100 -14
  131. package/src/cli/observe.ts +92 -3
  132. package/src/cli/opencode.ts +4 -2
  133. package/src/cli/provider-runtime.ts +18 -1
  134. package/src/cli/provider.ts +24 -3
  135. package/src/cli/ready.ts +301 -0
  136. package/src/cli/registry.ts +437 -0
  137. package/src/cli/root.ts +86 -0
  138. package/src/cli/route-policy.ts +92 -0
  139. package/src/cli/runtime-api.ts +6 -3
  140. package/src/cli/star-prompt.ts +71 -15
  141. package/src/cli/status.ts +10 -3
  142. package/src/cli/system-restart-client.ts +146 -0
  143. package/src/cli/tray-proxy.ts +153 -6
  144. package/src/cli/v2.ts +105 -10
  145. package/src/cli.ts +1 -1
  146. package/src/clients/config-export.ts +1358 -21
  147. package/src/codex/account-label.ts +14 -1
  148. package/src/codex/account-lifecycle.ts +130 -13
  149. package/src/codex/account-namespaces.ts +49 -3
  150. package/src/codex/account-priority.ts +83 -0
  151. package/src/codex/account-store.ts +29 -2
  152. package/src/codex/account-usability.ts +25 -2
  153. package/src/codex/admission.ts +256 -0
  154. package/src/codex/affinity-debug.ts +162 -0
  155. package/src/codex/app-server-processes.ts +493 -106
  156. package/src/codex/app-server-restart-service.ts +232 -0
  157. package/src/codex/auth-api.ts +849 -242
  158. package/src/codex/auth-collision.ts +5 -3
  159. package/src/codex/auth-context.ts +345 -32
  160. package/src/codex/autostart-health.ts +8 -1
  161. package/src/codex/catalog/account-models.ts +67 -0
  162. package/src/codex/catalog/aggregation.ts +68 -10
  163. package/src/codex/catalog/bundled.ts +331 -33
  164. package/src/codex/catalog/effort.ts +121 -30
  165. package/src/codex/catalog/filesystem-evidence.ts +302 -0
  166. package/src/codex/catalog/kinds.ts +2 -0
  167. package/src/codex/catalog/metadata.ts +529 -45
  168. package/src/codex/catalog/native-models.ts +72 -0
  169. package/src/codex/catalog/parsing.ts +224 -30
  170. package/src/codex/catalog/provider-fetch.ts +1460 -134
  171. package/src/codex/catalog/sync.ts +1449 -186
  172. package/src/codex/catalog-admission.ts +199 -0
  173. package/src/codex/catalog-refresh-status.ts +105 -0
  174. package/src/codex/catalog-write-serialization.ts +242 -0
  175. package/src/codex/catalog.ts +6 -3
  176. package/src/codex/codex-write-lock.ts +384 -0
  177. package/src/codex/convergence-types.ts +614 -0
  178. package/src/codex/convergence.ts +651 -0
  179. package/src/codex/coordinator-doctor.ts +332 -0
  180. package/src/codex/custom-model-catalog-migration.ts +176 -0
  181. package/src/codex/desired-state.ts +230 -0
  182. package/src/codex/features.ts +636 -39
  183. package/src/codex/generation.ts +202 -0
  184. package/src/codex/history-job.ts +407 -0
  185. package/src/codex/history-lock.ts +242 -0
  186. package/src/codex/history-migration-guardian.ts +26 -20
  187. package/src/codex/history-provider.ts +231 -28
  188. package/src/codex/history-transition.ts +105 -0
  189. package/src/codex/history-worker.ts +220 -0
  190. package/src/codex/inject-coordination.ts +290 -0
  191. package/src/codex/inject.ts +1073 -152
  192. package/src/codex/injected-marker.ts +37 -3
  193. package/src/codex/integration-record.ts +266 -0
  194. package/src/codex/internal/catalog-writer.ts +203 -0
  195. package/src/codex/internal/history-writer.ts +80 -0
  196. package/src/codex/journal.ts +66 -4
  197. package/src/codex/log-guard/inspect.ts +506 -0
  198. package/src/codex/log-guard/lock.ts +150 -0
  199. package/src/codex/log-guard/maintenance.ts +403 -0
  200. package/src/codex/log-guard/path-safety.ts +88 -0
  201. package/src/codex/log-guard/policy.ts +44 -0
  202. package/src/codex/log-guard/processes.ts +205 -0
  203. package/src/codex/log-guard/protection.ts +489 -0
  204. package/src/codex/log-guard/sqlite-errors.ts +9 -0
  205. package/src/codex/main-account-cache.ts +24 -0
  206. package/src/codex/main-account.ts +29 -1
  207. package/src/codex/management-convergence.ts +167 -0
  208. package/src/codex/model-cache.ts +56 -10
  209. package/src/codex/model-entitlements.ts +353 -0
  210. package/src/codex/native-main-admission.ts +47 -0
  211. package/src/codex/native-main-auth-temp.ts +187 -0
  212. package/src/codex/native-main-claim.ts +178 -0
  213. package/src/codex/native-main-lock-file.ts +162 -0
  214. package/src/codex/native-main-owner.ts +329 -0
  215. package/src/codex/native-profile-api.ts +247 -0
  216. package/src/codex/native-profile-manager.ts +1531 -0
  217. package/src/codex/native-profile-processes.ts +121 -0
  218. package/src/codex/native-profile-recovery.ts +99 -0
  219. package/src/codex/native-profile-stage-store.ts +387 -0
  220. package/src/codex/native-profile-startup.ts +492 -0
  221. package/src/codex/native-profile-store.ts +855 -0
  222. package/src/codex/native-profile-types.ts +120 -0
  223. package/src/codex/native-residue.ts +682 -0
  224. package/src/codex/paths.ts +80 -1
  225. package/src/codex/plan-from-token.ts +140 -0
  226. package/src/codex/plan.ts +40 -0
  227. package/src/codex/plugins-doctor.ts +1 -1
  228. package/src/codex/pool-rotation.ts +74 -4
  229. package/src/codex/project-config-warnings.ts +20 -6
  230. package/src/codex/prompt-journal.ts +352 -0
  231. package/src/codex/prompt-layers.ts +967 -0
  232. package/src/codex/prompt-lock.ts +143 -0
  233. package/src/codex/quota-rejection.ts +298 -0
  234. package/src/codex/quota.ts +175 -13
  235. package/src/codex/refresh.ts +11 -2
  236. package/src/codex/reset-credit-recovery.ts +1044 -0
  237. package/src/codex/routing.ts +505 -94
  238. package/src/codex/runtime.ts +159 -38
  239. package/src/codex/shim.ts +1009 -28
  240. package/src/codex/subagent-model-fallback.ts +350 -35
  241. package/src/codex/sync.ts +191 -2
  242. package/src/codex/transition-state.ts +612 -0
  243. package/src/codex/upstream-host-health.ts +368 -0
  244. package/src/codex/user-identity.ts +557 -0
  245. package/src/codex/warmup.ts +187 -81
  246. package/src/codex/write-coordination.ts +114 -0
  247. package/src/combos/failover.ts +20 -0
  248. package/src/combos/index.ts +4 -0
  249. package/src/combos/request.ts +32 -0
  250. package/src/combos/types.ts +81 -9
  251. package/src/config/provider-name.ts +24 -0
  252. package/src/config.ts +1762 -140
  253. package/src/generated/compatibility-version.json +3164 -0
  254. package/src/generated/{jawcode-model-metadata.ts → model-metadata.ts} +19 -17
  255. package/src/grok/inject.ts +16 -5
  256. package/src/grok/inspect.ts +45 -0
  257. package/src/grok/sync.ts +2 -2
  258. package/src/images/loop.ts +152 -29
  259. package/src/images/plan.ts +23 -13
  260. package/src/integrations/config-io.ts +269 -0
  261. package/src/integrations/journal.ts +315 -0
  262. package/src/integrations/merge.ts +135 -0
  263. package/src/integrations/mutation-flight.ts +71 -0
  264. package/src/integrations/native/ownership-preflight.ts +202 -0
  265. package/src/integrations/omp-yaml-source.ts +358 -0
  266. package/src/integrations/owned-refresh.ts +74 -0
  267. package/src/integrations/ownership.ts +111 -0
  268. package/src/integrations/registry.ts +159 -0
  269. package/src/integrations/serialize.ts +314 -0
  270. package/src/integrations/state.ts +361 -0
  271. package/src/integrations/store.ts +103 -0
  272. package/src/integrations/writer-lock.ts +98 -0
  273. package/src/integrations/writer.ts +691 -0
  274. package/src/lab/artifacts/sanitize.ts +586 -0
  275. package/src/lab/artifacts/secure-fs.ts +475 -0
  276. package/src/lab/artifacts/store.ts +310 -0
  277. package/src/lab/automation/budgets.ts +78 -0
  278. package/src/lab/automation/config-persistence.ts +256 -0
  279. package/src/lab/automation/constants.ts +39 -0
  280. package/src/lab/automation/cooldown.ts +103 -0
  281. package/src/lab/automation/dispatch.ts +211 -0
  282. package/src/lab/automation/index.ts +13 -0
  283. package/src/lab/automation/orchestrator.ts +499 -0
  284. package/src/lab/automation/persistence.ts +512 -0
  285. package/src/lab/automation/planner.ts +371 -0
  286. package/src/lab/automation/policy.ts +136 -0
  287. package/src/lab/automation/queue.ts +191 -0
  288. package/src/lab/automation/recovery.ts +24 -0
  289. package/src/lab/automation/route-context.ts +21 -0
  290. package/src/lab/automation/run-key.ts +44 -0
  291. package/src/lab/automation/runs-query.ts +34 -0
  292. package/src/lab/automation/types.ts +160 -0
  293. package/src/lab/conformance/assertion.ts +325 -0
  294. package/src/lab/conformance/digest.ts +22 -0
  295. package/src/lab/conformance/executor.ts +741 -0
  296. package/src/lab/conformance/fixture-provider.ts +27 -0
  297. package/src/lab/conformance/fixtures/live-v1-cases.json +175 -0
  298. package/src/lab/conformance/fixtures/protocol-v1-cases.json +461 -0
  299. package/src/lab/conformance/harness-budget.ts +47 -0
  300. package/src/lab/conformance/index.ts +5 -0
  301. package/src/lab/conformance/jcs.ts +64 -0
  302. package/src/lab/conformance/json-pointer.ts +39 -0
  303. package/src/lab/conformance/manifest.ts +180 -0
  304. package/src/lab/conformance/mcp-stub.ts +179 -0
  305. package/src/lab/conformance/negative-controls.ts +164 -0
  306. package/src/lab/conformance/observation.ts +355 -0
  307. package/src/lab/conformance/runner.ts +68 -0
  308. package/src/lab/conformance/sse-normalize.ts +59 -0
  309. package/src/lab/conformance/suite-manifest.ts +78 -0
  310. package/src/lab/conformance/types.ts +214 -0
  311. package/src/lab/constants.ts +126 -0
  312. package/src/lab/digest.ts +64 -0
  313. package/src/lab/events/errors.ts +9 -0
  314. package/src/lab/events/limits.ts +117 -0
  315. package/src/lab/events/types.ts +229 -0
  316. package/src/lab/events/validate.ts +781 -0
  317. package/src/lab/fabric/constants.ts +40 -0
  318. package/src/lab/fabric/executor.ts +492 -0
  319. package/src/lab/fabric/index.ts +80 -0
  320. package/src/lab/fabric/manifest.ts +222 -0
  321. package/src/lab/fabric/observe.ts +489 -0
  322. package/src/lab/fabric/patch.ts +79 -0
  323. package/src/lab/fabric/producer-child.ts +139 -0
  324. package/src/lab/fabric/producer-isolate.ts +276 -0
  325. package/src/lab/fabric/producer-protocol.ts +61 -0
  326. package/src/lab/fabric/scratch.ts +439 -0
  327. package/src/lab/fabric/subject.ts +106 -0
  328. package/src/lab/fabric/types.ts +134 -0
  329. package/src/lab/fabric/verifier.ts +98 -0
  330. package/src/lab/index.ts +54 -0
  331. package/src/lab/ledger/artifact-refs.ts +127 -0
  332. package/src/lab/ledger/invalidation.ts +136 -0
  333. package/src/lab/ledger/purge.ts +310 -0
  334. package/src/lab/ledger/store.ts +532 -0
  335. package/src/lab/live/credential-lease.ts +53 -0
  336. package/src/lab/live/destination.ts +155 -0
  337. package/src/lab/live/executor.ts +336 -0
  338. package/src/lab/live/inert-tools.ts +56 -0
  339. package/src/lab/live/manifest.ts +85 -0
  340. package/src/lab/live/mcp-loopback.ts +57 -0
  341. package/src/lab/live/runner.ts +19 -0
  342. package/src/lab/live/sandbox.ts +61 -0
  343. package/src/lab/live/suite-manifest.ts +41 -0
  344. package/src/lab/live/transport.ts +118 -0
  345. package/src/lab/live/types.ts +197 -0
  346. package/src/lab/observe/from-conformance.ts +301 -0
  347. package/src/lab/observe/from-live.ts +117 -0
  348. package/src/lab/paths.ts +153 -0
  349. package/src/lab/projection/rebuild.ts +495 -0
  350. package/src/lab/projection/schema.ts +135 -0
  351. package/src/lab/projection/verdicts.ts +474 -0
  352. package/src/lab/projection/verification.ts +412 -0
  353. package/src/lab/public/bundle.ts +217 -0
  354. package/src/lab/public/community-authority.ts +175 -0
  355. package/src/lab/public/community-files.ts +29 -0
  356. package/src/lab/public/community.ts +479 -0
  357. package/src/lab/public/file-safety.ts +155 -0
  358. package/src/lab/public/ids.ts +26 -0
  359. package/src/lab/public/index.ts +16 -0
  360. package/src/lab/public/mutation-lock.ts +424 -0
  361. package/src/lab/public/operator.ts +353 -0
  362. package/src/lab/public/origin-purge.ts +79 -0
  363. package/src/lab/public/origin.ts +203 -0
  364. package/src/lab/public/privacy.ts +143 -0
  365. package/src/lab/public/private-file.ts +261 -0
  366. package/src/lab/public/project.ts +124 -0
  367. package/src/lab/public/purge-test-fault.ts +21 -0
  368. package/src/lab/public/purge.ts +223 -0
  369. package/src/lab/public/registry.ts +44 -0
  370. package/src/lab/public/revocation.ts +252 -0
  371. package/src/lab/public/signature.ts +243 -0
  372. package/src/lab/public/storage.ts +105 -0
  373. package/src/lab/public/strict-json.ts +206 -0
  374. package/src/lab/public/time.ts +26 -0
  375. package/src/lab/public/types.ts +172 -0
  376. package/src/lab/public/validate.ts +391 -0
  377. package/src/lab/query/catalog.ts +101 -0
  378. package/src/lab/query/connection.ts +107 -0
  379. package/src/lab/query/constants.ts +4 -0
  380. package/src/lab/query/cursor.ts +132 -0
  381. package/src/lab/query/dto-map.ts +277 -0
  382. package/src/lab/query/errors.ts +22 -0
  383. package/src/lab/query/freshness.ts +53 -0
  384. package/src/lab/query/index.ts +45 -0
  385. package/src/lab/query/latest-observation.ts +59 -0
  386. package/src/lab/query/passive-production.ts +159 -0
  387. package/src/lab/query/queries.ts +444 -0
  388. package/src/lab/query/types.ts +266 -0
  389. package/src/lab/subject/behavior-fingerprint.ts +77 -0
  390. package/src/lab/subject/installation-salt.ts +112 -0
  391. package/src/lab/subject/protocol-subject.ts +80 -0
  392. package/src/lab/subject/route-subject.ts +74 -0
  393. package/src/lib/app-owned-memory-stores.ts +22 -0
  394. package/src/lib/bounded-body.ts +153 -9
  395. package/src/lib/bun-runtime.ts +125 -12
  396. package/src/lib/bun-stream-caps.ts +13 -9
  397. package/src/lib/codex-restart-contract.ts +120 -0
  398. package/src/lib/config-ownership.ts +6 -2
  399. package/src/lib/destination-policy.ts +65 -1
  400. package/src/lib/errors.ts +44 -2
  401. package/src/lib/fabric-task-execution-authority.ts +7 -0
  402. package/src/lib/fabric-task-host.ts +29 -0
  403. package/src/lib/lab-activation.ts +223 -0
  404. package/src/lib/lab-live-execution-authority.ts +13 -0
  405. package/src/lib/lab-live-host.ts +30 -0
  406. package/src/lib/lab-live-pinned-sender.ts +56 -0
  407. package/src/lib/lab-live-route-production.ts +130 -0
  408. package/src/lib/lab-passive-linker-registration.ts +26 -0
  409. package/src/lib/local-management-attestation.ts +51 -0
  410. package/src/lib/local-management-capability.ts +100 -0
  411. package/src/lib/local-provider-reload-contract.ts +100 -0
  412. package/src/lib/optional-shutdown-hooks.ts +57 -0
  413. package/src/lib/pinned-http.ts +145 -26
  414. package/src/lib/process-control.ts +4 -1
  415. package/src/lib/provider-outbound.ts +49 -9
  416. package/src/lib/redact.ts +419 -3
  417. package/src/lib/self-launch-argv.ts +15 -0
  418. package/src/lib/server-resource-ownership.ts +71 -0
  419. package/src/lib/shadow-call.ts +35 -4
  420. package/src/lib/sse-decoder.ts +41 -0
  421. package/src/lib/state-store-registrations.ts +10 -2
  422. package/src/lib/system-restart-contract.ts +73 -0
  423. package/src/lib/token-estimate.ts +19 -2
  424. package/src/lib/tool-argument-integers.ts +202 -0
  425. package/src/lib/translator-budget.ts +44 -0
  426. package/src/lib/upstream-http-version.ts +57 -0
  427. package/src/lib/upstream-reachability.ts +95 -0
  428. package/src/lib/upstream-retry.ts +156 -3
  429. package/src/lib/windows-atomic-replace.ts +155 -0
  430. package/src/lib/windows-elevation.ts +70 -2
  431. package/src/lib/windows-secret-acl.ts +409 -69
  432. package/src/lib/windows-service-wrappers.ts +72 -0
  433. package/src/lib/windows-text.ts +106 -0
  434. package/src/lib/windows-user-principal.ts +341 -0
  435. package/src/lib/winsw.ts +33 -5
  436. package/src/oauth/account-import/google-antigravity-adapter.ts +74 -0
  437. package/src/oauth/account-import/index.ts +15 -0
  438. package/src/oauth/account-import/parser.ts +83 -0
  439. package/src/oauth/account-import/registry.ts +18 -0
  440. package/src/oauth/account-import/service.ts +75 -0
  441. package/src/oauth/account-import/types.ts +91 -0
  442. package/src/oauth/anthropic.ts +12 -1
  443. package/src/oauth/callback-server.ts +8 -2
  444. package/src/oauth/chatgpt.ts +12 -1
  445. package/src/oauth/command-code.ts +239 -0
  446. package/src/oauth/cursor.ts +46 -5
  447. package/src/oauth/google-antigravity.ts +35 -3
  448. package/src/oauth/health.ts +20 -12
  449. package/src/oauth/index.ts +398 -66
  450. package/src/oauth/key-providers.ts +16 -0
  451. package/src/oauth/kimi.ts +16 -2
  452. package/src/oauth/kiro.ts +50 -6
  453. package/src/oauth/local-token-detect.ts +11 -2
  454. package/src/oauth/log.ts +3 -1
  455. package/src/oauth/login-cli.ts +88 -28
  456. package/src/oauth/nous.ts +798 -0
  457. package/src/oauth/store.ts +119 -21
  458. package/src/oauth/token-guardian.ts +9 -3
  459. package/src/pi/models.ts +2 -2
  460. package/src/providers/alibaba-region-migration.ts +1 -1
  461. package/src/providers/antigravity-models.ts +521 -31
  462. package/src/providers/base-url-choices.ts +10 -0
  463. package/src/providers/codex-capacity.ts +292 -0
  464. package/src/providers/command-code-efforts.ts +144 -0
  465. package/src/providers/context-cap.ts +22 -5
  466. package/src/providers/cursor-pool.ts +72 -0
  467. package/src/providers/derive.ts +253 -6
  468. package/src/providers/fastwire.ts +501 -0
  469. package/src/providers/free-directory.ts +10 -7
  470. package/src/providers/google-vertex-location.ts +14 -0
  471. package/src/providers/key-failover.ts +71 -3
  472. package/src/providers/label.ts +1 -1
  473. package/src/providers/model-discovery-limits.ts +16 -0
  474. package/src/providers/model-discovery.ts +115 -22
  475. package/src/providers/model-rename-migration.ts +255 -0
  476. package/src/providers/model-rename-startup.ts +28 -0
  477. package/src/providers/openai-sidecar.ts +72 -4
  478. package/src/providers/openai-tier-startup.ts +31 -2
  479. package/src/providers/openai-tiers.ts +119 -4
  480. package/src/providers/openai-virtual-models.ts +1 -0
  481. package/src/providers/opencode-zen-rate-limit.ts +102 -0
  482. package/src/providers/provider-id-rewrite.ts +29 -0
  483. package/src/providers/quota.ts +1319 -38
  484. package/src/providers/registry.ts +1429 -111
  485. package/src/providers/request-pacing.ts +310 -0
  486. package/src/providers/service-tier.ts +277 -0
  487. package/src/providers/slug-codec.ts +42 -6
  488. package/src/providers/static-model-discovery.ts +86 -0
  489. package/src/providers/xai-responses-opt-in.ts +15 -0
  490. package/src/providers/xai-transport.ts +11 -4
  491. package/src/reasoning-effort.ts +49 -1
  492. package/src/responses/compaction.ts +26 -1
  493. package/src/responses/custom-tool-compat.ts +266 -0
  494. package/src/responses/hosted-tool-policy.ts +9 -0
  495. package/src/responses/namespace-tool-compat.ts +355 -0
  496. package/src/responses/parser.ts +220 -38
  497. package/src/responses/provider-continuation.ts +98 -0
  498. package/src/responses/provider-opaque-metadata.ts +73 -0
  499. package/src/responses/reasoning-envelope.ts +9 -1
  500. package/src/responses/reasoning-replay-cache.ts +426 -0
  501. package/src/responses/schema.ts +7 -1
  502. package/src/responses/spill-store.ts +75 -10
  503. package/src/responses/state.ts +565 -27
  504. package/src/responses/thought-signature-replay.ts +347 -0
  505. package/src/responses/tool-search-compat.ts +301 -0
  506. package/src/responses/truncated-stop-reason.ts +60 -0
  507. package/src/router.ts +366 -30
  508. package/src/routing/analytics.ts +378 -0
  509. package/src/routing/capability.ts +244 -0
  510. package/src/routing/compatibility/assemble.ts +73 -0
  511. package/src/routing/compatibility/behavior.ts +278 -0
  512. package/src/routing/compatibility/catalog.ts +99 -0
  513. package/src/routing/compatibility/endpoint.ts +52 -0
  514. package/src/routing/compatibility/lab-evidence-provider.ts +130 -0
  515. package/src/routing/compatibility/policy.ts +181 -0
  516. package/src/routing/compatibility/provider-slot.ts +56 -0
  517. package/src/routing/compatibility/reader.ts +110 -0
  518. package/src/routing/compatibility/subject.ts +191 -0
  519. package/src/routing/compatibility/types.ts +64 -0
  520. package/src/routing/compatibility/version.ts +104 -0
  521. package/src/routing/cost.ts +77 -0
  522. package/src/routing/evaluator.ts +495 -0
  523. package/src/routing/health.ts +412 -0
  524. package/src/routing/history/cursor.ts +43 -0
  525. package/src/routing/history/indexer.ts +605 -0
  526. package/src/routing/history/schema.ts +72 -0
  527. package/src/routing/profile-namespace.ts +15 -0
  528. package/src/routing/profile.ts +547 -0
  529. package/src/routing/quota.ts +145 -0
  530. package/src/routing/request-evidence.ts +45 -0
  531. package/src/routing/trace.ts +776 -0
  532. package/src/server/adapter-resolve.ts +2 -29
  533. package/src/server/auth-cors.ts +267 -46
  534. package/src/server/background-lifecycle.ts +182 -0
  535. package/src/server/chat-completions.ts +130 -56
  536. package/src/server/chat-native-sse.ts +331 -0
  537. package/src/server/chat-native.ts +426 -0
  538. package/src/server/claude-messages.ts +159 -43
  539. package/src/server/direct-local-http.ts +347 -0
  540. package/src/server/effort-policy.ts +18 -0
  541. package/src/server/github-copilot-responses-repair.ts +338 -0
  542. package/src/server/gui-static.ts +39 -10
  543. package/src/server/images.ts +94 -12
  544. package/src/server/index.ts +865 -181
  545. package/src/server/lifecycle.ts +284 -13
  546. package/src/server/live.ts +136 -17
  547. package/src/server/local-management-read-client.ts +90 -0
  548. package/src/server/local-provider-reload-client.ts +137 -0
  549. package/src/server/management/agent-settings-routes.ts +398 -103
  550. package/src/server/management/api-key-usage.ts +31 -5
  551. package/src/server/management/body.ts +6 -0
  552. package/src/server/management/combo-routes.ts +62 -24
  553. package/src/server/management/config-routes.ts +464 -51
  554. package/src/server/management/context.ts +80 -2
  555. package/src/server/management/integration-routes.ts +498 -0
  556. package/src/server/management/lab-automation-routes.ts +206 -0
  557. package/src/server/management/lab-routes.ts +563 -0
  558. package/src/server/management/logs-usage-routes.ts +101 -32
  559. package/src/server/management/model-routes.ts +189 -131
  560. package/src/server/management/model-rows.ts +163 -0
  561. package/src/server/management/native-integration-routes.ts +769 -0
  562. package/src/server/management/oauth-account-routes.ts +80 -4
  563. package/src/server/management/provider-capability-config.ts +48 -0
  564. package/src/server/management/provider-routes.ts +764 -157
  565. package/src/server/management/request-history-routes.ts +191 -0
  566. package/src/server/management/routing-analytics-routes.ts +74 -0
  567. package/src/server/management/routing-profile-routes.ts +380 -0
  568. package/src/server/management/shared.ts +27 -11
  569. package/src/server/management/sidebar-routes.ts +47 -31
  570. package/src/server/management/storage-log-guard-routes.ts +186 -0
  571. package/src/server/management/sync-response.ts +69 -0
  572. package/src/server/management/system-restart.ts +288 -32
  573. package/src/server/management/system-routes.ts +77 -0
  574. package/src/server/management/usage-summary-cache.ts +9 -1
  575. package/src/server/management/vision-sidecar-options.ts +167 -0
  576. package/src/server/management/web-search-sidecar-options.ts +120 -0
  577. package/src/server/management-api.ts +115 -14
  578. package/src/server/management-auth.ts +220 -5
  579. package/src/server/passive-route-linker.ts +66 -0
  580. package/src/server/ports.ts +41 -1
  581. package/src/server/proxy-liveness.ts +132 -5
  582. package/src/server/readiness.ts +99 -0
  583. package/src/server/relay-eager.ts +82 -42
  584. package/src/server/relay.ts +236 -76
  585. package/src/server/request-decompress.ts +113 -6
  586. package/src/server/request-log.ts +235 -22
  587. package/src/server/responses/agent-task-recovery-cache.ts +143 -0
  588. package/src/server/responses/agent-task-recovery.ts +465 -0
  589. package/src/server/responses/collaboration.ts +204 -35
  590. package/src/server/responses/compact.ts +442 -55
  591. package/src/server/responses/core.ts +2872 -331
  592. package/src/server/responses/empty-completion-guard.ts +276 -0
  593. package/src/server/responses/encrypted-payload.ts +62 -39
  594. package/src/server/responses/fetch-helpers.ts +79 -4
  595. package/src/server/responses/input-admission.ts +185 -0
  596. package/src/server/responses/pacing-overload.ts +13 -0
  597. package/src/server/responses/policy-fallback.ts +178 -0
  598. package/src/server/responses/responses-field-backfill.ts +251 -0
  599. package/src/server/responses/terminal-guard.ts +26 -5
  600. package/src/server/responses/upstream-error.ts +5 -0
  601. package/src/server/responses/ws-upstream.ts +308 -0
  602. package/src/server/responses-custom-tool-repair.ts +282 -0
  603. package/src/server/responses-item-id-repair.ts +54 -6
  604. package/src/server/responses-json-events.ts +90 -0
  605. package/src/server/responses-model-rewrite.ts +29 -0
  606. package/src/server/responses-reasoning-summary-rewrite.ts +178 -0
  607. package/src/server/responses-snapshot-repair.ts +621 -0
  608. package/src/server/responses-terminal-repair.ts +342 -0
  609. package/src/server/responses-tool-search-repair.ts +267 -0
  610. package/src/server/responses-undeclared-tool-guard.ts +153 -0
  611. package/src/server/responses.ts +18 -2
  612. package/src/server/search.ts +78 -13
  613. package/src/server/sse-frame-buffer.ts +292 -0
  614. package/src/server/sse-payload-rewrite.ts +110 -22
  615. package/src/server/startup-action-control.ts +8 -1
  616. package/src/server/startup-health-cache.ts +19 -1
  617. package/src/server/system-env.ts +80 -9
  618. package/src/server/ws-bridge.ts +39 -38
  619. package/src/service-manager-probe.ts +892 -0
  620. package/src/service.ts +1111 -90
  621. package/src/sidecar/auth.ts +92 -0
  622. package/src/sidecar/candidates.ts +83 -0
  623. package/src/storage/cleanup.ts +2 -2
  624. package/src/storage/scanner.ts +1 -1
  625. package/src/storage/worker-lifecycle.ts +14 -14
  626. package/src/tray/windows-tray.ps1 +83 -9
  627. package/src/tray/windows.ts +43 -16
  628. package/src/types/accounts.ts +37 -0
  629. package/src/types/config.ts +845 -0
  630. package/src/types/provider.ts +545 -0
  631. package/src/types/request.ts +384 -0
  632. package/src/types/tools.ts +131 -0
  633. package/src/types/wire.ts +80 -0
  634. package/src/types.ts +104 -1236
  635. package/src/update/index.ts +32 -19
  636. package/src/update/job.ts +442 -67
  637. package/src/update/notify.ts +12 -6
  638. package/src/update/npm-cache-preflight.d.mts +47 -0
  639. package/src/update/npm-cache-preflight.mjs +201 -0
  640. package/src/update/transactional-install.d.mts +22 -0
  641. package/src/update/transactional-install.mjs +259 -0
  642. package/src/usage/cost.ts +0 -0
  643. package/src/usage/expected-prices.ts +268 -16
  644. package/src/usage/log.ts +606 -41
  645. package/src/usage/summary.ts +177 -9
  646. package/src/usage/user-cost-overlay-reconciler.ts +313 -0
  647. package/src/usage/user-cost-overlays.ts +314 -0
  648. package/src/vision/anthropic-describe.ts +10 -6
  649. package/src/vision/backends.ts +97 -0
  650. package/src/vision/describe.ts +9 -3
  651. package/src/vision/eligibility.ts +250 -0
  652. package/src/vision/index.ts +238 -24
  653. package/src/vision/reasoning.ts +55 -0
  654. package/src/vision/routed-describe.ts +175 -0
  655. package/src/vision/timeout-bounds.ts +9 -0
  656. package/src/web-search/anthropic-executor.ts +13 -7
  657. package/src/web-search/backends.ts +108 -0
  658. package/src/web-search/exa-executor.ts +88 -0
  659. package/src/web-search/executor.ts +11 -3
  660. package/src/web-search/gemini-executor.ts +141 -0
  661. package/src/web-search/index.ts +150 -15
  662. package/src/web-search/loop.ts +279 -50
  663. package/src/web-search/parse.ts +125 -30
  664. package/src/web-search/sources.ts +60 -0
  665. package/src/web-search/xai-executor.ts +219 -0
  666. package/gui/dist/assets/index-DTpMHS4F.js +0 -67
  667. package/gui/dist/assets/index-ZNVDE3C7.css +0 -1
  668. package/gui/dist/provider-icons/antigravity.svg +0 -1
  669. package/gui/dist/provider-icons/claude.svg +0 -1
  670. package/gui/dist/provider-icons/copilot.svg +0 -1
  671. package/gui/dist/provider-icons/cursor.svg +0 -2
  672. package/gui/dist/provider-icons/gemini.svg +0 -1
  673. package/gui/dist/provider-icons/grok-color.svg +0 -1
  674. package/gui/dist/provider-icons/kiro.svg +0 -14
  675. package/src/cli/internal-dispatch.ts +0 -20
@@ -1,8 +1,8 @@
1
1
  import { baseProviderLabel } from "../providers/label";
2
2
  import { canonicalAntigravityUsageModel } from "../providers/antigravity-models";
3
3
  import { usageDisplayTotalTokens } from "./totals";
4
- import type { PersistedUsageEntry, UsageStatus } from "./log";
5
- import { estimateComboCost, estimateRequestCost, effectiveServiceTier } from "./cost";
4
+ import { isCodexUsageAccountLogLabel, type PersistedUsageEntry, type UsageStatus } from "./log";
5
+ import { estimateAttemptCost, estimateComboCost, estimateRequestCost, serviceTierContext } from "./cost";
6
6
 
7
7
  export type UsageRange = "7d" | "30d" | "all";
8
8
  export type UsageSurface = "all" | "codex" | "claude" | "grok";
@@ -79,6 +79,28 @@ export interface UsageProvider {
79
79
  estimatedCostUsd?: number;
80
80
  }
81
81
 
82
+ export interface UsageAccount {
83
+ accountLogLabel: string;
84
+ ambiguous: boolean;
85
+ requests: number;
86
+ attemptCount: number;
87
+ measuredAttempts: number;
88
+ reportedAttempts: number;
89
+ estimatedAttempts: number;
90
+ unmeteredAttempts: number;
91
+ inputTokens: number;
92
+ outputTokens: number;
93
+ cacheReadInputTokens: number;
94
+ cacheCreationInputTokens: number;
95
+ reasoningOutputTokens: number;
96
+ totalTokens: number;
97
+ usageCoverageRatio: number;
98
+ estimatedCostUsd?: number;
99
+ pricedAttempts: number;
100
+ unpricedAttempts: number;
101
+ priceCoverageRatio: number;
102
+ }
103
+
82
104
  export interface UsageSummary {
83
105
  range: UsageRange;
84
106
  surface: UsageSurface;
@@ -88,6 +110,7 @@ export interface UsageSummary {
88
110
  days: UsageDay[];
89
111
  models: UsageModel[];
90
112
  providers: UsageProvider[];
113
+ accounts: UsageAccount[];
91
114
  }
92
115
 
93
116
  const DAY_MS = 86_400_000;
@@ -113,9 +136,23 @@ export function parseUsageSurface(input: string | null | undefined): UsageSurfac
113
136
  return "all";
114
137
  }
115
138
 
116
- function rangeWindow(range: UsageRange, now: number): { since: number | null; days: number } {
117
- if (range === "7d") return { since: now - 7 * DAY_MS, days: 7 };
118
- if (range === "30d") return { since: now - 30 * DAY_MS, days: 30 };
139
+ function startOfLocalDay(ts: number): number {
140
+ const d = new Date(ts);
141
+ d.setHours(0, 0, 0, 0);
142
+ return d.getTime();
143
+ }
144
+
145
+ export function rangeWindow(range: UsageRange, now: number): { since: number | null; days: number } {
146
+ if (range === "7d") {
147
+ const start = new Date(startOfLocalDay(now));
148
+ start.setDate(start.getDate() - 6);
149
+ return { since: start.getTime(), days: 7 };
150
+ }
151
+ if (range === "30d") {
152
+ const start = new Date(startOfLocalDay(now));
153
+ start.setDate(start.getDate() - 29);
154
+ return { since: start.getTime(), days: 30 };
155
+ }
119
156
  return { since: null, days: 0 };
120
157
  }
121
158
 
@@ -286,7 +323,7 @@ function addEstimatedCost(
286
323
  totals.unmeteredRequests += 1;
287
324
  return;
288
325
  }
289
- const tier = effectiveServiceTier(entry);
326
+ const tier = serviceTierContext(entry);
290
327
  const estimate = entry.attempts?.length
291
328
  ? estimateComboCost(entry.attempts, undefined, tier)
292
329
  : estimateRequestCost({ provider: entry.provider, model: entry.model, usage: entry.usage, usageStatus: entry.usageStatus, serviceTier: tier });
@@ -324,8 +361,11 @@ function buildDayGrid(range: UsageRange, since: number | null, now: number, entr
324
361
  m.attemptCount += 1;
325
362
  m.totalTokens += usageDisplayTotalTokens(attribution.usage, attribution.totalTokens) ?? 0;
326
363
  };
364
+ const startOfToday = startOfLocalDay(now);
327
365
  for (let i = days - 1; i >= 0; i--) {
328
- const key = localDateKey(now - i * DAY_MS);
366
+ const d = new Date(startOfToday);
367
+ d.setDate(d.getDate() - i);
368
+ const key = localDateKey(d.getTime());
329
369
  grid.set(key, { date: key, requests: 0, measuredRequests: 0, reportedRequests: 0, totalTokens: 0, models: [] });
330
370
  }
331
371
  for (const entry of entries) {
@@ -415,7 +455,7 @@ function buildModels(entries: PersistedUsageEntry[], totalTokens: number): Usage
415
455
  }
416
456
  // Accumulate per-model estimated cost
417
457
  for (const entry of entries) {
418
- const tier = effectiveServiceTier(entry);
458
+ const tier = serviceTierContext(entry);
419
459
  const estimate = entry.attempts?.length
420
460
  ? estimateComboCost(entry.attempts, undefined, tier)
421
461
  : estimateRequestCost({ provider: entry.provider, model: entry.model, usage: entry.usage, usageStatus: entry.usageStatus, serviceTier: tier });
@@ -524,7 +564,7 @@ function buildProviders(entries: PersistedUsageEntry[], totalTokens: number): Us
524
564
  }
525
565
  }
526
566
  for (const entry of entries) {
527
- const tier = effectiveServiceTier(entry);
567
+ const tier = serviceTierContext(entry);
528
568
  const estimate = entry.attempts?.length
529
569
  ? estimateComboCost(entry.attempts, undefined, tier)
530
570
  : estimateRequestCost({ provider: entry.provider, model: entry.model, usage: entry.usage, usageStatus: entry.usageStatus, serviceTier: tier });
@@ -547,6 +587,133 @@ function buildProviders(entries: PersistedUsageEntry[], totalTokens: number): Us
547
587
  return providers.sort((a, b) => b.requests - a.requests);
548
588
  }
549
589
 
590
+ const LEGACY_AMBIGUOUS_ACCOUNT_LABEL = "legacy-ambiguous";
591
+
592
+ function legacyCodexAccountLabel(provider: string): string | null {
593
+ if (baseProviderLabel(provider) !== "openai") return null;
594
+ const suffix = provider.match(/-(main|p[a-f0-9]{6})$/)?.[1];
595
+ return suffix ?? LEGACY_AMBIGUOUS_ACCOUNT_LABEL;
596
+ }
597
+
598
+ function accountLabelForAttribution(provider: string, explicit: unknown): string | null {
599
+ if (isCodexUsageAccountLogLabel(explicit)) return explicit;
600
+ return legacyCodexAccountLabel(provider);
601
+ }
602
+
603
+ function buildAccounts(entries: PersistedUsageEntry[]): UsageAccount[] {
604
+ const byLabel = new Map<string, UsageAccount>();
605
+ const requestIds = new Map<string, Set<string>>();
606
+
607
+ const add = (input: {
608
+ requestId: string;
609
+ provider: string;
610
+ accountLogLabel?: string;
611
+ usageStatus: UsageStatus;
612
+ usage?: PersistedUsageEntry["usage"];
613
+ totalTokens?: number;
614
+ estimate: ReturnType<typeof estimateRequestCost>;
615
+ }): void => {
616
+ const label = accountLabelForAttribution(input.provider, input.accountLogLabel);
617
+ if (!label) return;
618
+ let row = byLabel.get(label);
619
+ if (!row) {
620
+ row = {
621
+ accountLogLabel: label,
622
+ ambiguous: label === LEGACY_AMBIGUOUS_ACCOUNT_LABEL,
623
+ requests: 0,
624
+ attemptCount: 0,
625
+ measuredAttempts: 0,
626
+ reportedAttempts: 0,
627
+ estimatedAttempts: 0,
628
+ unmeteredAttempts: 0,
629
+ inputTokens: 0,
630
+ outputTokens: 0,
631
+ cacheReadInputTokens: 0,
632
+ cacheCreationInputTokens: 0,
633
+ reasoningOutputTokens: 0,
634
+ totalTokens: 0,
635
+ usageCoverageRatio: 0,
636
+ pricedAttempts: 0,
637
+ unpricedAttempts: 0,
638
+ priceCoverageRatio: 0,
639
+ };
640
+ byLabel.set(label, row);
641
+ requestIds.set(label, new Set());
642
+ }
643
+ requestIds.get(label)!.add(input.requestId);
644
+ row.requests = requestIds.get(label)!.size;
645
+ row.attemptCount += 1;
646
+ const measured = input.usage !== undefined && isMeasuredStatus(input.usageStatus);
647
+ if (!measured) {
648
+ row.unmeteredAttempts += 1;
649
+ return;
650
+ }
651
+
652
+ row.measuredAttempts += 1;
653
+ if (input.usageStatus === "reported") row.reportedAttempts += 1;
654
+ else if (input.usageStatus === "estimated") row.estimatedAttempts += 1;
655
+ row.inputTokens += input.usage!.inputTokens;
656
+ row.outputTokens += input.usage!.outputTokens;
657
+ const creation = input.usage!.cacheCreationInputTokens;
658
+ const read = typeof input.usage!.cacheReadInputTokens === "number"
659
+ ? input.usage!.cacheReadInputTokens
660
+ : typeof input.usage!.cachedInputTokens === "number" && typeof creation === "number"
661
+ ? Math.max(0, input.usage!.cachedInputTokens - creation)
662
+ : input.usage!.cachedInputTokens;
663
+ if (typeof read === "number") row.cacheReadInputTokens += read;
664
+ if (typeof creation === "number") row.cacheCreationInputTokens += creation;
665
+ if (typeof input.usage!.reasoningOutputTokens === "number") {
666
+ row.reasoningOutputTokens += input.usage!.reasoningOutputTokens;
667
+ }
668
+ row.totalTokens += usageDisplayTotalTokens(input.usage, input.totalTokens) ?? 0;
669
+ if (input.estimate) {
670
+ row.pricedAttempts += 1;
671
+ row.estimatedCostUsd = (row.estimatedCostUsd ?? 0) + input.estimate.cost.total;
672
+ } else {
673
+ row.unpricedAttempts += 1;
674
+ }
675
+ };
676
+
677
+ for (const entry of entries) {
678
+ const tier = serviceTierContext(entry);
679
+ if (entry.attempts?.length) {
680
+ for (const attempt of entry.attempts) {
681
+ add({
682
+ requestId: entry.requestId,
683
+ provider: attempt.provider,
684
+ ...(attempt.accountLogLabel ? { accountLogLabel: attempt.accountLogLabel } : {}),
685
+ usageStatus: attempt.usageStatus,
686
+ ...(attempt.usage ? { usage: attempt.usage } : {}),
687
+ ...(attempt.totalTokens !== undefined ? { totalTokens: attempt.totalTokens } : {}),
688
+ estimate: estimateAttemptCost(attempt, undefined, tier),
689
+ });
690
+ }
691
+ continue;
692
+ }
693
+ add({
694
+ requestId: entry.requestId,
695
+ provider: entry.provider,
696
+ ...(entry.accountLogLabel ? { accountLogLabel: entry.accountLogLabel } : {}),
697
+ usageStatus: entry.usageStatus,
698
+ ...(entry.usage ? { usage: entry.usage } : {}),
699
+ ...(entry.totalTokens !== undefined ? { totalTokens: entry.totalTokens } : {}),
700
+ estimate: estimateRequestCost({
701
+ provider: entry.provider,
702
+ model: entry.model,
703
+ usage: entry.usage,
704
+ usageStatus: entry.usageStatus,
705
+ serviceTier: tier,
706
+ }),
707
+ });
708
+ }
709
+
710
+ for (const row of byLabel.values()) {
711
+ row.usageCoverageRatio = row.attemptCount === 0 ? 0 : row.measuredAttempts / row.attemptCount;
712
+ row.priceCoverageRatio = row.measuredAttempts === 0 ? 0 : row.pricedAttempts / row.measuredAttempts;
713
+ }
714
+ return [...byLabel.values()].sort((a, b) => b.totalTokens - a.totalTokens);
715
+ }
716
+
550
717
  export function summarizeUsage(
551
718
  entries: PersistedUsageEntry[],
552
719
  range: UsageRange,
@@ -581,5 +748,6 @@ export function summarizeUsage(
581
748
  days: buildDayGrid(range, since, now, filteredEntries),
582
749
  models: buildModels(filteredEntries, totals.totalTokens),
583
750
  providers: buildProviders(filteredEntries, totals.totalTokens),
751
+ accounts: buildAccounts(filteredEntries),
584
752
  };
585
753
  }
@@ -0,0 +1,313 @@
1
+ /**
2
+ * Cross-process reconciliation for user cost overlays.
3
+ *
4
+ * `refreshUserCostOverlays` is process-local by design: `ocx config set`
5
+ * executes `saveConfig()` in the CLI process, and a direct `config.json` edit
6
+ * runs no in-process code at all. A running proxy therefore keeps its previous
7
+ * `activeUserCostOverlays()`/version until restart or another in-process
8
+ * refresh.
9
+ *
10
+ * This module gives the long-lived server a lightweight stat-based poller:
11
+ * when `config.json` changes on disk, it re-reads the persisted config, mirrors
12
+ * the disk `modelCosts` rows into the live provider rows (so a later in-process
13
+ * save cannot erase the external edit), and refreshes the overlay registry so
14
+ * Logs/Usage estimates follow the edit without a restart.
15
+ *
16
+ * The reconciler is owner-scoped: every `startServer` acquires its own lease
17
+ * (with its own live config), and the shared timer is torn down only when the
18
+ * LAST owner stops. This mirrors `acquireServerBackgroundLifecycle` so stopping
19
+ * one of several servers cannot kill reconciliation for the others.
20
+ */
21
+ import { statSync } from "node:fs";
22
+
23
+ import { getConfigPath, readConfigDiagnostics } from "../config";
24
+ import type { OcxConfig, OcxProviderConfig } from "../types";
25
+ import {
26
+ refreshPreservedProviderOwner,
27
+ refreshUserCostOverlays,
28
+ registerPreservedProviderOwner,
29
+ setPreservedDiskOnlyProviders,
30
+ unregisterPreservedProviderOwner,
31
+ } from "./user-cost-overlays";
32
+
33
+ /** Default poll cadence for external config edits. */
34
+ export const USER_COST_OVERLAY_RECONCILE_INTERVAL_MS = 5_000;
35
+
36
+ let reconcileTimer: ReturnType<typeof setInterval> | null = null;
37
+ let reconcileTimerMs = 0;
38
+ const owners = new Map<symbol, OcxConfig | null>();
39
+ const ownerIntervals = new Map<symbol, number>();
40
+ let lastStamp: { mtimeMs: number; size: number; ctimeMs: number; ino: number } | null = null;
41
+ let invalidReconcileCount = 0;
42
+
43
+ function configStamp(): { mtimeMs: number; size: number; ctimeMs: number; ino: number } | null {
44
+ try {
45
+ const stat = statSync(getConfigPath());
46
+ return {
47
+ mtimeMs: stat.mtimeMs,
48
+ size: stat.size,
49
+ ctimeMs: stat.ctimeMs,
50
+ ino: Number(stat.ino),
51
+ };
52
+ } catch {
53
+ return null;
54
+ }
55
+ }
56
+
57
+ /** Registered live configs plus an optional one-shot config, deduped by object identity. */
58
+ function liveConfigsForPreservation(extra?: OcxConfig | null): OcxConfig[] {
59
+ const liveConfigs: OcxConfig[] = [];
60
+ const seen = new Set<OcxConfig>();
61
+ if (extra) {
62
+ seen.add(extra);
63
+ liveConfigs.push(extra);
64
+ }
65
+ for (const config of owners.values()) {
66
+ if (!config || seen.has(config)) continue;
67
+ seen.add(config);
68
+ liveConfigs.push(config);
69
+ }
70
+ return liveConfigs;
71
+ }
72
+
73
+ /**
74
+ * Mirror disk `modelCosts` rows into provider rows the live config already
75
+ * knows. Providers added by the external edit are left out of the live config
76
+ * (they would change the routing surface); their overlays still become active
77
+ * because the registry below is refreshed from the disk config.
78
+ */
79
+ function adoptDiskModelCosts(live: OcxConfig, disk: OcxConfig): void {
80
+ if (!live.providers || !disk.providers) return;
81
+ for (const [name, diskProvider] of Object.entries(disk.providers)) {
82
+ const liveProvider = live.providers[name];
83
+ if (!liveProvider) continue;
84
+ if (diskProvider?.modelCosts === undefined) {
85
+ delete liveProvider.modelCosts;
86
+ } else {
87
+ liveProvider.modelCosts = structuredClone(diskProvider.modelCosts);
88
+ }
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Remember provider rows present on disk that at least one live routing
94
+ * config does NOT own. They stay out of the live configs that lack them
95
+ * (adding them would change the routing surface), but
96
+ * `persistConfigUnlocked` merges them back at serialization so ANY owner's
97
+ * unrelated save preserves a provider row that another active owner owns.
98
+ *
99
+ * A row is preserved when it is missing from at least one live config: the
100
+ * writer that lacks it would otherwise erase it. Rows every live config owns
101
+ * need no protection because every writer carries them from its own config.
102
+ */
103
+ function rememberDiskOnlyProviders(liveConfigs: readonly OcxConfig[], disk: OcxConfig): void {
104
+ const preserved: Record<string, OcxProviderConfig> = {};
105
+ if (disk.providers && liveConfigs.length > 0) {
106
+ for (const [name, provider] of Object.entries(disk.providers)) {
107
+ if (!provider) continue;
108
+ const ownedByAll = liveConfigs.every(live => Object.hasOwn(live.providers ?? {}, name));
109
+ if (!ownedByAll) preserved[name] = structuredClone(provider);
110
+ }
111
+ }
112
+ setPreservedDiskOnlyProviders(Object.keys(preserved).length > 0 ? preserved : null);
113
+ // Update only registered server owners. One-shot callers without a lease do
114
+ // not become deletion authorities merely by asking for a reconciliation.
115
+ for (const live of liveConfigs) refreshPreservedProviderOwner(live, disk);
116
+ }
117
+
118
+ /**
119
+ * Re-read the persisted config and recompute the disk-only provider
120
+ * preservation registry against the CURRENT owner set. Used when an owner
121
+ * stops but others remain: a newer owner may have owned a provider that an
122
+ * older owner still treats as disk-only, and the registry must reflect the
123
+ * remaining owners rather than the stale pre-stop snapshot.
124
+ *
125
+ * A missing or transiently invalid file leaves the registry untouched so a
126
+ * bad write cannot erase preservation state.
127
+ */
128
+ function recomputePreservedDiskOnlyProviders(): void {
129
+ const diagnostics = readConfigDiagnostics();
130
+ if (diagnostics.source !== "file") return;
131
+ const liveConfigs = liveConfigsForPreservation();
132
+ if (liveConfigs.length > 0) {
133
+ rememberDiskOnlyProviders(liveConfigs, diagnostics.config);
134
+ } else {
135
+ // No live routing configuration remains to protect disk-only providers;
136
+ // clear the cache so a later save cannot resurrect externally deleted rows.
137
+ setPreservedDiskOnlyProviders(null);
138
+ }
139
+ }
140
+
141
+ /**
142
+ * Re-read the persisted config and make external overlay edits live.
143
+ *
144
+ * Returns `false` (and leaves the registry untouched) when the file is missing
145
+ * or invalid, so a transient bad write cannot wipe display-only prices.
146
+ */
147
+ export function reconcileUserCostOverlaysFromDisk(liveConfig?: OcxConfig | null): boolean {
148
+ const diagnostics = readConfigDiagnostics();
149
+ if (diagnostics.source !== "file") return false;
150
+ const disk = diagnostics.config;
151
+ if (liveConfig) {
152
+ adoptDiskModelCosts(liveConfig, disk);
153
+ // A one-shot caller is not the whole process. Existing server owners still
154
+ // participate in global preservation or this call can drop protection for
155
+ // a provider absent from an older live projection.
156
+ rememberDiskOnlyProviders(liveConfigsForPreservation(liveConfig), disk);
157
+ } else {
158
+ // No live routing config was supplied: mirror the owners path so a stale
159
+ // preservation registry cannot resurrect externally deleted providers on
160
+ // the next saveConfig. Registered owners still protect disk-only rows;
161
+ // without any, preservation is cleared.
162
+ const liveConfigs = liveConfigsForPreservation();
163
+ if (liveConfigs.length > 0) {
164
+ for (const live of liveConfigs) adoptDiskModelCosts(live, disk);
165
+ rememberDiskOnlyProviders(liveConfigs, disk);
166
+ } else {
167
+ setPreservedDiskOnlyProviders(null);
168
+ }
169
+ }
170
+ // Refresh from the DISK config: overlays for providers only added by the
171
+ // external edit are display-only and must still resolve for historical rows.
172
+ refreshUserCostOverlays(disk);
173
+ return true;
174
+ }
175
+
176
+ function reconcileForOwners(): void {
177
+ const diagnostics = readConfigDiagnostics();
178
+ if (diagnostics.source !== "file") {
179
+ if (diagnostics.source === "fallback") invalidReconcileCount += 1;
180
+ return;
181
+ }
182
+ const disk = diagnostics.config;
183
+ const liveConfigs = liveConfigsForPreservation();
184
+ if (liveConfigs.length > 0) {
185
+ for (const live of liveConfigs) adoptDiskModelCosts(live, disk);
186
+ rememberDiskOnlyProviders(liveConfigs, disk);
187
+ } else {
188
+ // Overlay-only refresh with no live routing configuration: do not treat
189
+ // every disk provider as protected, and do not let a stale preservation
190
+ // cache resurrect providers that were intentionally removed.
191
+ setPreservedDiskOnlyProviders(null);
192
+ }
193
+ refreshUserCostOverlays(disk);
194
+ }
195
+
196
+ /** Test-only observation that proves the timer actually read an invalid config fallback. */
197
+ export function userCostOverlayInvalidReconcileCountForTests(): number {
198
+ return invalidReconcileCount;
199
+ }
200
+
201
+ /** Smallest poll interval across all active owners (the effective cadence). */
202
+ function effectiveIntervalMs(): number {
203
+ let min = Number.POSITIVE_INFINITY;
204
+ for (const interval of ownerIntervals.values()) {
205
+ if (interval < min) min = interval;
206
+ }
207
+ return min === Number.POSITIVE_INFINITY ? USER_COST_OVERLAY_RECONCILE_INTERVAL_MS : min;
208
+ }
209
+
210
+ /**
211
+ * Keep the shared timer on the effective minimum cadence across owners. A
212
+ * later owner may request a smaller interval, which restarts the timer; when
213
+ * an owner stops, the cadence relaxes back up to the smallest still-active
214
+ * owner's request. The timer therefore never outlives or ignores an owner's
215
+ * faster polling need, and never polls faster than the active set requires.
216
+ */
217
+ function syncReconcileTimer(): void {
218
+ const intervalMs = effectiveIntervalMs();
219
+ if (reconcileTimer && reconcileTimerMs === intervalMs) return;
220
+ if (reconcileTimer) clearInterval(reconcileTimer);
221
+ reconcileTimer = setInterval(() => {
222
+ const stamp = configStamp();
223
+ if (!stamp) return;
224
+ if (
225
+ lastStamp
226
+ && lastStamp.mtimeMs === stamp.mtimeMs
227
+ && lastStamp.size === stamp.size
228
+ && lastStamp.ctimeMs === stamp.ctimeMs
229
+ && lastStamp.ino === stamp.ino
230
+ ) return;
231
+ lastStamp = stamp;
232
+ try {
233
+ reconcileForOwners();
234
+ } catch {
235
+ // Display-only reconciliation must never take the proxy down.
236
+ }
237
+ }, intervalMs);
238
+ reconcileTimer.unref?.();
239
+ reconcileTimerMs = intervalMs;
240
+ }
241
+
242
+ /**
243
+ * Start the stat-based reconciler. Each call registers an owner lease; the
244
+ * shared timer starts with the first owner and stops when the last owner's
245
+ * `stop()` releases it.
246
+ */
247
+ export function startUserCostOverlayReconciler(
248
+ options: { intervalMs?: number; liveConfig?: OcxConfig | null } = {},
249
+ ): { stop(): void } {
250
+ const token = Symbol("user-cost-overlay-reconciler");
251
+ const liveConfig = options.liveConfig ?? null;
252
+ owners.set(token, liveConfig);
253
+ ownerIntervals.set(token, options.intervalMs ?? USER_COST_OVERLAY_RECONCILE_INTERVAL_MS);
254
+ if (liveConfig) registerPreservedProviderOwner(liveConfig);
255
+ syncReconcileTimer();
256
+ return {
257
+ stop() {
258
+ const ownedConfig = owners.get(token) ?? null;
259
+ owners.delete(token);
260
+ ownerIntervals.delete(token);
261
+ if (ownedConfig) unregisterPreservedProviderOwner(ownedConfig);
262
+ if (owners.size === 0) {
263
+ if (reconcileTimer) clearInterval(reconcileTimer);
264
+ reconcileTimer = null;
265
+ reconcileTimerMs = 0;
266
+ lastStamp = null;
267
+ // No live routing config remains, so nothing can keep disk-only
268
+ // providers alive: clear the cache to prevent a later save from
269
+ // resurrecting an externally deleted provider.
270
+ setPreservedDiskOnlyProviders(null);
271
+ return;
272
+ }
273
+ syncReconcileTimer();
274
+ // Other owners remain: recompute preservation against their live
275
+ // configs. A newer owner may have owned providers that an older owner
276
+ // still sees as disk-only; without this recompute the older owner's next
277
+ // unrelated save could erase them.
278
+ try {
279
+ recomputePreservedDiskOnlyProviders();
280
+ } catch {
281
+ // Preservation is display-only; a failed recompute must not break stop.
282
+ }
283
+ },
284
+ };
285
+ }
286
+
287
+ /**
288
+ * Process-wide stop: releases EVERY owner's lease and the shared timer.
289
+ * Intended for tests and full process teardown. A per-server shutdown must
290
+ * call its own owner-scoped `stop()` handle instead — this function would
291
+ * otherwise tear down reconciliation (and disk-only preservation) for every
292
+ * other server still running in the same process.
293
+ */
294
+ export function stopUserCostOverlayReconciler(): void {
295
+ for (const config of owners.values()) {
296
+ if (config) unregisterPreservedProviderOwner(config);
297
+ }
298
+ owners.clear();
299
+ ownerIntervals.clear();
300
+ if (reconcileTimer) clearInterval(reconcileTimer);
301
+ reconcileTimer = null;
302
+ reconcileTimerMs = 0;
303
+ lastStamp = null;
304
+ // No live routing config remains; drop preservation so a later save cannot
305
+ // resurrect externally deleted providers.
306
+ setPreservedDiskOnlyProviders(null);
307
+ }
308
+
309
+ /** Test-only reset for module-global reconciler state. */
310
+ export function resetUserCostOverlayReconcilerForTests(): void {
311
+ stopUserCostOverlayReconciler();
312
+ invalidReconcileCount = 0;
313
+ }