@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,457 @@
1
+ /**
2
+ * Single-flight controller for storage cleanup policy runs.
3
+ *
4
+ * Manual, startup, and scheduled evaluations share one in-flight slot. Heavy
5
+ * work (archive scan, FS cleanup, SQLite reconcile) runs in a Bun Worker so the
6
+ * proxy event loop stays responsive.
7
+ */
8
+ import type { CleanupMode, CleanupResult } from "./cleanup";
9
+ import { resolveCodexHomeDir } from "../codex/home";
10
+ import {
11
+ tryBeginStorageMutation,
12
+ } from "./storage-mutation-coordinator";
13
+ import type { AdmissionLease } from "../lib/admission";
14
+ import {
15
+ isPolicyDue,
16
+ readStorageCleanupPolicyFromConfig,
17
+ type PolicyRunReason,
18
+ type PolicyRunResult,
19
+ type PolicySkipReason,
20
+ } from "./policy";
21
+ import {
22
+ cancelQueuedStorageWorkerSpawns,
23
+ drainStorageWorkers,
24
+ StorageWorkerAdmissionBusyError,
25
+ terminateStorageWorker,
26
+ tryReserveStorageWorker,
27
+ withStorageWorkerSpawnGate,
28
+ } from "./worker-lifecycle";
29
+
30
+ export type PolicyJobStatus = "idle" | "running";
31
+
32
+ export interface PolicyJobOutcome {
33
+ ok: boolean;
34
+ skipped?: PolicySkipReason;
35
+ deferred?: "codex_busy";
36
+ error?: CleanupResult["error"] | "evaluation_failed" | "worker_failed" | "storage_mutation_busy";
37
+ mode?: CleanupMode;
38
+ freedBytes?: number;
39
+ removed?: number;
40
+ trashDir?: string;
41
+ }
42
+
43
+ export interface PolicyJobState {
44
+ status: PolicyJobStatus;
45
+ reason?: PolicyRunReason;
46
+ startedAt?: number;
47
+ finishedAt?: number;
48
+ lastError?: string;
49
+ lastOutcome?: PolicyJobOutcome;
50
+ }
51
+
52
+ export interface RequestPolicyRunOptions {
53
+ reason: PolicyRunReason;
54
+ force?: boolean;
55
+ codexHome?: string;
56
+ busyTimeoutMs?: number;
57
+ }
58
+
59
+ export interface PolicyJobTestHooks {
60
+ /**
61
+ * Block the worker (or in-process run) this many ms after the start-of-job
62
+ * policy load, so concurrent PUTs can race completion metadata writes.
63
+ */
64
+ blockMs?: number;
65
+ /**
66
+ * When true, run on the main thread via `queueMicrotask` + optional sleep.
67
+ * Used only for unit tests that cannot spawn workers; responsiveness tests
68
+ * must leave this unset so work stays in a Worker.
69
+ */
70
+ runInProcess?: boolean;
71
+ /** Expose GET /api/storage/cleanup-policy/test-stream for responsiveness tests. */
72
+ enableTestStream?: boolean;
73
+ }
74
+
75
+ const WORKER_TIMEOUT_MS = 10 * 60 * 1000;
76
+
77
+ let state: PolicyJobState = { status: "idle" };
78
+ let inflight: Promise<void> | null = null;
79
+ let activeWorker: Worker | null = null;
80
+ let testHooks: PolicyJobTestHooks | null = null;
81
+ /** Optional mirror so completed worker runs refresh the live server config. */
82
+ let livePolicyApply: ((policy: PolicyRunResult["policy"]) => void) | undefined;
83
+ /** Settles the active `runInWorker` promise (clears watchdog) before hard terminate. */
84
+ let cancelActiveRun: (() => void) | null = null;
85
+ /** Bumped on abort/reset so a late worker completion cannot clobber newer job state. */
86
+ let runGeneration = 0;
87
+ /** CODEX_HOME whose mutation slot this job holds (parent thread only). */
88
+ let heldMutationLease: AdmissionLease | undefined;
89
+
90
+ function releaseHeldMutationSlot(): void {
91
+ heldMutationLease?.release();
92
+ heldMutationLease = undefined;
93
+ }
94
+
95
+ export function setStorageCleanupPolicyJobLiveApply(
96
+ apply: ((policy: PolicyRunResult["policy"]) => void) | null,
97
+ ): void {
98
+ livePolicyApply = apply ?? undefined;
99
+ }
100
+
101
+ export function getStorageCleanupPolicyJobState(): PolicyJobState {
102
+ return { ...state, ...(state.lastOutcome ? { lastOutcome: { ...state.lastOutcome } } : {}) };
103
+ }
104
+
105
+ /** Test-only SSE/text stream served from the proxy while a worker is blocked. */
106
+ export function getStorageCleanupPolicyTestStreamResponse(): Response | null {
107
+ if (!testHooks?.enableTestStream) return null;
108
+ const encoder = new TextEncoder();
109
+ return new Response(
110
+ new ReadableStream({
111
+ async start(controller) {
112
+ for (let i = 0; i < 8; i++) {
113
+ controller.enqueue(encoder.encode(`chunk-${i}\n`));
114
+ await Bun.sleep(50);
115
+ }
116
+ controller.close();
117
+ },
118
+ }),
119
+ { headers: { "content-type": "text/plain; charset=utf-8" } },
120
+ );
121
+ }
122
+
123
+ export function setStorageCleanupPolicyJobTestHooks(hooks: PolicyJobTestHooks | null): void {
124
+ testHooks = hooks;
125
+ }
126
+
127
+ function disownActiveRun(): void {
128
+ runGeneration += 1;
129
+ const cancel = cancelActiveRun;
130
+ cancelActiveRun = null;
131
+ cancel?.();
132
+ }
133
+
134
+ /**
135
+ * Fire-and-forget reset. Prefer {@link resetStorageCleanupPolicyJobForTestsAsync}
136
+ * from test beforeEach/afterEach — sync terminate races Windows
137
+ * `bun test --isolate` reclaim when the next case spawns immediately.
138
+ */
139
+ export function resetStorageCleanupPolicyJobForTests(): void {
140
+ disownActiveRun();
141
+ // Invalidate spawnGate callbacks that have not created a Worker yet — otherwise
142
+ // they can still spawn after this sync path releases the mutation slot.
143
+ cancelQueuedStorageWorkerSpawns();
144
+ if (activeWorker) {
145
+ void terminateStorageWorker(activeWorker);
146
+ activeWorker = null;
147
+ }
148
+ inflight = null;
149
+ testHooks = null;
150
+ releaseHeldMutationSlot();
151
+ state = { status: "idle" };
152
+ }
153
+
154
+ /**
155
+ * Await-able sibling of the reset above, for test teardown.
156
+ *
157
+ * `bun test --isolate` reclaims a file's realm at the file boundary. A storage
158
+ * worker still exiting at that moment trips a Bun-internal assertion on Windows
159
+ * and takes the whole run down, so a suite that spawns workers must be able to
160
+ * wait for them rather than fire-and-forget.
161
+ *
162
+ * Do not route through the sync reset's `void terminate(...)`: that used to
163
+ * deregister the worker before the thread exited, so a follow-up drain saw an
164
+ * empty registry and returned while Windows was still reclaiming the thread.
165
+ */
166
+ export async function resetStorageCleanupPolicyJobForTestsAsync(): Promise<void> {
167
+ disownActiveRun();
168
+ cancelQueuedStorageWorkerSpawns();
169
+ const worker = activeWorker;
170
+ activeWorker = null;
171
+ inflight = null;
172
+ testHooks = null;
173
+ state = { status: "idle" };
174
+ // Join the worker before releasing the mutation slot so a concurrent run
175
+ // cannot acquire CODEX_HOME while the aborted thread is still mutating.
176
+ try {
177
+ if (worker) await terminateStorageWorker(worker);
178
+ await drainStorageWorkers();
179
+ } finally {
180
+ releaseHeldMutationSlot();
181
+ }
182
+ }
183
+
184
+ /** Terminate an in-flight worker during process shutdown. */
185
+ export function abortStorageCleanupPolicyJob(): void {
186
+ disownActiveRun();
187
+ cancelQueuedStorageWorkerSpawns();
188
+ if (activeWorker) {
189
+ void terminateStorageWorker(activeWorker);
190
+ activeWorker = null;
191
+ }
192
+ // Sync path cannot join; prefer abortStorageCleanupPolicyJobAsync when the
193
+ // caller can await so the mutation slot stays held until the thread exits.
194
+ releaseHeldMutationSlot();
195
+ if (state.status === "running") {
196
+ state = {
197
+ ...state,
198
+ status: "idle",
199
+ finishedAt: Date.now(),
200
+ lastError: "aborted",
201
+ lastOutcome: {
202
+ ok: false,
203
+ error: "evaluation_failed",
204
+ },
205
+ };
206
+ }
207
+ inflight = null;
208
+ }
209
+
210
+ /**
211
+ * Shutdown path that joins worker threads. Prefer this over the sync abort when
212
+ * the caller can await (server drain, test teardown) so Windows isolate reclaim
213
+ * does not race a still-exiting storage worker.
214
+ */
215
+ export async function abortStorageCleanupPolicyJobAsync(): Promise<void> {
216
+ disownActiveRun();
217
+ cancelQueuedStorageWorkerSpawns();
218
+ const worker = activeWorker;
219
+ activeWorker = null;
220
+ if (state.status === "running") {
221
+ state = {
222
+ ...state,
223
+ status: "idle",
224
+ finishedAt: Date.now(),
225
+ lastError: "aborted",
226
+ lastOutcome: {
227
+ ok: false,
228
+ error: "evaluation_failed",
229
+ },
230
+ };
231
+ }
232
+ inflight = null;
233
+ try {
234
+ if (worker) await terminateStorageWorker(worker);
235
+ await drainStorageWorkers();
236
+ } finally {
237
+ releaseHeldMutationSlot();
238
+ }
239
+ }
240
+
241
+ function outcomeFromResult(result: PolicyRunResult): PolicyJobOutcome {
242
+ return {
243
+ ok: result.ok,
244
+ ...(result.skipped ? { skipped: result.skipped } : {}),
245
+ ...(result.deferred ? { deferred: result.deferred } : {}),
246
+ ...(result.error ? { error: result.error } : {}),
247
+ ...(result.mode ? { mode: result.mode } : {}),
248
+ ...(result.freedBytes !== undefined ? { freedBytes: result.freedBytes } : {}),
249
+ ...(result.removed !== undefined ? { removed: result.removed } : {}),
250
+ ...(result.trashDir ? { trashDir: result.trashDir } : {}),
251
+ };
252
+ }
253
+
254
+ function applyFinished(result: PolicyRunResult): void {
255
+ // Prefer the latest persisted policy over `result.policy`. The worker (or
256
+ // in-process run) already merged run metadata into disk; a concurrent PUT
257
+ // may also have landed after that write. Re-reading avoids applying a stale
258
+ // start-of-job snapshot when the run skipped without saving.
259
+ try {
260
+ livePolicyApply?.(readStorageCleanupPolicyFromConfig());
261
+ } catch {
262
+ livePolicyApply?.(result.policy);
263
+ }
264
+ state = {
265
+ status: "idle",
266
+ reason: state.reason,
267
+ startedAt: state.startedAt,
268
+ finishedAt: Date.now(),
269
+ lastOutcome: outcomeFromResult(result),
270
+ };
271
+ }
272
+
273
+ function applyFailed(message: string): void {
274
+ state = {
275
+ status: "idle",
276
+ reason: state.reason,
277
+ startedAt: state.startedAt,
278
+ finishedAt: Date.now(),
279
+ lastError: message,
280
+ lastOutcome: { ok: false, error: "worker_failed" },
281
+ };
282
+ }
283
+
284
+ function applyMutationBusy(): void {
285
+ state = {
286
+ status: "idle",
287
+ reason: state.reason,
288
+ startedAt: state.startedAt,
289
+ finishedAt: Date.now(),
290
+ lastError: "storage_mutation_busy",
291
+ lastOutcome: { ok: false, error: "storage_mutation_busy" },
292
+ };
293
+ }
294
+
295
+ function runInWorker(opts: RequestPolicyRunOptions & { blockMs?: number }): Promise<PolicyRunResult> {
296
+ const reservation = tryReserveStorageWorker();
297
+ if (!reservation) return Promise.reject(new StorageWorkerAdmissionBusyError());
298
+ return withStorageWorkerSpawnGate(() => new Promise<PolicyRunResult>((resolve, reject) => {
299
+ const requestId = crypto.randomUUID();
300
+ let settled = false;
301
+ let worker: Worker;
302
+ try {
303
+ worker = new Worker(new URL("./policy-worker.ts", import.meta.url).href);
304
+ reservation.bind(worker);
305
+ } catch (error) {
306
+ reservation.release();
307
+ reject(error);
308
+ return;
309
+ }
310
+ activeWorker = worker;
311
+
312
+ const finish = (fn: () => void) => {
313
+ if (settled) return;
314
+ settled = true;
315
+ cancelActiveRun = null;
316
+ clearTimeout(timer);
317
+ if (activeWorker === worker) activeWorker = null;
318
+ // Settle the caller only after the thread is actually gone, so a suite
319
+ // that awaits its request cannot reach the next test file with a worker
320
+ // still exiting behind it. Also keeps executeJob's finally from releasing
321
+ // the mutation slot while the thread may still mutate CODEX_HOME.
322
+ void terminateStorageWorker(worker).then(fn, fn);
323
+ };
324
+
325
+ const timer = setTimeout(() => {
326
+ finish(() => reject(new Error("storage_cleanup_worker_timeout")));
327
+ }, WORKER_TIMEOUT_MS);
328
+
329
+ cancelActiveRun = () => {
330
+ finish(() => reject(new Error("aborted")));
331
+ };
332
+
333
+ worker.onmessage = (event: MessageEvent<unknown>) => {
334
+ const data = event.data;
335
+ if (!data || typeof data !== "object") return;
336
+ const msg = data as Record<string, unknown>;
337
+ if (msg.requestId !== requestId) return;
338
+ if (msg.type === "done" && msg.result && typeof msg.result === "object") {
339
+ finish(() => resolve(msg.result as PolicyRunResult));
340
+ return;
341
+ }
342
+ if (msg.type === "error") {
343
+ const message = typeof msg.message === "string" ? msg.message : "worker_failed";
344
+ finish(() => reject(new Error(message)));
345
+ }
346
+ };
347
+
348
+ worker.onerror = (err: ErrorEvent) => {
349
+ finish(() => reject(err.error instanceof Error ? err.error : new Error(err.message || "worker_failed")));
350
+ };
351
+
352
+ worker.postMessage({
353
+ type: "run",
354
+ requestId,
355
+ reason: opts.reason,
356
+ force: opts.force === true,
357
+ ...(opts.codexHome ? { codexHome: opts.codexHome } : {}),
358
+ ...(opts.busyTimeoutMs !== undefined ? { busyTimeoutMs: opts.busyTimeoutMs } : {}),
359
+ ...(opts.blockMs !== undefined ? { blockMs: opts.blockMs } : {}),
360
+ env: {
361
+ ...(process.env.CODEX_HOME ? { CODEX_HOME: process.env.CODEX_HOME } : {}),
362
+ ...(process.env.OPENCODEX_HOME ? { OPENCODEX_HOME: process.env.OPENCODEX_HOME } : {}),
363
+ },
364
+ });
365
+ })).catch(error => {
366
+ reservation.release();
367
+ throw error;
368
+ });
369
+ }
370
+
371
+ async function executeJob(opts: RequestPolicyRunOptions): Promise<void> {
372
+ const generation = ++runGeneration;
373
+ const codexHome = opts.codexHome ?? resolveCodexHomeDir();
374
+ const gate = tryBeginStorageMutation("policy", codexHome);
375
+ if (!gate.acquired) {
376
+ if (generation === runGeneration) {
377
+ applyMutationBusy();
378
+ }
379
+ return;
380
+ }
381
+ heldMutationLease = gate.lease;
382
+ try {
383
+ const blockMs = testHooks?.blockMs;
384
+ let result: PolicyRunResult;
385
+
386
+ if (testHooks?.runInProcess) {
387
+ // Dynamic import keeps the sync engine out of the hot path for the default Worker mode.
388
+ const { runStorageCleanupPolicy } = await import("./policy");
389
+ result = runStorageCleanupPolicy({
390
+ reason: opts.reason,
391
+ force: opts.force === true,
392
+ codexHome,
393
+ ...(opts.busyTimeoutMs !== undefined ? { busyTimeoutMs: opts.busyTimeoutMs } : {}),
394
+ ...(typeof blockMs === "number" && blockMs > 0 ? { holdAfterLoadMs: blockMs } : {}),
395
+ });
396
+ } else {
397
+ result = await runInWorker({
398
+ ...opts,
399
+ codexHome,
400
+ ...(typeof blockMs === "number" && blockMs > 0 ? { blockMs } : {}),
401
+ });
402
+ }
403
+
404
+ if (generation !== runGeneration) return;
405
+ applyFinished(result);
406
+ } catch (err) {
407
+ if (generation !== runGeneration) return;
408
+ if (err instanceof StorageWorkerAdmissionBusyError) applyMutationBusy();
409
+ else applyFailed(err instanceof Error ? err.message : "worker_failed");
410
+ } finally {
411
+ releaseHeldMutationSlot();
412
+ }
413
+ }
414
+
415
+ /**
416
+ * Start a cleanup evaluation if idle. Returns immediately; poll GET for outcome.
417
+ */
418
+ export function requestStorageCleanupPolicyRun(
419
+ opts: RequestPolicyRunOptions,
420
+ ): { accepted: true; state: PolicyJobState } | { accepted: false; error: "already_running"; state: PolicyJobState } {
421
+ if (inflight || state.status === "running") {
422
+ return { accepted: false, error: "already_running", state: getStorageCleanupPolicyJobState() };
423
+ }
424
+
425
+ state = {
426
+ status: "running",
427
+ reason: opts.reason,
428
+ startedAt: Date.now(),
429
+ lastError: undefined,
430
+ ...(state.lastOutcome ? { lastOutcome: state.lastOutcome } : {}),
431
+ };
432
+
433
+ const job = executeJob(opts);
434
+ inflight = job;
435
+ void job.finally(() => {
436
+ if (inflight === job) inflight = null;
437
+ });
438
+ return { accepted: true, state: getStorageCleanupPolicyJobState() };
439
+ }
440
+
441
+ /**
442
+ * Fire-and-forget entry for startup / schedule ticks.
443
+ * Skips the single-flight slot when disabled or not due so manual runs stay free.
444
+ */
445
+ export function maybeRequestStorageCleanupPolicyRun(
446
+ reason: PolicyRunReason,
447
+ opts?: Omit<RequestPolicyRunOptions, "reason">,
448
+ ): void {
449
+ try {
450
+ const policy = readStorageCleanupPolicyFromConfig();
451
+ if (!policy.enabled) return;
452
+ if (!isPolicyDue(policy, Date.now(), reason)) return;
453
+ requestStorageCleanupPolicyRun({ ...opts, reason });
454
+ } catch {
455
+ // Keep scheduler/startup non-throwing.
456
+ }
457
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Long-running schedule tick for daily/weekly storage cleanup policies.
3
+ * Unref'd interval — never keeps the process alive alone (safe for tests).
4
+ * Startup kickoff is tracked here so shutdown can cancel it.
5
+ */
6
+ import { maybeRequestStorageCleanupPolicyRun } from "./policy-job";
7
+
8
+ const DEFAULT_INTERVAL_MS = 60 * 60 * 1000; // 1h
9
+
10
+ let timer: ReturnType<typeof setInterval> | null = null;
11
+ let startupTimer: ReturnType<typeof setTimeout> | null = null;
12
+
13
+ export function startStorageCleanupScheduler(intervalMs = DEFAULT_INTERVAL_MS): void {
14
+ if (timer) return;
15
+ timer = setInterval(() => {
16
+ maybeRequestStorageCleanupPolicyRun("schedule");
17
+ }, intervalMs);
18
+ timer.unref?.();
19
+ }
20
+
21
+ /** Fire-and-forget startup evaluation; cancellable via stopStorageCleanupScheduler. */
22
+ export function scheduleStorageCleanupStartupRun(): void {
23
+ if (startupTimer) return;
24
+ startupTimer = setTimeout(() => {
25
+ startupTimer = null;
26
+ maybeRequestStorageCleanupPolicyRun("startup");
27
+ }, 0);
28
+ startupTimer.unref?.();
29
+ }
30
+
31
+ export function stopStorageCleanupScheduler(): void {
32
+ if (timer) {
33
+ clearInterval(timer);
34
+ timer = null;
35
+ }
36
+ if (startupTimer) {
37
+ clearTimeout(startupTimer);
38
+ startupTimer = null;
39
+ }
40
+ }
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Worker-thread entry for storage cleanup policy runs.
3
+ * Keeps archive scan / FS cleanup / SQLite reconcile off the proxy event loop.
4
+ */
5
+ import { runStorageCleanupPolicy, type PolicyRunReason } from "./policy";
6
+
7
+ interface RunMessage {
8
+ type: "run";
9
+ requestId: string;
10
+ reason: PolicyRunReason;
11
+ force?: boolean;
12
+ codexHome?: string;
13
+ busyTimeoutMs?: number;
14
+ /** Test-only: block after loading the start-of-job policy (see holdAfterLoadMs). */
15
+ blockMs?: number;
16
+ /** Env snapshot — Workers may not see parent mutations on all platforms. */
17
+ env?: { CODEX_HOME?: string; OPENCODEX_HOME?: string };
18
+ }
19
+
20
+ function isRunMessage(data: unknown): data is RunMessage {
21
+ if (!data || typeof data !== "object" || Array.isArray(data)) return false;
22
+ const o = data as Record<string, unknown>;
23
+ return o.type === "run"
24
+ && typeof o.requestId === "string"
25
+ && (o.reason === "startup" || o.reason === "schedule" || o.reason === "manual");
26
+ }
27
+
28
+ declare const self: Worker;
29
+
30
+ self.onmessage = (event: MessageEvent<unknown>) => {
31
+ if (!isRunMessage(event.data)) return;
32
+ const { requestId, reason, force, codexHome, busyTimeoutMs, blockMs, env } = event.data;
33
+ try {
34
+ if (env?.CODEX_HOME) process.env.CODEX_HOME = env.CODEX_HOME;
35
+ if (env?.OPENCODEX_HOME) process.env.OPENCODEX_HOME = env.OPENCODEX_HOME;
36
+ const result = runStorageCleanupPolicy({
37
+ reason,
38
+ force: force === true,
39
+ ...(codexHome ? { codexHome } : {}),
40
+ ...(busyTimeoutMs !== undefined ? { busyTimeoutMs } : {}),
41
+ ...(typeof blockMs === "number" && Number.isFinite(blockMs) && blockMs > 0
42
+ ? { holdAfterLoadMs: Math.floor(blockMs) }
43
+ : {}),
44
+ });
45
+ self.postMessage({ type: "done", requestId, result });
46
+ } catch (err) {
47
+ self.postMessage({
48
+ type: "error",
49
+ requestId,
50
+ message: err instanceof Error ? err.message : "worker_failed",
51
+ });
52
+ } finally {
53
+ // Close from inside the worker so the thread begins exiting before the
54
+ // parent’s terminate() races isolate realm reclaim on Windows.
55
+ try {
56
+ (self as unknown as { close?: () => void }).close?.();
57
+ } catch { /* already closing */ }
58
+ }
59
+ };