Merge remote-tracking branch 'origin/master' into feature/subagent-policy-inheritance

# Conflicts:
#	.agents/notes/implemented/feature/2026-07-06-approval-seam.i18n.yaml
#	examples/acp-agent/tests/acp.snapshot.ts
This commit is contained in:
kingwl
2026-07-26 16:12:38 +08:00
1297 changed files with 43626 additions and 9926 deletions

View File

@@ -0,0 +1,6 @@
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write
README.md: 4a651f262ee817edf5e9620d1cbf911b2d51b90b
README.zh.md: 63eaef2488a0bd478ec1f7f34cd96085faf63e45

View File

@@ -1,5 +1,7 @@
# sandbox/ — process-sandbox capability family
English | [中文](README.zh.md)
The confinement half of the [capability-seam split](../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md): an abstract provider interface, platform backends, and the shared policy home. Consumers hand `ctx.sandbox` the exact argv they are about to spawn and spawn the returned (wrapped) argv instead; a complete `SandboxExecutionPolicy` (mode + workspace root) rides each capability call, and its confined subset becomes the provider's `SandboxPolicy`. Different sessions and consumers can therefore confine under different policies at the same instant. All **product** packages.
| Package | Role | ctx key |

View File

@@ -0,0 +1,15 @@
# sandbox/:进程沙箱能力家族
[English](README.md) | 中文
[能力 seam 拆分](../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md)中负责限制的一半:抽象提供方接口、平台后端和共享策略归属位置。消费方把即将 spawn 的精确 argv 交给 `ctx.sandbox`,改为 spawn 返回的已包装 argv完整的 `SandboxExecutionPolicy`(模式 + Workspace 根)随每次能力调用传递,其中受限制的子集成为提供方的 `SandboxPolicy`。因此,不同会话与消费方可以同时按不同策略施加限制。这些全是**产品** 包。
| 包 | 职责 | ctx key |
|---|---|---|
| `sandbox/` | 抽象进程沙箱 seam`SandboxProvider` 契约 + 模式/强制执行/策略词汇),加共享 ESCALATION 工具包(`approveEscalation`、严格变宽的阶梯、拒绝/提示标记),以及所有强制执行方言共享的 `writableRoots` 派生 | `ctx.sandbox` |
| `sandbox-local/` | 按平台链选择的本地后端Linux 使用 `bwrap`,否则使用 `landlock-run` launcher通过 npm 分发的 [`node-addon-landlock-run`](https://www.npmjs.com/package/node-addon-landlock-run) 家族在自身仓库构建发布darwin 使用 `sandbox-exec`Seatbelt。多候选链会执行功能探测唯一候选项直接选择结论缓存快速失败 | (注册 `ctx.sandbox` |
| `sandbox-policy/` | 策略解析器:部署回退值,加每个会话的持久模式与不可变 cwd 根。两个强制执行家族都消费完整的逐调用结果,因此 bash 与 fs 不会限制到不同根目录 | `ctx.sandboxPolicy` |
该 seam 只限制与宿主共享文件系统和内核的子进程。容器、microVM 和远程执行器都不是这里的后端:它们会以环境一致的分组替换整个能力实现(`ctx.bash``ctx.fs`);边界记录在[沙箱 Agent Note](../../.agents/notes/implemented/feature/2026-07-06-sandbox.md) 中。
当前消费方:[`bash/bash-sandbox`](../bash/bash-sandbox/)(包装 `['bash', '-c', command]` 并通过 `ctx.sandbox` 执行)和 [`fs/fs-sandbox`](../fs/fs-sandbox/)(进程内路径隔离,而非 argv 包装层;读取 `ctx.sandboxPolicy`,对写入/编辑强制执行共享模式)。跨家族边界是沙箱 Agent Note 的[跨家族 fs 沙箱](../../.agents/notes/implemented/feature/2026-07-14-cross-family-fs-sandbox.md)阶段;共享词汇使两个家族可以向模型传授同一种拒绝标记与升权流程。

View File

@@ -0,0 +1,6 @@
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write
README.md: 923d983be8c2ccd60ed6eabcf9212dd89ef9bce3
README.zh.md: 9c5a79ed8df36281932959af7b0ad0b801dbaa55

View File

@@ -1,5 +1,7 @@
# @deepseek-ai/dsh-sandbox-local
English | [中文](README.zh.md)
Local implementation of the [`dsh-sandbox`](../sandbox/) seam. It selects and caches one platform runner: Linux prefers a working `bwrap` then Landlock; macOS uses Seatbelt. Multiple candidates are probed in order, while a sole candidate is selected directly.
The package root exports the default and named `LocalSandboxProvider` plugin, `Config`, and its public test-injection seam; platform profile builders stay internal.

View File

@@ -0,0 +1,40 @@
# @deepseek-ai/dsh-sandbox-local
[English](README.md) | 中文
[`dsh-sandbox`](../sandbox/) seam 的本地实现。它选择并缓存一个平台 runnerLinux 优先选择可工作的 `bwrap`,否则选择 LandlockmacOS 使用 Seatbelt。多个候选项会按顺序探测只有一个候选项时则直接选择。
包根导出默认及命名的 `LocalSandboxProvider` 插件、`Config` 和公共测试注入 seam平台 profile builder 保持内部状态。
不受支持的平台和不可用 runner 会以 `SANDBOX_UNAVAILABLE` 快速失败;执行绝不会静默回退为不受限制。每次包装都携带 runner 失败签名,使消费方能够区分损坏的沙箱与命令失败。[沙箱 Agent Note](../../../.agents/notes/implemented/feature/2026-07-06-sandbox.md)拥有选择原理与 profile 差异。
策略逐调用传入;提供方只存储机制与缓存的 runner 结论。每次包装都会报告强制执行完整度,以及后端专用的拒绝和 runner 失败签名。`runnerCommand` 是操作方对 bwrap 形状 runner 的断言,会跳过探测;但命令缺失或不可执行时,执行仍会快速失败。由于其机制未知,它会同时携带两种 Linux 拒绝方言。`probeTimeoutMs` 限制功能探测。[沙箱 Agent Note](../../../.agents/notes/implemented/feature/2026-07-06-sandbox.md)拥有选择与失败语义。
Seatbelt profile 默认允许,但带 `(deny file-write*)` 和写入 allow-list因此恰好治理对应模式承诺的文件 effect`read-only` 只授予 `/dev/null` 字面路径;`workspace-write` 另加 Workspace 根、`/tmp` 和逐用户 darwin 临时目录(`os.tmpdir()`,即平台供 mkstemp 家族工具使用的真实临时区域)。每个根都经过规范化,因为 Seatbelt 匹配解析后的路径(`/tmp` 就是 `/private/tmp`。Apple 将 `sandbox-exec` CLI 标为 deprecated但每个 macOS 仍会提供它;若情况发生变化,功能探测会快速失败。
[`node-addon-landlock-run`](https://www.npmjs.com/package/node-addon-landlock-run)提供平台 launcher、功能探测和 CLI 参数词汇。该提供方只拥有模式到授权的映射与 runner 选择。把路径解析和探测解析保留在带版本的 binary 中,可防止契约漂移。
每个阶梯都有会自行跳过的无密钥 world-effect 测试CI 在真实内核上运行平台 job并拒绝所有测试静默跳过。打包安装测试通过纯 Node 消费方运行 registry launcher 与可执行模式。
```yaml
- id: sandbox
name: '@deepseek-ai/dsh-sandbox-local'
```
消费方:[`@deepseek-ai/dsh-bash-sandbox`](../../bash/bash-sandbox/);可运行的默认组合见 [acp-agent 示例](../../../examples/acp-agent/)。
## 模型体验
通过 [`dsh-bash-sandbox`](../../bash/bash-sandbox/README.md) 和 [`dsh-tool-bash`](../../bash/tool-bash/README.md) 间接影响;它们渲染该提供方的强制执行与拒绝事实,而 [`dsh-sandbox`](../sandbox/README.md) seam 拥有 `SANDBOX_UNAVAILABLE` 文本runner 选择与 profile 则不进入上下文。
#### KV Cache 影响
不会直接失效;请求前缀变更由命名消费方负责。
## 已知限制与暂缓事项
- **Windows 没有 runner**`win32``SANDBOX_UNAVAILABLE` 快速失败AppContainer 家族后端暂缓实现。
- **Landlock 可能只实现部分强制执行**:较旧且受支持的内核 ABI 只能限制自身公开的访问类别,因此报告 `enforcement: 'partial'`,不会夸大为完整强制执行。
- **Seatbelt 依赖 deprecated 的 `sandbox-exec`**macOS 仍会提供它,但若 Apple 移除该私有策略引擎,该提供方无法替换或探测。
- **runner 选择在提供方生命周期内缓存**:安装、移除或修复 runner 后,必须重载插件才能改变选择。
- **`runnerCommand` 是操作方断言**:配置的自定义 runner 会跳过功能探测,并假定它诚实实现 bwrap 形状 profile。

View File

@@ -0,0 +1,6 @@
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write
README.md: 3e6d8082766d718b0cfcb94369f48a283713fcd2
README.zh.md: 2f84bd4971ddbe0f15e78ef7f5f069350ff43f1f

View File

@@ -1,5 +1,7 @@
# dsh-sandbox-policy — the sandbox policy home (`ctx.sandboxPolicy`)
English | [中文](README.zh.md)
The single owner of sandbox-policy resolution: the deployment's default [`SandboxMode`](../sandbox/README.md) and fallback root, plus each session's durable mode override and immutable workspace root. Every enforcing capability family receives one resolved mode-and-root policy per call.
## Why a shared home

View File

@@ -0,0 +1,42 @@
# dsh-sandbox-policy沙箱策略归属位置`ctx.sandboxPolicy`
[English](README.md) | 中文
沙箱策略解析的唯一 owner部署默认 [`SandboxMode`](../sandbox/README.md) 与回退根目录,加上每个会话的持久模式覆盖和不可变 Workspace 根。每个执行强制限制的能力家族在每次调用时收到一项解析完成的模式与根策略。
## 为何需要共享归属位置
两个家族强制执行同一套模式词汇:沙箱化 bash 执行器(`@deepseek-ai/dsh-bash-sandbox`)与沙箱化文件系统提供方(`@deepseek-ai/dsh-fs-sandbox`)。如果两者各自解析 `mode` + `workspaceRoot`就可能漂移成分裂世界bash 限制在一个根目录fs 却隔离另一个根目录,正是[沙箱 RFC](../../../.agents/notes/implemented/feature/2026-07-06-sandbox.md)所警告的情况。两个工具层都通过 `ctx.sandboxPolicy` 解析策略,两个执行后端也都消费完整的逐调用结果。[跨家族 fs 沙箱 RFC](../../../.agents/notes/implemented/feature/2026-07-14-cross-family-fs-sandbox.md)记录了共享策略决策。
## 配置
- `mode`:部署默认 `SandboxMode``read-only``workspace-write``danger-full-access`),加载时验证。默认为 `read-only`(故障安全)。
- `workspaceRoot`agentless 调用或没有 cwd 的会话在 `workspace-write` 下可写入的回退目录。默认为 `process.cwd()`,两种情况下都会解析为其绝对文件系统标识。普通 agent 调用改用其会话头中不可变的 `cwd`
## 表层
- `ctx.sandboxPolicy.resolve({ session?, mode? })`:解析一项完整的逐调用策略。显式批准的模式优先于会话最后一条 `sandbox/mode` 事件,后者又优先于 `defaultMode`;会话不可变的 `cwd` 会先按文件系统语义规范化,再成为 `workspaceRoot`,否则使用配置的回退值。规范化先于词法归一化,因此 `symlink/..` 与进程工作目录解析保持一致。
- `ctx.sandboxPolicy.defaultMode``ctx.sandboxPolicy.workspaceRoot``resolve()` 使用的部署默认值与回退根。
- `effectiveSandboxMode(events)`:会话 `sandbox/mode` 事件的纯 fold最后一次切换胜出没有则为 `undefined`),在 `resolve()` 内使用。
- `setSandboxMode(session, mode)`:逐会话覆盖的唯一写入路径:恰好追加一条 `sandbox/mode` 事件。切换本身就是事件;不会在带外修改模式。
- `ctx.sandboxPolicy.overrideOf(session)``ctx.sandboxPolicy.stampOverride(child, mode)`:委派继承的两半:仅折叠本身(绝不包含部署默认值),以及通过 `setSandboxMode` 写入捕获的覆盖项,子 agent 已折叠出该值时跳过。进程内 subagent 驱动器在委派时捕获,并在子 agent 的第一个轮次内盖章,使发起委派的父级收紧后的模式约束其子 agent参见[设计原理](../../../.agents/notes/implemented/feature/2026-07-25-subagent-policy-inheritance.md))。
- `SANDBOX_MODES`:所有模式,用于选项展示与运行时验证。
可选的 `./invariant` 配套组件会拒绝伪造的持久 `sandbox/mode` 事件只要其值不在该封闭词汇中Session 与其配套组件拥有周围的存储与轮次封闭规则。
## 逐会话 store
运行时切换是在对应会话日志中追加的一条 `sandbox/mode` 事件。`effective = explicit grant ?? fold(events) ?? deployment default`因此覆盖会通过回放跨重启保留两个会话也绝不会看到彼此状态。Workspace 标识无需另一条事件:创建时记录的不可变 `SessionHeader.cwd` 是该会话每次调用使用的根。该事件只进入日志(沿用 `approval/*` 先例):模型通过强制执行工具的拒绝标记获知模式,绝不会从事件获知。
## 模型体验
通过 `dsh-tool-bash``dsh-tool-fs` 间接影响;它们会在 `[sandbox: …]` 拒绝标记和升权提示词中渲染该服务持有的有效模式,`sandbox/mode` 事件本身绝不会到达模型。
#### KV Cache 影响
不会直接失效;请求前缀变更由命名消费方负责,且提示词有意不包含模式。
## 已知限制与暂缓事项
- **每个会话只有一个主要 Workspace 根**:策略解析 `SessionHeader.cwd`;额外可写根不属于 `SandboxExecutionPolicy`
- **只有文件 effect 模式**`SandboxMode` 治理文件 effect网络和进程策略不在其词汇中因此这里没有限制它们的旋钮。

