Expand description
toolchain.resolve_install_command / toolchain.install_system_tool —
one-click install of git/Node/npm/Python through the platform’s own
package manager, streamed via the exact same install_chunk wire
shape install.start already uses.
SPEC_SYSTEM_TOOLCHAIN_INSTALLER_2026_08_24.md. This is that spec’s
Phase 1+2 (Linux + macOS + Windows) — NOT its deferred Phase 3
(bootstrapping a MISSING package manager itself: installing Homebrew
from scratch, or guiding a pre-App-Installer Windows through updating
it). If brew/winget aren’t present, resolve_install_step simply
returns None and the caller falls back to the existing link+copy-
command UI — this module never tries to install the package manager.
The security-critical invariant of this whole module: every
command this module can ever run comes from the fixed, hardcoded
catalog in resolve_install_step below, addressed only by a tool_id
validated against is_safe_tool_id. The RPC boundary never accepts a
package name, a raw command, or anything else that could reach a
Command’s argv from client input. Every entry is a Vec<String>
passed straight to Command::new(program).args(args) — never a shell
string through sh -c/cmd /c — so there is no interpolation surface
even though nothing in this table is user-suppliable today.
Structs§
- Install
Command 🔒Available - Install
Command 🔒Unavailable - Install
System 🔒Tool Result - What
toolchain.install_system_toolanswers: the install session to follow. - System
Install 🔒Step - One resolved, ready-to-spawn install command. Never constructed from
client input — always the output of
resolve_install_step’s fixed catalog lookup. - Tool
IdReq 🔒
Enums§
- Linux
Package 🔒Manager - Linux package managers this module knows how to drive, in detection
priority order (first found on PATH wins — see
detect_linux_package_manager). - Resolve
Install 🔒Command Result - What
toolchain.resolve_install_commandanswers. Untagged, so the JSON is the same two shapes the handler always sent, and ts-rs renders it as the{ available: false } | { available: true, ... }union the frontend narrows on.
Constants§
Functions§
- apt_
primary_ 🔒package - Primary package name to query a version for on apt specifically — the
actual install still uses
resolve_linux_step’s full, PM-aware package list below; this is only the one representative package worth asking apt “what version would you install” about for display purposes. - brew_
formula 🔒 - Homebrew formula names — its own function for the same reason as
windows_winget_idabove: shared between the install-args builder and the version query, without a second copy that could drift. - claim_
key_ 🔒for_ tool - The one entry point into the catalog — dispatches by compile-time
platform, then (macOS/Linux) by what’s actually detected on this
machine. Returns
Nonewhenever nothing can be resolved (unknown tool id, or — macOS/Linux only — no usable package manager found); callers must treatNoneas “fall back to the existing link+copy- command UI,” never as an error. Normalizes which claim slot a tool_id occupies inInstallSessionRegistry.active_system_tools."npm"shares Node’s slot on every platform (§3.5: they resolve to the exact same winget/brew/apt-family package transaction — installing Node already gets npm), so starting installs from both rows concurrently must not be allowed to both pass the claim check and race two installs of the same package (winget/msi lock errors, duplicate install prompts). Codex P2, PR #2790. - detect_
linux_ 🔒package_ manager - Probe for a Linux system package manager on PATH, in priority order —
first match wins (a system with both
apt-getand an unrelated manually-installed tool named e.g.dnfshould still prefer the native one). Every mainstream Linux distro ships with exactly one of these as part of the base OS — unlike Homebrew/winget, there is no “package manager itself might be missing” case to handle here. - is_
safe_ 🔒tool_ id - Tool ids feed straight into the catalog match in
resolve_install_step— same shape constraint asinstall_handlers::is_safe_provider_id(short, alnum +_/-), kept as its own function rather than reused so this module’s validation doesn’t silently drift if that one’s constraints ever change for provider-id-specific reasons. - query_
apt_ 🔒version - Parses
apt-cache policy <pkg>’sCandidate:line — the version apt would actually install right now. Scoped to apt only, deliberately:dnf/pacman/zypper/apkeach have a genuinely different query command and output format (dnf info,pacman -Si,zypper info,apk policy/apk info), and implementing all five for a display-only version label isn’t worth the surface area in one pass. ReturnsNonefor every other manager — the frontend falls back to unversioned copy, which is honest, not a stale guess pretending to be real. - query_
brew_ 🔒version - Parses
brew info --json=v2 <formula>’sversions.stablefield. Best-effort, same posture asquery_winget_version. - query_
winget_ 🔒version - Parses
winget show --id <id> -e’sVersion:line. Best-effort: any failure (winget missing/erroring, unexpected output format) returnsNoneand the frontend falls back to unversioned copy — never a guess. Deliberately a separate call from the actual install, not a flag on it:shownever mutates anything, so it’s safe to run purely for display even before the user has consented to installing. - register_
system_ install_ handlers - resolve_
brew_ 🔒step - Only reachable when
brewis already on PATH (checked by the caller,resolve_install_step) — this module never bootstraps Homebrew itself. - resolve_
install_ 🔒step - resolve_
linux_ 🔒step - Elevated via
pkexec, which raises the desktop’s own native polkit authentication dialog — AgentMux never renders a password field or handles a credential itself. If no polkit agent is running (minimal window managers, some server-oriented desktops),pkexecfails fast with a clear, distinct error; the caller’s existing link+copy-command fallback remains available regardless. - resolve_
windows_ 🔒step - spawn_
system_ 🔒install_ task - verify_
bin_ 🔒for_ tool - Binary name to re-probe after a successful install (see
SystemInstallStep::verify_bin’s doc comment)."npm"verifies via"node"(bundled together, same reasoning asclaim_key_for_tool);"python"’s real executable name differs by platform. - windows_
winget_ 🔒id