@remodex/rmx 1.0.2

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 (588) hide show
  1. package/AGENTS_INSTALL.md +91 -0
  2. package/LICENSE +21 -0
  3. package/README.md +242 -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 +584 -0
  9. package/bin/package-main.mjs +9 -0
  10. package/gui/dist/assets/index-CZqebSPQ.css +1 -0
  11. package/gui/dist/assets/index-CkETtt7P.js +71 -0
  12. package/gui/dist/favicon.png +0 -0
  13. package/gui/dist/fonts/google-sans-cyrillic.woff2 +0 -0
  14. package/gui/dist/fonts/google-sans-latin.woff2 +0 -0
  15. package/gui/dist/icons.svg +24 -0
  16. package/gui/dist/index.html +25 -0
  17. package/gui/dist/logo.png +0 -0
  18. package/gui/dist/provider-icons/alibaba-color.svg +1 -0
  19. package/gui/dist/provider-icons/antigravity-color.svg +1 -0
  20. package/gui/dist/provider-icons/claude-color.svg +1 -0
  21. package/gui/dist/provider-icons/cline-color.svg +16 -0
  22. package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -0
  23. package/gui/dist/provider-icons/commandcode-color.svg +1 -0
  24. package/gui/dist/provider-icons/copilot-color.svg +1 -0
  25. package/gui/dist/provider-icons/cursor-color.svg +2 -0
  26. package/gui/dist/provider-icons/deepseek-color.svg +1 -0
  27. package/gui/dist/provider-icons/discord.svg +1 -0
  28. package/gui/dist/provider-icons/firepass-color.svg +1 -0
  29. package/gui/dist/provider-icons/fireworks-color.svg +1 -0
  30. package/gui/dist/provider-icons/gemini-color.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.svg +1 -0
  34. package/gui/dist/provider-icons/groq-color.svg +1 -0
  35. package/gui/dist/provider-icons/huggingface-color.svg +1 -0
  36. package/gui/dist/provider-icons/kimi-color.svg +1 -0
  37. package/gui/dist/provider-icons/kiro-color.svg +15 -0
  38. package/gui/dist/provider-icons/lm-studio-color.svg +1 -0
  39. package/gui/dist/provider-icons/mistral-color.svg +1 -0
  40. package/gui/dist/provider-icons/moonshot-color.svg +1 -0
  41. package/gui/dist/provider-icons/nvidia-color.svg +1 -0
  42. package/gui/dist/provider-icons/ollama-color.svg +1 -0
  43. package/gui/dist/provider-icons/openai.svg +1 -0
  44. package/gui/dist/provider-icons/opencode.svg +2 -0
  45. package/gui/dist/provider-icons/openrouter-color.svg +1 -0
  46. package/gui/dist/provider-icons/pi.svg +21 -0
  47. package/gui/dist/provider-icons/qianfan-color.svg +1 -0
  48. package/gui/dist/provider-icons/qwen-portal-color.svg +1 -0
  49. package/gui/dist/provider-icons/telegram.svg +1 -0
  50. package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -0
  51. package/gui/dist/provider-icons/vllm-color.svg +1 -0
  52. package/gui/dist/provider-icons/xiaomi-color.svg +1 -0
  53. package/package.json +118 -0
  54. package/src/AGENTS.md +28 -0
  55. package/src/adapters/anthropic-image-guard.ts +251 -0
  56. package/src/adapters/anthropic-image-normalize.ts +518 -0
  57. package/src/adapters/anthropic.ts +1205 -0
  58. package/src/adapters/azure.ts +36 -0
  59. package/src/adapters/base.ts +83 -0
  60. package/src/adapters/client-fingerprint.ts +59 -0
  61. package/src/adapters/command-code.ts +453 -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/cursor-errors.ts +165 -0
  65. package/src/adapters/cursor/discovery.ts +276 -0
  66. package/src/adapters/cursor/effort-map.ts +139 -0
  67. package/src/adapters/cursor/exec-policy.ts +88 -0
  68. package/src/adapters/cursor/framing.ts +250 -0
  69. package/src/adapters/cursor/gen/agent_pb.ts +15274 -0
  70. package/src/adapters/cursor/kv-store.ts +52 -0
  71. package/src/adapters/cursor/live-models.ts +153 -0
  72. package/src/adapters/cursor/live-smoke-gate.ts +41 -0
  73. package/src/adapters/cursor/live-transport.ts +1235 -0
  74. package/src/adapters/cursor/mcp-config.ts +42 -0
  75. package/src/adapters/cursor/mcp-manager.ts +333 -0
  76. package/src/adapters/cursor/message-mapper.ts +49 -0
  77. package/src/adapters/cursor/native-exec-common.ts +59 -0
  78. package/src/adapters/cursor/native-exec-desktop.ts +184 -0
  79. package/src/adapters/cursor/native-exec-fs.ts +332 -0
  80. package/src/adapters/cursor/native-exec-mcp.ts +153 -0
  81. package/src/adapters/cursor/native-exec-network.ts +43 -0
  82. package/src/adapters/cursor/native-exec-shell.ts +548 -0
  83. package/src/adapters/cursor/native-exec-tools.ts +118 -0
  84. package/src/adapters/cursor/native-exec.ts +604 -0
  85. package/src/adapters/cursor/protobuf-events.ts +735 -0
  86. package/src/adapters/cursor/protobuf-request.ts +719 -0
  87. package/src/adapters/cursor/request-builder.ts +280 -0
  88. package/src/adapters/cursor/thread-continuity.ts +67 -0
  89. package/src/adapters/cursor/tool-definitions.ts +621 -0
  90. package/src/adapters/cursor/transport-retry.ts +132 -0
  91. package/src/adapters/cursor/transport.ts +57 -0
  92. package/src/adapters/cursor/types.ts +59 -0
  93. package/src/adapters/cursor.ts +196 -0
  94. package/src/adapters/google-antigravity-replay.ts +520 -0
  95. package/src/adapters/google-antigravity-wire.ts +140 -0
  96. package/src/adapters/google-errors.ts +85 -0
  97. package/src/adapters/google-http.ts +100 -0
  98. package/src/adapters/google-tool-schema.ts +173 -0
  99. package/src/adapters/google-truncation.ts +24 -0
  100. package/src/adapters/google-wire-compiler.ts +232 -0
  101. package/src/adapters/google.ts +859 -0
  102. package/src/adapters/identity.ts +77 -0
  103. package/src/adapters/image.ts +23 -0
  104. package/src/adapters/kiro-constants.ts +16 -0
  105. package/src/adapters/kiro-errors.ts +208 -0
  106. package/src/adapters/kiro-events.ts +197 -0
  107. package/src/adapters/kiro-images.ts +129 -0
  108. package/src/adapters/kiro-retry.ts +312 -0
  109. package/src/adapters/kiro-thinking.ts +104 -0
  110. package/src/adapters/kiro-tool-fallback.ts +36 -0
  111. package/src/adapters/kiro-tools.ts +224 -0
  112. package/src/adapters/kiro-truncation.ts +33 -0
  113. package/src/adapters/kiro-wire.ts +129 -0
  114. package/src/adapters/kiro.ts +1924 -0
  115. package/src/adapters/mimo-free.ts +263 -0
  116. package/src/adapters/openai-chat.ts +1265 -0
  117. package/src/adapters/openai-responses.ts +1309 -0
  118. package/src/adapters/run-turn-queue.ts +114 -0
  119. package/src/adapters/tool-catalog-nudge.ts +71 -0
  120. package/src/adapters/upstream-http-error.ts +48 -0
  121. package/src/android-remote/assets.ts +218 -0
  122. package/src/android-remote/attachments.ts +168 -0
  123. package/src/android-remote/auth.ts +237 -0
  124. package/src/android-remote/cloudflare-provisioning.ts +409 -0
  125. package/src/android-remote/cloudflare-secret.ts +106 -0
  126. package/src/android-remote/cloudflare-tunnel.ts +488 -0
  127. package/src/android-remote/cloudflared.ts +286 -0
  128. package/src/android-remote/codex-app-server.ts +565 -0
  129. package/src/android-remote/desktop-history-page.ts +936 -0
  130. package/src/android-remote/desktop-ipc.ts +3643 -0
  131. package/src/android-remote/desktop-ownership-store.ts +98 -0
  132. package/src/android-remote/desktop-project-registration.ts +129 -0
  133. package/src/android-remote/desktop-session-stream.ts +1110 -0
  134. package/src/android-remote/desktop-workspace-state.ts +443 -0
  135. package/src/android-remote/file-change-parser.ts +112 -0
  136. package/src/android-remote/gateway.ts +9108 -0
  137. package/src/android-remote/mutation-store.ts +299 -0
  138. package/src/android-remote/projection.ts +1780 -0
  139. package/src/android-remote/queued-turn-store.ts +248 -0
  140. package/src/android-remote/session-command-recovery.ts +1384 -0
  141. package/src/android-remote/store.ts +466 -0
  142. package/src/android-remote/thread-reconciliation.ts +133 -0
  143. package/src/android-remote/thread-source-paths.ts +307 -0
  144. package/src/android-remote/thread-stream.ts +546 -0
  145. package/src/android-remote/turn-activity.ts +235 -0
  146. package/src/android-remote/user-message-identity.ts +94 -0
  147. package/src/bridge.ts +1793 -0
  148. package/src/chat/inbound.ts +295 -0
  149. package/src/chat/outbound.ts +821 -0
  150. package/src/claude/agents-inject.ts +267 -0
  151. package/src/claude/alias.ts +149 -0
  152. package/src/claude/auth-detect.ts +229 -0
  153. package/src/claude/auth-mode-migration.ts +32 -0
  154. package/src/claude/auth-mode.ts +62 -0
  155. package/src/claude/context-windows.ts +189 -0
  156. package/src/claude/desktop-3p-guard.ts +35 -0
  157. package/src/claude/desktop-3p-paths.ts +84 -0
  158. package/src/claude/desktop-3p.ts +601 -0
  159. package/src/claude/desktop-health.ts +26 -0
  160. package/src/claude/desktop-profile.ts +263 -0
  161. package/src/claude/gateway-cache.ts +70 -0
  162. package/src/claude/inbound-debug.ts +163 -0
  163. package/src/claude/inbound.ts +519 -0
  164. package/src/claude/model-info.ts +154 -0
  165. package/src/claude/outbound.ts +898 -0
  166. package/src/cli/access.ts +108 -0
  167. package/src/cli/account-api.ts +296 -0
  168. package/src/cli/account-auth.ts +250 -0
  169. package/src/cli/account-catalog-refresh.ts +14 -0
  170. package/src/cli/account-extended.ts +476 -0
  171. package/src/cli/account-main.ts +317 -0
  172. package/src/cli/account.ts +297 -0
  173. package/src/cli/agent-driven.ts +70 -0
  174. package/src/cli/agent.ts +184 -0
  175. package/src/cli/catalog-prewarm.ts +27 -0
  176. package/src/cli/claude-desktop.ts +211 -0
  177. package/src/cli/claude.ts +302 -0
  178. package/src/cli/codex-shim-autorestore.ts +45 -0
  179. package/src/cli/codex-shim-readiness.ts +69 -0
  180. package/src/cli/combo.ts +124 -0
  181. package/src/cli/config-command.ts +183 -0
  182. package/src/cli/debug.ts +228 -0
  183. package/src/cli/desktop-first-run.ts +25 -0
  184. package/src/cli/doctor.ts +1022 -0
  185. package/src/cli/export-command.ts +201 -0
  186. package/src/cli/help.ts +370 -0
  187. package/src/cli/index.ts +1565 -0
  188. package/src/cli/init.ts +224 -0
  189. package/src/cli/integrations.ts +225 -0
  190. package/src/cli/interactive-confirm.ts +133 -0
  191. package/src/cli/internal-dispatch.ts +35 -0
  192. package/src/cli/launcher-context.ts +77 -0
  193. package/src/cli/models-runtime.ts +224 -0
  194. package/src/cli/models.ts +340 -0
  195. package/src/cli/observe.ts +170 -0
  196. package/src/cli/opencode.ts +587 -0
  197. package/src/cli/provider-runtime.ts +179 -0
  198. package/src/cli/provider.ts +476 -0
  199. package/src/cli/ready.ts +301 -0
  200. package/src/cli/route-policy.ts +92 -0
  201. package/src/cli/runtime-api.ts +328 -0
  202. package/src/cli/star-prompt.ts +211 -0
  203. package/src/cli/status-oauth.ts +78 -0
  204. package/src/cli/status.ts +321 -0
  205. package/src/cli/system-command.ts +196 -0
  206. package/src/cli/system-restart-client.ts +146 -0
  207. package/src/cli/tray-proxy.ts +205 -0
  208. package/src/cli/v2.ts +200 -0
  209. package/src/cli.ts +10 -0
  210. package/src/clients/config-export.ts +1109 -0
  211. package/src/codex/account-id.ts +34 -0
  212. package/src/codex/account-label.ts +34 -0
  213. package/src/codex/account-lifecycle.ts +172 -0
  214. package/src/codex/account-namespace-match.ts +63 -0
  215. package/src/codex/account-namespaces.ts +195 -0
  216. package/src/codex/account-pause.ts +20 -0
  217. package/src/codex/account-priority.ts +83 -0
  218. package/src/codex/account-runtime-state.ts +31 -0
  219. package/src/codex/account-store.ts +517 -0
  220. package/src/codex/account-usability.ts +40 -0
  221. package/src/codex/admission.ts +263 -0
  222. package/src/codex/app-server-processes.ts +799 -0
  223. package/src/codex/auth-api.ts +2098 -0
  224. package/src/codex/auth-collision.ts +107 -0
  225. package/src/codex/auth-context.ts +480 -0
  226. package/src/codex/autostart-health.ts +156 -0
  227. package/src/codex/catalog/account-models.ts +67 -0
  228. package/src/codex/catalog/aggregation.ts +471 -0
  229. package/src/codex/catalog/bundled.ts +533 -0
  230. package/src/codex/catalog/effort.ts +432 -0
  231. package/src/codex/catalog/filesystem-evidence.ts +302 -0
  232. package/src/codex/catalog/kinds.ts +2 -0
  233. package/src/codex/catalog/metadata.ts +287 -0
  234. package/src/codex/catalog/native-models.ts +7 -0
  235. package/src/codex/catalog/parsing.ts +503 -0
  236. package/src/codex/catalog/provider-fetch.ts +2267 -0
  237. package/src/codex/catalog/sync.ts +1606 -0
  238. package/src/codex/catalog-admission.ts +197 -0
  239. package/src/codex/catalog-refresh-status.ts +87 -0
  240. package/src/codex/catalog-write-serialization.ts +242 -0
  241. package/src/codex/catalog.ts +15 -0
  242. package/src/codex/codex-write-lock.ts +384 -0
  243. package/src/codex/convergence-types.ts +593 -0
  244. package/src/codex/convergence.ts +580 -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/desktop-client-processes.ts +521 -0
  249. package/src/codex/exec-invocation.ts +22 -0
  250. package/src/codex/features.ts +1091 -0
  251. package/src/codex/generation.ts +202 -0
  252. package/src/codex/history-job.ts +347 -0
  253. package/src/codex/history-lock.ts +242 -0
  254. package/src/codex/history-migration-guardian.ts +115 -0
  255. package/src/codex/history-provider.ts +1075 -0
  256. package/src/codex/history-transition.ts +105 -0
  257. package/src/codex/history-worker.ts +204 -0
  258. package/src/codex/home.ts +206 -0
  259. package/src/codex/inject-coordination.ts +257 -0
  260. package/src/codex/inject.ts +1857 -0
  261. package/src/codex/injected-marker.ts +79 -0
  262. package/src/codex/integration-record.ts +266 -0
  263. package/src/codex/internal/catalog-writer.ts +203 -0
  264. package/src/codex/internal/history-writer.ts +105 -0
  265. package/src/codex/journal.ts +172 -0
  266. package/src/codex/main-account-cache.ts +56 -0
  267. package/src/codex/main-account.ts +40 -0
  268. package/src/codex/management-convergence.ts +114 -0
  269. package/src/codex/model-cache.ts +267 -0
  270. package/src/codex/native-main-admission.ts +47 -0
  271. package/src/codex/native-main-auth-temp.ts +187 -0
  272. package/src/codex/native-main-claim.ts +167 -0
  273. package/src/codex/native-main-lock-file.ts +162 -0
  274. package/src/codex/native-main-owner.ts +329 -0
  275. package/src/codex/native-profile-api.ts +247 -0
  276. package/src/codex/native-profile-manager.ts +1531 -0
  277. package/src/codex/native-profile-processes.ts +121 -0
  278. package/src/codex/native-profile-recovery.ts +99 -0
  279. package/src/codex/native-profile-stage-store.ts +387 -0
  280. package/src/codex/native-profile-startup.ts +348 -0
  281. package/src/codex/native-profile-store.ts +855 -0
  282. package/src/codex/native-profile-types.ts +120 -0
  283. package/src/codex/native-residue.ts +691 -0
  284. package/src/codex/paths.ts +78 -0
  285. package/src/codex/plugins-doctor.ts +242 -0
  286. package/src/codex/pool-rotation.ts +295 -0
  287. package/src/codex/project-config-warnings.ts +426 -0
  288. package/src/codex/prompt-journal.ts +311 -0
  289. package/src/codex/prompt-layers.ts +967 -0
  290. package/src/codex/prompt-lock.ts +143 -0
  291. package/src/codex/provider-adoption.ts +242 -0
  292. package/src/codex/quota-rejection.ts +224 -0
  293. package/src/codex/quota.ts +494 -0
  294. package/src/codex/refresh.ts +60 -0
  295. package/src/codex/routing.ts +1855 -0
  296. package/src/codex/runtime.ts +659 -0
  297. package/src/codex/shim.ts +1215 -0
  298. package/src/codex/subagent-defaults.ts +557 -0
  299. package/src/codex/subagent-model-fallback.ts +560 -0
  300. package/src/codex/sync.ts +238 -0
  301. package/src/codex/transition-state.ts +612 -0
  302. package/src/codex/upstream-host-health.ts +368 -0
  303. package/src/codex/user-identity.ts +374 -0
  304. package/src/codex/warmup.ts +192 -0
  305. package/src/codex/websocket-registry.ts +100 -0
  306. package/src/codex/write-coordination.ts +114 -0
  307. package/src/combos/failover.ts +140 -0
  308. package/src/combos/index.ts +44 -0
  309. package/src/combos/request.ts +64 -0
  310. package/src/combos/resolve.ts +232 -0
  311. package/src/combos/types.ts +392 -0
  312. package/src/config.ts +3270 -0
  313. package/src/generated/model-metadata.ts +144 -0
  314. package/src/github/star-state.ts +203 -0
  315. package/src/grok/inject.ts +540 -0
  316. package/src/grok/inspect.ts +45 -0
  317. package/src/grok/status.ts +127 -0
  318. package/src/grok/sync.ts +66 -0
  319. package/src/images/artifacts.ts +516 -0
  320. package/src/images/fulfill-video.ts +163 -0
  321. package/src/images/fulfill.ts +149 -0
  322. package/src/images/index.ts +4 -0
  323. package/src/images/loop.ts +922 -0
  324. package/src/images/plan.ts +133 -0
  325. package/src/images/synthetic-tool.ts +133 -0
  326. package/src/images/types.ts +41 -0
  327. package/src/images/xai-client.ts +141 -0
  328. package/src/images/xai-video-client.ts +163 -0
  329. package/src/index.ts +22 -0
  330. package/src/integrations/config-io.ts +151 -0
  331. package/src/integrations/journal.ts +315 -0
  332. package/src/integrations/merge.ts +135 -0
  333. package/src/integrations/native/ownership-preflight.ts +202 -0
  334. package/src/integrations/ownership.ts +111 -0
  335. package/src/integrations/registry.ts +108 -0
  336. package/src/integrations/serialize.ts +235 -0
  337. package/src/integrations/state.ts +290 -0
  338. package/src/integrations/store.ts +103 -0
  339. package/src/integrations/writer.ts +492 -0
  340. package/src/lib/abort.ts +146 -0
  341. package/src/lib/admin-secrets.ts +25 -0
  342. package/src/lib/admission.ts +83 -0
  343. package/src/lib/app-owned-memory-stores.ts +173 -0
  344. package/src/lib/app-owned-memory.ts +265 -0
  345. package/src/lib/bounded-body.ts +242 -0
  346. package/src/lib/bun-binary-validator.d.mts +3 -0
  347. package/src/lib/bun-binary-validator.mjs +18 -0
  348. package/src/lib/bun-runtime.ts +184 -0
  349. package/src/lib/bun-stream-caps.ts +127 -0
  350. package/src/lib/config-ownership.ts +438 -0
  351. package/src/lib/crash-guard.ts +344 -0
  352. package/src/lib/debug-log-buffer.ts +83 -0
  353. package/src/lib/debug-settings.ts +108 -0
  354. package/src/lib/debug.ts +31 -0
  355. package/src/lib/destination-policy.ts +316 -0
  356. package/src/lib/errors.ts +364 -0
  357. package/src/lib/eventstream-decoder.ts +253 -0
  358. package/src/lib/gcp-adc.ts +341 -0
  359. package/src/lib/injection-debug-log.ts +58 -0
  360. package/src/lib/local-management-attestation.ts +51 -0
  361. package/src/lib/open-url.ts +25 -0
  362. package/src/lib/pinned-http.ts +182 -0
  363. package/src/lib/privacy.ts +20 -0
  364. package/src/lib/process-control.ts +168 -0
  365. package/src/lib/provider-environment.ts +470 -0
  366. package/src/lib/provider-outbound.ts +203 -0
  367. package/src/lib/provider-url.ts +14 -0
  368. package/src/lib/proxy-env.ts +18 -0
  369. package/src/lib/redact.ts +510 -0
  370. package/src/lib/remodex-home.ts +616 -0
  371. package/src/lib/retry-after.ts +55 -0
  372. package/src/lib/service-secrets.ts +178 -0
  373. package/src/lib/shadow-call.ts +54 -0
  374. package/src/lib/sidecar-tracker.ts +52 -0
  375. package/src/lib/sse-decoder.ts +364 -0
  376. package/src/lib/state-store-registrations.ts +109 -0
  377. package/src/lib/state-store-sweeper.ts +184 -0
  378. package/src/lib/system-restart-contract.ts +73 -0
  379. package/src/lib/test-home-guard.ts +98 -0
  380. package/src/lib/token-estimate.ts +69 -0
  381. package/src/lib/translator-budget.ts +366 -0
  382. package/src/lib/upstream-reachability.ts +91 -0
  383. package/src/lib/upstream-retry.ts +508 -0
  384. package/src/lib/win-exec.ts +115 -0
  385. package/src/lib/win-paths.ts +68 -0
  386. package/src/lib/windows-elevation.ts +705 -0
  387. package/src/lib/windows-secret-acl.ts +817 -0
  388. package/src/lib/windows-user-principal.ts +283 -0
  389. package/src/lib/winsw.ts +402 -0
  390. package/src/model-sources.ts +73 -0
  391. package/src/oauth/anthropic-routing.ts +594 -0
  392. package/src/oauth/anthropic.ts +177 -0
  393. package/src/oauth/callback-server.ts +294 -0
  394. package/src/oauth/chatgpt.ts +150 -0
  395. package/src/oauth/command-code.ts +239 -0
  396. package/src/oauth/cursor.ts +231 -0
  397. package/src/oauth/github-copilot.ts +428 -0
  398. package/src/oauth/google-antigravity.ts +230 -0
  399. package/src/oauth/health.ts +443 -0
  400. package/src/oauth/index.ts +1280 -0
  401. package/src/oauth/key-providers.ts +128 -0
  402. package/src/oauth/kimi.ts +213 -0
  403. package/src/oauth/kiro-credentials.ts +726 -0
  404. package/src/oauth/kiro.ts +621 -0
  405. package/src/oauth/local-token-detect.ts +121 -0
  406. package/src/oauth/log.ts +48 -0
  407. package/src/oauth/login-cli.ts +163 -0
  408. package/src/oauth/pkce.ts +15 -0
  409. package/src/oauth/store.ts +655 -0
  410. package/src/oauth/token-guardian.ts +309 -0
  411. package/src/oauth/types.ts +62 -0
  412. package/src/oauth/xai.ts +241 -0
  413. package/src/providers/alibaba-region-backup.ts +75 -0
  414. package/src/providers/alibaba-region-migration.ts +156 -0
  415. package/src/providers/alibaba-region-startup.ts +36 -0
  416. package/src/providers/antigravity-models.ts +317 -0
  417. package/src/providers/api-keys.ts +140 -0
  418. package/src/providers/base-url-choices.ts +64 -0
  419. package/src/providers/codex-capacity.ts +288 -0
  420. package/src/providers/command-code-efforts.ts +85 -0
  421. package/src/providers/context-cap.ts +73 -0
  422. package/src/providers/derive.ts +451 -0
  423. package/src/providers/free-directory.ts +187 -0
  424. package/src/providers/github-copilot-transport.ts +56 -0
  425. package/src/providers/google-vertex-location.ts +14 -0
  426. package/src/providers/key-failover.ts +271 -0
  427. package/src/providers/kiro-models.ts +67 -0
  428. package/src/providers/label.ts +19 -0
  429. package/src/providers/model-discovery-limits.ts +16 -0
  430. package/src/providers/model-discovery.ts +361 -0
  431. package/src/providers/openai-sidecar.ts +235 -0
  432. package/src/providers/openai-tier-startup.ts +27 -0
  433. package/src/providers/openai-tiers.ts +301 -0
  434. package/src/providers/openai-virtual-models.ts +83 -0
  435. package/src/providers/openrouter-routing.ts +102 -0
  436. package/src/providers/provider-id-rewrite.ts +179 -0
  437. package/src/providers/quota.ts +1942 -0
  438. package/src/providers/reasoning-capabilities.ts +336 -0
  439. package/src/providers/registry.ts +2375 -0
  440. package/src/providers/slug-codec.ts +74 -0
  441. package/src/providers/xai-transport.ts +149 -0
  442. package/src/reasoning-effort.ts +243 -0
  443. package/src/responses/compaction.ts +124 -0
  444. package/src/responses/hosted-tool-policy.ts +9 -0
  445. package/src/responses/parser.ts +714 -0
  446. package/src/responses/reasoning-envelope.ts +60 -0
  447. package/src/responses/reasoning-replay-cache.ts +106 -0
  448. package/src/responses/schema.ts +159 -0
  449. package/src/responses/spill-store.ts +431 -0
  450. package/src/responses/state.ts +1039 -0
  451. package/src/responses/tool-groups.ts +19 -0
  452. package/src/router.ts +802 -0
  453. package/src/routing/analytics.ts +377 -0
  454. package/src/routing/capability.ts +205 -0
  455. package/src/routing/cost.ts +77 -0
  456. package/src/routing/evaluator.ts +444 -0
  457. package/src/routing/health.ts +401 -0
  458. package/src/routing/history/cursor.ts +43 -0
  459. package/src/routing/history/indexer.ts +605 -0
  460. package/src/routing/history/schema.ts +72 -0
  461. package/src/routing/profile-namespace.ts +15 -0
  462. package/src/routing/profile.ts +424 -0
  463. package/src/routing/quota.ts +145 -0
  464. package/src/routing/request-evidence.ts +45 -0
  465. package/src/routing/trace.ts +686 -0
  466. package/src/server/adapter-resolve.ts +83 -0
  467. package/src/server/auth-cors.ts +606 -0
  468. package/src/server/chat-completions.ts +379 -0
  469. package/src/server/claude-messages.ts +980 -0
  470. package/src/server/effort-policy.ts +251 -0
  471. package/src/server/github-copilot-responses-repair.ts +338 -0
  472. package/src/server/gui-static.ts +152 -0
  473. package/src/server/image-retry.ts +42 -0
  474. package/src/server/images.ts +485 -0
  475. package/src/server/index.ts +1633 -0
  476. package/src/server/lifecycle.ts +482 -0
  477. package/src/server/live.ts +609 -0
  478. package/src/server/management/agent-settings-routes.ts +1180 -0
  479. package/src/server/management/android-remote-routes.ts +390 -0
  480. package/src/server/management/api-access.ts +141 -0
  481. package/src/server/management/api-key-usage.ts +167 -0
  482. package/src/server/management/body.ts +35 -0
  483. package/src/server/management/combo-routes.ts +244 -0
  484. package/src/server/management/config-routes.ts +602 -0
  485. package/src/server/management/context.ts +88 -0
  486. package/src/server/management/integration-routes.ts +538 -0
  487. package/src/server/management/logs-usage-routes.ts +516 -0
  488. package/src/server/management/model-routes.ts +519 -0
  489. package/src/server/management/model-rows.ts +143 -0
  490. package/src/server/management/native-integration-routes.ts +781 -0
  491. package/src/server/management/oauth-account-routes.ts +573 -0
  492. package/src/server/management/provider-routes.ts +781 -0
  493. package/src/server/management/request-history-routes.ts +191 -0
  494. package/src/server/management/routing-analytics-routes.ts +74 -0
  495. package/src/server/management/routing-profile-routes.ts +384 -0
  496. package/src/server/management/shared.ts +277 -0
  497. package/src/server/management/sidebar-routes.ts +106 -0
  498. package/src/server/management/sync-response.ts +69 -0
  499. package/src/server/management/system-restart.ts +433 -0
  500. package/src/server/management/system-routes.ts +141 -0
  501. package/src/server/management/usage-summary-cache.ts +86 -0
  502. package/src/server/management-api.ts +269 -0
  503. package/src/server/management-auth.ts +353 -0
  504. package/src/server/memory-watchdog.ts +156 -0
  505. package/src/server/port-reclaim.ts +307 -0
  506. package/src/server/ports.ts +156 -0
  507. package/src/server/proxy-liveness.ts +326 -0
  508. package/src/server/proxy-stop.ts +92 -0
  509. package/src/server/readiness.ts +99 -0
  510. package/src/server/relay-eager.ts +353 -0
  511. package/src/server/relay.ts +1179 -0
  512. package/src/server/request-decompress.ts +132 -0
  513. package/src/server/request-log-conversation.ts +168 -0
  514. package/src/server/request-log.ts +1072 -0
  515. package/src/server/responses/collaboration.ts +409 -0
  516. package/src/server/responses/compact.ts +710 -0
  517. package/src/server/responses/core.ts +3561 -0
  518. package/src/server/responses/encrypted-payload.ts +308 -0
  519. package/src/server/responses/fetch-helpers.ts +171 -0
  520. package/src/server/responses/passthrough-error.ts +78 -0
  521. package/src/server/responses/policy-fallback.ts +152 -0
  522. package/src/server/responses/terminal-guard.ts +230 -0
  523. package/src/server/responses/upstream-error.ts +48 -0
  524. package/src/server/responses-image-gen-repair.ts +132 -0
  525. package/src/server/responses-item-id-repair.ts +272 -0
  526. package/src/server/responses-json-events.ts +52 -0
  527. package/src/server/responses-model-rewrite.ts +29 -0
  528. package/src/server/responses-snapshot-repair.ts +621 -0
  529. package/src/server/responses.ts +10 -0
  530. package/src/server/search.ts +181 -0
  531. package/src/server/sse-frame-buffer.ts +292 -0
  532. package/src/server/sse-payload-rewrite.ts +263 -0
  533. package/src/server/startup-action-control.ts +308 -0
  534. package/src/server/startup-health-cache.ts +119 -0
  535. package/src/server/system-env.ts +418 -0
  536. package/src/server/windows-tcp-drop.ts +184 -0
  537. package/src/server/windows-tray-control.ts +41 -0
  538. package/src/server/ws-bridge.ts +470 -0
  539. package/src/service-manager-probe.ts +824 -0
  540. package/src/service.ts +3011 -0
  541. package/src/stall-timeout.ts +20 -0
  542. package/src/storage/cleanup-job.ts +57 -0
  543. package/src/storage/cleanup.ts +3085 -0
  544. package/src/storage/policy-job.ts +457 -0
  545. package/src/storage/policy-scheduler.ts +40 -0
  546. package/src/storage/policy-worker.ts +59 -0
  547. package/src/storage/policy.ts +527 -0
  548. package/src/storage/restore-job.ts +299 -0
  549. package/src/storage/restore-worker.ts +58 -0
  550. package/src/storage/scanner.ts +238 -0
  551. package/src/storage/storage-mutation-coordinator.ts +139 -0
  552. package/src/storage/worker-lifecycle.ts +215 -0
  553. package/src/tray/assets/opencodex-tray-offline.ico +0 -0
  554. package/src/tray/assets/opencodex-tray-online.ico +0 -0
  555. package/src/tray/assets/opencodex-tray-warning.ico +0 -0
  556. package/src/tray/assets/opencodex-tray.png +0 -0
  557. package/src/tray/windows-tray.ps1 +364 -0
  558. package/src/tray/windows.ts +738 -0
  559. package/src/types.ts +1531 -0
  560. package/src/update/badge.ts +72 -0
  561. package/src/update/desktop-release.ts +1620 -0
  562. package/src/update/index.ts +402 -0
  563. package/src/update/job.ts +1906 -0
  564. package/src/update/notify.ts +261 -0
  565. package/src/update/npm-cache-preflight.d.mts +47 -0
  566. package/src/update/npm-cache-preflight.mjs +201 -0
  567. package/src/update/npm-invocation.d.mts +23 -0
  568. package/src/update/npm-invocation.mjs +94 -0
  569. package/src/update/tray-update-plan.d.mts +18 -0
  570. package/src/update/tray-update-plan.mjs +38 -0
  571. package/src/usage/cost.ts +0 -0
  572. package/src/usage/debug.ts +97 -0
  573. package/src/usage/expected-prices.ts +283 -0
  574. package/src/usage/log.ts +695 -0
  575. package/src/usage/summary.ts +585 -0
  576. package/src/usage/totals.ts +14 -0
  577. package/src/vision/anthropic-describe.ts +185 -0
  578. package/src/vision/describe.ts +127 -0
  579. package/src/vision/index.ts +558 -0
  580. package/src/vision/reasoning.ts +55 -0
  581. package/src/web-search/anthropic-executor.ts +189 -0
  582. package/src/web-search/executor.ts +105 -0
  583. package/src/web-search/format-result.ts +89 -0
  584. package/src/web-search/index.ts +196 -0
  585. package/src/web-search/loop.ts +791 -0
  586. package/src/web-search/parse.ts +235 -0
  587. package/src/web-search/progress-stream.ts +342 -0
  588. package/src/web-search/synthetic-tool.ts +47 -0
