Skip to content

fix(windows): host metrics via sysinfo + OpenCode session discovery#134

Open
XKHoshizora wants to merge 4 commits into
graykode:mainfrom
XKHoshizora:feat/windows-support
Open

fix(windows): host metrics via sysinfo + OpenCode session discovery#134
XKHoshizora wants to merge 4 commits into
graykode:mainfrom
XKHoshizora:feat/windows-support

Conversation

@XKHoshizora

@XKHoshizora XKHoshizora commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Summary

On Windows 11 abtop showed "n/a" host metrics and 0 OpenCode sessions even with an agent running (reported by an abtop-web-ui tester; reproduces with the TUI and abtop --json). This PR fixes both on Windows only — every runtime change is #[cfg(target_os = "windows")]-gated and the Linux /proc path and macOS stub are byte-for-byte unchanged.

Host metrics (src/host_info.rs)

HostSampler::sample() returned None on every non-Linux platform. sysinfo is already a Windows-only dependency, so the sampler now holds a sysinfo::System across ticks (CPU usage is a delta between two refreshes — mirrors the Linux prev/delta design): cpu_pct = global CPU (0.0 on the first tick, same as Linux), mem_pct = used/total, load1 = 0.0 (Windows has no load average; rendered as N/A).

OpenCode session discovery (src/collector/opencode.rs)

Three Windows-only root causes, found by debugging on a real Windows 11 machine:

  1. get_process_cwd() shelled out to lsof (the not(linux) branch), which doesn't exist on Windows → cwd matching always failed. New #[cfg(windows)] impl reads the cwd via sysinfo (process PEB), refreshing only the queried PID.
  2. Path-format mismatch: the OpenCode DB stores directory with forward slashes (C:/Users/x/proj — verified against a real DB) while the live process cwd has backslashes, and NTFS is case-insensitive. Windows-gated paths_equal() normalizes separators + case; unix keeps the exact comparison.
  3. Silent empty result when the sqlite3 CLI is missing — the common case on Windows. When the DB exists but sqlite3 isn't on PATH, a one-time stderr warning names the DB path and the install command (winget install SQLite.SQLite).

Also: %LOCALAPPDATA% / %APPDATA% are probed as DB-path fallbacks (npm-installed OpenCode keeps the XDG-style ~/.local/share layout on Windows, so the existing default already resolves), and the project-name fallback goes through last_path_segment() so backslash paths don't leak a full path as the project name.

Windows test suite (pre-existing failures)

cargo test had 18 pre-existing failures on Windows — two fixture bugs, not product bugs: claude.rs write_session_file() built JSON with format! (backslash paths → invalid escapes; 14 tests saw zero sessions), now serialized with serde_json; codex.rs set_modified() opened the file read-only before File::set_modified() (PermissionDenied on Windows; 4 panics), now opens with write access like claude.rs set_mtime() already did.

Verification

  • Windows 11 (MSVC): cargo build + cargo test green (163/163); abtop --json shows real CPU/MEM and the OpenCode session matched by cwd; warning path verified with sqlite3 removed from PATH
  • Linux: cargo build + cargo test green (165 passed + doc-test, 0 failed, verified on real Linux x86_64 before opening this PR); abtop --json confirmed unchanged — host metrics from /proc, session discovery identical
  • macOS: cargo check --target aarch64-apple-darwin passes (no code path changes outside #[cfg(windows)])
  • README: Windows section + OpenCode notes updated

Thanks for abtop!

XKHoshizora and others added 4 commits June 10, 2026 23:44
HostSampler::sample() previously returned None on every non-Linux
platform, so Windows rendered CPU/MEM/LOAD as "n/a". sysinfo is already
a Windows-only dependency; hold a sysinfo::System across ticks (CPU
usage is a delta between two refreshes, mirroring the Linux prev/delta
approach) and report:

- cpu_pct: global CPU usage (0.0 on the first tick, like Linux)
- mem_pct: used / total memory
- load1: 0.0 - Windows has no load average; callers render it as N/A

The Linux /proc path and the macOS stub are unchanged; all new code is
gated behind #[cfg(target_os = "windows")].

Refs #1 (Task 1)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Three Windows-only root causes made OpenCode sessions invisible:

1. get_process_cwd() fell into the not(linux) branch, which shells out
   to lsof - a tool that does not exist on Windows - so cwd matching
   always failed. Add a #[cfg(windows)] impl that reads the cwd via
   sysinfo (process PEB), refreshing only the queried PID.

2. The OpenCode DB stores `directory` with forward slashes on Windows
   (e.g. C:/Users/x/proj) while the live process cwd uses backslashes,
   and NTFS paths are case-insensitive. Compare via a Windows-gated
   paths_equal() that normalizes separators and case; unix keeps the
   exact string comparison.

3. collect_sessions() returned an empty vec silently when the sqlite3
   CLI is missing - the common case on Windows. When the DB exists but
   sqlite3 is not on PATH, emit a one-time stderr warning that names
   the DB path and the winget install command.

Also probe %LOCALAPPDATA%/%APPDATA% as DB-path fallbacks (verified:
npm-installed OpenCode keeps the XDG-style ~/.local/share layout on
Windows, which the existing default already resolves), and derive the
project-name fallback through last_path_segment() so backslash paths
do not leak a full path as the project name.

Unix behavior is byte-for-byte unchanged; everything new is gated
behind #[cfg(target_os = "windows")].

Refs #1 (Task 2)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- claude.rs write_session_file() interpolated cwd into a JSON literal
  with format!(); Windows backslash paths produced invalid JSON escape
  sequences, the session file failed to parse, and 14 tests saw zero
  sessions. Serialize the fixture with serde_json instead.

- codex.rs set_modified() opened the file read-only before calling
  File::set_modified(); on Windows that fails with PermissionDenied
  (os error 5) and 4 tests panicked. Open with write access (claude.rs
  set_mtime() already did this correctly).

Test-only changes; behavior on unix is equivalent. All 163 tests now
pass on Windows.

Refs #1

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Refs #1

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.

1 participant