@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
package/src/cli/claude.ts CHANGED
@@ -12,11 +12,15 @@ import { injectClaudeAgentDefs } from "../claude/agents-inject";
12
12
  import { effectiveModelEnv, resolveAutoContext } from "../claude/context-windows";
13
13
  import { refreshGatewayModelCacheFromProxy } from "../claude/gateway-cache";
14
14
  import { commandInvocation } from "../lib/win-exec";
15
+ import { isProxyAdmissionSecret } from "../server/auth-cors";
15
16
  import { findLiveProxy } from "../server/proxy-liveness";
16
17
  import type { OcxConfig } from "../types";
17
18
  import { configuredAdminToken } from "../lib/admin-secrets";
18
19
  import { PROXY_MARKER, ownAdmissionTokens, defaultAuthDetectDeps, detectClaudeAuth, type AuthDetectDeps } from "../claude/auth-detect";
19
20
  import { resolveClaudeAuthMode } from "../claude/auth-mode";
21
+ import { withProcessRuntimeProvenance } from "../lib/bun-runtime";
22
+ import { selfLaunchArgv } from "../lib/self-launch-argv";
23
+ import { ANTHROPIC_PARENT_ENV_SLOTS, trustedNodeLauncherContext, type AnthropicParentEnvSlot } from "./launcher-context";
20
24
 
