Conversation
…ng, and hot account switching ## Problem codex-team (codexm) is deeply tied to macOS: - Process discovery uses `/Contents/MacOS/Codex` paths, `mdfind`, BSD `stat -f` - App quit uses `osascript` (AppleScript) - `watch` command requires managed Desktop (DevTools WebSocket), unusable with CLI-only mode - Account switching requires Desktop restart via DevTools injection; CLI mode needs manual Ctrl+C restart This makes codexm non-functional on Windows WSL and native Linux. ## Solution ### New modules: - `src/platform.ts` — Platform detection (darwin/linux/wsl) with WSL detection via `/proc/version` - `src/codex-cli-watcher.ts` — CLI-mode quota monitoring via JSON-RPC polling + graceful process restart (SIGUSR1/SIGTERM) - `src/platform-desktop-adapter.ts` — Platform-aware adapter wrapping `CodexDesktopLauncher` with Linux/WSL overrides ### Key changes: 1. **Platform detection**: Distinguishes macOS, native Linux, and WSL 2. **Process discovery**: Linux uses `ps` + binary name matching; WSL adds `powershell.exe Get-Process` for Windows-side Desktop 3. **App finding**: Linux searches `/usr/local/bin/codex`, `which codex`, etc.; WSL also searches `/mnt/c/` Windows paths 4. **BSD stat → Node fs.access**: Eliminates BSD-only `stat -f` dependency 5. **osascript → SIGTERM**: Uses signal-based termination on Linux/WSL 6. **CLI watch mode**: New JSON-RPC polling loop for quota monitoring without Desktop 7. **CLI hot-switch**: SIGUSR1-based auth reload for running codex CLI processes ### Tests: - `tests/platform.test.ts` — Platform detection and binary identification - `tests/codex-cli-watcher.test.ts` — CLI process manager, quota polling, reconnection - `tests/platform-desktop-adapter.test.ts` — Linux/WSL process listing, app finding, stat interception
…estart, stale PID pruning
Previously, restartCliProcess() would broadcast SIGUSR1/SIGTERM to ALL
running codex CLI processes. This is wrong when multiple codex instances
run simultaneously under different accounts (common in WSL).
Changes:
- Add TrackedCliProcess type with accountId/email fields
- Add on-disk process registry (~/.codex-team/cli-processes.json)
- registerProcess(): record PID → account mapping
- pruneStaleProcesses(): remove dead PIDs automatically
- getTrackedProcesses(accountId?): filter by account
- restartCliProcess({ accountId }): targeted restart — only kill
processes using the specified account, leave others untouched
- Return { restarted, skipped, failed } counts instead of boolean
- Add registerProcess / getTrackedProcesses tests - Add multi-process registration with stale PID pruning - Add accountId filtering tests - Add re-registration (same PID) replacement test - Add pruneStaleProcesses tests (dead PIDs, missing file) - Add targeted restartCliProcess tests (by accountId) - Use tmpdir() for isolated test directories
…p running When `codexm watch` is run and no managed Codex Desktop session is detected, the watch command now automatically enters CLI watch mode instead of throwing an error. This enables quota monitoring on WSL/Linux without Codex Desktop. Changes: - Import getPlatform and createCliProcessManager - Detect desktop availability before choosing watch mode - CLI mode: poll quota via JSON-RPC, discover CLI processes, auto-switch with targeted SIGUSR1 restart - Detach mode still requires Desktop (not yet supported for CLI)
The watch command now enters CLI mode when no Desktop is running, so the old test expecting an error is replaced with one that verifies CLI mode entry. Also adds a test for --detach refusing without Desktop.
…top checks - Replace createCodexDesktopLauncher() with createPlatformDesktopLauncher() so Linux/WSL gets proper process discovery, app finding, and quit handling - Make isRunningDesktopFromApp() platform-aware using isCodexDesktopCommand() - Replace hardcoded '/Applications/Codex.app' error message with platform-specific guidance for macOS, Linux, and WSL - Pass platform param through isOnlyManagedDesktopInstanceRunning()
On WSL, xdg-open is often missing or non-functional. The new openBrowser() detects WSL via /proc/version and tries: 1. wslview (from wslu package) — opens in Windows default browser 2. powershell.exe Start-Process — direct Windows browser invocation 3. xdg-open — final fallback Non-WSL Linux behavior unchanged (still uses xdg-open).
|
Codex review note: I recommend narrowing the WSL/Linux direction to CLI-first support instead of trying to preserve full parity with the macOS Desktop model. The biggest current risk is mixing three different things together: the I would split the command surface into two groups: 1. Commands that should be fully supported on WSL/Linux in CLI mode
These are the commands that can be implemented cleanly using local auth state, quota refresh, the direct client / JSON-RPC path, and the 2. Commands / flags that should explicitly error or be rejected on WSL/Linux
3. README / help should split the runtime model by platform
For WSL/Linux, the recommended flow can be very simple:
That makes the mental model clear:
4. Implementation recommendation
In short: WSL/Linux should be a CLI-first closed loop, not an incomplete Desktop substitute. That gives users a stable command contract and makes the README much easier to understand. |
Per review feedback: - codexm launch now errors on non-macOS with guidance to use codexm run - switch --force warns when no Desktop session and downgrades to normal switch - watch --detach already rejected in CLI mode (no change needed)
|
Thanks for the thorough review! All points are well taken — agreed that WSL/Linux should be a CLI-first closed loop rather than an incomplete Desktop substitute. Here's what's been addressed: ✅ Adopted
Tests added (
|
Resolve conflicts in README.md, src/main.ts, tests/cli.test.ts. - README.md: Integrated WSL/Linux platform support docs with master's reorganized Account management / Desktop mode sections - src/main.ts: Combined PR's effectiveForce with master's shouldSkipManagedDesktopRefresh guard - tests/cli.test.ts: Clean three-way merge (no conflicts)
|
Codex follow-up note: Great work here. The CLI-first direction looks much better now, and adding both I think there is only one small TODO left: My understanding is:
Also, there is currently no combined So I would consider this good to merge, with that one small cleanup left as a follow-up. |
Dikevin
left a comment
There was a problem hiding this comment.
Looks good overall. The CLI-first direction makes the WSL/Linux workflow much clearer.
* feat: add Linux/WSL support for process discovery, CLI quota monitoring, and hot account switching
## Problem
codex-team (codexm) is deeply tied to macOS:
- Process discovery uses `/Contents/MacOS/Codex` paths, `mdfind`, BSD `stat -f`
- App quit uses `osascript` (AppleScript)
- `watch` command requires managed Desktop (DevTools WebSocket), unusable with CLI-only mode
- Account switching requires Desktop restart via DevTools injection; CLI mode needs manual Ctrl+C restart
This makes codexm non-functional on Windows WSL and native Linux.
## Solution
### New modules:
- `src/platform.ts` — Platform detection (darwin/linux/wsl) with WSL detection via `/proc/version`
- `src/codex-cli-watcher.ts` — CLI-mode quota monitoring via JSON-RPC polling + graceful process restart (SIGUSR1/SIGTERM)
- `src/platform-desktop-adapter.ts` — Platform-aware adapter wrapping `CodexDesktopLauncher` with Linux/WSL overrides
### Key changes:
1. **Platform detection**: Distinguishes macOS, native Linux, and WSL
2. **Process discovery**: Linux uses `ps` + binary name matching; WSL adds `powershell.exe Get-Process` for Windows-side Desktop
3. **App finding**: Linux searches `/usr/local/bin/codex`, `which codex`, etc.; WSL also searches `/mnt/c/` Windows paths
4. **BSD stat → Node fs.access**: Eliminates BSD-only `stat -f` dependency
5. **osascript → SIGTERM**: Uses signal-based termination on Linux/WSL
6. **CLI watch mode**: New JSON-RPC polling loop for quota monitoring without Desktop
7. **CLI hot-switch**: SIGUSR1-based auth reload for running codex CLI processes
### Tests:
- `tests/platform.test.ts` — Platform detection and binary identification
- `tests/codex-cli-watcher.test.ts` — CLI process manager, quota polling, reconnection
- `tests/platform-desktop-adapter.test.ts` — Linux/WSL process listing, app finding, stat interception
* fix: add multi-process support — process-account registry, targeted restart, stale PID pruning
Previously, restartCliProcess() would broadcast SIGUSR1/SIGTERM to ALL
running codex CLI processes. This is wrong when multiple codex instances
run simultaneously under different accounts (common in WSL).
Changes:
- Add TrackedCliProcess type with accountId/email fields
- Add on-disk process registry (~/.codex-team/cli-processes.json)
- registerProcess(): record PID → account mapping
- pruneStaleProcesses(): remove dead PIDs automatically
- getTrackedProcesses(accountId?): filter by account
- restartCliProcess({ accountId }): targeted restart — only kill
processes using the specified account, leave others untouched
- Return { restarted, skipped, failed } counts instead of boolean
* test: update codex-cli-watcher tests for multi-process registry support
- Add registerProcess / getTrackedProcesses tests
- Add multi-process registration with stale PID pruning
- Add accountId filtering tests
- Add re-registration (same PID) replacement test
- Add pruneStaleProcesses tests (dead PIDs, missing file)
- Add targeted restartCliProcess tests (by accountId)
- Use tmpdir() for isolated test directories
* feat: integrate CLI watch mode into main.ts — fallback when no Desktop running
When `codexm watch` is run and no managed Codex Desktop session is
detected, the watch command now automatically enters CLI watch mode
instead of throwing an error. This enables quota monitoring on
WSL/Linux without Codex Desktop.
Changes:
- Import getPlatform and createCliProcessManager
- Detect desktop availability before choosing watch mode
- CLI mode: poll quota via JSON-RPC, discover CLI processes,
auto-switch with targeted SIGUSR1 restart
- Detach mode still requires Desktop (not yet supported for CLI)
* test: update watch test for CLI fallback + add detach-refuses test
The watch command now enters CLI mode when no Desktop is running,
so the old test expecting an error is replaced with one that
verifies CLI mode entry. Also adds a test for --detach refusing
without Desktop.
* fix: wire platform-desktop-adapter into main.ts + platform-aware Desktop checks
- Replace createCodexDesktopLauncher() with createPlatformDesktopLauncher()
so Linux/WSL gets proper process discovery, app finding, and quit handling
- Make isRunningDesktopFromApp() platform-aware using isCodexDesktopCommand()
- Replace hardcoded '/Applications/Codex.app' error message with
platform-specific guidance for macOS, Linux, and WSL
- Pass platform param through isOnlyManagedDesktopInstanceRunning()
* fix: WSL browser opening — prefer wslview/powershell.exe over xdg-open
On WSL, xdg-open is often missing or non-functional. The new openBrowser()
detects WSL via /proc/version and tries:
1. wslview (from wslu package) — opens in Windows default browser
2. powershell.exe Start-Process — direct Windows browser invocation
3. xdg-open — final fallback
Non-WSL Linux behavior unchanged (still uses xdg-open).
* feat: add codex-cli-runner for auto-restart on auth changes
* feat: add codexm run command for auto-restart on auth changes
* fix: replace SIGUSR1 with SIGTERM in restartCliProcess (codex has no signal handlers)
* test: add tests for codex-cli-runner auto-restart wrapper
* fix: update watch auto-switch messages for SIGTERM restart pattern
* docs: update README with WSL/Linux support, codexm run, and platform table
* fix: reject launch on WSL/Linux, downgrade switch --force in CLI mode
Per review feedback:
- codexm launch now errors on non-macOS with guidance to use codexm run
- switch --force warns when no Desktop session and downgrades to normal switch
- watch --detach already rejected in CLI mode (no change needed)
* test: add platform rejection tests for launch and switch --force downgrade
* feat: add Linux/WSL support for process discovery, CLI quota monitoring, and hot account switching
## Problem
codex-team (codexm) is deeply tied to macOS:
- Process discovery uses `/Contents/MacOS/Codex` paths, `mdfind`, BSD `stat -f`
- App quit uses `osascript` (AppleScript)
- `watch` command requires managed Desktop (DevTools WebSocket), unusable with CLI-only mode
- Account switching requires Desktop restart via DevTools injection; CLI mode needs manual Ctrl+C restart
This makes codexm non-functional on Windows WSL and native Linux.
## Solution
### New modules:
- `src/platform.ts` — Platform detection (darwin/linux/wsl) with WSL detection via `/proc/version`
- `src/codex-cli-watcher.ts` — CLI-mode quota monitoring via JSON-RPC polling + graceful process restart (SIGUSR1/SIGTERM)
- `src/platform-desktop-adapter.ts` — Platform-aware adapter wrapping `CodexDesktopLauncher` with Linux/WSL overrides
### Key changes:
1. **Platform detection**: Distinguishes macOS, native Linux, and WSL
2. **Process discovery**: Linux uses `ps` + binary name matching; WSL adds `powershell.exe Get-Process` for Windows-side Desktop
3. **App finding**: Linux searches `/usr/local/bin/codex`, `which codex`, etc.; WSL also searches `/mnt/c/` Windows paths
4. **BSD stat → Node fs.access**: Eliminates BSD-only `stat -f` dependency
5. **osascript → SIGTERM**: Uses signal-based termination on Linux/WSL
6. **CLI watch mode**: New JSON-RPC polling loop for quota monitoring without Desktop
7. **CLI hot-switch**: SIGUSR1-based auth reload for running codex CLI processes
### Tests:
- `tests/platform.test.ts` — Platform detection and binary identification
- `tests/codex-cli-watcher.test.ts` — CLI process manager, quota polling, reconnection
- `tests/platform-desktop-adapter.test.ts` — Linux/WSL process listing, app finding, stat interception
* fix: add multi-process support — process-account registry, targeted restart, stale PID pruning
Previously, restartCliProcess() would broadcast SIGUSR1/SIGTERM to ALL
running codex CLI processes. This is wrong when multiple codex instances
run simultaneously under different accounts (common in WSL).
Changes:
- Add TrackedCliProcess type with accountId/email fields
- Add on-disk process registry (~/.codex-team/cli-processes.json)
- registerProcess(): record PID → account mapping
- pruneStaleProcesses(): remove dead PIDs automatically
- getTrackedProcesses(accountId?): filter by account
- restartCliProcess({ accountId }): targeted restart — only kill
processes using the specified account, leave others untouched
- Return { restarted, skipped, failed } counts instead of boolean
* test: update codex-cli-watcher tests for multi-process registry support
- Add registerProcess / getTrackedProcesses tests
- Add multi-process registration with stale PID pruning
- Add accountId filtering tests
- Add re-registration (same PID) replacement test
- Add pruneStaleProcesses tests (dead PIDs, missing file)
- Add targeted restartCliProcess tests (by accountId)
- Use tmpdir() for isolated test directories
* feat: integrate CLI watch mode into main.ts — fallback when no Desktop running
When `codexm watch` is run and no managed Codex Desktop session is
detected, the watch command now automatically enters CLI watch mode
instead of throwing an error. This enables quota monitoring on
WSL/Linux without Codex Desktop.
Changes:
- Import getPlatform and createCliProcessManager
- Detect desktop availability before choosing watch mode
- CLI mode: poll quota via JSON-RPC, discover CLI processes,
auto-switch with targeted SIGUSR1 restart
- Detach mode still requires Desktop (not yet supported for CLI)
* test: update watch test for CLI fallback + add detach-refuses test
The watch command now enters CLI mode when no Desktop is running,
so the old test expecting an error is replaced with one that
verifies CLI mode entry. Also adds a test for --detach refusing
without Desktop.
* fix: wire platform-desktop-adapter into main.ts + platform-aware Desktop checks
- Replace createCodexDesktopLauncher() with createPlatformDesktopLauncher()
so Linux/WSL gets proper process discovery, app finding, and quit handling
- Make isRunningDesktopFromApp() platform-aware using isCodexDesktopCommand()
- Replace hardcoded '/Applications/Codex.app' error message with
platform-specific guidance for macOS, Linux, and WSL
- Pass platform param through isOnlyManagedDesktopInstanceRunning()
* fix: WSL browser opening — prefer wslview/powershell.exe over xdg-open
On WSL, xdg-open is often missing or non-functional. The new openBrowser()
detects WSL via /proc/version and tries:
1. wslview (from wslu package) — opens in Windows default browser
2. powershell.exe Start-Process — direct Windows browser invocation
3. xdg-open — final fallback
Non-WSL Linux behavior unchanged (still uses xdg-open).
* feat: add codex-cli-runner for auto-restart on auth changes
* feat: add codexm run command for auto-restart on auth changes
* fix: replace SIGUSR1 with SIGTERM in restartCliProcess (codex has no signal handlers)
* test: add tests for codex-cli-runner auto-restart wrapper
* fix: update watch auto-switch messages for SIGTERM restart pattern
* docs: update README with WSL/Linux support, codexm run, and platform table
* fix: reject launch on WSL/Linux, downgrade switch --force in CLI mode
Per review feedback:
- codexm launch now errors on non-macOS with guidance to use codexm run
- switch --force warns when no Desktop session and downgrades to normal switch
- watch --detach already rejected in CLI mode (no change needed)
* test: add platform rejection tests for launch and switch --force downgrade
* feat: add Linux/WSL support for process discovery, CLI quota monitoring, and hot account switching
## Problem
codex-team (codexm) is deeply tied to macOS:
- Process discovery uses `/Contents/MacOS/Codex` paths, `mdfind`, BSD `stat -f`
- App quit uses `osascript` (AppleScript)
- `watch` command requires managed Desktop (DevTools WebSocket), unusable with CLI-only mode
- Account switching requires Desktop restart via DevTools injection; CLI mode needs manual Ctrl+C restart
This makes codexm non-functional on Windows WSL and native Linux.
## Solution
### New modules:
- `src/platform.ts` — Platform detection (darwin/linux/wsl) with WSL detection via `/proc/version`
- `src/codex-cli-watcher.ts` — CLI-mode quota monitoring via JSON-RPC polling + graceful process restart (SIGUSR1/SIGTERM)
- `src/platform-desktop-adapter.ts` — Platform-aware adapter wrapping `CodexDesktopLauncher` with Linux/WSL overrides
### Key changes:
1. **Platform detection**: Distinguishes macOS, native Linux, and WSL
2. **Process discovery**: Linux uses `ps` + binary name matching; WSL adds `powershell.exe Get-Process` for Windows-side Desktop
3. **App finding**: Linux searches `/usr/local/bin/codex`, `which codex`, etc.; WSL also searches `/mnt/c/` Windows paths
4. **BSD stat → Node fs.access**: Eliminates BSD-only `stat -f` dependency
5. **osascript → SIGTERM**: Uses signal-based termination on Linux/WSL
6. **CLI watch mode**: New JSON-RPC polling loop for quota monitoring without Desktop
7. **CLI hot-switch**: SIGUSR1-based auth reload for running codex CLI processes
### Tests:
- `tests/platform.test.ts` — Platform detection and binary identification
- `tests/codex-cli-watcher.test.ts` — CLI process manager, quota polling, reconnection
- `tests/platform-desktop-adapter.test.ts` — Linux/WSL process listing, app finding, stat interception
* fix: add multi-process support — process-account registry, targeted restart, stale PID pruning
Previously, restartCliProcess() would broadcast SIGUSR1/SIGTERM to ALL
running codex CLI processes. This is wrong when multiple codex instances
run simultaneously under different accounts (common in WSL).
Changes:
- Add TrackedCliProcess type with accountId/email fields
- Add on-disk process registry (~/.codex-team/cli-processes.json)
- registerProcess(): record PID → account mapping
- pruneStaleProcesses(): remove dead PIDs automatically
- getTrackedProcesses(accountId?): filter by account
- restartCliProcess({ accountId }): targeted restart — only kill
processes using the specified account, leave others untouched
- Return { restarted, skipped, failed } counts instead of boolean
* test: update codex-cli-watcher tests for multi-process registry support
- Add registerProcess / getTrackedProcesses tests
- Add multi-process registration with stale PID pruning
- Add accountId filtering tests
- Add re-registration (same PID) replacement test
- Add pruneStaleProcesses tests (dead PIDs, missing file)
- Add targeted restartCliProcess tests (by accountId)
- Use tmpdir() for isolated test directories
* feat: integrate CLI watch mode into main.ts — fallback when no Desktop running
When `codexm watch` is run and no managed Codex Desktop session is
detected, the watch command now automatically enters CLI watch mode
instead of throwing an error. This enables quota monitoring on
WSL/Linux without Codex Desktop.
Changes:
- Import getPlatform and createCliProcessManager
- Detect desktop availability before choosing watch mode
- CLI mode: poll quota via JSON-RPC, discover CLI processes,
auto-switch with targeted SIGUSR1 restart
- Detach mode still requires Desktop (not yet supported for CLI)
* test: update watch test for CLI fallback + add detach-refuses test
The watch command now enters CLI mode when no Desktop is running,
so the old test expecting an error is replaced with one that
verifies CLI mode entry. Also adds a test for --detach refusing
without Desktop.
* fix: wire platform-desktop-adapter into main.ts + platform-aware Desktop checks
- Replace createCodexDesktopLauncher() with createPlatformDesktopLauncher()
so Linux/WSL gets proper process discovery, app finding, and quit handling
- Make isRunningDesktopFromApp() platform-aware using isCodexDesktopCommand()
- Replace hardcoded '/Applications/Codex.app' error message with
platform-specific guidance for macOS, Linux, and WSL
- Pass platform param through isOnlyManagedDesktopInstanceRunning()
* fix: WSL browser opening — prefer wslview/powershell.exe over xdg-open
On WSL, xdg-open is often missing or non-functional. The new openBrowser()
detects WSL via /proc/version and tries:
1. wslview (from wslu package) — opens in Windows default browser
2. powershell.exe Start-Process — direct Windows browser invocation
3. xdg-open — final fallback
Non-WSL Linux behavior unchanged (still uses xdg-open).
* feat: add codex-cli-runner for auto-restart on auth changes
* feat: add codexm run command for auto-restart on auth changes
* fix: replace SIGUSR1 with SIGTERM in restartCliProcess (codex has no signal handlers)
* test: add tests for codex-cli-runner auto-restart wrapper
* fix: update watch auto-switch messages for SIGTERM restart pattern
* docs: update README with WSL/Linux support, codexm run, and platform table
* fix: reject launch on WSL/Linux, downgrade switch --force in CLI mode
Per review feedback:
- codexm launch now errors on non-macOS with guidance to use codexm run
- switch --force warns when no Desktop session and downgrades to normal switch
- watch --detach already rejected in CLI mode (no change needed)
* test: add platform rejection tests for launch and switch --force downgrade
Summary
Add cross-platform support for WSL and Linux environments, plus a new
codexm runwrapper that solves the auth hot-reload problem for codex CLI.Changes
1. Platform abstraction layer
src/platform.ts— platform detection (darwin/linux/wsl), WSL detection via/proc/version, platform-aware process matchingsrc/platform-desktop-adapter.ts— platform-aware Desktop launcher that wraps the macOS-onlycodex-desktop-launch.tsand provides correct behavior on each platform2. WSL / Linux support in core modules
src/main.ts— wired increatePlatformDesktopLauncher()to replace hardcoded macOS launcher; platform-awareisRunningDesktopFromApp(); platform-specific error messagessrc/codex-login.ts— WSL browser opening chain:wslview→powershell.exe Start-Process→xdg-openfallback3. CLI watch mode (no Desktop required)
src/codex-cli-watcher.ts— quota monitoring via JSON-RPC polling (codex-direct-client), CLI process registry, auto-switch supportsrc/main.tswatch command — falls back to CLI watch mode when no Codex Desktop is running (common on WSL/Linux)4.
codexm run— auth hot-reload wrapper ⭐src/codex-cli-runner.ts— new module that wrapscodexas a child process~/.codex/auth.jsonviafs.watch()with SHA-256 hash comparison and debouncingcodexm switch), automatically kills and restarts codexcodexm watchtrackingfs.watchis unreliablesrc/main.tscase "run"—codexm run [-- ...codexArgs]command entry pointWhy: Codex CLI (Rust) reads
~/.codex/auth.jsononce at startup and caches in memory. No file watcher, no signal handler, no IPC for reload. SIGUSR1 does NOT work. The only reliable approach is kill + restart.5. SIGUSR1 → SIGTERM fix
src/codex-cli-watcher.tsrestartCliProcess()— replaced broken SIGUSR1 approach with SIGTERM + SIGKILL fallback. When codex was started viacodexm run, the runner detects the exit and auto-respawns with updated auth.6. Tests
tests/codex-cli-runner.test.ts— 9 test cases for the runner (spawn, exit, restart, debounce, polling fallback, abort, SIGKILL timeout)tests/codex-cli-watcher.test.ts— updated with multi-process registry teststests/cli.test.ts— CLI watch mode tests, platform adapter testsUsage
Verification
pnpm typecheckpnpm testpnpm build