main
Kyle Bergstedt Publish 1.1.112 8d0a92c 5d ago

name: adom-vscode-exec description: "Run shell commands inside the Adom container through the adom-vscode extension, streamed live (SSE) or buffered, as the workspace user via a login shell. LOCAL-WORKSPACE ONLY (kind:hd — WSL2 on Windows, the Hydrogen workspace machine on macOS): cloud (hw) containers refuse exec (exec_disabled_on_cloud), check /health verbs first. THE native replacement for routing workspace commands through an out-of-band host spawn (wsl.exe on Windows, limactl/nsenter on macOS). Trigger words: exec disabled, exec_disabled_on_cloud, exec in container, run command in container, adom-vscode exec, stream exec, streamed output, exec stream, container shell, run npm test in container, long running command, exec timeout, exec cwd, no wsl.exe, wsl exec replacement, POST /exec, SSE exec."

Parent skill: adom-vscode

adom-vscode-exec, run container commands natively

LOCAL-WORKSPACE ONLY (security policy). exec runs only where container reports kind: hd — the WSL2 workspace on Windows and the systemd-nspawn workspace machine on macOS. Cloud (hw) containers refuse both exec verbs with errorCode: exec_disabled_on_cloud (HTTP 403), and /health omits exec / exec.stream from its verb roster there, so feature-detect before offering exec. Rationale: adom-vscode is a core install for every Adom user, and an arbitrary-shell verb on an internet-facing cloud container is an unnecessary exposure; local workspaces sit behind the user's own firewall. On a cloud container, run commands in your own terminal/session instead. Debug escape hatch: ADOM_VSCODE_ALLOW_EXEC=1 set in the EXTENSION HOST env by the platform (a remote caller cannot set it).

The 403 body carries its own error, kind and hint — read those. It does NOT mean the extension is missing, so do not answer a 403 by reinstalling and reloading the window (that kills live AI sessions and cannot fix a policy gate).

Commands run as the workspace user (adom) via bash -lc inside the container, spawned by the extension host itself. LOGIN shell matters: tools like adom-bridge need the workspace env from /etc/profile.d/ (hd-env.sh on Windows, hydrogen-env.sh on macOS), and a bare -c shell runs them env-less (they fail with nothing on stdout).

CLI

adom-vscode exec "ls -la" --cwd /home/adom/project   # streams stdout/stderr live
adom-vscode exec "npm test" --timeout 600            # long jobs: raise the timeout (seconds)
adom-vscode exec "uname -a" --json                   # buffered: waits, prints one JSON result
  • Streaming is the default: stdout goes to your stdout, stderr to stderr, and the CLI exits with the remote command's exit code, so && chains work.
  • --json (buffered) returns {ok, exitCode, timedOut, stdout, stderr} with output capped at 64 KB per stream; use streaming for anything chatty.
  • Timeouts: streaming default 300s (max 3600), buffered default 120s (max 1800). A timed-out command is SIGKILLed and reported (timedOut: true, exit 124 on the CLI when the remote code is unknown).

HTTP

  • POST /exec {command, cwd?, timeoutSec?} buffered.
  • POST /fs/write {path, base64 | text, mkdir?} writes a file as the workspace user (atomic, parent directories created); the way to land bytes in the container without piping through a shell. Same HD-local policy as exec; fs.write appears in /health verbs when allowed.
  • GET /stats returns kernel counters (memory, CPU ticks, OOM-kill count, load, uptime) in one read, for meters and health without a probe.
  • POST /exec/stream {command, cwd?, timeoutSec?} Server-Sent Events: start, then stdout / stderr events (data is a JSON-encoded chunk), then exit {exitCode, timedOut}. Closing the connection kills the child, so a frontend that navigates away does not leak processes.

Why not an out-of-band host spawn

Windows: Hydrogen's legacy path spawned wsl.exe -d Adom-Workspace -u adom -- bash -lc <cmd> on the Windows host behind a global serial lock. That path caused nearly every "wsl.exe is flaky / it wedged" incident: E_UNEXPECTED, management-plane wedges, and everything queued behind one lock, with no VS Code API access.

macOS: the equivalent is limactl shell / nsenter into the nspawn machine, or Hydrogen control's POST 127.0.0.1:47084/workspace/exec — same story: another process boundary, no VS Code API, and a per-call setup cost.

Either way: once the editor is up, prefer extension exec for EVERYTHING (on the extension's real port — see port.json, not a hard-coded 8821). Keep the host spawn only for the bootstrap phase (machine import, code-server start) before this API exists.

Gotchas

  • The exec verbs are for CONTAINER work. To run a VS Code command (palette action), use adom-vscode command <id> instead.
  • ok:true on the buffered form means the process ran; check exitCode.
  • Feature-detect with GET /health: verbs contains exec and exec.stream.