@deepseek-ai/dsh-shell 0.1.6-alpha.1 → 0.1.7-alpha.1
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 +2 -2
- package/README.md +17 -10
- package/README.zh.md +17 -10
- package/lib/index.js +19 -21
- package/lib/types/index.d.ts +25 -33
- package/lib/types/types.d.ts +57 -8
- package/package.json +7 -9
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/shell/shell/README.md
|
|
5
|
-
README.md:
|
|
6
|
-
README.zh.md:
|
|
5
|
+
README.md: b72440a38cefb67140ba0078169aac34f3ccdb19
|
|
6
|
+
README.zh.md: 272ffc85f8c4880eb77348f2f5ce780a68529df6
|
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ English | [中文](README.zh.md)
|
|
|
9
9
|
|
|
10
10
|
## Summary
|
|
11
11
|
|
|
12
|
-
Use `ctx.shell` to run
|
|
12
|
+
Use `ctx.shell` to run shell commands with bounded output or keep them running as background work. One execution handle supports foreground results and background reads. A profile can select local or sandboxed Bash or PowerShell execution without changing callers. Resolve requests before execution to make the working directory, timeout, and output limits explicit. Command exits, timeouts, and caller aborts return results; only infrastructure failures reject, while the `bash` and `pwsh` tools own model-visible rendering and sandbox guidance.
|
|
13
13
|
|
|
14
14
|
## Table of Contents
|
|
15
15
|
|
|
@@ -25,24 +25,31 @@ Use `ctx.shell` to run foreground shell commands with bounded output or prepare
|
|
|
25
25
|
<a id="use-this-package"></a>
|
|
26
26
|
## Use this package
|
|
27
27
|
|
|
28
|
-
Use `ctx.shell` when an agent or an in-process plugin needs to run a shell command and read its output,
|
|
28
|
+
Use `ctx.shell` when an agent or an in-process plugin needs to run a shell command and read its output, keep a process running and poll it, or hand a foreground command a way to outlive its deadline. There is one execution method — `execute(spec)` resolves with the prepared handle — and "foreground" is a property of what the caller awaits, not of the spawn. It is the contract every shell executor and the model-facing `bash`/`pwsh` tools build on, so code written against it works over any executor implementation.
|
|
29
29
|
|
|
30
30
|
### Foreground commands
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
Await the handle's `result()` projection to run a command in the foreground. The promise resolves when the command finishes: a nonzero exit, an executor timeout kill, or a caller abort kill is a result, never a rejection. `result()` rejects only for infrastructure failures such as an unusable working directory or a missing shell. The result carries the exit code or signal, whether a timeout or an abort cut the run short (first-cause classification), and the collected stdout/stderr with spill-file paths when a stream overflowed its budget.
|
|
33
33
|
|
|
34
34
|
```text
|
|
35
|
-
const
|
|
35
|
+
const execution = await ctx.shell.execute(ctx.shell.resolve({ command: 'ls -la' }))
|
|
36
|
+
const result = await execution.result()
|
|
36
37
|
console.log(result.exitCode, result.stdout.text)
|
|
37
38
|
```
|
|
38
39
|
|
|
39
40
|
### Background processes
|
|
40
41
|
|
|
41
|
-
|
|
42
|
+
Resolve the request with `onExpiry: 'none'` and await `execute` for the prepared handle: no deadline is armed, and the process runs until killed or finished. Read output incrementally with `readOutput()` — consecutive reads never repeat output, and lossy reads point at full-stream spill files. Terminate the provider-managed range with `kill()` (returns `false` once the direct command has finished) and await `done` for direct-command settlement. Job ids, ownership, polling, and notices belong to the generic `ctx.jobs` runtime, where the tool layer registers the handle. `ShellProcess.observed` exposes non-consuming offset readers over the same captured streams — for observers independent of the consuming cursor, such as the job registry's pull sources — including the `spawn failed: …` note a rejected spawn leaves on stderr.
|
|
43
|
+
|
|
44
|
+
### Deadlines and bounded waits
|
|
45
|
+
|
|
46
|
+
The deadline includes asynchronous preparation. Expiry before a process starts returns a settled handle whose result is `timedOut: true`, with empty output. Cancellation or preparation failure rejects `execute` before publication; late preparation cannot spawn a process.
|
|
47
|
+
|
|
48
|
+
The seam has two expiry policies and no hand-over protocol. `'kill'` stops the command at the deadline and classifies the result `timedOut`; `'none'` arms no deadline, so only the caller's signal and `kill()` stop the command. A caller that wants to wait only for a while runs the command under `'none'` and bounds its own wait: the handle stays valid after the caller stops waiting, and nothing changes hands at that moment. The `bash`/`pwsh` tools do exactly this — with a job registry composed they register every command with `ctx.jobs` as it starts and wait on the job, so a foreground command that outlives its timeout simply keeps running as the job it already was.
|
|
42
49
|
|
|
43
50
|
### Requests and resolved specs
|
|
44
51
|
|
|
45
|
-
Every execution starts from a `ShellExecRequest` with optional fields; the executor's `resolve()` turns it into a fully-resolved `ShellExecSpec` with explicit defaults and caps before anything runs. This request/spec split is the repository's template for explicit resolution at package boundaries: callers never rely on hidden defaults inside `
|
|
52
|
+
Every execution starts from a `ShellExecRequest` with optional fields; the executor's `resolve()` turns it into a fully-resolved `ShellExecSpec` with explicit defaults and caps before anything runs. This request/spec split is the repository's template for explicit resolution at package boundaries: callers never rely on hidden defaults inside `execute`. `resolve()` fills the working directory, timeout, and expiry policy (default `'kill'`) from the executor's configuration and the request, caps per-call overrides, and carries optional inputs — `stdin`, ordinary `env`, and the trusted `DSH_*` snapshot — through verbatim.
|
|
46
53
|
|
|
47
54
|
### Choosing and composing an executor
|
|
48
55
|
|
|
@@ -73,15 +80,15 @@ This section explains the design of the seam and points at the code that realize
|
|
|
73
80
|
|
|
74
81
|
The package is one role of a standard capability seam: the Service Definition that names the executor contract, with Service Providers and Consumers split so each role evolves independently (see the [capability-seams note](../../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md)). Two decisions anchor the contract:
|
|
75
82
|
|
|
76
|
-
- **Explicit resolution at the boundary.** `resolve(request)` is the single place defaults and caps are applied; `
|
|
77
|
-
- **
|
|
83
|
+
- **Explicit resolution at the boundary.** `resolve(request)` is the single place defaults and caps are applied; `execute` accepts only resolved specs and never re-defaults, so no hidden fallback lives inside an implementation.
|
|
84
|
+
- **One execution, projected views.** `execute` resolves with the prepared handle; the foreground result and the background cursor reads are projections over the same spawned process, so foreground/background is the caller's choice, never a second spawn path. The handle carries no id or owner; job identity, ownership, and lifecycle belong to the generic `ctx.jobs` runtime, keeping executors independent of sessions.
|
|
78
85
|
|
|
79
86
|
### Source map
|
|
80
87
|
|
|
81
88
|
| File | Role |
|
|
82
89
|
|---|---|
|
|
83
90
|
| [`src/index.ts`](src/index.ts) | Plugin entry: abstract `ShellExecutor` service and the shared settings namespace |
|
|
84
|
-
| [`src/types.ts`](src/types.ts) | Request/spec vocabulary, `
|
|
91
|
+
| [`src/types.ts`](src/types.ts) | Request/spec vocabulary, `ShellExecution`, `ShellRunResult`, and sandbox facts |
|
|
85
92
|
| [`src/render.ts`](src/render.ts) | `parseExitStatus`: the exit-status marker contract the shell tools share |
|
|
86
93
|
| — | No runtime invariant companion is published; this stateless Service Definition owns request/result types, while executors and policy own observations. |
|
|
87
94
|
|
|
@@ -91,7 +98,7 @@ The package is one role of a standard capability seam: the Service Definition th
|
|
|
91
98
|
|
|
92
99
|
### Background lifecycle and ownership
|
|
93
100
|
|
|
94
|
-
A
|
|
101
|
+
A spawned process belongs to the subprocess service, not to the executor: it survives an executor-only reload and is killed and joined when the composition tears down. Implementations must honor the seam's semantics — `result()` rejects only for infrastructure failures; the handle is published after preparation and its `done` never rejects (provider rejections, synchronous or asynchronous, settle the handle as `killed` with a stage-neutral note on stderr while `result()` carries the same failure as its rejection; a live handle whose rejection follows the execution's own `kill()` or abort settles as its terminal outcome instead); `readOutput` is consuming and lossy reads report spill files.
|
|
95
102
|
|
|
96
103
|
</details>
|
|
97
104
|
|
package/README.zh.md
CHANGED
|
@@ -9,7 +9,7 @@ kind: "package-reference"
|
|
|
9
9
|
|
|
10
10
|
## 概述
|
|
11
11
|
|
|
12
|
-
使用 `ctx.shell`
|
|
12
|
+
使用 `ctx.shell` 运行输出有界的 shell 命令,或让命令作为后台工作继续运行。同一个执行句柄支持前台结果与后台读取。配置文件可以选择本地或沙箱化的 Bash 或 PowerShell 执行方式,而无需更改调用方。执行前解析请求,以显式确定工作目录、超时与输出上限。命令退出、超时和调用方中止都会作为结果返回;只有基础设施故障才会 reject,模型可见的渲染与沙箱指引由 `bash` 和 `pwsh` 工具负责。
|
|
13
13
|
|
|
14
14
|
## 目录
|
|
15
15
|
|
|
@@ -25,24 +25,31 @@ kind: "package-reference"
|
|
|
25
25
|
<a id="use-this-package"></a>
|
|
26
26
|
## 使用本包
|
|
27
27
|
|
|
28
|
-
当 agent(智能体)或进程内插件需要运行 shell
|
|
28
|
+
当 agent(智能体)或进程内插件需要运行 shell 命令并读取输出、保持进程运行并轮询它,或让前台命令有办法活过自己的 deadline 时,使用 `ctx.shell`。执行方法只有一个——`execute(spec)` 在准备完成后返回句柄——「前台」是调用方等待什么的属性,而不是 spawn 的属性。它是每个 shell 执行器与面向模型的 `bash`/`pwsh` 工具共同依赖的约定,因此基于它编写的代码可以运行在任意执行器实现之上。
|
|
29
29
|
|
|
30
30
|
### 前台命令
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
等待句柄的 `result()` 投影即可在前台执行命令。promise 在命令结束时 resolve:非零退出、执行器超时终止或调用方中止终止都是结果,绝不是 rejection。`result()` 只在基础设施失败时 reject,例如工作目录不可用或缺少 shell。结果携带退出码或信号、是超时还是中止截断了运行(首因归类),以及收集到的 stdout/stderr;流超出预算时还附带 spill 文件路径。
|
|
33
33
|
|
|
34
34
|
```text
|
|
35
|
-
const
|
|
35
|
+
const execution = await ctx.shell.execute(ctx.shell.resolve({ command: 'ls -la' }))
|
|
36
|
+
const result = await execution.result()
|
|
36
37
|
console.log(result.exitCode, result.stdout.text)
|
|
37
38
|
```
|
|
38
39
|
|
|
39
40
|
### 后台进程
|
|
40
41
|
|
|
41
|
-
|
|
42
|
+
以 `onExpiry: 'none'` 解析请求并保留句柄:不布置任何 deadline,进程一直跑到被 kill 或自行结束。用 `readOutput()` 增量读取输出——连续读取绝不会重复交付,有损读取会指向完整流的 spill 文件。用 `kill()` 终止由提供方管理的进程范围(直接命令结束后返回 `false`),并等待 `done` 完成直接命令结算。job id、所有权、轮询与通知属于通用 `ctx.jobs` 运行时,工具层会把句柄注册进去。`ShellProcess.observed` 在同一份捕获流上暴露非消费的偏移读取器——供独立于消费游标的观察者使用,例如任务注册表的拉取源——包括被拒绝的 spawn 留在 stderr 上的 `spawn failed: …` 提示。
|
|
43
|
+
|
|
44
|
+
### deadline 与有界等待
|
|
45
|
+
|
|
46
|
+
deadline 包含异步准备耗时。进程启动前到期会返回已结算的句柄,其结果为 `timedOut: true`,输出为空。取消或准备失败会在发布句柄前拒绝 `execute`;迟到的准备结果不会启动进程。
|
|
47
|
+
|
|
48
|
+
seam 只有两种到期策略,没有任何移交协议。`'kill'` 在 deadline 停下命令并把结果归类为 `timedOut`;`'none'` 不设 deadline,只有调用方的信号和 `kill()` 能停下命令。只想等一段时间的调用方以 `'none'` 运行命令并自己限定等待时长:调用方停止等待后句柄依然有效,那一刻没有任何东西易手。`bash`/`pwsh` 工具正是这样做的——组合中有 job registry 时,每条命令一启动就登记到 `ctx.jobs` 并等待该 job,所以超时后仍在运行的前台命令只是继续作为它本来就是的那个 job 运行。
|
|
42
49
|
|
|
43
50
|
### 请求与已解析 spec
|
|
44
51
|
|
|
45
|
-
每次执行都从带可选字段的 `ShellExecRequest` 开始;执行器的 `resolve()` 在任何东西运行之前,把它变成默认值与上限都已显式填好的 `ShellExecSpec`。这一请求/spec 拆分正是仓库在包边界显式解析的模板:调用方绝不依赖 `
|
|
52
|
+
每次执行都从带可选字段的 `ShellExecRequest` 开始;执行器的 `resolve()` 在任何东西运行之前,把它变成默认值与上限都已显式填好的 `ShellExecSpec`。这一请求/spec 拆分正是仓库在包边界显式解析的模板:调用方绝不依赖 `execute` 内部隐藏的默认值。`resolve()` 从执行器配置与请求填充工作目录、超时与到期策略(默认 `'kill'`)、对每次调用的覆盖值设上限,并按原样携带可选输入——`stdin`、普通 `env` 与受信任的 `DSH_*` 快照。
|
|
46
53
|
|
|
47
54
|
### 选择并组合一个执行器
|
|
48
55
|
|
|
@@ -73,15 +80,15 @@ seam 本身不是执行器:每个组合只挂载一个提供方,工具即可
|
|
|
73
80
|
|
|
74
81
|
本包是标准能力 seam 中的一个角色:命名执行器约定的 Service Definition,Service Provider 与 Consumer 各自拆分,使每个角色都能独立演进(见[能力 seam 笔记](../../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.zh.md))。两项决策锚定了该约定:
|
|
75
82
|
|
|
76
|
-
- **边界处的显式解析。** `resolve(request)` 是应用默认值与上限的唯一位置;`
|
|
77
|
-
-
|
|
83
|
+
- **边界处的显式解析。** `resolve(request)` 是应用默认值与上限的唯一位置;`execute` 只接受已解析的 spec,绝不再次默认化,因此实现内部不会藏有隐藏的兜底值。
|
|
84
|
+
- **一次执行,多个投影。** `execute` 在准备完成后返回句柄;前台结果与后台游标读取都是同一个已 spawn 进程上的投影,前台/后台是调用方的选择,绝不是第二条 spawn 路径。句柄不带 id 或所有者;job 身份、所有权与生命周期属于通用 `ctx.jobs` 运行时,使执行器与会话保持独立。
|
|
78
85
|
|
|
79
86
|
### 源码地图
|
|
80
87
|
|
|
81
88
|
| 文件 | 职责 |
|
|
82
89
|
|---|---|
|
|
83
90
|
| [`src/index.ts`](src/index.ts) | 插件入口:抽象 `ShellExecutor` 服务与共享设置命名空间 |
|
|
84
|
-
| [`src/types.ts`](src/types.ts) | 请求/spec 词汇、`ShellRunResult
|
|
91
|
+
| [`src/types.ts`](src/types.ts) | 请求/spec 词汇、`ShellExecution`、`ShellRunResult` 与沙箱事实 |
|
|
85
92
|
| [`src/render.ts`](src/render.ts) | `parseExitStatus`:shell 工具共享的退出状态标记约定 |
|
|
86
93
|
| — | 不发布运行时不变式伴生入口;该无状态 Service Definition 负责请求/结果类型,执行器与策略负责观察。 |
|
|
87
94
|
|
|
@@ -91,7 +98,7 @@ seam 本身不是执行器:每个组合只挂载一个提供方,工具即可
|
|
|
91
98
|
|
|
92
99
|
### 后台生命周期与归属
|
|
93
100
|
|
|
94
|
-
|
|
101
|
+
已 spawn 的进程属于 subprocess 服务而非执行器:它能在仅重载执行器后存活,并在组合拆解时被终止并 join。实现必须遵守 seam 的语义——`result()` 只在基础设施失败时 reject;句柄在准备完成后发布且其 `done` 绝不 reject(无论同步还是异步的 provider rejection 都把句柄结算为 `killed`、把不声明阶段的提示写入 stderr,同时 `result()` 以同一失败 reject;活句柄在本次执行自己的 `kill()` 或 abort 之后才到来的 rejection 则结算为其终态);`readOutput` 是消费式的,有损读取会报告 spill 文件。
|
|
95
102
|
|
|
96
103
|
</details>
|
|
97
104
|
|
package/lib/index.js
CHANGED
|
@@ -53,34 +53,32 @@ function parseExitStatus(text) {
|
|
|
53
53
|
* @module @deepseek-ai/dsh-shell
|
|
54
54
|
*/
|
|
55
55
|
/**
|
|
56
|
-
* Settings namespace of this capability, owned here rather than by either
|
|
57
|
-
* executor family because it names the capability, not an implementation: a
|
|
58
|
-
* host composes exactly one provider of `ctx.shell` (the win32 layer swaps the
|
|
59
|
-
* POSIX rows for the pwsh ones, and mounting both fails loud on a duplicate
|
|
60
|
-
* service registration), so the providers share one namespace without ever
|
|
61
|
-
* registering it twice, and a settings document carried between platforms
|
|
62
|
-
* keeps resolving on both.
|
|
63
|
-
*/
|
|
64
|
-
const SHELL_SETTINGS_NAMESPACE = "shell";
|
|
65
|
-
/**
|
|
66
56
|
* Abstract bash execution service. Subclass, implement the abstract methods,
|
|
67
57
|
* and load the subclass as a plugin — it registers as `ctx.shell` (one
|
|
68
58
|
* implementation per context; loading a second throws, which is cordis'
|
|
69
59
|
* standard duplicate-service behavior).
|
|
70
60
|
*
|
|
61
|
+
* {@link execute} resolves with the process handle after preparation. "Foreground" is a property of what the caller awaits, not
|
|
62
|
+
* of the spawn — a caller that awaits {@link ShellExecution.result} ran the
|
|
63
|
+
* command in the foreground; one that keeps the handle ran it in the
|
|
64
|
+
* background. A caller that waits only for a while runs the command under
|
|
65
|
+
* `onExpiry: 'none'` and bounds its own wait; the handle stays valid after
|
|
66
|
+
* the caller stops waiting.
|
|
67
|
+
*
|
|
71
68
|
* Implementations must honor these semantics:
|
|
72
|
-
* - {@link
|
|
73
|
-
* timeout kills, and abort kills resolve with a
|
|
74
|
-
* -
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
69
|
+
* - {@link ShellExecution.result} rejects only for infrastructure failures.
|
|
70
|
+
* Nonzero exits, timeout kills, and abort kills resolve with a descriptive
|
|
71
|
+
* result: first-cause `timedOut`/`aborted`, the spec's `timeoutMs` echoed.
|
|
72
|
+
* - The handle is published after preparation. `done` settles at process close
|
|
73
|
+
* and never rejects; spawn failures settle as `killed` with the error on the read
|
|
74
|
+
* path, while `result()` carries the same failure as its rejection.
|
|
75
|
+
* - `onExpiry: 'none'` arms no deadline; `'kill'` kills at expiry. Expiry
|
|
76
|
+
* during preparation returns a settled timed-out handle without output.
|
|
78
77
|
* - {@link ShellProcess.readOutput} is incremental: consecutive reads never
|
|
79
78
|
* repeat output. Lossy reads report truncation and available spill files.
|
|
80
|
-
* - A still-running
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
* an executor-only reload.
|
|
79
|
+
* - A still-running process is stopped and awaited when its owning
|
|
80
|
+
* composition tears down. With the subprocess seam that boundary is
|
|
81
|
+
* `ctx.subprocess` disposal, so a process survives an executor-only reload.
|
|
84
82
|
*/
|
|
85
83
|
var ShellExecutor = class extends Service {
|
|
86
84
|
constructor(ctx) {
|
|
@@ -94,4 +92,4 @@ var ShellExecutor = class extends Service {
|
|
|
94
92
|
get sandboxMode() {}
|
|
95
93
|
};
|
|
96
94
|
//#endregion
|
|
97
|
-
export { DSH_ENV_PREFIX,
|
|
95
|
+
export { DSH_ENV_PREFIX, ShellExecutor, ShellExecutor as default, parseExitStatus };
|
package/lib/types/index.d.ts
CHANGED
|
@@ -6,19 +6,9 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { Context, Service } from '@deepseek-ai/cordis';
|
|
8
8
|
import type { SandboxMode } from '@deepseek-ai/dsh-sandbox';
|
|
9
|
-
import type { ShellExecRequest, ShellExecSpec,
|
|
10
|
-
/**
|
|
11
|
-
* Settings namespace of this capability, owned here rather than by either
|
|
12
|
-
* executor family because it names the capability, not an implementation: a
|
|
13
|
-
* host composes exactly one provider of `ctx.shell` (the win32 layer swaps the
|
|
14
|
-
* POSIX rows for the pwsh ones, and mounting both fails loud on a duplicate
|
|
15
|
-
* service registration), so the providers share one namespace without ever
|
|
16
|
-
* registering it twice, and a settings document carried between platforms
|
|
17
|
-
* keeps resolving on both.
|
|
18
|
-
*/
|
|
19
|
-
export declare const SHELL_SETTINGS_NAMESPACE = "shell";
|
|
9
|
+
import type { ShellExecRequest, ShellExecSpec, ShellExecution } from './types.ts';
|
|
20
10
|
export { DSH_ENV_PREFIX } from './types.ts';
|
|
21
|
-
export type { ShellExecRequest, ShellExecSpec, ShellProcess, ShellProcessRead, ShellProcessStatus, ShellRunResult, ShellSandboxInfo, CollectedOutput, DshEnvironment, DshEnvironmentKey, } from './types.ts';
|
|
11
|
+
export type { ShellExecRequest, ShellExecSpec, ShellExecution, ShellExpiryPolicy, ShellProcess, ShellProcessRead, ShellProcessStatus, ShellRunResult, ShellSandboxInfo, CollectedOutput, DshEnvironment, DshEnvironmentKey, } from './types.ts';
|
|
22
12
|
export { parseExitStatus } from './render.ts';
|
|
23
13
|
export type { ParsedExitStatus } from './render.ts';
|
|
24
14
|
declare module '@deepseek-ai/cordis' {
|
|
@@ -32,19 +22,27 @@ declare module '@deepseek-ai/cordis' {
|
|
|
32
22
|
* implementation per context; loading a second throws, which is cordis'
|
|
33
23
|
* standard duplicate-service behavior).
|
|
34
24
|
*
|
|
25
|
+
* {@link execute} resolves with the process handle after preparation. "Foreground" is a property of what the caller awaits, not
|
|
26
|
+
* of the spawn — a caller that awaits {@link ShellExecution.result} ran the
|
|
27
|
+
* command in the foreground; one that keeps the handle ran it in the
|
|
28
|
+
* background. A caller that waits only for a while runs the command under
|
|
29
|
+
* `onExpiry: 'none'` and bounds its own wait; the handle stays valid after
|
|
30
|
+
* the caller stops waiting.
|
|
31
|
+
*
|
|
35
32
|
* Implementations must honor these semantics:
|
|
36
|
-
* - {@link
|
|
37
|
-
* timeout kills, and abort kills resolve with a
|
|
38
|
-
* -
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
33
|
+
* - {@link ShellExecution.result} rejects only for infrastructure failures.
|
|
34
|
+
* Nonzero exits, timeout kills, and abort kills resolve with a descriptive
|
|
35
|
+
* result: first-cause `timedOut`/`aborted`, the spec's `timeoutMs` echoed.
|
|
36
|
+
* - The handle is published after preparation. `done` settles at process close
|
|
37
|
+
* and never rejects; spawn failures settle as `killed` with the error on the read
|
|
38
|
+
* path, while `result()` carries the same failure as its rejection.
|
|
39
|
+
* - `onExpiry: 'none'` arms no deadline; `'kill'` kills at expiry. Expiry
|
|
40
|
+
* during preparation returns a settled timed-out handle without output.
|
|
42
41
|
* - {@link ShellProcess.readOutput} is incremental: consecutive reads never
|
|
43
42
|
* repeat output. Lossy reads report truncation and available spill files.
|
|
44
|
-
* - A still-running
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
* an executor-only reload.
|
|
43
|
+
* - A still-running process is stopped and awaited when its owning
|
|
44
|
+
* composition tears down. With the subprocess seam that boundary is
|
|
45
|
+
* `ctx.subprocess` disposal, so a process survives an executor-only reload.
|
|
48
46
|
*/
|
|
49
47
|
export declare abstract class ShellExecutor extends Service {
|
|
50
48
|
constructor(ctx: Context);
|
|
@@ -58,23 +56,17 @@ export declare abstract class ShellExecutor extends Service {
|
|
|
58
56
|
* Apply implementation-owned defaults and caps to a request before execution.
|
|
59
57
|
* @param request - the caller's request; omitted fields get this
|
|
60
58
|
* implementation's defaults, capped fields are clamped.
|
|
61
|
-
* @returns the fully-specified spec to hand to {@link
|
|
59
|
+
* @returns the fully-specified spec to hand to {@link execute}.
|
|
62
60
|
*/
|
|
63
61
|
abstract resolve(request: ShellExecRequest): ShellExecSpec;
|
|
64
62
|
/**
|
|
65
|
-
*
|
|
63
|
+
* Prepare and spawn the command under its resolved deadline.
|
|
66
64
|
* @param spec - a resolved spec from {@link resolve}, never a raw request.
|
|
67
|
-
* @returns the
|
|
68
|
-
*
|
|
65
|
+
* @returns the prepared handle, including its result projection;
|
|
66
|
+
* preparation timeout yields an already-settled handle with no output.
|
|
69
67
|
* @throws on preparation failure or caller cancellation before process publication.
|
|
70
68
|
*/
|
|
71
|
-
abstract
|
|
72
|
-
/**
|
|
73
|
-
* Prepare a background process asynchronously and publish its live handle.
|
|
74
|
-
* @param spec - a resolved spec from {@link resolve}, never a raw request.
|
|
75
|
-
* @returns the live process handle after preparation; cancellation or setup failure rejects.
|
|
76
|
-
*/
|
|
77
|
-
abstract start(spec: ShellExecSpec): Promise<ShellProcess>;
|
|
69
|
+
abstract execute(spec: ShellExecSpec): Promise<ShellExecution>;
|
|
78
70
|
}
|
|
79
71
|
export default ShellExecutor;
|
|
80
72
|
//# sourceMappingURL=index.d.ts.map
|
package/lib/types/types.d.ts
CHANGED
|
@@ -7,9 +7,22 @@
|
|
|
7
7
|
* @module dsh-shell/types
|
|
8
8
|
*/
|
|
9
9
|
import type { SandboxEnforcement, SandboxExecutionPolicy, SandboxMode } from '@deepseek-ai/dsh-sandbox';
|
|
10
|
-
import type { CollectedOutput, DshEnvironment } from '@deepseek-ai/dsh-subprocess';
|
|
10
|
+
import type { CollectedOutput, DshEnvironment, SubprocessOutputReader } from '@deepseek-ai/dsh-subprocess';
|
|
11
11
|
export { DSH_ENV_PREFIX } from '@deepseek-ai/dsh-subprocess';
|
|
12
|
-
export type { CollectedOutput, DshEnvironment, DshEnvironmentKey } from '@deepseek-ai/dsh-subprocess';
|
|
12
|
+
export type { CollectedOutput, DshEnvironment, DshEnvironmentKey, SubprocessOutputRead, SubprocessOutputReader } from '@deepseek-ai/dsh-subprocess';
|
|
13
|
+
/**
|
|
14
|
+
* Non-consuming offset readers over a background process's captured streams,
|
|
15
|
+
* for observers independent of the consuming {@link ShellProcess.readOutput}
|
|
16
|
+
* cursor. Every background process exposes both streams; a spawn that
|
|
17
|
+
* rejected produced no process output, so its stderr reader serves the
|
|
18
|
+
* `spawn failed: …` note as the whole stream.
|
|
19
|
+
*/
|
|
20
|
+
export interface ShellObservedStreams {
|
|
21
|
+
/** Offset reader over captured stdout. */
|
|
22
|
+
stdout: SubprocessOutputReader;
|
|
23
|
+
/** Offset reader over captured stderr (the spawn-failure note after a rejected spawn). */
|
|
24
|
+
stderr: SubprocessOutputReader;
|
|
25
|
+
}
|
|
13
26
|
/**
|
|
14
27
|
* Sandbox facts for one run, present iff a sandboxing executor handled it.
|
|
15
28
|
* Facts are reported independently of process exit status so callers can
|
|
@@ -25,6 +38,14 @@ export interface ShellSandboxInfo {
|
|
|
25
38
|
/** Whether the sandbox runner failed before the command could run. */
|
|
26
39
|
runnerFailed?: boolean;
|
|
27
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* What the executor does when the deadline expires: `kill` stops the command
|
|
43
|
+
* and classifies the result `timedOut` (the default), and `none` arms no
|
|
44
|
+
* deadline at all, leaving the caller's signal and {@link ShellProcess.kill}
|
|
45
|
+
* as the only ways to stop the command. A consumer that wants to keep waiting
|
|
46
|
+
* only for a while runs the command under `none` and bounds its own wait.
|
|
47
|
+
*/
|
|
48
|
+
export type ShellExpiryPolicy = 'kill' | 'none';
|
|
28
49
|
/**
|
|
29
50
|
* A caller's execution REQUEST: `workdir` and `timeoutMs` are optional and
|
|
30
51
|
* filled by {@link ShellExecutor.resolve} from the implementation's config.
|
|
@@ -37,6 +58,8 @@ export interface ShellExecRequest {
|
|
|
37
58
|
workdir?: string | undefined;
|
|
38
59
|
/** Timeout override in milliseconds (implementations cap it). */
|
|
39
60
|
timeoutMs?: number | undefined;
|
|
61
|
+
/** Deadline policy at `timeoutMs` expiry (default `'kill'`). */
|
|
62
|
+
onExpiry?: ShellExpiryPolicy | undefined;
|
|
40
63
|
/**
|
|
41
64
|
* Foreground stdout capture budget in bytes. Absent uses the executor's
|
|
42
65
|
* default output cap. Trusted in-process consumers use this when they must
|
|
@@ -44,7 +67,7 @@ export interface ShellExecRequest {
|
|
|
44
67
|
* tool does not expose it as a parameter.
|
|
45
68
|
*/
|
|
46
69
|
stdoutMaxBytes?: number | undefined;
|
|
47
|
-
/** Abort signal — implementations kill the command when it fires. */
|
|
70
|
+
/** Abort signal — implementations kill the command when it fires, and treat a signal that is already aborted as fired. */
|
|
48
71
|
signal?: AbortSignal | undefined;
|
|
49
72
|
/**
|
|
50
73
|
* Bytes to write to the command's stdin, then close it. Absent leaves stdin
|
|
@@ -75,19 +98,21 @@ export interface ShellExecRequest {
|
|
|
75
98
|
}
|
|
76
99
|
/**
|
|
77
100
|
* A resolved execution spec. {@link ShellExecutor.resolve} fills and caps the
|
|
78
|
-
* required fields;
|
|
79
|
-
*
|
|
101
|
+
* required fields; under `onExpiry: 'none'` the resolved `timeoutMs` arms no
|
|
102
|
+
* timer and is only echoed into {@link ShellRunResult.timeoutMs}.
|
|
80
103
|
*/
|
|
81
104
|
export interface ShellExecSpec {
|
|
82
105
|
command: string;
|
|
83
106
|
workdir: string;
|
|
84
107
|
timeoutMs: number;
|
|
108
|
+
/** Deadline policy at `timeoutMs` expiry ({@link ShellExecutor.resolve} defaults it to `'kill'`). */
|
|
109
|
+
onExpiry: ShellExpiryPolicy;
|
|
85
110
|
/**
|
|
86
|
-
* Resolved
|
|
87
|
-
* stdout;
|
|
111
|
+
* Resolved stdout capture budget in bytes, applied to every execution's
|
|
112
|
+
* stdout; stderr keeps the executor's own output cap.
|
|
88
113
|
*/
|
|
89
114
|
stdoutMaxBytes: number;
|
|
90
|
-
/** Abort signal — implementations kill the command when it fires. */
|
|
115
|
+
/** Abort signal — implementations kill the command when it fires, and treat a signal that is already aborted as fired. */
|
|
91
116
|
signal?: AbortSignal | undefined;
|
|
92
117
|
/** Bytes to write to stdin before closing it; absent means no stdin. */
|
|
93
118
|
stdin?: string | undefined;
|
|
@@ -169,10 +194,34 @@ export interface ShellProcess {
|
|
|
169
194
|
* full-stream spill files when available.
|
|
170
195
|
*/
|
|
171
196
|
readOutput(): ShellProcessRead;
|
|
197
|
+
/**
|
|
198
|
+
* Non-consuming offset readers over the same captured streams the consuming
|
|
199
|
+
* {@link readOutput} cursor drains, including the provider-failure note a
|
|
200
|
+
* rejected spawn leaves on stderr. Independent observers read here at their
|
|
201
|
+
* own offsets without stealing bytes from `readOutput`.
|
|
202
|
+
*/
|
|
203
|
+
observed: ShellObservedStreams;
|
|
172
204
|
/**
|
|
173
205
|
* Terminate the provider-managed range. Returns false when it had already finished
|
|
174
206
|
* (no-op); idempotent.
|
|
175
207
|
*/
|
|
176
208
|
kill(): boolean;
|
|
177
209
|
}
|
|
210
|
+
/**
|
|
211
|
+
* The one execution handle {@link ShellExecutor.execute} returns: the live
|
|
212
|
+
* {@link ShellProcess} itself plus the foreground projection `result()`.
|
|
213
|
+
*/
|
|
214
|
+
export interface ShellExecution extends ShellProcess {
|
|
215
|
+
/**
|
|
216
|
+
* Foreground projection: settles when the process closes, with split
|
|
217
|
+
* collected streams and first-cause `timedOut`/`aborted` classification.
|
|
218
|
+
* Rejects only for infrastructure failures (a spawn that never produced a
|
|
219
|
+
* process); nonzero exits, timeout kills, and abort kills resolve with a
|
|
220
|
+
* descriptive result. Created on demand and memoized — callers that never
|
|
221
|
+
* invoke it (background producers) never observe the rejection either; the
|
|
222
|
+
* handle's `done`/read path carries the spawn-failure story for them.
|
|
223
|
+
* @returns the settled foreground result for this execution.
|
|
224
|
+
*/
|
|
225
|
+
result(): Promise<ShellRunResult>;
|
|
226
|
+
}
|
|
178
227
|
//# sourceMappingURL=types.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepseek-ai/dsh-shell",
|
|
3
3
|
"description": "Abstract bash executor seam (ctx.shell) for the DeepSeek Harness",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.7-alpha.1",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -27,15 +27,13 @@
|
|
|
27
27
|
],
|
|
28
28
|
"license": "MIT",
|
|
29
29
|
"peerDependencies": {
|
|
30
|
-
"@deepseek-ai/dsh-subprocess": "^0.1.
|
|
31
|
-
"@deepseek-ai/dsh-sandbox": "^0.1.
|
|
32
|
-
"@deepseek-ai/cordis": "^4.0.
|
|
33
|
-
"@deepseek-ai/dsh-settings": "^0.1.6-alpha.1"
|
|
30
|
+
"@deepseek-ai/dsh-subprocess": "^0.1.7-alpha.1",
|
|
31
|
+
"@deepseek-ai/dsh-sandbox": "^0.1.7-alpha.1",
|
|
32
|
+
"@deepseek-ai/cordis": "^4.0.3"
|
|
34
33
|
},
|
|
35
34
|
"devDependencies": {
|
|
36
|
-
"@deepseek-ai/dsh-subprocess": "^0.1.
|
|
37
|
-
"@deepseek-ai/
|
|
38
|
-
"@deepseek-ai/
|
|
39
|
-
"@deepseek-ai/dsh-settings": "^0.1.6-alpha.1"
|
|
35
|
+
"@deepseek-ai/dsh-subprocess": "^0.1.7-alpha.1",
|
|
36
|
+
"@deepseek-ai/dsh-sandbox": "^0.1.7-alpha.1",
|
|
37
|
+
"@deepseek-ai/cordis": "^4.0.3"
|
|
40
38
|
}
|
|
41
39
|
}
|