@iislee/opencodex 2.11.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 (476) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +225 -0
  3. package/assets/architecture.png +0 -0
  4. package/assets/banner.png +0 -0
  5. package/assets/claude-code-models.gif +0 -0
  6. package/assets/codex-app-picker.png +0 -0
  7. package/bin/ocx.mjs +451 -0
  8. package/bin/package-main.mjs +9 -0
  9. package/gui/dist/assets/index-DTpMHS4F.js +67 -0
  10. package/gui/dist/assets/index-ZNVDE3C7.css +1 -0
  11. package/gui/dist/favicon.png +0 -0
  12. package/gui/dist/icons.svg +24 -0
  13. package/gui/dist/index.html +25 -0
  14. package/gui/dist/logo.png +0 -0
  15. package/gui/dist/provider-icons/alibaba-color.svg +1 -0
  16. package/gui/dist/provider-icons/antigravity-color.svg +1 -0
  17. package/gui/dist/provider-icons/antigravity.svg +1 -0
  18. package/gui/dist/provider-icons/claude-color.svg +1 -0
  19. package/gui/dist/provider-icons/claude.svg +1 -0
  20. package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -0
  21. package/gui/dist/provider-icons/copilot-color.svg +1 -0
  22. package/gui/dist/provider-icons/copilot.svg +1 -0
  23. package/gui/dist/provider-icons/cursor-color.svg +2 -0
  24. package/gui/dist/provider-icons/cursor.svg +2 -0
  25. package/gui/dist/provider-icons/deepseek-color.svg +1 -0
  26. package/gui/dist/provider-icons/discord.svg +1 -0
  27. package/gui/dist/provider-icons/firepass-color.svg +1 -0
  28. package/gui/dist/provider-icons/fireworks-color.svg +1 -0
  29. package/gui/dist/provider-icons/gemini-color.svg +1 -0
  30. package/gui/dist/provider-icons/gemini.svg +1 -0
  31. package/gui/dist/provider-icons/github-copilot-color.svg +1 -0
  32. package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -0
  33. package/gui/dist/provider-icons/grok-color.svg +1 -0
  34. package/gui/dist/provider-icons/grok.svg +1 -0
  35. package/gui/dist/provider-icons/groq-color.svg +1 -0
  36. package/gui/dist/provider-icons/huggingface-color.svg +1 -0
  37. package/gui/dist/provider-icons/kimi-color.svg +1 -0
  38. package/gui/dist/provider-icons/kiro-color.svg +15 -0
  39. package/gui/dist/provider-icons/kiro.svg +14 -0
  40. package/gui/dist/provider-icons/lm-studio-color.svg +1 -0
  41. package/gui/dist/provider-icons/mistral-color.svg +1 -0
  42. package/gui/dist/provider-icons/moonshot-color.svg +1 -0
  43. package/gui/dist/provider-icons/nvidia-color.svg +1 -0
  44. package/gui/dist/provider-icons/ollama-color.svg +1 -0
  45. package/gui/dist/provider-icons/openai.svg +1 -0
  46. package/gui/dist/provider-icons/opencode.svg +1 -0
  47. package/gui/dist/provider-icons/openrouter-color.svg +1 -0
  48. package/gui/dist/provider-icons/pi.svg +21 -0
  49. package/gui/dist/provider-icons/qianfan-color.svg +1 -0
  50. package/gui/dist/provider-icons/qwen-portal-color.svg +1 -0
  51. package/gui/dist/provider-icons/telegram.svg +1 -0
  52. package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -0
  53. package/gui/dist/provider-icons/vllm-color.svg +1 -0
  54. package/gui/dist/provider-icons/xiaomi-color.svg +1 -0
  55. package/package.json +102 -0
  56. package/src/AGENTS.md +28 -0
  57. package/src/adapters/anthropic-image-guard.ts +251 -0
  58. package/src/adapters/anthropic-image-normalize.ts +518 -0
  59. package/src/adapters/anthropic.ts +1003 -0
  60. package/src/adapters/azure.ts +36 -0
  61. package/src/adapters/base.ts +72 -0
  62. package/src/adapters/client-fingerprint.ts +59 -0
  63. package/src/adapters/cursor/arg-codec.ts +38 -0
  64. package/src/adapters/cursor/arg-normalize.ts +104 -0
  65. package/src/adapters/cursor/cursor-errors.ts +165 -0
  66. package/src/adapters/cursor/discovery.ts +276 -0
  67. package/src/adapters/cursor/effort-map.ts +127 -0
  68. package/src/adapters/cursor/exec-policy.ts +88 -0
  69. package/src/adapters/cursor/framing.ts +211 -0
  70. package/src/adapters/cursor/gen/agent_pb.ts +15274 -0
  71. package/src/adapters/cursor/kv-store.ts +52 -0
  72. package/src/adapters/cursor/live-models.ts +153 -0
  73. package/src/adapters/cursor/live-smoke-gate.ts +41 -0
  74. package/src/adapters/cursor/live-transport.ts +1214 -0
  75. package/src/adapters/cursor/mcp-config.ts +42 -0
  76. package/src/adapters/cursor/mcp-manager.ts +333 -0
  77. package/src/adapters/cursor/message-mapper.ts +49 -0
  78. package/src/adapters/cursor/native-exec-common.ts +55 -0
  79. package/src/adapters/cursor/native-exec-desktop.ts +184 -0
  80. package/src/adapters/cursor/native-exec-fs.ts +329 -0
  81. package/src/adapters/cursor/native-exec-mcp.ts +153 -0
  82. package/src/adapters/cursor/native-exec-network.ts +43 -0
  83. package/src/adapters/cursor/native-exec-shell.ts +548 -0
  84. package/src/adapters/cursor/native-exec-tools.ts +118 -0
  85. package/src/adapters/cursor/native-exec.ts +576 -0
  86. package/src/adapters/cursor/protobuf-events.ts +563 -0
  87. package/src/adapters/cursor/protobuf-request.ts +714 -0
  88. package/src/adapters/cursor/request-builder.ts +255 -0
  89. package/src/adapters/cursor/thread-continuity.ts +67 -0
  90. package/src/adapters/cursor/tool-definitions.ts +505 -0
  91. package/src/adapters/cursor/transport-retry.ts +132 -0
  92. package/src/adapters/cursor/transport.ts +57 -0
  93. package/src/adapters/cursor/types.ts +52 -0
  94. package/src/adapters/cursor.ts +196 -0
  95. package/src/adapters/google-antigravity-replay.ts +303 -0
  96. package/src/adapters/google-antigravity-wire.ts +108 -0
  97. package/src/adapters/google-errors.ts +85 -0
  98. package/src/adapters/google-http.ts +100 -0
  99. package/src/adapters/google-tool-schema.ts +173 -0
  100. package/src/adapters/google-truncation.ts +13 -0
  101. package/src/adapters/google-wire-compiler.ts +232 -0
  102. package/src/adapters/google.ts +758 -0
  103. package/src/adapters/identity.ts +44 -0
  104. package/src/adapters/image.ts +23 -0
  105. package/src/adapters/kiro-constants.ts +16 -0
  106. package/src/adapters/kiro-errors.ts +197 -0
  107. package/src/adapters/kiro-events.ts +179 -0
  108. package/src/adapters/kiro-images.ts +129 -0
  109. package/src/adapters/kiro-retry.ts +312 -0
  110. package/src/adapters/kiro-thinking.ts +96 -0
  111. package/src/adapters/kiro-tool-fallback.ts +36 -0
  112. package/src/adapters/kiro-tools.ts +215 -0
  113. package/src/adapters/kiro-truncation.ts +33 -0
  114. package/src/adapters/kiro-wire.ts +129 -0
  115. package/src/adapters/kiro.ts +1898 -0
  116. package/src/adapters/mimo-free.ts +263 -0
  117. package/src/adapters/openai-chat.ts +1005 -0
  118. package/src/adapters/openai-responses.ts +1137 -0
  119. package/src/adapters/run-turn-queue.ts +114 -0
  120. package/src/adapters/tool-catalog-nudge.ts +71 -0
  121. package/src/adapters/upstream-http-error.ts +48 -0
  122. package/src/bridge.ts +1619 -0
  123. package/src/chat/inbound.ts +295 -0
  124. package/src/chat/outbound.ts +765 -0
  125. package/src/claude/agents-inject.ts +243 -0
  126. package/src/claude/alias.ts +149 -0
  127. package/src/claude/auth-detect.ts +229 -0
  128. package/src/claude/auth-mode-migration.ts +32 -0
  129. package/src/claude/auth-mode.ts +62 -0
  130. package/src/claude/context-windows.ts +189 -0
  131. package/src/claude/desktop-3p-guard.ts +35 -0
  132. package/src/claude/desktop-3p-paths.ts +84 -0
  133. package/src/claude/desktop-3p.ts +381 -0
  134. package/src/claude/desktop-health.ts +26 -0
  135. package/src/claude/desktop-profile.ts +263 -0
  136. package/src/claude/gateway-cache.ts +70 -0
  137. package/src/claude/inbound-debug.ts +163 -0
  138. package/src/claude/inbound.ts +509 -0
  139. package/src/claude/model-info.ts +151 -0
  140. package/src/claude/outbound.ts +872 -0
  141. package/src/cli/access.ts +108 -0
  142. package/src/cli/account-api.ts +268 -0
  143. package/src/cli/account-auth.ts +223 -0
  144. package/src/cli/account-extended.ts +350 -0
  145. package/src/cli/account.ts +275 -0
  146. package/src/cli/agent-driven.ts +70 -0
  147. package/src/cli/agent.ts +184 -0
  148. package/src/cli/catalog-prewarm.ts +27 -0
  149. package/src/cli/claude-desktop.ts +188 -0
  150. package/src/cli/claude.ts +286 -0
  151. package/src/cli/codex-shim-autorestore.ts +45 -0
  152. package/src/cli/combo.ts +119 -0
  153. package/src/cli/config-command.ts +145 -0
  154. package/src/cli/debug.ts +228 -0
  155. package/src/cli/doctor.ts +930 -0
  156. package/src/cli/export-command.ts +187 -0
  157. package/src/cli/help.ts +354 -0
  158. package/src/cli/index.ts +1113 -0
  159. package/src/cli/init.ts +224 -0
  160. package/src/cli/integrations.ts +142 -0
  161. package/src/cli/interactive-confirm.ts +133 -0
  162. package/src/cli/internal-dispatch.ts +20 -0
  163. package/src/cli/models-runtime.ts +212 -0
  164. package/src/cli/models.ts +336 -0
  165. package/src/cli/observe.ts +117 -0
  166. package/src/cli/opencode.ts +586 -0
  167. package/src/cli/pi.ts +188 -0
  168. package/src/cli/provider-runtime.ts +162 -0
  169. package/src/cli/provider.ts +463 -0
  170. package/src/cli/runtime-api.ts +325 -0
  171. package/src/cli/star-prompt.ts +155 -0
  172. package/src/cli/status-oauth.ts +78 -0
  173. package/src/cli/status.ts +321 -0
  174. package/src/cli/sync-cloud.ts +283 -0
  175. package/src/cli/system-command.ts +112 -0
  176. package/src/cli/tray-proxy.ts +52 -0
  177. package/src/cli/v2.ts +173 -0
  178. package/src/cli.ts +10 -0
  179. package/src/clients/config-export.ts +377 -0
  180. package/src/clients/effective-status.ts +385 -0
  181. package/src/clients/probes/agy.ts +55 -0
  182. package/src/clients/probes/cc-switch.ts +110 -0
  183. package/src/clients/probes/claude.ts +90 -0
  184. package/src/clients/probes/codex.ts +125 -0
  185. package/src/clients/probes/grok.ts +29 -0
  186. package/src/clients/probes/opencode.ts +109 -0
  187. package/src/clients/probes/paseo.ts +55 -0
  188. package/src/clients/probes/pi.ts +55 -0
  189. package/src/cloud/onedrive-auth.ts +666 -0
  190. package/src/cloud/onedrive-graph.ts +108 -0
  191. package/src/cloud/settings.ts +75 -0
  192. package/src/cloud/sync.ts +212 -0
  193. package/src/cloud/types.ts +56 -0
  194. package/src/cloud/vault.ts +89 -0
  195. package/src/codex/account-id.ts +34 -0
  196. package/src/codex/account-label.ts +34 -0
  197. package/src/codex/account-lifecycle.ts +55 -0
  198. package/src/codex/account-namespace-match.ts +63 -0
  199. package/src/codex/account-namespaces.ts +149 -0
  200. package/src/codex/account-pause.ts +20 -0
  201. package/src/codex/account-runtime-state.ts +31 -0
  202. package/src/codex/account-store.ts +517 -0
  203. package/src/codex/account-usability.ts +20 -0
  204. package/src/codex/app-server-processes.ts +756 -0
  205. package/src/codex/auth-api.ts +1540 -0
  206. package/src/codex/auth-collision.ts +107 -0
  207. package/src/codex/auth-context.ts +352 -0
  208. package/src/codex/autostart-health.ts +149 -0
  209. package/src/codex/catalog/aggregation.ts +378 -0
  210. package/src/codex/catalog/bundled.ts +251 -0
  211. package/src/codex/catalog/effort.ts +355 -0
  212. package/src/codex/catalog/metadata.ts +180 -0
  213. package/src/codex/catalog/parsing.ts +456 -0
  214. package/src/codex/catalog/provider-fetch.ts +902 -0
  215. package/src/codex/catalog/sync.ts +620 -0
  216. package/src/codex/catalog.ts +12 -0
  217. package/src/codex/data/upstream-models.json +830 -0
  218. package/src/codex/exec-invocation.ts +22 -0
  219. package/src/codex/features.ts +969 -0
  220. package/src/codex/history-migration-guardian.ts +102 -0
  221. package/src/codex/history-provider.ts +776 -0
  222. package/src/codex/home.ts +206 -0
  223. package/src/codex/inject.ts +799 -0
  224. package/src/codex/injected-marker.ts +72 -0
  225. package/src/codex/journal.ts +163 -0
  226. package/src/codex/main-account-cache.ts +32 -0
  227. package/src/codex/main-account.ts +40 -0
  228. package/src/codex/model-cache.ts +227 -0
  229. package/src/codex/paths.ts +65 -0
  230. package/src/codex/plugins-doctor.ts +242 -0
  231. package/src/codex/pool-rotation.ts +225 -0
  232. package/src/codex/project-config-warnings.ts +411 -0
  233. package/src/codex/quota.ts +411 -0
  234. package/src/codex/refresh.ts +53 -0
  235. package/src/codex/routing.ts +1477 -0
  236. package/src/codex/runtime.ts +538 -0
  237. package/src/codex/shim.ts +1189 -0
  238. package/src/codex/subagent-defaults.ts +550 -0
  239. package/src/codex/subagent-model-fallback.ts +469 -0
  240. package/src/codex/sync.ts +130 -0
  241. package/src/codex/warmup.ts +192 -0
  242. package/src/codex/websocket-registry.ts +100 -0
  243. package/src/combos/failover.ts +140 -0
  244. package/src/combos/index.ts +41 -0
  245. package/src/combos/request.ts +62 -0
  246. package/src/combos/resolve.ts +232 -0
  247. package/src/combos/types.ts +326 -0
  248. package/src/config.ts +2356 -0
  249. package/src/generated/jawcode-model-metadata.ts +104 -0
  250. package/src/github/star-state.ts +203 -0
  251. package/src/grok/inject.ts +545 -0
  252. package/src/grok/status.ts +121 -0
  253. package/src/grok/sync.ts +103 -0
  254. package/src/grok/usage-hook/report.mjs +348 -0
  255. package/src/grok/usage-hook.ts +278 -0
  256. package/src/images/artifacts.ts +516 -0
  257. package/src/images/fulfill-video.ts +163 -0
  258. package/src/images/fulfill.ts +149 -0
  259. package/src/images/index.ts +4 -0
  260. package/src/images/loop.ts +829 -0
  261. package/src/images/plan.ts +133 -0
  262. package/src/images/synthetic-tool.ts +133 -0
  263. package/src/images/types.ts +41 -0
  264. package/src/images/xai-client.ts +141 -0
  265. package/src/images/xai-video-client.ts +163 -0
  266. package/src/index.ts +22 -0
  267. package/src/lib/abort.ts +146 -0
  268. package/src/lib/admin-secrets.ts +25 -0
  269. package/src/lib/admission.ts +83 -0
  270. package/src/lib/app-owned-memory-stores.ts +173 -0
  271. package/src/lib/app-owned-memory.ts +265 -0
  272. package/src/lib/bounded-body.ts +202 -0
  273. package/src/lib/bun-binary-validator.d.mts +3 -0
  274. package/src/lib/bun-binary-validator.mjs +18 -0
  275. package/src/lib/bun-runtime.ts +71 -0
  276. package/src/lib/bun-stream-caps.ts +126 -0
  277. package/src/lib/config-ownership.ts +360 -0
  278. package/src/lib/crash-guard.ts +344 -0
  279. package/src/lib/debug-log-buffer.ts +83 -0
  280. package/src/lib/debug-settings.ts +108 -0
  281. package/src/lib/debug.ts +31 -0
  282. package/src/lib/destination-policy.ts +316 -0
  283. package/src/lib/errors.ts +364 -0
  284. package/src/lib/eventstream-decoder.ts +253 -0
  285. package/src/lib/gcp-adc.ts +341 -0
  286. package/src/lib/injection-debug-log.ts +58 -0
  287. package/src/lib/open-url.ts +25 -0
  288. package/src/lib/pinned-http.ts +151 -0
  289. package/src/lib/privacy.ts +20 -0
  290. package/src/lib/process-control.ts +165 -0
  291. package/src/lib/provider-outbound.ts +170 -0
  292. package/src/lib/provider-url.ts +14 -0
  293. package/src/lib/proxy-env.ts +18 -0
  294. package/src/lib/redact.ts +105 -0
  295. package/src/lib/retry-after.ts +55 -0
  296. package/src/lib/service-secrets.ts +25 -0
  297. package/src/lib/shadow-call.ts +30 -0
  298. package/src/lib/sidecar-tracker.ts +52 -0
  299. package/src/lib/sse-decoder.ts +323 -0
  300. package/src/lib/state-store-registrations.ts +109 -0
  301. package/src/lib/state-store-sweeper.ts +184 -0
  302. package/src/lib/test-home-guard.ts +90 -0
  303. package/src/lib/token-estimate.ts +69 -0
  304. package/src/lib/translator-budget.ts +356 -0
  305. package/src/lib/upstream-retry.ts +239 -0
  306. package/src/lib/win-exec.ts +115 -0
  307. package/src/lib/win-paths.ts +68 -0
  308. package/src/lib/windows-elevation.ts +705 -0
  309. package/src/lib/windows-secret-acl.ts +514 -0
  310. package/src/lib/winsw.ts +375 -0
  311. package/src/oauth/anthropic-routing.ts +594 -0
  312. package/src/oauth/anthropic.ts +177 -0
  313. package/src/oauth/callback-server.ts +294 -0
  314. package/src/oauth/chatgpt.ts +150 -0
  315. package/src/oauth/cursor.ts +211 -0
  316. package/src/oauth/github-copilot.ts +428 -0
  317. package/src/oauth/google-antigravity.ts +230 -0
  318. package/src/oauth/health.ts +399 -0
  319. package/src/oauth/index.ts +1174 -0
  320. package/src/oauth/key-providers.ts +108 -0
  321. package/src/oauth/kimi.ts +213 -0
  322. package/src/oauth/kiro-credentials.ts +726 -0
  323. package/src/oauth/kiro.ts +577 -0
  324. package/src/oauth/local-token-detect.ts +121 -0
  325. package/src/oauth/log.ts +48 -0
  326. package/src/oauth/login-cli.ts +163 -0
  327. package/src/oauth/pkce.ts +15 -0
  328. package/src/oauth/store.ts +630 -0
  329. package/src/oauth/token-guardian.ts +303 -0
  330. package/src/oauth/types.ts +62 -0
  331. package/src/oauth/xai.ts +241 -0
  332. package/src/pi/extensions.ts +72 -0
  333. package/src/pi/home.ts +42 -0
  334. package/src/pi/index.ts +40 -0
  335. package/src/pi/models.ts +278 -0
  336. package/src/pi/packages.ts +219 -0
  337. package/src/pi/settings.ts +365 -0
  338. package/src/pi/status.ts +68 -0
  339. package/src/pi/sync.ts +75 -0
  340. package/src/providers/alibaba-region-backup.ts +75 -0
  341. package/src/providers/alibaba-region-migration.ts +156 -0
  342. package/src/providers/alibaba-region-startup.ts +36 -0
  343. package/src/providers/antigravity-models.ts +205 -0
  344. package/src/providers/api-keys.ts +140 -0
  345. package/src/providers/base-url-choices.ts +64 -0
  346. package/src/providers/context-cap.ts +65 -0
  347. package/src/providers/derive.ts +339 -0
  348. package/src/providers/free-directory.ts +184 -0
  349. package/src/providers/github-copilot-transport.ts +56 -0
  350. package/src/providers/key-failover.ts +203 -0
  351. package/src/providers/kiro-models.ts +67 -0
  352. package/src/providers/label.ts +19 -0
  353. package/src/providers/model-discovery.ts +356 -0
  354. package/src/providers/openai-sidecar.ts +175 -0
  355. package/src/providers/openai-tier-startup.ts +27 -0
  356. package/src/providers/openai-tiers.ts +301 -0
  357. package/src/providers/openai-virtual-models.ts +82 -0
  358. package/src/providers/openrouter-routing.ts +102 -0
  359. package/src/providers/provider-id-rewrite.ts +150 -0
  360. package/src/providers/quota.ts +1260 -0
  361. package/src/providers/registry.ts +1600 -0
  362. package/src/providers/slug-codec.ts +67 -0
  363. package/src/providers/xai-transport.ts +141 -0
  364. package/src/reasoning-effort.ts +135 -0
  365. package/src/responses/compaction.ts +117 -0
  366. package/src/responses/parser.ts +656 -0
  367. package/src/responses/reasoning-envelope.ts +52 -0
  368. package/src/responses/schema.ts +159 -0
  369. package/src/responses/spill-store.ts +394 -0
  370. package/src/responses/state.ts +895 -0
  371. package/src/responses/tool-groups.ts +19 -0
  372. package/src/router.ts +425 -0
  373. package/src/server/adapter-resolve.ts +80 -0
  374. package/src/server/auth-cors.ts +530 -0
  375. package/src/server/chat-completions.ts +368 -0
  376. package/src/server/claude-messages.ts +914 -0
  377. package/src/server/effort-policy.ts +172 -0
  378. package/src/server/gui-static.ts +123 -0
  379. package/src/server/image-retry.ts +42 -0
  380. package/src/server/images.ts +476 -0
  381. package/src/server/index.ts +1126 -0
  382. package/src/server/lifecycle.ts +227 -0
  383. package/src/server/live.ts +598 -0
  384. package/src/server/management/agent-settings-routes.ts +1169 -0
  385. package/src/server/management/api-access.ts +141 -0
  386. package/src/server/management/api-key-usage.ts +167 -0
  387. package/src/server/management/body.ts +35 -0
  388. package/src/server/management/clients-routes.ts +63 -0
  389. package/src/server/management/cloud-sync-routes.ts +266 -0
  390. package/src/server/management/combo-routes.ts +220 -0
  391. package/src/server/management/config-routes.ts +422 -0
  392. package/src/server/management/context.ts +31 -0
  393. package/src/server/management/logs-usage-routes.ts +707 -0
  394. package/src/server/management/model-routes.ts +525 -0
  395. package/src/server/management/oauth-account-routes.ts +563 -0
  396. package/src/server/management/provider-routes.ts +556 -0
  397. package/src/server/management/shared.ts +277 -0
  398. package/src/server/management/sidebar-routes.ts +90 -0
  399. package/src/server/management/system-restart.ts +179 -0
  400. package/src/server/management/system-routes.ts +117 -0
  401. package/src/server/management/usage-summary-cache.ts +86 -0
  402. package/src/server/management-api.ts +215 -0
  403. package/src/server/management-auth.ts +267 -0
  404. package/src/server/memory-watchdog.ts +156 -0
  405. package/src/server/port-reclaim.ts +307 -0
  406. package/src/server/ports.ts +116 -0
  407. package/src/server/proxy-liveness.ts +201 -0
  408. package/src/server/relay-eager.ts +313 -0
  409. package/src/server/relay.ts +1049 -0
  410. package/src/server/request-decompress.ts +132 -0
  411. package/src/server/request-log-conversation.ts +168 -0
  412. package/src/server/request-log.ts +1046 -0
  413. package/src/server/responses/collaboration.ts +354 -0
  414. package/src/server/responses/compact.ts +384 -0
  415. package/src/server/responses/core.ts +2758 -0
  416. package/src/server/responses/encrypted-payload.ts +308 -0
  417. package/src/server/responses/fetch-helpers.ts +157 -0
  418. package/src/server/responses/passthrough-error.ts +78 -0
  419. package/src/server/responses/terminal-guard.ts +230 -0
  420. package/src/server/responses/upstream-error.ts +48 -0
  421. package/src/server/responses-image-gen-repair.ts +132 -0
  422. package/src/server/responses-item-id-repair.ts +224 -0
  423. package/src/server/responses.ts +9 -0
  424. package/src/server/search.ts +136 -0
  425. package/src/server/sse-payload-rewrite.ts +175 -0
  426. package/src/server/startup-action-control.ts +308 -0
  427. package/src/server/startup-health-cache.ts +113 -0
  428. package/src/server/system-env.ts +413 -0
  429. package/src/server/windows-tcp-drop.ts +184 -0
  430. package/src/server/windows-tray-control.ts +41 -0
  431. package/src/server/ws-bridge.ts +471 -0
  432. package/src/service.ts +2554 -0
  433. package/src/stall-timeout.ts +20 -0
  434. package/src/storage/cleanup-job.ts +57 -0
  435. package/src/storage/cleanup.ts +3085 -0
  436. package/src/storage/policy-job.ts +457 -0
  437. package/src/storage/policy-scheduler.ts +40 -0
  438. package/src/storage/policy-worker.ts +59 -0
  439. package/src/storage/policy.ts +527 -0
  440. package/src/storage/restore-job.ts +299 -0
  441. package/src/storage/restore-worker.ts +58 -0
  442. package/src/storage/scanner.ts +238 -0
  443. package/src/storage/storage-mutation-coordinator.ts +139 -0
  444. package/src/storage/worker-lifecycle.ts +215 -0
  445. package/src/tray/assets/opencodex-tray-offline.ico +0 -0
  446. package/src/tray/assets/opencodex-tray-online.ico +0 -0
  447. package/src/tray/assets/opencodex-tray-warning.ico +0 -0
  448. package/src/tray/assets/opencodex-tray.png +0 -0
  449. package/src/tray/windows-tray.ps1 +290 -0
  450. package/src/tray/windows.ts +730 -0
  451. package/src/types.ts +1237 -0
  452. package/src/update/badge.ts +72 -0
  453. package/src/update/index.ts +407 -0
  454. package/src/update/job.ts +1520 -0
  455. package/src/update/notify.ts +257 -0
  456. package/src/update/npm-invocation.d.mts +23 -0
  457. package/src/update/npm-invocation.mjs +94 -0
  458. package/src/update/tray-update-plan.d.mts +18 -0
  459. package/src/update/tray-update-plan.mjs +38 -0
  460. package/src/usage/cost.ts +0 -0
  461. package/src/usage/debug.ts +97 -0
  462. package/src/usage/expected-prices.ts +164 -0
  463. package/src/usage/log.ts +658 -0
  464. package/src/usage/summary.ts +585 -0
  465. package/src/usage/totals.ts +14 -0
  466. package/src/vision/anthropic-describe.ts +185 -0
  467. package/src/vision/describe.ts +125 -0
  468. package/src/vision/index.ts +467 -0
  469. package/src/web-search/anthropic-executor.ts +189 -0
  470. package/src/web-search/executor.ts +105 -0
  471. package/src/web-search/format-result.ts +89 -0
  472. package/src/web-search/index.ts +196 -0
  473. package/src/web-search/loop.ts +664 -0
  474. package/src/web-search/parse.ts +220 -0
  475. package/src/web-search/progress-stream.ts +342 -0
  476. package/src/web-search/synthetic-tool.ts +47 -0
