@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
@@ -130,6 +130,50 @@ function registryAllowsPrivateNetwork(name: string): boolean {
130
130
  return getProviderRegistryEntry(name)?.allowPrivateNetworkByDefault === true;
131
131
  }
132
132
 
133
+ /**
134
+ * OAuth registry entries that opt into `allowBaseUrlOverride` send bearer credentials to a
135
+ * user-configured endpoint (review findings, PR #2109 / PR #2110): a cleartext `http:`
136
+ * override would expose the OAuth token on the wire. `https:` is therefore required for
137
+ * every non-local destination. Loopback/localhost/private relays keep working over
138
+ * `http:` because they already sit behind the explicit `allowPrivateNetwork` opt-in
139
+ * enforced by {@link providerDestinationConfigError}. Keyed/local providers (Ollama,
140
+ * vLLM, LM Studio, LiteLLM, Moonshot, Qwen, Alibaba) are untouched: they are not
141
+ * `authKind: "oauth"`, so this check never fires for them.
142
+ */
143
+ function registrySendsOAuthToOverriddenBaseUrl(name: string): boolean {
144
+ const entry = getProviderRegistryEntry(name);
145
+ return entry?.authKind === "oauth" && entry.allowBaseUrlOverride === true;
146
+ }
147
+
148
+ export function providerSecureTransportConfigError(
149
+ name: string,
150
+ provider: Pick<OcxProviderConfig, "baseUrl" | "allowPrivateNetwork">,
151
+ ): string | null {
152
+ if (!registrySendsOAuthToOverriddenBaseUrl(name)) return null;
153
+ let parsed: URL;
154
+ try {
155
+ parsed = new URL(provider.baseUrl.trim());
156
+ } catch {
157
+ return null; // invalid URLs are providerBaseUrlConfigError's concern
158
+ }
159
+ if (parsed.protocol !== "http:") return null;
160
+ const assessment = assessDestination(provider.baseUrl);
161
+ // Classify FIRST, then consult the opt-in. `allowPrivateNetwork` says "this destination is
162
+ // intentionally local", which is a statement about the address, not a waiver of transport
163
+ // security — reading it before classification let `http://attacker.example` with the opt-in
164
+ // set carry an OAuth bearer in cleartext to a public host.
165
+ if (!assessment) return null;
166
+ const local = assessment.kind === "localhost"
167
+ || assessment.kind === "loopback"
168
+ || assessment.kind === "private";
169
+ if (local && providerAllowsPrivateNetwork(name, provider)) {
170
+ // A genuinely local relay over http stays reachable through the explicit opt-in; the
171
+ // private-network gate still governs whether it may be reached at all.
172
+ return null;
173
+ }
174
+ return "baseUrl must use https: this provider sends OAuth credentials to its endpoint, and http is allowed only for loopback/private relays";
175
+ }
176
+
133
177
  /**
134
178
  * Whether a provider may reach loopback/private addresses.
135
179
  *
@@ -150,6 +194,8 @@ export function providerAllowsPrivateNetwork(
150
194
  }
151
195
 
152
196
  export function providerDestinationConfigError(name: string, provider: Pick<OcxProviderConfig, "baseUrl" | "allowPrivateNetwork">): string | null {
197
+ const secureTransportError = providerSecureTransportConfigError(name, provider);
198
+ if (secureTransportError) return secureTransportError;
153
199
  const assessment = assessDestination(provider.baseUrl);
154
200
  if (!assessment) return null;
155
201
  if (assessment.kind === "public" || assessment.kind === "hostname") return null;
@@ -241,10 +287,18 @@ export function assessUrlDestination(url: string): UrlDestinationAssessment | nu
241
287
  * Returns the validated addresses so direct callers can pin the connect peer and
242
288
  * avoid a second, rebindable resolution. DNS failures remain fail-closed here;
243
289
  * the provider proxy wrapper alone may recognize that typed failure and degrade.
290
+ *
291
+ * `allowBenchmarkAddresses` is an explicit outbound-only opt-in for Clash/Surge/
292
+ * Mihomo fake-IP DNS (IANA benchmark space 198.18.0.0/15, credit #1748): a hostname
293
+ * answer in that range is accepted without marking the destination private, so the
294
+ * caller can keep the hostname on its configured HTTP(S) proxy path. It applies to
295
+ * resolved answers only — a literal 198.18.x URL still rejects — and mixed answers
296
+ * that include any other non-public address still fail. Callers that do not pass it
297
+ * (image and Lab fetch) keep rejecting benchmark space.
244
298
  */
