Skip to content

plugin/scripts: Windows (Git Bash) support#9

Open
Nedlitex wants to merge 1 commit intoReflexioAI:mainfrom
Nedlitex:windows-support
Open

plugin/scripts: Windows (Git Bash) support#9
Nedlitex wants to merge 1 commit intoReflexioAI:mainfrom
Nedlitex:windows-support

Conversation

@Nedlitex
Copy link
Copy Markdown

@Nedlitex Nedlitex commented Apr 27, 2026

Summary

Fixes five Windows-specific bugs in the plugin shell scripts so claude-smart installs and auto-starts cleanly under Git Bash (MINGW64) on Windows 10/11. Every change is gated on claude_smart_is_windows (uname matches MINGW*/MSYS*/CYGWIN*), so Linux and macOS behaviour is byte-for-byte unchanged.

Hit while installing the plugin on Windows 11 with claude-smart 0.1.17. The dashboard's /claude-smart:dashboard slash command failed with backend: not running and dashboard: .next missing, because the install never completed and the service-start scripts couldn't detach.

What was broken

# Where Symptom Cause
1 smart-install.sh uv install uv install reports success then uv sync fails because uv.exe is corrupt astral.sh's bash installer (install.sh) downloads a zip and unzips it; Git Bash's bundled unzip corrupts the Windows uv.exe (bad CRC on inflate).
2 smart-install.sh cs-cite heredoc Settings.json patch silently fails python3 is the Microsoft Store App Execution Alias stub at WindowsApps\python3.exe. command -v python3 returns truthy but invoking it prints "Python was not found" and exits non-zero.
3 _lib.sh claude_smart_spawn_detached Detach falls into broken python3 branch macOS fallback uses python3 -c '...os.setsid()...' — same App Execution stub fires; even with a real Python, os.setsid() is POSIX-only and would AttributeError.
4 backend-service.sh / dashboard-service.sh kill_group stop doesn't kill the service kill -TERM -- "-pgid" (negative pid = process group) is POSIX-only. Windows has no process groups, so the signal goes nowhere.
5 Service scripts inline detach blocks Same as #3, plus PID-file recording assumes pid==pgid which doesn't hold on Windows Inline copies of the setsid/python3/nohup chain in both service scripts.

What changes

_lib.sh — three new helpers, one rewritten:

  • claude_smart_is_windowsuname -s test for MINGW*|MSYS*|CYGWIN*.
  • claude_smart_resolve_python — probes interpreters with -V to filter the App Execution Alias stub. Prefers python over python3 on Windows; preserves python3-first ordering on POSIX.
  • claude_smart_kill_tree — POSIX: signal the process group (TERM, grace, KILL). Windows: taskkill //T //F //PID. Walks Git Bash's MSYS-pid to Windows-pid translation via ps (column 4 in default output is WINPID); $! for a backgrounded job returns the MSYS pid, but taskkill needs the native Windows pid.
  • claude_smart_spawn_detached — Windows path: plain nohup (no setsid, no process groups; nohup ignores SIGHUP, which is sufficient for the child to survive the parent console closing). POSIX path: setsid → resolved-python os.setsid() → nohup, with the python branch now gated on -V so the App Execution stub never fires.