View File

@@ -0,0 +1,6 @@
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write
README.md: 99f0641560937f66df6db76ae55c90595329792f
README.zh.md: 402c24135359137b5acde10e11aa676c2460584a

View File

@@ -1,5 +1,7 @@
# @deepseek-ai/dsh-sandbox
English | [中文](README.zh.md)
Abstract process-sandbox seam. Owns the `ctx.sandbox` service contract ([`SandboxProvider`](src/index.ts)) and the confinement vocabulary the harness shares: `SandboxMode` (`read-only` / `workspace-write` / `danger-full-access`, file effects only), `SandboxEnforcement` (`full` / `partial`, per kernel ABI), `SandboxExecutionPolicy` (the complete per-call mode + workspace root), `SandboxPolicy` (its confined subset), and the fail-closed `SANDBOX_UNAVAILABLE` error. Interface package of the [capability-seam split](../../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md): depends only on cordis (+ the harness error base), never on a backend.
The contract in one line: `ctx.sandbox.confine(argv, policy)` returns the argv to spawn INSTEAD of your own — wrapped so the process (and everything it spawns) runs confined — plus two facts about the selected backend: the enforcement completeness it achieves and its denial dialect (`denialSignatures`, the stderr substrings its kernel prints on a denied file effect — what stderr-inferring consumers match instead of a cross-backend union); when no backend is usable it throws rather than passing the argv through unconfined.