245
299
  export async function resolvePublicAddresses(
246
300
  url: string,
247
- options?: string | { context?: string; allowPrivateNetwork?: boolean },
301
+ options?: string | { context?: string; allowPrivateNetwork?: boolean; allowBenchmarkAddresses?: boolean },
248
302
  ): Promise<{
249
303
  hostname: string;
250
304
  addresses: { address: string; family: number }[];
@@ -254,6 +308,7 @@ export async function resolvePublicAddresses(
254
308
  ? `${options.trim() || "image"} URL`
255
309
  : options?.context?.trim() || "image URL";
256
310
  const privateNetworkAllowed = typeof options === "object" && options?.allowPrivateNetwork === true;
311
+ const benchmarkAllowed = typeof options === "object" && options?.allowBenchmarkAddresses === true;
257
312
  let hostname: string;
258
313
  try {
259
314
  hostname = normalizeHostname(new URL(url.trim()).hostname);
@@ -294,6 +349,14 @@ export async function resolvePublicAddresses(
294
349
  const ipKind = isIP(address) || (family === 4 || family === 6 ? family : 0);
295
350
  const assessment = ipKind === 4 ? classifyIpv4(address) : ipKind === 6 ? classifyIpv6(normalizeHostname(address)) : null;
296
351
  if (!assessment || assessment.kind !== "public") {
352
+ // Hostname → 198.18.0.0/15 under the explicit opt-in is Clash/Surge/Mihomo
353
+ // fake-IP DNS, not a LAN provider. Accept it without allowPrivateNetwork and
354
+ // do not mark the destination private, so the caller's HTTP(S)_PROXY path
355
+ // still applies (credit #1748).
356
+ if (benchmarkAllowed && assessment?.kind === "private" && assessment.detail === "benchmark address") {
357
+ validatedAddresses.push({ address, family: ipKind === 4 || ipKind === 6 ? ipKind : (family || 4) });
358
+ continue;
359
+ }
297
360
  const allowedPrivateAddress = privateNetworkAllowed
298
361
  && assessment
299
362
  && (assessment.kind === "loopback" || assessment.kind === "private");
@@ -314,3 +377,4 @@ export async function resolvePublicAddresses(
314
377
  export async function assertUrlResolvesPublic(url: string): Promise<void> {
315
378
  await resolvePublicAddresses(url);
316
379
  }
380
+
package/src/lib/errors.ts CHANGED
@@ -43,6 +43,25 @@ function isSubscriptionGateMessage(text: string): boolean {
43
43
  );
44
44
  }
45
45
 
46
+ function isLocalAclHardeningMessage(text: string): boolean {
47
+ const secretPathHardening = text.includes("secret path") && (
48
+ text.includes("acl") ||
49
+ text.includes("harden") ||
50
+ text.includes("permission") ||
51
+ text.includes("access denied") ||
52
+ text.includes("inheritance")
53
+ );
54
+ return (
55
+ text.includes("icacls") ||
56
+ text.includes("acl hardening") ||
57
+ text.includes("ntfs") ||
58
+ secretPathHardening ||
59
+ text.includes("inheritance:r") ||
60
+ /\bwindows\b.*\bacl\b/.test(text) ||
61
+ text.includes("/grant:r")
62
+ );
63
+ }
64
+
46
65
  function isAuthenticationMessage(text: string): boolean {
47
66
  const accessDeniedWithCredentialCue = (
48
67
  text.includes("access denied") ||
@@ -124,6 +143,15 @@ export function classifyError(status: number, type: string, message: string): Oc
124
143
  if (type === CYBER_POLICY_ERROR_CODE || isCyberPolicyMessage(text)) {
125
144
  return { message, type: "invalid_request_error", code: CYBER_POLICY_ERROR_CODE };
126
145
  }
146
+ // A LOCAL preflight refusal keeps its own code (#1524). The message necessarily says
147
+ // "context window" -- that is what it is refusing on -- so the generic remap below would
148
+ // rewrite it to `context_length_exceeded` and make it indistinguishable from an UPSTREAM
149
+ // verdict. The two need opposite fallback handling: ours means "this candidate does not
150
+ // fit", theirs means "the request is impossible", so collapsing them ended the chain at
151
+ // the first candidate that was merely too small.
152
+ if (type === "input_admission_refused") {
153
+ return { message, type: "invalid_request_error", code: "input_admission_refused" };
154
+ }
127
155
  if (
128
156
  text.includes("context_length_exceeded") ||
129
157
  text.includes("context window") ||
@@ -134,11 +162,16 @@ export function classifyError(status: number, type: string, message: string): Oc
134
162
  return { message, type: "invalid_request_error", code: "context_length_exceeded" };
135
163
  }
136
164
  // "Cursor resource limit exceeded" is emitted only for explicit request-size overflow
137
- // details (isCursorRequestTooLargeDetail in cursor-errors.ts); quota-style resource
138
- // exhaustion arrives as "Cursor rate limit exceeded" and falls through to 429 below.
165
+ // details (isCursorRequestTooLargeDetail in cursor-errors.ts); "Cursor context limit
166
+ // exceeded" is the bare payload-overflow shape (isCursorZeroTokenResourceExhausted);
167
+ // quota-style resource exhaustion arrives as "Cursor rate limit exceeded" and falls
168
+ // through to 429 below.
139
169
  if (text.includes("cursor resource limit exceeded")) {
140
170
  return { message, type: "invalid_request_error", code: "tool_catalog_too_large" };
141
171
  }
172
+ if (text.includes("cursor context limit exceeded")) {
173
+ return { message, type: "invalid_request_error", code: "context_length_exceeded" };
174
+ }
142
175
  // The Cursor adapter's classified rate-limit prefix is authoritative: its DETAIL may echo
143
176
  // quota wording ("... quota exhausted") that would otherwise hit the insufficient_quota
144
177
  // branch below and break the planned retry-with-backoff contract (WP3 review blocker 1).
@@ -170,6 +203,11 @@ export function classifyError(status: number, type: string, message: string): Oc
170
203
  if (type === "origin_rejected") {
171
204
  return { message, type: "invalid_request_error", code: "origin_rejected" };
172
205
  }
206
+ // Local ACL setup failures can contain provider-like auth wording (for example
207
+ // "access denied" or "authentication") but represent unavailable infrastructure.
208
+ if (status === 503 && isLocalAclHardeningMessage(text)) {
209
+ return { message, type: "server_error", code: "upstream_server_error" };
210
+ }
173
211
  // HTTP 401 and explicit auth failures are authoritative even when provider text
174
212
  // also advertises an upgrade or subscription.
175
213
  if (
@@ -273,6 +311,7 @@ export function inferHttpStatusFromAdapterMessage(message: string): number {
273
311
  // See classifyError: this prefix now only means explicit request-size overflow (400);
274
312
  // quota-style Cursor resource exhaustion carries the rate-limit prefix and maps to 429.
275
313
  if (lower.includes("cursor resource limit exceeded")) return 400;
314
+ if (lower.includes("cursor context limit exceeded")) return 400;
276
315
  if (
277
316
  lower.includes("resource_exhausted") ||
278
317
  lower.includes("resource exhausted") ||
@@ -280,6 +319,9 @@ export function inferHttpStatusFromAdapterMessage(message: string): number {
280
319
  lower.includes("too many requests") ||
281
320
  lower.includes("throttling")
282
321
  ) return 429;
322
+ // Local Windows filesystem hardening is infrastructure, not provider authentication.
323
+ // Keep this ahead of auth/permission and timeout keyword inference.
324
+ if (isLocalAclHardeningMessage(lower)) return 503;
283
325
  // Strong authentication signals win when a message contains mixed auth and
284
326
  // subscription/permission wording.
285
327
  if (isAuthenticationMessage(lower)) return 401;
@@ -0,0 +1,7 @@
1
+ import type { TrustedFabricPatchExecutor } from "../lab/fabric/types";
2
+ import { isHostIssuedFabricPatchExecutor } from "./fabric-task-host";
3
+
4
+ /** Trusted exact-route fabric patch executor recognition facade. */
5
+ export function isTrustedFabricPatchExecutor(value: unknown): value is TrustedFabricPatchExecutor {
6
+ return isHostIssuedFabricPatchExecutor(value);
7
+ }
@@ -0,0 +1,29 @@
1
+ import type { FabricPatchExecutor, FabricPatchExecutorInput, TrustedFabricPatchExecutor } from "../lab/fabric/types";
2
+
3
+ const HOST_ISSUED_EXECUTORS = new WeakSet<object>();
4
+
5
+ /**
6
+ * Trusted host integration boundary for CL-07 exact-route fabric patch production.
7
+ *
8
+ * @internal host integration only
9
+ */
10
+ export function createHostIssuedFabricPatchExecutor(
11
+ executorModulePath: string,
12
+ execute: FabricPatchExecutor,
13
+ ): TrustedFabricPatchExecutor {
14
+ const capability: TrustedFabricPatchExecutor = Object.freeze({
15
+ executorModulePath,
16
+ execute: (input: FabricPatchExecutorInput) => Promise.resolve(execute(input)),
17
+ });
18
+ HOST_ISSUED_EXECUTORS.add(capability);
19
+ return capability;
20
+ }
21
+
22
+ /** Internal recognition check consumed by the read-only authority facade. */
23
+ export function isHostIssuedFabricPatchExecutor(value: unknown): value is TrustedFabricPatchExecutor {
24
+ if (typeof value !== "object" || value === null || !HOST_ISSUED_EXECUTORS.has(value as object)) return false;
25
+ const capability = value as TrustedFabricPatchExecutor;
26
+ return typeof capability.executorModulePath === "string"
27
+ && capability.executorModulePath.length > 0
28
+ && typeof capability.execute === "function";
29
+ }
@@ -0,0 +1,223 @@
1
+ /**
2
+ * Compatibility Lab activation.
3
+ *
4
+ * The proxy core does not import Lab. This module is the seam that does, and the startup
5
+ * composition root calls it only when the install actually uses Lab, so a user with no
6
+ * routing profile and no automation executes no Lab code and starts no Lab timer.
7
+ *
8
+ * Activation is SYNCHRONOUS by design. Three audit rounds established that a deferred
9
+ * activation window is unpatchable: `routeModelInternal` is sync, and so is the
10
+ * subagent-fallback chain that calls `routeModel`, so those callers have nowhere to await.
11
+ * During such a window a policy alias would be silently dropped from a fallback chain and
12
+ * the subagent would run on a different model than the operator configured. Registration
13
+ * therefore completes before `startServer` returns, inside the same synchronous turn as
14
+ * `Bun.serve`, so no request can observe an unregistered slot.
15
+ *
16
+ * See devlog/_fin/260814_lab_core_decoupling/080_activation_is_synchronous.md
17
+ *
18
+ * Startup degrades, explicit operator action reports. This asymmetry is deliberate: an
19
+ * invalid automation config disables automation with a warning here, but the management
20
+ * API and CLI paths that start a scheduler leave `LabAutomationError` to surface (the
21
+ * management route maps it to a 400). Someone who just toggled automation should see the
22
+ * validation error; someone merely starting the proxy should not lose unrelated traffic.
23
+ *
24
+ * @internal host integration only
25
+ */
26
+ import { existsSync, readFileSync } from "node:fs";
27
+ import { dirname, join } from "node:path";
28
+ import { labAutomationPolicyPath } from "../lab/paths";
29
+ import type { OcxConfig } from "../types";
30
+ import { LabAutomationError } from "../lab/automation/types";
31
+ import { registerLabPassiveRouteLinker } from "./lab-passive-linker-registration";
32
+ import { registerCurrentServerResourceCleanup } from "./server-resource-ownership";
33
+ import { setCompatibilityEvidenceProvider } from "../routing/compatibility/provider-slot";
34
+ import { labCompatibilityEvidenceProvider } from "../routing/compatibility/lab-evidence-provider";
35
+ import {
36
+ setLabAutomationDispatchDeps,
37
+ startLabAutomationScheduler,
38
+ } from "../lab/automation/orchestrator";
39
+ import { createProductionLabRouteExecutor } from "./lab-live-route-production";
40
+
41
+ interface LabRuntimeBinding {
42
+ release(): void;
43
+ }
44
+
45
+ interface LabActivationRecord {
46
+ staticDetach: Array<() => void>;
47
+ runtime: LabRuntimeBinding | null;
48
+ seenRuntimeConfigs: WeakSet<OcxConfig>;
49
+ }
50
+
51
+ /** Activation records keyed by configDir, so one process can own several configs. */
52
+ const activated = new Map<string, LabActivationRecord>();
53
+
54
+ const activationKey = (configDir?: string): string => configDir ?? "";
55
+
56
+ function readJsonIfPresent(path: string): unknown {
57
+ try {
58
+ if (!existsSync(path)) return null;
59
+ return JSON.parse(readFileSync(path, "utf8")) as unknown;
60
+ } catch {
61
+ // A malformed or unreadable file means "not enabled": this detector must never throw
62
+ // during startup, and must never import Lab persistence to answer the question.
63
+ return null;
64
+ }
65
+ }
66
+
67
+ /**
68
+ * True when Lab automation is enabled on disk.
69
+ *
70
+ * Mirrors `loadLabAutomationConfig` precedence deliberately: the current authority is the
71
+ * combined `automation-config.json`, with `automation-policy.json` as the legacy fallback.
72
+ * Reading only the legacy file would miss every install that enabled automation through
73
+ * the current dashboard.
74
+ */
75
+ export function labAutomationEnabledOnDisk(configDir?: string): boolean {
76
+ const legacyPath = labAutomationPolicyPath(configDir);
77
+ const combined = readJsonIfPresent(join(dirname(legacyPath), "automation-config.json"));
78
+ if (combined && typeof combined === "object") {
79
+ const policy = (combined as { policy?: unknown }).policy;
80
+ if (policy && typeof policy === "object") {
81
+ return (policy as { enabled?: unknown }).enabled === true;
82
+ }
83
+ }
84
+ const legacy = readJsonIfPresent(legacyPath);
85
+ if (legacy && typeof legacy === "object") {
86
+ return (legacy as { enabled?: unknown }).enabled === true;
87
+ }
88
+ return false;
89
+ }
90
+
91
+ /** True when this install actually uses Lab: any routing profile, or automation enabled. */
92
+ export function labActivationRequired(config: OcxConfig, configDir?: string): boolean {
93
+ if (Object.keys(config.routingProfiles ?? {}).length > 0) return true;
94
+ return labAutomationEnabledOnDisk(configDir);
95
+ }
96
+
97
+ function startAutomationIfEnabled(configDir?: string): void {
98
+ if (!labAutomationEnabledOnDisk(configDir)) return;
99
+ try {
100
+ startLabAutomationScheduler(configDir);
101
+ } catch (err) {
102
+ // Neither a malformed automation file nor a busy state lock may take the proxy down
103
+ // at startup. Lab automation stays off for this run; routing, evidence, and every
104
+ // other subsystem keep working.
105
+ //
106
+ // The two causes get different messages because they need different actions, and a
107
+ // lock-contention failure reported as "invalid config" sends the operator to fix a
108
+ // file that is fine. Contention can also stall startup by up to the 5s lock wait.
109
+ const code = err instanceof LabAutomationError ? err.code : null;
110
+ if (code === "state_lock_busy" || code === "state_lock_failed") {
111
+ console.warn(
112
+ "[lab] Lab automation did not start: another process holds the automation state lock."
113
+ + " Automation stays off for this run and will be retried on the next start.",
114
+ );
115
+ } else {
116
+ console.warn(
117
+ "[lab] Lab automation is disabled for this run because its configuration could not be"
118
+ + " loaded:",
119
+ err instanceof Error ? err.message : err,
120
+ );
121
+ }
122
+ }
123
+ }
124
+
125
+ function installLabAutomationRuntime(
126
+ record: LabActivationRecord,
127
+ config: OcxConfig,
128
+ configDir?: string,
129
+ ): void {
130
+ const previous = record.runtime;
131
+ const routeExecutor = createProductionLabRouteExecutor({ configDir, loadConfig: () => config });
132
+ const releaseDispatchDeps = setLabAutomationDispatchDeps({
133
+ configDir,
134
+ loadConfig: () => config,
135
+ routeExecutor,
136
+ });
137
+
138
+ let released = false;
139
+ let detachOwnerCleanup = () => {};
140
+ const binding: LabRuntimeBinding = {
141
+ release() {
142
+ if (released) return;
143
+ released = true;
144
+ detachOwnerCleanup();
145
+ releaseDispatchDeps();
146
+ if (record.runtime === binding) record.runtime = null;
147
+ },
148
+ };
149
+ // `setLabAutomationDispatchDeps` already registers its own owner cleanup. This second
150
+ // receipt only keeps the activation record in sync with that owner-scoped lifetime, so a
151
+ // later same-process server can see that the static Lab slots survived but CL-08 authority
152
+ // did not. The release is idempotent, so cleanup order does not matter.
153
+ detachOwnerCleanup = registerCurrentServerResourceCleanup(binding.release);
154
+
155
+ // Install the successor before releasing the predecessor. The dispatcher token check then
156
+ // makes the predecessor release a no-op for the successor scheduler/authority.
157
+ record.runtime = binding;
158
+ record.seenRuntimeConfigs.add(config);
159
+ previous?.release();
160
+ }
161
+
162
+ /**
163
+ * Register Lab into the core slots. Static activation is idempotent per configDir. The
164
+ * server-owned CL-08 runtime binding is refreshed when its prior owner ended or when a new
165
+ * server instance arrives with a config object that has not owned this activation before.
166
+ */
167
+ export function activateLab(config: OcxConfig, configDir?: string): void {
168
+ const key = activationKey(configDir);
169
+ const existing = activated.get(key);
170
+ if (existing) {
171
+ // A released predecessor leaves the static Lab slots resident but removes dispatch
172
+ // authority and its scheduler. A live successor uses a fresh config object. Rebind in
173
+ // either case, but never let an older already-seen server steal authority back from a
174
+ // newer successor merely because it receives another management request.
175
+ if (existing.runtime === null || !existing.seenRuntimeConfigs.has(config)) {
176
+ installLabAutomationRuntime(existing, config, configDir);
177
+ startAutomationIfEnabled(configDir);
178
+ }
179
+ return;
180
+ }
181
+
182
+ // INVARIANT: static activation is all-or-nothing and reason-independent. Every static
183
+ // slot is registered here regardless of WHY activation was required, so automation-only
184
+ // activation still installs the compatibility provider a later profile needs.
185
+ const record: LabActivationRecord = {
186
+ staticDetach: [],
187
+ runtime: null,
188
+ seenRuntimeConfigs: new WeakSet<OcxConfig>(),
189
+ };
190
+ record.staticDetach.push(registerLabPassiveRouteLinker(configDir));
191
+ record.staticDetach.push(setCompatibilityEvidenceProvider(labCompatibilityEvidenceProvider));
192
+ installLabAutomationRuntime(record, config, configDir);
193
+
194
+ // Record the activation BEFORE the scheduler start. startLabAutomationScheduler runs the
195
+ // full automation normalizer, which throws on any field violation, and this call sits on
196
+ // the startup path of every install that has a routing profile. Storing the record first
197
+ // means a throw cannot orphan the detach receipts and leave slots registered with no
198
+ // activation record, which would let a later activateLab register them a second time.
199
+ activated.set(key, record);
200
+ startAutomationIfEnabled(configDir);
201
+ }
202
+
203
+ /** True when this configDir has been activated. */
204
+ export function isLabActivated(configDir?: string): boolean {
205
+ return activated.has(activationKey(configDir));
206
+ }
207
+
208
+ /**
209
+ * Test-only teardown. Deactivation is deliberately NOT a production path: tearing an
210
+ * activation down mid-run would finalize in-flight automation as ineligible rather than
211
+ * cancelled, and the orchestrator's shutdown signal is process-global. An install that
212
+ * creates then deletes a profile keeps Lab resident until restart, which does not affect
213
+ * users who never opted in.
214
+ */
215
+ export function resetLabActivationForTests(): void {
216
+ for (const [key, record] of [...activated]) {
217
+ activated.delete(key);
218
+ try { record.runtime?.release(); } catch { /* teardown is best-effort */ }
219
+ for (const release of [...record.staticDetach].reverse()) {
220
+ try { release(); } catch { /* teardown is best-effort */ }
221
+ }
222
+ }
223
+ }
@@ -0,0 +1,13 @@
1
+ import type { TrustedLabRouteExecutor } from "../lab/live/types";
2
+ import { isHostIssuedLabRouteExecutor } from "./lab-live-host";
3
+
4
+ /**
5
+ * Read-only trust check used by the Lab executor.
6
+ *
7
+ * Capability issuance intentionally does not live in this authority module: callers cannot
8
+ * self-attest sandbox boundary names here. Only the dedicated trusted host integration may
9
+ * construct and register an evidence-eligible route executor.
10
+ */
11
+ export function isTrustedLabRouteExecutor(value: unknown): value is TrustedLabRouteExecutor {
12
+ return isHostIssuedLabRouteExecutor(value);
13
+ }
@@ -0,0 +1,30 @@
1
+ import type { LabRouteExecutor, TrustedLabRouteExecutor } from "../lab/live/types";
2
+ import { REQUIRED_LAB_SANDBOX_BOUNDARIES } from "../lab/live/types";
3
+
4
+ const HOST_ISSUED_EXECUTORS = new WeakSet<object>();
5
+
6
+ /**
7
+ * Trusted host integration boundary for CL-03 exact-route execution.
8
+ *
9
+ * This module is intentionally not re-exported from the Lab public surface. The host owns
10
+ * enforcement of every mandatory sandbox boundary and therefore supplies no caller-controlled
11
+ * boundary list. Adapters/providers receive only the resulting opaque capability.
12
+ *
13
+ * @internal host integration only
14
+ */
15
+ export function createHostIssuedLabRouteExecutor(execute: LabRouteExecutor): TrustedLabRouteExecutor {
16
+ const capability: TrustedLabRouteExecutor = Object.freeze({
17
+ execute,
18
+ enforcedBoundaries: Object.freeze([...REQUIRED_LAB_SANDBOX_BOUNDARIES]),
19
+ });
20
+ HOST_ISSUED_EXECUTORS.add(capability);
21
+ return capability;
22
+ }
23
+
24
+ /** Internal recognition check consumed by the read-only authority facade. */
25
+ export function isHostIssuedLabRouteExecutor(value: unknown): value is TrustedLabRouteExecutor {
26
+ if (typeof value !== "object" || value === null || !HOST_ISSUED_EXECUTORS.has(value as object)) return false;
27
+ const capability = value as TrustedLabRouteExecutor;
28
+ return capability.enforcedBoundaries.length === REQUIRED_LAB_SANDBOX_BOUNDARIES.length
29
+ && REQUIRED_LAB_SANDBOX_BOUNDARIES.every((boundary, index) => capability.enforcedBoundaries[index] === boundary);
30
+ }
@@ -0,0 +1,56 @@
1
+ import { PinnedHttpError, pinnedHttpGet, pinnedHttpPost } from "./pinned-http";
2
+ import { TransportError } from "../lab/live/transport";
3
+ import type { LabCredentialLeaseV1, LabPinnedSender } from "../lab/live/types";
4
+
5
+ /** Only response metadata required by current live assertions crosses into Lab. */
6
+ const LAB_RESPONSE_HEADER_ALLOWLIST = ["content-type"] as const;
7
+
8
+ /**
9
+ * Trusted credential/transport owner. Secret headers exist only in this non-Lab module and are
10
+ * consumed directly by the pinned HTTP primitive; they are never returned to Lab code.
11
+ */
12
+ export function createLabAuthorizedPinnedSender(
13
+ authorize: (lease: LabCredentialLeaseV1) => Promise<HeadersInit> | HeadersInit,
14
+ ): LabPinnedSender {
15
+ return async (lease, destination, pinned, request, signal, limits) => {
16
+ const headers = await authorize(lease);
17
+ const url = `${destination.scheme}://${destination.host}:${destination.port}${destination.basePath}${request.path}`;
18
+ const options = {
19
+ headers,
20
+ maxBytes: limits.maxOutputBytes,
21
+ connectTimeoutMs: limits.connectTimeoutMs,
22
+ firstByteTimeoutMs: limits.firstByteTimeoutMs,
23
+ inactivityTimeoutMs: limits.inactivityTimeoutMs,
24
+ rejectUnauthorized: true,
25
+ context: "Lab provider response",
26
+ };
27
+ let response: Response;
28
+ let body: string;
29
+ try {
30
+ response = request.method === "POST"
31
+ ? await pinnedHttpPost(url, pinned, request.body ?? "", signal, options)
32
+ : await pinnedHttpGet(url, pinned, signal, options);
33
+ body = await response.text();
34
+ } catch (error) {
35
+ if (error instanceof PinnedHttpError) {
36
+ switch (error.code) {
37
+ case "connect_timeout":
38
+ throw new TransportError("connect_timeout", "pinned provider connection timed out");
39
+ case "first_byte_timeout":
40
+ throw new TransportError("first_byte_timeout", "pinned provider first byte timed out");
41
+ case "inactivity_timeout":
42
+ throw new TransportError("inactivity_timeout", "pinned provider response stalled");
43
+ case "output_byte_limit":
44
+ throw new TransportError("output_byte_limit", "pinned provider response exceeded byte budget");
45
+ }
46
+ }
47
+ throw error;
48
+ }
49
+ const responseHeaders: Record<string, string> = {};
50
+ for (const headerName of LAB_RESPONSE_HEADER_ALLOWLIST) {
51
+ const value = response.headers.get(headerName);
52
+ if (value !== null) responseHeaders[headerName] = value;
53
+ }
54
+ return { status: response.status, headers: responseHeaders, body };
55
+ };
56
+ }