@yansigit/opencodex 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 (826) hide show
  1. package/AGENTS_INSTALL.md +109 -0
  2. package/LICENSE +21 -0
  3. package/README.md +303 -0
  4. package/assets/architecture.png +0 -0
  5. package/assets/banner.png +0 -0
  6. package/assets/claude-code-models.gif +0 -0
  7. package/assets/codex-app-picker.png +0 -0
  8. package/bin/ocx.mjs +587 -0
  9. package/bin/package-main.mjs +9 -0
  10. package/gui/dist/assets/index-BNJ7r4Gd.js +102 -0
  11. package/gui/dist/assets/index-CGoDO3uO.css +1 -0
  12. package/gui/dist/favicon.png +0 -0
  13. package/gui/dist/icons.svg +24 -0
  14. package/gui/dist/index.html +25 -0
  15. package/gui/dist/logo.png +0 -0
  16. package/gui/dist/provider-icons/alibaba-color.svg +1 -0
  17. package/gui/dist/provider-icons/antigravity-color.svg +1 -0
  18. package/gui/dist/provider-icons/claude-color.svg +1 -0
  19. package/gui/dist/provider-icons/cline-color.svg +16 -0
  20. package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -0
  21. package/gui/dist/provider-icons/commandcode-color.svg +1 -0
  22. package/gui/dist/provider-icons/copilot-color.svg +1 -0
  23. package/gui/dist/provider-icons/cursor-color.svg +2 -0
  24. package/gui/dist/provider-icons/deepseek-color.svg +1 -0
  25. package/gui/dist/provider-icons/discord.svg +1 -0
  26. package/gui/dist/provider-icons/firepass-color.svg +1 -0
  27. package/gui/dist/provider-icons/fireworks-color.svg +1 -0
  28. package/gui/dist/provider-icons/gemini-color.svg +1 -0
  29. package/gui/dist/provider-icons/github-copilot-color.svg +1 -0
  30. package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -0
  31. package/gui/dist/provider-icons/grok.svg +1 -0
  32. package/gui/dist/provider-icons/groq-color.svg +1 -0
  33. package/gui/dist/provider-icons/huggingface-color.svg +1 -0
  34. package/gui/dist/provider-icons/kimi-color.svg +1 -0
  35. package/gui/dist/provider-icons/kiro-color.svg +15 -0
  36. package/gui/dist/provider-icons/lm-studio-color.svg +1 -0
  37. package/gui/dist/provider-icons/mistral-color.svg +1 -0
  38. package/gui/dist/provider-icons/moonshot-color.svg +1 -0
  39. package/gui/dist/provider-icons/nvidia-color.svg +1 -0
  40. package/gui/dist/provider-icons/ollama-color.svg +1 -0
  41. package/gui/dist/provider-icons/openai.svg +1 -0
  42. package/gui/dist/provider-icons/opencode.svg +2 -0
  43. package/gui/dist/provider-icons/openrouter-color.svg +1 -0
  44. package/gui/dist/provider-icons/pi.svg +21 -0
  45. package/gui/dist/provider-icons/qianfan-color.svg +1 -0
  46. package/gui/dist/provider-icons/qwen-portal-color.svg +1 -0
  47. package/gui/dist/provider-icons/telegram.svg +1 -0
  48. package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -0
  49. package/gui/dist/provider-icons/vllm-color.svg +1 -0
  50. package/gui/dist/provider-icons/xiaomi-color.svg +1 -0
  51. package/package.json +108 -0
  52. package/src/AGENTS.md +28 -0
  53. package/src/adapters/anthropic-image-guard.ts +251 -0
  54. package/src/adapters/anthropic-image-normalize.ts +518 -0
  55. package/src/adapters/anthropic-output-schema.ts +137 -0
  56. package/src/adapters/anthropic.ts +1327 -0
  57. package/src/adapters/azure.ts +36 -0
  58. package/src/adapters/base.ts +121 -0
  59. package/src/adapters/client-fingerprint.ts +65 -0
  60. package/src/adapters/cline-pass-deepseek-v4-tool-replay.ts +69 -0
  61. package/src/adapters/command-code.ts +601 -0
  62. package/src/adapters/cursor/arg-codec.ts +38 -0
  63. package/src/adapters/cursor/arg-normalize.ts +104 -0
  64. package/src/adapters/cursor/checkpoint-store.ts +303 -0
  65. package/src/adapters/cursor/cursor-errors.ts +288 -0
  66. package/src/adapters/cursor/discovery.ts +333 -0
  67. package/src/adapters/cursor/effort-map.ts +151 -0
  68. package/src/adapters/cursor/exec-policy.ts +88 -0
  69. package/src/adapters/cursor/framing.ts +250 -0
  70. package/src/adapters/cursor/gen/agent_pb.ts +15274 -0
  71. package/src/adapters/cursor/h2-pool.ts +123 -0
  72. package/src/adapters/cursor/http1-bidi.ts +361 -0
  73. package/src/adapters/cursor/images.ts +704 -0
  74. package/src/adapters/cursor/kv-store.ts +52 -0
  75. package/src/adapters/cursor/live-models.ts +269 -0
  76. package/src/adapters/cursor/live-smoke-gate.ts +41 -0
  77. package/src/adapters/cursor/live-transport.ts +1653 -0
  78. package/src/adapters/cursor/mcp-config.ts +42 -0
  79. package/src/adapters/cursor/mcp-manager.ts +333 -0
  80. package/src/adapters/cursor/message-mapper.ts +49 -0
  81. package/src/adapters/cursor/native-exec-common.ts +76 -0
  82. package/src/adapters/cursor/native-exec-desktop.ts +184 -0
  83. package/src/adapters/cursor/native-exec-fs.ts +332 -0
  84. package/src/adapters/cursor/native-exec-mcp.ts +153 -0
  85. package/src/adapters/cursor/native-exec-network.ts +43 -0
  86. package/src/adapters/cursor/native-exec-shell.ts +547 -0
  87. package/src/adapters/cursor/native-exec-tools.ts +118 -0
  88. package/src/adapters/cursor/native-exec.ts +663 -0
  89. package/src/adapters/cursor/protobuf-events.ts +1381 -0
  90. package/src/adapters/cursor/protobuf-request.ts +1032 -0
  91. package/src/adapters/cursor/request-builder.ts +461 -0
  92. package/src/adapters/cursor/thread-continuity.ts +67 -0
  93. package/src/adapters/cursor/tool-definitions.ts +735 -0
  94. package/src/adapters/cursor/tool-result-normalize.ts +92 -0
  95. package/src/adapters/cursor/transport-retry.ts +132 -0
  96. package/src/adapters/cursor/transport.ts +79 -0
  97. package/src/adapters/cursor/types.ts +79 -0
  98. package/src/adapters/cursor.ts +322 -0
  99. package/src/adapters/google-antigravity-hosts.ts +48 -0
  100. package/src/adapters/google-antigravity-replay.ts +827 -0
  101. package/src/adapters/google-antigravity-tools.ts +105 -0
  102. package/src/adapters/google-antigravity-wire.ts +141 -0
  103. package/src/adapters/google-errors.ts +92 -0
  104. package/src/adapters/google-http.ts +460 -0
  105. package/src/adapters/google-tool-schema.ts +238 -0
  106. package/src/adapters/google-truncation.ts +24 -0
  107. package/src/adapters/google-wire-compiler.ts +232 -0
  108. package/src/adapters/google.ts +1377 -0
  109. package/src/adapters/identity.ts +77 -0
  110. package/src/adapters/image.ts +23 -0
  111. package/src/adapters/kiro-constants.ts +16 -0
  112. package/src/adapters/kiro-errors.ts +208 -0
  113. package/src/adapters/kiro-events.ts +197 -0
  114. package/src/adapters/kiro-images.ts +129 -0
  115. package/src/adapters/kiro-retry.ts +312 -0
  116. package/src/adapters/kiro-thinking.ts +112 -0
  117. package/src/adapters/kiro-tool-fallback.ts +36 -0
  118. package/src/adapters/kiro-tools.ts +224 -0
  119. package/src/adapters/kiro-truncation.ts +33 -0
  120. package/src/adapters/kiro-wire.ts +129 -0
  121. package/src/adapters/kiro.ts +1936 -0
  122. package/src/adapters/mimo-free.ts +280 -0
  123. package/src/adapters/openai-chat-url.ts +11 -0
  124. package/src/adapters/openai-chat.ts +1980 -0
  125. package/src/adapters/openai-responses-url.ts +16 -0
  126. package/src/adapters/openai-responses.ts +1911 -0
  127. package/src/adapters/registry.ts +175 -0
  128. package/src/adapters/responses-tool-schema.ts +67 -0
  129. package/src/adapters/run-turn-queue.ts +114 -0
  130. package/src/adapters/tool-call-id.ts +119 -0
  131. package/src/adapters/tool-catalog-nudge.ts +154 -0
  132. package/src/adapters/upstream-http-error.ts +48 -0
  133. package/src/adapters/xai-web-search.ts +185 -0
  134. package/src/bridge.ts +1986 -0
  135. package/src/chat/inbound.ts +319 -0
  136. package/src/chat/outbound.ts +821 -0
  137. package/src/claude/agents-inject.ts +266 -0
  138. package/src/claude/alias.ts +149 -0
  139. package/src/claude/auth-detect.ts +229 -0
  140. package/src/claude/auth-mode-migration.ts +32 -0
  141. package/src/claude/auth-mode.ts +62 -0
  142. package/src/claude/context-windows.ts +205 -0
  143. package/src/claude/desktop-3p-guard.ts +35 -0
  144. package/src/claude/desktop-3p-paths.ts +84 -0
  145. package/src/claude/desktop-3p.ts +615 -0
  146. package/src/claude/desktop-health.ts +26 -0
  147. package/src/claude/desktop-profile.ts +263 -0
  148. package/src/claude/gateway-cache.ts +107 -0
  149. package/src/claude/inbound-debug.ts +163 -0
  150. package/src/claude/inbound.ts +578 -0
  151. package/src/claude/model-info.ts +174 -0
  152. package/src/claude/outbound.ts +926 -0
  153. package/src/cli/access.ts +108 -0
  154. package/src/cli/account-api.ts +302 -0
  155. package/src/cli/account-auth.ts +250 -0
  156. package/src/cli/account-catalog-refresh.ts +14 -0
  157. package/src/cli/account-extended.ts +737 -0
  158. package/src/cli/account-main.ts +317 -0
  159. package/src/cli/account.ts +299 -0
  160. package/src/cli/agent-driven.ts +70 -0
  161. package/src/cli/agent.ts +290 -0
  162. package/src/cli/catalog-prewarm.ts +27 -0
  163. package/src/cli/claude-agent-startup-sync.ts +73 -0
  164. package/src/cli/claude-desktop.ts +213 -0
  165. package/src/cli/claude.ts +355 -0
  166. package/src/cli/codex-log-guard-doctor.ts +103 -0
  167. package/src/cli/codex-shim-autorestore.ts +47 -0
  168. package/src/cli/codex-shim-readiness.ts +76 -0
  169. package/src/cli/combo.ts +127 -0
  170. package/src/cli/config-command.ts +209 -0
  171. package/src/cli/debug.ts +228 -0
  172. package/src/cli/dispatch.ts +585 -0
  173. package/src/cli/doctor.ts +1202 -0
  174. package/src/cli/ensure-desired-integrations.ts +152 -0
  175. package/src/cli/export-command.ts +213 -0
  176. package/src/cli/help.ts +101 -0
  177. package/src/cli/index.ts +973 -0
  178. package/src/cli/init.ts +211 -0
  179. package/src/cli/integrations.ts +260 -0
  180. package/src/cli/interactive-confirm.ts +133 -0
  181. package/src/cli/lab.ts +607 -0
  182. package/src/cli/launcher-context.ts +77 -0
  183. package/src/cli/minimax.ts +497 -0
  184. package/src/cli/models-runtime.ts +245 -0
  185. package/src/cli/models.ts +422 -0
  186. package/src/cli/observe.ts +206 -0
  187. package/src/cli/opencode.ts +588 -0
  188. package/src/cli/provider-replit.ts +232 -0
  189. package/src/cli/provider-runtime.ts +179 -0
  190. package/src/cli/provider.ts +492 -0
  191. package/src/cli/ready.ts +301 -0
  192. package/src/cli/registry.ts +422 -0
  193. package/src/cli/replit-gateway-key-input.ts +138 -0
  194. package/src/cli/root.ts +86 -0
  195. package/src/cli/route-policy.ts +92 -0
  196. package/src/cli/runtime-api.ts +328 -0
  197. package/src/cli/star-prompt.ts +211 -0
  198. package/src/cli/status-oauth.ts +78 -0
  199. package/src/cli/status.ts +328 -0
  200. package/src/cli/system-command.ts +112 -0
  201. package/src/cli/system-restart-client.ts +146 -0
  202. package/src/cli/tray-proxy.ts +199 -0
  203. package/src/cli/v2.ts +268 -0
  204. package/src/cli.ts +10 -0
  205. package/src/clients/config-export.ts +1704 -0
  206. package/src/codex/account-id.ts +34 -0
  207. package/src/codex/account-label.ts +47 -0
  208. package/src/codex/account-lifecycle.ts +172 -0
  209. package/src/codex/account-namespace-match.ts +63 -0
  210. package/src/codex/account-namespaces.ts +195 -0
  211. package/src/codex/account-pause.ts +20 -0
  212. package/src/codex/account-priority.ts +83 -0
  213. package/src/codex/account-runtime-state.ts +31 -0
  214. package/src/codex/account-store.ts +544 -0
  215. package/src/codex/account-usability.ts +43 -0
  216. package/src/codex/admission.ts +256 -0
  217. package/src/codex/affinity-debug.ts +162 -0
  218. package/src/codex/agent-roles-sync.ts +225 -0
  219. package/src/codex/agent-roles.ts +238 -0
  220. package/src/codex/app-server-processes.ts +1143 -0
  221. package/src/codex/app-server-restart-service.ts +232 -0
  222. package/src/codex/auth-api.ts +2147 -0
  223. package/src/codex/auth-collision.ts +109 -0
  224. package/src/codex/auth-context.ts +665 -0
  225. package/src/codex/autostart-health.ts +156 -0
  226. package/src/codex/catalog/account-models.ts +67 -0
  227. package/src/codex/catalog/aggregation.ts +436 -0
  228. package/src/codex/catalog/bundled.ts +549 -0
  229. package/src/codex/catalog/effort.ts +446 -0
  230. package/src/codex/catalog/filesystem-evidence.ts +302 -0
  231. package/src/codex/catalog/kinds.ts +2 -0
  232. package/src/codex/catalog/metadata.ts +664 -0
  233. package/src/codex/catalog/native-models.ts +72 -0
  234. package/src/codex/catalog/parsing.ts +650 -0
  235. package/src/codex/catalog/provider-fetch.ts +2064 -0
  236. package/src/codex/catalog/sync.ts +1883 -0
  237. package/src/codex/catalog-admission.ts +199 -0
  238. package/src/codex/catalog-refresh-status.ts +105 -0
  239. package/src/codex/catalog-write-serialization.ts +242 -0
  240. package/src/codex/catalog.ts +14 -0
  241. package/src/codex/codex-write-lock.ts +384 -0
  242. package/src/codex/convergence-types.ts +614 -0
  243. package/src/codex/convergence.ts +651 -0
  244. package/src/codex/coordinator-doctor.ts +332 -0
  245. package/src/codex/custom-model-catalog-migration.ts +176 -0
  246. package/src/codex/data/upstream-models.json +830 -0
  247. package/src/codex/desired-state.ts +230 -0
  248. package/src/codex/exec-invocation.ts +22 -0
  249. package/src/codex/features.ts +1566 -0
  250. package/src/codex/generation.ts +202 -0
  251. package/src/codex/history-job.ts +407 -0
  252. package/src/codex/history-lock.ts +242 -0
  253. package/src/codex/history-migration-guardian.ts +108 -0
  254. package/src/codex/history-provider.ts +979 -0
  255. package/src/codex/history-transition.ts +105 -0
  256. package/src/codex/history-worker.ts +220 -0
  257. package/src/codex/home.ts +206 -0
  258. package/src/codex/inject-coordination.ts +290 -0
  259. package/src/codex/inject.ts +1733 -0
  260. package/src/codex/injected-marker.ts +106 -0
  261. package/src/codex/integration-record.ts +266 -0
  262. package/src/codex/internal/catalog-writer.ts +203 -0
  263. package/src/codex/internal/history-writer.ts +80 -0
  264. package/src/codex/journal.ts +225 -0
  265. package/src/codex/log-guard/inspect.ts +506 -0
  266. package/src/codex/log-guard/lock.ts +150 -0
  267. package/src/codex/log-guard/maintenance.ts +403 -0
  268. package/src/codex/log-guard/path-safety.ts +88 -0
  269. package/src/codex/log-guard/policy.ts +44 -0
  270. package/src/codex/log-guard/processes.ts +205 -0
  271. package/src/codex/log-guard/protection.ts +489 -0
  272. package/src/codex/log-guard/sqlite-errors.ts +9 -0
  273. package/src/codex/main-account-cache.ts +56 -0
  274. package/src/codex/main-account.ts +68 -0
  275. package/src/codex/management-convergence.ts +167 -0
  276. package/src/codex/model-cache.ts +273 -0
  277. package/src/codex/model-entitlements.ts +353 -0
  278. package/src/codex/native-main-admission.ts +47 -0
  279. package/src/codex/native-main-auth-temp.ts +187 -0
  280. package/src/codex/native-main-claim.ts +178 -0
  281. package/src/codex/native-main-lock-file.ts +162 -0
  282. package/src/codex/native-main-owner.ts +329 -0
  283. package/src/codex/native-profile-api.ts +247 -0
  284. package/src/codex/native-profile-manager.ts +1531 -0
  285. package/src/codex/native-profile-processes.ts +121 -0
  286. package/src/codex/native-profile-recovery.ts +99 -0
  287. package/src/codex/native-profile-stage-store.ts +387 -0
  288. package/src/codex/native-profile-startup.ts +492 -0
  289. package/src/codex/native-profile-store.ts +855 -0
  290. package/src/codex/native-profile-types.ts +120 -0
  291. package/src/codex/native-residue.ts +682 -0
  292. package/src/codex/paths.ts +144 -0
  293. package/src/codex/plan-from-token.ts +140 -0
  294. package/src/codex/plan.ts +40 -0
  295. package/src/codex/plugins-doctor.ts +242 -0
  296. package/src/codex/pool-rotation.ts +295 -0
  297. package/src/codex/project-config-warnings.ts +425 -0
  298. package/src/codex/prompt-journal.ts +352 -0
  299. package/src/codex/prompt-layers.ts +967 -0
  300. package/src/codex/prompt-lock.ts +143 -0
  301. package/src/codex/quota-rejection.ts +298 -0
  302. package/src/codex/quota.ts +573 -0
  303. package/src/codex/refresh.ts +62 -0
  304. package/src/codex/reset-credit-recovery.ts +1044 -0
  305. package/src/codex/routing.ts +1888 -0
  306. package/src/codex/runtime.ts +659 -0
  307. package/src/codex/shim.ts +2170 -0
  308. package/src/codex/subagent-defaults.ts +550 -0
  309. package/src/codex/subagent-model-fallback.ts +784 -0
  310. package/src/codex/sync.ts +319 -0
  311. package/src/codex/transition-state.ts +612 -0
  312. package/src/codex/upstream-host-health.ts +368 -0
  313. package/src/codex/user-identity.ts +557 -0
  314. package/src/codex/warmup.ts +298 -0
  315. package/src/codex/websocket-registry.ts +100 -0
  316. package/src/codex/write-coordination.ts +114 -0
  317. package/src/combos/failover.ts +160 -0
  318. package/src/combos/index.ts +45 -0
  319. package/src/combos/request.ts +94 -0
  320. package/src/combos/resolve.ts +232 -0
  321. package/src/combos/types.ts +398 -0
  322. package/src/config/provider-name.ts +24 -0
  323. package/src/config.ts +4041 -0
  324. package/src/fork/register.ts +3 -0
  325. package/src/generated/compatibility-version.json +3116 -0
  326. package/src/generated/model-metadata.ts +106 -0
  327. package/src/github/star-state.ts +203 -0
  328. package/src/grok/inject.ts +530 -0
  329. package/src/grok/inspect.ts +45 -0
  330. package/src/grok/status.ts +121 -0
  331. package/src/grok/sync.ts +66 -0
  332. package/src/images/artifacts.ts +516 -0
  333. package/src/images/fulfill-video.ts +163 -0
  334. package/src/images/fulfill.ts +149 -0
  335. package/src/images/index.ts +4 -0
  336. package/src/images/loop.ts +955 -0
  337. package/src/images/plan.ts +143 -0
  338. package/src/images/synthetic-tool.ts +133 -0
  339. package/src/images/types.ts +41 -0
  340. package/src/images/xai-client.ts +141 -0
  341. package/src/images/xai-video-client.ts +163 -0
  342. package/src/index.ts +22 -0
  343. package/src/integrations/config-io.ts +269 -0
  344. package/src/integrations/journal.ts +315 -0
  345. package/src/integrations/merge.ts +135 -0
  346. package/src/integrations/mutation-flight.ts +71 -0
  347. package/src/integrations/native/ownership-preflight.ts +202 -0
  348. package/src/integrations/omp-yaml-source.ts +358 -0
  349. package/src/integrations/owned-refresh.ts +74 -0
  350. package/src/integrations/ownership.ts +111 -0
  351. package/src/integrations/registry.ts +159 -0
  352. package/src/integrations/serialize.ts +314 -0
  353. package/src/integrations/state.ts +361 -0
  354. package/src/integrations/store.ts +103 -0
  355. package/src/integrations/writer-lock.ts +98 -0
  356. package/src/integrations/writer.ts +691 -0
  357. package/src/lab/artifacts/sanitize.ts +586 -0
  358. package/src/lab/artifacts/secure-fs.ts +475 -0
  359. package/src/lab/artifacts/store.ts +310 -0
  360. package/src/lab/automation/budgets.ts +78 -0
  361. package/src/lab/automation/config-persistence.ts +256 -0
  362. package/src/lab/automation/constants.ts +39 -0
  363. package/src/lab/automation/cooldown.ts +103 -0
  364. package/src/lab/automation/dispatch.ts +211 -0
  365. package/src/lab/automation/index.ts +13 -0
  366. package/src/lab/automation/orchestrator.ts +499 -0
  367. package/src/lab/automation/persistence.ts +512 -0
  368. package/src/lab/automation/planner.ts +371 -0
  369. package/src/lab/automation/policy.ts +136 -0
  370. package/src/lab/automation/queue.ts +191 -0
  371. package/src/lab/automation/recovery.ts +24 -0
  372. package/src/lab/automation/route-context.ts +21 -0
  373. package/src/lab/automation/run-key.ts +44 -0
  374. package/src/lab/automation/runs-query.ts +34 -0
  375. package/src/lab/automation/types.ts +160 -0
  376. package/src/lab/conformance/assertion.ts +325 -0
  377. package/src/lab/conformance/digest.ts +22 -0
  378. package/src/lab/conformance/executor.ts +741 -0
  379. package/src/lab/conformance/fixture-provider.ts +27 -0
  380. package/src/lab/conformance/fixtures/live-v1-cases.json +175 -0
  381. package/src/lab/conformance/fixtures/protocol-v1-cases.json +461 -0
  382. package/src/lab/conformance/harness-budget.ts +47 -0
  383. package/src/lab/conformance/index.ts +5 -0
  384. package/src/lab/conformance/jcs.ts +64 -0
  385. package/src/lab/conformance/json-pointer.ts +39 -0
  386. package/src/lab/conformance/manifest.ts +180 -0
  387. package/src/lab/conformance/mcp-stub.ts +179 -0
  388. package/src/lab/conformance/negative-controls.ts +164 -0
  389. package/src/lab/conformance/observation.ts +355 -0
  390. package/src/lab/conformance/runner.ts +68 -0
  391. package/src/lab/conformance/sse-normalize.ts +59 -0
  392. package/src/lab/conformance/suite-manifest.ts +78 -0
  393. package/src/lab/conformance/types.ts +214 -0
  394. package/src/lab/constants.ts +126 -0
  395. package/src/lab/digest.ts +64 -0
  396. package/src/lab/events/errors.ts +9 -0
  397. package/src/lab/events/limits.ts +117 -0
  398. package/src/lab/events/types.ts +229 -0
  399. package/src/lab/events/validate.ts +781 -0
  400. package/src/lab/fabric/constants.ts +40 -0
  401. package/src/lab/fabric/executor.ts +492 -0
  402. package/src/lab/fabric/index.ts +80 -0
  403. package/src/lab/fabric/manifest.ts +222 -0
  404. package/src/lab/fabric/observe.ts +489 -0
  405. package/src/lab/fabric/patch.ts +79 -0
  406. package/src/lab/fabric/producer-child.ts +139 -0
  407. package/src/lab/fabric/producer-isolate.ts +276 -0
  408. package/src/lab/fabric/producer-protocol.ts +61 -0
  409. package/src/lab/fabric/scratch.ts +439 -0
  410. package/src/lab/fabric/subject.ts +106 -0
  411. package/src/lab/fabric/types.ts +134 -0
  412. package/src/lab/fabric/verifier.ts +98 -0
  413. package/src/lab/index.ts +54 -0
  414. package/src/lab/ledger/artifact-refs.ts +127 -0
  415. package/src/lab/ledger/invalidation.ts +136 -0
  416. package/src/lab/ledger/purge.ts +310 -0
  417. package/src/lab/ledger/store.ts +532 -0
  418. package/src/lab/live/credential-lease.ts +53 -0
  419. package/src/lab/live/destination.ts +155 -0
  420. package/src/lab/live/executor.ts +336 -0
  421. package/src/lab/live/inert-tools.ts +56 -0
  422. package/src/lab/live/manifest.ts +85 -0
  423. package/src/lab/live/mcp-loopback.ts +57 -0
  424. package/src/lab/live/runner.ts +19 -0
  425. package/src/lab/live/sandbox.ts +61 -0
  426. package/src/lab/live/suite-manifest.ts +41 -0
  427. package/src/lab/live/transport.ts +118 -0
  428. package/src/lab/live/types.ts +197 -0
  429. package/src/lab/observe/from-conformance.ts +301 -0
  430. package/src/lab/observe/from-live.ts +117 -0
  431. package/src/lab/paths.ts +153 -0
  432. package/src/lab/projection/rebuild.ts +495 -0
  433. package/src/lab/projection/schema.ts +135 -0
  434. package/src/lab/projection/verdicts.ts +474 -0
  435. package/src/lab/projection/verification.ts +412 -0
  436. package/src/lab/public/bundle.ts +217 -0
  437. package/src/lab/public/community-authority.ts +175 -0
  438. package/src/lab/public/community-files.ts +29 -0
  439. package/src/lab/public/community.ts +479 -0
  440. package/src/lab/public/file-safety.ts +155 -0
  441. package/src/lab/public/ids.ts +26 -0
  442. package/src/lab/public/index.ts +16 -0
  443. package/src/lab/public/mutation-lock.ts +424 -0
  444. package/src/lab/public/operator.ts +353 -0
  445. package/src/lab/public/origin-purge.ts +79 -0
  446. package/src/lab/public/origin.ts +203 -0
  447. package/src/lab/public/privacy.ts +143 -0
  448. package/src/lab/public/private-file.ts +261 -0
  449. package/src/lab/public/project.ts +124 -0
  450. package/src/lab/public/purge-test-fault.ts +21 -0
  451. package/src/lab/public/purge.ts +223 -0
  452. package/src/lab/public/registry.ts +44 -0
  453. package/src/lab/public/revocation.ts +252 -0
  454. package/src/lab/public/signature.ts +243 -0
  455. package/src/lab/public/storage.ts +105 -0
  456. package/src/lab/public/strict-json.ts +206 -0
  457. package/src/lab/public/time.ts +26 -0
  458. package/src/lab/public/types.ts +172 -0
  459. package/src/lab/public/validate.ts +391 -0
  460. package/src/lab/query/catalog.ts +101 -0
  461. package/src/lab/query/connection.ts +107 -0
  462. package/src/lab/query/constants.ts +4 -0
  463. package/src/lab/query/cursor.ts +132 -0
  464. package/src/lab/query/dto-map.ts +277 -0
  465. package/src/lab/query/errors.ts +22 -0
  466. package/src/lab/query/freshness.ts +53 -0
  467. package/src/lab/query/index.ts +45 -0
  468. package/src/lab/query/latest-observation.ts +59 -0
  469. package/src/lab/query/passive-production.ts +159 -0
  470. package/src/lab/query/queries.ts +444 -0
  471. package/src/lab/query/types.ts +266 -0
  472. package/src/lab/subject/behavior-fingerprint.ts +77 -0
  473. package/src/lab/subject/installation-salt.ts +112 -0
  474. package/src/lab/subject/protocol-subject.ts +80 -0
  475. package/src/lab/subject/route-subject.ts +74 -0
  476. package/src/lib/abort.ts +146 -0
  477. package/src/lib/admin-secrets.ts +25 -0
  478. package/src/lib/admission.ts +83 -0
  479. package/src/lib/app-owned-memory-stores.ts +195 -0
  480. package/src/lib/app-owned-memory.ts +265 -0
  481. package/src/lib/bounded-body.ts +346 -0
  482. package/src/lib/bun-binary-validator.d.mts +3 -0
  483. package/src/lib/bun-binary-validator.mjs +18 -0
  484. package/src/lib/bun-runtime.ts +184 -0
  485. package/src/lib/bun-stream-caps.ts +130 -0
  486. package/src/lib/codex-restart-contract.ts +120 -0
  487. package/src/lib/config-ownership.ts +364 -0
  488. package/src/lib/crash-guard.ts +344 -0
  489. package/src/lib/debug-log-buffer.ts +83 -0
  490. package/src/lib/debug-settings.ts +108 -0
  491. package/src/lib/debug.ts +31 -0
  492. package/src/lib/destination-policy.ts +380 -0
  493. package/src/lib/errors.ts +406 -0
  494. package/src/lib/eventstream-decoder.ts +253 -0
  495. package/src/lib/fabric-task-execution-authority.ts +7 -0
  496. package/src/lib/fabric-task-host.ts +29 -0
  497. package/src/lib/gcp-adc.ts +341 -0
  498. package/src/lib/injection-debug-log.ts +58 -0
  499. package/src/lib/lab-activation.ts +223 -0
  500. package/src/lib/lab-live-execution-authority.ts +13 -0
  501. package/src/lib/lab-live-host.ts +30 -0
  502. package/src/lib/lab-live-pinned-sender.ts +56 -0
  503. package/src/lib/lab-live-route-production.ts +130 -0
  504. package/src/lib/lab-passive-linker-registration.ts +26 -0
  505. package/src/lib/local-management-attestation.ts +51 -0
  506. package/src/lib/local-management-capability.ts +100 -0
  507. package/src/lib/local-provider-reload-contract.ts +100 -0
  508. package/src/lib/open-url.ts +25 -0
  509. package/src/lib/optional-shutdown-hooks.ts +57 -0
  510. package/src/lib/pinned-http.ts +270 -0
  511. package/src/lib/privacy.ts +20 -0
  512. package/src/lib/process-control.ts +168 -0
  513. package/src/lib/provider-outbound.ts +210 -0
  514. package/src/lib/provider-url.ts +14 -0
  515. package/src/lib/proxy-env.ts +18 -0
  516. package/src/lib/redact.ts +521 -0
  517. package/src/lib/retry-after.ts +55 -0
  518. package/src/lib/self-launch-argv.ts +15 -0
  519. package/src/lib/server-resource-ownership.ts +71 -0
  520. package/src/lib/service-secrets.ts +25 -0
  521. package/src/lib/shadow-call.ts +61 -0
  522. package/src/lib/sidecar-tracker.ts +52 -0
  523. package/src/lib/sse-decoder.ts +364 -0
  524. package/src/lib/state-store-registrations.ts +119 -0
  525. package/src/lib/state-store-sweeper.ts +184 -0
  526. package/src/lib/system-restart-contract.ts +73 -0
  527. package/src/lib/test-home-guard.ts +90 -0
  528. package/src/lib/token-estimate.ts +86 -0
  529. package/src/lib/tool-argument-integers.ts +202 -0
  530. package/src/lib/translator-budget.ts +400 -0
  531. package/src/lib/upstream-http-version.ts +57 -0
  532. package/src/lib/upstream-reachability.ts +95 -0
  533. package/src/lib/upstream-retry.ts +392 -0
  534. package/src/lib/win-exec.ts +115 -0
  535. package/src/lib/win-paths.ts +68 -0
  536. package/src/lib/windows-atomic-replace.ts +156 -0
  537. package/src/lib/windows-elevation.ts +773 -0
  538. package/src/lib/windows-secret-acl.ts +854 -0
  539. package/src/lib/windows-service-wrappers.ts +72 -0
  540. package/src/lib/windows-text.ts +106 -0
  541. package/src/lib/windows-user-principal.ts +341 -0
  542. package/src/lib/winsw.ts +403 -0
  543. package/src/oauth/account-import/google-antigravity-adapter.ts +74 -0
  544. package/src/oauth/account-import/index.ts +15 -0
  545. package/src/oauth/account-import/parser.ts +83 -0
  546. package/src/oauth/account-import/registry.ts +18 -0
  547. package/src/oauth/account-import/service.ts +75 -0
  548. package/src/oauth/account-import/types.ts +91 -0
  549. package/src/oauth/anthropic-routing.ts +594 -0
  550. package/src/oauth/anthropic.ts +188 -0
  551. package/src/oauth/antigravity-routing.ts +151 -0
  552. package/src/oauth/callback-server.ts +300 -0
  553. package/src/oauth/chatgpt.ts +161 -0
  554. package/src/oauth/command-code.ts +239 -0
  555. package/src/oauth/cursor.ts +252 -0
  556. package/src/oauth/github-copilot.ts +428 -0
  557. package/src/oauth/google-antigravity.ts +262 -0
  558. package/src/oauth/health.ts +407 -0
  559. package/src/oauth/index.ts +1504 -0
  560. package/src/oauth/key-providers.ts +124 -0
  561. package/src/oauth/kimi.ts +227 -0
  562. package/src/oauth/kiro-credentials.ts +726 -0
  563. package/src/oauth/kiro.ts +621 -0
  564. package/src/oauth/local-token-detect.ts +130 -0
  565. package/src/oauth/log.ts +50 -0
  566. package/src/oauth/login-cli.ts +223 -0
  567. package/src/oauth/nous.ts +798 -0
  568. package/src/oauth/pkce.ts +15 -0
  569. package/src/oauth/store.ts +728 -0
  570. package/src/oauth/token-guardian.ts +309 -0
  571. package/src/oauth/types.ts +62 -0
  572. package/src/oauth/xai.ts +241 -0
  573. package/src/providers/alibaba-region-backup.ts +75 -0
  574. package/src/providers/alibaba-region-migration.ts +156 -0
  575. package/src/providers/alibaba-region-startup.ts +36 -0
  576. package/src/providers/antigravity-models.ts +695 -0
  577. package/src/providers/antigravity-quota.ts +216 -0
  578. package/src/providers/api-keys.ts +140 -0
  579. package/src/providers/base-url-choices.ts +74 -0
  580. package/src/providers/codex-capacity.ts +292 -0
  581. package/src/providers/command-code-efforts.ts +144 -0
  582. package/src/providers/context-cap.ts +82 -0
  583. package/src/providers/cursor-pool.ts +72 -0
  584. package/src/providers/derive.ts +586 -0
  585. package/src/providers/fastwire.ts +501 -0
  586. package/src/providers/free-directory.ts +187 -0
  587. package/src/providers/github-copilot-transport.ts +56 -0
  588. package/src/providers/google-vertex-location.ts +14 -0
  589. package/src/providers/key-failover.ts +271 -0
  590. package/src/providers/kiro-models.ts +67 -0
  591. package/src/providers/label.ts +19 -0
  592. package/src/providers/model-discovery-limits.ts +16 -0
  593. package/src/providers/model-discovery.ts +449 -0
  594. package/src/providers/model-rename-migration.ts +255 -0
  595. package/src/providers/model-rename-startup.ts +28 -0
  596. package/src/providers/openai-sidecar.ts +243 -0
  597. package/src/providers/openai-tier-startup.ts +56 -0
  598. package/src/providers/openai-tiers.ts +423 -0
  599. package/src/providers/openai-virtual-models.ts +83 -0
  600. package/src/providers/opencode-zen-rate-limit.ts +102 -0
  601. package/src/providers/openrouter-routing.ts +102 -0
  602. package/src/providers/provider-id-rewrite.ts +185 -0
  603. package/src/providers/quota.ts +2345 -0
  604. package/src/providers/registry.ts +2918 -0
  605. package/src/providers/replit/constants.ts +27 -0
  606. package/src/providers/replit/derive.ts +85 -0
  607. package/src/providers/replit/headers.ts +28 -0
  608. package/src/providers/replit/origin.ts +55 -0
  609. package/src/providers/replit/pair-install-response.ts +72 -0
  610. package/src/providers/replit/probe.ts +199 -0
  611. package/src/providers/replit/setup.ts +350 -0
  612. package/src/providers/request-pacing.ts +310 -0
  613. package/src/providers/service-tier.ts +277 -0
  614. package/src/providers/slug-codec.ts +103 -0
  615. package/src/providers/static-model-discovery.ts +86 -0
  616. package/src/providers/xai-responses-opt-in.ts +15 -0
  617. package/src/providers/xai-transport.ts +148 -0
  618. package/src/reasoning-effort.ts +183 -0
  619. package/src/responses/compaction.ts +142 -0
  620. package/src/responses/custom-tool-compat.ts +266 -0
  621. package/src/responses/hosted-tool-policy.ts +9 -0
  622. package/src/responses/namespace-tool-compat.ts +355 -0
  623. package/src/responses/parser.ts +838 -0
  624. package/src/responses/provider-continuation.ts +98 -0
  625. package/src/responses/provider-opaque-metadata.ts +73 -0
  626. package/src/responses/reasoning-envelope.ts +60 -0
  627. package/src/responses/reasoning-replay-cache.ts +426 -0
  628. package/src/responses/schema.ts +165 -0
  629. package/src/responses/spill-store.ts +459 -0
  630. package/src/responses/state.ts +1433 -0
  631. package/src/responses/thought-signature-replay.ts +347 -0
  632. package/src/responses/tool-groups.ts +19 -0
  633. package/src/responses/tool-search-compat.ts +301 -0
  634. package/src/responses/truncated-stop-reason.ts +60 -0
  635. package/src/router.ts +761 -0
  636. package/src/routing/analytics.ts +378 -0
  637. package/src/routing/capability.ts +244 -0
  638. package/src/routing/compatibility/assemble.ts +73 -0
  639. package/src/routing/compatibility/behavior.ts +278 -0
  640. package/src/routing/compatibility/catalog.ts +99 -0
  641. package/src/routing/compatibility/endpoint.ts +52 -0
  642. package/src/routing/compatibility/lab-evidence-provider.ts +130 -0
  643. package/src/routing/compatibility/policy.ts +181 -0
  644. package/src/routing/compatibility/provider-slot.ts +56 -0
  645. package/src/routing/compatibility/reader.ts +110 -0
  646. package/src/routing/compatibility/subject.ts +191 -0
  647. package/src/routing/compatibility/types.ts +64 -0
  648. package/src/routing/compatibility/version.ts +104 -0
  649. package/src/routing/cost.ts +77 -0
  650. package/src/routing/evaluator.ts +495 -0
  651. package/src/routing/health.ts +412 -0
  652. package/src/routing/history/cursor.ts +43 -0
  653. package/src/routing/history/indexer.ts +605 -0
  654. package/src/routing/history/schema.ts +72 -0
  655. package/src/routing/profile-namespace.ts +15 -0
  656. package/src/routing/profile.ts +547 -0
  657. package/src/routing/quota.ts +145 -0
  658. package/src/routing/request-evidence.ts +45 -0
  659. package/src/routing/trace.ts +776 -0
  660. package/src/server/adapter-resolve.ts +53 -0
  661. package/src/server/auth-cors.ts +751 -0
  662. package/src/server/background-lifecycle.ts +182 -0
  663. package/src/server/chat-completions.ts +442 -0
  664. package/src/server/chat-native-sse.ts +331 -0
  665. package/src/server/chat-native.ts +426 -0
  666. package/src/server/claude-messages.ts +1030 -0
  667. package/src/server/direct-local-http.ts +347 -0
  668. package/src/server/effort-policy.ts +190 -0
  669. package/src/server/github-copilot-responses-repair.ts +338 -0
  670. package/src/server/gui-static.ts +152 -0
  671. package/src/server/image-retry.ts +42 -0
  672. package/src/server/images.ts +568 -0
  673. package/src/server/index.ts +1813 -0
  674. package/src/server/lifecycle.ts +498 -0
  675. package/src/server/live.ts +717 -0
  676. package/src/server/local-management-read-client.ts +90 -0
  677. package/src/server/local-provider-reload-client.ts +137 -0
  678. package/src/server/management/agent-settings-routes.ts +1433 -0
  679. package/src/server/management/api-access.ts +141 -0
  680. package/src/server/management/api-key-usage.ts +193 -0
  681. package/src/server/management/body.ts +41 -0
  682. package/src/server/management/combo-routes.ts +263 -0
  683. package/src/server/management/config-routes.ts +835 -0
  684. package/src/server/management/context.ts +113 -0
  685. package/src/server/management/integration-routes.ts +498 -0
  686. package/src/server/management/lab-automation-routes.ts +206 -0
  687. package/src/server/management/lab-routes.ts +563 -0
  688. package/src/server/management/logs-usage-routes.ts +586 -0
  689. package/src/server/management/model-routes.ts +560 -0
  690. package/src/server/management/model-rows.ts +163 -0
  691. package/src/server/management/native-integration-routes.ts +769 -0
  692. package/src/server/management/oauth-account-routes.ts +637 -0
  693. package/src/server/management/provider-capability-config.ts +48 -0
  694. package/src/server/management/provider-routes.ts +1033 -0
  695. package/src/server/management/replit-provider-routes.ts +86 -0
  696. package/src/server/management/request-history-routes.ts +191 -0
  697. package/src/server/management/routing-analytics-routes.ts +74 -0
  698. package/src/server/management/routing-profile-routes.ts +385 -0
  699. package/src/server/management/shared.ts +286 -0
  700. package/src/server/management/sidebar-routes.ts +106 -0
  701. package/src/server/management/storage-log-guard-routes.ts +186 -0
  702. package/src/server/management/sync-response.ts +69 -0
  703. package/src/server/management/system-restart.ts +435 -0
  704. package/src/server/management/system-routes.ts +194 -0
  705. package/src/server/management/usage-summary-cache.ts +94 -0
  706. package/src/server/management/vision-sidecar-options.ts +167 -0
  707. package/src/server/management/web-search-sidecar-options.ts +120 -0
  708. package/src/server/management-api.ts +314 -0
  709. package/src/server/management-auth.ts +482 -0
  710. package/src/server/memory-watchdog.ts +156 -0
  711. package/src/server/passive-route-linker.ts +66 -0
  712. package/src/server/port-reclaim.ts +307 -0
  713. package/src/server/ports.ts +156 -0
  714. package/src/server/proxy-liveness.ts +328 -0
  715. package/src/server/readiness.ts +99 -0
  716. package/src/server/relay-eager.ts +353 -0
  717. package/src/server/relay.ts +1209 -0
  718. package/src/server/request-decompress.ts +239 -0
  719. package/src/server/request-log-conversation.ts +168 -0
  720. package/src/server/request-log.ts +1259 -0
  721. package/src/server/responses/agent-task-recovery-cache.ts +143 -0
  722. package/src/server/responses/agent-task-recovery.ts +465 -0
  723. package/src/server/responses/collaboration.ts +551 -0
  724. package/src/server/responses/compact.ts +771 -0
  725. package/src/server/responses/core.ts +5389 -0
  726. package/src/server/responses/empty-completion-guard.ts +276 -0
  727. package/src/server/responses/encrypted-payload.ts +331 -0
  728. package/src/server/responses/fetch-helpers.ts +232 -0
  729. package/src/server/responses/input-admission.ts +185 -0
  730. package/src/server/responses/pacing-overload.ts +13 -0
  731. package/src/server/responses/passthrough-error.ts +78 -0
  732. package/src/server/responses/policy-fallback.ts +178 -0
  733. package/src/server/responses/responses-field-backfill.ts +251 -0
  734. package/src/server/responses/terminal-guard.ts +251 -0
  735. package/src/server/responses/upstream-error.ts +53 -0
  736. package/src/server/responses/ws-upstream.ts +308 -0
  737. package/src/server/responses-custom-tool-repair.ts +282 -0
  738. package/src/server/responses-image-gen-repair.ts +132 -0
  739. package/src/server/responses-item-id-repair.ts +272 -0
  740. package/src/server/responses-json-events.ts +90 -0
  741. package/src/server/responses-model-rewrite.ts +29 -0
  742. package/src/server/responses-reasoning-summary-rewrite.ts +178 -0
  743. package/src/server/responses-snapshot-repair.ts +621 -0
  744. package/src/server/responses-terminal-repair.ts +342 -0
  745. package/src/server/responses-tool-search-repair.ts +267 -0
  746. package/src/server/responses-undeclared-tool-guard.ts +153 -0
  747. package/src/server/responses.ts +25 -0
  748. package/src/server/search.ts +201 -0
  749. package/src/server/sse-frame-buffer.ts +292 -0
  750. package/src/server/sse-payload-rewrite.ts +263 -0
  751. package/src/server/startup-action-control.ts +315 -0
  752. package/src/server/startup-health-cache.ts +131 -0
  753. package/src/server/system-env.ts +484 -0
  754. package/src/server/windows-tcp-drop.ts +184 -0
  755. package/src/server/windows-tray-control.ts +41 -0
  756. package/src/server/ws-bridge.ts +472 -0
  757. package/src/service-manager-probe.ts +892 -0
  758. package/src/service.ts +3575 -0
  759. package/src/sidecar/auth.ts +92 -0
  760. package/src/sidecar/candidates.ts +83 -0
  761. package/src/stall-timeout.ts +20 -0
  762. package/src/storage/cleanup-job.ts +57 -0
  763. package/src/storage/cleanup.ts +3085 -0
  764. package/src/storage/policy-job.ts +457 -0
  765. package/src/storage/policy-scheduler.ts +40 -0
  766. package/src/storage/policy-worker.ts +59 -0
  767. package/src/storage/policy.ts +527 -0
  768. package/src/storage/restore-job.ts +299 -0
  769. package/src/storage/restore-worker.ts +58 -0
  770. package/src/storage/scanner.ts +238 -0
  771. package/src/storage/storage-mutation-coordinator.ts +139 -0
  772. package/src/storage/worker-lifecycle.ts +215 -0
  773. package/src/tray/assets/opencodex-tray-offline.ico +0 -0
  774. package/src/tray/assets/opencodex-tray-online.ico +0 -0
  775. package/src/tray/assets/opencodex-tray-warning.ico +0 -0
  776. package/src/tray/assets/opencodex-tray.png +0 -0
  777. package/src/tray/windows-tray.ps1 +364 -0
  778. package/src/tray/windows.ts +757 -0
  779. package/src/types/accounts.ts +37 -0
  780. package/src/types/config.ts +876 -0
  781. package/src/types/provider.ts +545 -0
  782. package/src/types/request.ts +384 -0
  783. package/src/types/tools.ts +131 -0
  784. package/src/types/wire.ts +80 -0
  785. package/src/types.ts +106 -0
  786. package/src/update/badge.ts +72 -0
  787. package/src/update/index.ts +415 -0
  788. package/src/update/job.ts +1887 -0
  789. package/src/update/notify.ts +263 -0
  790. package/src/update/npm-cache-preflight.d.mts +47 -0
  791. package/src/update/npm-cache-preflight.mjs +201 -0
  792. package/src/update/npm-invocation.d.mts +23 -0
  793. package/src/update/npm-invocation.mjs +94 -0
  794. package/src/update/transactional-install.d.mts +22 -0
  795. package/src/update/transactional-install.mjs +259 -0
  796. package/src/update/tray-update-plan.d.mts +18 -0
  797. package/src/update/tray-update-plan.mjs +38 -0
  798. package/src/usage/cost.ts +625 -0
  799. package/src/usage/debug.ts +97 -0
  800. package/src/usage/expected-prices.ts +416 -0
  801. package/src/usage/log.ts +1223 -0
  802. package/src/usage/summary.ts +753 -0
  803. package/src/usage/totals.ts +14 -0
  804. package/src/usage/user-cost-overlay-reconciler.ts +313 -0
  805. package/src/usage/user-cost-overlays.ts +314 -0
  806. package/src/vision/anthropic-describe.ts +189 -0
  807. package/src/vision/backends.ts +97 -0
  808. package/src/vision/describe.ts +131 -0
  809. package/src/vision/eligibility.ts +250 -0
  810. package/src/vision/index.ts +681 -0
  811. package/src/vision/reasoning.ts +55 -0
  812. package/src/vision/routed-describe.ts +175 -0
  813. package/src/vision/timeout-bounds.ts +9 -0
  814. package/src/web-search/anthropic-executor.ts +195 -0
  815. package/src/web-search/backends.ts +108 -0
  816. package/src/web-search/exa-executor.ts +88 -0
  817. package/src/web-search/executor.ts +113 -0
  818. package/src/web-search/format-result.ts +89 -0
  819. package/src/web-search/gemini-executor.ts +141 -0
  820. package/src/web-search/index.ts +331 -0
  821. package/src/web-search/loop.ts +896 -0
  822. package/src/web-search/parse.ts +315 -0
  823. package/src/web-search/progress-stream.ts +342 -0
  824. package/src/web-search/sources.ts +60 -0
  825. package/src/web-search/synthetic-tool.ts +47 -0
  826. package/src/web-search/xai-executor.ts +219 -0
