feat: put ncp on PATH on both platforms; rename WSL reqs to Windows

Ports the ncp PATH work from upstream. Registering ncp as a shell-profile
function failed three ways on Windows: the default Restricted execution policy
blocks the profile itself, profiles don't exist outside PowerShell (cmd, Win+R,
Task Scheduler), and the self-elevating installer writes the admin's profile.

Windows now ships management/ncp.cmd and the installer appends management\ to
the Machine PATH via [Environment]::SetEnvironmentVariable -- never setx, which
truncates PATH at 1024 chars. A .cmd is exempt from the execution policy.

Linux symlinks /usr/local/bin/ncp -> management/nexus-cli.sh, falling back to
the old .bashrc function when sudo is unavailable.

Also renames requirements-wsl.txt to requirements-windows.txt and purges stale
WSL references, including vite.config.js's dev-server comment and
controlpanel.py's "Check WSLg." error string.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
jon
2026-07-22 14:11:18 -05:00
co-authored by Claude Opus 4.8
parent 9befa1d561
commit 6137710c25
14 changed files with 124 additions and 91 deletions
+25 -5
View File
@@ -54,19 +54,39 @@ def test_default_models_have_one_source_of_truth():
assert hardcoded not in ps1, f"install-windows.ps1 hardcodes {hardcoded!r}"
def test_powershell_files_stay_ascii():
def test_windows_scripts_stay_ascii():
# PowerShell 5.1 decodes BOM-less files as ANSI: one stray Unicode dash
# eats a quote and the whole script dies at parse time. Globbed rather than
# listed by name so a newly added .ps1 is covered without editing this test.
# eats a quote and the whole script dies at parse time. cmd.exe is worse
# still - it decodes by the console codepage. Globbed rather than listed by
# name so a newly added script is covered without editing this test.
skip = {"Promethean", "node_modules", ".git", "dist"}
ps1s = [p for p in REPO_ROOT.rglob("*.ps1") if not skip & set(p.parts)]
assert ps1s, "no .ps1 files found - did the Windows path move?"
ps1s = [p for pat in ("*.ps1", "*.cmd") for p in REPO_ROOT.rglob(pat)
if not skip & set(p.parts)]
assert ps1s, "no .ps1/.cmd files found - did the Windows path move?"
for path in ps1s:
raw = path.read_bytes()
bad = [(i, b) for i, b in enumerate(raw) if b > 0x7F]
assert not bad, f"{path.relative_to(REPO_ROOT)} has non-ASCII bytes at {bad[:3]}"
def test_ncp_is_registered_on_path_not_in_a_shell_profile():
"""A `function ncp` in a shell profile is invisible to cron, .desktop Exec
lines, cmd.exe and Task Scheduler - and on Windows the default Restricted
execution policy blocks the profile outright. Both installers must put ncp
on PATH; the profile wiring only survives as a no-sudo fallback."""
linux = (REPO_ROOT / "bin" / "restore-linux.sh").read_text(encoding="utf-8")
runtime = linux.split('if [ "$stage" = "runtime" ]; then')[1].split("\n exit 0\nfi")[0]
assert "/usr/local/bin/ncp" in runtime
ps1 = (REPO_ROOT / "install-windows.ps1").read_text(encoding="utf-8")
assert "ncp.cmd" in ps1, "installer must register the .cmd shim, not a profile function"
# setx truncates PATH at 1024 characters and has permanently broken machines.
# Comments stripped so the code that explains the ban does not trip it.
code = "\n".join(ln for ln in ps1.splitlines() if not ln.strip().startswith("#"))
assert "setx" not in code.lower()
assert 'SetEnvironmentVariable("Path"' in code
def test_first_playbook_is_the_system_prompt(tmp_path, monkeypatch):
store = PlaybookFileStore(tmp_path)
store.add_playbook(PlaybookItem(id="ctx", title="Reference", goal="ref goal",