21
25
  export interface ClaudeLaunchEnv {
22
26
  [key: string]: string | undefined;
@@ -26,13 +30,41 @@ export interface ClaudeLaunchEnv {
26
30
  * Injectable IO for tests. `env` is deliberately NOT injectable: it is bound to the
27
31
  * launch base so detection and the spawned process can never disagree (audit R3-3).
28
32
  */
29
- export type ClaudeEnvDeps = { authDetect?: Omit<Partial<AuthDetectDeps>, "env" | "ownTokens"> };
33
+ export type ClaudeEnvDeps = {
34
+ authDetect?: Omit<Partial<AuthDetectDeps>, "env" | "ownTokens">;
35
+ /** Test seam; production uses the authenticated Node-launcher context. */
36
+ preBunAnthropicSlots?: readonly AnthropicParentEnvSlot[] | null;
37
+ };
38
+
39
+ function isClaudeLoopbackHostname(hostname: string): boolean {
40
+ const normalized = hostname.toLowerCase().replace(/\.$/, "");
41
+ return normalized === "localhost"
42
+ || normalized === "127.0.0.1"
43
+ || normalized === "::1"
44
+ || normalized === "[::1]";
45
+ }
46
+
47
+ function targetsLocalClaudeProxy(value: string | undefined, port: number): boolean {
48
+ if (!value) return false;
49
+ try {
50
+ const parsed = new URL(value);
51
+ const effectivePort = parsed.port === "" ? 80 : Number(parsed.port);
52
+ return parsed.protocol === "http:"
53
+ && isClaudeLoopbackHostname(parsed.hostname)
54
+ && effectivePort === port
55
+ && parsed.username === ""
56
+ && parsed.password === "";
57
+ } catch {
58
+ return false;
59
+ }
60
+ }
30
61
 
31
62
  /**
32
63
  * Pure env assembly (unit-tested): never sets ANTHROPIC_API_KEY (setting both
33
64
  * token vars triggers Claude Code's auth-conflict warning, 003 E1), and never
34
- * overrides variables the user already exported, apart from stale loopback
35
- * ANTHROPIC_BASE_URL values owned by a previous opencodex launch.
65
+ * preserves Anthropic variables proven to exist in the parent Node launcher,
66
+ * apart from stale loopback ANTHROPIC_BASE_URL values owned by a previous
67
+ * opencodex launch. Unproven ambient values fail closed as project dotenv.
36
68
  */
37
69
  export function buildClaudeEnv(
38
70
  config: OcxConfig,
@@ -47,28 +79,37 @@ export function buildClaudeEnv(
47
79
  // stale marker left in place would suppress the admission key and then be removed,
48
80
  // leaving the child with no token at all (audit R2-1). It is opencodex state, never
49
81
  // user auth, so dropping it unconditionally is safe.
50
- if (env.ANTHROPIC_AUTH_TOKEN === PROXY_MARKER) delete env.ANTHROPIC_AUTH_TOKEN;
51
- // Step 1b — drop Anthropic credentials that the bundled Bun runtime synthesized from a
52
- // project `.env`/`.env.local` (issue #701). Claude Code disables claude.ai connectors the
53
- // moment either token slot is populated, so an ambient project file silently moved a
54
- // subscriber onto API billing while their OAuth login stayed healthy. The npm launcher
55
- // runs under Node, which does NOT auto-load dotenv, so it records the slots that existed
56
- // before Bun started; anything populated now but absent then came from the working
57
- // directory, not from the user. A genuine shell export is still honored, which keeps
58
- // auto-mode API-key auth working. An ABSENT marker means provenance is unknowable
59
- // (a direct `bun src/cli/index.ts` run, a test, or an older launcher), and then we
60
- // change nothing rather than guess an EMPTY marker is different: the launcher ran
61
- // and saw no pre-existing slots.
62
- const preBunSlots = base.OCX_PRE_BUN_ANTHROPIC_ENV;
63
- if (preBunSlots !== undefined) {
64
- const exported = new Set(preBunSlots.split(",").filter(name => name.length > 0));
65
- for (const name of ["ANTHROPIC_API_KEY", "ANTHROPIC_AUTH_TOKEN"] as const) {
66
- const value = env[name];
67
- if (value !== undefined && value !== "" && !exported.has(name)) delete env[name];
68
- }
82
+ if (env.ANTHROPIC_AUTH_TOKEN?.trim() === PROXY_MARKER) delete env.ANTHROPIC_AUTH_TOKEN;
83
+ // Step 1b — drop Anthropic credentials AND destinations that Bun may have synthesized
84
+ // from a project `.env`/`.env.local`. The plain-Node launcher records genuine parent
85
+ // exports before Bun starts and pairs that context with an argv proof, so with a
86
+ // trusted context we know exactly which slots the user really exported.
87
+ //
88
+ // Without a trusted context all three slots are treated as project-controlled. An
89
+ // earlier revision of this branch preserved credentials here, reasoning that the
90
+ // destination is pinned below so a dotenv key would only ever reach the local proxy.
91
+ // That reasoning is wrong, and review caught it: `CLAUDE_CODE_PROVIDER_MANAGED_BY_HOST`
92
+ // is only set when we own an auth token (see below, and #253 for why asserting it
93
+ // otherwise logs a subscriber out), so on a subscription launch Claude Code's
94
+ // settings.env merge can still replace `ANTHROPIC_BASE_URL` after we return. A
95
+ // preserved key then travels to that host. The repository documents that residual for
96
+ // subscription mode; it must not be widened into a credential leak.
97
+ //
98
+ // Direct `bun src/cli/index.ts` therefore loses ambient Anthropic values. That is a
99
+ // real cost to a documented entry point, and the escape hatch is the launcher: run
100
+ // through `ocx` (the published bin) and genuine shell exports are preserved by proof.
101
+ const explicitSlots = deps.preBunAnthropicSlots;
102
+ const trustedSlots = explicitSlots === undefined
103
+ ? trustedNodeLauncherContext()?.anthropicEnvSlots ?? []
104
+ : explicitSlots ?? [];
105
+ const exported = new Set<AnthropicParentEnvSlot>(trustedSlots);
106
+ for (const name of ANTHROPIC_PARENT_ENV_SLOTS) {
107
+ const value = env[name];
108
+ if (value !== undefined && value !== "" && !exported.has(name)) delete env[name];
69
109
  }
70
- // Never forward the seam itself to Claude Code.
110
+ // Never forward old or current provenance seams to Claude Code.
71
111
  delete env.OCX_PRE_BUN_ANTHROPIC_ENV;
112
+ delete env.OCX_NODE_LAUNCH_CONTEXT;
72
113
  const setDefault = (name: string, value: string | undefined) => {
73
114
  if (value === undefined || value.length === 0) return;
74
115
  if (env[name] !== undefined && env[name] !== "") return; // user wins
@@ -79,10 +120,12 @@ export function buildClaudeEnv(
79
120
  if (existingBaseUrl) {
80
121
  try {
81
122
  const parsed = new URL(existingBaseUrl);
82
- const isLoopback = parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1";
83
- if (isLoopback && parsed.port !== "" && Number(parsed.port) !== port) {
123
+ const effectivePort = parsed.port === "" ? 80 : Number(parsed.port);
124
+ if (parsed.protocol === "http:"
125
+ && isClaudeLoopbackHostname(parsed.hostname)
126
+ && effectivePort !== port) {
84
127
  const replacement = `http://127.0.0.1:${port}`;
85
- console.error(`⚠ Replacing stale opencodex ANTHROPIC_BASE_URL ${existingBaseUrl} with ${replacement}.`);
128
+ console.error(`⚠ Replacing stale opencodex ANTHROPIC_BASE_URL ${parsed.origin} with ${replacement}.`);
86
129
  env.ANTHROPIC_BASE_URL = replacement;
87
130
  }
88
131
  } catch {
@@ -94,8 +137,26 @@ export function buildClaudeEnv(
94
137
  // the user's Claude login. Only inject a token when the proxy actually requires an
95
138
  // admission key; otherwise Claude Code keeps its own OAuth and sends it to us —
96
139
  // native claude models then pass through verbatim (see server/claude-messages.ts).
97
- if ((config.apiKeys?.length ?? 0) > 0) {
98
- setDefault("ANTHROPIC_AUTH_TOKEN", config.apiKeys![0].key);
140
+ const ownTokens = ownAdmissionTokens(config);
141
+ const targetsLocalProxy = targetsLocalClaudeProxy(env.ANTHROPIC_BASE_URL, port);
142
+ const inheritedApiKey = env.ANTHROPIC_API_KEY;
143
+ if (typeof inheritedApiKey === "string" && isProxyAdmissionSecret(inheritedApiKey, config)) {
144
+ delete env.ANTHROPIC_API_KEY;
145
+ }
146
+ const hasUserApiKey = Boolean(env.ANTHROPIC_API_KEY?.trim());
147
+ const inheritedAuthToken = env.ANTHROPIC_AUTH_TOKEN;
148
+ const inheritedTokenIsOurs = typeof inheritedAuthToken === "string"
149
+ && isProxyAdmissionSecret(inheritedAuthToken, config);
150
+ // system-env may have injected the proxy's admission key into the parent. A
151
+ // proof-bound external BASE_URL is still user-owned, so never let our inherited
152
+ // key follow it. A user API key also wins on a local launch; remove only the token
153
+ // values recognized by the shared proxy-admission contract and preserve every
154
+ // other token.
155
+ if (inheritedTokenIsOurs && (!targetsLocalProxy || hasUserApiKey)) {
156
+ delete env.ANTHROPIC_AUTH_TOKEN;
157
+ }
158
+ if (targetsLocalProxy && !hasUserApiKey && ownTokens.length > 0) {
159
+ setDefault("ANTHROPIC_AUTH_TOKEN", ownTokens[0]);
99
160
  }
100
161
  // Detection reads the SANITIZED launch env — the exact object spawned below — so the
101
162
  // resolver and the spawned process cannot disagree. It deliberately does NOT read the
@@ -110,11 +171,19 @@ export function buildClaudeEnv(
110
171
  ...defaultAuthDetectDeps(env as NodeJS.ProcessEnv),
111
172
  ...(deps.authDetect ?? {}),
112
173
  env: () => env as NodeJS.ProcessEnv,
113
- ownTokens: ownAdmissionTokens(config),
174
+ ownTokens,
114
175
  }));
115
- if (!env.ANTHROPIC_AUTH_TOKEN && resolved.markerMode === "proxy") {
176
+ if (!env.ANTHROPIC_AUTH_TOKEN && !hasUserApiKey && targetsLocalProxy && resolved.markerMode === "proxy") {
116
177
  env.ANTHROPIC_AUTH_TOKEN = PROXY_MARKER;
117
178
  }
179
+ const finalAuthToken = env.ANTHROPIC_AUTH_TOKEN;
180
+ const hostOwnsAuthentication = targetsLocalProxy
181
+ && !hasUserApiKey
182
+ && typeof finalAuthToken === "string"
183
+ && (
184
+ finalAuthToken.trim() === PROXY_MARKER
185
+ || isProxyAdmissionSecret(finalAuthToken, config)
186
+ );
118
187
  if (resolved.origin === "auto-unknown") {
119
188
  console.error("⚠ Claude 인증을 확인하지 못했습니다 — 구독 방식으로 진행합니다. GUI에서 인증 모드를 직접 지정하면 이 판단을 덮어쓸 수 있습니다.");
120
189
  }
@@ -136,7 +205,7 @@ export function buildClaudeEnv(
136
205
  // Claude Code 2.1.206+ also treats this as a host-auth assertion. Injecting it
137
206
  // without a host token makes a valid claude.ai subscription look logged out,
138
207
  // so the guard is only safe when opencodex actually owns authentication.
139
- if (env.ANTHROPIC_AUTH_TOKEN) {
208
+ if (hostOwnsAuthentication) {
140
209
  setDefault("CLAUDE_CODE_PROVIDER_MANAGED_BY_HOST", "1");
141
210
  }
142
211
  // Opt-in effort forcing (devlog 136 B6): opus-shaped aliases already carry
@@ -201,11 +270,11 @@ async function ensureProxyForClaude(): Promise<number | null> {
201
270
  if (live) return live.port;
202
271
  const cfgPort = loadConfig().port;
203
272
  const pinPort = typeof cfgPort === "number" && cfgPort > 0 ? cfgPort : 10100;
204
- const child = spawn(process.execPath, [process.argv[1], "start", "--port", String(pinPort)], {
273
+ const child = spawn(process.execPath, selfLaunchArgv(["start", "--port", String(pinPort)]), {
205
274
  detached: true,
206
275
  stdio: "ignore",
207
276
  windowsHide: true,
208
- env: { ...process.env, OCX_SERVICE: "1" },
277
+ env: withProcessRuntimeProvenance({ ...process.env, OCX_SERVICE: "1" }),
209
278
  });
210
279
  child.unref();
211
280
  const deadline = Date.now() + 8_000;
@@ -248,7 +317,7 @@ export async function cmdClaude(args: string[]): Promise<number> {
248
317
  // Pre-write the CLI's gateway-model cache (devlog 030): without a token the CLI
249
318
  // never refreshes it, so the picker would keep showing yesterday's aliases.
250
319
  try {
251
- const cachePath = await refreshGatewayModelCacheFromProxy(port);
320
+ const cachePath = await refreshGatewayModelCacheFromProxy(port, { admissionConfig: config });
252
321
  if (cachePath === null) {
253
322
  console.error("⚠ Gateway model cache could not be refreshed; the model picker may be stale.");
254
323
  }
@@ -0,0 +1,103 @@
1
+ import { inspectCodexLogs, type CodexLogGuardInspection } from "../codex/log-guard/inspect";
2
+ import {
3
+ getCodexLogGuardProtectionStatus,
4
+ type CodexLogGuardStatus,
5
+ } from "../codex/log-guard/protection";
6
+
7
+ function kib(bytes: number): string {
8
+ return `${(bytes / 1024).toFixed(1)} KiB`;
9
+ }
10
+
11
+ function fileMetadataLines(report: CodexLogGuardInspection): string[] {
12
+ if (report.externalSqliteHome === null) return [];
13
+ const location = report.externalSqliteHome ? "external sqlite_home" : "CODEX_HOME sqlite_home";
14
+ return [
15
+ ` ${location}; DB ${kib(report.files.databaseBytes)}, WAL ${kib(report.files.walBytes)}, SHM ${kib(report.files.shmBytes)}`,
16
+ ];
17
+ }
18
+
19
+ type DoctorReport = CodexLogGuardInspection | CodexLogGuardStatus;
20
+
21
+ function protectionLines(report: DoctorReport): string[] {
22
+ if (!("protection" in report)) return [];
23
+ const protection = report.protection;
24
+ switch (protection.state) {
25
+ case "active":
26
+ return [` ok protection active (${protection.desiredMode})`];
27
+ case "off":
28
+ return [" -- protection off"];
29
+ case "drifted":
30
+ return [
31
+ ` WARN protection drifted (desired ${protection.desiredMode}; observed ${protection.observedMode})`,
32
+ " Action: ocx storage codex-logs repair",
33
+ ];
34
+ case "unsupported":
35
+ return [" -- protection unavailable for this schema"];
36
+ case "unknown":
37
+ return [" WARN protection state unknown; inspect reserved Log Guard triggers before changing mode"];
38
+ }
39
+ }
40
+
41
+ export function formatCodexLogGuardDoctor(report: DoctorReport): string[] {
42
+ const lines = ["Codex diagnostic logs"];
43
+ lines.push(...protectionLines(report));
44
+
45
+ if (report.schema.state === "unavailable") {
46
+ lines.push(" -- inspection unavailable");
47
+ return lines;
48
+ }
49
+ if (report.schema.state === "missing") {
50
+ lines.push(" -- logs_2.sqlite is not present");
51
+ return lines;
52
+ }
53
+ if (report.schema.state === "unreadable") {
54
+ lines.push(" -- logs_2.sqlite is unreadable; inspection metadata only");
55
+ lines.push(...fileMetadataLines(report));
56
+ lines.push(" checkpointed read-only snapshot; activity rate not measured");
57
+ return lines;
58
+ }
59
+ if (report.schema.state === "unsupported") {
60
+ lines.push(" -- unknown schema; inspection only");
61
+ } else {
62
+ lines.push(" ok schema compatible");
63
+ }
64
+
65
+ lines.push(...fileMetadataLines(report));
66
+
67
+ if (report.metrics) {
68
+ lines.push(
69
+ ` ${report.metrics.totalRows} rows; TRACE ${(report.metrics.traceShare * 100).toFixed(1)}%; reclaimable ${kib(report.metrics.reclaimableBytes)}`,
70
+ );
71
+ const top = report.metrics.topTargets[0];
72
+ if (top) lines.push(` top target ${top.target} (${top.rows} rows)`);
73
+ }
74
+
75
+ lines.push(" checkpointed read-only snapshot; activity rate not measured");
76
+ return lines;
77
+ }
78
+
79
+ export interface CodexLogGuardDoctorDeps {
80
+ inspect?: () => DoctorReport;
81
+ log?: (line: string) => void;
82
+ }
83
+
84
+ /** Observe-only doctor section. Inspection failures are reported without mutating or failing doctor. */
85
+ export function printCodexLogGuardDoctor(deps: CodexLogGuardDoctorDeps = {}): void {
86
+ const inspect = deps.inspect ?? getCodexLogGuardProtectionStatus;
87
+ const log = deps.log ?? console.log;
88
+ try {
89
+ for (const line of formatCodexLogGuardDoctor(inspect())) log(line);
90
+ } catch (error) {
91
+ // Production can still fall back to PR 1's simpler inspector if the enriched
92
+ // protection lookup fails. An injected inspector is a test/caller boundary:
93
+ // never escape that boundary and touch the real Codex home behind its back.
94
+ if (!deps.inspect) {
95
+ try {
96
+ for (const line of formatCodexLogGuardDoctor(inspectCodexLogs())) log(line);
97
+ return;
98
+ } catch { /* report the original failure below */ }
99
+ }
100
+ log("Codex diagnostic logs");
101
+ log(" -- inspection unavailable");
102
+ }
103
+ }
@@ -17,6 +17,8 @@ const DEFAULT_DEPS: CodexShimAutoRestoreCliDeps = {
17
17
 
18
18
  export function skipsCodexShimAutoRestore(command: string | undefined, args: string[]): boolean {
19
19
  if (command === "uninstall" || command === "remove") return true;
20
+ // `lab` is read-only inspection; it must not trigger shim side effects.
21
+ if (command === "lab") return true;
20
22
  return command === "codex-shim" && ["install", "uninstall", "remove"].includes(args[1] ?? "");
21
23
  }
22
24
 
@@ -0,0 +1,76 @@
1
+ import {
2
+ currentExternalCodexModelProvider,
3
+ getCodexRoutingKind,
4
+ type CodexRoutingKind,
5
+ } from "../codex/inject";
6
+ import { loadConfig, resolveEnvValue } from "../config";
7
+
8
+ const PROXY_ENV_KEYS = [
9
+ "HTTP_PROXY",
10
+ "HTTPS_PROXY",
11
+ "ALL_PROXY",
12
+ "http_proxy",
13
+ "https_proxy",
14
+ "all_proxy",
15
+ ] as const;
16
+
17
+ export interface CodexShimReadinessInputs {
18
+ routingKind: CodexRoutingKind;
19
+ externalProvider: string | null;
20
+ processProxyEnvPresent: boolean;
21
+ configuredProxyResolved: boolean;
22
+ }
23
+
24
+ function externalProviderLabel(provider: string | null): string {
25
+ return provider
26
+ ? `external model_provider ${JSON.stringify(provider)}`
27
+ : "the active Codex route";
28
+ }
29
+
30
+ export function codexShimReadinessWarnings(
31
+ inputs: CodexShimReadinessInputs,
32
+ ): string[] {
33
+ const warnings: string[] = [];
34
+ const provider = externalProviderLabel(inputs.externalProvider);
35
+
36
+ if (inputs.routingKind === "unknown") {
37
+ warnings.push(
38
+ inputs.externalProvider
39
+ ? `Codex still selects ${provider}. The shim can start OpenCodex, but it does not redirect that provider; point it at the live OpenCodex /v1 endpoint with wire_api = "responses", or switch to the built-in openai provider and run 'ocx sync'.`
40
+ : "Codex routing could not be verified. The shim can start OpenCodex, but it may not redirect Codex; run 'ocx doctor' before relying on autostart.",
41
+ );
42
+ } else if (inputs.routingKind === "custom-local") {
43
+ warnings.push(
44
+ `Codex uses ${provider} through a user-owned local gateway. The shim can start OpenCodex, but OpenCodex does not own that route; run 'ocx doctor' to verify its lifecycle.`,
45
+ );
46
+ } else if (inputs.routingKind === "custom-remote") {
47
+ warnings.push(
48
+ `Codex uses ${provider} through a remote gateway. The shim only starts a local OpenCodex proxy and will not affect those requests.`,
49
+ );
50
+ }
51
+
52
+ if (inputs.processProxyEnvPresent && !inputs.configuredProxyResolved) {
53
+ warnings.push(
54
+ "Proxy environment variables are present only in this process while config.proxy is unset or unresolved. Codex launchers and background services may not inherit them; persist config.proxy before relying on autostart.",
55
+ );
56
+ }
57
+
58
+ return warnings;
59
+ }
60
+
61
+ export function collectCodexShimReadinessWarnings(): string[] {
62
+ const config = loadConfig();
63
+ let externalProvider: string | null = null;
64
+ try {
65
+ externalProvider = currentExternalCodexModelProvider();
66
+ } catch {
67
+ // Routing readiness is advisory; getCodexRoutingKind() already reports an
68
+ // unreadable config as unknown, so preserve that warning instead of failing.
69
+ }
70
+ return codexShimReadinessWarnings({
71
+ routingKind: getCodexRoutingKind(),
72
+ externalProvider,
73
+ processProxyEnvPresent: PROXY_ENV_KEYS.some(key => Boolean(process.env[key]?.trim())),
74
+ configuredProxyResolved: Boolean(resolveEnvValue(config.proxy)?.trim()),
75
+ });
76
+ }
package/src/cli/combo.ts CHANGED
@@ -16,6 +16,7 @@ const USAGE = `Usage:
16
16
  ocx combo set <id> --targets <provider/model[:weight],...>
17
17
  [--strategy <failover|round-robin>] [--sticky <1-100>]
18
18
  [--effort <low|medium|high|xhigh|max|ultra|->] [--alias <name|->]
19
+ [--native-alias] [--display-name <label|->]
19
20
  [--rename-from <id>] [--json]
20
21
  ocx combo remove <id> --yes [--json]`;
21
22
 
@@ -77,6 +78,8 @@ async function set(argv: string[], deps: RuntimeApiDeps): Promise<void> {
77
78
  if (stickyLimit > 100) throw new CliUsageError("--sticky must be <= 100", USAGE);
78
79
  const effort = takeOption(args, "--effort");
79
80
  const alias = takeOption(args, "--alias");
81
+ const nativeAlias = takeFlag(args, "--native-alias");
82
+ const displayName = takeOption(args, "--display-name");
80
83
  const renameFrom = takeOption(args, "--rename-from");
81
84
  rejectArgs(args, USAGE);
82
85
  const combo: Record<string, unknown> = {
@@ -86,6 +89,11 @@ async function set(argv: string[], deps: RuntimeApiDeps): Promise<void> {
86
89
  };
87
90
  if (effort !== undefined) combo.defaultEffort = effort === "-" ? null : effort;
88
91
  if (alias !== undefined) combo.alias = alias === "-" ? "" : alias;
92
+ if (nativeAlias) combo.nativeAlias = true;
93
+ if (displayName !== undefined) combo.displayName = displayName === "-" ? "" : displayName;
94
+ const current = await runtimeRequest<{ combos?: ComboRow[] }>("/api/combos", {}, deps);
95
+ const existing = (current.combos ?? []).find(row => row.id === (renameFrom ?? id));
96
+ if (existing?.imageInput === "disabled") combo.imageInput = "disabled";
89
97
  const result = await runtimeRequest("/api/combos", {
90
98
  method: "PUT",
91
99
  body: JSON.stringify({ id, combo, ...(renameFrom ? { renameFrom } : {}) }),
@@ -1,6 +1,9 @@
1
1
  import { readFileSync, writeFileSync } from "node:fs";
2
- import { getConfigPath, readConfigDiagnostics, saveConfig, validateConfigCandidate } from "../config";
2
+ import { clearCodexAccountPin } from "../codex/account-priority";
3
+ import { getConfigPath, mutatePersistedConfig, readConfigDiagnostics, sanitizeModelCostsForDisplay, saveConfig, validateConfigCandidate } from "../config";
4
+ import { VISION_REASONING_EFFORTS, isVisionReasoningEffort } from "../reasoning-effort";
3
5
  import type { OcxConfig } from "../types";
6
+ import { normalizeVisionReasoningForModel } from "../vision/reasoning";
4
7
  import { CliUsageError, printData, rejectArgs, runCliAction, takeFlag } from "./runtime-api";
5
8
 
6
9
  const USAGE = `Usage:
@@ -17,6 +20,9 @@ const BLOCKED_SEGMENTS = new Set(["__proto__", "prototype", "constructor"]);
17
20
 
18
21
  function redact(value: unknown, key = ""): unknown {
19
22
  if (SECRET_KEYS.test(key) && typeof value === "string") return value ? "********" : value;
23
+ // modelCosts rows are keyed by model id; a pasted API key in a key position
24
+ // must not be echoed back by config show/get (values are already redacted).
25
+ if (key === "modelCosts") return sanitizeModelCostsForDisplay(value);
20
26
  if (Array.isArray(value)) return value.map(item => redact(item));
21
27
  if (value && typeof value === "object") {
22
28
  return Object.fromEntries(Object.entries(value as Record<string, unknown>).map(([childKey, child]) => [childKey, redact(child, childKey)]));
@@ -64,10 +70,36 @@ function loadInput(path: string): unknown {
64
70
  catch { throw new CliUsageError(`invalid JSON in ${path}`); }
65
71
  }
66
72
 
73
+ function visionReasoningError(value: unknown): string | null {
74
+ if (!value || typeof value !== "object" || Array.isArray(value)) return null;
75
+ const vision = (value as Record<string, unknown>).visionSidecar;
76
+ if (!vision || typeof vision !== "object" || Array.isArray(vision)) return null;
77
+ const reasoning = (vision as Record<string, unknown>).reasoning;
78
+ if (reasoning === undefined || isVisionReasoningEffort(reasoning)) return null;
79
+ return `schema_invalid: visionSidecar.reasoning: must be one of ${VISION_REASONING_EFFORTS.join(", ")}`;
80
+ }
81
+
82
+ function validateCandidate(value: unknown): ReturnType<typeof validateConfigCandidate> {
83
+ const error = visionReasoningError(value);
84
+ return error ? { ok: false, error } : validateConfigCandidate(value);
85
+ }
86
+
87
+ function normalizeVisionConfig(config: OcxConfig): OcxConfig {
88
+ const vision = config.visionSidecar;
89
+ if (!vision || vision.reasoning === undefined) return config;
90
+ // Keep CLI import/set semantics aligned with the execution path: an omitted or blank model means
91
+ // the bounded OpenAI vision default, gpt-5.4-mini, not the Dashboard's web-search default.
92
+ const model = vision.model || "gpt-5.4-mini";
93
+ const normalized = normalizeVisionReasoningForModel(model, vision.reasoning);
94
+ if (normalized === undefined) delete vision.reasoning;
95
+ else vision.reasoning = normalized;
96
+ return config;
97
+ }
98
+
67
99
  function validate(value: unknown): OcxConfig {
68
- const result = validateConfigCandidate(value);
100
+ const result = validateCandidate(value);
69
101
  if (!result.ok) throw new CliUsageError(result.error);
70
- return result.config;
102
+ return normalizeVisionConfig(result.config);
71
103
  }
72
104
 
73
105
  export async function handleConfigCommand(argv: string[]): Promise<number> {
@@ -98,11 +130,42 @@ export async function handleConfigCommand(argv: string[]): Promise<number> {
98
130
  const raw = action === "set" ? args.shift() : undefined;
99
131
  if (!path || (action === "set" && raw === undefined)) throw new CliUsageError("config path and value are required", USAGE);
100
132
  rejectArgs(args, USAGE);
101
- const candidate = structuredClone(readConfigDiagnostics().config) as unknown as Record<string, unknown>;
102
- setPath(candidate, path, raw === undefined ? undefined : parseValue(raw), action === "unset");
103
- const config = validate(candidate);
104
- const savedValue = action === "unset" ? null : getPath(config, path);
105
- saveConfig(config);
133
+ // #1835/#1838: the read used to happen OUTSIDE the mutation lock, so a concurrent
134
+ // edit landing between it and the save was reverted by this whole-snapshot write.
135
+ // `mutatePersistedConfig` reruns this callback against the latest validated disk
136
+ // state, so the operation is applied to what is actually there at commit time.
137
+ let savedValue: unknown = null;
138
+ const outcome = mutatePersistedConfig(fresh => {
139
+ // Snapshot BEFORE mutating: comparing after the write compares a value with
140
+ // itself and would report every no-op as a change, bumping the generation.
141
+ const before = JSON.stringify(fresh);
142
+ const candidate = structuredClone(fresh) as unknown as Record<string, unknown>;
143
+ setPath(candidate, path, raw === undefined ? undefined : parseValue(raw), action === "unset");
144
+ const config = validate(candidate);
145
+ savedValue = action === "unset" ? null : getPath(config, path);
146
+ // Setting the order here is the operator restating it, exactly as through
147
+ // `ocx account priority` or the management route, so it releases the manual pin
148
+ // for the same reason those do: a pin made before any order existed would
149
+ // otherwise outrank every order set afterwards, capping the pool at the pinned
150
+ // account's tier with nothing on any surface explaining why. `import` is
151
+ // deliberately not covered — that file supplies its own pin, so there is no
152
+ // stale one to release.
153
+ if (pathSegments(path)[0] === "codexAccountPriorities") clearCodexAccountPin(config);
154
+ // REPLACE rather than merge: `Object.assign` alone cannot remove a key that
155
+ // `unset` deleted, which would make unset silently succeed while changing nothing.
156
+ for (const key of Object.keys(fresh)) {
157
+ if (!(key in (config as unknown as Record<string, unknown>))) {
158
+ delete (fresh as unknown as Record<string, unknown>)[key];
159
+ }
160
+ }
161
+ Object.assign(fresh, config);
162
+ return { changed: JSON.stringify(fresh) !== before, value: undefined };
163
+ });
164
+ if (outcome.status === "unavailable") {
165
+ throw new Error(outcome.reason === "conflict"
166
+ ? "config changed while applying this update; retry"
167
+ : `config is ${outcome.reason}`);
168
+ }
106
169
  printData({ ok: true, path, value: redact(savedValue, path.split(".").at(-1)) }, wantsJson,
107
170
  [`${action === "unset" ? "Unset" : "Set"} ${path}.`]);
108
171
  return;
@@ -110,9 +173,10 @@ export async function handleConfigCommand(argv: string[]): Promise<number> {
110
173
  if (action === "validate") {
111
174
  const path = args.shift();
112
175
  rejectArgs(args, USAGE);
113
- const result = path ? validateConfigCandidate(loadInput(path)) : (() => {
176
+ const result = path ? validateCandidate(loadInput(path)) : (() => {
114
177
  const diagnostics = readConfigDiagnostics();
115
- return diagnostics.error ? { ok: false as const, error: diagnostics.error } : { ok: true as const, config: diagnostics.config };
178
+ if (diagnostics.error) return { ok: false as const, error: diagnostics.error };
179
+ return validateCandidate(diagnostics.config);
116
180
  })();
117
181
  printData(result.ok ? { ok: true, source: path ?? getConfigPath() } : result, wantsJson,
118
182
  [result.ok ? "Config is valid." : `Config is invalid: ${result.error}`]);