Download

Shell & process verbs

Run shell commands, scripts, WSL, and launch/locate apps on the laptop.

Part of the Adom Desktop verb reference. Invoke as adom-desktop <verb> '<json>'.

find_exe

Find an executable without launching it. Searches: (1) absolute path as-is, (2) glob expansion for webdeploy-style version directories, (3) Start Menu .lnk targets, (4) PATH. Returns the resolved absolute path or an error.

Args:

  • name — required: bare name ('Fusion360.exe'), glob ('.../webdeploy/production/*/Fusion360.exe'), or full path
  • searchPaths — optional array of extra dirs to scan

Returns: path, source (absolute|glob|startmenu|path)

launch

args

run_script

v1.8.46+: Execute a base64-encoded script via a chosen interpreter (cmd / powershell / bash). The script bytes never touch a shell-string parser, so NO quoting/escaping survives to be mangled by cmd.exe, PowerShell's parser quirks, or MSYS path conversion — caller never hand-escapes anything. Host-side: cmd / powershell get a temp file (.cmd / .ps1); bash gets the script via stdin (no temp file). Output decoded as UTF-8 (UTF-16LE detection for PowerShell 5.1 output). Returns stdout/stderr/exitCode and cleans up any temp file.

Args:

  • allowPopupRisk — optional bool (v1.8.117+) — bypass the popup-risk pre-flight on cmd scripts. AD refuses (errorCode popup_risk, failedAt popup_scan, scriptLine N) any start <target> line whose target doesn't resolve — that flashes a modal 'Windows cannot find' dialog on the user's desktop. powershell/bash scripts aren't scanned (no ShellExecute popup failure mode).
  • interpreter — required string: 'cmd' | 'powershell' | 'bash'. PowerShell prefers pwsh (PS 7+) if on PATH, falls back to powershell.exe (5.1). Bash uses whichever is first on PATH — on Windows that's typically WSL2's System32\bash.exe (the intended interpreter; stdin piping means no path-form mismatch). For explicit distro / user control on WSL, use wsl_exec.
  • scriptB64 — required string: base64-encoded script content (no length limit beyond practical WS message size — keep under a few MB for sanity).
  • timeoutSeconds — optional int (default 60). The CLI's WS timeout is auto-sized to scriptTimeout + 15s margin.

Returns: On success: {success:true, ok:true, stdout, stderr, exitCode, durationMs, interpreter, [_hint?]}. On failure: {success:false, ok:false, stdout:'', stderr:'', exitCode:-1, error, failedAt, _hint}. failedAt is one of: 'args' (interpreter unknown / scriptB64 empty), 'decode' (base64 not parseable), 'tempfile' (cmd/powershell temp-file write failed — see tempPath in payload), 'spawn' (interpreter exe couldn't launch — see spawn_failure_hint output), 'timeout' (script ran longer than timeoutSeconds). EVERY failure path carries a _hint with the specific recovery recipe — READ the hint, don't guess. v1.8.60+ ADVISORY: success responses may also include an optional _hint field when the script looks like a direct HD build (raw cargo/pnpm against hydrogen-desktop/crates/hd-* paths). The hint is additive — exit code / stdout / stderr are UNCHANGED — and points at the dedicated hd_build_* / hd_ship verbs.

Note: Requires shell auto-approve to be active — same trust level as shell_execute. Enable with shell_auto_approve '{"duration_secs": 86400}' (24h) or '{"permanent": true}' (no expiry). Embedded mode defaults to permanent. Refuses cleanly with an actionable error if not approved (no per-call modal — these are programmatic verbs, not interactive).

shell_execute

Execute a shell command on the user's desktop (requires user approval). Escape hatch for things that don't have a structured verb yet — most common operations are covered by desktop_install_node / desktop_install_kicad / desktop_list_files / desktop_watch_files / desktop_list_browsers etc., which DON'T require per-call approval. Use shell_execute only when no structured verb exists for the task.

Args:

  • allowPopupRisk — optional bool (v1.8.117+) — bypass the popup-risk pre-flight. AD refuses (errorCode popup_risk) any start <target> whose target doesn't resolve, because that flashes a modal 'Windows cannot find' dialog on the user's desktop. Verify targets first (find_exe / launch / desktop_open_url); only pass true when the command creates its own target and the scan misjudged it.
  • command — required string — full shell command (Windows: runs through cmd /c; macOS/Linux: through sh -c)
  • cwd — optional working directory
  • timeoutSeconds — optional int (default 30, max effectively unbounded — pass whatever your task needs). v1.7.3+ this is actually honored end-to-end. Pre-v1.7.3 the CLI accepted it for its own HTTP socket but dropped it before forwarding, so the desktop side defaulted to 120s and killed long-running tasks regardless. Long rust builds / ffmpeg renders / docker pulls etc. should set 600-1800s.

Returns: stdout, stderr, exitCode

Note: User must approve via in-app dialog unless auto-approve is active. v1.7.3+ timeout forwarding bug fixed — your timeoutSeconds is now respected by the desktop-side shell killer. v1.7.16+ approval-polling fixed — the CLI now polls the relay's deferred-result endpoint with the original requestId instead of re-sending the command every second (which v1.7.15 did, causing infinite 'Another shell command is already waiting for approval' loops because every retry created a fresh approval the user could never out-click).

shell_kill_all

Kill all running shell command processes

wsl_exec

v1.8.46+: Execute a base64-encoded script inside a WSL distro via the canonical wsl -d <distro> -u <user> -- bash -lc <decoded> argv array. Eliminates the --, nested-quote, and $_ pitfalls because Rust's std::process::Command on Windows applies proper CommandLineToArgvW quoting per argv element — wsl.exe sees bash -lc <decoded> as three distinct argv items, then bash's -c sees the entire script as ONE string with no outer-shell interpretation. The exact 50×-per-session call pattern.

Args:

  • distro — required string: WSL distro name (e.g. 'Adom-Workspace', 'Ubuntu'). wsl -l -v enumerates installed distros.
  • scriptB64 — required string: base64-encoded bash script. Decoded content must be valid UTF-8.
  • timeoutSeconds — optional int (default 60). The CLI's WS timeout auto-sizes to scriptTimeout + 15s margin.
  • user — required string: WSL user to run as (e.g. 'adom', 'root'). Must exist in the distro.

Returns: On success: {success:true, ok:true, stdout, stderr, exitCode, durationMs, interpreter:'wsl', distro, user, [_hint?]}. wsl.exe's UTF-16LE output is decoded as text automatically (BOM-detect + odd-position-NULL heuristic, fall back to UTF-8 lossy). On failure: {success:false, ok:false, stdout:'', stderr:'', exitCode:-1, error, failedAt, _hint}. failedAt is one of: 'args' (distro/user/scriptB64 empty), 'decode' (base64 invalid), 'utf8' (decoded bytes not UTF-8), 'spawn' (wsl.exe couldn't launch — see wsl_error_hint), 'timeout' (script exceeded timeoutSeconds). EVERY failure carries an actionable _hint. The most common spawn failure is 'distro not installed' — the hint will tell you to run wsl -l -v to enumerate, or fall back to run_script interpreter:bash for the default distro. v1.8.60+ ADVISORY: success responses may carry an additive _hint when the script looks like a direct HD build (raw cargo/pnpm targeting hydrogen-desktop/crates/hd-*); the hint points at the dedicated hd_* verbs that handle the exe lock + SHA verification.