Files
deepseek-harness/packages/bash/bash
Tianyi Cui 8590ba00a4 Merge remote-tracking branch 'origin/master' into codex/trim-ai-prose
# Conflicts:
#	docs/AGENTS.md
#	docs/config-catalog.md
#	packages/bash/bash-sandbox/src/index.ts
#	packages/bash/bash/src/session-mode.ts
#	packages/bash/tool-bash/README.md
#	packages/code-runtime/code-runtime-worker/README.md
#	packages/compact/compact/src/index.ts
#	packages/core/agent-core/README.md
#	packages/hooks/hooks-claude/src/config.ts
#	packages/hooks/hooks-claude/src/index.ts
#	packages/hooks/hooks-codex/src/config.ts
#	packages/hooks/hooks-codex/src/index.ts
#	packages/llm/llm/README.md
#	packages/session-persistence/session-persistence-jsonl/README.md
#	packages/session-persistence/session-persistence/README.md
#	packages/skill/skill-local/README.md
#	packages/support/acp-snapshot/README.md
#	packages/support/invariants/src/index.ts
#	packages/ui/acp/README.md
#	packages/ui/jsonrpc-agent/README.md
#	packages/ui/jsonrpc/README.md
#	packages/ui/permission/README.md
#	packages/ui/user-approval/README.md
#	packages/ui/user-interaction/README.md
#	packages/web/web-search-deepseek/README.md
2026-07-14 14:37:16 +08:00
..

@deepseek-ai/dsh-bash

The bash executor seam: an abstract BashExecutor service (ctx.bash) defining WHAT a bash backend does — run commands, manage background tasks — without saying HOW.

This package is the interface quarter of the bash capability, split so each concern can evolve (and be swapped) independently:

Package Role
@deepseek-ai/dsh-bash (this) the interface: abstract service + vocabulary types
@deepseek-ai/dsh-bash-local an implementation: local subprocesses
@deepseek-ai/dsh-bash-sandbox an implementation: dsh-bash-local's mechanics with every spawn confined via ctx.sandbox, denials reported as result facts
@deepseek-ai/dsh-tool-bash the model-facing tool schemas over ctx.bash

The split mirrors the LLM seam (LlmService/LlmAdapter) and the agent-tool survey: pi hides execution behind a BashOperations interface (local shell / SSH / VM backends), Codex behind an exec-server protocol. dsh-bash-sandbox is exactly that swap in action — a sandboxing executor behind the same interface; the consumer detects its sandboxMode capability and adds escalation fields without importing the implementation. A containerized or remote executor slots in the same way.

Service API (ctx.bash)

Member Semantics
run(spec) Foreground execution. Resolves when the command finishes. Rejects only for infrastructure failures (unusable workdir, missing shell, pre-aborted signal); nonzero exits, timeout kills, and abort kills resolve with a descriptive BashRunResult.
start(spec) Background execution. Returns a BashTask handle immediately; no timeout applies (stop tasks via kill).
get(id) / list() Task lookup.
sandboxMode The capability fact for the tool layer: the default mode a SANDBOXING executor confines under (undefined in the base class — "this executor does not sandbox"). dsh-tool-bash reads it at registration to advertise the escalation fields only when the composition honors them.
ownerOf(id) The opaque OWNER token recorded for a background task at start (from the spec's owner), or undefined for an unknown id OR a known-but-ownerless task. The executor stores/returns it verbatim and NEVER interprets it — the access POLICY lives in the consumer (dsh-tool-bash), which compares ownerOf(id) to the caller's token. Storing ownership here (disposed with the executor's fiber) is what makes it survive a consumer HMR reload.
readOutput(id) Incremental output read — consecutive reads never re-deliver. Reads that lost data to buffer bounds flag lossy and point at full-stream spill files. Throws for unknown ids.
kill(id) Kill a running task. Returns false when it already finished; throws for unknown ids.
onTaskDone(listener) Completion listener (effect-based, disposer returned). Fires exactly once per task; never after the service is disposed.

Implementations subclass BashExecutor, implement the abstract methods, and call notifyTaskDone(task) on background completion. Disposal must kill every running task (no orphan processes) — see the HMR-safety tests.

Vocabulary

BashExecRequest (command, workdir?, timeoutMs?, signal?, stdin?, env?, owner?, sandboxMode?) resolves to BashExecSpec (command, workdir, timeoutMs, signal?, stdin?, env?, owner, sandboxMode) before execution; owner and sandboxMode are optional on the request and required-but-nullable on the resolved spec, so a forgotten one is a visible undefined rather than a silently-absent property. sandboxMode is the explicit per-call sandbox-policy input: an escalation grant a human just issued (the sandbox RFC § Escalation, which outranks) or the session's standing override (the sandbox RFC § Per-session mode switching); a sandboxing executor's resolve() stamps its configured default when the request carries none, and a non-sandboxing executor carries the field verbatim and confines nothing.

The seam owns per-session sandbox overrides through the log-only bash/sandbox-mode event, effectiveSandboxMode, and setSandboxMode; writers preserve turn enclosure, and replay restores the last override. BashTaskId and OwnerToken are distinct brands. Foreground run returns exit, timeout, cancellation, output, and optional sandbox facts; background start and readOutput use task records. A sandboxing executor reports the executed mode, conservative denial classification, and enforcement completeness. See core-data-structures/bash.md for full shapes.

stdin and env are set by in-process plugins (the hooks bridges, native plugins) to feed a hook command its JSON payload on stdin and its CLAUDE_PROJECT_DIR/CLAUDE_PLUGIN_ROOT env. The model-facing dsh-tool-bash tool does not expose them as parameters — a model already has equivalent power through shell syntax (FOO=bar cmd, a heredoc), so they would be redundant tool params. This is not a security boundary: the implementation's credential scrub (not these fields) is what keeps the harness's ambient secrets out of a spawned command. They are plain optionals on the resolved spec (unlike owner's required-but-nullable): a missing one means "none", the safe default. See the bash-stdin-env RFC.

Model Experience

Indirectly, through dsh-tool-bash, which turns executor output and sandbox facts into guidance and retained tool-result tokens.

Known Limitations and Deferred Work

  • No interactive-input vocabularystdin is written once at spawn and closed; the seam has no channel to feed a running task and no PTY session concept.
  • Foreground timeouts are always executor-owned — a caller-owned-deadline mode on the seam is explicitly deferred by the tool-call timeout-policy RFC.