@@ -0,0 +1,375 @@
1
+ /**
2
+ * WinSW-backed native Windows service (opt-in via `ocx service install --native`).
3
+ *
4
+ * Design (devlog/_plan/260720_windows_service/060):
5
+ * - WinSW 2.12.0 NET461 build, downloaded on first native install and verified against
6
+ * a pinned SHA-256 (fail-closed: mismatch deletes the file and throws). The binary is
7
+ * NOT bundled in npm; offline installs get an explicit manual-placement hint.
8
+ * - Runs as the USER account (v2 `<serviceaccount>` domain/user/allowservicelogon —
9
+ * never LocalSystem: the ACL hardening in windows-secret-acl grants only the user SID,
10
+ * so a SYSTEM service could not read the token file, and SYSTEM-owned writes would
11
+ * change the user-access contract).
12
+ * - No password in XML: `winsw install /p` prompts on the console (stdin inherit).
13
+ * - Absolute paths only — no %USERPROFILE% indirection (that exists for OEM-codepage
14
+ * batch parsing; WinSW XML is Unicode).
15
+ */
16
+ import { createHash } from "node:crypto";
17
+ import { execFileSync } from "node:child_process";
18
+ import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
19
+ import { homedir } from "node:os";
20
+ import { join, resolve } from "node:path";
21
+ import { expandUserPath, getConfigDir, loadConfig } from "../config";
22
+ import { recordOwnedConfigPath } from "./config-ownership";
23
+ import { durableBunPath } from "./bun-runtime";
24
+ import { serviceApiTokenFilePath } from "./service-secrets";
25
+
26
+ export const WINSW_VERSION = "2.12.0";
27
+ export const WINSW_URL = `https://github.com/winsw/winsw/releases/download/v${WINSW_VERSION}/WinSW.NET461.exe`;
28
+ /** SHA-256 of the official v2.12.0 WinSW.NET461.exe release asset (655872 bytes). */
29
+ export const WINSW_SHA256 = "b5066b7bbdfba1293e5d15cda3caaea88fbeab35bd5b38c41c913d492aadfc4f";
30
+
31
+ /** SCM service id — distinct from the Task Scheduler task name (opencodex-proxy). */
32
+ export const WINSW_SERVICE_ID = "opencodex-proxy-native";
33
+
34
+ export function winswDir(): string {
35
+ return join(getConfigDir(), "winsw");
36
+ }
37
+
38
+ /** WinSW discovers its config as the same-basename XML next to the exe. */
39
+ export function winswExePath(): string {
40
+ return join(winswDir(), `${WINSW_SERVICE_ID}.exe`);
41
+ }
42
+
43
+ export function winswXmlPath(): string {
44
+ return join(winswDir(), `${WINSW_SERVICE_ID}.xml`);
45
+ }
46
+
47
+ function winswLogDir(): string {
48
+ return getConfigDir();
49
+ }
50
+
51
+ function xmlEscape(value: string): string {
52
+ return value
53
+ .replace(/&/g, "&amp;")
54
+ .replace(/</g, "&lt;")
55
+ .replace(/>/g, "&gt;")
56
+ .replace(/"/g, "&quot;")
57
+ .replace(/'/g, "&apos;");
58
+ }
59
+
60
+ function currentCodexHomeAbsolute(): string {
61
+ const raw = process.env.CODEX_HOME?.trim();
62
+ return raw ? resolve(expandUserPath(raw)) : join(homedir(), ".codex");
63
+ }
64
+
65
+ export interface WinswEntry {
66
+ bun: string;
67
+ cli: string;
68
+ }
69
+
70
+ /**
71
+ * Build the WinSW v2 XML. Never embeds the API token value — the app loads it from
72
+ * OCX_API_TOKEN_FILE at startup (cli handleStart). PATH is baked for parity with the
73
+ * Task Scheduler wrapper / launchd / systemd: the SCM service environment lacks the
74
+ * user's interactive PATH, which provider subprocesses may need.
75
+ */
76
+ export function buildWinswXml(entry: WinswEntry, env: NodeJS.ProcessEnv = process.env, port?: number): string {
77
+ const domain = env.USERDOMAIN?.trim() || ".";
78
+ const user = env.USERNAME?.trim() || "";
79
+ const listenPort = (() => {
80
+ if (typeof port === "number" && Number.isFinite(port) && port > 0 && port <= 65535) return Math.trunc(port);
81
+ const baked = env.OCX_BAKE_PORT?.trim();
82
+ if (baked && /^\d+$/.test(baked)) {
83
+ const n = Number(baked);
84
+ if (n > 0 && n <= 65535) return n;
85
+ }
86
+ return loadConfig().port ?? 10100;
87
+ })();
88
+ // Services never bake `--port 0` (parsePortOption rejects it); treat as default.
89
+ const safeListenPort = listenPort > 0 && listenPort <= 65535 ? listenPort : 10100;
90
+ // SCM services do not inherit the interactive user environment (#764). Bake:
91
+ // - OPENCODEX_HOME so file-backed admin auth (`admin-api-token`) resolves
92
+ // - OPENCODEX_ACL_TIMEOUT_MS when set (not a secret)
93
+ // Never embed OPENCODEX_ADMIN_AUTH_TOKEN or OPENCODEX_API_AUTH_TOKEN values in XML —
94
+ // those stay file-pointer / generated-file only (uninstall retains the XML).
95
+ const aclTimeout = env.OPENCODEX_ACL_TIMEOUT_MS?.trim();
96
+ const envLines = [
97
+ ` <env name="OCX_SERVICE" value="1"/>`,
98
+ ` <env name="OCX_API_TOKEN_FILE" value="${xmlEscape(serviceApiTokenFilePath())}"/>`,
99
+ ` <env name="PATH" value="${xmlEscape(env.PATH ?? "")}"/>`,
100
+ env.CODEX_HOME?.trim() ? ` <env name="CODEX_HOME" value="${xmlEscape(currentCodexHomeAbsolute())}"/>` : null,
101
+ ` <env name="OPENCODEX_HOME" value="${xmlEscape(getConfigDir())}"/>`,
102
+ aclTimeout ? ` <env name="OPENCODEX_ACL_TIMEOUT_MS" value="${xmlEscape(aclTimeout)}"/>` : null,
103
+ ].filter((line): line is string => Boolean(line));
104
+ return `<?xml version="1.0" encoding="UTF-8"?>
105
+ <service>
106
+ <id>${WINSW_SERVICE_ID}</id>
107
+ <name>OpenCodex Proxy (native)</name>
108
+ <description>OpenCodex proxy running as a native Windows service (windowless, starts at boot).</description>
109
+ <executable>${xmlEscape(entry.bun)}</executable>
110
+ <arguments>${xmlEscape(`"${entry.cli}" start --port ${safeListenPort}`)}</arguments>
111
+ ${envLines.join("\n")}
112
+ <logpath>${xmlEscape(winswLogDir())}</logpath>
113
+ <log mode="roll-by-size">
114
+ <sizeThreshold>10240</sizeThreshold>
115
+ <keepFiles>4</keepFiles>
116
+ </log>
117
+ <onfailure action="restart" delay="5 sec"/>
118
+ <stoptimeout>20 sec</stoptimeout>
119
+ <serviceaccount>
120
+ <domain>${xmlEscape(domain)}</domain>
121
+ <user>${xmlEscape(user)}</user>
122
+ <allowservicelogon>true</allowservicelogon>
123
+ </serviceaccount>
124
+ </service>
125
+ `;
126
+ }
127
+
128
+ export function sha256Hex(data: Uint8Array | Buffer): string {
129
+ return createHash("sha256").update(data).digest("hex");
130
+ }
131
+
132
+ /**
133
+ * Ensure the pinned WinSW binary exists locally; download + verify on first use.
134
+ * Fail-closed: any hash mismatch deletes the file and throws.
135
+ */
136
+ export async function ensureWinswBinary(fetchImpl: typeof fetch = fetch): Promise<string> {
137
+ const exe = winswExePath();
138
+ if (existsSync(exe)) {
139
+ const digest = sha256Hex(readFileSync(exe));
140
+ if (digest === WINSW_SHA256) return exe;
141
+ unlinkSync(exe);
142
+ console.warn("⚠️ Existing WinSW binary failed hash verification; re-downloading.");
143
+ }
144
+ recordOwnedConfigPath(getConfigDir(), winswDir());
145
+ if (!existsSync(winswDir())) mkdirSync(winswDir(), { recursive: true });
146
+ let body: ArrayBuffer;
147
+ try {
148
+ const res = await fetchImpl(WINSW_URL);
149
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
150
+ body = await res.arrayBuffer();
151
+ } catch (err) {
152
+ throw new Error(
153
+ `Failed to download WinSW ${WINSW_VERSION} (${err instanceof Error ? err.message : String(err)}). ` +
154
+ `Offline? Place the official WinSW.NET461.exe (v${WINSW_VERSION}) at ${exe} and retry.`,
155
+ );
156
+ }
157
+ const bytes = Buffer.from(body);
158
+ const digest = sha256Hex(bytes);
159
+ if (digest !== WINSW_SHA256) {
160
+ throw new Error(
161
+ `WinSW download failed SHA-256 verification (got ${digest}, expected ${WINSW_SHA256}). ` +
162
+ "Refusing to install an unverified service binary.",
163
+ );
164
+ }
165
+ writeFileSync(exe, bytes);
166
+ return exe;
167
+ }
168
+
169
+ function runWinsw(args: string[]): string {
170
+ return execFileSync(winswExePath(), args, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], windowsHide: true }).trim();
171
+ }
172
+
173
+ /** `install /p` prompts for the service-account password on the console — stdin must be inherited. */
174
+ function runWinswInteractive(args: string[]): void {
175
+ if (!process.stdin.isTTY) {
176
+ throw new Error(
177
+ "WinSW install requires an interactive console to prompt for the service account password. "
178
+ + "Run `ocx service install --native` from an elevated Command Prompt or PowerShell window, not a hidden or piped session.",
179
+ );
180
+ }
181
+ execFileSync(winswExePath(), args, { stdio: "inherit" });
182
+ }
183
+
184
+ function scQc(): string {
185
+ const sc = join(process.env.SystemRoot ?? "C:\\Windows", "System32", "sc.exe");
186
+ return execFileSync(existsSync(sc) ? sc : "sc.exe", ["qc", WINSW_SERVICE_ID], {
187
+ encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], windowsHide: true,
188
+ });
189
+ }
190
+
191
+ export type WinswStatus = "started" | "stopped" | "nonexistent" | "unknown";
192
+
193
+ /** WinSW v2 `status` prints exactly Started / Stopped / NonExistent. */
194
+ export function parseWinswStatus(output: string): WinswStatus {
195
+ const normalized = output.trim().toLowerCase();
196
+ if (normalized.includes("nonexistent")) return "nonexistent";
197
+ if (normalized.includes("started")) return "started";
198
+ if (normalized.includes("stopped")) return "stopped";
199
+ // Anything else is an unparseable result — NOT proof of absence. Callers must
200
+ // fail closed: only an exact NonExistent may skip stop/uninstall.
201
+ return "unknown";
202
+ }
203
+
204
+ export function statusWinswRaw(): WinswStatus {
205
+ if (existsSync(winswExePath())) {
206
+ try {
207
+ return parseWinswStatus(runWinsw(["status"]));
208
+ } catch {
209
+ // The query itself failed (access denied, damaged/quarantined exe, ...). Treat the
210
+ // service as possibly-installed so lifecycle operations still attempt stop/uninstall
211
+ // instead of skipping a live SCM service that would keep respawning the proxy.
212
+ return "unknown";
213
+ }
214
+ }
215
+ // A missing exe does NOT prove the SCM registration is gone (quarantined binary,
216
+ // partial uninstall): a stale opencodex-proxy-native registration can outlive it.
217
+ // Confirm absence against the SCM itself before reporting "nonexistent".
218
+ if (process.platform !== "win32") return "nonexistent";
219
+ const probe = probeScmRegistration();
220
+ // probe === "error": the SCM could not be queried — fail closed, never claim absence.
221
+ return probe === false ? "nonexistent" : "unknown";
222
+ }
223
+
224
+ /**
225
+ * Probe the SCM for the native service registration.
226
+ * Returns true (registered), false (confirmed absent — exit 1060 only), or "error"
227
+ * (query itself failed: access denied, sc.exe missing, ...). Only a confirmed
228
+ * ERROR_SERVICE_DOES_NOT_EXIST may prove absence to lifecycle callers.
229
+ */
230
+ export function probeScmRegistration(run: () => string = queryScmForService): boolean | "error" {
231
+ try {
232
+ run();
233
+ return true;
234
+ } catch (err) {
235
+ const e = err as { status?: number | null; stderr?: string | Buffer | null; stdout?: string | Buffer | null; message?: string };
236
+ // sc.exe does not reliably channel the 1060 line — it can land on stderr OR stdout
237
+ // depending on the host — so scan every captured stream and the error message.
238
+ const text = [e.stderr, e.stdout, e.message]
239
+ .map(v => (typeof v === "string" ? v : ""))
240
+ .join("\n");
241
+ // ERROR_SERVICE_DOES_NOT_EXIST: the numeric identifier 1060 is locale-invariant
242
+ // (FALHA 1060 pt-BR, localized ko output, English FAILED 1060). The query is a
243
+ // fixed `sc.exe query <service>` so a standalone 1060 in its output is proof of
244
+ // absence. Bun may deliver e.status as 36 (1060 & 0xff) — status 36 ALONE is
245
+ // NOT accepted (collides with any status ≡ 36 mod 256); the textual 1060 is
246
+ // required corroboration and covers those hosts.
247
+ if (e.status === 1060 || /\b1060\b/.test(text)) return false;
248
+ return "error";
249
+ }
250
+ }
251
+
252
+ function scExePath(): string {
253
+ const sc = join(process.env.SystemRoot ?? "C:\\Windows", "System32", "sc.exe");
254
+ return existsSync(sc) ? sc : "sc.exe";
255
+ }
256
+
257
+ function queryScmForService(): string {
258
+ return execFileSync(scExePath(), ["query", WINSW_SERVICE_ID], {
259
+ encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], windowsHide: true,
260
+ });
261
+ }
262
+
263
+ /**
264
+ * Verify the installed SCM service runs as the intended user, not LocalSystem (WinSW's
265
+ * default when the XML account section is ignored/malformed). Rolls back on mismatch.
266
+ */
267
+ function assertServiceAccountApplied(env: NodeJS.ProcessEnv = process.env): void {
268
+ const qc = scQc();
269
+ const startName = /SERVICE_START_NAME\s*:\s*(.+)/i.exec(qc)?.[1]?.trim() ?? "";
270
+ const user = env.USERNAME?.trim() ?? "";
271
+ if (/localsystem/i.test(startName) || (user && !startName.toLowerCase().includes(user.toLowerCase()))) {
272
+ try { runWinsw(["uninstall"]); } catch { /* rollback is best-effort */ }
273
+ throw new Error(
274
+ `Native service was registered as "${startName || "unknown"}" instead of the current user; ` +
275
+ "rolled back. Re-run `ocx service install --native` and enter the account credentials when prompted.",
276
+ );
277
+ }
278
+ }
279
+
280
+ export interface WinswInstallDeps {
281
+ ensureBinary?: () => Promise<string>;
282
+ writeXml?: (path: string, content: string) => void;
283
+ interactive?: (args: string[]) => void;
284
+ run?: (args: string[]) => string;
285
+ verifyAccount?: () => void;
286
+ status?: () => WinswStatus;
287
+ }
288
+
289
+ /**
290
+ * Install (or repair) the native service. Re-running against an existing service skips
291
+ * `install /p` — assets are rewritten and the service restarted without re-prompting
292
+ * credentials (WinSW `install` fails with "service already exists").
293
+ */
294
+ export async function installWinswService(entry: WinswEntry, deps: WinswInstallDeps = {}): Promise<void> {
295
+ const ensureBinary = deps.ensureBinary ?? ensureWinswBinary;
296
+ const writeXml = deps.writeXml ?? ((path: string, content: string) => writeFileSync(path, content, "utf8"));
297
+ const interactive = deps.interactive ?? runWinswInteractive;
298
+ const run = deps.run ?? runWinsw;
299
+ const verifyAccount = deps.verifyAccount ?? assertServiceAccountApplied;
300
+ const status = deps.status ?? statusWinswRaw;
301
+
302
+ await ensureBinary();
303
+ writeXml(winswXmlPath(), buildWinswXml(entry));
304
+ const existing = status();
305
+ if (existing === "unknown") {
306
+ throw new Error(
307
+ "Could not query the native service state (WinSW status failed or returned an unexpected result). " +
308
+ "Refusing to guess the install state — check 'ocx service status' and retry.",
309
+ );
310
+ }
311
+ if (existing === "nonexistent") {
312
+ // WinSW self-elevates via UAC; a refused prompt aborts install (no silent fallback).
313
+ // v2.12 recognizes prompting only as args[1]: `install /p` (XML is auto-discovered
314
+ // as the same-basename file next to the exe).
315
+ interactive(["install", "/p"]);
316
+ verifyAccount();
317
+ } else {
318
+ // Use `stopwait` (not `stop`) so the SCM service fully stops before `start` — bare
319
+ // `stop` only sends the stop request; `start` against a STOP_PENDING service fails.
320
+ try { run(["stopwait"]); } catch { /* already stopped */ }
321
+ }
322
+ run(["start"]);
323
+ }
324
+
325
+ export function startWinswService(): void { runWinsw(["start"]); }
326
+ export function stopWinswService(): void { try { runWinsw(["stopwait"]); } catch { /* not running */ } }
327
+ export function uninstallWinswService(): void {
328
+ if (!existsSync(winswExePath())) {
329
+ // The binary is gone but the SCM registration can outlive it (quarantine, partial
330
+ // uninstall). WinSW can't run without its exe, so remove the stale registration
331
+ // directly via sc.exe — otherwise the SCM service survives every cleanup path.
332
+ if (process.platform === "win32") {
333
+ const probe = probeScmRegistration();
334
+ if (probe === "error") {
335
+ // Presence unknown — fail closed: keep service state, surface the failure
336
+ // instead of reporting a clean uninstall over a possibly-live registration.
337
+ throw new Error(
338
+ `Cannot verify the native service registration (sc.exe query failed). ` +
339
+ `Uninstall aborted; check 'sc query ${WINSW_SERVICE_ID}' and retry.`,
340
+ );
341
+ }
342
+ if (probe === true) {
343
+ try {
344
+ execFileSync(scExePath(), ["stop", WINSW_SERVICE_ID], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], windowsHide: true });
345
+ } catch { /* not running */ }
346
+ execFileSync(scExePath(), ["delete", WINSW_SERVICE_ID], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], windowsHide: true });
347
+ }
348
+ }
349
+ return;
350
+ }
351
+ try { runWinsw(["stopwait"]); } catch { /* not running */ }
352
+ try { runWinsw(["uninstall"]); } catch (err) {
353
+ // Surface the failure so the caller can decide; silent swallow hides UAC refusals.
354
+ const msg = err instanceof Error ? err.message : String(err);
355
+ if (!msg.toLowerCase().includes("nonexistent")) throw new Error(`WinSW uninstall failed: ${msg}`);
356
+ // "NonExistent" means already absent — that's fine.
357
+ }
358
+ // exe/xml intentionally retained for credential-free reinstall; `--purge` is out of scope.
359
+ }
360
+
361
+ export function winswStatusSummary(): string {
362
+ const status = statusWinswRaw();
363
+ if (status === "nonexistent") {
364
+ // A stale SCM service can outlive a deleted exe; surface the repair path.
365
+ return existsSync(winswXmlPath()) && !existsSync(winswExePath())
366
+ ? "native assets present but WinSW binary missing — run 'ocx service install --native' to repair"
367
+ : "";
368
+ }
369
+ return `native (WinSW ${WINSW_VERSION}): ${status}`;
370
+ }
371
+
372
+ /** Default entry mirrors the Task Scheduler baking: durable Bun + cli.ts. */
373
+ export function defaultWinswEntry(cliDir: string): WinswEntry {
374
+ return { bun: durableBunPath(), cli: join(cliDir, "cli", "index.ts") };
375
+ }