@deepseek-ai/dsh-sandbox 0.1.5-rc.2 → 0.1.6-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.i18n.yaml CHANGED
@@ -2,5 +2,5 @@
2
2
  # side as of the last confirmed-consistent state. Both languages carry equal authority;
3
3
  # after editing either side, bring the other along and re-record with:
4
4
  # pnpm run verify-translation-pairing --write packages/sandbox/sandbox/README.md
5
- README.md: b80e923e3dc6d5fd95f79546cdfa39a9ef82055f
6
- README.zh.md: 9d80a3621be0533bf31294702da7f6b9c9292ae2
5
+ README.md: 56cdd87c274cc8d951d4bc4e1388d7e985aa4a28
6
+ README.zh.md: c09d7e31fca4825e370636a4c5d9648e145f6a54
package/README.md CHANGED
@@ -63,7 +63,7 @@ Enforcement is reported per call: `full` means the backend governs every promise
63
63
 
64
64
  ### Denied calls and escalation
65
65
 
66
- When a confined call is denied, the operation reports a denial marker naming the mode — `[sandbox: file access denied under <mode> mode]` — and, when the composition advertises escalation, an escalation hint. The model may retry the exact call once with `sandbox_permissions` (the narrowest wider mode that suffices) plus a `justification`; the user sees one approval prompt and can allow once, reject, or cancel. The escalation must be strictly wider than the call's effective mode, and it applies to that one call only.
66
+ When a confined call is denied, the operation reports a denial marker naming the mode — `[sandbox: file access denied under <mode> mode]` — and, when the composition advertises escalation, an escalation hint. The model may retry the exact call once with `sandbox_permissions` (the narrowest wider mode that suffices) plus a `justification`; the user sees one approval prompt and can allow once, reject, or cancel. A wider mode requires approval and applies to that one call only. Repeating the call's effective mode succeeds without approval; narrower targets remain invalid.
67
67
 
68
68
  ### Fail-closed behavior
69
69
 
@@ -81,9 +81,9 @@ This section explains the design decisions behind the contract and points at the
81
81
 
82
82
  ### Design philosophy
83
83
 
84
- - **Same-world by contract.** `ctx.sandbox` wraps argv under a host-path file policy; containers, microVMs, and remote execution replace the surrounding capability seam instead.
84
+ - **One execution world.** The filesystem, subprocess and sandbox providers operate on the same filesystem and kernel. Remote compositions replace all three providers; confinement resolves asynchronously in that world.
85
85
  - **Policy rides the call.** `SandboxPolicy` is carried per call, never fixed on the provider: two consumers may confine under different policies at the same instant, and an escalated retry is a new call with a wider policy. Defaulting and resolution are explicit consumer steps.
86
- - **Fail closed.** `confine()` returns enforcing argv or throws `SandboxUnavailableError`; silent unconfined passthrough is forbidden, and functional probes arbitrate multi-runner chains.
86
+ - **Fail closed.** `confine()` resolves to enforcing argv or rejects with `SandboxUnavailableError`; silent unconfined passthrough is forbidden, and functional probes arbitrate multi-runner chains.
87
87
  - **One vocabulary for denial and escalation.** The marker and hint texts and the strictly-wider ladder live here so the bash and fs families cannot drift apart.
88
88
 
89
89
  ### Source map
@@ -97,7 +97,7 @@ This section explains the design decisions behind the contract and points at the
97
97
 
98
98
  ### Escalation choreography
99
99
 
100
- The ladder is a closed table — `read-only` may escalate to `workspace-write` or `danger-full-access`, `workspace-write` only to `danger-full-access` — checked at execution, never baked into a tool schema, whose enum stays the closed target vocabulary. [`approveEscalation`](src/escalation.ts) validates the `sandbox_permissions`/`justification` pairing, rejects non-widening requests without prompting a human, and maps every approval outcome to its own error before anything executes.
100
+ The ladder is a closed table — `read-only` may escalate to `workspace-write` or `danger-full-access`, `workspace-write` only to `danger-full-access` — checked at execution, never baked into a tool schema, whose enum stays the closed target vocabulary. [`approveEscalation`](src/escalation.ts) returns the current mode without approval when it is repeated, rejects narrower or unsupported targets, and requests approval for wider modes. Callers validate the `sandbox_permissions`/`justification` pairing first.
101
101
 
