English | 中文
The subprocess seam (ctx.subprocess) is the process half of one execution world. The abstract SubprocessService exposes executable lookup, ordinary managed spawn, and one terminal-process primitive; its vocabulary covers raw/collected stdio, process and terminal handles, exit facts, tree/session cleanup, and the managed DSH_* environment namespace. The local implementation lives in dsh-subprocess-local.
spawn(spec) returns immediately with a live handle; done resolves at process close with exit facts (SubprocessOutcome carries no output and no cause classification) and rejects only for spawn-level failures.resolveExecutable(command, env?, signal?) verifies absolute commands or resolves bare names against that world's scrubbed PATH plus explicit overrides.dsh-bash request/spec split is the owning template). argv is never shell-interpreted; a consumer that wants a shell passes ['bash', '-c', command] itself.'pipe' hands the caller the raw stream for its own protocol framing (LSP JSON-RPC, ACP ndjson), 'inherit' passes the parent descriptor through for diagnostics, and collect mode ({ maxBytes, spill? }) buffers a bounded tail with an optional full-stream spill file. Collect readers take whole-stream byte offsets and never consume, so independent readers cannot steal one another's deltas; a read whose offset slid out of the in-memory tail is lossy and points at the spill file when one exists. Collected output stays readable after settlement.taskkill /T): terminate() — the only termination verb — escalates SIGTERM→grace→SIGKILL (idempotent, driven by the spec's abort signal too, a no-op once the tree is gone), and waitForExit(signal?) observes whole-tree liveness so a consumer-owned teardown ladder holds each tier on real quiescence — the manager reacts but never classifies why (callers own deadlines, teardown ladders, and cause classification).spawnTerminal(spec) is the only non-pipe primitive. Its handle owns a real PTY, UTF-8 text I/O, foreground-process-group inspection/signalling, and one awaited terminate() operation that reaches quiescence for every session member the provider can still observe and settles in-flight handle calls; providers document substrate-specific observability limits. The spec signal cancels allocation only; the published handle owns its lifetime. The output stream ends after queued output when the top-level process exits, and a live transport failure rejects done. These operations remain one substrate primitive because ordinary pipes cannot allocate a controlling terminal or clean terminal-session members; readiness, scrollback, and owner policy remain in the PTY consumer.scrubbedParentEnv() / SENSITIVE_ENV_PATTERN are the one shared scrub definition: ambient credential-shaped and DSH_* names are dropped, and explicit env merges after the scrub. The local ordinary and terminal spawns both apply it; SDK-managed transports that own their spawn may import it directly.See the subprocess subsystem page and the seam Agent Note.
Indirectly, through Consumers (today the bash executor family behind dsh-tool-bash), which own all model-facing rendering of process output and lifecycle.
No direct invalidation; the named consumers own any request-prefix changes.
scrubbedParentEnv so environment policy stays single-sourced.