@yansigit/opencodex 2.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (826) hide show
  1. package/AGENTS_INSTALL.md +109 -0
  2. package/LICENSE +21 -0
  3. package/README.md +303 -0
  4. package/assets/architecture.png +0 -0
  5. package/assets/banner.png +0 -0
  6. package/assets/claude-code-models.gif +0 -0
  7. package/assets/codex-app-picker.png +0 -0
  8. package/bin/ocx.mjs +587 -0
  9. package/bin/package-main.mjs +9 -0
  10. package/gui/dist/assets/index-BNJ7r4Gd.js +102 -0
  11. package/gui/dist/assets/index-CGoDO3uO.css +1 -0
  12. package/gui/dist/favicon.png +0 -0
  13. package/gui/dist/icons.svg +24 -0
  14. package/gui/dist/index.html +25 -0
  15. package/gui/dist/logo.png +0 -0
  16. package/gui/dist/provider-icons/alibaba-color.svg +1 -0
  17. package/gui/dist/provider-icons/antigravity-color.svg +1 -0
  18. package/gui/dist/provider-icons/claude-color.svg +1 -0
  19. package/gui/dist/provider-icons/cline-color.svg +16 -0
  20. package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -0
  21. package/gui/dist/provider-icons/commandcode-color.svg +1 -0
  22. package/gui/dist/provider-icons/copilot-color.svg +1 -0
  23. package/gui/dist/provider-icons/cursor-color.svg +2 -0
  24. package/gui/dist/provider-icons/deepseek-color.svg +1 -0
  25. package/gui/dist/provider-icons/discord.svg +1 -0
  26. package/gui/dist/provider-icons/firepass-color.svg +1 -0
  27. package/gui/dist/provider-icons/fireworks-color.svg +1 -0
  28. package/gui/dist/provider-icons/gemini-color.svg +1 -0
  29. package/gui/dist/provider-icons/github-copilot-color.svg +1 -0
  30. package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -0
  31. package/gui/dist/provider-icons/grok.svg +1 -0
  32. package/gui/dist/provider-icons/groq-color.svg +1 -0
  33. package/gui/dist/provider-icons/huggingface-color.svg +1 -0
  34. package/gui/dist/provider-icons/kimi-color.svg +1 -0
  35. package/gui/dist/provider-icons/kiro-color.svg +15 -0
  36. package/gui/dist/provider-icons/lm-studio-color.svg +1 -0
  37. package/gui/dist/provider-icons/mistral-color.svg +1 -0
  38. package/gui/dist/provider-icons/moonshot-color.svg +1 -0
  39. package/gui/dist/provider-icons/nvidia-color.svg +1 -0
  40. package/gui/dist/provider-icons/ollama-color.svg +1 -0
  41. package/gui/dist/provider-icons/openai.svg +1 -0
  42. package/gui/dist/provider-icons/opencode.svg +2 -0
  43. package/gui/dist/provider-icons/openrouter-color.svg +1 -0
  44. package/gui/dist/provider-icons/pi.svg +21 -0
  45. package/gui/dist/provider-icons/qianfan-color.svg +1 -0
  46. package/gui/dist/provider-icons/qwen-portal-color.svg +1 -0
  47. package/gui/dist/provider-icons/telegram.svg +1 -0
  48. package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -0
  49. package/gui/dist/provider-icons/vllm-color.svg +1 -0
  50. package/gui/dist/provider-icons/xiaomi-color.svg +1 -0
  51. package/package.json +108 -0
  52. package/src/AGENTS.md +28 -0
  53. package/src/adapters/anthropic-image-guard.ts +251 -0
  54. package/src/adapters/anthropic-image-normalize.ts +518 -0
  55. package/src/adapters/anthropic-output-schema.ts +137 -0
  56. package/src/adapters/anthropic.ts +1327 -0
  57. package/src/adapters/azure.ts +36 -0
  58. package/src/adapters/base.ts +121 -0
  59. package/src/adapters/client-fingerprint.ts +65 -0
  60. package/src/adapters/cline-pass-deepseek-v4-tool-replay.ts +69 -0
  61. package/src/adapters/command-code.ts +601 -0
  62. package/src/adapters/cursor/arg-codec.ts +38 -0
  63. package/src/adapters/cursor/arg-normalize.ts +104 -0
  64. package/src/adapters/cursor/checkpoint-store.ts +303 -0
  65. package/src/adapters/cursor/cursor-errors.ts +288 -0
  66. package/src/adapters/cursor/discovery.ts +333 -0
  67. package/src/adapters/cursor/effort-map.ts +151 -0
  68. package/src/adapters/cursor/exec-policy.ts +88 -0
  69. package/src/adapters/cursor/framing.ts +250 -0
  70. package/src/adapters/cursor/gen/agent_pb.ts +15274 -0
  71. package/src/adapters/cursor/h2-pool.ts +123 -0
  72. package/src/adapters/cursor/http1-bidi.ts +361 -0
  73. package/src/adapters/cursor/images.ts +704 -0
  74. package/src/adapters/cursor/kv-store.ts +52 -0
  75. package/src/adapters/cursor/live-models.ts +269 -0
  76. package/src/adapters/cursor/live-smoke-gate.ts +41 -0
  77. package/src/adapters/cursor/live-transport.ts +1653 -0
  78. package/src/adapters/cursor/mcp-config.ts +42 -0
  79. package/src/adapters/cursor/mcp-manager.ts +333 -0
  80. package/src/adapters/cursor/message-mapper.ts +49 -0
  81. package/src/adapters/cursor/native-exec-common.ts +76 -0
  82. package/src/adapters/cursor/native-exec-desktop.ts +184 -0
  83. package/src/adapters/cursor/native-exec-fs.ts +332 -0
  84. package/src/adapters/cursor/native-exec-mcp.ts +153 -0
  85. package/src/adapters/cursor/native-exec-network.ts +43 -0
  86. package/src/adapters/cursor/native-exec-shell.ts +547 -0
  87. package/src/adapters/cursor/native-exec-tools.ts +118 -0
  88. package/src/adapters/cursor/native-exec.ts +663 -0
  89. package/src/adapters/cursor/protobuf-events.ts +1381 -0
  90. package/src/adapters/cursor/protobuf-request.ts +1032 -0
  91. package/src/adapters/cursor/request-builder.ts +461 -0
  92. package/src/adapters/cursor/thread-continuity.ts +67 -0
  93. package/src/adapters/cursor/tool-definitions.ts +735 -0
  94. package/src/adapters/cursor/tool-result-normalize.ts +92 -0
  95. package/src/adapters/cursor/transport-retry.ts +132 -0
  96. package/src/adapters/cursor/transport.ts +79 -0
  97. package/src/adapters/cursor/types.ts +79 -0
  98. package/src/adapters/cursor.ts +322 -0
  99. package/src/adapters/google-antigravity-hosts.ts +48 -0
  100. package/src/adapters/google-antigravity-replay.ts +827 -0
  101. package/src/adapters/google-antigravity-tools.ts +105 -0
  102. package/src/adapters/google-antigravity-wire.ts +141 -0
  103. package/src/adapters/google-errors.ts +92 -0
  104. package/src/adapters/google-http.ts +460 -0
  105. package/src/adapters/google-tool-schema.ts +238 -0
  106. package/src/adapters/google-truncation.ts +24 -0
  107. package/src/adapters/google-wire-compiler.ts +232 -0
  108. package/src/adapters/google.ts +1377 -0
  109. package/src/adapters/identity.ts +77 -0
  110. package/src/adapters/image.ts +23 -0
  111. package/src/adapters/kiro-constants.ts +16 -0
  112. package/src/adapters/kiro-errors.ts +208 -0
  113. package/src/adapters/kiro-events.ts +197 -0
  114. package/src/adapters/kiro-images.ts +129 -0
  115. package/src/adapters/kiro-retry.ts +312 -0
  116. package/src/adapters/kiro-thinking.ts +112 -0
  117. package/src/adapters/kiro-tool-fallback.ts +36 -0
  118. package/src/adapters/kiro-tools.ts +224 -0
  119. package/src/adapters/kiro-truncation.ts +33 -0
  120. package/src/adapters/kiro-wire.ts +129 -0
  121. package/src/adapters/kiro.ts +1936 -0
  122. package/src/adapters/mimo-free.ts +280 -0
  123. package/src/adapters/openai-chat-url.ts +11 -0
  124. package/src/adapters/openai-chat.ts +1980 -0
  125. package/src/adapters/openai-responses-url.ts +16 -0
  126. package/src/adapters/openai-responses.ts +1911 -0
  127. package/src/adapters/registry.ts +175 -0
  128. package/src/adapters/responses-tool-schema.ts +67 -0
  129. package/src/adapters/run-turn-queue.ts +114 -0
  130. package/src/adapters/tool-call-id.ts +119 -0
  131. package/src/adapters/tool-catalog-nudge.ts +154 -0
  132. package/src/adapters/upstream-http-error.ts +48 -0
  133. package/src/adapters/xai-web-search.ts +185 -0
  134. package/src/bridge.ts +1986 -0
  135. package/src/chat/inbound.ts +319 -0
  136. package/src/chat/outbound.ts +821 -0
  137. package/src/claude/agents-inject.ts +266 -0
  138. package/src/claude/alias.ts +149 -0
  139. package/src/claude/auth-detect.ts +229 -0
  140. package/src/claude/auth-mode-migration.ts +32 -0
  141. package/src/claude/auth-mode.ts +62 -0
  142. package/src/claude/context-windows.ts +205 -0
  143. package/src/claude/desktop-3p-guard.ts +35 -0
  144. package/src/claude/desktop-3p-paths.ts +84 -0
  145. package/src/claude/desktop-3p.ts +615 -0
  146. package/src/claude/desktop-health.ts +26 -0
  147. package/src/claude/desktop-profile.ts +263 -0
  148. package/src/claude/gateway-cache.ts +107 -0
  149. package/src/claude/inbound-debug.ts +163 -0
  150. package/src/claude/inbound.ts +578 -0
  151. package/src/claude/model-info.ts +174 -0
  152. package/src/claude/outbound.ts +926 -0
  153. package/src/cli/access.ts +108 -0
  154. package/src/cli/account-api.ts +302 -0
  155. package/src/cli/account-auth.ts +250 -0
  156. package/src/cli/account-catalog-refresh.ts +14 -0
  157. package/src/cli/account-extended.ts +737 -0
  158. package/src/cli/account-main.ts +317 -0
  159. package/src/cli/account.ts +299 -0
  160. package/src/cli/agent-driven.ts +70 -0
  161. package/src/cli/agent.ts +290 -0
  162. package/src/cli/catalog-prewarm.ts +27 -0
  163. package/src/cli/claude-agent-startup-sync.ts +73 -0
  164. package/src/cli/claude-desktop.ts +213 -0
  165. package/src/cli/claude.ts +355 -0
  166. package/src/cli/codex-log-guard-doctor.ts +103 -0
  167. package/src/cli/codex-shim-autorestore.ts +47 -0
  168. package/src/cli/codex-shim-readiness.ts +76 -0
  169. package/src/cli/combo.ts +127 -0
  170. package/src/cli/config-command.ts +209 -0
  171. package/src/cli/debug.ts +228 -0
  172. package/src/cli/dispatch.ts +585 -0
  173. package/src/cli/doctor.ts +1202 -0
  174. package/src/cli/ensure-desired-integrations.ts +152 -0
  175. package/src/cli/export-command.ts +213 -0
  176. package/src/cli/help.ts +101 -0
  177. package/src/cli/index.ts +973 -0
  178. package/src/cli/init.ts +211 -0
  179. package/src/cli/integrations.ts +260 -0
  180. package/src/cli/interactive-confirm.ts +133 -0
  181. package/src/cli/lab.ts +607 -0
  182. package/src/cli/launcher-context.ts +77 -0
  183. package/src/cli/minimax.ts +497 -0
  184. package/src/cli/models-runtime.ts +245 -0
  185. package/src/cli/models.ts +422 -0
  186. package/src/cli/observe.ts +206 -0
  187. package/src/cli/opencode.ts +588 -0
  188. package/src/cli/provider-replit.ts +232 -0
  189. package/src/cli/provider-runtime.ts +179 -0
  190. package/src/cli/provider.ts +492 -0
  191. package/src/cli/ready.ts +301 -0
  192. package/src/cli/registry.ts +422 -0
  193. package/src/cli/replit-gateway-key-input.ts +138 -0
  194. package/src/cli/root.ts +86 -0
  195. package/src/cli/route-policy.ts +92 -0
  196. package/src/cli/runtime-api.ts +328 -0
  197. package/src/cli/star-prompt.ts +211 -0
  198. package/src/cli/status-oauth.ts +78 -0
  199. package/src/cli/status.ts +328 -0
  200. package/src/cli/system-command.ts +112 -0
  201. package/src/cli/system-restart-client.ts +146 -0
  202. package/src/cli/tray-proxy.ts +199 -0
  203. package/src/cli/v2.ts +268 -0
  204. package/src/cli.ts +10 -0
  205. package/src/clients/config-export.ts +1704 -0
  206. package/src/codex/account-id.ts +34 -0
  207. package/src/codex/account-label.ts +47 -0
  208. package/src/codex/account-lifecycle.ts +172 -0
  209. package/src/codex/account-namespace-match.ts +63 -0
  210. package/src/codex/account-namespaces.ts +195 -0
  211. package/src/codex/account-pause.ts +20 -0
  212. package/src/codex/account-priority.ts +83 -0
  213. package/src/codex/account-runtime-state.ts +31 -0
  214. package/src/codex/account-store.ts +544 -0
  215. package/src/codex/account-usability.ts +43 -0
  216. package/src/codex/admission.ts +256 -0
  217. package/src/codex/affinity-debug.ts +162 -0
  218. package/src/codex/agent-roles-sync.ts +225 -0
  219. package/src/codex/agent-roles.ts +238 -0
  220. package/src/codex/app-server-processes.ts +1143 -0
  221. package/src/codex/app-server-restart-service.ts +232 -0
  222. package/src/codex/auth-api.ts +2147 -0
  223. package/src/codex/auth-collision.ts +109 -0
  224. package/src/codex/auth-context.ts +665 -0
  225. package/src/codex/autostart-health.ts +156 -0
  226. package/src/codex/catalog/account-models.ts +67 -0
  227. package/src/codex/catalog/aggregation.ts +436 -0
  228. package/src/codex/catalog/bundled.ts +549 -0
  229. package/src/codex/catalog/effort.ts +446 -0
  230. package/src/codex/catalog/filesystem-evidence.ts +302 -0
  231. package/src/codex/catalog/kinds.ts +2 -0
  232. package/src/codex/catalog/metadata.ts +664 -0
  233. package/src/codex/catalog/native-models.ts +72 -0
  234. package/src/codex/catalog/parsing.ts +650 -0
  235. package/src/codex/catalog/provider-fetch.ts +2064 -0
  236. package/src/codex/catalog/sync.ts +1883 -0
  237. package/src/codex/catalog-admission.ts +199 -0
  238. package/src/codex/catalog-refresh-status.ts +105 -0
  239. package/src/codex/catalog-write-serialization.ts +242 -0
  240. package/src/codex/catalog.ts +14 -0
  241. package/src/codex/codex-write-lock.ts +384 -0
  242. package/src/codex/convergence-types.ts +614 -0
  243. package/src/codex/convergence.ts +651 -0
  244. package/src/codex/coordinator-doctor.ts +332 -0
  245. package/src/codex/custom-model-catalog-migration.ts +176 -0
  246. package/src/codex/data/upstream-models.json +830 -0
  247. package/src/codex/desired-state.ts +230 -0
  248. package/src/codex/exec-invocation.ts +22 -0
  249. package/src/codex/features.ts +1566 -0
  250. package/src/codex/generation.ts +202 -0
  251. package/src/codex/history-job.ts +407 -0
  252. package/src/codex/history-lock.ts +242 -0
  253. package/src/codex/history-migration-guardian.ts +108 -0
  254. package/src/codex/history-provider.ts +979 -0
  255. package/src/codex/history-transition.ts +105 -0
  256. package/src/codex/history-worker.ts +220 -0
  257. package/src/codex/home.ts +206 -0
  258. package/src/codex/inject-coordination.ts +290 -0
  259. package/src/codex/inject.ts +1733 -0
  260. package/src/codex/injected-marker.ts +106 -0
  261. package/src/codex/integration-record.ts +266 -0
  262. package/src/codex/internal/catalog-writer.ts +203 -0
  263. package/src/codex/internal/history-writer.ts +80 -0
  264. package/src/codex/journal.ts +225 -0
  265. package/src/codex/log-guard/inspect.ts +506 -0
  266. package/src/codex/log-guard/lock.ts +150 -0
  267. package/src/codex/log-guard/maintenance.ts +403 -0
  268. package/src/codex/log-guard/path-safety.ts +88 -0
  269. package/src/codex/log-guard/policy.ts +44 -0
  270. package/src/codex/log-guard/processes.ts +205 -0
  271. package/src/codex/log-guard/protection.ts +489 -0
  272. package/src/codex/log-guard/sqlite-errors.ts +9 -0
  273. package/src/codex/main-account-cache.ts +56 -0
  274. package/src/codex/main-account.ts +68 -0
  275. package/src/codex/management-convergence.ts +167 -0
  276. package/src/codex/model-cache.ts +273 -0
  277. package/src/codex/model-entitlements.ts +353 -0
  278. package/src/codex/native-main-admission.ts +47 -0
  279. package/src/codex/native-main-auth-temp.ts +187 -0
  280. package/src/codex/native-main-claim.ts +178 -0
  281. package/src/codex/native-main-lock-file.ts +162 -0
  282. package/src/codex/native-main-owner.ts +329 -0
  283. package/src/codex/native-profile-api.ts +247 -0
  284. package/src/codex/native-profile-manager.ts +1531 -0
  285. package/src/codex/native-profile-processes.ts +121 -0
  286. package/src/codex/native-profile-recovery.ts +99 -0
  287. package/src/codex/native-profile-stage-store.ts +387 -0
  288. package/src/codex/native-profile-startup.ts +492 -0
  289. package/src/codex/native-profile-store.ts +855 -0
  290. package/src/codex/native-profile-types.ts +120 -0
  291. package/src/codex/native-residue.ts +682 -0
  292. package/src/codex/paths.ts +144 -0
  293. package/src/codex/plan-from-token.ts +140 -0
  294. package/src/codex/plan.ts +40 -0
  295. package/src/codex/plugins-doctor.ts +242 -0
  296. package/src/codex/pool-rotation.ts +295 -0
  297. package/src/codex/project-config-warnings.ts +425 -0
  298. package/src/codex/prompt-journal.ts +352 -0
  299. package/src/codex/prompt-layers.ts +967 -0
  300. package/src/codex/prompt-lock.ts +143 -0
  301. package/src/codex/quota-rejection.ts +298 -0
  302. package/src/codex/quota.ts +573 -0
  303. package/src/codex/refresh.ts +62 -0
  304. package/src/codex/reset-credit-recovery.ts +1044 -0
  305. package/src/codex/routing.ts +1888 -0
  306. package/src/codex/runtime.ts +659 -0
  307. package/src/codex/shim.ts +2170 -0
  308. package/src/codex/subagent-defaults.ts +550 -0
  309. package/src/codex/subagent-model-fallback.ts +784 -0
  310. package/src/codex/sync.ts +319 -0
  311. package/src/codex/transition-state.ts +612 -0
  312. package/src/codex/upstream-host-health.ts +368 -0
  313. package/src/codex/user-identity.ts +557 -0
  314. package/src/codex/warmup.ts +298 -0
  315. package/src/codex/websocket-registry.ts +100 -0
  316. package/src/codex/write-coordination.ts +114 -0
  317. package/src/combos/failover.ts +160 -0
  318. package/src/combos/index.ts +45 -0
  319. package/src/combos/request.ts +94 -0
  320. package/src/combos/resolve.ts +232 -0
  321. package/src/combos/types.ts +398 -0
  322. package/src/config/provider-name.ts +24 -0
  323. package/src/config.ts +4041 -0
  324. package/src/fork/register.ts +3 -0
  325. package/src/generated/compatibility-version.json +3116 -0
  326. package/src/generated/model-metadata.ts +106 -0
  327. package/src/github/star-state.ts +203 -0
  328. package/src/grok/inject.ts +530 -0
  329. package/src/grok/inspect.ts +45 -0
  330. package/src/grok/status.ts +121 -0
  331. package/src/grok/sync.ts +66 -0
  332. package/src/images/artifacts.ts +516 -0
  333. package/src/images/fulfill-video.ts +163 -0
  334. package/src/images/fulfill.ts +149 -0
  335. package/src/images/index.ts +4 -0
  336. package/src/images/loop.ts +955 -0
  337. package/src/images/plan.ts +143 -0
  338. package/src/images/synthetic-tool.ts +133 -0
  339. package/src/images/types.ts +41 -0
  340. package/src/images/xai-client.ts +141 -0
  341. package/src/images/xai-video-client.ts +163 -0
  342. package/src/index.ts +22 -0
  343. package/src/integrations/config-io.ts +269 -0
  344. package/src/integrations/journal.ts +315 -0
  345. package/src/integrations/merge.ts +135 -0
  346. package/src/integrations/mutation-flight.ts +71 -0
  347. package/src/integrations/native/ownership-preflight.ts +202 -0
  348. package/src/integrations/omp-yaml-source.ts +358 -0
  349. package/src/integrations/owned-refresh.ts +74 -0
  350. package/src/integrations/ownership.ts +111 -0
  351. package/src/integrations/registry.ts +159 -0
  352. package/src/integrations/serialize.ts +314 -0
  353. package/src/integrations/state.ts +361 -0
  354. package/src/integrations/store.ts +103 -0
  355. package/src/integrations/writer-lock.ts +98 -0
  356. package/src/integrations/writer.ts +691 -0
  357. package/src/lab/artifacts/sanitize.ts +586 -0
  358. package/src/lab/artifacts/secure-fs.ts +475 -0
  359. package/src/lab/artifacts/store.ts +310 -0
  360. package/src/lab/automation/budgets.ts +78 -0
  361. package/src/lab/automation/config-persistence.ts +256 -0
  362. package/src/lab/automation/constants.ts +39 -0
  363. package/src/lab/automation/cooldown.ts +103 -0
  364. package/src/lab/automation/dispatch.ts +211 -0
  365. package/src/lab/automation/index.ts +13 -0
  366. package/src/lab/automation/orchestrator.ts +499 -0
  367. package/src/lab/automation/persistence.ts +512 -0
  368. package/src/lab/automation/planner.ts +371 -0
  369. package/src/lab/automation/policy.ts +136 -0
  370. package/src/lab/automation/queue.ts +191 -0
  371. package/src/lab/automation/recovery.ts +24 -0
  372. package/src/lab/automation/route-context.ts +21 -0
  373. package/src/lab/automation/run-key.ts +44 -0
  374. package/src/lab/automation/runs-query.ts +34 -0
  375. package/src/lab/automation/types.ts +160 -0
  376. package/src/lab/conformance/assertion.ts +325 -0
  377. package/src/lab/conformance/digest.ts +22 -0
  378. package/src/lab/conformance/executor.ts +741 -0
  379. package/src/lab/conformance/fixture-provider.ts +27 -0
  380. package/src/lab/conformance/fixtures/live-v1-cases.json +175 -0
  381. package/src/lab/conformance/fixtures/protocol-v1-cases.json +461 -0
  382. package/src/lab/conformance/harness-budget.ts +47 -0
  383. package/src/lab/conformance/index.ts +5 -0
  384. package/src/lab/conformance/jcs.ts +64 -0
  385. package/src/lab/conformance/json-pointer.ts +39 -0
  386. package/src/lab/conformance/manifest.ts +180 -0
  387. package/src/lab/conformance/mcp-stub.ts +179 -0
  388. package/src/lab/conformance/negative-controls.ts +164 -0
  389. package/src/lab/conformance/observation.ts +355 -0
  390. package/src/lab/conformance/runner.ts +68 -0
  391. package/src/lab/conformance/sse-normalize.ts +59 -0
  392. package/src/lab/conformance/suite-manifest.ts +78 -0
  393. package/src/lab/conformance/types.ts +214 -0
  394. package/src/lab/constants.ts +126 -0
  395. package/src/lab/digest.ts +64 -0
  396. package/src/lab/events/errors.ts +9 -0
  397. package/src/lab/events/limits.ts +117 -0
  398. package/src/lab/events/types.ts +229 -0
  399. package/src/lab/events/validate.ts +781 -0
  400. package/src/lab/fabric/constants.ts +40 -0
  401. package/src/lab/fabric/executor.ts +492 -0
  402. package/src/lab/fabric/index.ts +80 -0
  403. package/src/lab/fabric/manifest.ts +222 -0
  404. package/src/lab/fabric/observe.ts +489 -0
  405. package/src/lab/fabric/patch.ts +79 -0
  406. package/src/lab/fabric/producer-child.ts +139 -0
  407. package/src/lab/fabric/producer-isolate.ts +276 -0
  408. package/src/lab/fabric/producer-protocol.ts +61 -0
  409. package/src/lab/fabric/scratch.ts +439 -0
  410. package/src/lab/fabric/subject.ts +106 -0
  411. package/src/lab/fabric/types.ts +134 -0
  412. package/src/lab/fabric/verifier.ts +98 -0
  413. package/src/lab/index.ts +54 -0
  414. package/src/lab/ledger/artifact-refs.ts +127 -0
  415. package/src/lab/ledger/invalidation.ts +136 -0
  416. package/src/lab/ledger/purge.ts +310 -0
  417. package/src/lab/ledger/store.ts +532 -0
  418. package/src/lab/live/credential-lease.ts +53 -0
  419. package/src/lab/live/destination.ts +155 -0
  420. package/src/lab/live/executor.ts +336 -0
  421. package/src/lab/live/inert-tools.ts +56 -0
  422. package/src/lab/live/manifest.ts +85 -0
  423. package/src/lab/live/mcp-loopback.ts +57 -0
  424. package/src/lab/live/runner.ts +19 -0
  425. package/src/lab/live/sandbox.ts +61 -0
  426. package/src/lab/live/suite-manifest.ts +41 -0
  427. package/src/lab/live/transport.ts +118 -0
  428. package/src/lab/live/types.ts +197 -0
  429. package/src/lab/observe/from-conformance.ts +301 -0
  430. package/src/lab/observe/from-live.ts +117 -0
  431. package/src/lab/paths.ts +153 -0
  432. package/src/lab/projection/rebuild.ts +495 -0
  433. package/src/lab/projection/schema.ts +135 -0
  434. package/src/lab/projection/verdicts.ts +474 -0
  435. package/src/lab/projection/verification.ts +412 -0
  436. package/src/lab/public/bundle.ts +217 -0
  437. package/src/lab/public/community-authority.ts +175 -0
  438. package/src/lab/public/community-files.ts +29 -0
  439. package/src/lab/public/community.ts +479 -0
  440. package/src/lab/public/file-safety.ts +155 -0
  441. package/src/lab/public/ids.ts +26 -0
  442. package/src/lab/public/index.ts +16 -0
  443. package/src/lab/public/mutation-lock.ts +424 -0
  444. package/src/lab/public/operator.ts +353 -0
  445. package/src/lab/public/origin-purge.ts +79 -0
  446. package/src/lab/public/origin.ts +203 -0
  447. package/src/lab/public/privacy.ts +143 -0
  448. package/src/lab/public/private-file.ts +261 -0
  449. package/src/lab/public/project.ts +124 -0
  450. package/src/lab/public/purge-test-fault.ts +21 -0
  451. package/src/lab/public/purge.ts +223 -0
  452. package/src/lab/public/registry.ts +44 -0
  453. package/src/lab/public/revocation.ts +252 -0
  454. package/src/lab/public/signature.ts +243 -0
  455. package/src/lab/public/storage.ts +105 -0
  456. package/src/lab/public/strict-json.ts +206 -0
  457. package/src/lab/public/time.ts +26 -0
  458. package/src/lab/public/types.ts +172 -0
  459. package/src/lab/public/validate.ts +391 -0
  460. package/src/lab/query/catalog.ts +101 -0
  461. package/src/lab/query/connection.ts +107 -0
  462. package/src/lab/query/constants.ts +4 -0
  463. package/src/lab/query/cursor.ts +132 -0
  464. package/src/lab/query/dto-map.ts +277 -0
  465. package/src/lab/query/errors.ts +22 -0
  466. package/src/lab/query/freshness.ts +53 -0
  467. package/src/lab/query/index.ts +45 -0
  468. package/src/lab/query/latest-observation.ts +59 -0
  469. package/src/lab/query/passive-production.ts +159 -0
  470. package/src/lab/query/queries.ts +444 -0
  471. package/src/lab/query/types.ts +266 -0
  472. package/src/lab/subject/behavior-fingerprint.ts +77 -0
  473. package/src/lab/subject/installation-salt.ts +112 -0
  474. package/src/lab/subject/protocol-subject.ts +80 -0
  475. package/src/lab/subject/route-subject.ts +74 -0
  476. package/src/lib/abort.ts +146 -0
  477. package/src/lib/admin-secrets.ts +25 -0
  478. package/src/lib/admission.ts +83 -0
  479. package/src/lib/app-owned-memory-stores.ts +195 -0
  480. package/src/lib/app-owned-memory.ts +265 -0
  481. package/src/lib/bounded-body.ts +346 -0
  482. package/src/lib/bun-binary-validator.d.mts +3 -0
  483. package/src/lib/bun-binary-validator.mjs +18 -0
  484. package/src/lib/bun-runtime.ts +184 -0
  485. package/src/lib/bun-stream-caps.ts +130 -0
  486. package/src/lib/codex-restart-contract.ts +120 -0
  487. package/src/lib/config-ownership.ts +364 -0
  488. package/src/lib/crash-guard.ts +344 -0
  489. package/src/lib/debug-log-buffer.ts +83 -0
  490. package/src/lib/debug-settings.ts +108 -0
  491. package/src/lib/debug.ts +31 -0
  492. package/src/lib/destination-policy.ts +380 -0
  493. package/src/lib/errors.ts +406 -0
  494. package/src/lib/eventstream-decoder.ts +253 -0
  495. package/src/lib/fabric-task-execution-authority.ts +7 -0
  496. package/src/lib/fabric-task-host.ts +29 -0
  497. package/src/lib/gcp-adc.ts +341 -0
  498. package/src/lib/injection-debug-log.ts +58 -0
  499. package/src/lib/lab-activation.ts +223 -0
  500. package/src/lib/lab-live-execution-authority.ts +13 -0
  501. package/src/lib/lab-live-host.ts +30 -0
  502. package/src/lib/lab-live-pinned-sender.ts +56 -0
  503. package/src/lib/lab-live-route-production.ts +130 -0
  504. package/src/lib/lab-passive-linker-registration.ts +26 -0
  505. package/src/lib/local-management-attestation.ts +51 -0
  506. package/src/lib/local-management-capability.ts +100 -0
  507. package/src/lib/local-provider-reload-contract.ts +100 -0
  508. package/src/lib/open-url.ts +25 -0
  509. package/src/lib/optional-shutdown-hooks.ts +57 -0
  510. package/src/lib/pinned-http.ts +270 -0
  511. package/src/lib/privacy.ts +20 -0
  512. package/src/lib/process-control.ts +168 -0
  513. package/src/lib/provider-outbound.ts +210 -0
  514. package/src/lib/provider-url.ts +14 -0
  515. package/src/lib/proxy-env.ts +18 -0
  516. package/src/lib/redact.ts +521 -0
  517. package/src/lib/retry-after.ts +55 -0
  518. package/src/lib/self-launch-argv.ts +15 -0
  519. package/src/lib/server-resource-ownership.ts +71 -0
  520. package/src/lib/service-secrets.ts +25 -0
  521. package/src/lib/shadow-call.ts +61 -0
  522. package/src/lib/sidecar-tracker.ts +52 -0
  523. package/src/lib/sse-decoder.ts +364 -0
  524. package/src/lib/state-store-registrations.ts +119 -0
  525. package/src/lib/state-store-sweeper.ts +184 -0
  526. package/src/lib/system-restart-contract.ts +73 -0
  527. package/src/lib/test-home-guard.ts +90 -0
  528. package/src/lib/token-estimate.ts +86 -0
  529. package/src/lib/tool-argument-integers.ts +202 -0
  530. package/src/lib/translator-budget.ts +400 -0
  531. package/src/lib/upstream-http-version.ts +57 -0
  532. package/src/lib/upstream-reachability.ts +95 -0
  533. package/src/lib/upstream-retry.ts +392 -0
  534. package/src/lib/win-exec.ts +115 -0
  535. package/src/lib/win-paths.ts +68 -0
  536. package/src/lib/windows-atomic-replace.ts +156 -0
  537. package/src/lib/windows-elevation.ts +773 -0
  538. package/src/lib/windows-secret-acl.ts +854 -0
  539. package/src/lib/windows-service-wrappers.ts +72 -0
  540. package/src/lib/windows-text.ts +106 -0
  541. package/src/lib/windows-user-principal.ts +341 -0
  542. package/src/lib/winsw.ts +403 -0
  543. package/src/oauth/account-import/google-antigravity-adapter.ts +74 -0
  544. package/src/oauth/account-import/index.ts +15 -0
  545. package/src/oauth/account-import/parser.ts +83 -0
  546. package/src/oauth/account-import/registry.ts +18 -0
  547. package/src/oauth/account-import/service.ts +75 -0
  548. package/src/oauth/account-import/types.ts +91 -0
  549. package/src/oauth/anthropic-routing.ts +594 -0
  550. package/src/oauth/anthropic.ts +188 -0
  551. package/src/oauth/antigravity-routing.ts +151 -0
  552. package/src/oauth/callback-server.ts +300 -0
  553. package/src/oauth/chatgpt.ts +161 -0
  554. package/src/oauth/command-code.ts +239 -0
  555. package/src/oauth/cursor.ts +252 -0
  556. package/src/oauth/github-copilot.ts +428 -0
  557. package/src/oauth/google-antigravity.ts +262 -0
  558. package/src/oauth/health.ts +407 -0
  559. package/src/oauth/index.ts +1504 -0
  560. package/src/oauth/key-providers.ts +124 -0
  561. package/src/oauth/kimi.ts +227 -0
  562. package/src/oauth/kiro-credentials.ts +726 -0
  563. package/src/oauth/kiro.ts +621 -0
  564. package/src/oauth/local-token-detect.ts +130 -0
  565. package/src/oauth/log.ts +50 -0
  566. package/src/oauth/login-cli.ts +223 -0
  567. package/src/oauth/nous.ts +798 -0
  568. package/src/oauth/pkce.ts +15 -0
  569. package/src/oauth/store.ts +728 -0
  570. package/src/oauth/token-guardian.ts +309 -0
  571. package/src/oauth/types.ts +62 -0
  572. package/src/oauth/xai.ts +241 -0
  573. package/src/providers/alibaba-region-backup.ts +75 -0
  574. package/src/providers/alibaba-region-migration.ts +156 -0
  575. package/src/providers/alibaba-region-startup.ts +36 -0
  576. package/src/providers/antigravity-models.ts +695 -0
  577. package/src/providers/antigravity-quota.ts +216 -0
  578. package/src/providers/api-keys.ts +140 -0
  579. package/src/providers/base-url-choices.ts +74 -0
  580. package/src/providers/codex-capacity.ts +292 -0
  581. package/src/providers/command-code-efforts.ts +144 -0
  582. package/src/providers/context-cap.ts +82 -0
  583. package/src/providers/cursor-pool.ts +72 -0
  584. package/src/providers/derive.ts +586 -0
  585. package/src/providers/fastwire.ts +501 -0
  586. package/src/providers/free-directory.ts +187 -0
  587. package/src/providers/github-copilot-transport.ts +56 -0
  588. package/src/providers/google-vertex-location.ts +14 -0
  589. package/src/providers/key-failover.ts +271 -0
  590. package/src/providers/kiro-models.ts +67 -0
  591. package/src/providers/label.ts +19 -0
  592. package/src/providers/model-discovery-limits.ts +16 -0
  593. package/src/providers/model-discovery.ts +449 -0
  594. package/src/providers/model-rename-migration.ts +255 -0
  595. package/src/providers/model-rename-startup.ts +28 -0
  596. package/src/providers/openai-sidecar.ts +243 -0
  597. package/src/providers/openai-tier-startup.ts +56 -0
  598. package/src/providers/openai-tiers.ts +423 -0
  599. package/src/providers/openai-virtual-models.ts +83 -0
  600. package/src/providers/opencode-zen-rate-limit.ts +102 -0
  601. package/src/providers/openrouter-routing.ts +102 -0
  602. package/src/providers/provider-id-rewrite.ts +185 -0
  603. package/src/providers/quota.ts +2345 -0
  604. package/src/providers/registry.ts +2918 -0
  605. package/src/providers/replit/constants.ts +27 -0
  606. package/src/providers/replit/derive.ts +85 -0
  607. package/src/providers/replit/headers.ts +28 -0
  608. package/src/providers/replit/origin.ts +55 -0
  609. package/src/providers/replit/pair-install-response.ts +72 -0
  610. package/src/providers/replit/probe.ts +199 -0
  611. package/src/providers/replit/setup.ts +350 -0
  612. package/src/providers/request-pacing.ts +310 -0
  613. package/src/providers/service-tier.ts +277 -0
  614. package/src/providers/slug-codec.ts +103 -0
  615. package/src/providers/static-model-discovery.ts +86 -0
  616. package/src/providers/xai-responses-opt-in.ts +15 -0
  617. package/src/providers/xai-transport.ts +148 -0
  618. package/src/reasoning-effort.ts +183 -0
  619. package/src/responses/compaction.ts +142 -0
  620. package/src/responses/custom-tool-compat.ts +266 -0
  621. package/src/responses/hosted-tool-policy.ts +9 -0
  622. package/src/responses/namespace-tool-compat.ts +355 -0
  623. package/src/responses/parser.ts +838 -0
  624. package/src/responses/provider-continuation.ts +98 -0
  625. package/src/responses/provider-opaque-metadata.ts +73 -0
  626. package/src/responses/reasoning-envelope.ts +60 -0
  627. package/src/responses/reasoning-replay-cache.ts +426 -0
  628. package/src/responses/schema.ts +165 -0
  629. package/src/responses/spill-store.ts +459 -0
  630. package/src/responses/state.ts +1433 -0
  631. package/src/responses/thought-signature-replay.ts +347 -0
  632. package/src/responses/tool-groups.ts +19 -0
  633. package/src/responses/tool-search-compat.ts +301 -0
  634. package/src/responses/truncated-stop-reason.ts +60 -0
  635. package/src/router.ts +761 -0
  636. package/src/routing/analytics.ts +378 -0
  637. package/src/routing/capability.ts +244 -0
  638. package/src/routing/compatibility/assemble.ts +73 -0
  639. package/src/routing/compatibility/behavior.ts +278 -0
  640. package/src/routing/compatibility/catalog.ts +99 -0
  641. package/src/routing/compatibility/endpoint.ts +52 -0
  642. package/src/routing/compatibility/lab-evidence-provider.ts +130 -0
  643. package/src/routing/compatibility/policy.ts +181 -0
  644. package/src/routing/compatibility/provider-slot.ts +56 -0
  645. package/src/routing/compatibility/reader.ts +110 -0
  646. package/src/routing/compatibility/subject.ts +191 -0
  647. package/src/routing/compatibility/types.ts +64 -0
  648. package/src/routing/compatibility/version.ts +104 -0
  649. package/src/routing/cost.ts +77 -0
  650. package/src/routing/evaluator.ts +495 -0
  651. package/src/routing/health.ts +412 -0
  652. package/src/routing/history/cursor.ts +43 -0
  653. package/src/routing/history/indexer.ts +605 -0
  654. package/src/routing/history/schema.ts +72 -0
  655. package/src/routing/profile-namespace.ts +15 -0
  656. package/src/routing/profile.ts +547 -0
  657. package/src/routing/quota.ts +145 -0
  658. package/src/routing/request-evidence.ts +45 -0
  659. package/src/routing/trace.ts +776 -0
  660. package/src/server/adapter-resolve.ts +53 -0
  661. package/src/server/auth-cors.ts +751 -0
  662. package/src/server/background-lifecycle.ts +182 -0
  663. package/src/server/chat-completions.ts +442 -0
  664. package/src/server/chat-native-sse.ts +331 -0
  665. package/src/server/chat-native.ts +426 -0
  666. package/src/server/claude-messages.ts +1030 -0
  667. package/src/server/direct-local-http.ts +347 -0
  668. package/src/server/effort-policy.ts +190 -0
  669. package/src/server/github-copilot-responses-repair.ts +338 -0
  670. package/src/server/gui-static.ts +152 -0
  671. package/src/server/image-retry.ts +42 -0
  672. package/src/server/images.ts +568 -0
  673. package/src/server/index.ts +1813 -0
  674. package/src/server/lifecycle.ts +498 -0
  675. package/src/server/live.ts +717 -0
  676. package/src/server/local-management-read-client.ts +90 -0
  677. package/src/server/local-provider-reload-client.ts +137 -0
  678. package/src/server/management/agent-settings-routes.ts +1433 -0
  679. package/src/server/management/api-access.ts +141 -0
  680. package/src/server/management/api-key-usage.ts +193 -0
  681. package/src/server/management/body.ts +41 -0
  682. package/src/server/management/combo-routes.ts +263 -0
  683. package/src/server/management/config-routes.ts +835 -0
  684. package/src/server/management/context.ts +113 -0
  685. package/src/server/management/integration-routes.ts +498 -0
  686. package/src/server/management/lab-automation-routes.ts +206 -0
  687. package/src/server/management/lab-routes.ts +563 -0
  688. package/src/server/management/logs-usage-routes.ts +586 -0
  689. package/src/server/management/model-routes.ts +560 -0
  690. package/src/server/management/model-rows.ts +163 -0
  691. package/src/server/management/native-integration-routes.ts +769 -0
  692. package/src/server/management/oauth-account-routes.ts +637 -0
  693. package/src/server/management/provider-capability-config.ts +48 -0
  694. package/src/server/management/provider-routes.ts +1033 -0
  695. package/src/server/management/replit-provider-routes.ts +86 -0
  696. package/src/server/management/request-history-routes.ts +191 -0
  697. package/src/server/management/routing-analytics-routes.ts +74 -0
  698. package/src/server/management/routing-profile-routes.ts +385 -0
  699. package/src/server/management/shared.ts +286 -0
  700. package/src/server/management/sidebar-routes.ts +106 -0
  701. package/src/server/management/storage-log-guard-routes.ts +186 -0
  702. package/src/server/management/sync-response.ts +69 -0
  703. package/src/server/management/system-restart.ts +435 -0
  704. package/src/server/management/system-routes.ts +194 -0
  705. package/src/server/management/usage-summary-cache.ts +94 -0
  706. package/src/server/management/vision-sidecar-options.ts +167 -0
  707. package/src/server/management/web-search-sidecar-options.ts +120 -0
  708. package/src/server/management-api.ts +314 -0
  709. package/src/server/management-auth.ts +482 -0
  710. package/src/server/memory-watchdog.ts +156 -0
  711. package/src/server/passive-route-linker.ts +66 -0
  712. package/src/server/port-reclaim.ts +307 -0
  713. package/src/server/ports.ts +156 -0
  714. package/src/server/proxy-liveness.ts +328 -0
  715. package/src/server/readiness.ts +99 -0
  716. package/src/server/relay-eager.ts +353 -0
  717. package/src/server/relay.ts +1209 -0
  718. package/src/server/request-decompress.ts +239 -0
  719. package/src/server/request-log-conversation.ts +168 -0
  720. package/src/server/request-log.ts +1259 -0
  721. package/src/server/responses/agent-task-recovery-cache.ts +143 -0
  722. package/src/server/responses/agent-task-recovery.ts +465 -0
  723. package/src/server/responses/collaboration.ts +551 -0
  724. package/src/server/responses/compact.ts +771 -0
  725. package/src/server/responses/core.ts +5389 -0
  726. package/src/server/responses/empty-completion-guard.ts +276 -0
  727. package/src/server/responses/encrypted-payload.ts +331 -0
  728. package/src/server/responses/fetch-helpers.ts +232 -0
  729. package/src/server/responses/input-admission.ts +185 -0
  730. package/src/server/responses/pacing-overload.ts +13 -0
  731. package/src/server/responses/passthrough-error.ts +78 -0
  732. package/src/server/responses/policy-fallback.ts +178 -0
  733. package/src/server/responses/responses-field-backfill.ts +251 -0
  734. package/src/server/responses/terminal-guard.ts +251 -0
  735. package/src/server/responses/upstream-error.ts +53 -0
  736. package/src/server/responses/ws-upstream.ts +308 -0
  737. package/src/server/responses-custom-tool-repair.ts +282 -0
  738. package/src/server/responses-image-gen-repair.ts +132 -0
  739. package/src/server/responses-item-id-repair.ts +272 -0
  740. package/src/server/responses-json-events.ts +90 -0
  741. package/src/server/responses-model-rewrite.ts +29 -0
  742. package/src/server/responses-reasoning-summary-rewrite.ts +178 -0
  743. package/src/server/responses-snapshot-repair.ts +621 -0
  744. package/src/server/responses-terminal-repair.ts +342 -0
  745. package/src/server/responses-tool-search-repair.ts +267 -0
  746. package/src/server/responses-undeclared-tool-guard.ts +153 -0
  747. package/src/server/responses.ts +25 -0
  748. package/src/server/search.ts +201 -0
  749. package/src/server/sse-frame-buffer.ts +292 -0
  750. package/src/server/sse-payload-rewrite.ts +263 -0
  751. package/src/server/startup-action-control.ts +315 -0
  752. package/src/server/startup-health-cache.ts +131 -0
  753. package/src/server/system-env.ts +484 -0
  754. package/src/server/windows-tcp-drop.ts +184 -0
  755. package/src/server/windows-tray-control.ts +41 -0
  756. package/src/server/ws-bridge.ts +472 -0
  757. package/src/service-manager-probe.ts +892 -0
  758. package/src/service.ts +3575 -0
  759. package/src/sidecar/auth.ts +92 -0
  760. package/src/sidecar/candidates.ts +83 -0
  761. package/src/stall-timeout.ts +20 -0
  762. package/src/storage/cleanup-job.ts +57 -0
  763. package/src/storage/cleanup.ts +3085 -0
  764. package/src/storage/policy-job.ts +457 -0
  765. package/src/storage/policy-scheduler.ts +40 -0
  766. package/src/storage/policy-worker.ts +59 -0
  767. package/src/storage/policy.ts +527 -0
  768. package/src/storage/restore-job.ts +299 -0
  769. package/src/storage/restore-worker.ts +58 -0
  770. package/src/storage/scanner.ts +238 -0
  771. package/src/storage/storage-mutation-coordinator.ts +139 -0
  772. package/src/storage/worker-lifecycle.ts +215 -0
  773. package/src/tray/assets/opencodex-tray-offline.ico +0 -0
  774. package/src/tray/assets/opencodex-tray-online.ico +0 -0
  775. package/src/tray/assets/opencodex-tray-warning.ico +0 -0
  776. package/src/tray/assets/opencodex-tray.png +0 -0
  777. package/src/tray/windows-tray.ps1 +364 -0
  778. package/src/tray/windows.ts +757 -0
  779. package/src/types/accounts.ts +37 -0
  780. package/src/types/config.ts +876 -0
  781. package/src/types/provider.ts +545 -0
  782. package/src/types/request.ts +384 -0
  783. package/src/types/tools.ts +131 -0
  784. package/src/types/wire.ts +80 -0
  785. package/src/types.ts +106 -0
  786. package/src/update/badge.ts +72 -0
  787. package/src/update/index.ts +415 -0
  788. package/src/update/job.ts +1887 -0
  789. package/src/update/notify.ts +263 -0
  790. package/src/update/npm-cache-preflight.d.mts +47 -0
  791. package/src/update/npm-cache-preflight.mjs +201 -0
  792. package/src/update/npm-invocation.d.mts +23 -0
  793. package/src/update/npm-invocation.mjs +94 -0
  794. package/src/update/transactional-install.d.mts +22 -0
  795. package/src/update/transactional-install.mjs +259 -0
  796. package/src/update/tray-update-plan.d.mts +18 -0
  797. package/src/update/tray-update-plan.mjs +38 -0
  798. package/src/usage/cost.ts +625 -0
  799. package/src/usage/debug.ts +97 -0
  800. package/src/usage/expected-prices.ts +416 -0
  801. package/src/usage/log.ts +1223 -0
  802. package/src/usage/summary.ts +753 -0
  803. package/src/usage/totals.ts +14 -0
  804. package/src/usage/user-cost-overlay-reconciler.ts +313 -0
  805. package/src/usage/user-cost-overlays.ts +314 -0
  806. package/src/vision/anthropic-describe.ts +189 -0
  807. package/src/vision/backends.ts +97 -0
  808. package/src/vision/describe.ts +131 -0
  809. package/src/vision/eligibility.ts +250 -0
  810. package/src/vision/index.ts +681 -0
  811. package/src/vision/reasoning.ts +55 -0
  812. package/src/vision/routed-describe.ts +175 -0
  813. package/src/vision/timeout-bounds.ts +9 -0
  814. package/src/web-search/anthropic-executor.ts +195 -0
  815. package/src/web-search/backends.ts +108 -0
  816. package/src/web-search/exa-executor.ts +88 -0
  817. package/src/web-search/executor.ts +113 -0
  818. package/src/web-search/format-result.ts +89 -0
  819. package/src/web-search/gemini-executor.ts +141 -0
  820. package/src/web-search/index.ts +331 -0
  821. package/src/web-search/loop.ts +896 -0
  822. package/src/web-search/parse.ts +315 -0
  823. package/src/web-search/progress-stream.ts +342 -0
  824. package/src/web-search/sources.ts +60 -0
  825. package/src/web-search/synthetic-tool.ts +47 -0
  826. package/src/web-search/xai-executor.ts +219 -0
