VS Code agent bootstrap and safe Praetor CLI execution
Recommendation (13 September 2026): keep the extension as a thin, trusted
workspace adapter and invoke a pinned praetorctl binary through
vscode.ProcessExecution with an argument array and an explicit selected
workspace folder. Do not send interpolated strings to a terminal. Gate commands
that read or execute workspace content on Workspace Trust, and return a clear
restricted-mode result. Make the executable path a machine-scoped setting or a
validated user choice; never accept a workspace setting as an executable
authority while untrusted.
The baseline scaffold at commit 54435ec in editors/vscode/src/extension.ts
started an LSP with a configurable executable and first workspace folder
(:20-30), but its audit,
compile, and GC commands call terminal.sendText with shell command strings
(:100-143). Its status bar claims HISS: 100% Pass and “verified” sentinel
headroom without invoking Praetor (:60-95, :125-134). The manifest exposes
workspace-overridable configuration by default and has no explicit
capabilities.untrustedWorkspaces declaration (editors/vscode/package.json:45-86).
The package has only TypeScript, Node types, VS Code types, and
vscode-languageclient development dependencies; no process runner is already
available.
Relevant VS Code contracts
The Workspace Trust extension guide
(current documentation checked 2026-09-13) supports manifest declarations
untrustedWorkspaces: {supported: true|false|'limited', ...}. A limited
extension can gate sensitive paths with vscode.workspace.isTrusted and
onDidGrantWorkspaceTrust; the isWorkspaceTrusted context key can hide or
disable commands. VS Code’s Workspace Trust guide
explains that Restricted Mode limits terminal, tasks, debugging, agents, and
extensions, but also warns that a malicious extension can ignore the boundary.
Trust is therefore a user consent boundary, not a sandbox or proof that another
extension is safe. The extension cannot universally force other extensions or
native clients to request permissions; their manifests, user settings, and
host policy control those behaviors.
For direct execution, the VS Code API reference
defines ProcessExecution(process, options) as an external process without
shell interaction; options.cwd sets its working directory. Use
new vscode.Task(..., new vscode.ProcessExecution(binary, args, {cwd})) or a
child-process wrapper with equivalent argv semantics. The API also defines
ShellExecution, but the task-provider guide
warns that shell execution interprets quoting, expansion, and wildcards; it is
not the safe default for user or workspace data. Validate that the configured
binary is an absolute regular executable, resolve the chosen workspace folder,
and pass request/store paths as separate arguments. Capture exit status and
bounded output, and surface cancellation and timeout as incomplete results.
vscode.workspace.workspaceFolders is an array for multi-root workspaces.
workspace.getWorkspaceFolder(uri) maps a resource to its containing folder,
and
showWorkspaceFolderPick
returns a user-selected folder or undefined when no folder is open. Commands
must not silently use index zero when multiple roots exist. A picker or an
explicit command argument should select the root; no-root windows should return
an actionable “open a workspace” result.
Contributed commands and settings are declared in the extension manifest and
read with workspace.getConfiguration, as documented by the contribution
points reference
and command guide.
Mark executable and trust-sensitive settings with the appropriate scope and
restrictedConfigurations; a workspace can otherwise provide an executable
path that changes what the extension runs.
Small adapter seam and tests
The adapter should expose one pure request object: selected folder URI,
validated executable, fixed subcommand, argv, bounded deadline, and output
limit. A resolver performs workspace selection, trust/configuration checks, and
path validation. An executor receives argv and cwd, invokes ProcessExecution
or an equivalent no-shell child-process wrapper, and returns {exitCode, stdout, stderr, cancelled, timedOut, outputExceeded}. It must not
construct a shell command. Existing commands map to praetorctl audit and
praetorctl compile-context with the selected root as the process working
directory. Verification uses make verify-all; it is not a CLI subcommand.
Test the resolver and executor as ordinary Node/TypeScript unit tests with fake process and workspace objects: trusted/untrusted, no-root, single-root, multi-root selection, relative or symlinked executable, spaces and shell metacharacters in paths, cancellation, timeout, non-zero exit, bounded output, and configuration changes. Add an extension-host smoke test only for command registration and trust gating. VS Code’s extension testing guide explicitly notes that tests cannot programmatically grant or revoke Workspace Trust, so trust scenarios need separate launched fixtures or manual acceptance. The CLI itself should be tested independently against temporary repositories; those tests provide stronger evidence than terminal screenshot or GUI tests.
The later local adapter revision has unit coverage for argv separation, invalid
executable values, bounded output, and timeout termination; npm test compiles
the package and passes the current 17 runner/setup tests, including real Go CLI
configuration preparation, application and backup readback. Those are package checks,
not a Workspace Trust transition test or native client activation proof.
The separate test:host command passed on installed VS Code 1.137.0: the extension
activated, registered five commands, and blocked an audit subprocess in the
observed untrusted workspace. It uses temporary profiles and the documented
extension-development/test CLI flags. This does not qualify other editors or
trusted multi-root command flows. The baseline scaffold findings above should be read against
commit 54435ec; subsequent implementation work is not retroactive evidence for
that snapshot. The smoke test is partial host evidence; no native agent session
has proved full adapter behavior or granted permissions through this test.