@@ -0,0 +1,737 @@
1
+ import { loadConfig } from "../config";
2
+ import { closeSync, openSync, readSync } from "node:fs";
3
+ import {
4
+ MAX_ACCOUNT_PRIORITY,
5
+ MIN_ACCOUNT_PRIORITY,
6
+ normalizeAccountPriority,
7
+ parseAccountPriority,
8
+ } from "../codex/pool-rotation";
9
+ import {
10
+ apiError,
11
+ apiJson,
12
+ classifyAccount,
13
+ fetchCodexRows,
14
+ fetchProviderQuotaReport,
15
+ fetchRows,
16
+ proxyUnreachable,
17
+ resolveBaseUrl,
18
+ type AccountDeps, type AccountStdin, type FamilyRows,
19
+ type ProviderQuotaDto, type ProviderQuotaReportDto,
20
+ } from "./account-api";
21
+ import {
22
+ codexCatalogRefreshPending,
23
+ warnIfCodexCatalogRefreshPending,
24
+ } from "./account-catalog-refresh";
25
+ import {
26
+ ACCOUNT_IMPORT_DEADLINE_MS,
27
+ ACCOUNT_IMPORT_FORMAT,
28
+ ACCOUNT_IMPORT_MAX_BYTES,
29
+ ACCOUNT_IMPORT_PROVIDER,
30
+ type AccountImportCode,
31
+ type AccountImportRecordResult,
32
+ type AccountImportResult,
33
+ type AccountImportStatus,
34
+ } from "../oauth/account-import";
35
+
36
+ const MAIN_ID = "__main__";
37
+ const AUTO_NOTE = "auto (no pin — lowest-usage account is selected per request)";
38
+ const EXTENDED_USAGE = `Usage:
39
+ ocx account refresh <provider> [--json]
40
+ ocx account auto-switch <provider> <on|off|status|threshold <0-100>> [--json]
41
+ ocx account alias <provider> <id|main> <display-name|-> [--json]
42
+ ocx account priority <provider> <id|main> [<-100..100|first|earlier|normal|later|last|reset>] [--json]
43
+ ocx account remove <provider> <id|main> --yes [--json]
44
+ ocx account clear-cooldown <provider> <id|main> [--json]
45
+ ocx account add-key <provider> [--label <label>] [--json]
46
+ ocx account import <provider> --format <format> (--file <path>|--stdin) [--json]`;
47
+ const PIPE_GUIDANCE = `Pipe the API key on stdin, for example:
48
+ ocx account add-key <provider> <<< "$MY_KEY"
49
+ security find-generic-password -w <item> | ocx account add-key <provider>`;
50
+ const ACCOUNT_IMPORT_TIMEOUT_MS = ACCOUNT_IMPORT_DEADLINE_MS;
51
+
52
+ function flag(args: string[], value: string): boolean {
53
+ const index = args.indexOf(value);
54
+ if (index < 0) return false;
55
+ args.splice(index, 1);
56
+ return true;
57
+ }
58
+
59
+ function flagValue(args: string[], value: string): { found: boolean; value?: string } {
60
+ const index = args.indexOf(value);
61
+ if (index < 0) return { found: false };
62
+ if (index + 1 >= args.length) return { found: true };
63
+ const result = args[index + 1];
64
+ args.splice(index, 2);
65
+ return { found: true, value: result };
66
+ }
67
+
68
+ function boundedUtf8(bytes: Uint8Array): string {
69
+ try {
70
+ return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
71
+ } catch {
72
+ throw new Error("invalid_document");
73
+ }
74
+ }
75
+
76
+ function readBoundedImportFile(path: string): string {
77
+ let descriptor: number | undefined;
78
+ try {
79
+ descriptor = openSync(path, "r");
80
+ const buffer = Buffer.allocUnsafe(ACCOUNT_IMPORT_MAX_BYTES + 1);
81
+ let offset = 0;
82
+ while (offset < buffer.length) {
83
+ const read = readSync(descriptor, buffer, offset, buffer.length - offset, null);
84
+ if (read === 0) break;
85
+ offset += read;
86
+ }
87
+ if (offset > ACCOUNT_IMPORT_MAX_BYTES) throw new Error("invalid_document");
88
+ return boundedUtf8(buffer.subarray(0, offset));
89
+ } catch (error) {
90
+ if (error instanceof Error && error.message === "invalid_document") throw error;
91
+ throw new Error("source_read_failed");
92
+ } finally {
93
+ if (descriptor !== undefined) closeSync(descriptor);
94
+ }
95
+ }
96
+
97
+ async function readBoundedImportStdin(deps: AccountDeps): Promise<string> {
98
+ const input: AccountStdin = deps.stdinImpl ?? process.stdin;
99
+ if (input.isTTY) throw new Error("stdin_required");
100
+ const timeoutMs = deps.stdinTimeoutMs ?? 15_000;
101
+ return await new Promise<string>((resolve, reject) => {
102
+ const chunks: Buffer[] = [];
103
+ let bytes = 0;
104
+ let settled = false;
105
+ const cleanup = () => {
106
+ clearTimeout(timer);
107
+ input.removeListener("data", onData);
108
+ input.removeListener("end", onEnd);
109
+ input.removeListener("error", onError);
110
+ };
111
+ const finish = (fn: () => void) => {
112
+ if (settled) return;
113
+ settled = true;
114
+ cleanup();
115
+ fn();
116
+ };
117
+ const onData = (chunk: unknown) => {
118
+ const encoded = Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk));
119
+ bytes += encoded.byteLength;
120
+ if (bytes > ACCOUNT_IMPORT_MAX_BYTES) {
121
+ finish(() => reject(new Error("invalid_document")));
122
+ return;
123
+ }
124
+ chunks.push(encoded);
125
+ };
126
+ const onEnd = () => finish(() => {
127
+ try { resolve(boundedUtf8(Buffer.concat(chunks, bytes))); }
128
+ catch (error) { reject(error); }
129
+ });
130
+ const onError = () => finish(() => reject(new Error("source_read_failed")));
131
+ const timer = setTimeout(() => finish(() => reject(new Error("stdin_timeout"))), timeoutMs);
132
+ input.on("data", onData);
133
+ input.on("end", onEnd);
134
+ input.on("error", onError);
135
+ });
136
+ }
137
+
138
+ const IMPORT_STATUSES = new Set<AccountImportStatus>(["imported", "updated", "failed", "unsupported"]);
139
+ const IMPORT_CODES = new Set<AccountImportCode>([
140
+ "imported", "updated", "import_cancelled", "unsupported_provider", "unsupported_format", "invalid_document",
141
+ "invalid_record", "credential_rejected", "identity_mismatch", "missing_project", "persist_failed",
142
+ ]);
143
+ const IMPORT_RESULT_FIELDS = new Set([
144
+ "totalCount", "importedCount", "updatedCount", "failedCount", "unsupportedCount", "results",
145
+ ]);
146
+ const IMPORT_RECORD_FIELDS = new Set(["index", "status", "code"]);
147
+ const IMPORT_STATUS_CODES: Record<AccountImportStatus, ReadonlySet<AccountImportCode>> = {
148
+ imported: new Set(["imported"]),
149
+ updated: new Set(["updated"]),
150
+ failed: new Set(["invalid_record", "credential_rejected", "identity_mismatch", "missing_project", "persist_failed"]),
151
+ unsupported: new Set(["unsupported_provider", "unsupported_format"]),
152
+ };
153
+
154
+ function isPlainObject(value: unknown): value is Record<string, unknown> {
155
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
156
+ const prototype = Object.getPrototypeOf(value);
157
+ return prototype === Object.prototype || prototype === null;
158
+ }
159
+
160
+ function hasExactFields(value: Record<string, unknown>, allowed: ReadonlySet<string>): boolean {
161
+ const fields = Object.keys(value);
162
+ return fields.length === allowed.size && fields.every(field => allowed.has(field));
163
+ }
164
+
165
+ function isNonNegativeSafeInteger(value: unknown): value is number {
166
+ return typeof value === "number" && Number.isFinite(value) && Number.isSafeInteger(value) && value >= 0;
167
+ }
168
+
169
+ function safeImportResult(json: unknown): AccountImportResult | null {
170
+ if (!isPlainObject(json) || !hasExactFields(json, IMPORT_RESULT_FIELDS)) return null;
171
+ if (
172
+ !isNonNegativeSafeInteger(json.totalCount)
173
+ || !isNonNegativeSafeInteger(json.importedCount)
174
+ || !isNonNegativeSafeInteger(json.updatedCount)
175
+ || !isNonNegativeSafeInteger(json.failedCount)
176
+ || !isNonNegativeSafeInteger(json.unsupportedCount)
177
+ ) return null;
178
+ if (!Array.isArray(json.results)) return null;
179
+ if (json.results.length !== json.totalCount) return null;
180
+
181
+ const results: AccountImportRecordResult[] = [];
182
+ const indices = new Set<number>();
183
+ const aggregate: Record<AccountImportStatus, number> = {
184
+ imported: 0,
185
+ updated: 0,
186
+ failed: 0,
187
+ unsupported: 0,
188
+ };
189
+ for (const raw of json.results) {
190
+ if (!isPlainObject(raw) || !hasExactFields(raw, IMPORT_RECORD_FIELDS)) return null;
191
+ const item = raw;
192
+ if (!isNonNegativeSafeInteger(item.index) || item.index >= json.totalCount || indices.has(item.index)) return null;
193
+ if (!IMPORT_STATUSES.has(item.status as AccountImportStatus)) return null;
194
+ if (!IMPORT_CODES.has(item.code as AccountImportCode)) return null;
195
+ const status = item.status as AccountImportStatus;
196
+ const code = item.code as AccountImportCode;
197
+ if (!IMPORT_STATUS_CODES[status].has(code)) return null;
198
+ indices.add(item.index);
199
+ aggregate[status] += 1;
200
+ results.push({
201
+ index: item.index,
202
+ status,
203
+ code,
204
+ });
205
+ }
206
+ if (
207
+ indices.size !== json.totalCount
208
+ || aggregate.imported !== json.importedCount
209
+ || aggregate.updated !== json.updatedCount
210
+ || aggregate.failed !== json.failedCount
211
+ || aggregate.unsupported !== json.unsupportedCount
212
+ ) return null;
213
+
214
+ return {
215
+ totalCount: json.totalCount,
216
+ importedCount: json.importedCount,
217
+ updatedCount: json.updatedCount,
218
+ failedCount: json.failedCount,
219
+ unsupportedCount: json.unsupportedCount,
220
+ results,
221
+ };
222
+ }
223
+
224
+ function usage(message?: string): number {
225
+ if (message) console.error(message);
226
+ console.error(EXTENDED_USAGE);
227
+ return 1;
228
+ }
229
+
230
+ function configAndType(deps: AccountDeps, name: string) {
231
+ return classifyAccount(deps.loadConfigImpl?.() ?? loadConfig(), name);
232
+ }
233
+
234
+ function familyFailure(result: FamilyRows, fallback: string): number | null {
235
+ if (result.networkDown) return proxyUnreachable();
236
+ if (result.errorJson) return apiError(result.errorJson, fallback);
237
+ return null;
238
+ }
239
+
240
+ function errorText(json: Record<string, unknown> | undefined, fallback: string): string {
241
+ return typeof json?.error === "string" ? json.error : fallback;
242
+ }
243
+
244
+ function resetIso(value: number | undefined): string | null {
245
+ if (typeof value !== "number" || !Number.isFinite(value)) return null;
246
+ const date = new Date(value < 10_000_000_000 ? value * 1000 : value);
247
+ return Number.isNaN(date.getTime()) ? null : date.toISOString();
248
+ }
249
+
250
+ function refreshLine(row: FamilyRows["rows"][number]): string {
251
+ const parts = [row.id === MAIN_ID ? "main" : row.id, row.email, row.plan];
252
+ const quota = row.quota;
253
+ if (!quota || (quota.weeklyPercent === undefined && quota.monthlyPercent === undefined)) {
254
+ parts.push("quota: unknown");
255
+ } else {
256
+ if (quota.weeklyPercent !== undefined) parts.push(`weekly ${quota.weeklyPercent}%`);
257
+ const weeklyReset = resetIso(quota.weeklyResetAt);
258
+ if (weeklyReset) parts.push(`resets ${weeklyReset}`);
259
+ if (quota.monthlyPercent !== undefined) parts.push(`monthly ${quota.monthlyPercent}%`);
260
+ const monthlyReset = resetIso(quota.monthlyResetAt);
261
+ if (monthlyReset) parts.push(`resets ${monthlyReset}`);
262
+ }
263
+ if (row.needsReauth) parts.push("needs-reauth");
264
+ return parts.filter(Boolean).join(" ");
265
+ }
266
+
267
+ function quotaParts(quota: ProviderQuotaDto): string[] {
268
+ const parts: string[] = [];
269
+ const add = (label: string, percent: number | undefined, resetAt?: number) => {
270
+ if (percent === undefined) return;
271
+ parts.push(`${label} ${percent}%`);
272
+ const reset = resetIso(resetAt);
273
+ if (reset) parts.push(`resets ${reset}`);
274
+ };
275
+ add("5h", quota.fiveHourPercent, quota.fiveHourResetAt);
276
+ add("weekly", quota.weeklyPercent, quota.weeklyResetAt);
277
+ add("monthly", quota.monthlyPercent, quota.monthlyResetAt);
278
+ for (const window of quota.customWindows ?? []) add(window.label, window.percent, window.resetAt);
279
+ return parts;
280
+ }
281
+
282
+ function providerQuotaLine(name: string, report: ProviderQuotaReportDto): string {
283
+ return [name, ...quotaParts(report.quota)].join(" ");
284
+ }
285
+
286
+ export async function readStdinLine(deps: AccountDeps): Promise<string> {
287
+ const input: AccountStdin = deps.stdinImpl ?? process.stdin;
288
+ const timeoutMs = deps.stdinTimeoutMs ?? 15_000;
289
+ return await new Promise<string>((resolve, reject) => {
290
+ let buffer = "";
291
+ let settled = false;
292
+ const cleanup = () => {
293
+ clearTimeout(timer);
294
+ input.removeListener("data", onData);
295
+ input.removeListener("end", onEnd);
296
+ input.removeListener("error", onError);
297
+ };
298
+ const finish = (fn: () => void) => {
299
+ if (settled) return;
300
+ settled = true;
301
+ cleanup();
302
+ fn();
303
+ };
304
+ const onData = (chunk: unknown) => {
305
+ buffer += Buffer.isBuffer(chunk) ? chunk.toString("utf8") : String(chunk);
306
+ const newline = buffer.search(/[\r\n]/);
307
+ if (newline >= 0) finish(() => resolve(buffer.slice(0, newline).trim()));
308
+ };
309
+ const onEnd = () => finish(() => resolve(buffer.trim()));
310
+ const onError = (error: Error) => finish(() => reject(error));
311
+ const timer = setTimeout(() => finish(() => reject(new Error("timed out waiting for API key on stdin"))), timeoutMs);
312
+ input.on("data", onData);
313
+ input.on("end", onEnd);
314
+ input.on("error", onError);
315
+ });
316
+ }
317
+
318
+ export async function cmdRefresh(args: string[], deps: AccountDeps): Promise<number> {
319
+ const wantsJson = flag(args, "--json");
320
+ const name = args.shift();
321
+ if (!name || args.length) return usage();
322
+ const classified = configAndType(deps, name);
323
+ if ("error" in classified) return usage(`Error: ${classified.error}`);
324
+ const baseUrl = await resolveBaseUrl(deps);
325
+ if (!baseUrl) return proxyUnreachable();
326
+ if (classified.type !== "codex") {
327
+ const result = await fetchProviderQuotaReport(deps, baseUrl, name);
328
+ if (result.status === 0) return proxyUnreachable();
329
+ if (result.status !== 200) return apiError(result.errorJson ?? {}, `failed to refresh ${name}`);
330
+ if (wantsJson) console.log(JSON.stringify({ provider: name, report: result.report }, null, 2));
331
+ else console.log(result.report ? providerQuotaLine(name, result.report) : `no quota report available for ${name}`);
332
+ return 0;
333
+ }
334
+ const result = await fetchCodexRows(deps, baseUrl, true);
335
+ const failed = familyFailure(result, `failed to refresh ${name}`);
336
+ if (failed !== null) return failed;
337
+ if (wantsJson) console.log(JSON.stringify({ accounts: result.rows }, null, 2));
338
+ else for (const row of result.rows) console.log(refreshLine(row));
339
+ return 0;
340
+ }
341
+
342
+ export async function cmdAutoSwitch(args: string[], deps: AccountDeps): Promise<number> {
343
+ const wantsJson = flag(args, "--json");
344
+ const name = args.shift();
345
+ const action = args.shift();
346
+ if (!name || !action) return usage();
347
+ const classified = configAndType(deps, name);
348
+ if ("error" in classified || classified.type !== "codex") {
349
+ return usage("Error: auto-switch only applies to the openai Codex account pool");
350
+ }
351
+ let threshold: number | undefined;
352
+ if (action === "on" && args.length === 0) threshold = 80;
353
+ else if (action === "off" && args.length === 0) threshold = 0;
354
+ else if (action === "threshold" && args.length === 1 && /^\d+$/.test(args[0]!)) threshold = Number(args[0]);
355
+ else if (action !== "status" || args.length !== 0) return usage();
356
+ if (threshold !== undefined && (!Number.isInteger(threshold) || threshold < 0 || threshold > 100)) {
357
+ return usage("Error: threshold must be an integer 0-100");
358
+ }
359
+ const baseUrl = await resolveBaseUrl(deps);
360
+ if (!baseUrl) return proxyUnreachable();
361
+ if (action === "status") {
362
+ const response = await apiJson(deps, baseUrl, "GET", "/api/codex-auth/active");
363
+ if (response.status === 0) return proxyUnreachable();
364
+ if (response.status !== 200 || typeof response.json.autoSwitchThreshold !== "number") {
365
+ return apiError(response.json, "failed to read auto-switch status");
366
+ }
367
+ threshold = response.json.autoSwitchThreshold;
368
+ } else {
369
+ const response = await apiJson(deps, baseUrl, "PUT", "/api/codex-auth/auto-switch", { threshold });
370
+ if (response.status === 0) return proxyUnreachable();
371
+ if (response.status !== 200) return apiError(response.json, "failed to update auto-switch");
372
+ }
373
+ const enabled = threshold! > 0;
374
+ if (wantsJson) console.log(JSON.stringify({ provider: name, autoSwitchThreshold: threshold, enabled }, null, 2));
375
+ else console.log(enabled ? `auto-switch: on (threshold ${threshold}%)` : "auto-switch: off");
376
+ return 0;
377
+ }
378
+
379
+ function deletePath(type: "codex" | "oauth" | "api-key", name: string, id: string): string {
380
+ if (type === "codex") return `/api/codex-auth/accounts?id=${encodeURIComponent(id)}`;
381
+ if (type === "oauth") return `/api/oauth/accounts?provider=${encodeURIComponent(name)}&id=${encodeURIComponent(id)}`;
382
+ return `/api/providers/keys?name=${encodeURIComponent(name)}&id=${encodeURIComponent(id)}`;
383
+ }
384
+
385
+ export async function cmdRemove(args: string[], deps: AccountDeps): Promise<number> {
386
+ const wantsJson = flag(args, "--json");
387
+ const fail = (message: string): number => {
388
+ if (wantsJson) console.error(JSON.stringify({ error: message }));
389
+ else console.error(`Error: ${message}`);
390
+ return 1;
391
+ };
392
+ const confirmed = flag(args, "--yes");
393
+ const name = args.shift();
394
+ const requestedId = args.shift();
395
+ if (!name || !requestedId || args.length) return wantsJson ? fail("provider and account id are required") : usage();
396
+ if (!confirmed) {
397
+ const message = `Confirmation required. Re-run: ocx account remove ${name} ${requestedId} --yes`;
398
+ return wantsJson ? fail(message) : usage(message);
399
+ }
400
+ const classified = configAndType(deps, name);
401
+ if ("error" in classified) return wantsJson ? fail(classified.error) : usage(`Error: ${classified.error}`);
402
+ const id = classified.type === "codex" && requestedId === "main" ? MAIN_ID : requestedId;
403
+ if (classified.type === "codex" && id === MAIN_ID) return wantsJson
404
+ ? fail("the main Codex App login cannot be removed")
405
+ : usage("Error: the main Codex App login cannot be removed");
406
+ const baseUrl = await resolveBaseUrl(deps);
407
+ if (!baseUrl) return fail("Proxy not reachable. Start it with 'ocx start' or 'ocx ensure'.");
408
+ const before = await fetchRows(deps, baseUrl, name, classified.type);
409
+ if (before.networkDown) return fail("Proxy not reachable. Start it with 'ocx start' or 'ocx ensure'.");
410
+ if (before.errorJson) return fail(errorText(before.errorJson, `failed to verify ${name} before removal`));
411
+ if (!before.rows.some(row => row.id === id)) return wantsJson
412
+ ? fail(`account or key "${requestedId}" was not found`)
413
+ : usage(`Error: account or key "${requestedId}" was not found`);
414
+ const response = await apiJson(deps, baseUrl, "DELETE", deletePath(classified.type, name, id));
415
+ if (response.status === 0) return fail("Proxy not reachable. Start it with 'ocx start' or 'ocx ensure'.");
416
+ if (response.status !== 200) return fail(errorText(response.json, `failed to remove ${requestedId}`));
417
+ const catalogRefreshPending = classified.type === "codex"
418
+ && codexCatalogRefreshPending(response.json);
419
+ const after = await fetchRows(deps, baseUrl, name, classified.type);
420
+ if (after.networkDown || after.errorJson) {
421
+ const detail = after.networkDown ? "proxy not reachable" : typeof after.errorJson?.error === "string" ? after.errorJson.error : "unknown error";
422
+ return fail(`post-delete verification failed; delete may have succeeded: ${detail}`);
423
+ }
424
+ const removedActive = before.activeId === id;
425
+ const result = {
426
+ ok: true,
427
+ provider: name,
428
+ id,
429
+ removedActive,
430
+ promotedActiveId: after.activeId,
431
+ ...(classified.type === "codex" ? { catalogRefreshPending } : {}),
432
+ };
433
+ if (wantsJson) console.log(JSON.stringify(result, null, 2));
434
+ else if (classified.type === "codex" && removedActive && after.activeId === null) console.log(`openai: ${AUTO_NOTE}`);
435
+ else if (classified.type === "oauth") console.log(after.rows.length ? `${name}: active account is now ${after.activeId}` : `${name}: no accounts remaining`);
436
+ else if (classified.type === "api-key") console.log(after.rows.length ? `${name}: active key is now ${after.activeId}` : `${name}: no keys remaining`);
437
+ else console.log(`${name}: removed account ${requestedId}`);
438
+ if (!wantsJson && catalogRefreshPending) warnIfCodexCatalogRefreshPending(response.json);
439
+ return 0;
440
+ }
441
+
442
+ export async function cmdAddKey(args: string[], deps: AccountDeps): Promise<number> {
443
+ const wantsJson = flag(args, "--json");
444
+ const labelArg = flagValue(args, "--label");
445
+ const name = args.shift();
446
+ if (!name || args.length || (labelArg.found && labelArg.value === undefined)) return usage();
447
+ const classified = configAndType(deps, name);
448
+ if ("error" in classified || classified.type !== "api-key") return usage("Error: add-key only applies to API-key providers");
449
+ const input: AccountStdin = deps.stdinImpl ?? process.stdin;
450
+ if (input.isTTY) return usage(PIPE_GUIDANCE);
451
+ let key: string;
452
+ try {
453
+ key = await readStdinLine(deps);
454
+ } catch (error) {
455
+ return usage(`Error: ${error instanceof Error ? error.message : String(error)}\n${PIPE_GUIDANCE}`);
456
+ }
457
+ if (!key) return usage(`Error: API key input was empty\n${PIPE_GUIDANCE}`);
458
+ const label = labelArg.value?.trim();
459
+ const baseUrl = await resolveBaseUrl(deps);
460
+ if (!baseUrl) return proxyUnreachable();
461
+ const response = await apiJson(deps, baseUrl, "POST", "/api/providers/keys", { name, key, ...(label ? { label } : {}) });
462
+ if (response.status === 0) return proxyUnreachable();
463
+ if (response.status !== 201) return apiError(response.json, `failed to add a key for ${name}`);
464
+ const id = typeof response.json.id === "string" ? response.json.id : null;
465
+ // Redact the key inside the label BEFORE serialization — a key containing
466
+ // JSON-escaped characters (" or \) would otherwise survive the whole-output
467
+ // pass in escaped form (audit finding, Carver WP3-C).
468
+ const safeLabel = label ? label.replaceAll(key, "[redacted]") : undefined;
469
+ const result = { ok: true, id, ...(safeLabel ? { label: safeLabel } : {}) };
470
+ const output = wantsJson ? JSON.stringify(result, null, 2)
471
+ : `${name}: added API key ${id ?? ""}${safeLabel ? ` (${safeLabel})` : ""}`.trim();
472
+ console.log(output.replaceAll(key, "[redacted]"));
473
+ return 0;
474
+ }
475
+
476
+ export async function cmdImport(args: string[], deps: AccountDeps): Promise<number> {
477
+ const wantsJson = flag(args, "--json");
478
+ const formatArg = flagValue(args, "--format");
479
+ const fileArg = flagValue(args, "--file");
480
+ const fromStdin = flag(args, "--stdin");
481
+ const provider = args.shift();
482
+
483
+ // Admission happens before source I/O. In particular, an inline JSON positional argument is
484
+ // rejected without inspecting or echoing it, keeping secrets out of any subsequent surface.
485
+ if (
486
+ provider !== ACCOUNT_IMPORT_PROVIDER
487
+ || formatArg.value !== ACCOUNT_IMPORT_FORMAT
488
+ || formatArg.found !== true
489
+ ) {
490
+ const code = provider === ACCOUNT_IMPORT_PROVIDER ? "unsupported_format" : "unsupported_provider";
491
+ console.error(`Error: ${code}`);
492
+ return 1;
493
+ }
494
+ const hasFile = fileArg.found && typeof fileArg.value === "string" && fileArg.value.length > 0;
495
+ if (args.length > 0 || hasFile === fromStdin || (fileArg.found && !hasFile)) {
496
+ return usage("Error: choose exactly one bounded source: --file <path> or --stdin");
497
+ }
498
+
499
+ let source: string;
500
+ try {
501
+ source = hasFile ? readBoundedImportFile(fileArg.value!) : await readBoundedImportStdin(deps);
502
+ } catch (error) {
503
+ const code = error instanceof Error ? error.message : "source_read_failed";
504
+ console.error(`Error: ${["invalid_document", "source_read_failed", "stdin_required", "stdin_timeout"].includes(code) ? code : "source_read_failed"}`);
505
+ return 1;
506
+ }
507
+
508
+ let document: unknown;
509
+ try {
510
+ document = JSON.parse(source) as unknown;
511
+ } catch {
512
+ console.error("Error: invalid_document");
513
+ return 1;
514
+ }
515
+
516
+ const baseUrl = await resolveBaseUrl(deps);
517
+ if (!baseUrl) return proxyUnreachable();
518
+ const configuredImportTimeout = deps.importTimeoutMs;
519
+ const importTimeoutMs = typeof configuredImportTimeout === "number" && Number.isFinite(configuredImportTimeout)
520
+ ? Math.min(ACCOUNT_IMPORT_TIMEOUT_MS, Math.max(1, Math.floor(configuredImportTimeout)))
521
+ : ACCOUNT_IMPORT_TIMEOUT_MS;
522
+ const controller = new AbortController();
523
+ let timedOut = false;
524
+ const timer = setTimeout(() => {
525
+ timedOut = true;
526
+ controller.abort();
527
+ }, importTimeoutMs);
528
+ let response;
529
+ try {
530
+ response = await apiJson(deps, baseUrl, "POST", "/api/oauth/accounts/import", {
531
+ provider,
532
+ format: formatArg.value,
533
+ document,
534
+ }, { signal: controller.signal });
535
+ } finally {
536
+ clearTimeout(timer);
537
+ }
538
+ if (response.status === 0) {
539
+ if (!timedOut) return proxyUnreachable();
540
+ console.error(`Error: import_timeout after ${importTimeoutMs}ms`);
541
+ return 1;
542
+ }
543
+ if (response.status !== 200) {
544
+ if (IMPORT_CODES.has(response.json.code as AccountImportCode)) {
545
+ console.error(`Error: ${response.json.code as AccountImportCode}`);
546
+ } else {
547
+ console.error(`Error: import_request_failed (status ${response.status})`);
548
+ }
549
+ return 1;
550
+ }
551
+ const result = safeImportResult(response.json);
552
+ if (!result) {
553
+ console.error("Error: invalid_response");
554
+ return 1;
555
+ }
556
+
557
+ if (wantsJson) {
558
+ console.log(JSON.stringify(result, null, 2));
559
+ } else {
560
+ console.log(
561
+ `${provider}: ${result.importedCount} imported, ${result.updatedCount} updated, ${result.failedCount} failed, ${result.unsupportedCount} unsupported`,
562
+ );
563
+ for (const item of result.results) console.log(` #${item.index + 1} ${item.status} (${item.code})`);
564
+ }
565
+ return result.failedCount > 0 || result.unsupportedCount > 0 ? 1 : 0;
566
+ }
567
+
568
+ /**
569
+ * Lift a quota cooldown on a Codex account.
570
+ *
571
+ * This is the user-facing escape from the lockout described in
572
+ * `devlog/_plan/260726_cooldown_lockout_hardening`: injected routing makes the proxy the
573
+ * only model path for Codex Desktop, so a stuck cooldown reads as "the whole app is dead".
574
+ *
575
+ * Codex accounts only. API-key pools already reset their own 429 cooldowns through key
576
+ * management (`clearKeyCooldowns`), and OAuth providers have no equivalent state here.
577
+ */
578
+ export async function cmdClearCooldown(args: string[], deps: AccountDeps): Promise<number> {
579
+ const wantsJson = flag(args, "--json");
580
+ const name = args.shift();
581
+ const requestedId = args.shift();
582
+ if (!name || !requestedId || args.length) return usage();
583
+ const classified = configAndType(deps, name);
584
+ if ("error" in classified) return usage(`Error: ${classified.error}`);
585
+ if (classified.type !== "codex") {
586
+ return usage(`Error: ${name} is not a Codex account pool; cooldown clearing applies to Codex accounts only`);
587
+ }
588
+ const id = requestedId === "main" ? MAIN_ID : requestedId;
589
+ const baseUrl = await resolveBaseUrl(deps);
590
+ if (!baseUrl) return proxyUnreachable();
591
+ const response = await apiJson(deps, baseUrl, "POST", "/api/codex-auth/accounts/clear-cooldown", { id });
592
+ if (response.status === 0) return proxyUnreachable();
593
+ if (response.status !== 200) return apiError(response.json, `failed to clear cooldown for ${requestedId}`);
594
+ const cleared = response.json?.cleared === true;
595
+ if (wantsJson) console.log(JSON.stringify({ ok: true, provider: name, id, cleared }, null, 2));
596
+ else if (cleared) console.log(`${name}: cooldown lifted for ${requestedId}`);
597
+ else console.log(`${name}: no active cooldown for ${requestedId}`);
598
+ return 0;
599
+ }
600
+
601
+ /**
602
+ * Named selection orders. The words convey sequence rather than rank because the
603
+ * pool moves down the list only when everything above it is drained — "high
604
+ * priority" would suggest the account gets more traffic, which is not what
605
+ * ordering does.
606
+ */
607
+ const PRIORITY_PRESETS: Record<string, number> = {
608
+ first: 2,
609
+ earlier: 1,
610
+ normal: 0,
611
+ later: -1,
612
+ last: -2,
613
+ };
614
+
615
+ function priorityPresetName(priority: number): string | null {
616
+ return Object.entries(PRIORITY_PRESETS).find(([, value]) => value === priority)?.[0] ?? null;
617
+ }
618
+
619
+ function formatPriority(priority: number): string {
620
+ const preset = priorityPresetName(priority);
621
+ const signed = priority > 0 ? `+${priority}` : String(priority);
622
+ return preset ? `${signed} (${preset})` : signed;
623
+ }
624
+
625
+ /** `null` = reset to the default; `undefined` = unparseable. */
626
+ function parsePriorityArgument(raw: string): number | null | undefined {
627
+ const word = raw.trim().toLowerCase();
628
+ if (word === "reset") return null;
629
+ // Own keys only: `in` also matches "constructor", "__proto__", and friends.
630
+ if (Object.hasOwn(PRIORITY_PRESETS, word)) return PRIORITY_PRESETS[word];
631
+ // The regex only rules out shapes Number() would coerce ("1e2", " 1 ", ""); the range
632
+ // itself comes from the core parser so the CLI cannot drift from what the API accepts.
633
+ if (!/^[+-]?\d+$/.test(word)) return undefined;
634
+ return parseAccountPriority(Number(word)) ?? undefined;
635
+ }
636
+
637
+ export async function cmdPriority(args: string[], deps: AccountDeps): Promise<number> {
638
+ const wantsJson = flag(args, "--json");
639
+ const name = args.shift();
640
+ const requestedId = args.shift();
641
+ const requestedPriority = args.shift();
642
+ if (!name || !requestedId || args.length) return usage();
643
+ const classified = configAndType(deps, name);
644
+ if ("error" in classified) return usage(`Error: ${classified.error}`);
645
+ if (classified.type !== "codex") {
646
+ return usage("Error: selection order only applies to the openai Codex account pool");
647
+ }
648
+ const id = requestedId === "main" ? MAIN_ID : requestedId;
649
+
650
+ // Validate before touching the network so a typo never reaches the proxy.
651
+ let priority: number | null | undefined;
652
+ if (requestedPriority !== undefined) {
653
+ priority = parsePriorityArgument(requestedPriority);
654
+ if (priority === undefined) {
655
+ return usage(`Error: selection order must be an integer ${MIN_ACCOUNT_PRIORITY}..${MAX_ACCOUNT_PRIORITY}, one of ${Object.keys(PRIORITY_PRESETS).join("/")}, or reset`);
656
+ }
657
+ }
658
+
659
+ const baseUrl = await resolveBaseUrl(deps);
660
+ if (!baseUrl) return proxyUnreachable();
661
+
662
+ // No value means "show" — a read must not rewrite what it is reporting.
663
+ if (priority === undefined) {
664
+ const result = await fetchCodexRows(deps, baseUrl);
665
+ const failed = familyFailure(result, `failed to read ${name} accounts`);
666
+ if (failed !== null) return failed;
667
+ const row = result.rows.find(candidate => candidate.id === id);
668
+ if (!row) return usage(`Error: no ${name} account ${requestedId}`);
669
+ const current = normalizeAccountPriority(row.priority);
670
+ if (wantsJson) {
671
+ console.log(JSON.stringify(
672
+ { ok: true, provider: name, id, priority: current, preset: priorityPresetName(current) },
673
+ null,
674
+ 2,
675
+ ));
676
+ } else {
677
+ console.log(`${name}: ${requestedId} selection order is ${formatPriority(current)}`);
678
+ }
679
+ return 0;
680
+ }
681
+
682
+ const response = await apiJson(deps, baseUrl, "PUT", "/api/codex-auth/accounts/priority", { id, priority });
683
+ if (response.status === 0) return proxyUnreachable();
684
+ if (response.status !== 200) return apiError(response.json, `failed to set selection order for ${requestedId}`);
685
+ const applied = typeof response.json.priority === "number" ? response.json.priority : (priority ?? 0);
686
+ if (wantsJson) {
687
+ console.log(JSON.stringify(
688
+ { ok: true, provider: name, id, priority: applied, preset: priorityPresetName(applied) },
689
+ null,
690
+ 2,
691
+ ));
692
+ } else {
693
+ console.log(`${name}: ${requestedId} selection order is now ${formatPriority(applied)}`);
694
+ }
695
+ // Not cmdUse's note: re-ordering takes effect on the next unbound request rather than
696
+ // only on new sessions, because preemption moves those requests up immediately.
697
+ console.error("Takes effect from the next unbound request; running threads keep their current account until drained.");
698
+ // The release is not optional and not conditional on the value changing, so it has to be
699
+ // stated: this route is the only way to clear a pin without immediately setting another,
700
+ // which means a write storing the order an account already had still releases it. Without
701
+ // this line that is a silent side effect of a command that looks purely declarative.
702
+ console.error('Also releases any manual "use this account now" pin, on any account.');
703
+ return 0;
704
+ }
705
+
706
+ export async function cmdAlias(args: string[], deps: AccountDeps): Promise<number> {
707
+ const wantsJson = flag(args, "--json");
708
+ const name = args.shift();
709
+ const requestedId = args.shift();
710
+ const requestedAlias = args.shift();
711
+ if (!name || !requestedId || requestedAlias === undefined || args.length) return usage();
712
+ const classified = configAndType(deps, name);
713
+ if ("error" in classified) return usage(`Error: ${classified.error}`);
714
+ const id = classified.type === "codex" && requestedId === "main" ? MAIN_ID : requestedId;
715
+ if (id === MAIN_ID) return usage("Error: the main Codex App login cannot be renamed");
716
+ const alias = requestedAlias === "-" ? "" : requestedAlias.trim();
717
+ if (alias.length > 80 || /[\x00-\x1f\x7f]/.test(alias)) return usage("Error: alias must be at most 80 printable characters");
718
+ const baseUrl = await resolveBaseUrl(deps);
719
+ if (!baseUrl) return proxyUnreachable();
720
+ const path = classified.type === "codex"
721
+ ? "/api/codex-auth/accounts/alias"
722
+ : classified.type === "oauth"
723
+ ? "/api/oauth/accounts/alias"
724
+ : "/api/providers/keys/alias";
725
+ const body = classified.type === "codex"
726
+ ? { id, alias }
727
+ : classified.type === "oauth"
728
+ ? { provider: name, accountId: id, alias }
729
+ : { name, id, alias };
730
+ const response = await apiJson(deps, baseUrl, "PUT", path, body);
731
+ if (response.status === 0) return proxyUnreachable();
732
+ if (response.status !== 200) return apiError(response.json, `failed to rename ${requestedId}`);
733
+ const result = { ok: true, provider: name, id, alias: alias || null };
734
+ if (wantsJson) console.log(JSON.stringify(result, null, 2));
735
+ else console.log(alias ? `${name}: ${requestedId} is now “${alias}”` : `${name}: cleared alias for ${requestedId}`);
736
+ return 0;
737
+ }