From c952ae954e91250925615f8c561ffb4f4df3c057 Mon Sep 17 00:00:00 2001 From: "Hermes (debby)" Date: Wed, 17 Jun 2026 16:34:01 +0200 Subject: [PATCH] =?UTF-8?q?chore:=20unify=20toolchain=20=E2=80=94=20fnm=20?= =?UTF-8?q?Node=2024,=20uv=200.11,=20probe=20detects=20version=20managers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - verify_facts_probe.py: detect fnm/nvm Node managers - TOOLCHAIN.md: resolve Node divergence (debby fnm→24, OSA node24) - uv bumped 0.9.7→0.11.21 on debby - fnm 1.39.0 installed, Node 24.16.0 default --- docs/TOOLCHAIN.md | 25 ++++++++++---------- scripts/verify_facts_probe.py | 43 +++++++++++++++++++++++++++++------ 2 files changed, 48 insertions(+), 20 deletions(-) diff --git a/docs/TOOLCHAIN.md b/docs/TOOLCHAIN.md index 92913c0..d004d7b 100644 --- a/docs/TOOLCHAIN.md +++ b/docs/TOOLCHAIN.md @@ -10,15 +10,15 @@ Probe before trusting this table — facts come from `scripts/verify_facts_probe ## Baseline versions -| Tool | Standard | Linux (Debian/Ubuntu) | FreeBSD 15 (pkg) | Manager / source | -| ---------- | ------------------- | --------------------- | ----------------------- | -------------------------------- | -| **Python** | **3.12** (floor) | `python3.12` | `python312` | system pkg + **uv** for venvs | -| **uv** | ≥ 0.11 | `uv` (astral) | `uv` (pkg) — confirm | standalone binary | -| **Node** | **24 LTS** (target) | `node` 24 | `node24` + `npm-node24` | LTS only; never a non-LTS major | -| **Rust** | stable (pinned) | rustup `stable` | `rust` (pkg) | `rust-toolchain.toml` per repo | -| **Go** | latest stable | `golang` | `go` (pkg) | only where a Go component exists | -| **Zig** | 0.15.2 | `~/.local/bin/zig` | manual | pinned (herdr build dep) | -| **tmux** | latest stable | `tmux` | `tmux` | system pkg | +| Tool | Standard | Linux (Debian/Ubuntu) | FreeBSD 15 (pkg) | Manager / source | +| ----------- | ------------------ | ---------------------------- | ----------------------- | --------------------------------- | +| **Python** | **3.12** (floor) | `python3.13` (debby) — ≥ floor | `python312` + `py312-*` | system pkg + **uv** for venvs | +| **uv** | ≥ 0.11 | `uv` 0.11.21 | `uv` (pkg) — confirm | standalone binary | +| **Node** | **24 LTS** (target)| `fnm` → v24.16.0 (debby) | `node24` + `npm-node24` | **fnm** (Rust, cross-platform) | +| **Rust** | stable (pinned) | rustup 1.95.0 | `rust` (pkg) | `rust-toolchain.toml` per repo | +| **Go** | latest stable | `golang` | `go` (pkg) | only where a Go component exists | +| **Zig** | 0.15.2 | `~/.local/bin/zig` | manual | pinned (herdr build dep) | +| **tmux** | latest stable | `tmux` | `tmux` | system pkg | ## Conventions @@ -44,10 +44,9 @@ Probe before trusting this table — facts come from `scripts/verify_facts_probe ### Node — LTS only, one major across the matrix - Standard target: **Node 24 LTS** (FreeBSD already ships `node24`; npm 11). -- **Open divergence to resolve:** debby's Hermes Docker image deliberately pins **Node 22 - LTS** (Debian trixie's bundled 20.x is EOL). FreeBSD is on **24**. These must converge. - Proposed resolution: bump the Hermes `node_source` stage `22 → 24` and retest the gateway - UI build. **Pending Hermes confirmation before flipping.** +- **Resolved 2026-06-17:** debby switched to Node 24 via `fnm` (system Node 20 remains + for OS-level tools, but all Clawdie/agent workloads use 24). FreeBSD already on 24. + One step remains: bump the Hermes Dockerfile `node_source:22` → `24` to match. - `package.json` engines floor stays generous (`>=20`) but installed runtime tracks the agreed LTS. Never run a non-LTS Node major in production. diff --git a/scripts/verify_facts_probe.py b/scripts/verify_facts_probe.py index 8974691..05d21c1 100644 --- a/scripts/verify_facts_probe.py +++ b/scripts/verify_facts_probe.py @@ -369,15 +369,44 @@ def probe_git() -> dict: def probe_build_tools() -> dict: + # Node: check fnm/nvm first (version managers override system node) + node_info = {} + system_node = run_raw(["node", "--version"]) if shutil.which("node") else None + system_npm = run_raw(["npm", "--version"]) if shutil.which("npm") else None + + # fnm (Fast Node Manager) — Rust, cross-platform, like uv for Node + fnm_bin = shutil.which("fnm") + if fnm_bin: + node_info["manager"] = "fnm" + node_info["fnm_version"] = run_raw([fnm_bin, "--version"]) + # List installed node versions via fnm + versions_dir = Path.home() / ".local" / "share" / "fnm" / "node-versions" + if versions_dir.exists(): + installed = [d.name for d in versions_dir.iterdir() if d.is_dir()] + node_info["installed"] = installed + # Check for default alias + default_link = Path.home() / ".local" / "share" / "fnm" / "aliases" / "default" / "current" + if default_link.exists(): + node_info["default"] = default_link.resolve().name + # nvm fallback + nvm_bin = shutil.which("nvm") + if nvm_bin: + node_info["manager"] = node_info.get("manager", "nvm") + + if node_info: + node_info["system_node"] = system_node + node_info["system_npm"] = system_npm + else: + node_info = {"version": system_node, "npm": system_npm, "manager": "system"} + return { - "rust": run(["rustc", "--version"]) if shutil.which("rustc") else None, - "go": run(["go", "version"]) if shutil.which("go") else None, - "zig": run(["zig", "version"]) if shutil.which("zig") else None, + "rust": run_raw(["rustc", "--version"]) if shutil.which("rustc") else None, + "go": run_raw(["go", "version"]) if shutil.which("go") else None, + "zig": run_raw(["zig", "version"]) if shutil.which("zig") else None, "python": f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}", - "node": run(["node", "--version"]) if shutil.which("node") else None, - "npm": run(["npm", "--version"]) if shutil.which("npm") else None, - "gmake": run(["gmake", "--version"]) if shutil.which("gmake") else None, - "uv": run(["uv", "--version"]) if shutil.which("uv") else None, + "node": node_info, + "gmake": run_raw(["gmake", "--version"]) if shutil.which("gmake") else None, + "uv": run_raw(["uv", "--version"]) if shutil.which("uv") else None, }