Skip to main content

Module system_install_handlers

Module system_install_handlers 

Source
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§

InstallCommandAvailable 🔒
InstallCommandUnavailable 🔒
InstallSystemToolResult 🔒
What toolchain.install_system_tool answers: the install session to follow.
SystemInstallStep 🔒
One resolved, ready-to-spawn install command. Never constructed from client input — always the output of resolve_install_step’s fixed catalog lookup.
ToolIdReq 🔒

Enums§

LinuxPackageManager 🔒
Linux package managers this module knows how to drive, in detection priority order (first found on PATH wins — see detect_linux_package_manager).
ResolveInstallCommandResult 🔒
What toolchain.resolve_install_command answers. 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§

COMMAND_TOOLCHAIN_INSTALL_SYSTEM_TOOL
COMMAND_TOOLCHAIN_RESOLVE_INSTALL_COMMAND

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_id above: 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 None whenever nothing can be resolved (unknown tool id, or — macOS/Linux only — no usable package manager found); callers must treat None as “fall back to the existing link+copy- command UI,” never as an error. Normalizes which claim slot a tool_id occupies in InstallSessionRegistry.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-get and an unrelated manually-installed tool named e.g. dnf should 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 as install_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>’s Candidate: line — the version apt would actually install right now. Scoped to apt only, deliberately: dnf/pacman/zypper/apk each 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. Returns None for 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>’s versions.stable field. Best-effort, same posture as query_winget_version.
query_winget_version 🔒
Parses winget show --id <id> -e’s Version: line. Best-effort: any failure (winget missing/erroring, unexpected output format) returns None and the frontend falls back to unversioned copy — never a guess. Deliberately a separate call from the actual install, not a flag on it: show never 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 brew is 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), pkexec fails 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 as claim_key_for_tool); "python"’s real executable name differs by platform.
windows_winget_id 🔒