Files
deepseek-harness/.agents/notes/implemented/feature/2026-08-02-pwsh-tool-bash-parity.md
T

4.4 KiB

Agent Note: pwsh tool bash parity

Status: implemented

English | 中文

Problem

The first Windows-native foundation shipped dsh-tool-pwsh as a deliberately minimal profile — foreground only, no background tasks, no managed-environment parity beyond three hardcoded DSH_* keys, and a marker story ("always [exit code: N]") that diverged from the bash tool's rendering without being declared. Review of that change found the model-visible contract drifting from the implementation: the description promised spill-path reporting the renderer never performed, the README claimed exports that did not exist and rendering the tool did not do, and the tool's own tests pinned the lossy behavior. The minimal profile also left the DSH_* contributor seam duplicated-by-absence: plugins contributing environment facts to ctx.bashEnv had no effect on pwsh calls.

Decision

dsh-tool-pwsh now mirrors dsh-tool-bash call-for-call, minus the sandbox surface, and its model-visible text describes exactly that behavior:

  • Rendering adopts the bash story verbatim: stdout, a marked [stderr] section, truncation notices with spill paths, (no output) for an empty body, and exit markers only for non-zero exits — a clean exit produces no marker. The description and the tool:pwsh prompt section state this precisely ("Non-zero exits are reported as [exit code: N] markers"), deliberately not copying the bash prompt's "every result" phrasing, which its own renderer contradicts.
  • run_in_background is wired through the generic task runtime exactly like the bash tool: preflight, owner registration, task_output/task_kill control, and the same outcome mapping. pwsh-local's already-mirrored start() handle backs it.
  • The DSH_* environment is shared, not duplicated: BashEnvRegistry moved out of dsh-tool-bash into a new tool-independent @deepseek-ai/dsh-bash-env package (ctx.bashEnv + built-ins + the session-persistence contributor), and both shell tools inject it. Contributors apply to pwsh calls exactly as they do to bash calls, resolving the bash tool's FIXME(bash-env-ownership).
  • Windows reality is pinned where bash has no analog: every command runs under a UTF-8 I/O preamble so the Windows PowerShell 5.1 fallback cannot garble non-ASCII output through the UTF-8-decoding collector, and the prompts teach that Windows forced termination settles as exit 1 without a signal marker.
  • Out of scope, unchanged: sandbox escalation (waits for a Windows-confining executor), persistent PTY shells (backends are Linux/macOS-only; ConPTY is roadmap work), and pwsh-specific TUI/GUI presentation (generic/terminal cards stay; a PowerShell-aware terminal card with an exit pill is roadmap work).

Alternatives considered

Keep the minimal profile and fix only the claims. Rejected: the review's core finding was that text contracts copied from bash drift without the corresponding implementation; a minimal tool plus accurate claims still leaves pwsh calls without background execution, without contributor parity, and with a divergent marker story that must be re-justified forever.

Extract a fully shared tool implementation base (abstract shell dialect, two thin leaves). Considered and deferred: the bash-env extraction and the structural mirror (render.ts/background.ts twins) are the foundation it would rest on; a full base waits until a third dialect or the persistent-PTY twin makes the abstraction's shape observable.

Consequences

  • The bash and pwsh tools are now behaviorally interchangeable for foreground and background shell work (minus sandbox), and the pwsh prompt/description sentences are each backed by the renderer — the reviewer's grep-against-code check passes.
  • @deepseek-ai/dsh-bash-env is a new shipped package; dsh-tool-bash's dshHome config moved there, so compositions mounting the shell tools must also mount bash-env (the spine bundles do).
  • Windows-only semantics (CRLF normalization, forced-termination exit-1/signal-null, POSIX-only self-signal) remain pinned by tests as before.
  • The pwsh tool's per-file coverage gate rides on the scriptable fake-executor suite (tests/tools.spec.ts); the real-pwsh integration and Loader-composition suites self-skip where pwsh is absent, mirroring the bash suites' division of labor.
  • The roadmap proposal's parity stage is delivered; its remaining stages are the Windows default composition and pwsh TUI/GUI rendering.