description: "The local PowerShell executor for deployments and maintainers choosing, configuring, or debugging unconfined PowerShell command execution over the shell seam."
English | 中文
dsh-pwsh-local is the PowerShell executor: every command runs as a fresh, non-interactive pwsh -Command process with no profile files, so no shell state survives between calls. It mirrors dsh-bash-local's semantics call-for-call and adds PowerShell-shaped concerns: executable resolution, UTF-8 output pinning, and the model-friendly terminal environment. Commands run with the harness process's own authority — this executor confines nothing; compose dsh-pwsh-sandbox when commands need the sandbox capability. The model-facing pwsh tool talks to it once it is mounted.
Mount this executor when a composition needs PowerShell command execution — typically on Windows — without confinement. It registers as ctx.shell, and the model-facing pwsh tool works over it immediately: an agent calls the tool, and the command runs as a fresh pwsh -Command process with the budgets below.
It is the Windows counterpart of dsh-bash-local: choose it where pwsh is the platform shell, so a composition can swap the POSIX rows for the pwsh rows and keep the same semantics. The executor resolves the pwsh executable from an explicit pwshPath, well-known Windows install locations, PATH entries, or Windows PowerShell 5.1 as a last resort. For unconfined execution it is the default; compose dsh-pwsh-sandbox when commands need the sandbox capability.
Load the executor with the budgets you want; every field has a default, so the smallest composition is the plugin entry alone. The settings provider (when composed) layers a user section over this entry, so budgets can change at runtime without a reload (see Adjusting budgets at runtime).
- id: bash
name: '@deepseek-ai/dsh-pwsh-local'
config:
cwd: C:\path\to\workspace
timeoutMs: 120000
| Field | Default | Meaning |
|---|---|---|
cwd |
process.cwd() |
Default working directory for commands |
timeoutMs |
120,000 |
Default foreground timeout, in milliseconds |
maxTimeoutMs |
600,000 |
Cap for per-call timeout overrides |
maxOutputBytes |
64,000 |
Per-stream in-memory output cap; overflow spills to a temp file |
maxSpillBytes |
67,108,864 |
Per-stream full-output spill cap |
graceMs |
3,000 |
Grace period for kill escalation and post-exit pipe draining |
pwshPath |
resolved | Explicit pwsh executable; else well-known locations, then PATH |
The generated configuration catalog is the exhaustive source for every accepted field and its JSDoc.
Run a command with run and read its output from the result; a nonzero exit, a timeout, or a cancellation resolves descriptively, and only infrastructure failures reject. The command string rides as one argument to -Command: PowerShell parses the text itself and no intermediate shell exists, so there is no shell-quoting layer to escape and native Win32 paths pass through unchanged. Every command pins UTF-8 output first, so non-ASCII output is not garbled even on the Windows PowerShell 5.1 fallback. The environment is model-friendly: NO_COLOR=1 PAGER=cat GIT_PAGER=cat (no TERM=dumb — a POSIX concept), with explicit caller-provided entries still winning.
const result = await ctx.shell.run(ctx.shell.resolve({ command: 'Get-ChildItem' }))
if (result.timedOut) console.log('timed out after', result.timeoutMs)
Await start to run a command in the background; it resolves with the prepared process handle and no execution timeout applies. Cancellation or preparation failure rejects before a handle is published. readOutput() merges the stream deltas into one consuming read, marking stderr under a [stderr] section; kill() terminates the provider-managed range; done settles when the direct command closes and never rejects. Job ids, ownership, polling, and notices belong to the generic ctx.jobs runtime, which the tool layer registers the handle with.
When a settings provider is composed, this executor registers the capability's shared shell settings namespace — the same one the POSIX family uses, because a host composes exactly one provider of ctx.shell — so a user section in settings.yaml layers over the composition entry and the next command runs with the new budgets. Values the schema cannot judge — positive and finite numbers, and the graceMs timer bound — are refused at the write, leaving the running executor on its last good section.
Read these pages when the executor contract is not enough. They move from the seam to the confining sibling and the PowerShell tool.
pwsh tool over this executor.Indirectly, through dsh-tool-pwsh, which renders this executor's bounded stdout/stderr tails, background-process deltas (through the generic job runtime), spill-file paths, and infrastructure failures.
No direct invalidation; the named consumer owns any request-prefix changes.
These limits define when this executor is a poor fit. They are current package constraints, not a roadmap.
pwsh -Command.-Command domain has no shell-quoting layer, but a model-facing command is parsed by PowerShell itself, so PowerShell syntax errors are command failures, not launch failures.SubprocessHandle.done can reject before or after target execution begins, so the executor injects the stage-neutral subprocess failed before reporting an outcome: … into exactly one readOutput() delta; a reader that discards that delta cannot recover it.signal: null, so signal-based status classification does not apply on Windows; kill()-initiated stops still stamp killed directly.param(...), #requires, and using statements at the very top of a script, so a command whose first statement is one of those cannot run under the UTF-8 output preamble; wrap a param(...) script in & { … }, and run using/#requires scripts from a file instead.[Console]::InputEncoding stays at the host default because setting it under redirected stdin throws; pwsh 7 defaults to UTF-8 and is unaffected.