@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,95 @@
1
+ /**
2
+ * Classification of upstream fetch rejections that occur before any request
3
+ * bytes can reach the origin: DNS resolution failure and TCP connect refusal.
4
+ *
5
+ * Issue #914: these failures are machine/network-wide, not account-specific —
6
+ * every Codex pool account shares the provider host, so rotating accounts
7
+ * cannot repair them. The transport layer previously mapped every non-timeout
8
+ * rejection to `connect_error`, and at `upstreamFailoverThreshold` that streak
9
+ * soft-avoided a healthy account and cleared thread affinity.
10
+ *
11
+ * Bun collapses DNS failure and TCP refusal into one label class
12
+ * (`ConnectionRefused` / `FailedToOpenSocket`, errno 0); Node's undici emits
13
+ * the classic `ECONNREFUSED` / `ENOTFOUND` / `EAI_AGAIN` / `ENETUNREACH` /
14
+ * `ENETDOWN` / `EHOSTUNREACH` shapes. Both shapes are matched here, on `code`
15
+ * values only, through a bounded cause chain. Message substrings are never
16
+ * trusted (a message-only match is a negative case), and labels that can also
17
+ * appear after the origin saw the credential — `ECONNRESET`, `EPIPE`, TLS
18
+ * errors, unknown shapes — deliberately stay outside the set.
19
+ *
20
+ * Classifier semantics extracted from PR #966 (Yuxin-Qiao) with attribution;
21
+ * sidecar blast radius intentionally not inherited.
22
+ *
23
+ * MUST stay a leaf module: imports nothing from server.ts or adapters.
24
+ */
25
+
26
+ import { RequestPacingQueueOverloadError } from "../providers/request-pacing";
27
+ import { UpstreamRetryEvidenceError } from "./upstream-retry";
28
+
29
+ export const PRE_CONNECT_REACHABILITY_CODES = new Set([
30
+ // Bun: DNS failure and TCP refusal share this class.
31
+ "ConnectionRefused",
32
+ "FailedToOpenSocket",
33
+ // Node undici / classic Node shapes.
34
+ "ECONNREFUSED",
35
+ "ENOTFOUND",
36
+ "EAI_AGAIN",
37
+ "ENETUNREACH",
38
+ "ENETDOWN",
39
+ "EHOSTUNREACH",
40
+ ]);
41
+
42
+ /** Upper bound on how far `cause` chains are inspected. */
43
+ export const MAX_REACHABILITY_CAUSE_DEPTH = 3;
44
+
45
+ /**
46
+ * True when the rejection (or a bounded `cause` of it) carries a proven
47
+ * pre-connection reachability code. Never matches message text.
48
+ */
49
+ export function isPreConnectReachabilityError(err: unknown): boolean {
50
+ let current: unknown = err;
51
+ const seen = new Set<unknown>();
52
+ for (let depth = 0; depth < MAX_REACHABILITY_CAUSE_DEPTH; depth++) {
53
+ if (!(current instanceof Error) || seen.has(current)) return false;
54
+ seen.add(current);
55
+ const code = (current as { code?: unknown }).code;
56
+ if (typeof code === "string" && PRE_CONNECT_REACHABILITY_CODES.has(code)) return true;
57
+ current = current.cause;
58
+ }
59
+ return false;
60
+ }
61
+
62
+ export type TransportFailureKind = "timeout" | "connect_neutral" | "connect_error";
63
+
64
+ /**
65
+ * Shared transport rejection classification for Codex pool upstream sends.
66
+ * Timeouts keep their existing identity (account-transient); proven pre-connect
67
+ * reachability failures become account-neutral; everything else (ECONNRESET,
68
+ * EPIPE, TLS, unknown shapes) keeps the existing `connect_error`
69
+ * account-attributed behavior.
70
+ */
71
+ export function classifyTransportFailureKind(err: unknown): TransportFailureKind {
72
+ // A local pacing admission failure happened before transport classification and must
73
+ // remain a client-visible overload, not account or host health evidence.
74
+ if (err instanceof RequestPacingQueueOverloadError) throw err;
75
+ const evidence = err instanceof UpstreamRetryEvidenceError ? err : undefined;
76
+ const rejection = evidence ? evidence.cause : err;
77
+ if (rejection instanceof Error && rejection.name === "TimeoutError") return "timeout";
78
+ if (isPreConnectReachabilityError(rejection)) {
79
+ // A transient upstream response (5xx) or a credential-visible connection
80
+ // reset before the rejection proves the host and credential path were
81
+ // reached: the failure is account-attributable, never the pre-connection
82
+ // neutral class (issue #914 review).
83
+ if (evidence && (evidence.transientStatuses.length > 0 || evidence.resetSeen)) return "connect_error";
84
+ return "connect_neutral";
85
+ }
86
+ return "connect_error";
87
+ }
88
+
89
+ /** Stable `code` carried by a transport rejection, when there is one. */
90
+ export function transportErrorCode(err: unknown): string | undefined {
91
+ const rejection = err instanceof UpstreamRetryEvidenceError ? err.cause : err;
92
+ if (!(rejection instanceof Error)) return undefined;
93
+ const code = (rejection as { code?: unknown }).code;
94
+ return typeof code === "string" && code !== "" ? code : undefined;
95
+ }
@@ -0,0 +1,392 @@
1
+ /**
2
+ * Retry guard for upstream fetches that die on stale pooled keep-alive sockets.
3
+ *
4
+ * chatgpt.com (Cloudflare) closes idle keep-alive connections server-side; Bun's fetch pool
5
+ * reuses the half-closed socket and the request write fails with ECONNRESET before any
6
+ * response bytes arrive. Retrying on a fresh connection is safe for our replayable
7
+ * (string-body) upstream requests, because fetch() rejects only before response headers —
8
+ * a caught error here means no response was ever received.
9
+ *
10
+ * Deliberately narrow: timeouts, aborts, ECONNREFUSED/DNS/TLS failures, and HTTP error
11
+ * statuses (returned as Response, never thrown) are NOT retried. Mid-stream SSE resets are
12
+ * out of scope — the response has already resolved by then.
13
+ *
14
+ * MUST stay a leaf module: imports nothing from server.ts or adapters (kiro-retry imports
15
+ * the shared abort helpers from here).
16
+ */
17
+ import { clearableDeadline } from "./abort";
18
+
19
+ // 1 initial + 2 retries: the pool may hold more than one stale socket.
20
+ const RESET_RETRY_MAX_ATTEMPTS = 3;
21
+ const RESET_RETRY_BASE_DELAY_MS = 150;
22
+ const RESET_RETRY_MAX_DELAY_MS = 1_000;
23
+
24
+ // Transient-5xx status retry layer (pre-stream only; devlog/_plan/260716_claudecode_hardening/010).
25
+ const TRANSIENT_RETRY_MAX_ATTEMPTS = 3; // 1 initial + 2 retries
26
+ const TRANSIENT_RETRY_BASE_DELAY_MS = 400;
27
+ const TRANSIENT_RETRY_MAX_DELAY_MS = 5_000;
28
+ // A failed attempt slower than this is the "slow 502" incident shape (191s observed on
29
+ // 2026-07-15): retrying it only duplicates upstream load past client timeouts — return it.
30
+ const TRANSIENT_RETRY_SLOW_ATTEMPT_MS = 15_000;
31
+
32
+ /**
33
+ * Upstream statuses treated as transient: gateway errors and Cloudflare 52x.
34
+ * 500 is included per the OpenAI SDK default (auto-retries >=500; Tier-2 proven in
35
+ * devlog/260716_ocx_claude_sol_502_midstream/02). 507 was observed in the 48h ledger
36
+ * but is deliberately excluded (storage-class, not gateway-transient).
37
+ */
38
+ export function isTransientUpstreamStatus(status: number): boolean {
39
+ return status === 500 || status === 502 || status === 503 || status === 504
40
+ || status === 520 || status === 521 || status === 522;
41
+ }
42
+
43
+ export interface RetryBackoffOptions {
44
+ baseDelayMs: number;
45
+ maxDelayMs: number;
46
+ headers?: Headers;
47
+ }
48
+
49
+ export function abortError(signal?: AbortSignal): unknown {
50
+ return signal?.reason ?? new DOMException("The operation was aborted", "AbortError");
51
+ }
52
+
53
+ export async function sleepWithAbort(ms: number, signal?: AbortSignal): Promise<void> {
54
+ if (ms <= 0) return;
55
+ if (signal?.aborted) throw abortError(signal);
56
+ await new Promise<void>((resolve, reject) => {
57
+ let timer: ReturnType<typeof setTimeout>;
58
+ const cleanup = () => {
59
+ clearTimeout(timer);
60
+ signal?.removeEventListener("abort", onAbort);
61
+ };
62
+ const onAbort = () => {
63
+ cleanup();
64
+ reject(abortError(signal));
65
+ };
66
+ timer = setTimeout(() => {
67
+ cleanup();
68
+ resolve();
69
+ }, ms);
70
+ signal?.addEventListener("abort", onAbort, { once: true });
71
+ });
72
+ }
73
+
74
+ /**
75
+ * Best-effort, bounded cancellation of a response body before a retry backoff.
76
+ *
77
+ * The 429 paths release the unread body before waiting so sockets do not accumulate under a
78
+ * rate-limit storm, but a never-settling `cancel()` promise must not be able to block the
79
+ * abort-aware backoff (client cancel, `maxIntervalMs`, or the cumulative header deadline).
80
+ * Cancellation is started and its rejection observed; the await is bounded by `timeoutMs`
81
+ * and the abort signal. This mirrors the rotation-path guarantee (release is initiated, not
82
+ * awaited forever) while preserving the resource-release intent of the same-target paths.
83
+ */
84
+ export async function releaseResponseBodyBestEffort(
85
+ body: ReadableStream<Uint8Array> | null,
86
+ signal: AbortSignal | undefined,
87
+ timeoutMs = 1_000,
88
+ ): Promise<void> {
89
+ if (!body) return;
90
+ if (signal?.aborted) {
91
+ void body.cancel().catch(() => {});
92
+ return;
93
+ }
94
+ const cancel = body.cancel().catch(() => {});
95
+ if (!signal) {
96
+ await Promise.race([cancel, new Promise<void>(resolve => setTimeout(resolve, timeoutMs))]);
97
+ return;
98
+ }
99
+ await new Promise<void>(resolve => {
100
+ let timer: ReturnType<typeof setTimeout>;
101
+ /**
102
+ * Abort hook: clear the bounded-body release timer and settle the promise so a
103
+ * never-settling cancel() can never block the abort-aware backoff.
104
+ */
105
+ const onAbort = () => {
106
+ clearTimeout(timer);
107
+ resolve();
108
+ };
109
+ timer = setTimeout(() => {
110
+ signal.removeEventListener("abort", onAbort);
111
+ resolve();
112
+ }, timeoutMs);
113
+ signal.addEventListener("abort", onAbort, { once: true });
114
+ void cancel.then(() => {
115
+ clearTimeout(timer);
116
+ signal.removeEventListener("abort", onAbort);
117
+ resolve();
118
+ });
119
+ });
120
+ }
121
+
122
+ /**
123
+ * Abort-aware sleep that yields an adapter `heartbeat` at least every `heartbeatIntervalMs`.
124
+ * The Responses bridge treats a returned iterator event as upstream liveness and aborts turns
125
+ * that stay silent past the stall budget (default 300s), while a retryOn429 wait may legally
126
+ * reach 600s — so deliberate waits must keep the watchdog fed or a long backoff is killed
127
+ * mid-turn. The final chunk always yields once, which doubles as the post-wait liveness beat.
128
+ */
129
+ export async function* sleepWithHeartbeats(
130
+ ms: number,
131
+ signal?: AbortSignal,
132
+ heartbeatIntervalMs = 10_000,
133
+ ): AsyncGenerator<{ type: "heartbeat" }> {
134
+ if (ms <= 0) return;
135
+ // Guard against a non-positive interval: a zero/negative step would spin the loop forever
136
+ // while sleepWithAbort early-returns without ever observing the abort signal. NaN must be
137
+ // normalized too: Math.max(1, NaN) is NaN, which would abort the wait after one beat.
138
+ const stepMs = Number.isNaN(heartbeatIntervalMs) ? 1 : Math.max(1, heartbeatIntervalMs);
139
+ let remaining = ms;
140
+ while (remaining > 0) {
141
+ const chunk = Math.min(remaining, stepMs);
142
+ await sleepWithAbort(chunk, signal);
143
+ remaining -= chunk;
144
+ yield { type: "heartbeat" };
145
+ }
146
+ }
147
+
148
+ export interface SameTarget429WaitOptions {
149
+ body: ReadableStream<Uint8Array> | null;
150
+ signal?: AbortSignal;
151
+ delayMs: number;
152
+ /**
153
+ * When set, the wait yields adapter heartbeats so bridge stall watchdogs stay fed.
154
+ * Omit for pre-stream recovery paths that have no stall watchdog.
155
+ */
156
+ heartbeatIntervalMs?: number;
157
+ }
158
+
159
+ /**
160
+ * Shared pre-replay prep for opt-in same-target 429 waits:
161
+ * release the unread 429 body, then sleep (optionally with heartbeats).
162
+ * Callers still own attempt budgeting, abort re-checks, and the replay itself.
163
+ */
164
+ export async function* prepareSameTarget429Wait(
165
+ options: SameTarget429WaitOptions,
166
+ ): AsyncGenerator<{ type: "heartbeat" }> {
167
+ await releaseResponseBodyBestEffort(options.body, options.signal);
168
+ if (options.heartbeatIntervalMs === undefined) {
169
+ await sleepWithAbort(options.delayMs, options.signal);
170
+ return;
171
+ }
172
+ yield* sleepWithHeartbeats(options.delayMs, options.signal, options.heartbeatIntervalMs);
173
+ }
174
+
175
+ export function isConnectionResetError(err: unknown): boolean {
176
+ if (!(err instanceof Error)) return false;
177
+ // Aborts and timeouts are caller decisions / honest failures — never retryable.
178
+ if (err.name === "AbortError" || err.name === "TimeoutError") return false;
179
+ const code = (err as { code?: unknown }).code;
180
+ if (code === "ECONNRESET" || code === "EPIPE") return true;
181
+ const msg = err.message.toLowerCase();
182
+ return msg.includes("socket connection was closed unexpectedly")
183
+ || msg.includes("connection reset by peer");
184
+ }
185
+
186
+ function retryAfterDelayMs(headers: Headers): number | undefined {
187
+ const raw = headers.get("retry-after")?.trim();
188
+ if (!raw) return undefined;
189
+ const seconds = Number(raw);
190
+ if (Number.isFinite(seconds)) return Math.max(0, seconds * 1000);
191
+ const dateMs = Date.parse(raw);
192
+ if (!Number.isFinite(dateMs)) return undefined;
193
+ return Math.max(0, dateMs - Date.now());
194
+ }
195
+
196
+ export function retryBackoffDelayMs(attempt: number, opts: RetryBackoffOptions): number {
197
+ const retryAfter = opts.headers ? retryAfterDelayMs(opts.headers) : undefined;
198
+ if (retryAfter !== undefined) return Math.min(retryAfter, opts.maxDelayMs);
199
+ const exp = Math.min(opts.baseDelayMs * (2 ** attempt), opts.maxDelayMs);
200
+ return Math.floor(exp * (0.8 + Math.random() * 0.4));
201
+ }
202
+
203
+ export function cancelResponseBodyBestEffort(res: Response): void {
204
+ try {
205
+ const cancellation = res.body?.cancel();
206
+ if (cancellation) void cancellation.catch(() => {});
207
+ } catch {
208
+ // Cancellation is cleanup only; retries must not wait for or fail because of it.
209
+ }
210
+ }
211
+
212
+ export async function fetchWithAttemptDeadline(
213
+ url: string,
214
+ init: RequestInit,
215
+ timeoutMs: number,
216
+ abortSignal?: AbortSignal,
217
+ preferIdentityEncoding = false,
218
+ executor: typeof globalThis.fetch = globalThis.fetch,
219
+ ): Promise<Response> {
220
+ const attemptTimeout = clearableDeadline(timeoutMs, abortSignal);
221
+ const headers = new Headers(init.headers);
222
+ if (preferIdentityEncoding && !headers.has("accept-encoding")) {
223
+ headers.set("accept-encoding", "identity");
224
+ }
225
+ try {
226
+ return await executor(url, {
227
+ ...init,
228
+ headers,
229
+ signal: attemptTimeout.signal,
230
+ });
231
+ } finally {
232
+ // Only the header timer is cleared. The composed signal still contains the parent, so a
233
+ // caller abort after headers continue to cancel consumption of the returned response body.
234
+ attemptTimeout.clear();
235
+ }
236
+ }
237
+
238
+ export interface ResetRetryOptions {
239
+ abortSignal?: AbortSignal;
240
+ /** Short host/path label for the retry warn log (no secrets/query strings). */
241
+ label?: string;
242
+ attempts?: number;
243
+ }
244
+
245
+ export interface TransientRetryOptions extends ResetRetryOptions {
246
+ /** Test seam: per-attempt slow budget override (defaults to TRANSIENT_RETRY_SLOW_ATTEMPT_MS). */
247
+ slowAttemptMs?: number;
248
+ }
249
+
250
+ export type UpstreamSendRecovery = "connection-reset" | "transient-5xx";
251
+ type ReplayableFetch = (recovery?: UpstreamSendRecovery) => Promise<Response>;
252
+
253
+ /**
254
+ * Rejection thrown by the upstream retry helpers when the terminal attempt
255
+ * rejects after earlier attempts already produced credential-visible evidence:
256
+ * transient 5xx responses, or a connection reset after the request was read.
257
+ *
258
+ * That evidence proves the host and credential path were reached, so the
259
+ * failure must stay account-attributed even though the terminal promise looks
260
+ * like a transport rejection (issue #914 review: mixed 5xx/reset -> rejection
261
+ * must not be downgraded to the account-neutral pre-connection class). The
262
+ * original rejection is preserved as `cause` so its code and message stay
263
+ * inspectable. Extracted from PR #966 (Yuxin-Qiao) with attribution.
264
+ */
265
+ export class UpstreamRetryEvidenceError extends Error {
266
+ constructor(
267
+ public readonly transientStatuses: readonly number[],
268
+ cause: unknown,
269
+ /** True when a connection-reset retry already reached the origin. */
270
+ public readonly resetSeen = false,
271
+ ) {
272
+ const detail = cause instanceof Error ? cause.message : String(cause);
273
+ const kinds: string[] = [];
274
+ if (transientStatuses.length > 0) kinds.push("transient 5xx response(s)");
275
+ if (resetSeen) kinds.push("a credential-visible connection reset");
276
+ super(
277
+ kinds.length > 0
278
+ ? `upstream fetch failed after ${kinds.join(" and ")}: ${detail}`
279
+ : `upstream fetch failed: ${detail}`,
280
+ { cause },
281
+ );
282
+ this.name = "UpstreamRetryEvidenceError";
283
+ }
284
+ }
285
+
286
+ /**
287
+ * Opt out of Bun's keep-alive pool after a connection-reset retry.
288
+ *
289
+ * Prefer the Bun fetch extension `keepalive: false` (transport-level) over
290
+ * relying on the hop-by-hop `Connection: close` header alone — Bun has ignored
291
+ * that header in past releases (oven-sh/bun#20492), so a header-only retry can
292
+ * still reuse the same half-closed pooled socket. Still set Connection: close
293
+ * as a belt-and-suspenders signal for intermediaries that honor it.
294
+ */
295
+ export function applyUpstreamRecoveryInit<T extends RequestInit>(
296
+ init: T,
297
+ recovery?: UpstreamSendRecovery,
298
+ ): T & { headers: Headers } {
299
+ const headers = new Headers(init.headers);
300
+ if (recovery !== "connection-reset") {
301
+ return { ...init, headers };
302
+ }
303
+ headers.set("connection", "close");
304
+ return { ...init, headers, keepalive: false };
305
+ }
306
+
307
+ /**
308
+ * Run `doFetch`, retrying only connection-reset-shaped rejections (see
309
+ * isConnectionResetError) with jittered backoff. The caller's thunk must be replay-safe
310
+ * (string body); every retry is logged so persistent resets stay visible.
311
+ */
312
+ export async function fetchWithResetRetry(
313
+ doFetch: ReplayableFetch,
314
+ opts: ResetRetryOptions = {},
315
+ firstRecovery?: UpstreamSendRecovery,
316
+ ): Promise<Response> {
317
+ const attempts = Math.max(1, opts.attempts ?? RESET_RETRY_MAX_ATTEMPTS);
318
+ let lastError: unknown;
319
+ let sawReset = false;
320
+ for (let attempt = 0; attempt < attempts; attempt++) {
321
+ if (opts.abortSignal?.aborted) throw abortError(opts.abortSignal);
322
+ try {
323
+ return await doFetch(attempt === 0 ? firstRecovery : "connection-reset");
324
+ } catch (err) {
325
+ if (opts.abortSignal?.aborted) throw err;
326
+ if (!isConnectionResetError(err)) {
327
+ // A reset that already reached the origin is credential-visible
328
+ // evidence: keep it attached so the terminal rejection cannot be
329
+ // downgraded to the pre-connection neutral class (#914 review).
330
+ if (sawReset) throw new UpstreamRetryEvidenceError([], err, true);
331
+ throw err;
332
+ }
333
+ if (attempt === attempts - 1) throw err;
334
+ sawReset = true;
335
+ lastError = err;
336
+ console.warn(
337
+ `[upstream-retry] connection reset${opts.label ? ` (${opts.label})` : ""} — retrying (${attempt + 2}/${attempts})`,
338
+ );
339
+ await sleepWithAbort(retryBackoffDelayMs(attempt, {
340
+ baseDelayMs: RESET_RETRY_BASE_DELAY_MS,
341
+ maxDelayMs: RESET_RETRY_MAX_DELAY_MS,
342
+ }), opts.abortSignal);
343
+ }
344
+ }
345
+ throw lastError ?? new Error("upstream fetch failed");
346
+ }
347
+
348
+ /**
349
+ * fetchWithResetRetry plus a transient-5xx status retry layer, PRE-STREAM only: a
350
+ * returned Response has by definition not been relayed to the client yet, so replaying
351
+ * the (string-body) request is safe. The failed attempt's body is cancelled before the
352
+ * retry; every returned response (ok, non-transient, aborted, slow, exhausted) keeps
353
+ * its body intact. Honors Retry-After via retryBackoffDelayMs.
354
+ *
355
+ * A failed attempt slower than the slow budget is returned as-is (slow-502 shape);
356
+ * note `opts.attempts` is shared with the inner reset layer (no caller passes it today).
357
+ */
358
+ export async function fetchWithTransientRetry(
359
+ doFetch: ReplayableFetch,
360
+ opts: TransientRetryOptions = {},
361
+ ): Promise<Response> {
362
+ const attempts = Math.max(1, opts.attempts ?? TRANSIENT_RETRY_MAX_ATTEMPTS);
363
+ const slowAttemptMs = opts.slowAttemptMs ?? TRANSIENT_RETRY_SLOW_ATTEMPT_MS;
364
+ const transientStatuses: number[] = [];
365
+ let attemptStart = Date.now();
366
+ let res = await fetchWithResetRetry(doFetch, opts);
367
+ for (let attempt = 0; attempt < attempts - 1; attempt++) {
368
+ if (res.ok || !isTransientUpstreamStatus(res.status)) return res;
369
+ if (opts.abortSignal?.aborted) return res;
370
+ if (Date.now() - attemptStart > slowAttemptMs) return res;
371
+ console.warn(
372
+ `[upstream-retry] transient ${res.status}${opts.label ? ` (${opts.label})` : ""} — retrying (${attempt + 2}/${attempts})`,
373
+ );
374
+ const delay = retryBackoffDelayMs(attempt, {
375
+ baseDelayMs: TRANSIENT_RETRY_BASE_DELAY_MS,
376
+ maxDelayMs: TRANSIENT_RETRY_MAX_DELAY_MS,
377
+ headers: res.headers,
378
+ });
379
+ cancelResponseBodyBestEffort(res);
380
+ await sleepWithAbort(delay, opts.abortSignal);
381
+ attemptStart = Date.now();
382
+ transientStatuses.push(res.status);
383
+ try {
384
+ res = await fetchWithResetRetry(doFetch, opts, "transient-5xx");
385
+ } catch (err) {
386
+ // Keep the prior 5xx evidence attached: the origin already responded, so
387
+ // this rejection is not pre-connection and must not classify as neutral.
388
+ throw new UpstreamRetryEvidenceError(transientStatuses, err);
389
+ }
390
+ }
391
+ return res;
392
+ }
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Cross-platform command launching (devlog 260715_cross_platform_audit/020).
3
+ *
4
+ * Windows npm installs expose CLIs as `.cmd` shims, and Node/Bun refuse shell-less
5
+ * `.cmd` spawns (CVE-2024-27980 hardening). Bare names like `spawn("claude")` also
6
+ * skip PATHEXT resolution entirely, so they ENOENT even when `claude.cmd` is on PATH.
7
+ * This module mirrors the battle-tested cross-spawn approach: resolve the real target
8
+ * via PATH×PATHEXT, launch `.exe` targets directly (argument boundaries preserved by
9
+ * the normal shell-less spawn), and route `.cmd`/`.bat` targets through
10
+ * `cmd.exe /d /s /c "<escaped line>"` with `windowsVerbatimArguments: true`.
11
+ */
12
+ import { existsSync } from "node:fs";
13
+ import { win32 } from "node:path";
14
+
15
+ const CMD_META = /([()\][%!^"`<>&|;, *?])/g;
16
+ /** cross-spawn parse.js: only npm local-bin shims get double escaping. */
17
+ const IS_CMD_SHIM = /node_modules[\\/].bin[\\/][^\\/]+\.cmd$/i;
18
+
19
+ /** cross-spawn escape.js argument(): quote + escape one argument for cmd.exe /d /s /c. */
20
+ export function escapeCmdArg(arg: string, doubleEscape = false): string {
21
+ let out = String(arg).replace(/(\\*)"/g, '$1$1\\"').replace(/(\\*)$/, "$1$1");
22
+ out = `"${out}"`.replace(CMD_META, "^$1");
23
+ return doubleEscape ? out.replace(CMD_META, "^$1") : out;
24
+ }
25
+
26
+ /** cross-spawn escape.js command(): escape the command token itself (no quoting). */
27
+ export function escapeCmdCommand(command: string): string {
28
+ return command.replace(CMD_META, "^$1");
29
+ }
30
+
31
+ export interface ResolveDeps {
32
+ env?: Record<string, string | undefined>;
33
+ exists?: (path: string) => boolean;
34
+ }
35
+
36
+ /**
37
+ * Resolve a bare command name to its first PATH×PATHEXT hit (win32 semantics).
38
+ * Commands that already carry an extension, a separator, or an absolute prefix are
39
+ * returned unchanged; unresolvable names fall back unchanged (spawn will surface it).
40
+ */
41
+ export function resolveWindowsCommand(command: string, deps: ResolveDeps = {}): string {
42
+ const env = deps.env ?? process.env;
43
+ const exists = deps.exists ?? existsSync;
44
+ if (win32.extname(command) || command.includes("\\") || command.includes("/") || win32.isAbsolute(command)) {
45
+ return command;
46
+ }
47
+ // Windows environment variables are case-insensitive, and a spawned child can
48
+ // arrive with `Path`, `PATH`, or both depending on who built its env. Reading
49
+ // only two fixed spellings silently resolved against the wrong list once a
50
+ // caller added a second casing, so match however the key is spelled.
51
+ const lookup = (name: string): string | undefined => {
52
+ const direct = env[name] ?? env[name.toUpperCase()] ?? env[name.toLowerCase()];
53
+ if (direct !== undefined) return direct;
54
+ const key = Object.keys(env).find(k => k.toLowerCase() === name.toLowerCase());
55
+ return key ? env[key] : undefined;
56
+ };
57
+ const exts = (lookup("PATHEXT") ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean);
58
+ for (const dir of (lookup("PATH") ?? "").split(win32.delimiter).filter(Boolean)) {
59
+ for (const ext of exts) {
60
+ const candidate = win32.join(dir, command + ext.toLowerCase());
61
+ if (exists(candidate)) return candidate;
62
+ }
63
+ }
64
+ return command;
65
+ }
66
+
67
+ export interface SpawnInvocation {
68
+ file: string;
69
+ args: string[];
70
+ options: { windowsVerbatimArguments?: boolean };
71
+ }
72
+
73
+ /**
74
+ * Platform-safe invocation preserving argument boundaries (cross-spawn parse.js).
75
+ * POSIX: passthrough. win32 `.exe`: resolved direct spawn. win32 `.cmd`/`.bat`:
76
+ * `ComSpec /d /s /c "<escaped command line>"` with verbatim args; npm local-bin
77
+ * shims get cross-spawn's double escaping, all other batch targets single.
78
+ */
79
+ export function commandInvocation(
80
+ command: string,
81
+ args: readonly string[],
82
+ platform: NodeJS.Platform = process.platform,
83
+ deps: ResolveDeps = {},
84
+ ): SpawnInvocation {
85
+ if (platform !== "win32") return { file: command, args: [...args], options: {} };
86
+ const resolved = resolveWindowsCommand(command, deps);
87
+ if (!/\.(cmd|bat)$/i.test(resolved)) return { file: resolved, args: [...args], options: {} };
88
+ const env = deps.env ?? process.env;
89
+ const doubleEscape = IS_CMD_SHIM.test(resolved);
90
+ const line = [escapeCmdCommand(resolved), ...args.map(a => escapeCmdArg(a, doubleEscape))].join(" ");
91
+ return {
92
+ file: env.ComSpec ?? "cmd.exe",
93
+ args: ["/d", "/s", "/c", `"${line}"`],
94
+ options: { windowsVerbatimArguments: true },
95
+ };
96
+ }
97
+
98
+ /**
99
+ * `sh -c <command>` analog per platform. The configured command string is passed
100
+ * VERBATIM in content; on win32 it gets the outer quotes `/s` requires, so
101
+ * `"C:\Program Files\x.exe" --json` runs as `cmd.exe /d /s /c ""C:\Program Files\x.exe" --json"`.
102
+ * Contract: the command is platform-native shell syntax (sh on POSIX, CMD on Windows).
103
+ */
104
+ export function shellInvocation(
105
+ command: string,
106
+ platform: NodeJS.Platform = process.platform,
107
+ env: Record<string, string | undefined> = process.env,
108
+ ): SpawnInvocation {
109
+ if (platform !== "win32") return { file: "sh", args: ["-c", command], options: {} };
110
+ return {
111
+ file: env.ComSpec ?? "cmd.exe",
112
+ args: ["/d", "/s", "/c", `"${command}"`],
113
+ options: { windowsVerbatimArguments: true },
114
+ };
115
+ }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Windows path → batch-safe env indirection.
3
+ *
4
+ * cmd.exe parses .cmd files in the console's OEM codepage (CP949/GBK/CP437…), NOT UTF-8.
5
+ * Any absolute path we bake into a generated batch file breaks for users whose profile
6
+ * directory contains non-ASCII characters (e.g. Korean/Chinese usernames), because the
7
+ * UTF-8 bytes we wrote are decoded as mojibake at parse time. Instead of baking the
8
+ * profile prefix literally, rewrite it as a `%USERPROFILE%`-style token: cmd expands the
9
+ * variable natively at parse time in the correct codepage, so the non-ASCII prefix never
10
+ * has to survive a file-encoding round trip.
11
+ */
12
+
13
+ export type WindowsEnvMap = Record<string, string | undefined>;
14
+
15
+ /** Ordered by specificity; longest resolved prefix wins regardless of this order. */
16
+ const INDIRECTION_VARS = ["LOCALAPPDATA", "APPDATA", "USERPROFILE"] as const;
17
+
18
+ /** True when `prefix` matches a leading whole-component span of `path` (case-insensitive). */
19
+ function isComponentPrefix(path: string, prefix: string): boolean {
20
+ if (path.length < prefix.length) return false;
21
+ if (path.slice(0, prefix.length).toLowerCase() !== prefix.toLowerCase()) return false;
22
+ if (path.length === prefix.length) return true;
23
+ const next = path[prefix.length];
24
+ return next === "\\" || next === "/";
25
+ }
26
+
27
+ /**
28
+ * Split a Windows path into an env-token prefix and the remaining literal suffix.
29
+ * Returns `token: ""` (and the full path as `rest`) when no known prefix applies.
30
+ */
31
+ export function splitWindowsEnvPrefix(path: string, env: WindowsEnvMap = process.env): { token: string; rest: string } {
32
+ let best: { name: string; value: string } | null = null;
33
+ for (const name of INDIRECTION_VARS) {
34
+ const raw = env[name]?.trim();
35
+ if (!raw) continue;
36
+ const value = raw.replace(/[\\/]+$/, "");
37
+ if (!value || !isComponentPrefix(path, value)) continue;
38
+ if (!best || value.length > best.value.length) best = { name, value };
39
+ }
40
+ if (!best) return { token: "", rest: path };
41
+ return { token: `%${best.name}%`, rest: path.slice(best.value.length) };
42
+ }
43
+
44
+ /**
45
+ * Render a single path for embedding in a batch `set "X=…"` line: env-token prefix kept
46
+ * verbatim (cmd must expand it), remaining literal suffix run through the caller's batch
47
+ * escaping (which doubles `%` and would otherwise destroy the token itself).
48
+ */
49
+ export function windowsEnvIndirectBatchValue(
50
+ path: string,
51
+ escape: (value: string) => string,
52
+ env: WindowsEnvMap = process.env,
53
+ ): string {
54
+ const { token, rest } = splitWindowsEnvPrefix(path, env);
55
+ return token + escape(rest);
56
+ }
57
+
58
+ /** Same as {@link windowsEnvIndirectBatchValue} for `;`-separated path lists (PATH). */
59
+ export function windowsEnvIndirectBatchPathList(
60
+ value: string,
61
+ escape: (value: string) => string,
62
+ env: WindowsEnvMap = process.env,
63
+ ): string {
64
+ return value
65
+ .split(";")
66
+ .map(part => (part ? windowsEnvIndirectBatchValue(part, escape, env) : part))
67
+ .join(";");
68
+ }