@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,263 @@
1
+ import { spawn } from "node:child_process";
2
+ import { existsSync, readFileSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { createInterface } from "node:readline/promises";
5
+ import { atomicWriteFile, getConfigDir } from "../config";
6
+ import { hasStarPromptRun } from "../cli/star-prompt";
7
+ import { selfLaunchArgv } from "../lib/self-launch-argv";
8
+ import {
9
+ type Channel,
10
+ currentVersion,
11
+ detectInstall,
12
+ latestVersion,
13
+ runUpdate,
14
+ updateCommandStr,
15
+ updateTag,
16
+ } from "./index";
17
+
18
+ const VERSION_FILENAME = "version.json";
19
+ const REFRESH_INTERVAL_MS = 20 * 60 * 60 * 1000; // 20h, matching codex-rs
20
+ const RELEASE_NOTES_URL = "https://github.com/lidge-jun/opencodex/releases/latest";
21
+
22
+ export interface VersionCache {
23
+ latest_version: string;
24
+ /** ISO-8601 (RFC3339) timestamp of the last successful registry check. */
25
+ last_checked_at: string;
26
+ dismissed_version?: string;
27
+ tag: Channel;
28
+ }
29
+
30
+ function versionFilePath(): string {
31
+ return join(getConfigDir(), VERSION_FILENAME);
32
+ }
33
+
34
+ /**
35
+ * Read the cached version info. Returns null on any error or when the cached
36
+ * channel differs from the current one (so a stable<->preview switch re-fetches
37
+ * instead of comparing across channels).
38
+ */
39
+ export function readVersionCache(channel: Channel): VersionCache | null {
40
+ try {
41
+ const raw = readFileSync(versionFilePath(), "utf8");
42
+ const parsed = JSON.parse(raw) as Partial<VersionCache>;
43
+ if (typeof parsed.latest_version !== "string" || typeof parsed.last_checked_at !== "string") return null;
44
+ if (parsed.tag !== channel) return null;
45
+ return {
46
+ latest_version: parsed.latest_version,
47
+ last_checked_at: parsed.last_checked_at,
48
+ dismissed_version: typeof parsed.dismissed_version === "string" ? parsed.dismissed_version : undefined,
49
+ tag: parsed.tag,
50
+ };
51
+ } catch {
52
+ return null;
53
+ }
54
+ }
55
+
56
+ export function writeVersionCache(cache: VersionCache): void {
57
+ try {
58
+ atomicWriteFile(versionFilePath(), `${JSON.stringify(cache)}\n`);
59
+ } catch {
60
+ /* best-effort; never block startup */
61
+ }
62
+ }
63
+
64
+ function parseStable(v: string): [number, number, number] | null {
65
+ const m = /^(\d+)\.(\d+)\.(\d+)$/.exec(v.trim());
66
+ if (!m) return null;
67
+ return [Number(m[1]), Number(m[2]), Number(m[3])];
68
+ }
69
+
70
+ function parsePreview(v: string): [number, number, number, number] | null {
71
+ const m = /^(\d+)\.(\d+)\.(\d+)-preview\.(\d+)$/.exec(v.trim());
72
+ if (!m) return null;
73
+ return [Number(m[1]), Number(m[2]), Number(m[3]), Number(m[4])];
74
+ }
75
+
76
+ function gt(a: number[], b: number[]): boolean {
77
+ for (let i = 0; i < Math.max(a.length, b.length); i++) {
78
+ const av = a[i] ?? 0;
79
+ const bv = b[i] ?? 0;
80
+ if (av !== bv) return av > bv;
81
+ }
82
+ return false;
83
+ }
84
+
85
+ /**
86
+ * Channel-aware "is latest newer than current?".
87
+ * - latest channel: compare maj.min.pat only; prerelease TARGETS are never
88
+ * "newer" (parity with codex-rs), so stable users are not pushed onto
89
+ * previews. An installed preview CURRENT compares by its maj.min.pat core,
90
+ * so a stable release with a strictly higher base is offered (same base is
91
+ * content-lateral promotion and stays not-newer, mirroring the preview
92
+ * channel's O3 rule).
93
+ * - preview channel: preview-vs-preview compares the trailing -preview.N; a
94
+ * stable release with a strictly higher base counts as newer (O3), while a
95
+ * stable release with the same base as the current preview does not.
96
+ */
97
+ export function isNewer(latest: string, current: string, channel: Channel): boolean {
98
+ if (channel === "latest") {
99
+ const l = parseStable(latest);
100
+ const c = parseStable(current) ?? parsePreview(current)?.slice(0, 3);
101
+ if (!l || !c) return false;
102
+ return gt(l, c);
103
+ }
104
+ // preview channel
105
+ const lPre = parsePreview(latest);
106
+ const cPre = parsePreview(current);
107
+ if (lPre && cPre) return gt(lPre, cPre);
108
+
109
+ const lStable = parseStable(latest);
110
+ if (lStable && cPre) {
111
+ // Stable release vs current preview: newer only if the base is strictly
112
+ // higher than the preview's base (equal base would be a downgrade nag).
113
+ return gt(lStable, [cPre[0], cPre[1], cPre[2]]);
114
+ }
115
+ const cStable = parseStable(current);
116
+ if (lStable && cStable) return gt(lStable, cStable);
117
+ return false;
118
+ }
119
+
120
+ export function isSourceBuildVersion(v: string): boolean {
121
+ return v.trim() === "0.0.0";
122
+ }
123
+
124
+ /** The interactive/TTY + install-method gate shared with the star prompt. */
125
+ function interactiveGuardOk(): boolean {
126
+ return !(process.env.OCX_SERVICE || !process.stdin.isTTY || !process.stdout.isTTY);
127
+ }
128
+
129
+ /**
130
+ * Decide whether this run should even consider showing the prompt. Returns the
131
+ * channel + current version when eligible, else null. Eligibility requires a
132
+ * real global install, a non-source version, the interactive guard, and that
133
+ * the one-time star prompt has already run (first-run yield, O1).
134
+ */
135
+ export function shouldConsider(): { channel: Channel; current: string } | null {
136
+ if (detectInstall() === "source") return null;
137
+ const current = currentVersion();
138
+ if (current === "?" || isSourceBuildVersion(current)) return null;
139
+ if (!interactiveGuardOk()) return null;
140
+ if (!hasStarPromptRun()) return null; // yield on the very first run
141
+ return { channel: updateTag(current), current };
142
+ }
143
+
144
+ /** The cached upgrade version to surface, honoring the user's dismissal. */
145
+ export function getUpgradeVersionForPopup(
146
+ cache: VersionCache | null,
147
+ current: string,
148
+ channel: Channel,
149
+ ): string | null {
150
+ if (!cache) return null;
151
+ if (!isNewer(cache.latest_version, current, channel)) return null;
152
+ if (cache.dismissed_version === cache.latest_version) return null;
153
+ return cache.latest_version;
154
+ }
155
+
156
+ function cacheIsStale(cache: VersionCache | null): boolean {
157
+ if (!cache) return true;
158
+ const checked = Date.parse(cache.last_checked_at);
159
+ if (!Number.isFinite(checked)) return true;
160
+ return Date.now() - checked > REFRESH_INTERVAL_MS;
161
+ }
162
+
163
+ /**
164
+ * If the cache is missing or older than 20h, kick off a detached helper to
165
+ * refresh it without blocking this (soon-to-be daemon) process. Fire-and-forget.
166
+ */
167
+ export function triggerBackgroundRefreshIfStale(channel: Channel, cache: VersionCache | null): void {
168
+ if (!cacheIsStale(cache)) return;
169
+ try {
170
+ const commandArgs = ["__refresh-version", channel];
171
+ const args = selfLaunchArgv(commandArgs);
172
+ if (args.length > commandArgs.length && (!args[0] || !existsSync(args[0]))) return;
173
+ const child = spawn(process.execPath, args, {
174
+ detached: true,
175
+ stdio: "ignore",
176
+ windowsHide: true,
177
+ env: { ...process.env, OCX_SERVICE: "1" }, // never let the helper prompt
178
+ });
179
+ child.unref();
180
+ } catch {
181
+ /* best-effort */
182
+ }
183
+ }
184
+
185
+ /**
186
+ * Body of the hidden `__refresh-version` subcommand: fetch the latest version
187
+ * for the channel and persist it. Only advances `last_checked_at` on success so
188
+ * a failed fetch retries on the next start.
189
+ */
190
+ export async function refreshVersionCache(channel: Channel): Promise<void> {
191
+ const latest = latestVersion(channel);
192
+ if (!latest) return; // do not dirty the cache or advance the timestamp
193
+ const prev = readVersionCache(channel);
194
+ writeVersionCache({
195
+ latest_version: latest,
196
+ last_checked_at: new Date().toISOString(),
197
+ dismissed_version: prev?.dismissed_version,
198
+ tag: channel,
199
+ });
200
+ }
201
+
202
+ /** Persist a dismissal so this exact version stops prompting. */
203
+ function dismissVersion(channel: Channel, version: string): void {
204
+ const cache = readVersionCache(channel);
205
+ if (!cache) return;
206
+ writeVersionCache({ ...cache, dismissed_version: version });
207
+ }
208
+
209
+ function renderPrompt(current: string, latest: string, channel: Channel): string {
210
+ const command = updateCommandStr(detectInstall(), channel);
211
+ return [
212
+ "",
213
+ ` \x1b[38;5;141m✨ Update available!\x1b[0m \x1b[2m${current} -> ${latest}\x1b[0m`,
214
+ "",
215
+ ` \x1b[2mRelease notes:\x1b[0m ${RELEASE_NOTES_URL}`,
216
+ "",
217
+ ` 1) Update now (runs \`${command}\`)`,
218
+ " 2) Skip",
219
+ " 3) Skip until next version",
220
+ "",
221
+ " [1/2/3] (default 1): ",
222
+ ].join("\n");
223
+ }
224
+
225
+ /**
226
+ * Interactive-only update prompt for `ocx start`. Must be called BEFORE the
227
+ * server binds a port / writes a PID, because "Update now" installs globally
228
+ * and exits. No-op for service/daemon/non-TTY runs and source checkouts.
229
+ * Never throws.
230
+ */
231
+ export async function maybeShowUpdatePrompt(): Promise<void> {
232
+ try {
233
+ const eligible = shouldConsider();
234
+ if (!eligible) return;
235
+ const { channel, current } = eligible;
236
+
237
+ const cache = readVersionCache(channel);
238
+ triggerBackgroundRefreshIfStale(channel, cache);
239
+
240
+ const latest = getUpgradeVersionForPopup(cache, current, channel);
241
+ if (!latest) return;
242
+
243
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
244
+ let answer = "";
245
+ try {
246
+ answer = (await rl.question(renderPrompt(current, latest, channel))).trim();
247
+ } finally {
248
+ rl.close();
249
+ }
250
+
251
+ const choice = answer === "" ? "1" : answer;
252
+ if (choice === "1") {
253
+ await runUpdate();
254
+ console.log("\nRestart the proxy: ocx start");
255
+ process.exit(0);
256
+ } else if (choice === "3") {
257
+ dismissVersion(channel, latest);
258
+ }
259
+ // "2" (or anything else) -> Skip: continue this run unchanged.
260
+ } catch {
261
+ /* never let the update prompt disrupt startup */
262
+ }
263
+ }
@@ -0,0 +1,47 @@
1
+ import type { spawnSync } from "node:child_process";
2
+
3
+ export type NpmCachePreflightReason =
4
+ | "cache_accessible"
5
+ | "cache_entry_foreign_owner"
6
+ | "cache_entry_inaccessible"
7
+ | "cache_path_malformed"
8
+ | "inspection_incomplete"
9
+ | "npm_config_failed"
10
+ | "npm_unavailable"
11
+ | "windows_skip"
12
+ | "worker_failed"
13
+ | "worker_output_malformed"
14
+ | "worker_timeout";
15
+
16
+ export interface NpmCachePreflightResult {
17
+ ok: boolean;
18
+ reason: NpmCachePreflightReason;
19
+ }
20
+
21
+ export interface NpmCacheInspectionOptions {
22
+ expectedUid?: number;
23
+ maxDepth?: number;
24
+ maxEntries?: number;
25
+ nowMs?: () => number;
26
+ /** Test seam: resolve a symlinked cache root. Defaults to realpathSync. */
27
+ realpathFn?: (path: string) => string;
28
+ /** Test seam: resolve an entry's owner uid. Defaults to the lstat result. */
29
+ uidOf?: (path: string, stat: { uid: number }) => number;
30
+ timeoutMs?: number;
31
+ }
32
+
33
+ export interface NpmCachePreflightOptions {
34
+ env?: NodeJS.ProcessEnv;
35
+ execPath?: string;
36
+ platform?: NodeJS.Platform;
37
+ spawnSyncFn?: typeof spawnSync;
38
+ timeoutMs?: number;
39
+ }
40
+
41
+ export function inspectNpmCacheDirectory(
42
+ cachePath: string,
43
+ options?: NpmCacheInspectionOptions,
44
+ ): NpmCachePreflightResult;
45
+
46
+ export function runNpmCachePreflight(options?: NpmCachePreflightOptions): NpmCachePreflightResult;
47
+ export function npmCachePreflightFailureMessage(reason: NpmCachePreflightReason): string;
@@ -0,0 +1,201 @@
1
+ import { lstatSync, readdirSync, realpathSync } from "node:fs";
2
+ import { spawnSync } from "node:child_process";
3
+ import { isAbsolute, resolve } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { npmInvocation } from "./npm-invocation.mjs";
6
+
7
+ const WORKER_ARG = "--ocx-npm-cache-preflight-worker";
8
+ const PROTOCOL_VERSION = 1;
9
+ const WORKER_TIMEOUT_MS = 10_000;
10
+ const NPM_CONFIG_TIMEOUT_MS = 5_000;
11
+ const INSPECTION_TIMEOUT_MS = 7_500;
12
+ const MAX_ENTRIES = 100_000;
13
+ const MAX_DEPTH = 64;
14
+
15
+ const RESULT_REASONS = new Set([
16
+ "cache_accessible",
17
+ "cache_entry_foreign_owner",
18
+ "cache_entry_inaccessible",
19
+ "cache_path_malformed",
20
+ "inspection_incomplete",
21
+ "npm_config_failed",
22
+ "npm_unavailable",
23
+ ]);
24
+
25
+ function inaccessibleByMode(stat) {
26
+ if (stat.isSymbolicLink()) return false;
27
+ const ownerBits = stat.mode & 0o700;
28
+ if (stat.isDirectory()) return (ownerBits & 0o700) !== 0o700;
29
+ return (ownerBits & 0o400) === 0;
30
+ }
31
+
32
+ /**
33
+ * Inspect an existing Unix npm cache without following symlinks. The limits are
34
+ * deliberately part of the result contract: an incomplete inspection cannot prove
35
+ * that replacing the live package will succeed.
36
+ */
37
+ export function inspectNpmCacheDirectory(cachePath, options = {}) {
38
+ const expectedUid = options.expectedUid ?? process.getuid?.();
39
+ const deadline = (options.nowMs ?? Date.now)() + (options.timeoutMs ?? INSPECTION_TIMEOUT_MS);
40
+ const maxEntries = options.maxEntries ?? MAX_ENTRIES;
41
+ const maxDepth = options.maxDepth ?? MAX_DEPTH;
42
+ const nowMs = options.nowMs ?? Date.now;
43
+ // Injected uid seam. A test cannot create a genuinely foreign-owned file without a second
44
+ // account, and without this the symlink-before-ownership rule cannot be pinned: `!isDirectory`
45
+ // skips a link anyway, so removing the rule leaves every assertion green.
46
+ const uidOf = options.uidOf ?? ((_path, stat) => stat.uid);
47
+ const stack = [{ path: cachePath, depth: 0 }];
48
+ let inspected = 0;
49
+ let rootResolved = false;
50
+
51
+ while (stack.length > 0) {
52
+ // Budget exhausted is NOT a failure. A mature npm cache legitimately holds hundreds of
53
+ // thousands of entries — this machine's has ~256k — and treating "we ran out of time to
54
+ // look" as "your cache is broken" would block updates for ordinary users, which is worse
55
+ // than the bug this preflight exists to prevent. We looked at a bounded prefix, found
56
+ // nothing wrong, and let the update proceed.
57
+ if (inspected >= maxEntries || nowMs() > deadline) {
58
+ return { ok: true, reason: "inspection_incomplete" };
59
+ }
60
+ const current = stack.pop();
61
+ let stat;
62
+ try {
63
+ stat = lstatSync(current.path);
64
+ } catch (error) {
65
+ if (current.depth === 0 && error?.code === "ENOENT") {
66
+ return { ok: true, reason: "cache_accessible" };
67
+ }
68
+ return { ok: false, reason: "cache_entry_inaccessible" };
69
+ }
70
+ inspected += 1;
71
+
72
+ // A symlinked cache ROOT used to be rejected outright, but pointing ~/.npm at another volume
73
+ // is ordinary npm configuration, and blocking those users would be the same false-positive
74
+ // failure this preflight exists to avoid. Resolve the root once and inspect the target;
75
+ // only an unresolvable root is a real problem. Nested links are still never followed.
76
+ if (current.depth === 0 && stat.isSymbolicLink()) {
77
+ // Resolve exactly once. realpath already collapses a chain, so a second pass would only
78
+ // happen if the target is itself reported as a link — treat that as unresolvable rather
79
+ // than looping.
80
+ if (rootResolved) return { ok: false, reason: "cache_entry_inaccessible" };
81
+ rootResolved = true;
82
+ let resolved;
83
+ try {
84
+ resolved = (options.realpathFn ?? realpathSync)(current.path);
85
+ } catch {
86
+ return { ok: false, reason: "cache_entry_inaccessible" };
87
+ }
88
+ stack.push({ path: resolved, depth: 0 });
89
+ continue;
90
+ }
91
+ // A nested symlink is not. npm creates them constantly below _npx, node_modules and .bin,
92
+ // and we never follow them — so its owner is irrelevant and must not abort the update.
93
+ // This has to come BEFORE the ownership check: a foreign-owned but never-followed link is
94
+ // exactly the false positive that made the previous attempt at this feature unusable.
95
+ if (stat.isSymbolicLink()) continue;
96
+
97
+ if (expectedUid !== undefined && uidOf(current.path, stat) !== expectedUid) {
98
+ return { ok: false, reason: "cache_entry_foreign_owner" };
99
+ }
100
+ if (inaccessibleByMode(stat)) {
101
+ return { ok: false, reason: "cache_entry_inaccessible" };
102
+ }
103
+ if (!stat.isDirectory()) continue;
104
+ // Same reasoning as the entry budget: too deep to finish is not evidence of a bad cache.
105
+ if (current.depth >= maxDepth) return { ok: true, reason: "inspection_incomplete" };
106
+
107
+ let entries;
108
+ try {
109
+ entries = readdirSync(current.path, { withFileTypes: true });
110
+ } catch {
111
+ return { ok: false, reason: "cache_entry_inaccessible" };
112
+ }
113
+ for (const entry of entries) {
114
+ stack.push({ path: resolve(current.path, entry.name), depth: current.depth + 1 });
115
+ }
116
+ }
117
+
118
+ return { ok: true, reason: "cache_accessible" };
119
+ }
120
+
121
+ function workerResult() {
122
+ const invocation = npmInvocation(["config", "get", "cache"]);
123
+ if (!invocation) return { ok: false, reason: "npm_unavailable" };
124
+ const npm = spawnSync(invocation.file, invocation.args, {
125
+ encoding: "utf8",
126
+ timeout: NPM_CONFIG_TIMEOUT_MS,
127
+ windowsHide: true,
128
+ ...invocation.options,
129
+ });
130
+ if (npm.status !== 0) return { ok: false, reason: "npm_config_failed" };
131
+
132
+ const output = typeof npm.stdout === "string" ? npm.stdout.trim() : "";
133
+ if (!output || output.length > 4096 || output.includes("\0") || /[\r\n]/.test(output) || !isAbsolute(output)) {
134
+ return { ok: false, reason: "cache_path_malformed" };
135
+ }
136
+ return inspectNpmCacheDirectory(output);
137
+ }
138
+
139
+ // Reasons that legitimately accompany `ok: true`. The parser below cross-checks the flag against
140
+ // this set so a worker cannot claim success with a failure reason (or the reverse). It is a SET,
141
+ // not a single value: a bounded inspection that ran out of budget without finding a problem is a
142
+ // pass, and hardcoding `cache_accessible` here silently rejected exactly that — the pass never
143
+ // reached the caller and every large cache still failed, as `worker_output_malformed`.
144
+ const OK_REASONS = new Set([
145
+ "cache_accessible",
146
+ "inspection_incomplete",
147
+ "windows_skip",
148
+ ]);
149
+
150
+ function parseWorkerOutput(stdout) {
151
+ if (typeof stdout !== "string" || stdout.length > 1024) return null;
152
+ try {
153
+ const parsed = JSON.parse(stdout);
154
+ if (!parsed || parsed.protocol !== PROTOCOL_VERSION || typeof parsed.ok !== "boolean") return null;
155
+ if (typeof parsed.reason !== "string" || !RESULT_REASONS.has(parsed.reason)) return null;
156
+ if (parsed.ok !== OK_REASONS.has(parsed.reason)) return null;
157
+ if (Object.keys(parsed).sort().join(",") !== "ok,protocol,reason") return null;
158
+ return { ok: parsed.ok, reason: parsed.reason };
159
+ } catch {
160
+ return null;
161
+ }
162
+ }
163
+
164
+ /** Run the bounded cache inspection in an isolated, synchronously-timeboxed worker. */
165
+ export function runNpmCachePreflight(options = {}) {
166
+ if ((options.platform ?? process.platform) === "win32") {
167
+ return { ok: true, reason: "windows_skip" };
168
+ }
169
+ const spawn = options.spawnSyncFn ?? spawnSync;
170
+ const result = spawn(
171
+ options.execPath ?? process.execPath,
172
+ [fileURLToPath(import.meta.url), WORKER_ARG],
173
+ {
174
+ encoding: "utf8",
175
+ timeout: options.timeoutMs ?? WORKER_TIMEOUT_MS,
176
+ windowsHide: true,
177
+ env: options.env ?? process.env,
178
+ },
179
+ );
180
+ if (result.status === null) return { ok: false, reason: "worker_timeout" };
181
+ if (result.status !== 0) return { ok: false, reason: "worker_failed" };
182
+ return parseWorkerOutput(result.stdout) ?? { ok: false, reason: "worker_output_malformed" };
183
+ }
184
+
185
+ /** Fixed operator guidance; worker/npm output is intentionally never interpolated. */
186
+ export function npmCachePreflightFailureMessage(reason) {
187
+ return `npm cache access pre-flight failed (${reason}); fix cache ownership and permissions, then retry`;
188
+ }
189
+
190
+ const isWorker = process.argv[1]
191
+ && resolve(process.argv[1]) === fileURLToPath(import.meta.url)
192
+ && process.argv[2] === WORKER_ARG;
193
+ if (isWorker) {
194
+ let result;
195
+ try {
196
+ result = workerResult();
197
+ } catch {
198
+ result = { ok: false, reason: "cache_entry_inaccessible" };
199
+ }
200
+ process.stdout.write(JSON.stringify({ protocol: PROTOCOL_VERSION, ...result }));
201
+ }
@@ -0,0 +1,23 @@
1
+ export interface NpmInvocationDeps {
2
+ cwd?: string;
3
+ exists?: (path: string) => boolean;
4
+ }
5
+
6
+ export interface NpmInvocation {
7
+ file: string;
8
+ args: string[];
9
+ options: { windowsVerbatimArguments?: boolean };
10
+ }
11
+
12
+ export declare function resolveNpmCommand(
13
+ platform?: NodeJS.Platform,
14
+ env?: Record<string, string | undefined>,
15
+ deps?: NpmInvocationDeps,
16
+ ): string | null;
17
+
18
+ export declare function npmInvocation(
19
+ args: readonly string[],
20
+ platform?: NodeJS.Platform,
21
+ env?: Record<string, string | undefined>,
22
+ deps?: NpmInvocationDeps,
23
+ ): NpmInvocation | null;
@@ -0,0 +1,94 @@
1
+ import { existsSync } from "node:fs";
2
+ import { win32 } from "node:path";
3
+
4
+ const CMD_META = /([()%!^"`<>&|;, *?])/g;
5
+
6
+ function escapeCmdArg(arg) {
7
+ let out = String(arg).replace(/(\\*)"/g, '$1$1\\"').replace(/(\\*)$/, "$1$1");
8
+ return `"${out}"`.replace(CMD_META, "^$1");
9
+ }
10
+
11
+ function escapeCmdCommand(command) {
12
+ return command.replace(CMD_META, "^$1");
13
+ }
14
+
15
+ /**
16
+ * Whether a PATH entry *is* the current directory. The hijack this guards against is
17
+ * cmd.exe resolving a bare `npm` out of the directory opencodex was launched from, so
18
+ * only that exact directory has to be skipped — every candidate we hand to spawn is an
19
+ * absolute path, which is what actually defeats the implicit cwd-first search.
20
+ *
21
+ * Deliberately not a subtree test: npm's default Windows global prefix is
22
+ * `%AppData%\npm` (`C:\Users\x\AppData\Roaming\npm`), so excluding everything under the
23
+ * cwd would fail closed for anyone whose shell sits in their home directory — a normal
24
+ * setup, not the untrusted-project case this hardening is for.
25
+ */
26
+ function isCurrentDirectory(cwd, entry) {
27
+ const left = win32.resolve(entry);
28
+ const right = win32.resolve(cwd);
29
+ return left.toLowerCase() === right.toLowerCase();
30
+ }
31
+
32
+ function cleanPathEntry(entry) {
33
+ const trimmed = entry.trim();
34
+ if (trimmed.startsWith('"') && trimmed.endsWith('"')) return trimmed.slice(1, -1);
35
+ return trimmed;
36
+ }
37
+
38
+ export function resolveNpmCommand(
39
+ platform = process.platform,
40
+ env = process.env,
41
+ deps = {},
42
+ ) {
43
+ if (platform !== "win32") return "npm";
44
+ const exists = deps.exists ?? existsSync;
45
+ const cwd = deps.cwd ?? process.cwd();
46
+ const extensions = (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD")
47
+ .split(";")
48
+ .filter(Boolean);
49
+ const pathEntries = (env.PATH ?? env.Path ?? "")
50
+ .split(win32.delimiter)
51
+ .map(cleanPathEntry)
52
+ .filter(Boolean);
53
+
54
+ for (const entry of pathEntries) {
55
+ if (!win32.isAbsolute(entry)) continue;
56
+ if (isCurrentDirectory(cwd, entry)) continue;
57
+ for (const extension of extensions) {
58
+ const candidate = win32.join(entry, `npm${extension.toLowerCase()}`);
59
+ if (exists(candidate)) return win32.resolve(candidate);
60
+ }
61
+ }
62
+ return null;
63
+ }
64
+
65
+ function systemCommandProcessor(env) {
66
+ const systemRoot = env.SystemRoot ?? env.windir;
67
+ if (systemRoot && win32.isAbsolute(systemRoot)) {
68
+ return win32.join(systemRoot, "System32", "cmd.exe");
69
+ }
70
+ const comSpec = env.ComSpec;
71
+ return comSpec && win32.isAbsolute(comSpec) ? win32.resolve(comSpec) : null;
72
+ }
73
+
74
+ export function npmInvocation(
75
+ args,
76
+ platform = process.platform,
77
+ env = process.env,
78
+ deps = {},
79
+ ) {
80
+ const npm = resolveNpmCommand(platform, env, deps);
81
+ if (!npm) return null;
82
+ if (platform !== "win32" || !/\.(cmd|bat)$/i.test(npm)) {
83
+ return { file: npm, args: [...args], options: {} };
84
+ }
85
+
86
+ const commandProcessor = systemCommandProcessor(env);
87
+ if (!commandProcessor) return null;
88
+ const line = [escapeCmdCommand(npm), ...args.map(escapeCmdArg)].join(" ");
89
+ return {
90
+ file: commandProcessor,
91
+ args: ["/d", "/s", "/c", `"${line}"`],
92
+ options: { windowsVerbatimArguments: true },
93
+ };
94
+ }
@@ -0,0 +1,22 @@
1
+ export type InstallTreeVerification = { ok: boolean; failures: string[] };
2
+ export function verifyInstallTree(packageDir: string, expectedVersion?: string): InstallTreeVerification;
3
+ export function bootRestoreProbe(
4
+ packageDir: string,
5
+ deps?: { rename?: (from: string, to: string) => void },
6
+ ): { action: "none" | "reaped" | "restored" | "failed"; count?: number; from?: string; error?: string };
7
+ export function transactionalNpmUpdate(args: {
8
+ packageDir: string;
9
+ pkgName: string;
10
+ targetVersion?: string;
11
+ tag: string;
12
+ runNpm: (args: string[]) => { status: number | null };
13
+ log?: (line: string) => void;
14
+ deps?: { rename?: (from: string, to: string) => void };
15
+ }): {
16
+ ok: boolean;
17
+ phase: "stage" | "verify" | "swap-backup" | "swap-live" | "post-verify" | "double-fault" | "done";
18
+ error?: string;
19
+ rolledBack?: boolean;
20
+ backup?: string;
21
+ };
22
+