102
102
  ### Writable roots
103
103
 
@@ -141,7 +141,7 @@ Conditional error text is visible for that call and retained in history until co
141
141
 
142
142
  #### KV Cache effect
143
143
 
144
- Append-only; newly visible content follows the reusable request prefix and does not invalidate existing KV-cache entries.
144
+ Append-only; newly visible content follows the reusable request prefix and does not invalidate existing KV Cache entries.
145
145
 
146
146
  ### Escalation request and outcome
147
147
 
package/README.zh.md CHANGED
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: "进程沙箱服务约定:面向组合、使用或扩展同世界子进程隔离的用户与维护者。"
2
+ description: "面向用户与维护者的进程沙箱服务约定,用于组合、使用或扩展与宿主共享文件系统和内核的子进程限制机制。"
3
3
  kind: "package-reference"
4
4
  ---
5
5
 
@@ -9,7 +9,7 @@ kind: "package-reference"
9
9
 
10
10
  ## 概述
11
11
 
12
- 使用 `dsh-sandbox`,可以让子进程及其派生的所有进程在逐调用文件访问策略下运行。命令可以禁止写入(`read-only`)、只写入工作区(`workspace-write`),或不受限制地运行(`danger-full-access`)。无法强制执行所请求的模式时,调用以 `SANDBOX_UNAVAILABLE` 失败,绝不会不受限制地运行。调用被拒绝后,模型可以请求一个严格更宽的模式,交由人类批准一次。这是同世界隔离:进程仍与宿主共享内核和文件系统;需要隔离整个环境时,请使用容器、microVM 或远程执行器。
12
+ 使用 `dsh-sandbox`,可以让子进程及其派生的所有进程在逐调用文件访问策略下运行。命令可以禁止写入(`read-only`)、只写入工作区(`workspace-write`),或不受限制地运行(`danger-full-access`)。无法强制执行所请求的模式时,调用以 `SANDBOX_UNAVAILABLE` 失败,绝不会不受限制地运行。调用被拒绝后,模型可以请求一个严格更宽的模式,交由人类批准一次。这种限制只适用于与宿主共享内核和文件系统的进程;需要隔离整个环境时,请使用容器、microVM 或远程执行器。
13
13
 
14
14
  ## 目录
15
15
 
@@ -29,11 +29,11 @@ kind: "package-reference"
29
29
 
30
30
  ### 何时选择
31
31
 
32
- 当组合需要在宿主机上隔离子进程时选择本包:本地后端与受限执行器都实现这个约定,因此在 `ctx.sandbox` 后挂载 `sandbox-local`、在 `ctx.shell` 后挂载受限执行器,就能让每次 bash 或 pwsh 调用都有受限默认值。当进程必须在隔离环境中运行时请另选方案——容器、microVM 或远程执行器会替换整个 `ctx.shell`/`ctx.fs` 能力,而不是在这里添加后端。
32
+ 当组合需要在宿主机上隔离子进程时选择本包:本地后端与受限执行器都实现这个约定,因此在 `ctx.sandbox` 后挂载 `sandbox-local`、在 `ctx.shell` 后挂载受限执行器,就能使每次 bash 或 pwsh 调用默认在限制下运行。当进程必须在隔离环境中运行时请另选方案——容器、microVM 或远程执行器会替换整个 `ctx.shell`/`ctx.fs` 能力,而不是在这里添加后端。
33
33
 
34
34
  ### 隔离命令
35
35
 
36
- 挂载服务、后端与受限执行器;[base bundle](../../bundle/base/cordis.patch.yml)拥有随附组合。
36
+ 挂载服务、后端与受限执行器;随附的组合由[基础组合包(base bundle)](../../bundle/base/cordis.patch.yml)定义。
37
37
 