@@ -0,0 +1,521 @@
1
+ /**
2
+ * Narrow, current-user lifecycle support for the official Codex/ChatGPT desktop
3
+ * client. This is intentionally separate from app-server restart: closing the
4
+ * full GUI can discard unsaved input, so only the explicitly confirmed desktop
5
+ * tray action calls this module.
6
+ *
7
+ * There is no broad process-name kill. We require a supported absolute install
8
+ * path, reject Electron helper command lines, revalidate pid + command identity
9
+ * immediately before requesting a graceful close, and never escalate to a
10
+ * forced kill.
11
+ */
12
+ import { execFileSync, spawn } from "node:child_process";
13
+ import { readdirSync, readFileSync, readlinkSync } from "node:fs";
14
+ import { basename, dirname, join } from "node:path";
15
+ import { waitForExit } from "../lib/process-control";
16
+ import { tokenizeCommandLine } from "./app-server-processes";
17
+
18
+ export type DesktopClientProduct = "codex" | "chatgpt";
19
+
20
+ export interface DesktopClientSnapshot {
21
+ pid: number;
22
+ commandLine: string;
23
+ executablePath: string;
24
+ uid?: number;
25
+ owner?: string;
26
+ }
27
+
28
+ export interface DesktopClientProcess extends DesktopClientSnapshot {
29
+ product: DesktopClientProduct;
30
+ }
31
+
32
+ export interface DesktopClientProcessIo {
33
+ platform?: NodeJS.Platform;
34
+ getuid?: () => number | undefined;
35
+ listSnapshots?: () => DesktopClientSnapshot[];
36
+ }
37
+
38
+ export interface RestartDesktopClientIo {
39
+ listProcesses?: () => DesktopClientProcess[];
40
+ requestClose?: (target: DesktopClientProcess) => void;
41
+ waitExit?: (pid: number, timeoutMs: number) => boolean;
42
+ launch?: (target: DesktopClientProcess) => void | Promise<void>;
43
+ platform?: NodeJS.Platform;
44
+ /** Test seam for the bounded post-launch process check. */
45
+ replacementTimeoutMs?: number;
46
+ replacementPollIntervalMs?: number;
47
+ sleep?: (milliseconds: number) => Promise<void>;
48
+ now?: () => number;
49
+ }
50
+
51
+ export type RestartDesktopClientResult =
52
+ | { ok: true; target: DesktopClientProcess }
53
+ | { ok: false; reason: "not_running" | "ambiguous" | "target_changed" | "close_failed" | "still_running" | "launch_failed"; message: string };
54
+
55
+ function normalizedPath(path: string): string {
56
+ return path.trim().replace(/\\/g, "/");
57
+ }
58
+
59
+ function supportedProduct(executablePath: string, platform: NodeJS.Platform): DesktopClientProduct | null {
60
+ const normalized = normalizedPath(executablePath);
61
+ const lower = normalized.toLowerCase();
62
+ const executable = basename(lower);
63
+ const product: DesktopClientProduct | null = executable === "codex" || executable === "codex.exe"
64
+ ? "codex"
65
+ : executable === "chatgpt" || executable === "chatgpt.exe"
66
+ ? "chatgpt"
67
+ : null;
68
+ if (!product) return null;
69
+
70
+ if (platform === "darwin") {
71
+ return /^\/(?:applications|users\/[^/]+\/applications)\/(?:codex|chatgpt)[.]app\/contents\/macos\/(?:codex|chatgpt)$/i.test(normalized)
72
+ ? product
73
+ : null;
74
+ }
75
+ if (platform === "win32") {
76
+ if (!/^[a-z]:\//i.test(normalized)) return null;
77
+ return /\/(?:program files(?: \(x86\))?|users\/[^/]+\/appdata\/local\/programs|windowsapps)\//i.test(normalized)
78
+ && /(?:\/|[.])(?:codex|chatgpt)(?:\/|_|[.])/i.test(normalized)
79
+ ? product
80
+ : null;
81
+ }
82
+ if (!/^(?:\/usr\/|\/opt\/|\/snap\/|\/var\/lib\/flatpak\/)/.test(lower)) return null;
83
+ const segments = lower.split("/").filter(Boolean);
84
+ const parent = segments.at(-2);
85
+ return parent === "codex" || parent === "chatgpt" ? product : null;
86
+ }
87
+
88
+ /** True only for a top-level supported desktop executable, never an Electron helper. */
89
+ export function classifyDesktopClientSnapshot(
90
+ snapshot: DesktopClientSnapshot,
91
+ platform: NodeJS.Platform = process.platform,
92
+ ): DesktopClientProcess | null {
93
+ if (!Number.isSafeInteger(snapshot.pid) || snapshot.pid <= 1) return null;
94
+ const product = supportedProduct(snapshot.executablePath, platform);
95
+ if (!product) return null;
96
+ const tokens = tokenizeCommandLine(snapshot.commandLine);
97
+ if (tokens.length === 0) return null;
98
+ if (normalizedPath(tokens[0]!).toLowerCase() !== normalizedPath(snapshot.executablePath).toLowerCase()) {
99
+ return null;
100
+ }
101
+ if (tokens.slice(1).some(token => {
102
+ const lower = token.toLowerCase();
103
+ return lower.startsWith("--type=")
104
+ || lower.startsWith("--utility-sub-type=")
105
+ || lower.includes("crashpad-handler")
106
+ || lower === "app-server"
107
+ || lower.includes("code-mode-host");
108
+ })) {
109
+ return null;
110
+ }
111
+ return { ...snapshot, product };
112
+ }
113
+
114
+ function parseProcUid(status: string): number | undefined {
115
+ const match = /^Uid:\s+(\d+)/m.exec(status);
116
+ const uid = match ? Number(match[1]) : NaN;
117
+ return Number.isSafeInteger(uid) ? uid : undefined;
118
+ }
119
+
120
+ function listLinuxSnapshots(uid: number): DesktopClientSnapshot[] {
121
+ const snapshots: DesktopClientSnapshot[] = [];
122
+ for (const entry of readdirSync("/proc")) {
123
+ if (!/^\d+$/.test(entry)) continue;
124
+ const pid = Number(entry);
125
+ if (!Number.isSafeInteger(pid) || pid <= 1) continue;
126
+ try {
127
+ const processUid = parseProcUid(readFileSync(`/proc/${pid}/status`, "utf8"));
128
+ if (processUid !== uid) continue;
129
+ const executablePath = readlinkSync(`/proc/${pid}/exe`);
130
+ const commandLine = readFileSync(`/proc/${pid}/cmdline`, "utf8")
131
+ .replace(/\0/g, " ")
132
+ .trim();
133
+ if (!commandLine) continue;
134
+ snapshots.push({ pid, commandLine, executablePath, uid: processUid });
135
+ } catch {
136
+ /* Process exited or became unreadable during the scan. */
137
+ }
138
+ }
139
+ return snapshots;
140
+ }
141
+
142
+ function listDarwinSnapshots(uid: number): DesktopClientSnapshot[] {
143
+ const output = execFileSync("ps", ["-u", String(uid), "-o", "pid=,command="], {
144
+ encoding: "utf8",
145
+ stdio: ["ignore", "pipe", "ignore"],
146
+ timeout: 5_000,
147
+ });
148
+ const snapshots: DesktopClientSnapshot[] = [];
149
+ for (const raw of output.split(/\r?\n/)) {
150
+ const match = /^\s*(\d+)\s+(.+)$/.exec(raw);
151
+ if (!match) continue;
152
+ const pid = Number(match[1]);
153
+ const commandLine = match[2]!.trim();
154
+ const executablePath = tokenizeCommandLine(commandLine)[0];
155
+ if (!Number.isSafeInteger(pid) || pid <= 1 || !executablePath) continue;
156
+ snapshots.push({ pid, commandLine, executablePath, uid });
157
+ }
158
+ return snapshots;
159
+ }
160
+
161
+ function listWindowsSnapshots(): DesktopClientSnapshot[] {
162
+ const script = [
163
+ "$ErrorActionPreference='SilentlyContinue'",
164
+ "$me=[System.Security.Principal.WindowsIdentity]::GetCurrent().Name",
165
+ "Get-CimInstance Win32_Process | Where-Object { $_.Name -in @('Codex.exe','ChatGPT.exe') } | ForEach-Object {",
166
+ " $o=Invoke-CimMethod -InputObject $_ -MethodName GetOwner -ErrorAction SilentlyContinue",
167
+ " if($null -eq $o -or $o.ReturnValue -ne 0){return}",
168
+ " $owner=if($o.Domain){\"$($o.Domain)\\$($o.User)\"}else{$o.User}",
169
+ " if($owner -ine $me -or [string]::IsNullOrWhiteSpace($_.ExecutablePath) -or [string]::IsNullOrWhiteSpace($_.CommandLine)){return}",
170
+ " $cmd=($_.CommandLine -replace \"`t\",\" \" -replace \"`r|`n\",\" \" )",
171
+ " \"{0}`t{1}`t{2}`t{3}\" -f $_.ProcessId,$_.ExecutablePath,$cmd,$owner",
172
+ "}",
173
+ ].join("\n");
174
+ const output = execFileSync("powershell.exe", [
175
+ "-NoProfile", "-NoLogo", "-NonInteractive", "-WindowStyle", "Hidden", "-Command", script,
176
+ ], {
177
+ encoding: "utf8",
178
+ stdio: ["ignore", "pipe", "ignore"],
179
+ timeout: 8_000,
180
+ windowsHide: true,
181
+ });
182
+ const snapshots: DesktopClientSnapshot[] = [];
183
+ for (const raw of output.split(/\r?\n/)) {
184
+ const [pidRaw, executablePath, commandLine, owner] = raw.split("\t", 4);
185
+ const pid = Number(pidRaw);
186
+ if (!Number.isSafeInteger(pid) || pid <= 1 || !executablePath || !commandLine || !owner) continue;
187
+ snapshots.push({ pid, executablePath, commandLine, owner });
188
+ }
189
+ return snapshots;
190
+ }
191
+
192
+ function currentUid(getuid?: () => number | undefined): number | undefined {
193
+ try {
194
+ return (getuid ?? (() => typeof process.getuid === "function" ? process.getuid() : undefined))();
195
+ } catch {
196
+ return undefined;
197
+ }
198
+ }
199
+
200
+ /** Enumerate only identity-checked top-level clients owned by the current user. */
201
+ export function listDesktopClientProcesses(io: DesktopClientProcessIo = {}): DesktopClientProcess[] {
202
+ const platform = io.platform ?? process.platform;
203
+ let snapshots: DesktopClientSnapshot[];
204
+ try {
205
+ if (io.listSnapshots) snapshots = io.listSnapshots();
206
+ else if (platform === "win32") snapshots = listWindowsSnapshots();
207
+ else {
208
+ const uid = currentUid(io.getuid);
209
+ if (uid === undefined) return [];
210
+ snapshots = platform === "darwin" ? listDarwinSnapshots(uid) : listLinuxSnapshots(uid);
211
+ }
212
+ } catch {
213
+ return [];
214
+ }
215
+ const seen = new Set<number>();
216
+ const matched: DesktopClientProcess[] = [];
217
+ for (const snapshot of snapshots) {
218
+ if (seen.has(snapshot.pid)) continue;
219
+ const process = classifyDesktopClientSnapshot(snapshot, platform);
220
+ if (!process) continue;
221
+ seen.add(process.pid);
222
+ matched.push(process);
223
+ }
224
+ return matched;
225
+ }
226
+
227
+ export function desktopClientProcessIdentity(target: DesktopClientProcess): string {
228
+ return `${target.pid}\0${normalizedPath(target.executablePath).toLowerCase()}\0${target.commandLine.trim().replace(/\s+/g, " ")}`;
229
+ }
230
+
231
+ function defaultRequestClose(target: DesktopClientProcess, platform: NodeJS.Platform): void {
232
+ if (platform !== "win32") {
233
+ process.kill(target.pid, "SIGTERM");
234
+ return;
235
+ }
236
+ const script = [
237
+ `$p=Get-Process -Id ${target.pid} -ErrorAction Stop`,
238
+ "if(-not $p.CloseMainWindow()){exit 4}",
239
+ ].join(";");
240
+ execFileSync("powershell.exe", [
241
+ "-NoProfile", "-NoLogo", "-NonInteractive", "-WindowStyle", "Hidden", "-Command", script,
242
+ ], { stdio: "ignore", timeout: 5_000, windowsHide: true });
243
+ }
244
+
245
+ function macosAppBundle(executablePath: string): string | null {
246
+ const normalized = normalizedPath(executablePath);
247
+ const marker = normalized.toLowerCase().indexOf(".app/contents/macos/");
248
+ return marker < 0 ? null : normalized.slice(0, marker + 4);
249
+ }
250
+
251
+ function windowsExplorerPath(): string {
252
+ const root = process.env.SystemRoot?.trim() || process.env.WINDIR?.trim() || "C:\\Windows";
253
+ return join(root, "explorer.exe");
254
+ }
255
+
256
+ function powershellSingleQuoted(value: string): string {
257
+ return value.replace(/'/g, "''");
258
+ }
259
+
260
+ export function isValidWindowsAppUserModelId(
261
+ value: string,
262
+ product?: DesktopClientProduct,
263
+ ): boolean {
264
+ if (!/^[A-Za-z0-9._~-]{1,255}![A-Za-z0-9._~-]{1,255}$/.test(value)) return false;
265
+ if (!product) return true;
266
+ const lower = value.toLowerCase();
267
+ return lower.includes(product) || lower.includes("openai");
268
+ }
269
+
270
+ /**
271
+ * Resolve a packaged executable to exactly one current-user AUMID. The path
272
+ * match is preferred; the Start-menu AppID fallback covers execution aliases
273
+ * under AppData\Local\Microsoft\WindowsApps.
274
+ */
275
+ export function windowsAppUserModelIdDiscoveryScript(target: DesktopClientProcess): string {
276
+ const executable = powershellSingleQuoted(target.executablePath);
277
+ const productName = target.product === "chatgpt" ? "ChatGPT" : "Codex";
278
+ return [
279
+ "$ErrorActionPreference='SilentlyContinue'",
280
+ `$target=[IO.Path]::GetFullPath('${executable}')`,
281
+ `$product='${productName}'`,
282
+ "$ids=@()",
283
+ "foreach($package in @(Get-AppxPackage)){",
284
+ " $location=[string]$package.InstallLocation",
285
+ " if([string]::IsNullOrWhiteSpace($location)){continue}",
286
+ " try{$root=[IO.Path]::GetFullPath($location).TrimEnd('\\')+'\\'}catch{continue}",
287
+ " if(-not $target.StartsWith($root,[StringComparison]::OrdinalIgnoreCase)){continue}",
288
+ " $manifest=Get-AppxPackageManifest -Package $package",
289
+ " foreach($application in @($manifest.Package.Applications.Application)){",
290
+ " $relative=[string]$application.Executable",
291
+ " if([string]::IsNullOrWhiteSpace($relative)){continue}",
292
+ " try{$candidate=[IO.Path]::GetFullPath((Join-Path $location $relative))}catch{continue}",
293
+ " if([string]::Equals($candidate,$target,[StringComparison]::OrdinalIgnoreCase)){",
294
+ " $ids += \"$($package.PackageFamilyName)!$($application.Id)\"",
295
+ " }",
296
+ " }",
297
+ "}",
298
+ "if($ids.Count -eq 0){",
299
+ " $ids += @(Get-StartApps | Where-Object {$_.Name -ieq $product} | ForEach-Object {[string]$_.AppID})",
300
+ "}",
301
+ "$ids=@($ids | Where-Object {-not [string]::IsNullOrWhiteSpace($_)} | Sort-Object -Unique)",
302
+ "if($ids.Count -ne 1){exit 3}",
303
+ "[Console]::Out.Write($ids[0])",
304
+ ].join("\n");
305
+ }
306
+
307
+ function resolveWindowsAppUserModelId(target: DesktopClientProcess): string | null {
308
+ const script = windowsAppUserModelIdDiscoveryScript(target);
309
+ const encoded = Buffer.from(script, "utf16le").toString("base64");
310
+ try {
311
+ const value = execFileSync("powershell.exe", [
312
+ "-NoProfile",
313
+ "-NoLogo",
314
+ "-NonInteractive",
315
+ "-EncodedCommand",
316
+ encoded,
317
+ ], {
318
+ encoding: "utf8",
319
+ stdio: ["ignore", "pipe", "ignore"],
320
+ timeout: 8_000,
321
+ windowsHide: true,
322
+ }).trim();
323
+ return isValidWindowsAppUserModelId(value, target.product) ? value : null;
324
+ } catch {
325
+ return null;
326
+ }
327
+ }
328
+
329
+ function spawnDetached(
330
+ command: string,
331
+ args: readonly string[],
332
+ options: { cwd?: string; windowsHide?: boolean } = {},
333
+ ): Promise<void> {
334
+ return new Promise((resolve, reject) => {
335
+ let child;
336
+ try {
337
+ child = spawn(command, [...args], {
338
+ cwd: options.cwd,
339
+ detached: true,
340
+ stdio: "ignore",
341
+ windowsHide: options.windowsHide,
342
+ });
343
+ } catch (error) {
344
+ reject(error);
345
+ return;
346
+ }
347
+
348
+ let settled = false;
349
+ // Keep the listener attached after a successful `spawn` event. A late
350
+ // platform error must be consumed rather than becoming an uncaught
351
+ // exception in the tray action process.
352
+ child.once("error", error => {
353
+ if (settled) return;
354
+ settled = true;
355
+ reject(error);
356
+ });
357
+ child.once("spawn", () => {
358
+ if (settled) return;
359
+ settled = true;
360
+ child.unref();
361
+ resolve();
362
+ });
363
+ });
364
+ }
365
+
366
+ async function defaultLaunch(target: DesktopClientProcess, platform: NodeJS.Platform): Promise<void> {
367
+ if (platform === "darwin") {
368
+ const bundle = macosAppBundle(target.executablePath);
369
+ if (!bundle) throw new Error("desktop app bundle could not be resolved");
370
+ await spawnDetached("open", ["-n", bundle], {
371
+ cwd: dirname(bundle),
372
+ windowsHide: true,
373
+ });
374
+ return;
375
+ }
376
+
377
+ if (platform === "win32") {
378
+ const appUserModelId = resolveWindowsAppUserModelId(target);
379
+ if (appUserModelId) {
380
+ try {
381
+ await spawnDetached(
382
+ windowsExplorerPath(),
383
+ [`shell:AppsFolder\\${appUserModelId}`],
384
+ {
385
+ cwd: dirname(windowsExplorerPath()),
386
+ windowsHide: true,
387
+ },
388
+ );
389
+ return;
390
+ } catch {
391
+ // Continue to the identity-checked executable fallbacks below. The
392
+ // post-launch process verification still decides whether restart
393
+ // actually succeeded.
394
+ }
395
+ }
396
+ try {
397
+ await spawnDetached(target.executablePath, [], {
398
+ cwd: dirname(target.executablePath),
399
+ windowsHide: false,
400
+ });
401
+ } catch (directError) {
402
+ // Packaged WindowsApps/MSIX launches can reject a direct executable
403
+ // request even though Explorer can activate the registered app. The
404
+ // path was already identity-checked, so this fallback does not broaden
405
+ // which application may be started.
406
+ try {
407
+ await spawnDetached(windowsExplorerPath(), [target.executablePath], {
408
+ cwd: dirname(windowsExplorerPath()),
409
+ windowsHide: true,
410
+ });
411
+ } catch (fallbackError) {
412
+ throw new Error(
413
+ `direct launch failed: ${directError instanceof Error ? directError.message : String(directError)}; ` +
414
+ `Explorer fallback failed: ${fallbackError instanceof Error ? fallbackError.message : String(fallbackError)}`,
415
+ );
416
+ }
417
+ }
418
+ return;
419
+ }
420
+
421
+ await spawnDetached(target.executablePath, [], {
422
+ cwd: dirname(target.executablePath),
423
+ windowsHide: true,
424
+ });
425
+ }
426
+
427
+ function replacementFor(
428
+ processes: DesktopClientProcess[],
429
+ target: DesktopClientProcess,
430
+ ): DesktopClientProcess | null {
431
+ const executable = normalizedPath(target.executablePath).toLowerCase();
432
+ return processes.find(candidate =>
433
+ candidate.pid !== target.pid
434
+ && candidate.product === target.product
435
+ && normalizedPath(candidate.executablePath).toLowerCase() === executable,
436
+ ) ?? null;
437
+ }
438
+
439
+ async function waitForReplacement(
440
+ list: () => DesktopClientProcess[],
441
+ target: DesktopClientProcess,
442
+ options: Pick<RestartDesktopClientIo, "replacementTimeoutMs" | "replacementPollIntervalMs" | "sleep" | "now"> = {},
443
+ ): Promise<DesktopClientProcess | null> {
444
+ const timeoutMs = Math.max(0, options.replacementTimeoutMs ?? 10_000);
445
+ const intervalMs = Math.max(1, options.replacementPollIntervalMs ?? 100);
446
+ const now = options.now ?? Date.now;
447
+ const sleep = options.sleep ?? ((milliseconds: number) => new Promise<void>(resolve => {
448
+ setTimeout(resolve, milliseconds);
449
+ }));
450
+ const deadline = now() + timeoutMs;
451
+ // The attempt cap keeps injected clocks/sleeps from creating an accidental
452
+ // infinite loop while retaining a time-based bound in production.
453
+ const maxAttempts = Math.max(1, Math.ceil(timeoutMs / intervalMs) + 1);
454
+
455
+ for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
456
+ try {
457
+ const replacement = replacementFor(list(), target);
458
+ if (replacement) return replacement;
459
+ } catch {
460
+ // A process enumeration race is normal while an app is exiting/starting.
461
+ // Keep polling until the bounded deadline rather than reporting a false
462
+ // success or crashing the action worker.
463
+ }
464
+ const remaining = deadline - now();
465
+ if (remaining <= 0) break;
466
+ await sleep(Math.min(intervalMs, remaining));
467
+ }
468
+ return null;
469
+ }
470
+
471
+ /** Gracefully close and relaunch exactly one supported desktop client. */
472
+ export async function restartDesktopClient(
473
+ io: RestartDesktopClientIo = {},
474
+ ): Promise<RestartDesktopClientResult> {
475
+ const platform = io.platform ?? process.platform;
476
+ const list = io.listProcesses ?? (() => listDesktopClientProcesses({ platform }));
477
+ const targets = list();
478
+ if (targets.length === 0) {
479
+ return { ok: false, reason: "not_running", message: "No supported Codex/ChatGPT desktop application is running." };
480
+ }
481
+ if (targets.length !== 1) {
482
+ return { ok: false, reason: "ambiguous", message: "Multiple desktop applications matched; close and reopen the intended one manually." };
483
+ }
484
+ const target = targets[0]!;
485
+ const current = list().find(candidate => candidate.pid === target.pid);
486
+ if (!current || desktopClientProcessIdentity(current) !== desktopClientProcessIdentity(target)) {
487
+ return { ok: false, reason: "target_changed", message: "The desktop application changed before restart; nothing was closed." };
488
+ }
489
+ try {
490
+ (io.requestClose ?? (candidate => defaultRequestClose(candidate, platform)))(target);
491
+ } catch (error) {
492
+ return {
493
+ ok: false,
494
+ reason: "close_failed",
495
+ message: `The desktop application did not accept a graceful close: ${error instanceof Error ? error.message : String(error)}`,
496
+ };
497
+ }
498
+ const exited = (io.waitExit ?? waitForExit)(target.pid, 8_000);
499
+ if (!exited) {
500
+ return { ok: false, reason: "still_running", message: "The desktop application is still running; no force-close was attempted." };
501
+ }
502
+ try {
503
+ await (io.launch ?? (candidate => defaultLaunch(candidate, platform)))(target);
504
+ } catch (error) {
505
+ return {
506
+ ok: false,
507
+ reason: "launch_failed",
508
+ message: `The desktop application closed but could not be relaunched: ${error instanceof Error ? error.message : String(error)}`,
509
+ };
510
+ }
511
+
512
+ const replacement = await waitForReplacement(list, target, io);
513
+ if (!replacement) {
514
+ return {
515
+ ok: false,
516
+ reason: "launch_failed",
517
+ message: "The desktop application launch was requested, but no replacement process appeared within 10 seconds.",
518
+ };
519
+ }
520
+ return { ok: true, target };
521
+ }
@@ -0,0 +1,22 @@
1
+ import { commandInvocation, type ResolveDeps, type SpawnInvocation } from "../lib/win-exec";
2
+
3
+ export function isSpawnableCodexCandidate(path: string, platform: NodeJS.Platform = process.platform): boolean {
4
+ if (platform !== "win32") return true;
5
+ return /\.(cmd|bat|exe|com)$/i.test(path);
6
+ }
7
+
8
+ /**
9
+ * Platform-safe Codex launcher invocation.
10
+ *
11
+ * Windows `.cmd`/`.bat` must go through `cmd.exe`, but never via `shell: true`
12
+ * (Node does not escape cmd metacharacters there). Reuse the shared
13
+ * `commandInvocation` helper (`ComSpec /d /s /c` + cross-spawn escaping).
14
+ */
15
+ export function codexExecInvocation(
16
+ command: string,
17
+ args: readonly string[],
18
+ platform: NodeJS.Platform = process.platform,
19
+ deps: ResolveDeps = {},
20
+ ): SpawnInvocation {
21
+ return commandInvocation(command, args, platform, deps);
22
+ }