merge: bring master into feat/pwsh-persistent-pty

This commit is contained in:
Huanqi Cao
2026-08-13 01:33:16 +08:00
2446 changed files with 36532 additions and 9922 deletions
+1 -1
View File
@@ -3,4 +3,4 @@
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write packages/bash/README.md
README.md: edffdd67a982a885b7e3e537be77c8971f5b697b
README.zh.md: 8cb56f38df4999cb2055b9e2808ce092bc7a8282
README.zh.md: 21d28fcd01e4c4f3da2c55af6edbbda63dbe1961
+1 -1
View File
@@ -9,7 +9,7 @@
| [`bash/`](bash/README.md) | 定义 Service provider 与 Consumer 共享的执行器约定。 | `ctx.bash` |
| [`bash-local/`](bash-local/README.md) | 通过本地 [`subprocess`](../subprocess/README.md) 服务执行命令。 | (注册 `ctx.bash` |
| [`bash-sandbox/`](bash-sandbox/README.md) | 在本地执行前应用已配置的 [`sandbox`](../sandbox/README.md) 后端。 | (注册 `ctx.bash` |
| [`pwsh-local/`](pwsh-local/README.md) | Windows 专用进程行为执行 PowerShell 命令。 | (注册 `ctx.bash` |
| [`pwsh-local/`](pwsh-local/README.md) | 采用 Windows 特有的进程行为执行 PowerShell 命令。 | (注册 `ctx.bash` |
| [`bash-env/`](bash-env/README.md) | 提供 shell 工具共享的托管 `DSH_*` 环境。 | `ctx.bashEnv` |
| [`tool-bash/`](tool-bash/README.md) | 向模型公开 Bash 执行和后台任务集成。 | (注册到 `ctx.tools` |
| [`tool-pwsh/`](tool-pwsh/README.md) | 向模型公开 PowerShell 执行。 | (注册到 `ctx.tools` |
+1 -1
View File
@@ -3,4 +3,4 @@
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write packages/bash/bash-env/README.md
README.md: 54758a91773aad723c6fbbebe2ffe25aedb38599
README.zh.md: e0663b003e94942c76cde4fb7867ed0ce74c2aa2
README.zh.md: 902eb9f7cb00853986501fffccb66d858dfdefa7
+3 -3
View File
@@ -36,15 +36,15 @@ export function apply(ctx: Context): void {
}
```
覆盖层根据当前 `ToolExecution` 计算,并通过专用的 `BashExecRequest.dshEnv` 通道传递。本地执行器在合并该快照前移除所有继承的 `DSH_*`,因此嵌套 harness 与并发的父子 agent 无法泄漏过期的身份。`process.env` 永不被修改。shell 工具的描述只教授通用的 `$DSH_*` 约定,而不是点名持久化相关的变量或添加常驻的 system-prompt 段落。
覆盖层根据当前 `ToolExecution` 计算,并通过专用的 `BashExecRequest.dshEnv` 通道传递。本地执行器在合并该快照前移除所有继承的 `DSH_*`,因此嵌套 harness 与并发的父子 agent 无法泄漏陈旧身份。`process.env` 永不被修改。shell 工具的描述只教授通用的 `$DSH_*` 约定,而不是点名持久化相关的变量或添加常驻的 system-prompt 段落。
## Model Experience
Indirectly, through the shell tools (`dsh-tool-bash`, `dsh-tool-pwsh`), which collect this registry's managed `DSH_*` snapshot into every shell-tool call.
通过 shell 工具(`dsh-tool-bash``dsh-tool-pwsh`)间接产生影响;这些工具会把该注册表的受管 `DSH_*` 快照收集进每次 shell 工具调用。
#### KV Cache effect
No direct invalidation; the named consumers own any request-prefix changes.
不会直接导致缓存失效;任何请求前缀变更均由上述消费方负责。
## Known Limitations and Deferred Work
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-bash-env",
"description": "Tool-independent managed DSH_* shell environment registry",
"version": "0.0.1-rc.1",
"version": "0.0.1-rc.2",
"publishConfig": {
"access": "restricted"
},
+1 -1
View File
@@ -3,4 +3,4 @@
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write packages/bash/bash-local/README.md
README.md: 386ffc00466108ab14352b6d39d3a20da3321e1c
README.zh.md: 39d37bededa72ec96911bb1ce055ed105fdd7082
README.zh.md: 01b4f3a7f8c290b3e03d4cccc696dff57c1112f7
+2 -2
View File
@@ -39,9 +39,9 @@
## 已知限制与暂缓事项
- **自身不提供隔离**:此执行器始终以 harness 进程的权限运行命令;需要限制的部署可以组合 [`dsh-bash-sandbox`](../bash-sandbox/README.md),每次调用的 allow/deny/ask 策略则属于 `tools/pre-execute`
- **自身不提供隔离**:此执行器始终以 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()` 增量;丢弃了该增量的读取方无法再恢复它。
- **后台 spawn 失败提示只交付一次**:subprocess 服务不会为从未真正运行的进程缓冲任何输出,因此执行器把 `spawn failed: …` 注入恰好一个 `readOutput()` 增量;丢弃了该增量的读取方无法再恢复它。
凭据清除启发式规则与 spill 保留的注意事项随 [`dsh-subprocess-local`](../../subprocess/subprocess-local/README.md) 记录;这些机制归它所有。
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-bash-local",
"description": "Local-subprocess implementation of the DeepSeek Harness bash executor seam",
"version": "0.0.1-rc.1",
"version": "0.0.1-rc.2",
"publishConfig": {
"access": "restricted"
},
+1 -1
View File
@@ -3,4 +3,4 @@
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write packages/bash/bash-sandbox/README.md
README.md: 44321d7ef26e9e4399438f61b3fdfbfa2e4d8c11
README.zh.md: f3e110c049871a5a6121716307aaa3d1d1f3eedb
README.zh.md: 12e4688cba5baf04190f52b87677b5c4a7ad3925
+3 -3
View File
@@ -2,7 +2,7 @@
[English](README.md) | 中文
这是使用沙箱能力的 [`@deepseek-ai/dsh-bash`](../bash/) 执行器 seam Service provider。加载它时,应**用它替代** `@deepseek-ai/dsh-bash-local`,并同时加载 [`ctx.sandbox`](../../sandbox/sandbox/) 提供方(例如 [`@deepseek-ai/dsh-sandbox-local`](../../sandbox/sandbox-local/))及 [`ctx.sandboxPolicy`](../../sandbox/sandbox-policy/);默认模式和工作区根目录由后者负责,并与受沙箱约束的文件系统共享这些设置。无需使用替代工具插件;`dsh-tool-bash` 会检测执行器的 `sandboxMode` 能力并添加升权字段。
这是使用沙箱能力的 [`@deepseek-ai/dsh-bash`](../bash/) 执行器 seam Service provider。加载它时,应**用它替代** `@deepseek-ai/dsh-bash-local`,并同时加载 [`ctx.sandbox`](../../sandbox/sandbox/) 提供方(例如 [`@deepseek-ai/dsh-sandbox-local`](../../sandbox/sandbox-local/))及 [`ctx.sandboxPolicy`](../../sandbox/sandbox-policy/);默认模式和工作区根目录由后者负责,并与受沙箱约束的文件系统共享这些设置。无需使用替代工具插件;`dsh-tool-bash` 会检测执行器的 `sandboxMode` 能力并添加升权字段。
包根目录导出默认与具名的 `SandboxBashExecutor` 插件及其 `Config`;结果分类 helper 保留在内部。
@@ -64,7 +64,7 @@
#### KV Cache 影响
仅追加;新可见内容位于可复用请求前缀之后,不会使现有 KV-cache 条目失效。
仅追加;新可见内容位于可复用请求前缀之后,不会使现有 KV Cache 条目失效。
### 间接的 Bash 工具错误
@@ -78,7 +78,7 @@
#### KV Cache 影响
仅追加;新可见内容位于可复用请求前缀之后,不会使现有 KV-cache 条目失效。
仅追加;新可见内容位于可复用请求前缀之后,不会使现有 KV Cache 条目失效。
## 已知限制与暂缓事项
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-bash-sandbox",
"description": "Sandbox-consuming implementation of the DeepSeek Harness bash executor seam (confines every command via ctx.sandbox, reports denial/enforcement result facts)",
"version": "0.0.1-rc.1",
"version": "0.0.1-rc.2",
"publishConfig": {
"access": "restricted"
},
+1 -1
View File
@@ -3,4 +3,4 @@
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write packages/bash/bash/README.md
README.md: ef873dfb87cb330847274be59d5f2a0c3a5bc0b9
README.zh.md: 4047765f248a25ff700ba62bf87636c0e8bfe7ac
README.zh.md: 8370575a7c314009be964b7b25f43ce4076f23dc
+1 -1
View File
@@ -22,7 +22,7 @@
| `run(spec)` | 前台执行。命令完成时 resolve。**只会因基础设施失败而 reject**(工作目录不可用、shell 缺失、信号已在调用前中止);非零退出、超时终止和中止导致的终止都会 resolve 为描述性 `BashRunResult`。 |
| `start(spec)` | 后台执行。立即返回不含任务语义的 `BashProcess` 句柄;**不应用超时**。调用方可以将其适配到 `ctx.tasks`。 |
| `sandboxMode` | 工具层的能力事实:沙箱执行器用于限制执行的默认模式(基类中为 `undefined`,即「此执行器不使用沙箱」)。`dsh-tool-bash` 会在注册时读取它,仅当组合确实支持升权字段时才公布这些字段。 |
| `BashProcess.readOutput()` | **增量** 读取输出:连续读取绝不会重复交付。因缓冲区边界丢失数据的读取会标记 `lossy`,并指向完整流 spill 文件。 |
| `BashProcess.readOutput()` | **增量** 读取输出:连续读取绝不会重复交付。因缓冲区容量限制而丢失数据的读取会标记 `lossy`,并指向完整流 spill 文件。 |
| `BashProcess.kill()` | 终止进程组。如果进程已结束,返回 `false`。 |
实现会继承 `BashExecutor` 并实现抽象方法。dispose(资源释放)必须终止每个运行中的进程并等待其退出。
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-bash",
"description": "Abstract bash executor seam (ctx.bash) for the DeepSeek Harness",
"version": "0.0.1-rc.1",
"version": "0.0.1-rc.2",
"publishConfig": {
"access": "restricted"
},
+1 -1
View File
@@ -3,4 +3,4 @@
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write packages/bash/pwsh-local/README.md
README.md: 76f3071dc1049e2ea5929d5990ee0cb526ef702e
README.zh.md: e773e0e83e81ffa311bd555b7a75433ba22dfd22
README.zh.md: 3337bb5f890adf63d74c88a5da0325e2a95ce3b8
+10 -10
View File
@@ -2,9 +2,9 @@
[English](README.md) | 中文
`@deepseek-ai/dsh-bash` 执行器 seam 的本地 PowerShell Service provider,基于 [`@deepseek-ai/dsh-subprocess`](../../subprocess/subprocess/README.md) 服务:`PwshLocalExecutor` 每次调用以受管进程的方式通过 `ctx.subprocess` spawn `pwsh -NoLogo -NoProfile -NonInteractive -Command <command>`,并拥有所有 PowerShell 形状的职责——可执行文件解析、命令默认化与上限、超时/取消分类、面向模型的终端环境,以及后台读取的 stdout/stderr 合并。进程组机制(有界 spill 输出、凭据清理、终止升级、销毁)属于 subprocess 服务。
`@deepseek-ai/dsh-bash` 执行器 seam 的本地 PowerShell Service provider,基于 [`@deepseek-ai/dsh-subprocess`](../../subprocess/subprocess/README.md) 服务:`PwshLocalExecutor` 每次调用以受管进程的方式通过 `ctx.subprocess` spawn `pwsh -NoLogo -NoProfile -NonInteractive -Command <command>`,并负责所有 PowerShell 相关事项——可执行文件解析、命令默认化与上限、超时/取消分类、面向模型的终端环境,以及后台读取的 stdout/stderr 合并。进程组机制(有界 spill 输出、凭据清理、终止升级、dispose(资源释放))属于 subprocess 服务。
命令字符串作为 ONE argv 元素传给 `-Command`:由 PowerShell 自己解析文本,不存在中间 shell,因此没有需要转义的 shell 引号层(这里不存在与 `bash -c` 字符串域对应的层)。原生 Win32 路径(`C:\...`)原样通过。
命令字符串作为单个 argv 元素传给 `-Command`:由 PowerShell 自己解析文本,不存在中间 shell,因此没有需要转义的 shell 引号层(这里不存在与 `bash -c` 字符串域对应的层)。原生 Win32 路径(`C:\...`)原样通过。
包根导出默认与具名 `PwshLocalExecutor` 插件、其 `Config`、纯函数 `resolvePwshPath`/`candidatePwshPaths` 辅助函数,以及执行器注入每次 spawn 的 `ENV_OVERRIDES`/`ENCODING_PREAMBLE` 常量。
@@ -25,16 +25,16 @@
## 行为
作为 `dsh-bash-local` 的 Windows 对应物,逐调用地镜像其语义
这是 `dsh-bash-local` 的 Windows 对应实现,有意逐次调用保持语义一致
- **每次调用新建进程,无 shell 状态**——每次调用都是全新的非交互 `pwsh -Command`(确定性;不加载 profile 文件)。`-NoLogo -NoProfile -NonInteractive` 关闭启动横幅、profile 加载与会干扰工具输出的提示符。
- **组装条目是一层,而不是最终值**——当组装中存在 settings 提供方时,本执行器以上面的条目为 base 注册该能力的 [`bash` 命名空间](../bash/README.md),因此 `settings.yaml` 中的用户段会叠加其上,下一条命令即按新预算运行。该命名空间与 POSIX 家族共用,因为一个宿主只组装一个 `ctx.bash` 提供方;在任一平台写下的文档在另一平台仍能解析。schema 无法判定的值(正有限、`graceMs` 的定时器上界)会在写入时被拒绝,运行中的执行器保持它最后一份可用的段。
- **UTF-8 输出固定**——每条命令都先以 UTF-8 设置 `[Console]::OutputEncoding``$OutputEncoding`,因此 Windows PowerShell 5.1 兜底(或任何控制台代码页非 UTF-8 的主机)不会破坏非 ASCII 输出:subprocess collector 以 UTF-8 解码字节。输入编码保持宿主默认;pwsh 7 默认为 UTF-8,不受影响。
- **UTF-8 输出固定**——每条命令都先以 UTF-8 设置 `[Console]::OutputEncoding``$OutputEncoding`,因此 Windows PowerShell 5.1 兜底(或任何控制台代码页非 UTF-8 的主机)不会破坏非 ASCII 输出:subprocess 收集器以 UTF-8 解码字节。输入编码保持宿主默认;pwsh 7 默认为 UTF-8,不受影响。
- **可执行文件解析**——`resolvePwshPath` 优先显式 `pwshPath`,然后在 Windows 上依次探测 PowerShell 7 安装位置、每个 PATH 条目(Microsoft Store 安装;剥离两端引号)以及作为遗留兜底的 Windows PowerShell 5.1,逐一检查 `existsSync`;其他平台回退为通过 PATH 解析的裸 `pwsh`。解析是 `(configured, env, platform)` 的纯函数;它在构造时执行,此后仅当存储的 `pwshPath` 与当前可执行文件所依据的值不同才再次执行,因此无关的设置变更绝不会重新探测文件系统。
- **受管进程组之上的配置预算**——`resolve()` 从配置填充 `workdir`/`timeoutMs`/`stdoutMaxBytes`,每次 spawn 都向服务提供显式字节上限、spill 上限与 `graceMs`。该宽限期须为正有限值,且不得大于 [`MAX_TIMER_DELAY_MS`](../../util/timeout/README.md),这样 Node 就能用一个定时器表示它。进程树终止(Windows 用 taskkillPOSIX 用进程组信号)、退出后管道排空宽限、保尾截断与有界 spill 文件是 [`dsh-subprocess-local`](../../subprocess/subprocess-local/README.md) 的机制。前台 `BashExecRequest.stdoutMaxBytes` 可为单个受信调用方提高 stdout 捕获预算;stderr 与后台运行仍使用 `maxOutputBytes`
- **超时与取消分类**——`run()` 通过一个 deadline 融合按配置上限截取的超时与调用方信号;只有执行器自身超时报告 `timedOut`,上游取消报告 `aborted`,自我终止的命令两者都不报告(见 [timeout 库 Agent Note](../../../.agents/notes/implemented/architecture/2026-07-06-timeout-deadline-library.md))。Windows 将强制终止报告为退出码 1 且无信号,因此带信号标记的事实(`signal``killed` 状态)在那里仅限 POSIX;超时/取消分类与平台无关。
- **面向模型的终端环境**——`NO_COLOR=1 PAGER=cat GIT_PAGER=cat`(没有 `TERM=dumb`:那是 POSIX 概念;现代 PowerShell 渲染器遵循 `NO_COLOR`),作为普通 env 在服务的凭据清理与 `DSH_*` 通道规则之下合并;显式调用方条目仍然优先。
- **后台进程**——`start()` 立即返回存活的 `BashProcess` 句柄,不设超时;句柄的 `readOutput()` 把服务基于偏移的 stdout/stderr 读取合并为带标记分段的增量与消费游标。仍在运行的进程属于 subprocess 服务,因此它跨执行器重载存活,并随服务销毁(被终止并 join)。一切任务形状的职责(id、所有权、轮询、通知)都在通用 [`ctx.tasks` 运行时](../../tasks/tasks/README.md) 中,由工具层把句柄注册进去——本执行器从不接触会话或注册表。
- **后台进程**——`start()` 立即返回存活的 `BashProcess` 句柄,不设超时;句柄的 `readOutput()` 把服务基于偏移的 stdout/stderr 读取合并为一条按分段标记、通过消费游标推进的增量。仍在运行的进程属于 subprocess 服务,因此它跨执行器重载存活,并随服务 dispose(被终止并 join)。一切任务相关职责(task id、所有权、轮询、通知)都在通用 [`ctx.tasks` 运行时](../../tasks/tasks/README.md) 中,由工具层把句柄注册进去——本执行器从不接触会话或注册表。
## 模型体验
@@ -42,16 +42,16 @@
#### KV Cache 影响
无直接失效;具名消费方拥有请求前缀的任何变更。
不会直接导致 KV Cache 失效;请求前缀的任何变更由具名消费方负责
## 已知局限与延期工作
## 已知限制与暂缓事项
- **自身不设沙箱**——本执行器始终以 harness 进程的权限运行命令;需要约束的部署应组合沙箱 bash 执行器或策略。
- **自身不设沙箱**——本执行器始终以 harness 进程的权限运行命令;需要隔离的部署应组合启用沙箱 bash 执行器或策略。
- **无持久 shell 或 PTY**——每次调用都是全新的 `pwsh -Command`
- **命令字符串是 PowerShell 文本**——`-Command` 域没有 shell 引号层,但面向模型的命令由 PowerShell 自己解析,因此 PowerShell 语法错误是命令失败,而非启动失败。
- **后台 spawn 失败提示只投递一次**——subprocess 服务不会为从未运行的进程缓冲输出,因此执行器只把 `spawn failed: …` 注入一次 `readOutput()` 增量;丢弃该增量的读取方无法恢复它。
- **Windows 终止不报告信号**——被强制终止的进程以退出码 1、`signal: null` 结束,因此基于信号的状态分类(POSIX `killed`)在 Windows 上不适用;`kill()` 发起的停止仍会直接盖上 `killed`
- **Windows 终止不报告信号**——被强制终止的进程以退出码 1、`signal: null` 结束,因此基于信号的状态分类(POSIX `killed`)在 Windows 上不适用;`kill()` 发起的停止仍会直接标记为 `killed`
- **编码 preamble 位于命令之前**——PowerShell 要求 `param(...)``#requires``using namespace`/`using assembly` 语句位于脚本最顶部,因此以其中一种开头的命令无法在 UTF-8 输出 preamble 下运行。`param(...)` 脚本可包进 `& { … }`(param 块可以合法地位于脚本块开头);`using` 语句与 `#requires` 在命令内没有变通办法(`#requires``-Command` 中无论位置如何都不生效)——此类脚本请改从文件运行。
- **Windows PowerShell 5.1 下的非 ASCII stdin 可能被错误解码**——preamble 只固定输出编码;`[Console]::InputEncoding` 保持主机默认,因为在重定向 stdin 下设置它会抛出异常。pwsh 7 默认 UTF-8,不受影响。
清理启发式与 spill 保留的注意事项 [`dsh-subprocess-local`](../../subprocess/subprocess-local/README.md) 持有,它拥有这些机制
清理启发式与 spill 保留的注意事项 [`dsh-subprocess-local`](../../subprocess/subprocess-local/README.md),相关机制由其负责
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-pwsh-local",
"description": "Local PowerShell implementation of the DeepSeek Harness bash executor seam",
"version": "0.0.1-rc.1",
"version": "0.0.1-rc.2",
"publishConfig": {
"access": "restricted"
},
@@ -31,10 +31,10 @@ const hasPwsh = spawnSync(resolvePwshPath(), ['-NoLogo', '-NoProfile', '-NonInte
/** Normalize PowerShell's platform line endings (CRLF on Windows, LF elsewhere). */
const lf = (text: string): string => text.replace(/\r\n/g, '\n')
/** Case-insensitive path equality on Windows (Get-Location may re-case the drive). */
/** Filesystem path equality across macOS temp symlinks and Windows drive-letter casing. */
function samePath(actual: string, expected: string): boolean {
const norm = (value: string) => (
process.platform === 'win32' ? realpathSync.native(value).toLowerCase() : value
process.platform === 'win32' ? realpathSync.native(value).toLowerCase() : realpathSync.native(value)
)
return norm(actual) === norm(expected)
}
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-pwsh-sandbox",
"description": "Sandbox-consuming implementation of the DeepSeek Harness PowerShell executor seam (confines every command via ctx.sandbox, reports denial/enforcement result facts)",
"version": "0.0.1-rc.1",
"version": "0.0.1-rc.2",
"publishConfig": {
"access": "restricted"
},
+1 -1
View File
@@ -3,4 +3,4 @@
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write packages/bash/tool-bash/README.md
README.md: d5483e5e266a5362d9a8d324d71046591fe146bc
README.zh.md: 527543ea7130cb89e7e9776cb71adec842527e85
README.zh.md: b163939df58af5f11031b43aff877dab72b7c263
+10 -10
View File
@@ -6,7 +6,7 @@
需要加载执行器 Service provider(例如 `@deepseek-ai/dsh-bash-local`)与 [`@deepseek-ai/dsh-bash-env`](../bash-env/README.md) 注册表;在每个注入服务就绪之前,插件会保持等待状态(`inject: ['tools', 'bash', 'systemPrompt', 'bashEnv']`)。工具约定是 bash 方言——请挂载能解析 bash 的执行器。
package根只公开 Cordis 插件约定(`name``inject``Config``apply`);结果渲染和后台进程适配仍保留在包内部。
包根只公开 Cordis 插件约定(`name``inject``Config``apply`);结果渲染和后台进程适配仍保留在包内部。
插件还会提供 `tool:bash` 提示词段落(顺序 105):检查每个结果中的 `[exit code: N]` 标记,发现失败时先调查原因再继续。
@@ -28,13 +28,13 @@
### 托管 shell 环境
每次模型发起的前台或后台 bash 调用都会通过共享的 [`dsh-bash-env`](../bash-env/README.md) 注册表收到新收集的一组可信 `DSH_*` 环境变量:`DSH_HOME`Harness home 绝对路径)、`DSH_SHELL=1`、agent 的 `DSH_SESSION_ID`,以及当活跃持久化后端能定位时的 `DSH_SESSION_JSONL`。注册表约定——贡献方注册、重复/未声明键的响亮失败、内置项保留与贡献方示例——住在该包的 README。快照通过专用的 `BashExecRequest.dshEnv` 通道传递;本地执行器会先删除继承的所有 `DSH_*` 再合并,因此嵌套 harness 和并发的父/子 agent 不会泄漏陈旧身份,且绝不修改 `process.env`。工具说明只教授通用 `$DSH_*` 约定,不会点名持久化专用变量,也不会添加永久的系统提示词段落。
每次模型发起的前台或后台 bash 调用都会通过共享的 [`dsh-bash-env`](../bash-env/README.md) 注册表收到新收集的一组可信 `DSH_*` 环境变量:`DSH_HOME`Harness home 绝对路径)、`DSH_SHELL=1`、agent 的 `DSH_SESSION_ID`,以及当活跃持久化后端能定位时的 `DSH_SESSION_JSONL`。注册表约定——贡献方注册、重复/未声明键的显式报错机制、内置项保留与贡献方示例——载于该包的 README。快照通过专用的 `BashExecRequest.dshEnv` 通道传递;本地执行器会先删除继承的所有 `DSH_*` 再合并,因此嵌套 harness 和并发的父/子 agent 不会泄漏陈旧身份,且绝不修改 `process.env`。工具说明只教授通用 `$DSH_*` 约定,不会点名持久化专用变量,也不会添加永久的系统提示词段落。
结果文本依次包含 stdout、可选的 `[stderr]` 段落和适用的沙箱拒绝、超时、信号、退出代码及截断标记。超时与最终退出状态分别报告;非零退出仍是由模型解释的结果,不会成为 `isError`。截断结果会链接安全的完整 spill 文件,或报告文件不可用。只有 spawn 错误和中止等基础设施故障才会产生 `isError`
已完成前台进程的规范成功值为 `{ kind: 'foreground', ...BashRunResult }`,已发布任务则为 `{ kind: 'background', taskId }`。Native renderer 保留上述文本,包括精确的 `started background task <id>`;程序化消费方使用带类型字段,无需解析这些字符串。执行器的流上限仍是 `BashRunResult` 的采集限制,并携带其 spill 路径。
`run_in_background` 为 true 时,此插件会在 spawn 前预检 `ctx.tasks.start()`,把调用方 agent 注册为持有者,并将返回的 `BashProcess` 句柄适配为通用的取消/完成/增量输出钩子。任务运行时持有 id、跨会话隔离、完成通知、等待和 dispose(资源释放)清理;此插件只把 bash 退出/沙箱事实映射为任务输出和结果详情。`enableRunInBackground: false` 会移除该参数,并在执行时拒绝强制后台调用。
`run_in_background` 为 true 时,此插件会在 spawn 前预检 `ctx.tasks.start()`,把调用方 agent 注册为持有者,并将返回的 `BashProcess` 句柄适配为通用的取消/完成/增量输出钩子。任务运行时负责 task id、跨会话隔离、完成通知、等待和 dispose(资源释放)清理;此插件只把 bash 退出/沙箱事实映射为任务输出和结果详情。`enableRunInBackground: false` 会移除该参数,并在执行时拒绝强制后台调用。
## UI 展示
@@ -48,11 +48,11 @@
除非启用沙箱的执行器([`dsh-bash-sandbox`](../bash-sandbox/))限制命令,否则命令以执行器的完整权限运行。仅拒绝型沙箱会把拒绝作为结果事实报告,并在此渲染为拒绝标记;逐调用的允许/拒绝/询问策略由 `tools/pre-execute` waterfall(瀑布式事件)负责(参见 docs/architecture.md)。
需要升权的 bash 调用会在执行前解析 `ctx.approval``allowed-once` 只对该次调用应用请求模式;审批被拒、取消、不可用或缺少审批上下文时,命令完全不会执行,并返回不同的错误。发生真实拒绝后,模型可以在同一轮次中使用满足需要的最窄模式和理由重试同一命令一次;审批提示本身就是征求同意的步骤。升权绝不能预先推测,禁用或拒绝审批即为最终结果。其理由 [沙箱 Agent Note](../../../.agents/notes/implemented/feature/2026-07-06-sandbox.md) 持有
需要升权的 bash 调用会在执行前解析 `ctx.approval``allowed-once` 只对该次调用应用请求模式;审批被拒、取消、不可用或缺少审批上下文时,命令完全不会执行,并返回不同的错误。发生真实拒绝后,模型可以在同一轮次中使用满足需要的最窄模式和理由重试同一命令一次;审批提示本身就是征求同意的步骤。升权绝不能预先推测,禁用或拒绝审批即为最终结果。其理由 [沙箱 Agent Note](../../../.agents/notes/implemented/feature/2026-07-06-sandbox.md)。
## 逐会话模式切换
对于启用沙箱的执行器,每次调用依次按单次升权、会话覆盖、执行器默认值解析模式。未启用沙箱以及没有 agent 的调用不携带会话覆盖。策略归属方贡献当前且不区分具体能力的常驻模式;拒绝结果仍负责操作特定的有效模式与重试引导。参见 [`dsh-bash` 整合](../bash/README.md)和[沙箱切换约定](../../../.agents/notes/implemented/feature/2026-07-06-sandbox.md)。
对于启用沙箱的执行器,每次调用依次按单次升权、会话覆盖、执行器默认值解析模式。未启用沙箱以及没有 agent 的调用不携带会话覆盖。策略归属方贡献当前且不区分具体能力的常驻模式;拒绝结果仍负责特定于该操作的有效模式与重试引导。参见 [`dsh-bash` 折叠计算](../bash/README.md)和[沙箱切换约定](../../../.agents/notes/implemented/feature/2026-07-06-sandbox.md)。
## 模型体验
@@ -88,7 +88,7 @@ Check the [exit code: N] marker on every bash result; investigate failures befor
#### KV Cache 影响
只要可见性、后台支持和执行器沙箱能保持不变,前缀即可稳定复用。限制、配置或执行器发生变化时,可能从首个变化的工具定义开始使复用失效。
只要可见性、后台支持和执行器沙箱能保持不变,前缀即可稳定复用。限制、配置或执行器发生变化时,可能从首个变化的工具定义开始使复用失效。
### 前台结果
@@ -102,13 +102,13 @@ renderer 先输出依数据而定的 stdout 尾部,再输出可选的 `[stderr
#### KV Cache 影响
仅追加;新可见内容位于可复用请求前缀之后,不会使现有 KV-cache 条目失效。
仅追加;新可见内容位于可复用请求前缀之后,不会使现有 KV Cache 条目失效。
### 后台任务上下文与结果
#### 模型看到的内容
启动会精确返回 `started background task <taskId>`。此生产方会向通用任务运行时提供增量进程输出、可选的 `[some output was dropped from memory; full output: <paths-or-(unavailable)>]`、沙箱事实,以及 `exit code: <exitCode>``signal: <signal>` 等终止详情。[`dsh-tool-tasks`](../../tasks/tool-tasks/README.md) 持有模型可见的状态行、完成通知、列表和取消响应。
启动会精确返回 `started background task <taskId>`。此生产方会向通用任务运行时提供增量进程输出、可选的 `[some output was dropped from memory; full output: <paths-or-(unavailable)>]`、沙箱事实,以及 `exit code: <exitCode>``signal: <signal>` 等终止详情。[`dsh-tool-tasks`](../../tasks/tool-tasks/README.md) 负责模型可见的状态行、完成通知、列表和取消响应。
#### Token 影响
@@ -116,7 +116,7 @@ renderer 先输出依数据而定的 stdout 尾部,再输出可选的 `[stderr
#### KV Cache 影响
仅追加;新可见内容位于可复用请求前缀之后,不会使现有 KV-cache 条目失效。
仅追加;新可见内容位于可复用请求前缀之后,不会使现有 KV Cache 条目失效。
### 工具错误
@@ -130,7 +130,7 @@ renderer 先输出依数据而定的 stdout 尾部,再输出可选的 `[stderr
#### KV Cache 影响
仅追加;新可见内容位于可复用请求前缀之后,不会使现有 KV-cache 条目失效。
仅追加;新可见内容位于可复用请求前缀之后,不会使现有 KV Cache 条目失效。
## 已知限制与延期工作
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-tool-bash",
"description": "Model-facing bash tool with optional generic background-task and sandbox-escalation support",
"version": "0.0.1-rc.1",
"version": "0.0.1-rc.2",
"publishConfig": {
"access": "restricted"
},
+1 -1
View File
@@ -4,7 +4,7 @@
* rather than the tool-call signal after an id is returned.
*
* TODO(permissions): deployment policy belongs in `tools/pre-execute` and
* sandboxing executors; see docs/architecture.md § Extending The Harness.
* sandboxing executors; see docs/architecture.md § Where new behavior goes.
* @module @deepseek-ai/dsh-tool-bash
*/
@@ -1,7 +1,7 @@
import { createUserMessage } from '@deepseek-ai/dsh-llm'
import { afterEach, describe, expect, it, vi } from 'vitest'
import { Context } from '@deepseek-ai/cordis'
import { existsSync, mkdtempSync, readFileSync, rmSync } from 'node:fs'
import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { SessionId, type SessionEvent } from '@deepseek-ai/dsh-session'
@@ -174,11 +174,24 @@ describe('bash tool through the agent loop', () => {
expect(resultText(toolResult)).toContain('[exit code: 9]')
})
it('background: start ack → pending completion notice → task_output collects it', async () => {
it('background: start ack → completion wakes the idle agent → task_output collects it', async () => {
// The command blocks on a sentinel this test creates only after the agent
// has gone idle, so settlement cannot fold into the still-running turn.
// Without that fence a fast command can settle before step 2's pre-step
// claim, which folds the notice into a turn whose scripted reply is final:
// the turn then closes with an empty next-step inbox and the collection
// entries are never reached.
const dir = mkdtempSync(join(tmpdir(), 'dsh-bg-'))
dirs.push(dir)
const sentinel = join(dir, 'release')
// The task id is deterministic (a fresh LocalTaskService counts per kind from 1),
// so the script can name `bash-1` without threading a generated id.
const adapter = new MockAdapter([
toolCallResponse('call-1', 'bash', { command: 'echo bg-ok', description: 'test command', run_in_background: true }),
toolCallResponse('call-1', 'bash', {
command: `while [ ! -f ${JSON.stringify(sentinel)} ]; do sleep 0.02; done; echo bg-ok`,
description: 'test command',
run_in_background: true,
}),
textResponse('Started it in the background.'),
toolCallResponse('call-2', 'task_output', { task_id: 'bash-1' }),
textResponse('Background task finished.'),
@@ -192,29 +205,35 @@ describe('bash tool through the agent loop', () => {
const firstResult = findEvent(events(agent), 'tool/result')
expect(firstResult.data.message.content[0].isError).toBe(false)
expect(resultText(firstResult)).toBe('started background task bash-1')
// The task settles on its own; the tool-tasks notice listener injects a
// pending next-step message without waking the idle agent.
// The turn closed with the task still running, so the notice cannot exist yet.
const isNotice = (e: SessionEvent): e is SessionEvent<'user/message'> =>
e.type === 'user/message' && e.data.source.kind === 'plugin'
await pollUntil(() => agent.inbox.nextStep.some(message => message.source.kind === 'plugin'))
const pendingNotice = agent.inbox.nextStep.find(message => message.source.kind === 'plugin')!
expect(pendingNotice.content.some(
block => block.type === 'text' && block.text.includes('background task bash-1 (bash: echo bg-ok) finished'),
)).toBe(true)
expect(pendingNotice.source).toEqual({
expect(events(agent).some(isNotice)).toBe(false)
// Releasing the command now settles it against a provably idle owner. No
// second user message: the wake alone opens the turn that collects it.
writeFileSync(sentinel, '')
const lastResultText = (): string => {
const found = events(agent).findLast(event => event.type === 'tool/result')
return found === undefined ? '' : resultText(found)
}
await pollUntil(() => events(agent).some(isNotice) && lastResultText().includes('bg-ok'))
// Two turns: the user's, then the one the completion opened by itself.
expect(events(agent).filter(event => event.type === 'turn/start')).toHaveLength(2)
// The notice carries the gated command as its label, so this pins the id,
// the terminal status, and the producer identity; the verbatim notice text
// and its bounding are pinned in the tool-tasks unit tests.
const notice = events(agent).find(isNotice)!
const noticeText = notice.data.content
.filter(block => block.type === 'text').map(block => block.text).join('')
expect(noticeText).toContain('background task bash-1 (bash: ')
expect(noticeText).toContain('finished [status: completed, exit code: 0]')
expect(notice.data.source).toMatchObject({
kind: 'plugin',
plugin: 'tool-tasks',
form: 'notice',
summary: 'bash echo bg-ok [status: completed, exit code: 0]',
})
// The next turn first admits that notice as user/message, then collects
// the output through the generic task tool.
agent.followup(createUserMessage({ content: [{ type: 'text', text: 'collect it' }], source: { kind: 'user' } }))
await waitForIdle(ctx, agent)
const notice = events(agent).find(isNotice)!
expect(notice.data).toEqual(pendingNotice)
const readResult = findEvent(events(agent), 'tool/result', 'last')
expect(readResult.data.message.content[0].isError).toBe(false)
expect(resultText(readResult)).toContain('bg-ok')
+1 -1
View File
@@ -3,4 +3,4 @@
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write packages/bash/tool-pwsh/README.md
README.md: b843ed11823aadec7c28cc26e45da41701e40d3d
README.zh.md: 04f471fd15d6bf4343f674a29d03bb48c4870fdb
README.zh.md: 588e174d9eebbd5d426db3a9c5da5589c5d13a97
+29 -29
View File
@@ -2,13 +2,13 @@
[English](README.md) | 中文
注册在 `ctx.bash` 执行器 seam 之上的模型可见 `pwsh` 工具。面向由 PowerShell 执行器(如 `@deepseek-ai/dsh-pwsh-local`)支撑 `ctx.bash` 的 Windows 组合;工具约定是 PowerShell 方言:原生 `C:\...` 路径与 `$env:NAME` 变量。行为与 `dsh-tool-bash` 逐调用对齐——通过通用任务运行时执行前台与 `run_in_background`、通过共享 `bash-env` 注册表管理 `DSH_*` 环境、sandbox 拒绝渲染与同轮次 `sandbox_permissions` 升级面、以及 bash 的 marker/截断渲染故事(干净退出不产生 marker)。
注册在 `ctx.bash` 执行器 seam 之上的面向模型的 `pwsh` 工具。面向由 PowerShell 执行器(如 `@deepseek-ai/dsh-pwsh-local`)支撑 `ctx.bash` 的 Windows 组合;工具约定是 PowerShell 方言:原生 `C:\...` 路径与 `$env:NAME` 变量。行为与 `dsh-tool-bash` 逐调用对齐——通过通用任务运行时执行前台与 `run_in_background`、通过共享 `bash-env` 注册表管理 `DSH_*` 环境、sandbox 拒绝渲染与同轮次 `sandbox_permissions` 升级面、以及 bash 的 marker/截断渲染故事(干净退出不产生 marker)。
需要已加载的执行器实现与 `bash-env` 插件;两者都存在前工具保持 pending(`inject: ['tools', 'bash', 'systemPrompt', 'bashEnv']`)。
包根只导出 Cordis 插件约定(`name``inject``Config``apply`);结果渲染(`src/render.ts`)与后台任务适配(`src/background.ts`)镜像 bash 工具的结构,并可通过包的 `./src/*` 导出访问。
插件还贡献 `tool:pwsh` prompt sectionorder 105):非零退出以 `[exit code: N]` marker 报告,Windows 上的中断以无 signal 的 exit 1 结算。
插件还贡献 `tool:pwsh` 提示词段落order 105):非零退出以 `[exit code: N]` marker 报告,Windows 上的中断以无 signal 的 exit 1 结算。
## 工具
@@ -30,21 +30,21 @@
每次前台与后台模型 pwsh 调用都会通过共享的 [`dsh-bash-env`](../bash-env/) 注册表收到一份新收集的受信任 `DSH_*` 环境:`DSH_HOME`Harness 主目录绝对路径)、`DSH_SHELL=1`、agent 的 `DSH_SESSION_ID`,以及活跃持久化后端定位到 JSONL 时的 `DSH_SESSION_JSONL`。向 `ctx.bashEnv` 贡献 `DSH_*` 事实的插件对 pwsh 调用与 bash 调用一视同仁。快照通过专用的 `BashExecRequest.dshEnv` 通道传递;`process.env` 永不被修改。描述只教授通用的 `$env:DSH_*` 约定,而不是点名持久化相关的变量。
结果文本包含 stdout、可选的 `[stderr]` 段,然后是适用的截断、sandbox 拒绝(组合公开升级能力时带同轮次升级提示)、超时、signal 与退出 marker。干净退出(0、无 signal)不产生 marker;空体渲染为 `(no output)`。截断会链接一个安全的完整 spill 文件,或报告其不可用。超时独立于最终退出状态报告;非零退出仍是模型解读的结果而非 `isError`。Windows 上强制终止以无 signal 的 exit 1 结算,因此 `[killed by signal: …]` 在那里仅存在于 POSIX。只有基础设施失败——spawn 错误与中止(`tool call aborted`)——产生 `isError`
结果文本包含 stdout、可选的 `[stderr]` 段,然后是适用的截断、sandbox 拒绝(组合公开升级能力时带同轮次升级提示)、超时、signal 与退出 marker。干净退出(0、无 signal)不产生 marker;空体渲染为 `(no output)`。截断会链接一个安全的完整 spill 文件,或报告其不可用。超时独立于最终退出状态报告;非零退出仍是模型解读的结果而非 `isError`。Windows 上强制终止以无 signal 的 exit 1 结算,因此 `[killed by signal: …]` 仅适用于 POSIX。只有基础设施失败——spawn 错误与中止(`tool call aborted`)——产生 `isError`
规范成功形态是已完成前台进程的 `{ kind: 'foreground', ...BashRunResult }`(存在时投影执行器的 `sandbox` 事实——`mode`/`denied`、可选的 `enforcement`/`runnerFailed`)或已发布任务的 `{ kind: 'background', taskId }`。渲染器对后台 ack 精确保留 `started background task <id>`;编程消费者使用类型化字段而不解析渲染文本。
`run_in_background` 为 true 时,本插件在 spawn 前预检 `ctx.tasks.start()`,把调用 agent 注册为 owner,并将返回的 `BashProcess` 句柄适配为通用的 cancel/done/增量输出钩子。任务运行时拥有 id、跨会话隔离、完成通知、等待清理;本插件只把 pwsh 退出事实映射进任务输出与结果明细。`enableRunInBackground: false` 会移除参数并在执行时拒绝强制的后台调用。
`run_in_background` 为 true 时,本插件在 spawn 前预检 `ctx.tasks.start()`,把调用 agent 注册为 owner,并将返回的 `BashProcess` 句柄适配为通用的 cancel/done/增量输出钩子。任务运行时负责 task id、跨会话隔离、完成通知、等待和 dispose(资源释放)清理;本插件只把 pwsh 退出事实映射进任务输出与结果明细。`enableRunInBackground: false` 会移除参数并在执行时拒绝强制的后台调用。
## UI presentation
工具拥有自己的 `presentCall`/`presentResult` 呈现意图。前台调用是携带命令、描述与可选 cwd 的 `terminal` 卡;`run_in_background` 调用是携带原始命令的 `generic` 卡,镜像 bash 工具的后台呈现。完成的前台结果同样是 `terminal` 卡:退出 marker 变成卡片的退出状态 pill(`exitCode`/`signal`),去 marker 的正文成为卡片输出——与 bash 工具的 terminal 卡故事完全一致,经由 `@deepseek-ai/dsh-bash` 的共享退出状态解析。后台 ack 与执行错误保持 `generic` 卡,以 `console` 围栏包裹渲染输出。这些 presenter 是纯函数且可重放。
## Model Experience
## 模型体验
### System prompt
### 系统提示词
#### What the model sees
#### 模型看到的内容
本插件注册作用域内的每个请求都包含下面的 pwsh 指引。作用域工具限制可以隐藏 schema,但不会移除这个独立注册的段落。
@@ -54,71 +54,71 @@
Non-zero exits are reported as `[exit code: N]` markers; investigate failures before moving on. On Windows a killed process settles as `[exit code: 1]` without a signal marker; treat a bare exit 1 after an interruption as a termination, not a command failure.
```
#### Token effect
#### Token 影响
插件激活期间每次请求的固定小额输入成本。
#### KV Cache effect
#### KV Cache 影响
注册作用域与 prompt 文本不变时前缀稳定。插件激活或释放可能使该 prompt 段落的复用失效。
### Tool schemas
### 工具 schema
#### What the model sees
#### 模型看到的内容
模型看到生成的 [`pwsh` schema](../../../docs/tool-catalog.md#deepseek-aidsh-tool-pwsh)。按 agent 作用域的工具限制可以移除该 agent 的定义。
#### Token effect
#### Token 影响
工具可见的每个请求上的固定 schema 成本。
#### KV Cache effect
#### KV Cache 影响
可见性与工具定义不变时前缀稳定。限制或配置变更可能从首个变化 token 起使复用失效。
### Foreground result
### 前台结果
#### What the model sees
#### 模型看到的内容
渲染器输出数据相关的 stdout 尾部,然后是可选的 `[stderr]` 与 stderr 尾部。条件行精确为 `[output truncated; full output: <path>]``[sandbox: file access denied under <mode> mode]` 加升级提示 `[sandbox: escalation available — …]`(仅当组合公开升级能力时)、`[timed out after <timeoutMs>ms]``[killed by signal: <signal>]``[exit code: <exitCode>]`(仅非零退出);空体渲染为 `(no output)`
#### Token effect
#### Token 影响
调用前零结果 token。每个流的输出有界,而每条已发出的行保留在历史中直到压缩。
#### KV Cache effect
#### KV Cache 影响
仅追加;新出现的内容跟随可复用的请求前缀,不会使既有 KV-cache 条目失效。
仅追加;新出现的内容跟随可复用的请求前缀,不会使既有 KV Cache 条目失效。
### Background result
### 后台结果
#### What the model sees
#### 模型看到的内容
后台启动精确渲染为 `started background task <id>`;随后的读取与状态通过通用 `task_output`/`task_kill` 工具流转,包括内存截断丢弃未读字节时的 lossy 读取 spill 通知。
#### Token effect
#### Token 影响
ack 是固定短行;任务输出按读取有界。
#### KV Cache effect
#### KV Cache 影响
仅追加;新出现的内容跟随可复用的请求前缀,不会使既有 KV-cache 条目失效。
仅追加;新出现的内容跟随可复用的请求前缀,不会使既有 KV Cache 条目失效。
### Tool errors
### 工具错误
#### What the model sees
#### 模型看到的内容
校验与基础设施失败规范化为 `Error: <message>`。本包的稳定消息包括 `invalid command: expected a non-empty string``invalid description: expected a non-empty string``invalid timeoutMs: expected a positive number, got <value>``invalid escalation: sandbox_permissions requires a justification``invalid escalation: justification is only valid together with sandbox_permissions``invalid justification: expected a non-empty sentence``sandbox_permissions is not available in this composition (no sandboxing executor to escalate)`、共享的升级失败(非严格更宽、无审批服务、无 agent 可路由、无审批通道、用户拒绝、已取消)、`run_in_background is disabled for this deployment (enableRunInBackground: false)``background tasks unavailable: load @deepseek-ai/dsh-tasks and @deepseek-ai/dsh-tool-tasks``tool call aborted`
#### Token effect
#### Token 影响
只有失败的调用会新增这些保留 token;被中止的调用不产生命令输出。
#### KV Cache effect
#### KV Cache 影响
仅追加;新出现的内容跟随可复用的请求前缀,不会使既有 KV-cache 条目失效。
仅追加;新出现的内容跟随可复用的请求前缀,不会使既有 KV Cache 条目失效。
## Known Limitations and Deferred Work
## 已知限制与暂缓事项
- **Windows 沙箱下的语言模式与 named-pipe 捕获** — 在 [Windows ACL 沙箱](../../sandbox/sandbox-windows-acl/README.md) 下,read-only pwsh 会以 ConstrainedLanguage 启动,因为临时目录写入被拒绝,导致 PowerShell 的 AppLocker 探针失败并按 fail-closed 处理:`Add-Type`、非核心 .NET 静态调用(`[System.IO.*]::``[math]::`)、COM 对象与反射都会以“only core types”错误失败,且该模式无法从内部解除。workspace-write 的私有临时目录使探针得以完成,因此除非主机策略另有规定,否则它保持 FullLanguage。两种受限模式都拒绝 named-pipe 打开,因此受限命令内的管道 stdio spawn 以 EPERM 失败。工具描述把这两个约定教给模型;后端 README 负责完整的限制说明。
- **无持久 shell** — 每次调用都启动全新的 `pwsh -Command`;持久 shell 对应物是 [`@deepseek-ai/dsh-tool-pwsh-persistent`](../../pty/tool-pwsh-persistent/README.md),它在 WindowsConPTY)以及装有 pwsh 的 POSIX 主机上跨调用保持一个 owner 作用域的 pwsh 存活。
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@deepseek-ai/dsh-tool-pwsh",
"description": "Model-facing pwsh tool over the bash executor seam",
"version": "0.0.1-rc.1",
"version": "0.0.1-rc.2",
"publishConfig": {
"access": "restricted"
},