smart-install.sh — Windows branch in the uv-install block uses the official PowerShell installer (irm https://astral.sh/uv/install.ps1 | iex); same destination (~/.local/bin/uv.exe), so the post-install PATH prepend works uniformly. The cs-cite settings.json patcher uses claude_smart_resolve_python instead of bare python3. Also adds ~/.local/bin/uv.exe to the post-install fallback search.

backend-service.sh / dashboard-service.sh — drop the inline setsid/python3/nohup chains; call claude_smart_spawn_detached and record $!. PID-file logic split per-OS:

  • Windows: record the spawned MSYS pid; claude_smart_kill_tree translates to WINPID at signal time.
  • POSIX with setsid: record the pid (== pgid by setsid contract).
  • POSIX fallback: derive pgid via ps -o pgid as before.

kill_group becomes a one-line wrapper around claude_smart_kill_tree so the cross-OS logic lives in one place.

What's intentionally out of scope

  • reap_port_listeners (backend-service.sh) and the dashboard stop fallback both use lsof, which isn't on Git Bash by default. Existing command -v lsof guards already make these no-ops on Windows. Replacing them with netstat -ano | findstr LISTENING parsing would work but expands surface area. The recorded-pid path with taskkill /T /F already covers the normal stop case (kills npm plus its node children).
  • Pinning uv sync --python <ver>: while building this PR I hit a separate failure where uv defaulted to Python 3.14 and hdbscan (transitive via reflexio-ai) has no 3.14 wheel for Windows, so the source build fired and failed on a 3.14 incompatibility. That's a transitive-dep issue, not a Windows-bash issue, and would also bite Linux/macOS users who install Python 3.14. Worth fixing upstream (probably by pinning in pyproject.toml or via a --python flag), but I left it out so this PR stays focused on the bash-vs-Windows angle.
  • .env file encoding: reflexio's .env scaffolding wrote a CP1252-encoded em-dash (byte 0x97) into a comment, which python-dotenv then rejected on the backend at startup. Repository for that fix is ReflexioAI/reflexio, not this one.

Test plan

  • bash -n clean on all four edited scripts.
  • claude_smart_is_windows returns 0 on Git Bash MINGW64 (Windows 11), 1 on Linux/macOS shells.
  • claude_smart_resolve_python returns the real python interpreter on Windows when both real-Python and the WindowsApps stub are on PATH; returns python3 on POSIX.
  • claude_smart_spawn_detached + claude_smart_kill_tree round-trip: spawn ping -n 100 127.0.0.1, verify kill -0 reports alive, verify tasklist shows PING.EXE with the matching WINPID, kill via helper, confirm process gone from tasklist and kill -0 reports dead.
  • smart-install.sh end-to-end on Windows 11 / Git Bash: uv installs via PowerShell (no unzip corruption), uv sync completes (with Python 3.12 — see the "out of scope" note above), dashboard npm install + npm run build produce a working .next/.
  • Backend (reflexio services start --only backend --no-reload) and dashboard (npm run start) reach /health after manual launch via the helpers; /claude-smart:dashboard opens http://localhost:3001 and renders.
  • Validation on Linux + macOS — code paths are gated on claude_smart_is_windows so behaviour should be unchanged, but a maintainer with those environments should re-run the existing service start/stop tests to confirm.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved process lifecycle and termination management for consistent cross-platform behavior across Windows, macOS, and Linux
    • Enhanced Windows installation script compatibility with better system integration
    • More robust background service startup and shutdown handling with improved platform-specific support

Five Git-Bash-on-Windows bugs prevented the plugin install + service
auto-start from working. None of them affect Linux/macOS — every change
is gated on `claude_smart_is_windows` (uname matches MINGW*/MSYS*/CYGWIN*).

1. uv install: the astral.sh bash installer downloads a zip and unzips
   it, but Git Bash's bundled unzip corrupts the Windows uv.exe (bad CRC
   on the inflated binary). On Windows, run the official PowerShell
   installer (install.ps1) instead — same destination
   (~/.local/bin/uv.exe), so the post-install PATH prepend works
   uniformly.

2. python3 App Execution Alias stub: on Windows,
   %LocalAppData%\Microsoft\WindowsApps\python3.exe is a Microsoft Store
   launcher stub. `command -v python3` returns truthy but invoking it
   prints "Python was not found" and exits non-zero. Add
   claude_smart_resolve_python which probes interpreters with `-V` to
   filter the stub out, preferring `python` (the real installed one)
   over `python3` on Windows. Used by smart-install.sh's settings.json
   patcher and by the spawn-detached fallback.

3. spawn_detached on Windows: Git Bash has no setsid, no process groups,
   and os.setsid() is POSIX-only — the existing python3-based fallback
   would never work even if a real Python were on PATH. Use plain nohup
   on Windows: ignoring SIGHUP is sufficient for the child to survive
   the parent console closing, and Windows doesn't have the
   zombie-on-parent-exit problem POSIX has.

4. kill_tree on Windows: kill -TERM -- "-pgid" (negative pid = process
   group) is a POSIX construct with no Windows equivalent. Use taskkill
   /T /F /PID, which walks the child-process tree via the
   parent-pid/job-object relationships. Subtlety: in Git Bash, $! for a
   backgrounded job returns the MSYS pid (an internal counter), not the
   native Windows pid taskkill needs. ps's default output exposes the
   WINPID column; awk extracts it. Service scripts now delegate
   kill_group to claude_smart_kill_tree so the logic stays in one place.

5. Service start scripts (backend-service.sh, dashboard-service.sh):
   the inline setsid/python3/nohup detach blocks would land in the
   broken python3 branch on Windows. Replace with the unified
   claude_smart_spawn_detached helper. PID-file recording is split:
   Windows records the spawned MSYS pid (translated to WINPID by
   kill_tree at signal time); POSIX still records the pgid where setsid
   guarantees pid==pgid, and falls back to ps -o pgid otherwise.

Tested on Windows 11 / Git Bash (MINGW64): smart-install.sh now
completes (uv install + uv sync + dashboard build), and
claude_smart_spawn_detached + kill_tree round-trip a `ping -n 100`
through start-alive-kill-gone end-to-end.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 27, 2026

📝 Walkthrough

Walkthrough

