# @deepseek-ai/dsh-bash-local

[English](README.md) | 中文

`@deepseek-ai/dsh-bash` 执行器 seam 的本地实现，构建在 [`@deepseek-ai/dsh-subprocess`](../../subprocess/subprocess/README.md) 服务之上：`LocalBashExecutor` 每次调用都通过 `ctx.subprocess` 把 `bash -c <command>` 作为受管进程组 spawn，并拥有所有 bash 形态的职责（命令默认值补全与上限、超时与取消分类、适合模型的终端环境，以及后台读取时面向模型的 stdout/stderr 合并）。进程组机制（以 spill 文件兜底的有界输出、凭据清除、kill 升级、dispose（资源释放））归进程管理器服务所有。

包根目录导出默认与具名的 `LocalBashExecutor` 插件及其 `Config`。

## 配置

```yaml
- id: bash
  name: '@deepseek-ai/dsh-bash-local'
  config:
    cwd: /path/to/workspace   # default: process.cwd()
    timeoutMs: 120000          # default foreground timeout
    maxTimeoutMs: 600000       # cap for per-call overrides
    maxOutputBytes: 64000      # per-stream in-memory cap; overflow spills to disk
    maxSpillBytes: 67108864    # per-stream full-output spill cap
    graceMs: 3000              # kill escalation and post-exit pipe-drain grace
```

## 行为（以及设计来源）

设计时调研了 Claude Code、OpenCode、Codex 和 pi 的 bash 工具，主要取舍如下：

- **每次调用都 spawn，不保留 shell 状态**：每次调用都启动新的非登录 `bash -c`（行为确定，不读取 rc 文件）。调研的四种工具均会每次调用单独 spawn。`XXX(stateful-shell)` 位于 `src/index.ts`，记录了两种已验证的有状态设计（Claude Code 仅持久化 cwd；Codex 使用 PTY exec 会话），供真实工作流程需要时采用。
- **在受管进程组之上应用配置预算**：`resolve()` 从配置补全 `workdir`／`timeoutMs`／`stdoutMaxBytes`，每次 spawn 都向服务传入显式的字节上限、spill 上限与 `graceMs`（默认 3 秒，沿用 OpenCode 的升级策略）。进程组终止、退出后的管道排空宽限期、尾部保留截断与有界 spill 文件是 [`dsh-subprocess-local`](../../subprocess/subprocess-local/README.md) 的机制。前台 `BashExecRequest.stdoutMaxBytes` 可为某个受信任调用方提高单次 stdout 捕获预算；stderr 和后台运行仍使用 `maxOutputBytes`。
- **超时与取消分类**：`run()` 通过同一个 deadline 把经配置钳位的超时与调用方的信号融合；只有执行器自身的超时报告 `timedOut`，上游取消报告 `aborted`，自行发出信号终止的命令两者皆不报告（见[超时库 Agent Note（agent 决策记录）](../../../.agents/notes/implemented/architecture/2026-07-06-timeout-deadline-library.md)）。
- **适合模型的终端环境**：设置 `NO_COLOR=1 TERM=dumb PAGER=cat GIT_PAGER=cat`（Codex 硬编码的集合），防止分页器与 ANSI 颜色破坏结果；这些条目作为普通 env 合并，遵循服务的凭据清除与 `DSH_*` 通道规则；调用方的显式条目依旧优先。详见 [stdin/env Agent Note](../../../.agents/notes/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-surface.md) 与 [受管环境 Agent Note](../../../.agents/notes/implemented/feature/2026-07-10-agent-session-identity-and-log-location.md)。
- **后台进程**：`start()` 会立即返回实时 `BashProcess` 句柄，不应用超时（Claude Code 在转为后台时会解除超时）；句柄的 `readOutput()` 把服务基于偏移量的 stdout/stderr 读取合并为一条带标记分节的增量，由一个消费游标驱动。仍在运行的进程归进程管理器服务所有，因此它能在执行器重载后存活，并随服务的 dispose 被终止且等待退出。所有具有任务形态的事项（id、所有权、轮询、通知）都属于通用 [`ctx.tasks` 运行时](../../tasks/tasks/README.md)，工具层会在其中注册该句柄；本执行器不会接触会话或注册表。

## 模型体验

通过 `dsh-tool-bash` 间接影响；该工具会渲染此执行器有界的 stdout/stderr 尾部、后台进程增量、spill 文件路径与基础设施失败。

#### KV Cache 影响

不会直接失效；请求前缀变更由具名消费方负责。

## 已知限制与暂缓事项

- **自身不受约束**：此执行器始终以 harness 进程的权限运行命令；需要限制的部署可以组合 [`dsh-bash-sandbox`](../bash-sandbox/README.md)，每次调用的 allow/deny/ask 策略则属于 `tools/pre-execute`。
- **没有持久 shell 或 PTY**：每次调用都启动新的非登录 `bash -c`；仅持久化 cwd 与交互式终端会话均继续暂缓，直到真实工作流程需要它们。
- **仅支持 POSIX**：`bash` 二进制已硬编码，底层服务的进程组语义也是 POSIX 的；不支持 Windows。
- **后台 spawn 失败提示只交付一次**：进程管理器不会为从未真正运行的进程缓冲任何输出，因此执行器把 `spawn failed: …` 注入恰好一个 `readOutput()` 增量；丢弃了该增量的读取方无法再恢复它。

凭据清除启发式规则与 spill 保留的注意事项随 [`dsh-subprocess-local`](../../subprocess/subprocess-local/README.md) 记录；这些机制归它所有。
