@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
@@ -0,0 +1,353 @@
1
+ import { createHash } from "node:crypto";
2
+ import { readBoundedResponseBody } from "../lib/bounded-body";
3
+ import type { OcxConfig } from "../types";
4
+ import { isSelectableCodexPoolAccount } from "./account-id";
5
+ import { getValidCodexToken, readCodexAccountRecord } from "./account-store";
6
+ import { getMainAccountToken, MAIN_CODEX_ACCOUNT_ID } from "./main-account";
7
+ import { ACCOUNT_GATED_NATIVE_OPENAI_MODELS } from "./catalog/native-models";
8
+
9
+ const CODEX_MODELS_URL = "https://chatgpt.com/backend-api/codex/models?client_version=0.0.0";
10
+ const MODEL_ROSTER_TTL_MS = 5 * 60_000;
11
+ const MODEL_ROSTER_FAILURE_TTL_MS = 15_000;
12
+ const MODEL_ROSTER_TIMEOUT_MS = 8_000;
13
+ const MODEL_ROSTER_MAX_BYTES = 2 * 1024 * 1024;
14
+ const MODEL_ROSTER_CACHE_MAX = 64;
15
+ const DIRECT_CALLER_ACCOUNT_PREFIX = "__direct_codex__:";
16
+
17
+ export interface CodexModelEntitlementCredentialSnapshot {
18
+ readonly accountId: string;
19
+ readonly accessToken: string;
20
+ readonly chatgptAccountId: string;
21
+ /** Stable local identity for rejecting a catalog commit after credential replacement. */
22
+ readonly credentialIdentity: string;
23
+ }
24
+
25
+ interface CachedAccountModels {
26
+ readonly credentialIdentity: string;
27
+ readonly expiresAt: number;
28
+ readonly models: ReadonlySet<string>;
29
+ readonly confirmed: boolean;
30
+ }
31
+
32
+ export interface CodexModelEntitlementSnapshot {
33
+ readonly modelsByAccount: ReadonlyMap<string, ReadonlySet<string>>;
34
+ readonly confirmedAccountIds: ReadonlySet<string>;
35
+ readonly credentialIdentities: ReadonlyMap<string, string>;
36
+ }
37
+
38
+ export interface CodexModelEntitlementResolveOptions {
39
+ readonly fetcher?: typeof fetch;
40
+ readonly now?: number;
41
+ /** Test-only credential seam; production callers enumerate local main + Pool credentials. */
42
+ readonly credentials?: readonly CodexModelEntitlementCredentialSnapshot[];
43
+ }
44
+
45
+ const accountModelsCache = new Map<string, CachedAccountModels>();
46
+ const accountModelsFlights = new Map<string, Promise<CachedAccountModels>>();
47
+
48
+ /**
49
+ * Direct-caller entries are evicted separately from main/Pool entries.
50
+ *
51
+ * Direct keys are per-credential (`__direct_codex__:<hash>`) and unbounded in practice, while
52
+ * main/Pool keys are the evidence the CATALOG projects from. Sharing one LRU let 64 distinct
53
+ * Direct callers evict `__main__` and the Pool accounts, which makes the gated row vanish from
54
+ * the catalog until rediscovery — fail-closed flapping rather than a leak, but still a visible
55
+ * model disappearing for a reason the operator cannot see. Two budgets keep one class of caller
56
+ * from erasing the other's evidence.
57
+ */
58
+ function boundedCacheSet(accountId: string, value: CachedAccountModels): void {
59
+ accountModelsCache.delete(accountId);
60
+ accountModelsCache.set(accountId, value);
61
+ const isDirect = (key: string): boolean => key.startsWith(DIRECT_CALLER_ACCOUNT_PREFIX);
62
+ const evictClass = (direct: boolean): void => {
63
+ let count = 0;
64
+ for (const key of accountModelsCache.keys()) if (isDirect(key) === direct) count += 1;
65
+ while (count > MODEL_ROSTER_CACHE_MAX) {
66
+ let oldest: string | undefined;
67
+ for (const key of accountModelsCache.keys()) {
68
+ if (isDirect(key) === direct) { oldest = key; break; }
69
+ }
70
+ if (oldest === undefined) break;
71
+ accountModelsCache.delete(oldest);
72
+ count -= 1;
73
+ }
74
+ };
75
+ evictClass(isDirect(accountId));
76
+ }
77
+
78
+ function currentCredentialIdentity(accountId: string): string | undefined {
79
+ if (accountId.startsWith(DIRECT_CALLER_ACCOUNT_PREFIX)) {
80
+ return `direct:${accountId.slice(DIRECT_CALLER_ACCOUNT_PREFIX.length)}`;
81
+ }
82
+ if (accountId === MAIN_CODEX_ACCOUNT_ID) {
83
+ const token = getMainAccountToken();
84
+ return token ? `main:${token.chatgptAccountId}` : undefined;
85
+ }
86
+ const record = readCodexAccountRecord(accountId);
87
+ if (!record?.credential || record.deletedAt != null) return undefined;
88
+ return `pool:${record.generation}:${record.credential.chatgptAccountId}`;
89
+ }
90
+
91
+ async function accountCredentialSnapshot(accountId: string): Promise<CodexModelEntitlementCredentialSnapshot | null> {
92
+ if (accountId === MAIN_CODEX_ACCOUNT_ID) {
93
+ const token = getMainAccountToken();
94
+ return token
95
+ ? {
96
+ accountId,
97
+ accessToken: token.accessToken,
98
+ chatgptAccountId: token.chatgptAccountId,
99
+ credentialIdentity: `main:${token.chatgptAccountId}`,
100
+ }
101
+ : null;
102
+ }
103
+ try {
104
+ const token = await getValidCodexToken(accountId);
105
+ return {
106
+ accountId,
107
+ accessToken: token.accessToken,
108
+ chatgptAccountId: token.chatgptAccountId,
109
+ credentialIdentity: `pool:${token.generation}:${token.chatgptAccountId}`,
110
+ };
111
+ } catch {
112
+ return null;
113
+ }
114
+ }
115
+
116
+ function parseAccountModels(text: string): ReadonlySet<string> | null {
117
+ try {
118
+ const payload = JSON.parse(text) as { models?: unknown };
119
+ if (!Array.isArray(payload.models)) return null;
120
+ const models = payload.models.flatMap(entry => {
121
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) return [];
122
+ const row = entry as { slug?: unknown; supported_in_api?: unknown; visibility?: unknown };
123
+ if (typeof row.slug !== "string" || row.supported_in_api !== true || row.visibility === "hide") return [];
124
+ return [row.slug];
125
+ });
126
+ return new Set(models);
127
+ } catch {
128
+ return null;
129
+ }
130
+ }
131
+
132
+ async function fetchAccountModels(
133
+ credential: CodexModelEntitlementCredentialSnapshot,
134
+ fetcher: typeof fetch,
135
+ now: number,
136
+ ): Promise<CachedAccountModels> {
137
+ const controller = new AbortController();
138
+ const timer = setTimeout(() => controller.abort(new DOMException("Codex model discovery timed out", "TimeoutError")), MODEL_ROSTER_TIMEOUT_MS);
139
+ try {
140
+ const headers = new Headers({
141
+ Authorization: `Bearer ${credential.accessToken}`,
142
+ Accept: "application/json",
143
+ });
144
+ if (credential.chatgptAccountId) headers.set("ChatGPT-Account-Id", credential.chatgptAccountId);
145
+ const response = await fetcher(CODEX_MODELS_URL, {
146
+ headers,
147
+ redirect: "error",
148
+ signal: controller.signal,
149
+ });
150
+ const body = await readBoundedResponseBody(response, {
151
+ signal: controller.signal,
152
+ maxBytes: MODEL_ROSTER_MAX_BYTES,
153
+ fatalUtf8: true,
154
+ });
155
+ const models = response.ok && body.displaySafe && !body.truncated
156
+ ? parseAccountModels(body.text)
157
+ : null;
158
+ return {
159
+ credentialIdentity: credential.credentialIdentity,
160
+ expiresAt: now + (models ? MODEL_ROSTER_TTL_MS : MODEL_ROSTER_FAILURE_TTL_MS),
161
+ models: models ?? new Set(),
162
+ confirmed: models !== null,
163
+ };
164
+ } catch {
165
+ return {
166
+ credentialIdentity: credential.credentialIdentity,
167
+ expiresAt: now + MODEL_ROSTER_FAILURE_TTL_MS,
168
+ models: new Set(),
169
+ confirmed: false,
170
+ };
171
+ } finally {
172
+ clearTimeout(timer);
173
+ }
174
+ }
175
+
176
+ function directCallerCredential(headers: Headers): CodexModelEntitlementCredentialSnapshot | null {
177
+ const match = /^Bearer\s+(\S+)$/i.exec(headers.get("authorization")?.trim() ?? "");
178
+ if (!match) return null;
179
+ const accessToken = match[1]!;
180
+ const chatgptAccountId = headers.get("chatgpt-account-id")?.trim() ?? "";
181
+ const fingerprint = createHash("sha256")
182
+ .update(accessToken)
183
+ .update("\0")
184
+ .update(chatgptAccountId)
185
+ .digest("hex");
186
+ return {
187
+ accountId: `${DIRECT_CALLER_ACCOUNT_PREFIX}${fingerprint}`,
188
+ accessToken,
189
+ chatgptAccountId,
190
+ credentialIdentity: `direct:${fingerprint}`,
191
+ };
192
+ }
193
+
194
+ async function modelsForCredential(
195
+ credential: CodexModelEntitlementCredentialSnapshot,
196
+ fetcher: typeof fetch,
197
+ now: number,
198
+ ): Promise<CachedAccountModels> {
199
+ const cached = accountModelsCache.get(credential.accountId);
200
+ if (
201
+ cached
202
+ && cached.credentialIdentity === credential.credentialIdentity
203
+ && cached.expiresAt > now
204
+ ) return cached;
205
+
206
+ const flightKey = `${credential.accountId}\u0000${credential.credentialIdentity}`;
207
+ const existing = accountModelsFlights.get(flightKey);
208
+ if (existing) return existing;
209
+ const flight = fetchAccountModels(credential, fetcher, now)
210
+ .then(result => {
211
+ if (currentCredentialIdentity(credential.accountId) === credential.credentialIdentity) {
212
+ boundedCacheSet(credential.accountId, result);
213
+ }
214
+ return result;
215
+ })
216
+ .finally(() => {
217
+ if (accountModelsFlights.get(flightKey) === flight) accountModelsFlights.delete(flightKey);
218
+ });
219
+ accountModelsFlights.set(flightKey, flight);
220
+ return flight;
221
+ }
222
+
223
+ function candidateAccountIds(config: Pick<OcxConfig, "codexAccounts">): string[] {
224
+ return [
225
+ MAIN_CODEX_ACCOUNT_ID,
226
+ ...(config.codexAccounts ?? [])
227
+ .filter(isSelectableCodexPoolAccount)
228
+ .map(account => account.id),
229
+ ];
230
+ }
231
+
232
+ /**
233
+ * Fetch the authenticated model roster for every locally usable Codex account.
234
+ *
235
+ * [Decision Log]
236
+ * - 목적과 의도: Account-gated native models must be advertised and selected only for accounts
237
+ * whose own authenticated upstream catalog confirms the model.
238
+ * - 기존 구현 및 제약 조건: The injected Codex catalog is static, while Pool may contain
239
+ * accounts with different entitlements. A global allowlist therefore exposed unusable rows.
240
+ * - 검토한 주요 대안: Infer access from plan labels, learn only after a failed prompt, or rewrite
241
+ * Daybreak to its current physical model.
242
+ * - 선택한 방식: Cache bounded authenticated `/models` rosters per credential generation and
243
+ * fail closed for unconfirmed accounts.
244
+ * - 다른 대안 대신 이 방식을 선택한 이유: Plan names do not prove grants, post-failure
245
+ * learning spends a real turn, and model rewriting changes the requested product identity.
246
+ * - 장점, 단점 및 영향: Catalog and routing share exact account evidence. Cold gated requests
247
+ * pay one bounded discovery call per account; discovery failure temporarily hides the gated row.
248
+ */
249
+ export async function resolveCodexModelEntitlements(
250
+ config: Pick<OcxConfig, "codexAccounts">,
251
+ options: CodexModelEntitlementResolveOptions = {},
252
+ ): Promise<CodexModelEntitlementSnapshot> {
253
+ const now = options.now ?? Date.now();
254
+ const fetcher = options.fetcher ?? fetch;
255
+ const credentials = options.credentials
256
+ ? [...options.credentials]
257
+ : (await Promise.all(candidateAccountIds(config).map(accountCredentialSnapshot)))
258
+ .filter((value): value is CodexModelEntitlementCredentialSnapshot => value !== null);
259
+ const results = await Promise.all(credentials.map(async credential => ({
260
+ credential,
261
+ result: await modelsForCredential(credential, fetcher, now),
262
+ })));
263
+ return {
264
+ modelsByAccount: new Map(results.map(({ credential, result }) => [credential.accountId, result.models])),
265
+ confirmedAccountIds: new Set(results.flatMap(({ credential, result }) => result.confirmed ? [credential.accountId] : [])),
266
+ credentialIdentities: new Map(results.map(({ credential }) => [credential.accountId, credential.credentialIdentity])),
267
+ };
268
+ }
269
+
270
+ /** Fail-closed entitlement check for a Direct request's own forwarded ChatGPT credential. */
271
+ export async function isDirectCallerEntitledToCodexModel(
272
+ headers: Headers,
273
+ modelId: string,
274
+ options: Pick<CodexModelEntitlementResolveOptions, "fetcher" | "now"> = {},
275
+ ): Promise<boolean> {
276
+ if (!ACCOUNT_GATED_NATIVE_OPENAI_MODELS.has(modelId)) return true;
277
+ const credential = directCallerCredential(headers);
278
+ if (!credential) return false;
279
+ const result = await modelsForCredential(
280
+ credential,
281
+ options.fetcher ?? fetch,
282
+ options.now ?? Date.now(),
283
+ );
284
+ return result.confirmed && result.models.has(modelId);
285
+ }
286
+
287
+ export function entitledCodexAccountIdsForModel(
288
+ snapshot: CodexModelEntitlementSnapshot,
289
+ modelId: string | undefined,
290
+ ): ReadonlySet<string> | undefined {
291
+ if (!modelId || !ACCOUNT_GATED_NATIVE_OPENAI_MODELS.has(modelId)) return undefined;
292
+ return new Set([...snapshot.modelsByAccount].flatMap(([accountId, models]) => (
293
+ snapshot.confirmedAccountIds.has(accountId) && models.has(modelId) ? [accountId] : []
294
+ )));
295
+ }
296
+
297
+ export function availableAccountGatedNativeModels(
298
+ snapshot: CodexModelEntitlementSnapshot,
299
+ eligibleAccountIds?: ReadonlySet<string>,
300
+ ): ReadonlySet<string> {
301
+ return new Set([...ACCOUNT_GATED_NATIVE_OPENAI_MODELS].filter(modelId => (
302
+ [...snapshot.modelsByAccount].some(([accountId, models]) => (
303
+ (!eligibleAccountIds || eligibleAccountIds.has(accountId))
304
+ && snapshot.confirmedAccountIds.has(accountId)
305
+ && models.has(modelId)
306
+ ))
307
+ )));
308
+ }
309
+
310
+ /** Synchronous projection for management/catalog readers after a discovery pass. */
311
+ export function cachedAvailableAccountGatedNativeModels(
312
+ now = Date.now(),
313
+ eligibleAccountIds?: ReadonlySet<string>,
314
+ ): ReadonlySet<string> {
315
+ return new Set([...ACCOUNT_GATED_NATIVE_OPENAI_MODELS].filter(modelId => (
316
+ [...accountModelsCache].some(([accountId, entry]) => (
317
+ (!eligibleAccountIds || eligibleAccountIds.has(accountId))
318
+ && !accountId.startsWith(DIRECT_CALLER_ACCOUNT_PREFIX)
319
+ && entry.confirmed
320
+ && entry.expiresAt > now
321
+ && entry.models.has(modelId)
322
+ ))
323
+ )));
324
+ }
325
+
326
+ export function isCodexModelEntitlementSnapshotCurrent(snapshot: CodexModelEntitlementSnapshot): boolean {
327
+ for (const [accountId, identity] of snapshot.credentialIdentities) {
328
+ if (currentCredentialIdentity(accountId) !== identity) return false;
329
+ }
330
+ return true;
331
+ }
332
+
333
+ export function invalidateCodexModelEntitlementsForAccount(accountId: string | null | undefined): void {
334
+ if (accountId) accountModelsCache.delete(accountId);
335
+ }
336
+
337
+ export function resetCodexModelEntitlementCacheForTests(): void {
338
+ accountModelsCache.clear();
339
+ accountModelsFlights.clear();
340
+ }
341
+
342
+ export function seedCodexModelEntitlementsForTests(
343
+ accountId: string,
344
+ models: readonly string[],
345
+ now = Date.now(),
346
+ ): void {
347
+ boundedCacheSet(accountId, {
348
+ credentialIdentity: `test:${accountId}`,
349
+ expiresAt: now + MODEL_ROSTER_TTL_MS,
350
+ models: new Set(models),
351
+ confirmed: true,
352
+ });
353
+ }
@@ -0,0 +1,47 @@
1
+ import type { AdmissionLease } from "../lib/admission";
2
+ import {
3
+ tryAcquireNativeMainProfileClaim as tryAcquireLifecycleNativeMainProfileClaim,
4
+ tryClaimNativeMainProfileForTurn as tryClaimLifecycleNativeMainProfileForTurn,
5
+ } from "../server/lifecycle";
6
+ import { isNativeMainTrafficBlocked } from "./native-profile-startup";
7
+
8
+ export interface NativeMainTurnClaimDeps {
9
+ /** Test seams for the synchronous precheck/claim/postcheck transition. */
10
+ isTrafficBlocked?: typeof isNativeMainTrafficBlocked;
11
+ claimTurn?: typeof tryClaimLifecycleNativeMainProfileForTurn;
12
+ }
13
+
14
+ /**
15
+ * Admit a physical native-main credential read on an existing turn.
16
+ *
17
+ * Lifecycle admission owns the scoped switch/shutdown fence while the startup
18
+ * gate owns retained journal/manual recovery. Keep their composition here so
19
+ * low-level server lifecycle code does not import NativeProfileManager through
20
+ * native-profile-startup and create a fragile dependency cycle.
21
+ */
22
+ export function tryClaimNativeMainProfileForTurn(
23
+ lease?: AdmissionLease,
24
+ deps: NativeMainTurnClaimDeps = {},
25
+ ): boolean {
26
+ const isBlocked = deps.isTrafficBlocked ?? isNativeMainTrafficBlocked;
27
+ const claimTurn = deps.claimTurn ?? tryClaimLifecycleNativeMainProfileForTurn;
28
+ if (isBlocked()) return false;
29
+ if (!claimTurn(lease)) return false;
30
+ if (!isBlocked()) return true;
31
+
32
+ // Recovery became visible between the precheck and lifecycle claim. This
33
+ // request must not read auth.json. Keep the caller-owned turn claimed until
34
+ // normal request cleanup: optional routed work may continue, and releasing
35
+ // the whole turn here would let shutdown/profile switching overlap it.
36
+ return false;
37
+ }
38
+
39
+ /** Acquire standalone ownership only when both native-main gates admit work. */
40
+ export function tryAcquireNativeMainProfileClaim(): AdmissionLease | null {
41
+ if (isNativeMainTrafficBlocked()) return null;
42
+ const claim = tryAcquireLifecycleNativeMainProfileClaim();
43
+ if (!claim) return null;
44
+ if (!isNativeMainTrafficBlocked()) return claim;
45
+ claim.release();
46
+ return null;
47
+ }
@@ -0,0 +1,187 @@
1
+ import {
2
+ closeSync,
3
+ constants as fsConstants,
4
+ fstatSync,
5
+ fsyncSync,
6
+ ftruncateSync,
7
+ lstatSync,
8
+ openSync,
9
+ readdirSync,
10
+ realpathSync,
11
+ unlinkSync,
12
+ } from "node:fs";
13
+ import { dirname, join, resolve } from "node:path";
14
+
15
+ import type { NativeProfileContext } from "./native-profile-store";
16
+ import { NativeProfileError } from "./native-profile-types";
17
+
18
+ const AUTH_TEMP_NAME = /^auth\.json\.ocx\.[1-9]\d*\.[1-9]\d*\.tmp$/;
19
+ const MAX_AUTH_TEMP_RESIDUES = 128;
20
+
21
+ interface PathIdentity {
22
+ readonly dev: bigint;
23
+ readonly ino: bigint;
24
+ }
25
+
26
+ export interface NativeMainAuthTempScrubTestSeam {
27
+ /** Test-only race seam. Production never supplies this callback. */
28
+ beforeOpen?: (path: string) => void;
29
+ /** Test-only removal-failure seam. Production never supplies this callback. */
30
+ beforeUnlink?: (path: string) => void;
31
+ }
32
+
33
+ export interface NativeMainAuthTempScrubResult {
34
+ scrubbed: number;
35
+ }
36
+
37
+ function cleanupRequired(): NativeProfileError {
38
+ return new NativeProfileError(
39
+ "AUTH_TEMP_CLEANUP_REQUIRED",
40
+ "A native-main credential write residue could not be safely removed; manual cleanup is required.",
41
+ 500,
42
+ false,
43
+ true,
44
+ );
45
+ }
46
+
47
+ function errorCode(error: unknown): string | undefined {
48
+ return error && typeof error === "object" && "code" in error
49
+ ? String((error as { code?: unknown }).code)
50
+ : undefined;
51
+ }
52
+
53
+ function sameIdentity(stats: { dev: bigint; ino: bigint }, expected: PathIdentity): boolean {
54
+ return stats.dev === expected.dev && stats.ino === expected.ino;
55
+ }
56
+
57
+ function samePath(left: string, right: string): boolean {
58
+ return resolve(left) === resolve(right);
59
+ }
60
+
61
+ function inspectCanonicalParent(path: string, expected?: PathIdentity): PathIdentity {
62
+ const absolute = resolve(path);
63
+ const entry = lstatSync(absolute, { bigint: true });
64
+ if (!entry.isDirectory() || entry.isSymbolicLink()) throw cleanupRequired();
65
+ const canonical = realpathSync.native(absolute);
66
+ if (!samePath(canonical, absolute)) throw cleanupRequired();
67
+ if (expected && !sameIdentity(entry, expected)) throw cleanupRequired();
68
+ return { dev: entry.dev, ino: entry.ino };
69
+ }
70
+
71
+ function inspectExactPath(path: string, parent: string, expected?: PathIdentity): PathIdentity {
72
+ const absolute = resolve(path);
73
+ if (!samePath(dirname(absolute), parent)) throw cleanupRequired();
74
+ const entry = lstatSync(absolute, { bigint: true });
75
+ if (!entry.isFile() || entry.isSymbolicLink() || entry.nlink !== 1n) throw cleanupRequired();
76
+ const canonical = realpathSync.native(absolute);
77
+ if (!samePath(canonical, absolute) || !samePath(dirname(canonical), parent)) throw cleanupRequired();
78
+ if (expected && !sameIdentity(entry, expected)) throw cleanupRequired();
79
+ return { dev: entry.dev, ino: entry.ino };
80
+ }
81
+
82
+ function exactResidues(parent: string, parentIdentity: PathIdentity): string[] {
83
+ inspectCanonicalParent(parent, parentIdentity);
84
+ const names = readdirSync(parent).filter(name => AUTH_TEMP_NAME.test(name)).sort();
85
+ inspectCanonicalParent(parent, parentIdentity);
86
+ if (names.length > MAX_AUTH_TEMP_RESIDUES) throw cleanupRequired();
87
+ return names;
88
+ }
89
+
90
+ function assertOpenIdentity(
91
+ fd: number,
92
+ path: string,
93
+ parent: string,
94
+ parentIdentity: PathIdentity,
95
+ expected: PathIdentity,
96
+ expectedLinks: bigint,
97
+ ): void {
98
+ inspectCanonicalParent(parent, parentIdentity);
99
+ const opened = fstatSync(fd, { bigint: true });
100
+ if (
101
+ !opened.isFile()
102
+ || !sameIdentity(opened, expected)
103
+ || opened.nlink !== expectedLinks
104
+ ) throw cleanupRequired();
105
+ inspectExactPath(path, parent, expected);
106
+ inspectCanonicalParent(parent, parentIdentity);
107
+ }
108
+
109
+ function scrubOne(
110
+ path: string,
111
+ parent: string,
112
+ parentIdentity: PathIdentity,
113
+ seam: NativeMainAuthTempScrubTestSeam,
114
+ ): void {
115
+ const observed = inspectExactPath(path, parent);
116
+ inspectCanonicalParent(parent, parentIdentity);
117
+ seam.beforeOpen?.(path);
118
+
119
+ const flags = process.platform === "win32"
120
+ ? fsConstants.O_RDWR
121
+ : fsConstants.O_RDWR | fsConstants.O_NOFOLLOW;
122
+ let fd: number | undefined;
123
+ let failed = false;
124
+ try {
125
+ fd = openSync(path, flags);
126
+ assertOpenIdentity(fd, path, parent, parentIdentity, observed, 1n);
127
+
128
+ ftruncateSync(fd, 0);
129
+ fsyncSync(fd);
130
+ const truncated = fstatSync(fd, { bigint: true });
131
+ if (!sameIdentity(truncated, observed) || truncated.nlink !== 1n || truncated.size !== 0n) {
132
+ throw cleanupRequired();
133
+ }
134
+ assertOpenIdentity(fd, path, parent, parentIdentity, observed, 1n);
135
+ seam.beforeUnlink?.(path);
136
+
137
+ // The lifetime owner and exclusive claim exclude cooperative OpenCodex writers.
138
+ // A malicious process running as the same OS user can still race Node's final
139
+ // identity-check/unlink gap and is intentionally outside this trusted-owner boundary.
140
+ unlinkSync(path);
141
+ const unlinked = fstatSync(fd, { bigint: true });
142
+ if (!sameIdentity(unlinked, observed) || unlinked.nlink !== 0n || unlinked.size !== 0n) {
143
+ throw cleanupRequired();
144
+ }
145
+ try {
146
+ lstatSync(path);
147
+ throw cleanupRequired();
148
+ } catch (error) {
149
+ if (error instanceof NativeProfileError) throw error;
150
+ if (errorCode(error) !== "ENOENT") throw error;
151
+ }
152
+ inspectCanonicalParent(parent, parentIdentity);
153
+ } catch (error) {
154
+ failed = true;
155
+ throw error;
156
+ } finally {
157
+ if (fd !== undefined) {
158
+ try { closeSync(fd); }
159
+ catch (error) { if (!failed) throw error; }
160
+ }
161
+ }
162
+ }
163
+
164
+ /**
165
+ * Remove only crash residues created by atomicWriteFileAsync for canonical auth.json.
166
+ * The caller must hold the lifetime native-main owner and exclusive credential claim.
167
+ */
168
+ export function scrubNativeMainAuthTempResidues(
169
+ context: NativeProfileContext,
170
+ seam: NativeMainAuthTempScrubTestSeam = {},
171
+ ): NativeMainAuthTempScrubResult {
172
+ try {
173
+ const parent = resolve(context.codexHome);
174
+ const parentIdentity = inspectCanonicalParent(parent);
175
+ const names = exactResidues(parent, parentIdentity);
176
+ for (const name of names) {
177
+ scrubOne(join(parent, name), parent, parentIdentity, seam);
178
+ }
179
+ // A cooperative writer cannot create a new residue while the owner and
180
+ // exclusive claim are held. Seeing one now is ambiguous, so admission stays closed.
181
+ if (exactResidues(parent, parentIdentity).length !== 0) throw cleanupRequired();
182
+ return { scrubbed: names.length };
183
+ } catch (error) {
184
+ if (error instanceof NativeProfileError) throw error;
185
+ throw cleanupRequired();
186
+ }
187
+ }