Introduces cross-platform process lifecycle management abstractions for shell scripts. Adds Windows/POSIX-aware spawning, killing, and Python resolution primitives in a shared library, then refactors service scripts to use these helpers instead of direct system calls.

Changes

Cohort / File(s) Summary
Core Platform Abstractions
plugin/scripts/_lib.sh
Introduces claude_smart_is_windows(), claude_smart_resolve_python(), updates claude_smart_spawn_detached() with Windows/POSIX branching, and adds claude_smart_kill_tree() for cross-platform process termination with escalation logic.
Service Lifecycle Refactoring
plugin/scripts/backend-service.sh, plugin/scripts/dashboard-service.sh
Replaces manual process group signaling and platform-specific spawning with calls to claude_smart_spawn_detached() and claude_smart_kill_tree(); adjusts PID/PGID recording to account for platform differences (Windows vs. setsid-capable vs. macOS fallback).
Installation & Tooling
plugin/scripts/smart-install.sh
Adds Windows-specific uv installer branch (PowerShell) and .exe binary detection; replaces hard-coded python3 requirement with claude_smart_resolve_python() for cs-cite allowlist updates.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 Processes now hop with platform flair,
Windows and POSIX both handled with care,
Spawning and killing, now neat and divine,
Cross-platform helpers make all scripts align!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding Windows (Git Bash) support to plugin shell scripts.
Docstring Coverage ✅ Passed Docstring coverage is 80.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@plugin/scripts/_lib.sh`:
- Around line 42-59: The POSIX branch of claude_smart_resolve_python currently
only checks discoverability with command -v but must also verify the interpreter
actually runs like the Windows branch; update the for-loop for cand in python3
python to, after command -v "$cand", attempt a lightweight runtime check (e.g.,
"$cand" -V or --version redirected to /dev/null) and only return that candidate
if the check succeeds so that claude_smart_spawn_detached() will receive a
working interpreter; keep the same candidate order and error handling (return 1
if none pass).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 18d623bb-c99a-403a-a30b-f6680f6fd22a

📥 Commits

Reviewing files that changed from the base of the PR and between e412c32 and 0bfaebb.

📒 Files selected for processing (4)
  • plugin/scripts/_lib.sh
  • plugin/scripts/backend-service.sh
  • plugin/scripts/dashboard-service.sh
  • plugin/scripts/smart-install.sh

Comment thread plugin/scripts/_lib.sh
Comment on lines +42 to +59
claude_smart_resolve_python() {
if claude_smart_is_windows; then
for cand in python python3; do
if command -v "$cand" >/dev/null 2>&1 && "$cand" -V >/dev/null 2>&1; then
command -v "$cand"
return 0
fi
done
return 1
fi
for cand in python3 python; do
if command -v "$cand" >/dev/null 2>&1; then
command -v "$cand"
return 0
fi
done
return 1
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Resolver implementation:"
sed -n '35,59p' plugin/scripts/_lib.sh

echo
echo "Detach path that executes the resolved interpreter:"
sed -n '71,83p' plugin/scripts/_lib.sh

echo
echo "Other runtime call sites:"
rg -n 'claude_smart_resolve_python|claude_smart_spawn_detached' plugin/scripts

Repository: ReflexioAI/claude-smart

Length of output: 2565


Probe POSIX candidates before returning them.

The function's comment explicitly promises a working interpreter, but the POSIX branch only checks discoverability via command -v, whereas the Windows branch validates with -V. A broken shim (e.g., pyenv stub) can pass the POSIX check and then fail at runtime when executed directly in claude_smart_spawn_detached() at line 78. This is inconsistent with the documented contract and the Windows logic.

Suggested change
 claude_smart_resolve_python() {
   if claude_smart_is_windows; then
     for cand in python python3; do
       if command -v "$cand" >/dev/null 2>&1 && "$cand" -V >/dev/null 2>&1; then
         command -v "$cand"
         return 0
       fi
     done
     return 1
   fi
   for cand in python3 python; do
-    if command -v "$cand" >/dev/null 2>&1; then
+    if command -v "$cand" >/dev/null 2>&1 && "$cand" -V >/dev/null 2>&1; then
       command -v "$cand"
       return 0
     fi
   done
   return 1
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugin/scripts/_lib.sh` around lines 42 - 59, The POSIX branch of
claude_smart_resolve_python currently only checks discoverability with command
-v but must also verify the interpreter actually runs like the Windows branch;
update the for-loop for cand in python3 python to, after command -v "$cand",
attempt a lightweight runtime check (e.g., "$cand" -V or --version redirected to
/dev/null) and only return that candidate if the check succeeds so that
claude_smart_spawn_detached() will receive a working interpreter; keep the same
candidate order and error handling (return 1 if none pass).

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