View File

@@ -0,0 +1,42 @@
# @deepseek-ai/dsh-sandbox
[English](README.md) | 中文
抽象进程沙箱 seam。拥有 `ctx.sandbox` 服务契约([`SandboxProvider`](src/index.ts))与 harness 共享的限制词汇:`SandboxMode``read-only``workspace-write``danger-full-access`,仅限文件 effect`SandboxEnforcement``full``partial`,逐内核 ABI`SandboxExecutionPolicy`(完整的逐调用模式 + Workspace 根)、`SandboxPolicy`(其中受限制的子集),以及快速失败的 `SANDBOX_UNAVAILABLE` 错误。它是[能力 seam 拆分](../../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md)的接口包:只依赖 cordis及 harness 错误基类),绝不依赖后端。
用一句话概括契约:`ctx.sandbox.confine(argv, policy)` 返回应当取代自有 argv 用于 spawn 的 argv。返回值经过包装使进程及其 spawn 的一切都在限制下运行;另附所选后端的两个事实:它达到的强制执行完整度,以及拒绝方言(`denialSignatures`,即内核在文件 effect 被拒绝时打印到 stderr 的子字符串;通过 stderr 推断的消费方会匹配这些字符串,而不是跨后端联合)。没有可用后端时,它会抛出异常,绝不会原样传递 argv 使其不受限制地运行。
策略随调用传递而不属于提供方两个消费方可以同时按不同策略施加限制bash 使用 `read-only`,而受限制子 agent 保持其状态目录可写);获批的升权重试只是使用更宽策略发起的新调用。
**只支持与宿主共享文件系统和内核的限制。** 后端与宿主共享文件系统和内核(`bwrap`、Landlock、Seatbelt`workspaceRoot` 指向文件系统规范化后的真实主机目录。系统先解析 Workspace 标识,再做词法规范化,因此包含 `symlink/..` 的有效 cwd 会授权 `chdir` 实际到达的目录而非无关的词法父目录。容器、microVM 与远程执行器都不是该 seam 的后端:它们会以环境一致的分组替换整个能力实现(`ctx.bash``ctx.fs`)。边界及其原理见[沙箱 Agent Note](../../../.agents/notes/implemented/feature/2026-07-06-sandbox.md)。
实现:[`@deepseek-ai/dsh-sandbox-local`](../sandbox-local/)Linux`bwrap`,否则使用逐平台 Landlock launchermacOS`sandbox-exec`Seatbelt。消费方[`@deepseek-ai/dsh-bash-sandbox`](../../bash/bash-sandbox/)(包装 `['bash', '-c', command]`)。
## 模型体验
### 间接的限制错误
#### 模型看到的内容
通过 [`dsh-bash-sandbox`](../../bash/bash-sandbox/README.md) 和 [`dsh-tool-bash`](../../bash/tool-bash/README.md),无法强制执行所请求模式时会生成 code `SANDBOX_UNAVAILABLE` 及以下精确错误。执行期 runner 失败会追加 ` Runner failure: <detail>`
##### 精确错误
```markdown
sandbox mode "<mode>" is requested but no sandbox backend is usable on this host; refusing to run the command unconfined. Install bubblewrap or run a Landlock-enforcing kernel (Linux), ensure sandbox-exec is usable (macOS) — Windows has no confinement backend yet — or switch the consumer to danger-full-access.
```
#### Token 影响
条件性错误文本对该次调用可见,并保留在历史中直到压缩。
#### KV Cache 影响
仅追加;新可见内容位于可复用请求前缀之后,不会使现有 KV-cache 配置项失效。
## 已知限制与暂缓事项
- **文件 effect 是完整的策略词汇**:该 seam 不表达网络、进程、syscall、设备或 credential 限制。
- **只支持与宿主共享文件系统和内核的限制**容器、microVM 与远程执行需要替换能力实现,而不是在此处增加提供方。
- **拒绝报告是一种 stderr 方言**:该 seam 返回后端签名,而非类型化运行时拒绝通道,因此需要分类的消费方必须从子进程输出推断。
- **每个上下文只有一个提供方**:同时组合不同沙箱机制需要提供方级阶梯或独立 Cordis 上下文;调用方逐调用选择策略,而非后端标识。