Skip to content

Feat/wsl linux support#13

Merged
Dikevin merged 16 commits intoHOOLC:masterfrom
Tsutomu-miku:feat/wsl-linux-support
Apr 13, 2026
Merged

Feat/wsl linux support#13
Dikevin merged 16 commits intoHOOLC:masterfrom
Tsutomu-miku:feat/wsl-linux-support

Conversation

@Tsutomu-miku
Copy link
Copy Markdown
Contributor

@Tsutomu-miku Tsutomu-miku commented Apr 12, 2026

Summary

Add cross-platform support for WSL and Linux environments, plus a new codexm run wrapper 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 matching
  • src/platform-desktop-adapter.ts — platform-aware Desktop launcher that wraps the macOS-only codex-desktop-launch.ts and provides correct behavior on each platform

2. WSL / Linux support in core modules

  • src/main.ts — wired in createPlatformDesktopLauncher() to replace hardcoded macOS launcher; platform-aware isRunningDesktopFromApp(); platform-specific error messages
  • src/codex-login.ts — WSL browser opening chain: wslviewpowershell.exe Start-Processxdg-open fallback

3. 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 support
  • src/main.ts watch 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 wraps codex as a child process
    • Watches ~/.codex/auth.json via fs.watch() with SHA-256 hash comparison and debouncing
    • When auth file changes (e.g., after codexm switch), automatically kills and restarts codex
    • Process registry integration for codexm watch tracking
    • Polling fallback for systems where fs.watch is unreliable
  • src/main.ts case "run"codexm run [-- ...codexArgs] command entry point

Why: Codex CLI (Rust) reads ~/.codex/auth.json once 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.ts restartCliProcess() — replaced broken SIGUSR1 approach with SIGTERM + SIGKILL fallback. When codex was started via codexm 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 tests
  • tests/cli.test.ts — CLI watch mode tests, platform adapter tests

Usage

# Instead of running `codex` directly:
codexm run -- --model o3

# In another terminal, switch accounts:
codexm switch my-other-account

# The running codex process auto-restarts with the new auth ✓

Verification

  • pnpm typecheck
  • pnpm test
  • pnpm build

…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).
@Dikevin
Copy link
Copy Markdown
Collaborator

Dikevin commented Apr 13, 2026

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 codex CLI binary path, Windows-side Desktop processes, and managed Desktop/devtools semantics. That makes some commands look supported even when they cannot actually deliver on their contract.

I would split the command surface into two groups:

1. Commands that should be fully supported on WSL/Linux in CLI mode

  • codexm add
  • codexm save
  • codexm current
  • codexm current --refresh
  • codexm list
  • codexm list --verbose
  • codexm update
  • codexm switch <name>
  • codexm switch --auto
  • codexm watch (foreground CLI watch mode)
  • codexm run [-- ...codexArgs]
  • codexm remove
  • codexm rename
  • codexm completion

These are the commands that can be implemented cleanly using local auth state, quota refresh, the direct client / JSON-RPC path, and the codexm run restart model. They do not need Desktop/devtools semantics.

2. Commands / flags that should explicitly error or be rejected on WSL/Linux

  • codexm launch
    This should fail with a clear message such as: “On WSL/Linux, use codexm run instead of launch."
  • codexm launch --watch
    Same reason. This should not try to treat a CLI codex path as a Desktop binary.
  • codexm switch --force
  • codexm switch --auto --force
    These should either error or be downgraded with a very explicit warning. The meaning of --force today is “apply immediately to the running managed Desktop session.” In CLI mode, that responsibility should belong to codexm run auto-restarting on auth change, not to borrowed Desktop semantics.
  • codexm watch --detach
    If detached CLI watch is not implemented reliably yet, keep it as a clear error instead of partial support.

3. README / help should split the runtime model by platform
I would strongly recommend documenting two separate operating modes:

  • macOS Desktop mode
  • WSL/Linux CLI mode

