|
| 1 | +# Codex Desktop Windows 通路 TODO |
| 2 | + |
| 3 | +这份文档记录 `codexm` 把 Desktop 通路扩到 Windows 时,需要补的依赖、平台适配点和建议落地顺序。 |
| 4 | + |
| 5 | +它不是正式设计稿,只作为后续实现前的内部 TODO 清单。 |
| 6 | + |
| 7 | +## 1. 当前结论 |
| 8 | + |
| 9 | +现在 `codexm` 的 Desktop 通路本质上分两层: |
| 10 | + |
| 11 | +1. Desktop 进程管理层 |
| 12 | + - 找到已安装的 Codex Desktop |
| 13 | + - 枚举运行中的 Desktop 进程 |
| 14 | + - 判断当前 shell 是否跑在 Desktop 内 |
| 15 | + - 退出和重启 Desktop |
| 16 | + - 记录和校验受管 Desktop 状态 |
| 17 | + |
| 18 | +2. Desktop runtime 交互层 |
| 19 | + - 通过 DevTools websocket 连到 `app://-/index.html?hostId=local` |
| 20 | + - 在页面内执行 JS |
| 21 | + - 通过 `window.electronBridge.sendMessageFromView(...)` 走 bridge |
| 22 | + - 读取 runtime account / quota |
| 23 | + - 触发 `codex-app-server-restart` |
| 24 | + - 监听 bridge 消息流做 `watch` |
| 25 | + |
| 26 | +当前上层 runtime 交互逻辑没有明显的平台绑定,主要的 macOS 假设都集中在 Desktop 进程管理层。 |
| 27 | + |
| 28 | +## 2. 现有 macOS-only 假设 |
| 29 | + |
| 30 | +当前实现里,这些点默认是 macOS 专属: |
| 31 | + |
| 32 | +1. 安装路径 |
| 33 | + - `/Applications/Codex.app` |
| 34 | + - `~/Applications/Codex.app` |
| 35 | + - `mdfind "Codex.app"` |
| 36 | + |
| 37 | +2. 可执行文件路径 |
| 38 | + - `.../Contents/MacOS/Codex` |
| 39 | + |
| 40 | +3. 进程枚举 |
| 41 | + - `ps -Ao pid=,command=` |
| 42 | + |
| 43 | +4. 父进程链判断 |
| 44 | + - 通过 `ps -o ppid=,command= -p <pid>` 逐层向上找 Desktop |
| 45 | + |
| 46 | +5. 优雅退出 |
| 47 | + - `osascript -e 'tell application "Codex" to quit'` |
| 48 | + |
| 49 | +6. 错误提示 |
| 50 | + - 直接写死了 `/Applications/Codex.app` |
| 51 | + |
| 52 | +这些都需要 Win32 适配。 |
| 53 | + |
| 54 | +## 3. Windows 版最小依赖 |
| 55 | + |
| 56 | +从当前代码结构看,Windows Desktop 通路不需要额外 npm 依赖,最小依赖应控制在: |
| 57 | + |
| 58 | +- Windows 上已安装 Codex Desktop |
| 59 | +- Desktop 可执行文件支持 `--remote-debugging-port=<port>` |
| 60 | +- 本机可访问 `http://127.0.0.1:<port>/json/list` |
| 61 | +- Desktop 页面仍暴露: |
| 62 | + - `app://-/index.html?hostId=local` |
| 63 | + - `window.electronBridge.sendMessageFromView(...)` |
| 64 | +- 系统自带命令可用: |
| 65 | + - `powershell` 或 `pwsh` |
| 66 | + - `taskkill` |
| 67 | + - `cmd.exe` |
| 68 | + |
| 69 | +换句话说,真正要补的是平台适配,不是新的通信协议。 |
| 70 | + |
| 71 | +## 4. 建议实现方式 |
| 72 | + |
| 73 | +建议先把 Desktop 进程管理抽成平台层,不要继续把 `if (process.platform === ...)` 散落在主逻辑里。 |
| 74 | + |
| 75 | +建议拆成: |
| 76 | + |
| 77 | +- `desktop-platform-darwin.ts` |
| 78 | +- `desktop-platform-win32.ts` |
| 79 | + |
| 80 | +至少抽出这几个动作: |
| 81 | + |
| 82 | +- `findInstalledApp()` |
| 83 | +- `listRunningApps()` |
| 84 | +- `isRunningInsideDesktopShell()` |
| 85 | +- `quitRunningApps()` |
| 86 | +- `launch()` |
| 87 | + |
| 88 | +然后由 `createCodexDesktopLauncher()` 只负责组装平台实现和上层 runtime 逻辑。 |
| 89 | + |
| 90 | +## 5. Windows v1 落地范围 |
| 91 | + |
| 92 | +第一版只追求“能用”,不追求最优雅。 |
| 93 | + |
| 94 | +### 5.1 查找安装路径 |
| 95 | + |
| 96 | +优先尝试常见路径,例如: |
| 97 | + |
| 98 | +- `%LocalAppData%\\Programs\\Codex\\Codex.exe` |
| 99 | +- `%ProgramFiles%\\Codex\\Codex.exe` |
| 100 | +- `%ProgramFiles(x86)%\\Codex\\Codex.exe` |
| 101 | + |
| 102 | +如果这些都失败,再考虑: |
| 103 | + |
| 104 | +- 开始菜单快捷方式解析 |
| 105 | +- 注册表查询 |
| 106 | + |
| 107 | +第一版可以只做常见路径探测。 |
| 108 | + |
| 109 | +### 5.2 枚举进程 |
| 110 | + |
| 111 | +建议用 PowerShell 查询进程和命令行,例如: |
| 112 | + |
| 113 | +- `Get-CimInstance Win32_Process` |
| 114 | + |
| 115 | +需要拿到: |
| 116 | + |
| 117 | +- `ProcessId` |
| 118 | +- `CommandLine` |
| 119 | + |
| 120 | +因为后面还要校验: |
| 121 | + |
| 122 | +- 是否真的是 Codex Desktop |
| 123 | +- 是否带了指定的 `--remote-debugging-port` |
| 124 | + |
| 125 | +### 5.3 判断当前是否跑在 Desktop 内 |
| 126 | + |
| 127 | +同样建议沿着父进程链向上查,只是实现改成 Windows 版本。 |
| 128 | + |
| 129 | +可以继续保留现有语义: |
| 130 | + |
| 131 | +- 如果当前 CLI 是从 Codex Desktop 内部开的,就拒绝执行 `launch` |
| 132 | + |
| 133 | +### 5.4 退出 Desktop |
| 134 | + |
| 135 | +Windows v1 不强求优雅退出。 |
| 136 | + |
| 137 | +建议: |
| 138 | + |
| 139 | +- 普通退出:先尝试 `taskkill /PID <pid> /T` |
| 140 | +- force 退出:`taskkill /PID <pid> /T /F` |
| 141 | + |
| 142 | +如果后面验证发现存在更稳定的非强杀退出方式,再单独补。 |
| 143 | + |
| 144 | +### 5.5 启动 Desktop |
| 145 | + |
| 146 | +直接 `spawn` Windows 可执行文件,例如: |
| 147 | + |
| 148 | +- `Codex.exe --remote-debugging-port=39223` |
| 149 | + |
| 150 | +并保留: |
| 151 | + |
| 152 | +- detached |
| 153 | +- 隐藏控制台窗口 |
| 154 | + |
| 155 | +### 5.6 复用现有 bridge / watch / restart |
| 156 | + |
| 157 | +只要 Windows 版 Desktop 保留现有这些运行时能力: |
| 158 | + |
| 159 | +- DevTools websocket |
| 160 | +- `app://-/index.html?hostId=local` |
| 161 | +- `electronBridge` |
| 162 | + |
| 163 | +那么以下能力应尽量直接复用: |
| 164 | + |
| 165 | +- `current` 的 Desktop 优先读取 |
| 166 | +- `switch` 的 managed refresh |
| 167 | +- `watch` 的 bridge 监听 |
| 168 | +- `codex-app-server-restart` |
| 169 | + |
| 170 | +不要为 Windows 重写第二套上层逻辑。 |
| 171 | + |
| 172 | +## 6. 建议实施顺序 |
| 173 | + |
| 174 | +建议按下面顺序做: |
| 175 | + |
| 176 | +1. 先抽平台层接口 |
| 177 | +2. 保持 darwin 行为不变 |
| 178 | +3. 补 win32 的: |
| 179 | + - app 查找 |
| 180 | + - 进程枚举 |
| 181 | + - kill / launch |
| 182 | +4. 跑通 Windows 上的: |
| 183 | + - `launch` |
| 184 | + - `current` |
| 185 | + - `watch` |
| 186 | + - `switch` |
| 187 | +5. 最后再考虑: |
| 188 | + - 更优雅的退出 |
| 189 | + - 更稳的安装路径发现 |
| 190 | + |
| 191 | +不要一开始就碰 Linux。 |
| 192 | + |
| 193 | +## 7. 风险点 |
| 194 | + |
| 195 | +后续真正实现前,需要确认这些前提: |
| 196 | + |
| 197 | +1. Windows 版 Codex Desktop 是否也支持 `--remote-debugging-port` |
| 198 | +2. DevTools `/json/list` 是否同样暴露目标页面 |
| 199 | +3. 目标页面 URL 是否仍是 `app://-/index.html?hostId=local` |
| 200 | +4. `electronBridge.sendMessageFromView(...)` 是否保持同名 |
| 201 | +5. `codex-app-server-restart` 在 Windows Desktop 上是否可用 |
| 202 | + |
| 203 | +如果这些运行时前提有任何一项变化,就不是单纯的平台适配,而是需要补协议兼容层。 |
| 204 | + |
| 205 | +## 8. 验收标准 |
| 206 | + |
| 207 | +Windows Desktop 通路做完后,至少要满足: |
| 208 | + |
| 209 | +1. `codexm launch` 能找到并启动 Windows 版 Codex Desktop |
| 210 | +2. `codexm launch` 能记录受管 Desktop 状态 |
| 211 | +3. `codexm current` 在受管 Desktop 存在时,仍优先走 Desktop runtime |
| 212 | +4. `codexm watch` 能收到 quota 更新 |
| 213 | +5. `codexm switch` 能在受管 Desktop 上触发 refresh |
| 214 | +6. 在 Codex Desktop 内部 shell 中,`launch` 仍会拒绝重启自己 |
| 215 | +7. macOS 现有行为不回归 |
| 216 | + |
| 217 | +## 9. 后续实现备注 |
| 218 | + |
| 219 | +真正开做时,建议先补一份正式 spec,再实现,不要直接按这页 TODO 开写。 |
0 commit comments