38
38
  ```yaml
39
39
  - id: sandbox
@@ -63,7 +63,7 @@ kind: "package-reference"
63
63
 
64
64
  ### 被拒绝的调用与升权
65
65
 
66
- 受限调用被拒绝时,操作会报告指明模式的拒绝标记——`[sandbox: file access denied under <mode> mode]`——组合声明升权能力时还会给出升权提示。模型可以用 `sandbox_permissions`(足以放行的最窄更宽模式)加 `justification` 重试一次完全相同的调用;用户会看到一次审批提示,可以选择允许一次、拒绝或取消。升权必须严格宽于调用的生效模式,且只作用于该次调用。
66
+ 受限调用被拒绝时,操作会报告指明模式的拒绝标记——`[sandbox: file access denied under <mode> mode]`——组合声明升权能力时还会给出升权提示。模型可以用 `sandbox_permissions`(足以放行的最窄更宽模式)加 `justification` 重试一次完全相同的调用;用户会看到一次审批提示,可以选择允许一次、拒绝或取消。更宽的模式需要审批,且只作用于该次调用。重复指定调用的生效模式无需审批即可成功;更窄的目标仍然无效。
67
67
 
68
68
  ### 故障关闭行为
69
69
 
@@ -81,9 +81,9 @@ kind: "package-reference"
81
81
 
82
82
  ### 设计理念
83
83
 
84
- - **按约定限同世界。** `ctx.sandbox` 在宿主路径文件策略下包装 argv;容器、microVM 与远程执行会替换周边能力 seam。
84
+ - **同一执行环境。** 文件系统、子进程与沙箱提供方使用同一文件系统和内核。远端组合替换这三个提供方,并在该环境中异步解析限制。
85
85
  - **策略随调用传递。** `SandboxPolicy` 逐调用携带,绝不在提供方上固定:两个消费方可以同时按不同策略隔离,获批的升权重试只是用更宽策略发起的新调用。默认与解析是消费方显式步骤。
86
- - **故障关闭。** `confine()` 返回受强制的 argv,或抛出 `SandboxUnavailableError`;绝不允许静默无限制放行,功能探测用于仲裁多 runner 链。
86
+ - **故障关闭。** `confine()` 异步返回用于强制执行限制的 argv,或以 `SandboxUnavailableError` 拒绝;绝不允许静默无限制放行,功能探测用于仲裁多 runner 链。
87
87
  - **统一的拒绝与升权词汇。** 标记与提示文本以及严格更宽阶梯都放在这里,使 bash 与 fs 家族不会漂移。
88
88
 
89
89
  ### 源码地图
@@ -93,11 +93,11 @@ kind: "package-reference"
93
93
  | [`src/index.ts`](src/index.ts) | 插件入口:`SandboxProvider` 服务、模式/强制执行/策略类型、故障关闭错误 |
94
94
  | [`src/escalation.ts`](src/escalation.ts) | 升权词汇:更宽模式阶梯、参数校验、拒绝与提示标记、审批编排 |
95
95
  | [`src/roots.ts`](src/roots.ts) | 可写根目录推导,Seatbelt profile 与进程内 fs 栅栏共享 |
96
- | — | 不发布运行时不变式伴生入口;抽象 seam 不注册事件或数据关系。 |
96
+ | — | 不发布运行时不变式伴生入口;除所属 seam 强制执行的约定外,本包不公开独立的事件序列或可变数据关系。 |
97
97
 
98
98
  ### 升权编排
99
99
 
100
- 阶梯是封闭表——`read-only` 可升权到 `workspace-write` 或 `danger-full-access`,`workspace-write` 只能升权到 `danger-full-access`——在执行时检查,绝不写入工具 schema,schema 的枚举保持封闭的目标词汇。[`approveEscalation`](src/escalation.ts) 校验 `sandbox_permissions`/`justification` 配对、不提示人类就拒绝非加宽请求,并在任何执行前把每个审批结果映射到各自的错误。
100
+ 阶梯是封闭表——`read-only` 可升权到 `workspace-write` 或 `danger-full-access`,`workspace-write` 只能升权到 `danger-full-access`——在执行时检查,绝不写入工具 schema,schema 的枚举保持封闭的目标词汇。[`approveEscalation`](src/escalation.ts) 在请求重复当前模式时无需审批就返回该模式,拒绝更窄或不支持的目标,并为更宽模式请求审批。调用方先校验 `sandbox_permissions`/`justification` 配对。
101
101
 
102
102
  ### 可写根目录
103
103
 
@@ -165,7 +165,7 @@ sandbox mode "<mode>" is requested but no sandbox backend is usable on this host
165
165
  这些限制说明该 seam 何时不合适,或何时需要特别运维。它们是当前包约束,不是通用沙箱对比或任务积压。
166
166
 
167
167
  - **文件操作是完整的策略词汇**——该 seam 不表达网络、进程、系统调用、设备或凭据限制。
168
- - **仅限同世界隔离**——容器、microVM 与远程执行需要替换能力实现,而不是在此添加提供方。
168
+ - **只支持与宿主共享文件系统和内核的限制**——容器、microVM 与远程执行需要替换能力实现,而不是在此添加提供方。
169
169
  - **拒绝报告是一种 stderr 方言**——该 seam 返回后端签名,而非类型化运行时拒绝通道,需要分类的消费方必须从子进程输出推断。
170
170
  - **Runner 诊断使用带内通道**——退出状态与 stderr 证据无法证明匹配行由哪个进程写入,因此故意模仿 runner 的受限子进程可能造成错误的可用性或诊断归因;这无法绕过隔离,带外 runner 状态通道暂缓实现。
171
171
  - **每个上下文只有一个提供方**——同时组合不同沙箱机制需要提供方级阶梯或独立 Cordis 上下文;调用方逐调用选择策略,而非后端标识。
package/lib/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Service } from "@deepseek-ai/cordis";
2
2
  import { HarnessError } from "@deepseek-ai/dsh-llm";
3
3
  import { assertNever } from "@deepseek-ai/dsh-util-values";
4
- import { realpathSync } from "node:fs";
4
+ import { accessSync, constants, realpathSync, statSync } from "node:fs";
5
5
  import { tmpdir } from "node:os";
6
6
  //#region lib/types/escalation.js
7
7
  /**
@@ -77,21 +77,18 @@ function escalationHintMarker(subject) {
77
77
  return `[sandbox: escalation available — retry this exact ${subject} once with sandbox_permissions (the narrowest wider mode that suffices) + justification; the approval prompt asks the user]`;
78
78
  }
79
79
  /**
80
- * Resolve a sandbox-escalation request BEFORE anything executes: check strict
81
- * widening against the call's effective mode, then resolve the approval
82
- * channel, then map every outcome — the ordered fail-closed sequence both
83
- * enforcing families share. Returns the granted mode to stamp onto exactly
84
- * this call; throws the distinct verbatim text for every other path (a
85
- * non-widening request, a missing approval service, an agent-less execution,
86
- * a rejection, a cancellation, an unanswerable ask) — the tool registry turns
87
- * the throw into the call's isError result, and nothing has run. A
88
- * non-widening request never prompts a human.
80
+ * Resolve a sandbox permission request before execution. Repeating the call's
81
+ * effective mode returns it without approval. A strictly wider mode requires
82
+ * approval and applies only to this call. Narrower or unsupported targets,
83
+ * missing approval services or agents for widening, and non-grant outcomes
84
+ * throw before execution.
89
85
  * @param request - the escalation to judge (see {@link EscalationRequest}).
90
86
  * @param approval - the approval ingredients the tool holds (see {@link EscalationApproval}).
91
87
  * @returns the granted mode, consumed by the one call that asked.
92
88
  */
93
89
  async function approveEscalation(request, approval) {
94
90
  const { requestedMode: mode, effectiveMode, justification, subject } = request;
91
+ if (mode === effectiveMode) return effectiveMode;
95
92
  if (!(WIDER_MODES[effectiveMode] ?? []).includes(mode)) throw new Error(`sandbox escalation to "${mode}" is not strictly wider than this call's current "${effectiveMode}" mode`);
96
93
  if (approval.approver === void 0) throw new Error(`sandbox escalation to "${mode}" requires approval, but no approval service is composed`);
97
94
  if (approval.agent === void 0) throw new Error(`sandbox escalation to "${mode}" requires approval, but the call has no agent to route it through`);
@@ -161,6 +158,82 @@ function writableRoots(policy) {
161
158
  ].map(canonicalPath))];
162
159
  }
163
160
  //#endregion
161
+ //#region lib/types/diagnostics.js
162
+ /** Classify observed sandbox runner failures and file-effect denials. */
163
+ /** Node-local spawn codes proven to identify executable resolution or permission failure. */
164
+ const EXECUTABLE_SPAWN_CODES = new Set(["EACCES", "ENOENT"]);
165
+ /** Whether the caller-owned spawn cwd can be entered. */
166
+ function isUsableWorkdir(path) {
167
+ try {
168
+ if (!statSync(path).isDirectory()) return false;
169
+ accessSync(path, constants.X_OK);
170
+ return true;
171
+ } catch {
172
+ return false;
173
+ }
174
+ }
175
+ /**
176
+ * Attribute only Node ENOENT/EACCES failures whose error path equals argv[0]
177
+ * after independently ruling out the caller-owned cwd. A supplied error path
178
+ * must exactly identify the runner; without one, the syscall must. With a
179
+ * usable cwd, these codes describe resolution or execute permission for that
180
+ * argv[0] or its shebang interpreter.
181
+ * The workdir is checked at classification time, not atomically with spawn;
182
+ * concurrent path replacement may change attribution but cannot permit an
183
+ * unconfined execution.
184
+ * @param error - the original spawn rejection.
185
+ * @param runnerProgram - provider argv[0], the executable that establishes confinement.
186
+ * @param workdir - the caller-owned spawn cwd, checked independently for usability.
187
+ * @returns whether the rejection has executable-specific runner evidence.
188
+ */
189
+ function isRunnerSpawnFailure(error, runnerProgram, workdir) {
190
+ if (runnerProgram === void 0 || !isUsableWorkdir(workdir)) return false;
191
+ if (typeof error !== "object" || error === null) return false;
192
+ const { code, path, syscall } = error;
193
+ if (typeof code !== "string" || !EXECUTABLE_SPAWN_CODES.has(code)) return false;
194
+ if (typeof syscall !== "string") return false;
195
+ const exactSyscall = `spawn ${runnerProgram}`;
196
+ if (path === void 0) return syscall === exactSyscall;
197
+ if (typeof path !== "string" || path.length === 0 || path !== runnerProgram) return false;
198
+ return syscall === "spawn" || syscall === exactSyscall;
199
+ }
200
+ /**
201
+ * Classify one settled process against the selected backend's structured
202
+ * runner-failure rules. Each rule requires a nonzero exit, its optional
203
+ * exit-code gate, and a fatal signature on one stderr line after exact
204
+ * informational lines are excluded.
205
+ * @param exitCode - process exit code; null means signal termination.
206
+ * @param stderr - collected stderr text, left unchanged.
207
+ * @param rules - structured runner-failure rules from the active wrap.
208
+ * @returns the first matching fatal line, or undefined when evidence is insufficient.
209
+ */
210
+ function classifyRunnerFailure(exitCode, stderr, rules) {
211
+ if (exitCode === null || exitCode === 0) return void 0;
212
+ const lines = stderr.split(/\r?\n/);
213
+ for (const rule of rules) {
214
+ if (rule.allowedExitCodes !== void 0 && !rule.allowedExitCodes.includes(exitCode)) continue;
215
+ const informationalLines = new Set((rule.informationalLines ?? []).map((line) => line.toLowerCase()));
216
+ const fatalSignatures = rule.fatalSignatures.filter((signature) => signature.trim().length > 0).map((signature) => signature.toLowerCase());
217
+ for (const line of lines) {
218
+ const lowered = line.toLowerCase();
219
+ if (informationalLines.has(lowered)) continue;
220
+ if (fatalSignatures.some((signature) => lowered.includes(signature))) return { detail: line };
221
+ }
222
+ }
223
+ }
224
+ /**
225
+ * Match a non-zero exit against case-insensitive stderr signatures.
226
+ * @param exitCode - process exit code; null means signal termination.
227
+ * @param stderr - collected stderr text.
228
+ * @param signatures - substrings identifying the selected backend's dialect.
229
+ * @returns whether this is a non-zero exit whose stderr matches a signature.
230
+ */
231
+ function matchesSignature(exitCode, stderr, signatures) {
232
+ if (exitCode === null || exitCode === 0) return false;
233
+ const lowered = stderr.toLowerCase();
234
+ return signatures.some((signature) => lowered.includes(signature.toLowerCase()));
235
+ }
236
+ //#endregion
164
237
  //#region lib/types/index.js
165
238
  /**
166
239
  * Service Definition for the same-world process-confinement capability seam: wrap exact subprocess argv under a
@@ -199,4 +272,4 @@ var SandboxProvider = class extends Service {
199
272
  }
200
273
  };
201
274
  //#endregion
202
- export { ESCALATION_TARGETS, SANDBOX_UNAVAILABLE, SandboxProvider, SandboxProvider as default, SandboxUnavailableError, WIDER_MODES, approveEscalation, canonicalPath, escalationHintMarker, sandboxDenialMarker, validateEscalationArgs, writableRoots };
275
+ export { ESCALATION_TARGETS, SANDBOX_UNAVAILABLE, SandboxProvider, SandboxProvider as default, SandboxUnavailableError, WIDER_MODES, approveEscalation, canonicalPath, classifyRunnerFailure, escalationHintMarker, isRunnerSpawnFailure, matchesSignature, sandboxDenialMarker, validateEscalationArgs, writableRoots };
@@ -0,0 +1,42 @@
1
+ import type { RunnerFailureRule } from './index.ts';
2
+ /**
3
+ * Attribute only Node ENOENT/EACCES failures whose error path equals argv[0]
4
+ * after independently ruling out the caller-owned cwd. A supplied error path
5
+ * must exactly identify the runner; without one, the syscall must. With a
6
+ * usable cwd, these codes describe resolution or execute permission for that
7
+ * argv[0] or its shebang interpreter.
8
+ * The workdir is checked at classification time, not atomically with spawn;
9
+ * concurrent path replacement may change attribution but cannot permit an
10
+ * unconfined execution.
11
+ * @param error - the original spawn rejection.
12
+ * @param runnerProgram - provider argv[0], the executable that establishes confinement.
13
+ * @param workdir - the caller-owned spawn cwd, checked independently for usability.
14
+ * @returns whether the rejection has executable-specific runner evidence.
15
+ */
16
+ export declare function isRunnerSpawnFailure(error: unknown, runnerProgram: string | undefined, workdir: string): boolean;
17
+ /** Fatal runner evidence retained for infrastructure-error detail. */
18
+ interface RunnerFailureMatch {
19
+ /** The original stderr line that matched a fatal signature. */
20
+ detail: string;
21
+ }
22
+ /**
23
+ * Classify one settled process against the selected backend's structured
24
+ * runner-failure rules. Each rule requires a nonzero exit, its optional
25
+ * exit-code gate, and a fatal signature on one stderr line after exact
26
+ * informational lines are excluded.
27
+ * @param exitCode - process exit code; null means signal termination.
28
+ * @param stderr - collected stderr text, left unchanged.
29
+ * @param rules - structured runner-failure rules from the active wrap.
30
+ * @returns the first matching fatal line, or undefined when evidence is insufficient.
31
+ */
32
+ export declare function classifyRunnerFailure(exitCode: number | null, stderr: string, rules: readonly RunnerFailureRule[]): RunnerFailureMatch | undefined;
33
+ /**
34
+ * Match a non-zero exit against case-insensitive stderr signatures.
35
+ * @param exitCode - process exit code; null means signal termination.
36
+ * @param stderr - collected stderr text.
37
+ * @param signatures - substrings identifying the selected backend's dialect.
38
+ * @returns whether this is a non-zero exit whose stderr matches a signature.
39
+ */
40
+ export declare function matchesSignature(exitCode: number | null, stderr: string, signatures: readonly string[]): boolean;
41
+ export {};
42
+ //# sourceMappingURL=diagnostics.d.ts.map
@@ -112,21 +112,17 @@ export interface EscalationRequest {
112
112
  requestedMode: string;
113
113
  /** The model's one-sentence reason, shown verbatim to the user inside the audit reason. */
114
114
  justification: string;
115
- /** The call's effective mode (session override ?? composition default) the request must strictly widen. */
115
+ /** The call's effective mode (session override ?? composition default); repeating it needs no approval. */
116
116
  effectiveMode: SandboxMode;
117
117
  /** The family's noun for the escalated action in user-facing texts (`command` for bash, `operation` for fs). */
118
118
  subject: string;
119
119
  }
120
120
  /**
121
- * Resolve a sandbox-escalation request BEFORE anything executes: check strict
122
- * widening against the call's effective mode, then resolve the approval
123
- * channel, then map every outcome — the ordered fail-closed sequence both
124
- * enforcing families share. Returns the granted mode to stamp onto exactly
125
- * this call; throws the distinct verbatim text for every other path (a
126
- * non-widening request, a missing approval service, an agent-less execution,
127
- * a rejection, a cancellation, an unanswerable ask) — the tool registry turns
128
- * the throw into the call's isError result, and nothing has run. A
129
- * non-widening request never prompts a human.
121
+ * Resolve a sandbox permission request before execution. Repeating the call's
122
+ * effective mode returns it without approval. A strictly wider mode requires
123
+ * approval and applies only to this call. Narrower or unsupported targets,
124
+ * missing approval services or agents for widening, and non-grant outcomes
125
+ * throw before execution.
130
126
  * @param request - the escalation to judge (see {@link EscalationRequest}).
131
127
  * @param approval - the approval ingredients the tool holds (see {@link EscalationApproval}).
132
128
  * @returns the granted mode, consumed by the one call that asked.
@@ -134,10 +134,12 @@ export declare abstract class SandboxProvider extends Service {
134
134
  * `['bash', '-c', command]`.
135
135
  * @param policy - the file-effect policy this execution runs under,
136
136
  * carried per call (see {@link SandboxPolicy}).
137
+ * @param signal - cancellation while the provider resolves the policy and runner.
137
138
  * @returns the argv to spawn instead, plus the enforcement completeness
138
139
  * the selected backend achieves for it.
139
140
  */