For WSL/Linux, the recommended flow can be very simple:

  1. codexm add ...
  2. codexm run -- --model ...
  3. In another terminal, run codexm watch
  4. When watch detects quota exhaustion and switches accounts, run restarts automatically and picks up the new auth

That makes the mental model clear:

  • hot switching in CLI mode is achieved through codexm run restart behavior
  • not through Desktop devtools refresh or --force

4. Implementation recommendation

  • Do not let Linux/WSL findInstalledApp() return a CLI codex binary and then feed it into the Desktop launch() path with --remote-debugging-port.
  • If future support for WSL + Windows-side Desktop is desired, that should be a separate implementation with an actual Windows process/devtools bridge. Until then, it is better to explicitly say “unsupported on this platform” than to provide misleading pseudo-compatibility.

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)
@Tsutomu-miku
Copy link
Copy Markdown
Contributor Author

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

Suggestion Commit Details
codexm launch should reject on WSL/Linux af038fe Now errors with: "codexm launch is not supported on WSL/Linux. Use \"codexm run [-- ...args]\"..."
codexm launch --watch same af038fe Blocked at the same platform gate — all launch flags rejected
switch --force downgrade in CLI mode af038fe Detects no managed Desktop → sets effectiveForce = false + prints warning guiding to codexm run
watch --detach reject in CLI mode Already done Was already rejecting: "Detached CLI watch is not yet supported." (no change needed)
README split by platform Already done README has separate Quick Start / Typical Flow sections for macOS Desktop vs WSL/Linux CLI
Don't feed CLI binary into Desktop launch path af038fe launch now rejects before findInstalledApp() is ever called on non-macOS

Tests added (02f4b7e)

  • launch rejects on Linux with guidance to use codexm run
  • launch rejects on WSL with guidance to use codexm run
  • launch --auto also rejects on non-macOS
  • switch --force warns and downgrades when no Desktop session is running

Uses setPlatformForTesting() from platform.ts for clean platform overrides in tests.

CLI-first closed loop on WSL/Linux

The recommended flow is now:

  1. codexm add / codexm save — account management (fully supported)
  2. codexm run -- --model o3 — wraps codex with auth file watcher
  3. codexm watch — foreground CLI quota monitor with auto-switch
  4. When watch auto-switches → auth file changes → codexm run detects and restarts codex

No Desktop semantics leak into the CLI path.

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)
@Dikevin
Copy link
Copy Markdown
Collaborator

Dikevin commented Apr 13, 2026

Codex follow-up note:

Great work here. The CLI-first direction looks much better now, and adding both codexm watch and the restart-based switching flow for CLI mode makes the WSL/Linux story much more complete.

I think there is only one small TODO left: switch --auto --force should probably be treated the same way as manual switch --force in CLI mode.

My understanding is:

  • in CLI mode, auth changes are actually applied by the codexm run / CLI restart path
  • --force does not have meaningful extra effect there
  • so this is not a functional blocker, because the workflow still works
  • it is mostly a semantics / UX consistency issue, to make it explicit and unambiguous that --force is effectively meaningless in CLI mode

Also, there is currently no combined codexm run --watch flow for CLI mode. I do not consider that a defect or a problem in this PR — just a reasonable future feature suggestion if we want a more integrated CLI workflow later.

So I would consider this good to merge, with that one small cleanup left as a follow-up.

Copy link
Copy Markdown
Collaborator

@Dikevin Dikevin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good overall. The CLI-first direction makes the WSL/Linux workflow much clearer.

@Dikevin Dikevin merged commit 85482b0 into HOOLC:master Apr 13, 2026
1 check failed
Dikevin pushed a commit that referenced this pull request Apr 14, 2026
* 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
Dikevin pushed a commit that referenced this pull request Apr 14, 2026
* 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
Dikevin pushed a commit that referenced this pull request Apr 14, 2026
* 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants