@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,443 @@
1
+ import { open, readFile } from "node:fs/promises";
2
+ import { basename, join } from "node:path";
3
+ import { getCodexHome } from "../codex/paths";
4
+ import { resolveThreadSourcePaths } from "./thread-source-paths";
5
+ import { boundedTurnErrorMessage } from "./turn-activity";
6
+
7
+ type JsonRecord = Record<string, unknown>;
8
+
9
+ export const DESKTOP_CODEX_PROJECT_ID_PREFIX = "codex-desktop-project-";
10
+ const SESSION_ACTIVITY_SCAN_CHUNK_BYTES = 256 * 1024;
11
+ const SESSION_ACTIVITY_SCAN_LIMIT = 50;
12
+ const DESKTOP_RUNNING_MARKER_FRESH_MS = 30_000;
13
+
14
+ export type DesktopTaskActivityOptions = {
15
+ now?: () => number;
16
+ isThreadActive?: (threadId: string) => Promise<boolean | null>;
17
+ runningMarkerFreshMs?: number;
18
+ };
19
+
20
+ /** The small, presentation-safe project shape exposed by Codex Desktop. */
21
+ export type DesktopWorkspaceProject = {
22
+ readonly id: string;
23
+ readonly title: string;
24
+ readonly workspaceRoot: string;
25
+ readonly createdAt?: string;
26
+ };
27
+
28
+ export type DesktopWorkspaceSnapshot = {
29
+ readonly threads: JsonRecord[];
30
+ readonly projects: DesktopWorkspaceProject[];
31
+ };
32
+
33
+ type DesktopTaskActivity = {
34
+ state: "running" | "completed" | "interrupted" | "error";
35
+ turnId: string;
36
+ occurredAt: string;
37
+ errorMessage: string | null;
38
+ waitingOnUserInput: boolean;
39
+ pendingUserInput: DesktopPendingUserInput | null;
40
+ };
41
+
42
+ type DesktopPendingUserInput = {
43
+ itemId: string;
44
+ callId: string;
45
+ requestedAt: string;
46
+ questions: Array<{
47
+ id: string;
48
+ header: string;
49
+ question: string;
50
+ options: Array<{ label: string; description: string }>;
51
+ multiSelect: false;
52
+ }>;
53
+ };
54
+
55
+ const desktopTaskActivityCache = new Map<string, {
56
+ size: number;
57
+ activity: DesktopTaskActivity | null;
58
+ }>();
59
+
60
+ function record(value: unknown): JsonRecord | null {
61
+ return value && typeof value === "object" && !Array.isArray(value)
62
+ ? value as JsonRecord
63
+ : null;
64
+ }
65
+
66
+ function text(value: unknown): string {
67
+ return typeof value === "string" ? value.trim() : "";
68
+ }
69
+
70
+ function desktopProjectsFromState(stateValue: unknown): DesktopWorkspaceProject[] {
71
+ const state = record(stateValue);
72
+ const projects = record(state?.["local-projects"]);
73
+ if (!projects) return [];
74
+ const result: DesktopWorkspaceProject[] = [];
75
+ const seen = new Set<string>();
76
+ for (const [key, value] of Object.entries(projects)) {
77
+ const project = record(value);
78
+ if (!project) continue;
79
+ const id = text(project.id) || key;
80
+ const roots = Array.isArray(project.rootPaths)
81
+ ? project.rootPaths.flatMap(candidate => text(candidate) ? [text(candidate)] : [])
82
+ : [];
83
+ const workspaceRoot = roots[0] ?? "";
84
+ if (!id || !workspaceRoot) continue;
85
+ const projectId = `${DESKTOP_CODEX_PROJECT_ID_PREFIX}${id}`;
86
+ if (seen.has(projectId)) continue;
87
+ seen.add(projectId);
88
+ result.push({
89
+ id: projectId,
90
+ title: text(project.name) || basename(workspaceRoot),
91
+ workspaceRoot,
92
+ ...(text(project.createdAt) ? { createdAt: text(project.createdAt) } : {}),
93
+ });
94
+ }
95
+ return result;
96
+ }
97
+
98
+ function desktopWorkspaceSnapshotFromState(
99
+ threads: readonly JsonRecord[],
100
+ stateValue: unknown,
101
+ ): DesktopWorkspaceSnapshot {
102
+ const state = record(stateValue);
103
+ const projects = record(state?.["local-projects"]);
104
+ const assignments = record(state?.["thread-project-assignments"]);
105
+ if (!projects || !assignments) {
106
+ return { threads: [...threads], projects: desktopProjectsFromState(stateValue) };
107
+ }
108
+
109
+ const projectedThreads = threads.map(thread => {
110
+ const nativeThreadId = text(thread.androidRemoteNativeThreadId) || text(thread.id);
111
+ const assignment = record(assignments[nativeThreadId]);
112
+ if (text(assignment?.projectKind) !== "local") return thread;
113
+ const desktopProjectId = text(assignment?.projectId);
114
+ const project = record(projects[desktopProjectId]);
115
+ if (!desktopProjectId || !project) return thread;
116
+ const rootPaths = Array.isArray(project.rootPaths)
117
+ ? project.rootPaths.flatMap(value => text(value) ? [text(value)] : [])
118
+ : [];
119
+ return {
120
+ ...thread,
121
+ androidRemoteProjectId: `${DESKTOP_CODEX_PROJECT_ID_PREFIX}${desktopProjectId}`,
122
+ androidRemoteProjectTitle: text(project.name) || "Codex project",
123
+ androidRemoteProjectWorkspaceRoot: text(assignment?.cwd) || rootPaths[0] || text(thread.cwd),
124
+ };
125
+ });
126
+ return { threads: projectedThreads, projects: desktopProjectsFromState(stateValue) };
127
+ }
128
+
129
+ function parsedLine(line: string): JsonRecord | null {
130
+ let row: JsonRecord | null;
131
+ try {
132
+ row = record(JSON.parse(line));
133
+ } catch {
134
+ return null;
135
+ }
136
+ return row;
137
+ }
138
+
139
+ function activityFromRow(
140
+ row: JsonRecord,
141
+ waitingOnUserInput: boolean,
142
+ pendingUserInput: DesktopPendingUserInput | null,
143
+ ): DesktopTaskActivity | null {
144
+ if (row?.type !== "event_msg") return null;
145
+ const payload = record(row.payload);
146
+ const event = text(payload?.type);
147
+ const errorMessage = event === "task_complete"
148
+ ? boundedTurnErrorMessage(payload?.error)
149
+ : "";
150
+ const state = event === "task_started"
151
+ ? "running"
152
+ : event === "task_complete"
153
+ ? errorMessage ? "error" : "completed"
154
+ : event === "turn_aborted"
155
+ ? "interrupted"
156
+ : null;
157
+ if (!state) return null;
158
+ return {
159
+ state,
160
+ turnId: text(payload?.turn_id),
161
+ occurredAt: text(row.timestamp),
162
+ errorMessage: errorMessage || null,
163
+ waitingOnUserInput: state === "running" && waitingOnUserInput,
164
+ pendingUserInput: state === "running" && waitingOnUserInput ? pendingUserInput : null,
165
+ };
166
+ }
167
+
168
+ function responseCall(row: JsonRecord): {
169
+ type: string;
170
+ name: string;
171
+ itemId: string;
172
+ callId: string;
173
+ arguments: unknown;
174
+ } | null {
175
+ if (row.type !== "response_item") return null;
176
+ const payload = record(row.payload);
177
+ if (!payload) return null;
178
+ return {
179
+ type: text(payload.type),
180
+ name: text(payload.name),
181
+ itemId: text(payload.id),
182
+ callId: text(payload.call_id),
183
+ arguments: payload.arguments,
184
+ };
185
+ }
186
+
187
+ function pendingUserInputFromCall(row: JsonRecord, call: NonNullable<ReturnType<typeof responseCall>>): DesktopPendingUserInput | null {
188
+ let args: JsonRecord | null = record(call.arguments);
189
+ if (!args && typeof call.arguments === "string") {
190
+ try { args = record(JSON.parse(call.arguments)); }
191
+ catch { return null; }
192
+ }
193
+ const questions = (Array.isArray(args?.questions) ? args.questions : []).flatMap(value => {
194
+ const question = record(value);
195
+ const id = text(question?.id).slice(0, 128);
196
+ const prompt = text(question?.question).slice(0, 2048);
197
+ if (!id || !prompt) return [];
198
+ const options = (Array.isArray(question?.options) ? question.options : []).flatMap(optionValue => {
199
+ const option = record(optionValue);
200
+ const label = text(option?.label).slice(0, 256);
201
+ if (!label) return [];
202
+ return [{
203
+ label,
204
+ description: text(option?.description).slice(0, 1024) || label,
205
+ }];
206
+ });
207
+ return [{
208
+ id,
209
+ header: text(question?.header).slice(0, 256) || "Question",
210
+ question: prompt,
211
+ options,
212
+ multiSelect: false as const,
213
+ }];
214
+ });
215
+ if (!call.itemId || !call.callId || questions.length === 0) return null;
216
+ return {
217
+ itemId: call.itemId.slice(0, 128),
218
+ callId: call.callId.slice(0, 128),
219
+ requestedAt: text(row.timestamp),
220
+ questions,
221
+ };
222
+ }
223
+
224
+ async function scanLatestDesktopTaskActivity(
225
+ file: Awaited<ReturnType<typeof open>>,
226
+ lowerBound: number,
227
+ fileSize: number,
228
+ ): Promise<DesktopTaskActivity | null> {
229
+ let end = fileSize;
230
+ let suffix = "";
231
+ let waitingOnUserInput = false;
232
+ let pendingUserInput: DesktopPendingUserInput | null = null;
233
+ const resolvedCallIds = new Set<string>();
234
+ while (end > lowerBound) {
235
+ const length = Math.min(SESSION_ACTIVITY_SCAN_CHUNK_BYTES, end - lowerBound);
236
+ const start = end - length;
237
+ const chunk = Buffer.allocUnsafe(length);
238
+ const { bytesRead } = await file.read(chunk, 0, length, start);
239
+ const source = chunk.subarray(0, bytesRead).toString("utf8") + suffix;
240
+ const lines = source.split("\n");
241
+ // The first line may start in the middle of a UTF-8 or JSON record.
242
+ const firstCompleteLine = start === lowerBound && lowerBound === 0 ? 0 : 1;
243
+ for (let index = lines.length - 1; index >= firstCompleteLine; index -= 1) {
244
+ const line = lines[index];
245
+ if (!line) continue;
246
+ const row = parsedLine(line);
247
+ if (!row) continue;
248
+ const call = responseCall(row);
249
+ if (call?.type === "function_call_output" && call.callId) {
250
+ resolvedCallIds.add(call.callId);
251
+ } else if (
252
+ call?.type === "function_call"
253
+ && call.name === "request_user_input"
254
+ && call.callId
255
+ && !resolvedCallIds.has(call.callId)
256
+ ) {
257
+ waitingOnUserInput = true;
258
+ pendingUserInput ??= pendingUserInputFromCall(row, call);
259
+ }
260
+ const activity = activityFromRow(row, waitingOnUserInput, pendingUserInput);
261
+ if (activity) return activity;
262
+ }
263
+ suffix = lines[0]?.slice(0, SESSION_ACTIVITY_SCAN_CHUNK_BYTES) ?? "";
264
+ end = start;
265
+ }
266
+ return null;
267
+ }
268
+
269
+ /** Read backwards until the most recent authoritative Desktop task marker is found. */
270
+ async function readLatestDesktopTaskActivity(path: string): Promise<DesktopTaskActivity | null> {
271
+ const file = await open(path, "r");
272
+ try {
273
+ const { size } = await file.stat();
274
+ const cached = desktopTaskActivityCache.get(path);
275
+ if (cached?.size === size) return cached.activity;
276
+
277
+ // Session files are append-only. Once the current marker is known, only
278
+ // inspect newly appended records instead of rescanning a large transcript
279
+ // on every five-second shell refresh.
280
+ if (cached && size > cached.size) {
281
+ const lowerBound = Math.max(0, cached.size - 1_024);
282
+ const probe = Buffer.allocUnsafe(size - lowerBound);
283
+ const { bytesRead } = await file.read(probe, 0, probe.length, lowerBound);
284
+ const appendedText = probe.subarray(0, bytesRead).toString("utf8");
285
+ // A question changes state without emitting a task marker. Re-scan the
286
+ // current turn only for that rare transition so a submitted answer also
287
+ // clears the sidebar badge before the turn completes.
288
+ const questionStateChanged = appendedText.includes('"name":"request_user_input"')
289
+ || (cached.activity?.waitingOnUserInput === true
290
+ && appendedText.includes('"type":"function_call_output"'));
291
+ const appendedActivity = await scanLatestDesktopTaskActivity(
292
+ file,
293
+ questionStateChanged ? 0 : lowerBound,
294
+ size,
295
+ );
296
+ const activity = appendedActivity ?? cached.activity;
297
+ desktopTaskActivityCache.set(path, { size, activity });
298
+ return activity;
299
+ }
300
+
301
+ const activity = await scanLatestDesktopTaskActivity(file, 0, size);
302
+ desktopTaskActivityCache.set(path, { size, activity });
303
+ return activity;
304
+ } finally {
305
+ await file.close();
306
+ }
307
+ }
308
+
309
+ /**
310
+ * Codex's list response deliberately omits turns and reports Desktop-owned
311
+ * tasks as `notLoaded`. The append-only session file still carries exact
312
+ * task_started/task_complete markers, so project those into lightweight rows.
313
+ */
314
+ export async function annotateDesktopTaskActivity(
315
+ threads: readonly JsonRecord[],
316
+ limit = SESSION_ACTIVITY_SCAN_LIMIT,
317
+ options: DesktopTaskActivityOptions = {},
318
+ ): Promise<JsonRecord[]> {
319
+ return Promise.all(threads.map(async (thread, index) => {
320
+ if (index >= limit) return thread;
321
+ try {
322
+ const threadId = text(thread.androidRemoteNativeThreadId) || text(thread.id);
323
+ const explicitPaths = [
324
+ text(thread.path),
325
+ ...(Array.isArray(thread.androidRemoteSourcePaths)
326
+ ? thread.androidRemoteSourcePaths.flatMap(value => {
327
+ const path = text(value);
328
+ return path ? [path] : [];
329
+ })
330
+ : []),
331
+ ];
332
+ if (!threadId || explicitPaths.length === 0) return thread;
333
+ const sourcePaths = await resolveThreadSourcePaths(threadId, explicitPaths, {
334
+ now: options.now,
335
+ discover: false,
336
+ });
337
+ if (sourcePaths.length === 0) return thread;
338
+ const activities = (
339
+ await Promise.all(sourcePaths.map(path => readLatestDesktopTaskActivity(path)))
340
+ ).flatMap(activity => activity ? [activity] : []);
341
+ const activity = activities
342
+ .map((candidate, candidateIndex) => ({
343
+ candidate,
344
+ candidateIndex,
345
+ timestamp: Date.parse(candidate.occurredAt),
346
+ }))
347
+ .sort((left, right) => {
348
+ const leftTimestamp = Number.isFinite(left.timestamp) ? left.timestamp : -Infinity;
349
+ const rightTimestamp = Number.isFinite(right.timestamp) ? right.timestamp : -Infinity;
350
+ return leftTimestamp - rightTimestamp || left.candidateIndex - right.candidateIndex;
351
+ })
352
+ .at(-1)?.candidate;
353
+ if (!activity) return thread;
354
+ if (
355
+ activity.state === "running"
356
+ && !activity.waitingOnUserInput
357
+ && options.isThreadActive
358
+ && runningMarkerIsStale(thread, activity, options)
359
+ ) {
360
+ if (threadId && await options.isThreadActive(threadId) === false) {
361
+ const inactive: JsonRecord = {
362
+ ...thread,
363
+ androidRemoteLatestTurnState: "interrupted",
364
+ androidRemoteLatestTurnId: activity.turnId,
365
+ androidRemoteLatestTurnAt: activity.occurredAt,
366
+ androidRemoteWaitingOnUserInput: false,
367
+ };
368
+ delete inactive.androidRemoteLatestTurnError;
369
+ delete inactive.androidRemotePendingUserInput;
370
+ return inactive;
371
+ }
372
+ }
373
+ const annotated: JsonRecord = {
374
+ ...thread,
375
+ androidRemoteLatestTurnState: activity.state,
376
+ androidRemoteLatestTurnId: activity.turnId,
377
+ androidRemoteLatestTurnAt: activity.occurredAt,
378
+ androidRemoteWaitingOnUserInput: activity.waitingOnUserInput,
379
+ ...(activity.errorMessage
380
+ ? { androidRemoteLatestTurnError: activity.errorMessage }
381
+ : {}),
382
+ ...(activity.pendingUserInput
383
+ ? { androidRemotePendingUserInput: activity.pendingUserInput }
384
+ : {}),
385
+ };
386
+ if (!activity.errorMessage) delete annotated.androidRemoteLatestTurnError;
387
+ if (!activity.pendingUserInput) delete annotated.androidRemotePendingUserInput;
388
+ return annotated;
389
+ } catch {
390
+ return thread;
391
+ }
392
+ }));
393
+ }
394
+
395
+ function runningMarkerIsStale(
396
+ thread: JsonRecord,
397
+ activity: DesktopTaskActivity,
398
+ options: DesktopTaskActivityOptions,
399
+ ): boolean {
400
+ const updatedAt = typeof thread.updatedAt === "number" && Number.isFinite(thread.updatedAt)
401
+ ? (thread.updatedAt > 10_000_000_000 ? thread.updatedAt : thread.updatedAt * 1_000)
402
+ : Date.parse(activity.occurredAt);
403
+ if (!Number.isFinite(updatedAt)) return false;
404
+ const freshMs = Math.max(0, options.runningMarkerFreshMs ?? DESKTOP_RUNNING_MARKER_FRESH_MS);
405
+ return (options.now?.() ?? Date.now()) - updatedAt >= freshMs;
406
+ }
407
+
408
+ /**
409
+ * Apply Codex Desktop's explicit project membership to app-server thread rows.
410
+ * Working-directory equality is not sufficient: projectless Chats can use the
411
+ * same cwd as a real project.
412
+ */
413
+ export function annotateDesktopWorkspaceMembership(
414
+ threads: readonly JsonRecord[],
415
+ stateValue: unknown,
416
+ ): JsonRecord[] {
417
+ return desktopWorkspaceSnapshotFromState(threads, stateValue).threads;
418
+ }
419
+
420
+ /**
421
+ * Read Desktop's registry once and return both explicit projects (including
422
+ * projects with no tasks yet) and the thread membership annotations.
423
+ */
424
+ export async function readDesktopWorkspaceSnapshot(
425
+ threads: readonly JsonRecord[],
426
+ codexHome = getCodexHome(),
427
+ ): Promise<DesktopWorkspaceSnapshot> {
428
+ try {
429
+ const raw = await readFile(join(codexHome, ".codex-global-state.json"), "utf8");
430
+ return desktopWorkspaceSnapshotFromState(threads, JSON.parse(raw));
431
+ } catch {
432
+ // Older Codex builds and non-Desktop hosts may not expose this optional
433
+ // state file. Keep the existing cwd projection in that case.
434
+ return { threads: [...threads], projects: [] };
435
+ }
436
+ }
437
+
438
+ export async function readDesktopWorkspaceMembership(
439
+ threads: readonly JsonRecord[],
440
+ codexHome = getCodexHome(),
441
+ ): Promise<JsonRecord[]> {
442
+ return (await readDesktopWorkspaceSnapshot(threads, codexHome)).threads;
443
+ }
@@ -0,0 +1,112 @@
1
+ type JsonRecord = Record<string, unknown>;
2
+
3
+ export type AndroidRemoteFileChange = {
4
+ path: string;
5
+ kind: { type: "add" | "update" | "delete" };
6
+ diff?: string;
7
+ };
8
+
9
+ const MAX_FILE_CHANGES = 64;
10
+
11
+ function record(value: unknown): JsonRecord | null {
12
+ return value && typeof value === "object" && !Array.isArray(value)
13
+ ? value as JsonRecord
14
+ : null;
15
+ }
16
+
17
+ function stringValue(value: unknown): string {
18
+ return typeof value === "string" ? value : "";
19
+ }
20
+
21
+ function parsedArguments(payload: JsonRecord): JsonRecord {
22
+ const direct = record(payload.arguments);
23
+ if (direct) return direct;
24
+ const encoded = stringValue(payload.arguments);
25
+ if (!encoded) return {};
26
+ try { return record(JSON.parse(encoded)) ?? {}; }
27
+ catch { return {}; }
28
+ }
29
+
30
+ function decodedDoubleQuotedStrings(source: string): string[] {
31
+ const decoded: string[] = [];
32
+ const literals = /"((?:\\[\s\S]|[^"\\])*)"/gu;
33
+ for (const match of source.matchAll(literals)) {
34
+ const body = match[1];
35
+ if (!body || !body.includes("*** ")) continue;
36
+ try {
37
+ const value = JSON.parse(`"${body}"`);
38
+ if (typeof value === "string") decoded.push(value);
39
+ } catch {
40
+ // A malformed or non-JSON JavaScript string is ignored. The original
41
+ // source remains a candidate and can still contain a literal patch.
42
+ }
43
+ }
44
+ return decoded;
45
+ }
46
+
47
+ function patchSources(payload: JsonRecord): string[] {
48
+ const input = stringValue(payload.input);
49
+ const args = parsedArguments(payload);
50
+ const sources = [stringValue(args.patch), input].filter(Boolean);
51
+ if (input.includes("\\n") || input.includes('\\"')) {
52
+ sources.push(...decodedDoubleQuotedStrings(input));
53
+ }
54
+ return sources;
55
+ }
56
+
57
+ function dedupeKey(path: string): string {
58
+ // Windows treats drive-letter and network paths as case-insensitive. Keep
59
+ // the first spelling for display, but do not count the same file twice.
60
+ return /^(?:[A-Za-z]:[\\/]|\\\\)/u.test(path) ? path.toLocaleLowerCase("en-US") : path;
61
+ }
62
+
63
+ function changesFromPatchSource(source: string): AndroidRemoteFileChange[] {
64
+ const header = /^\*\*\* (Add|Update|Delete) File:\s*(.+?)\s*$/gmu;
65
+ const matches = [...source.matchAll(header)];
66
+ const byPath = new Map<string, AndroidRemoteFileChange>();
67
+
68
+ for (const [index, match] of matches.entries()) {
69
+ const operation = match[1]?.toLocaleLowerCase("en-US");
70
+ const path = match[2]?.trim();
71
+ if (!path || !["add", "update", "delete"].includes(operation ?? "")) continue;
72
+
73
+ const bodyStart = (match.index ?? 0) + match[0].length;
74
+ const bodyEnd = matches[index + 1]?.index ?? source.length;
75
+ const body = source
76
+ .slice(bodyStart, bodyEnd)
77
+ .replace(/^\*\*\* End Patch\s*$/gmu, "")
78
+ .trim();
79
+ const key = dedupeKey(path);
80
+ const existing = byPath.get(key);
81
+ const diff = [existing?.diff, body].filter(Boolean).join("\n");
82
+ byPath.set(key, {
83
+ path: existing?.path ?? path,
84
+ kind: existing?.kind ?? { type: operation as "add" | "update" | "delete" },
85
+ ...(diff ? { diff } : {}),
86
+ });
87
+ }
88
+
89
+ return [...byPath.values()];
90
+ }
91
+
92
+ /** Reads file paths and the immediately available line diff from an apply_patch call. */
93
+ export function fileChangesFromToolCall(payload: JsonRecord): AndroidRemoteFileChange[] {
94
+ const name = stringValue(payload.name);
95
+ const input = stringValue(payload.input);
96
+ if (name !== "apply_patch" && !(name === "exec" && /\btools\.apply_patch\s*\(/u.test(input))) {
97
+ return [];
98
+ }
99
+
100
+ const changes: AndroidRemoteFileChange[] = [];
101
+ const seen = new Set<string>();
102
+ for (const source of patchSources(payload)) {
103
+ for (const change of changesFromPatchSource(source)) {
104
+ const key = dedupeKey(change.path);
105
+ if (seen.has(key)) continue;
106
+ seen.add(key);
107
+ changes.push(change);
108
+ if (changes.length >= MAX_FILE_CHANGES) return changes;
109
+ }
110
+ }
111
+ return changes;
112
+ }