140
- abstract confine(argv: readonly string[], policy: SandboxPolicy): ConfinedArgv;
141
+ abstract confine(argv: readonly string[], policy: SandboxPolicy, signal?: AbortSignal): Promise<ConfinedArgv>;
141
142
  }
142
143
  export default SandboxProvider;
144
+ export { classifyRunnerFailure, isRunnerSpawnFailure, matchesSignature } from './diagnostics.ts';
143
145
  //# sourceMappingURL=index.d.ts.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-sandbox",
3
3
  "description": "Abstract process-sandbox seam (ctx.sandbox) for the DeepSeek Harness: same-world confinement vocabulary and the SandboxProvider contract",
4
- "version": "0.1.5-rc.2",
4
+ "version": "0.1.6-alpha.2",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -28,15 +28,15 @@
28
28
  "license": "MIT",
29
29
  "peerDependencies": {
30
30
  "@deepseek-ai/cordis": "^4.0.2",
31
- "@deepseek-ai/dsh-llm": "^0.1.5-rc.2",
32
- "@deepseek-ai/dsh-session": "^0.1.5-rc.2"
31
+ "@deepseek-ai/dsh-llm": "^0.1.6-alpha.2",
32
+ "@deepseek-ai/dsh-session": "^0.1.6-alpha.2"
33
33
  },
34
34
  "devDependencies": {
35
+ "@deepseek-ai/dsh-llm": "^0.1.6-alpha.2",
35
36
  "@deepseek-ai/cordis": "^4.0.2",
36
- "@deepseek-ai/dsh-llm": "^0.1.5-rc.2",
37
- "@deepseek-ai/dsh-session": "^0.1.5-rc.2"
37
+ "@deepseek-ai/dsh-session": "^0.1.6-alpha.2"
38
38
  },
39
39
  "dependencies": {
40
- "@deepseek-ai/dsh-util-values": "^0.1.5-rc.2"
40
+ "@deepseek-ai/dsh-util-values": "^0.1.6-alpha.2"
41
41
  }
42
42
  }