* ci: add windows-latest to test matrix + fix 11 cross-platform test bugs
The test workflow ran on ``ubuntu-latest`` only. Per the issue's
first bullet — the maintainer's explicit #1 priority — add
``windows-latest`` to the matrix so the manager and related
modules are exercised on Windows on every PR.
The matrix addition surfaces 18 pre-existing Windows-only test
failures. Without fixes the new leg would be 18+ reds from
day one and the matrix would just produce a wall of
``fail-fast`` noise. This PR fixes 11 of them; each fix is
a real (cross-platform) bug, not a Windows-specific hack —
most were already flagged by CodeRabbit on PR #236 but never
acted on. The remaining 4 failures need code refactors
(``os.killpg`` → ``psutil`` in ``background.py``,
``convert_virtual_paths_in_command`` Windows-aware quoting,
tilde expansion) that are documented as out-of-scope
follow-ups below.
## What changed
* ``.github/workflows/test.yml``
- ``os: [ubuntu-latest, windows-latest]`` → 2 OS × 2 Python
= 4 cells.
- ``fail-fast: false`` so one bad cell doesn't cancel the
rest while the Windows leg is being brought up. Removable
in a future PR once the suite is fully green.
* ``tests/test_backends.py``
- Hard-coded ``"python3"`` → ``{sys.executable}`` in 7
test commands. Windows has no ``python3`` on PATH; using
``sys.executable`` is portable and matches what CodeRabbit
flagged on PR #236.
- Strict string comparisons → ``shlex.split`` round-trip in
5 resolver tests. ``shlex.quote`` adds single quotes
around backslash paths on Windows, which broke the
direct ``==`` compare.
- Cross-platform suffix checks in 2 path-resolution tests
(``Path(resolved).parts[-2:]`` instead of
``str(resolved).endswith("src/main.py")``).
- ``mkdir -p`` → ``sys.executable -c "import os;
os.makedirs(...)"`` in the cwd-sanitization test.
- ``skipif(sys.platform == "win32")`` on 3 e2e tests that
hit the underlying ``shlex.quote`` + ``cmd.exe`` quoting
bug (real, separate issue).
* ``tests/test_sessions.py``
- ``test_uses_data_dir``: check ``.evoscientist`` in the
long path form (via ``Path.resolve()``) rather than the
short-path form ``get_db_path`` returns on Windows.
* ``tests/test_mcp_client.py``
- ``endswith("python")`` → ``Path(result).stem.lower()`` so
``python.EXE`` matches on Windows.
- ``endswith("npx")`` also accepts ``npx.cmd`` so the npm
shim on Windows matches.
## Out of scope (follow-up issues to file)
* ``os.killpg`` doesn't exist on Windows
(``EvoScientist/background.py:248``) — 3 background tests
fail. Real fix is the same ``psutil`` walk pattern PR #200
shipped in ``langgraph_dev/manager.py``.
* Tilde expansion in file mentions.
* Windows-aware shell quoting in
``convert_virtual_paths_in_command``.
* Path conventions (``~/.config/evoscientist/`` vs
``%APPDATA%\EvoScientist``) — needs design discussion +
``platformdirs`` migration.
* Cross-module audit of
``EvoScientist/tools/execute.py``,
``EvoScientist/ccproxy_manager.py``,
``EvoScientist/config/onboard.py``.
Closes#207 (step 1 only — CI matrix + the easy test
fixes; remaining bullets tracked separately).
* fix: cross-platform compatibility for Windows CI runners
- background.py: replace POSIX-only os.killpg/os.getpgid with
cross-platform _kill_process_tree() helper. On Windows falls back
to Popen.terminate()/Popen.kill() (TerminateProcess); on POSIX
keeps existing os.killpg logic.
- test_backends.py: replace mkdir -p shell execution in
test_literal_workspace_path_replaced with preprocessing-boundary
assertion (patch LocalShellBackend.execute, capture command,
assert workspace path was rewritten to ./). Avoids POSIX-only
mkdir -p on Windows runners.
- test_file_mentions.py: monkeypatch USERPROFILE on Windows so
ntpath.expanduser() resolves ~ to tmp_path even when HOME is
unset on CI runners.
* fix(test): cross-platform sleep/true commands for Windows CI
Replace POSIX-only sleep/true with module-level helpers that use
ping -n / cmd /c on Windows. Also fix python3 -> sys.executable
in the non-timeout recovery test.
- test_background.py: 7 sleep/true fixes
- test_background_middleware.py: 6 sleep/true fixes
- test_backends.py: 4 sleep fixes + 1 python3 fix
2318 passed, 0 failed on Windows.
* fix(test): use shell-portable double quotes for python -c on Windows
cmd.exe does not treat single quotes as string delimiters, so
-c 'raise SystemExit(1)' was passed with literal quotes on Windows.
Switch to double quotes which work on both cmd.exe and POSIX sh.
* fix: use psutil for Windows process tree kill + avoid sys.executable under uv
- background.py: replace Popen.terminate()/kill() with psutil-based
process tree walking on Windows. TerminateProcess does NOT cascade
to grandchildren; psutil.Process.children(recursive=True) ensures
the entire tree is signaled.
- test_backends.py: replace sys.executable with 'python' in sandbox
execute() calls. Under uv, sys.executable is under the workspace
and gets rewritten to ./ by prepare_sandbox_command, breaking
Linux CI. The plain 'python' command resolves correctly in any
activated venv.
* fix: broaden try/except in _kill_process_tree to cover proc.children()
If the process exits between Process(popen.pid) and children(recursive=True),
the children call raises an uncaught exception escaping stop(). Move it inside
the existing try/except block.
* fix: narrow exception to ProcessLookupError in POSIX _kill_process_tree
OSError is too broad — would silently swallow EPERM on SIGKILL, leaving
the process alive when we report it as stopped. Match original behavior
which only caught ProcessLookupError (process already gone).
* style: ruff format test_backends.py
* ci: trigger re-run for flaky prompt_toolkit test
* style: fix ruff check (import order + RUF005 unpacking)
---------
Co-authored-by: Xi Zhang <106144707+X-iZhang@users.noreply.github.com>
* fix(cli): handle spaces in @file mentions
The @file parser truncated at the first space, so dragging or pasting a
filename like `@PREPING_ Building Agent.pdf` only matched `@PREPING_`
and warned "file not found". Now supports `@"..."` / `@'...'` quoted
form for explicit paths, plus a greedy expansion fallback that walks
across whitespace until an existing file resolves (bounded by newlines,
the next `@`, and a 20-token cap). Autocomplete also returns quoted
mentions for any candidate containing a space.
* style: apply ruff format to file_mentions
* feat(tui): enhance conversation history rendering and implement two-level thread hierarchy in picker
* feat(tui): improve conversation history display and enhance thread selection UI
* feat(file_mentions): implement @file mention parsing and completion for CLI and TUI
* feat(uv-tool): add compatibility checks and installation helpers for uv tool environments
* feat(dependencies): update package versions in uv.lock for compatibility and improvements
* feat(badges): update PyPI version to v0.0.4 in SVG assets and README files
* feat(tests): format code in TestUvToolCompat for improved readability