@@ -0,0 +1,270 @@
1
+ import http, { type ClientRequest, type IncomingMessage, type RequestOptions } from "node:http";
2
+ import https from "node:https";
3
+
4
+ export type PinnedAddress = { address: string; family: number };
5
+
6
+ export type PinnedHttpErrorCode =
7
+ | "connect_timeout"
8
+ | "first_byte_timeout"
9
+ | "inactivity_timeout"
10
+ | "output_byte_limit";
11
+
12
+ export class PinnedHttpError extends Error {
13
+ override readonly name = "PinnedHttpError";
14
+ constructor(readonly code: PinnedHttpErrorCode, message: string) { super(message); }
15
+ }
16
+
17
+ export interface PinnedHttpRequestOptions {
18
+ headers?: HeadersInit;
19
+ maxBytes?: number;
20
+ /** Optional deadline for establishing the TCP connection and, for HTTPS, completing TLS. */
21
+ connectTimeoutMs?: number;
22
+ /** Optional deadline from connection establishment until response headers arrive. */
23
+ firstByteTimeoutMs?: number;
24
+ /** Optional maximum idle interval between response-body chunks. */
25
+ inactivityTimeoutMs?: number;
26
+ /** @deprecated Use firstByteTimeoutMs and inactivityTimeoutMs. */
27
+ idleTimeoutMs?: number;
28
+ rejectUnauthorized?: boolean;
29
+ context?: string;
30
+ }
31
+
32
+ /** @deprecated Use {@link PinnedHttpRequestOptions}. */
33
+ export type PinnedHttpGetOptions = PinnedHttpRequestOptions;
34
+
35
+ function pinnedHttpRequest(
36
+ url: string,
37
+ pinned: PinnedAddress,
38
+ method: "GET" | "POST",
39
+ body: string | undefined,
40
+ signal?: AbortSignal,
41
+ options?: PinnedHttpRequestOptions,
42
+ ): Promise<Response> {
43
+ const parsed = new URL(url);
44
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
45
+ throw new Error(`${options?.context ?? "request"} must use HTTP or HTTPS, got ${parsed.protocol}`);
46
+ }
47
+ const context = options?.context ?? "request";
48
+ const connectTimeoutMs = options?.connectTimeoutMs;
49
+ const legacyIdleTimeoutMs = options?.idleTimeoutMs ?? 60_000;
50
+ const usesLegacyIdleTimeout = options?.firstByteTimeoutMs === undefined
51
+ && options?.inactivityTimeoutMs === undefined;
52
+ const firstByteTimeoutMs = options?.firstByteTimeoutMs ?? legacyIdleTimeoutMs;
53
+ const inactivityTimeoutMs = options?.inactivityTimeoutMs ?? legacyIdleTimeoutMs;
54
+ const legacyFirstByteDisabled = usesLegacyIdleTimeout && legacyIdleTimeoutMs === 0;
55
+ const maxBytes = options?.maxBytes;
56
+ const headers = new Headers(options?.headers);
57
+ headers.set("host", parsed.host);
58
+ if (body !== undefined && !headers.has("content-length")) {
59
+ headers.set("content-length", String(Buffer.byteLength(body)));
60
+ }
61
+ const requestHeaders: Record<string, string> = {};
62
+ headers.forEach((value, key) => { requestHeaders[key] = value; });
63
+
64
+ return new Promise<Response>((resolve, reject) => {
65
+ if (signal?.aborted) {
66
+ reject(signal.reason instanceof Error ? signal.reason : new Error("aborted"));
67
+ return;
68
+ }
69
+
70
+ let settled = false;
71
+ let req: ClientRequest | undefined;
72
+ let connectTimer: ReturnType<typeof setTimeout> | undefined;
73
+ let firstByteTimer: ReturnType<typeof setTimeout> | undefined;
74
+ const clearConnectTimer = () => {
75
+ if (connectTimer !== undefined) clearTimeout(connectTimer);
76
+ connectTimer = undefined;
77
+ };
78
+ const clearFirstByteTimer = () => {
79
+ if (firstByteTimer !== undefined) clearTimeout(firstByteTimer);
80
+ firstByteTimer = undefined;
81
+ };
82
+ const fail = (error: unknown) => {
83
+ clearConnectTimer();
84
+ clearFirstByteTimer();
85
+ try { req?.destroy(); } catch { /* ignore */ }
86
+ if (settled) return;
87
+ settled = true;
88
+ reject(error instanceof Error ? error : new Error(String(error)));
89
+ };
90
+ const startFirstByteTimer = () => {
91
+ clearFirstByteTimer();
92
+ if (settled || legacyFirstByteDisabled) return;
93
+ firstByteTimer = setTimeout(
94
+ () => fail(new PinnedHttpError("first_byte_timeout", `${context} first byte timed out`)),
95
+ firstByteTimeoutMs,
96
+ );
97
+ };
98
+ const requestOptions: RequestOptions & { servername?: string } = {
99
+ protocol: parsed.protocol,
100
+ hostname: parsed.hostname,
101
+ port: parsed.port || (parsed.protocol === "https:" ? 443 : 80),
102
+ path: `${parsed.pathname}${parsed.search}`,
103
+ method,
104
+ headers: requestHeaders,
105
+ ...(parsed.protocol === "https:"
106
+ ? {
107
+ servername: parsed.hostname,
108
+ rejectUnauthorized: options?.rejectUnauthorized ?? true,
109
+ }
110
+ : {}),
111
+ lookup(_hostname, lookupOptions, callback) {
112
+ const opts = typeof lookupOptions === "function" ? undefined : lookupOptions;
113
+ const cb = typeof lookupOptions === "function" ? lookupOptions : callback;
114
+ if (!cb) return;
115
+ if (opts && typeof opts === "object" && "all" in opts && opts.all) {
116
+ (cb as (error: NodeJS.ErrnoException | null, addresses: PinnedAddress[]) => void)(
117
+ null,
118
+ [{ address: pinned.address, family: pinned.family }],
119
+ );
120
+ return;
121
+ }
122
+ (cb as (error: NodeJS.ErrnoException | null, address: string, family: 4 | 6) => void)(
123
+ null,
124
+ pinned.address,
125
+ pinned.family as 4 | 6,
126
+ );
127
+ },
128
+ };
129
+
130
+ const onResponse = (response: IncomingMessage) => {
131
+ clearConnectTimer();
132
+ clearFirstByteTimer();
133
+ const status = response.statusCode ?? 0;
134
+ const responseHeaders = new Headers();
135
+ for (const [key, value] of Object.entries(response.headers)) {
136
+ if (value === undefined || value === null) continue;
137
+ if (Array.isArray(value)) {
138
+ for (const item of value) responseHeaders.append(key, String(item));
139
+ } else {
140
+ responseHeaders.set(key, String(value));
141
+ }
142
+ }
143
+
144
+ if (status < 200 || status >= 300) {
145
+ try { response.destroy(); } catch { /* ignore */ }
146
+ try { req?.destroy(); } catch { /* ignore */ }
147
+ if (settled) return;
148
+ settled = true;
149
+ resolve(new Response(null, { status, headers: responseHeaders }));
150
+ return;
151
+ }
152
+
153
+ let received = 0;
154
+ const stream = new ReadableStream<Uint8Array>({
155
+ start(controller) {
156
+ let bodySettled = false;
157
+ const failBody = (error: Error) => {
158
+ if (bodySettled) return;
159
+ bodySettled = true;
160
+ try { controller.error(error); } catch { /* closed */ }
161
+ try { response.destroy(); } catch { /* ignore */ }
162
+ try { req?.destroy(); } catch { /* ignore */ }
163
+ };
164
+
165
+ response.setTimeout(inactivityTimeoutMs, () => {
166
+ failBody(new PinnedHttpError("inactivity_timeout", `${context} stalled`));
167
+ });
168
+ response.on("data", (chunk: Buffer | string) => {
169
+ if (bodySettled) return;
170
+ const buffer = typeof chunk === "string" ? Buffer.from(chunk) : chunk;
171
+ received += buffer.byteLength;
172
+ if (maxBytes !== undefined && received > maxBytes) {
173
+ failBody(new PinnedHttpError("output_byte_limit", `${context} exceeds ${maxBytes} byte cap`));
174
+ return;
175
+ }
176
+ try { controller.enqueue(buffer); } catch { /* closed */ }
177
+ });
178
+ response.on("end", () => {
179
+ if (bodySettled) return;
180
+ bodySettled = true;
181
+ try { controller.close(); } catch { /* closed */ }
182
+ });
183
+ response.on("error", (error: Error) => {
184
+ failBody(error);
185
+ });
186
+ },
187
+ cancel() {
188
+ req?.destroy();
189
+ },
190
+ });
191
+
192
+ if (settled) return;
193
+ settled = true;
194
+ resolve(new Response(stream, { status, headers: responseHeaders }));
195
+ };
196
+
197
+ const requestFn = parsed.protocol === "https:" ? https.request : http.request;
198
+ req = requestFn(requestOptions, onResponse);
199
+ if (usesLegacyIdleTimeout) startFirstByteTimer();
200
+ const onAbort = () => fail(signal?.reason instanceof Error ? signal.reason : new Error("aborted"));
201
+ req.on("socket", (socket) => {
202
+ const connectedEvent = parsed.protocol === "https:" ? "secureConnect" : "connect";
203
+ if (!socket.connecting) {
204
+ if (!usesLegacyIdleTimeout) startFirstByteTimer();
205
+ return;
206
+ }
207
+ if (connectTimeoutMs !== undefined) {
208
+ connectTimer = setTimeout(
209
+ () => fail(new PinnedHttpError("connect_timeout", `${context} connect timed out`)),
210
+ connectTimeoutMs,
211
+ );
212
+ }
213
+ socket.once(connectedEvent, () => {
214
+ clearConnectTimer();
215
+ if (!usesLegacyIdleTimeout) startFirstByteTimer();
216
+ });
217
+ socket.once("error", () => {
218
+ clearConnectTimer();
219
+ clearFirstByteTimer();
220
+ });
221
+ socket.once("close", () => {
222
+ clearConnectTimer();
223
+ clearFirstByteTimer();
224
+ });
225
+ });
226
+ if (usesLegacyIdleTimeout) {
227
+ req.setTimeout(legacyIdleTimeoutMs, () => fail(new Error(`${context} timed out`)));
228
+ }
229
+ req.on("error", error => {
230
+ signal?.removeEventListener("abort", onAbort);
231
+ fail(error);
232
+ });
233
+ req.on("close", () => {
234
+ clearConnectTimer();
235
+ clearFirstByteTimer();
236
+ signal?.removeEventListener("abort", onAbort);
237
+ });
238
+ signal?.addEventListener("abort", onAbort, { once: true });
239
+ if (signal?.aborted && !settled) onAbort();
240
+ if (settled) return;
241
+ req.end(body);
242
+ });
243
+ }
244
+
245
+ /**
246
+ * GET a URL through one previously validated address. The original hostname
247
+ * remains authoritative for Host, SNI, and certificate verification.
248
+ */
249
+ export function pinnedHttpGet(
250
+ url: string,
251
+ pinned: PinnedAddress,
252
+ signal?: AbortSignal,
253
+ options?: PinnedHttpRequestOptions,
254
+ ): Promise<Response> {
255
+ return pinnedHttpRequest(url, pinned, "GET", undefined, signal, options);
256
+ }
257
+
258
+ /**
259
+ * POST a string body through one previously validated address. The original
260
+ * hostname remains authoritative for Host, SNI, and certificate verification.
261
+ */
262
+ export function pinnedHttpPost(
263
+ url: string,
264
+ pinned: PinnedAddress,
265
+ body: string,
266
+ signal?: AbortSignal,
267
+ options?: PinnedHttpRequestOptions,
268
+ ): Promise<Response> {
269
+ return pinnedHttpRequest(url, pinned, "POST", body, signal, options);
270
+ }
@@ -0,0 +1,20 @@
1
+ export function maskEmail(value: string | null | undefined): string | null {
2
+ if (!value) return null;
3
+ const at = value.indexOf("@");
4
+ if (at <= 0) return value;
5
+ const local = value.slice(0, at);
6
+ const domain = value.slice(at + 1);
7
+ if (!domain) return value;
8
+ if (local.length === 1) return `*@${domain}`;
9
+ if (local.length === 2) return `${local[0]}*@${domain}`;
10
+ return `${local[0]}***${local[local.length - 1]}@${domain}`;
11
+ }
12
+
13
+ export function maskAccountId(value: string | null | undefined): string | null {
14
+ if (!value) return null;
15
+ const id = value.trim();
16
+ if (!id) return null;
17
+ // Short IDs would disclose the entire identifier via the suffix; use a non-identifying placeholder.
18
+ if (id.length <= 4) return "account-…";
19
+ return `account-…${id.slice(-4)}`;
20
+ }
@@ -0,0 +1,168 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import { loadConfig, readRuntimePort } from "../config";
3
+ import { configuredAdminToken } from "./admin-secrets";
4
+
5
+ export function isProcessAlive(pid: number): boolean {
6
+ try {
7
+ process.kill(pid, 0);
8
+ return true;
9
+ } catch {
10
+ return false;
11
+ }
12
+ }
13
+
14
+ export function waitForExit(pid: number, timeoutMs: number): boolean {
15
+ const deadline = Date.now() + timeoutMs;
16
+ const marker = new Int32Array(new SharedArrayBuffer(4));
17
+ while (Date.now() < deadline) {
18
+ if (!isProcessAlive(pid)) return true;
19
+ Atomics.wait(marker, 0, 0, 50);
20
+ }
21
+ return !isProcessAlive(pid);
22
+ }
23
+
24
+ /** Injectable seams so the graceful-stop flow is unit-testable without a live proxy. */
25
+ export interface GracefulStopIo {
26
+ fetchFn?: typeof fetch;
27
+ readRuntime?: (pid: number) => { port: number; hostname?: string } | null;
28
+ waitExit?: (pid: number, timeoutMs: number) => boolean;
29
+ env?: Record<string, string | undefined>;
30
+ exitTimeoutMs?: number;
31
+ }
32
+
33
+ /**
34
+ * Host to POST /api/stop against: follow the recorded bind hostname when it names a
35
+ * concrete address (a proxy bound to ::1 or a LAN IP is unreachable on 127.0.0.1);
36
+ * loopback aliases and wildcard binds all answer on IPv4 loopback.
37
+ */
38
+ export function gracefulStopHost(hostname: string | undefined): string {
39
+ const trimmed = (hostname ?? "").trim();
40
+ const lower = trimmed.toLowerCase();
41
+ if (!trimmed || lower === "localhost" || trimmed === "127.0.0.1" || trimmed === "0.0.0.0" || trimmed === "::" || trimmed === "[::]") {
42
+ return "127.0.0.1";
43
+ }
44
+ if (lower === "::1" || lower === "[::1]") return "[::1]";
45
+ if (trimmed.startsWith("[") && trimmed.endsWith("]")) return trimmed;
46
+ return trimmed.includes(":") ? `[${trimmed}]` : trimmed;
47
+ }
48
+
49
+ /**
50
+ * Outcome of a graceful stop attempt. `"refused"` is distinct from failure: the proxy answered
51
+ * that it must NOT be stopped from here, so callers must not escalate to a forced kill.
52
+ */
53
+ export type GracefulStopResult = boolean | "refused";
54
+
55
+ /** A proxy declined shutdown because a service under another home owns it (HTTP 409). */
56
+ export class ProxyOwnershipRefusedError extends Error {}
57
+
58
+ /**
59
+ * Ask a running proxy to stop itself via the management API (`POST /api/stop`), which
60
+ * drains in-flight turns, restores native Codex, and cleans its pid/runtime files.
61
+ * This is the only way to get a GRACEFUL stop on Windows, where the POSIX
62
+ * SIGTERM-then-SIGKILL ladder does not exist and `taskkill /F` gives the proxy no
63
+ * chance to run its shutdown handlers. Returns false when the proxy can't be reached
64
+ * or doesn't exit in time — callers fall back to {@link killProxy}. Returns `"refused"`
65
+ * when the proxy declines the stop (HTTP 409), which callers must NOT force past.
66
+ */
67
+ export async function stopProxyGracefully(pid: number, io: GracefulStopIo = {}): Promise<GracefulStopResult> {
68
+ const readRuntime = io.readRuntime ?? readRuntimePort;
69
+ const runtime = readRuntime(pid);
70
+ if (!runtime?.port) return false;
71
+ const env = io.env ?? process.env;
72
+ const headers: Record<string, string> = {};
73
+ const token = configuredAdminToken(env.OPENCODEX_HOME?.trim() || undefined, env as NodeJS.ProcessEnv);
74
+ if (token) headers["x-opencodex-api-key"] = token;
75
+ const fetchFn = io.fetchFn ?? fetch;
76
+ try {
77
+ const res = await fetchFn(`http://${gracefulStopHost(runtime.hostname)}:${runtime.port}/api/stop`, {
78
+ method: "POST",
79
+ headers,
80
+ // Hung proxies with many CLOSE_WAIT clients can be slow to accept; give them
81
+ // longer than a health poll so we prefer drain over taskkill /F.
82
+ signal: AbortSignal.timeout(io.exitTimeoutMs ? Math.min(io.exitTimeoutMs, 10_000) : 10_000),
83
+ });
84
+ // 409 is the proxy REFUSING to stop (a service installed under another home owns it and
85
+ // would respawn it anyway). That is a policy answer, not a dead endpoint — escalating to
86
+ // SIGTERM here would run the daemon's cleanup and strip shared config out from under the
87
+ // still-running service. Report the refusal instead of forcing.
88
+ if (res.status === 409) return "refused";
89
+ if (!res.ok) return false;
90
+ } catch {
91
+ return false;
92
+ }
93
+ const waitExit = io.waitExit ?? waitForExit;
94
+ // Honor the server's own drain window: /api/stop answers 200 first, then drains for
95
+ // config.shutdownTimeoutMs. Waiting less than that hard-kills mid-drain.
96
+ const exitTimeoutMs = io.exitTimeoutMs ?? drainDeadlineMs();
97
+ return waitExit(pid, exitTimeoutMs);
98
+ }
99
+
100
+ function drainDeadlineMs(): number {
101
+ try {
102
+ return (loadConfig().shutdownTimeoutMs ?? 5000) + 3000;
103
+ } catch {
104
+ return 8000;
105
+ }
106
+ }
107
+
108
+ /** Graceful-first stop: management-API drain, then the platform kill ladder. */
109
+ export async function stopProxy(pid: number): Promise<void> {
110
+ if (!isProcessAlive(pid)) return;
111
+ const runtime = readRuntimePort(pid);
112
+ const graceful = await stopProxyGracefully(pid);
113
+ if (graceful === "refused") {
114
+ // The proxy refused on purpose (foreign service owns it). Forcing would strip shared
115
+ // config while that service keeps the proxy alive.
116
+ throw new ProxyOwnershipRefusedError(
117
+ "The running proxy refused to stop: a service installed under a different "
118
+ + "CODEX_HOME/OPENCODEX_HOME owns it. Run the stop from that home.",
119
+ );
120
+ }
121
+ if (graceful) {
122
+ await waitForStoppedPort(runtime, pid);
123
+ return;
124
+ }
125
+ killProxy(pid);
126
+ await waitForStoppedPort(runtime, pid);
127
+ }
128
+
129
+ /** After stop/kill, wait for the former listen port to become bindable (Windows drain). */
130
+ async function waitForStoppedPort(
131
+ runtime: { port: number; hostname?: string } | null | undefined,
132
+ stoppedPid?: number,
133
+ ): Promise<void> {
134
+ if (!runtime?.port) return;
135
+ try {
136
+ const { reclaimListenPort } = await import("../server/port-reclaim");
137
+ await reclaimListenPort(runtime.port, runtime.hostname ?? "127.0.0.1", {
138
+ timeoutMs: 15_000,
139
+ intervalMs: 100,
140
+ scanIntervalMs: 500,
141
+ // Only the process we just stopped — never kill a newly started twin proxy.
142
+ killOcxHolders: !!(stoppedPid && stoppedPid > 0),
143
+ onlyKillPids: stoppedPid && stoppedPid > 0 ? [stoppedPid] : [],
144
+ });
145
+ } catch {
146
+ /* best-effort — callers that need a hard guarantee reclaim again before bind */
147
+ }
148
+ }
149
+
150
+ export function killProxy(pid: number): void {
151
+ if (!isProcessAlive(pid)) return;
152
+ if (process.platform === "win32") {
153
+ // Windows process.kill(SIGTERM/SIGINT) is TerminateProcess — not a graceful signal.
154
+ // Graceful drain happens only via stopProxyGracefully() (POST /api/stop). This path
155
+ // is the hard fallback: taskkill /T /F so the process tree exits (ghost LISTEN /
156
+ // CLOSE_WAIT are then cleared by reclaimListenPort / SetTcpEntry).
157
+ const taskkill = `${process.env.SystemRoot ?? "C:\\Windows"}\\System32\\taskkill.exe`;
158
+ try {
159
+ execFileSync(taskkill, ["/PID", String(pid), "/T", "/F"], { stdio: "pipe", windowsHide: true });
160
+ } catch (err) {
161
+ if (isProcessAlive(pid)) throw err;
162
+ }
163
+ } else {
164
+ process.kill(pid, "SIGTERM");
165
+ if (!waitForExit(pid, 5000)) process.kill(pid, "SIGKILL");
166
+ }
167
+ if (!waitForExit(pid, 5000)) throw new Error(`process ${pid} did not exit`);
168
+ }
@@ -0,0 +1,210 @@
1
+ import type { OcxProviderConfig } from "../types";
2
+ import {
3
+ assessUrlDestination,
4
+ DestinationDnsResolutionError,
5
+ providerAllowsPrivateNetwork,
6
+ providerDestinationConfigError,
7
+ resolvePublicAddresses,
8
+ } from "./destination-policy";
9
+ import { pinnedHttpGet, pinnedHttpPost } from "./pinned-http";
10
+ import { outboundProxyConfigured } from "./proxy-env";
11
+ import { publicProviderBaseUrl } from "./provider-url";
12
+
13
+ type ProviderGetInit = Omit<RequestInit, "body" | "method" | "redirect">;
14
+ type ProviderPostInit = ProviderGetInit & { body: string };
15
+ type ProviderOutboundConfig = Pick<OcxProviderConfig, "baseUrl" | "allowPrivateNetwork"> & {
16
+ fetch?: typeof globalThis.fetch;
17
+ };
18
+ export interface ProviderOutboundDependencies {
19
+ resolveAddresses?: typeof resolvePublicAddresses;
20
+ pinnedGet?: typeof pinnedHttpGet;
21
+ pinnedPost?: typeof pinnedHttpPost;
22
+ }
23
+
24
+ export class ProviderOutboundPolicyError extends Error {
25
+ override readonly name = "ProviderOutboundPolicyError";
26
+ }
27
+
28
+ function pickPinnedAddress(addresses: Array<{ address: string; family: number }>): { address: string; family: number } {
29
+ return addresses.find(address => address.family === 4) ?? addresses[0]!;
30
+ }
31
+
32
+ function configuredProxyFor(): boolean {
33
+ return outboundProxyConfigured();
34
+ }
35
+
36
+ function normalizeProxyHostname(hostname: string): string {
37
+ const normalized = hostname.trim().toLowerCase().replace(/\.+$/, "");
38
+ return normalized.startsWith("[") && normalized.endsWith("]")
39
+ ? normalized.slice(1, -1)
40
+ : normalized;
41
+ }
42
+
43
+ function noProxyMatches(url: URL): boolean {
44
+ const raw = process.env.NO_PROXY ?? process.env.no_proxy ?? "";
45
+ const hostname = normalizeProxyHostname(url.hostname);
46
+ const port = url.port || (url.protocol === "https:" ? "443" : "80");
47
+ for (const rawEntry of raw.split(",")) {
48
+ let entry = rawEntry.trim().toLowerCase();
49
+ if (!entry) continue;
50
+ if (entry === "*") return true;
51
+ entry = entry.replace(/^https?:\/\//, "").split("/", 1)[0]!;
52
+
53
+ let entryHost = entry;
54
+ let entryPort = "";
55
+ const bracketed = /^\[([^\]]+)](?::(\d+))?$/.exec(entry);
56
+ if (bracketed) {
57
+ entryHost = bracketed[1]!;
58
+ entryPort = bracketed[2] ?? "";
59
+ } else if ((entry.match(/:/g)?.length ?? 0) === 1) {
60
+ const separator = entry.lastIndexOf(":");
61
+ const possiblePort = entry.slice(separator + 1);
62
+ if (/^\d+$/.test(possiblePort)) {
63
+ entryHost = entry.slice(0, separator);
64
+ entryPort = possiblePort;
65
+ }
66
+ }
67
+ if (entryPort && entryPort !== port) continue;
68
+ entryHost = normalizeProxyHostname(entryHost.replace(/^\*?\./, ""));
69
+ if (!entryHost) continue;
70
+ if (hostname === entryHost || hostname.endsWith(`.${entryHost}`)) return true;
71
+ }
72
+ return false;
73
+ }
74
+
75
+ let proxyBoundaryWarned = false;
76
+ let proxyDnsDegradationWarned = false;
77
+
78
+ function warnProxyBoundaryOnce(): void {
79
+ if (proxyBoundaryWarned) return;
80
+ proxyBoundaryWarned = true;
81
+ console.warn(
82
+ "[opencodex] Provider outbound proxy mode preserves Bun proxy/NO_PROXY routing and validates "
83
+ + "the URL plus available local DNS results; the final route and peer cannot be pinned locally.",
84
+ );
85
+ }
86
+
87
+ function warnProxyDnsDegradationOnce(): void {
88
+ if (proxyDnsDegradationWarned) return;
89
+ proxyDnsDegradationWarned = true;
90
+ console.warn(
91
+ "[opencodex] Local DNS could not resolve a proxied provider hostname; continuing after URL/literal checks. "
92
+ + "The proxy-selected peer cannot be verified or pinned locally.",
93
+ );
94
+ }
95
+
96
+ export async function providerRedirectError(response: Response, requestUrl: string): Promise<string | null> {
97
+ if (response.status < 300 || response.status >= 400) return null;
98
+ try { await response.body?.cancel(); } catch { /* ignore cancellation failures */ }
99
+ const location = response.headers.get("location");
100
+ let target = "the final upstream URL";
101
+ if (location) {
102
+ try { target = publicProviderBaseUrl(new URL(location, requestUrl).toString()); } catch { /* keep fallback */ }
103
+ }
104
+ return `provider returned ${response.status} redirect to ${target}; configure the final provider URL directly`;
105
+ }
106
+
107
+ async function providerOutboundRequest(
108
+ name: string,
109
+ provider: ProviderOutboundConfig,
110
+ url: string,
111
+ method: "GET" | "POST",
112
+ init: ProviderGetInit | ProviderPostInit,
113
+ dependencies: ProviderOutboundDependencies = {},
114
+ ): Promise<Response> {
115
+ const postUrl = method === "POST" ? new URL(url) : undefined;
116
+ if (postUrl?.protocol !== undefined && postUrl.protocol !== "https:") {
117
+ throw new ProviderOutboundPolicyError("provider POST URL must use HTTPS");
118
+ }
119
+ if (provider.fetch) {
120
+ // A caller-owned executor cannot be peer-pinned here. This branch keeps literal/config
121
+ // checks and redirect blocking, but does not provide the resolved-address guarantees of
122
+ // the built-in transport. Main-request migration must define that executor contract first.
123
+ const assessment = assessUrlDestination(url);
124
+ if (assessment?.kind === "metadata" || assessment?.kind === "link-local" || assessment?.kind === "unspecified") {
125
+ throw new ProviderOutboundPolicyError(`provider URL targets ${assessment.detail}`);
126
+ }
127
+ // Registry defaults count here too, not just the operator flag: a stock Ollama entry is
128
+ // local by definition and previously passed config validation only to be refused at the
129
+ // fetch (#758). Metadata/link-local/unspecified were already rejected above.
130
+ const allowPrivate = providerAllowsPrivateNetwork(name, provider);
131
+ if (!allowPrivate) {
132
+ const destinationError = providerDestinationConfigError(name, {
133
+ baseUrl: url,
134
+ allowPrivateNetwork: false,
135
+ });
136
+ if (destinationError) throw new ProviderOutboundPolicyError(destinationError);
137
+ }
138
+ return provider.fetch(url, { ...init, method, redirect: "manual" });
139
+ }
140
+ const parsed = postUrl ?? new URL(url);
141
+ const proxyConfigured = configuredProxyFor();
142
+ const resolveAddresses = dependencies.resolveAddresses ?? resolvePublicAddresses;
143
+ const pinnedGet = dependencies.pinnedGet ?? pinnedHttpGet;
144
+ const pinnedPost = dependencies.pinnedPost ?? pinnedHttpPost;
145
+ const allowPrivate = providerAllowsPrivateNetwork(name, provider);
146
+ let resolved: Awaited<ReturnType<typeof resolvePublicAddresses>>;
147
+ try {
148
+ resolved = await resolveAddresses(url, {
149
+ context: "provider URL",
150
+ allowPrivateNetwork: allowPrivate,
151
+ // Clash/Surge/Mihomo fake-IP DNS (198.18.0.0/15) answers are admitted only
152
+ // when this exact host will use the configured outbound proxy: the hostname
153
+ // then rides the proxy as an ordinary CONNECT instead of failing as a private
154
+ // destination or being pin-connected to the fake-IP (credit #1748). A NO_PROXY
155
+ // match is a direct route, so it keeps the benchmark answer rejected. Image/Lab
156
+ // fetch never passes this flag.
157
+ allowBenchmarkAddresses: proxyConfigured && !noProxyMatches(parsed),
158
+ });
159
+ } catch (error) {
160
+ const dnsResolutionFailed = error instanceof DestinationDnsResolutionError
161
+ || (error instanceof Error && error.name === "DestinationDnsResolutionError");
162
+ if (!dnsResolutionFailed) {
163
+ throw new ProviderOutboundPolicyError(error instanceof Error ? error.message : "provider destination was blocked");
164
+ }
165
+ if (!proxyConfigured) throw error;
166
+ warnProxyBoundaryOnce();
167
+ warnProxyDnsDegradationOnce();
168
+ return globalThis.fetch(url, { ...init, method, redirect: "manual" });
169
+ }
170
+ if (proxyConfigured && !resolved.privateNetwork) {
171
+ warnProxyBoundaryOnce();
172
+ return globalThis.fetch(url, { ...init, method, redirect: "manual" });
173
+ }
174
+ if (proxyConfigured && resolved.privateNetwork && !noProxyMatches(parsed)) {
175
+ const hostname = normalizeProxyHostname(parsed.hostname);
176
+ throw new Error(
177
+ `provider URL resolves to a private-network destination; add ${hostname} to NO_PROXY before using allowPrivateNetwork with an outbound proxy`,
178
+ );
179
+ }
180
+ const requestOptions = {
181
+ headers: init.headers,
182
+ rejectUnauthorized: true,
183
+ context: "provider response",
184
+ };
185
+ const pinned = pickPinnedAddress(resolved.addresses);
186
+ if (method === "POST") {
187
+ return pinnedPost(url, pinned, (init as ProviderPostInit).body, init.signal ?? undefined, requestOptions);
188
+ }
189
+ return pinnedGet(url, pinned, init.signal ?? undefined, requestOptions);
190
+ }
191
+
192
+ export async function providerOutboundGet(
193
+ name: string,
194
+ provider: ProviderOutboundConfig,
195
+ url: string,
196
+ init: ProviderGetInit = {},
197
+ dependencies: ProviderOutboundDependencies = {},
198
+ ): Promise<Response> {
199
+ return providerOutboundRequest(name, provider, url, "GET", init, dependencies);
200
+ }
201
+
202
+ export async function providerOutboundPost(
203
+ name: string,
204
+ provider: ProviderOutboundConfig,
205
+ url: string,
206
+ init: ProviderPostInit,
207
+ dependencies: ProviderOutboundDependencies = {},
208
+ ): Promise<Response> {
209
+ return providerOutboundRequest(name, provider, url, "POST", init, dependencies);
210
+ }
@@ -0,0 +1,14 @@
1
+ /** Strip credentials and non-routing URL components before displaying a provider URL. */
2
+ export function publicProviderBaseUrl(baseUrl: string): string {
3
+ try {
4
+ const parsed = new URL(baseUrl.trim());
5
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return "(invalid URL)";
6
+ parsed.username = "";
7
+ parsed.password = "";
8
+ parsed.search = "";
9
+ parsed.hash = "";
10
+ return parsed.toString().replace(/\/$/, baseUrl.endsWith("/") ? "/" : "");
11
+ } catch {
12
+ return "(invalid URL)";
13
+ }
14
+ }