@deepseek-ai/dsh-bash-local 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 +2 -2
- package/README.md +3 -1
- package/README.zh.md +11 -9
- package/lib/index.js +55 -14
- package/lib/types/index.d.ts +7 -4
- package/package.json +11 -11
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/bash-local/README.md
|
|
5
|
-
README.md:
|
|
6
|
-
README.zh.md:
|
|
5
|
+
README.md: 2cd69993b454a462bcbfa43175ff7dc7dba72e01
|
|
6
|
+
README.zh.md: 81436511992d93a2bb81c4f3e242dd2046ec11e8
|
package/README.md
CHANGED
|
@@ -61,7 +61,7 @@ if (result.timedOut) console.log('timed out after', result.timeoutMs)
|
|
|
61
61
|
|
|
62
62
|
### Background processes
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
Await `start` to run a command in the background; it resolves with the prepared process handle and no execution timeout applies. Cancellation or preparation failure rejects before a handle is published. `readOutput()` merges the stream deltas into one consuming read, marking stderr under a `[stderr]` section; `kill()` terminates the provider-managed range; `done` settles when the direct command closes and never rejects. Job ids, ownership, polling, and notices belong to the generic `ctx.jobs` runtime, which the tool layer registers the handle with.
|
|
65
65
|
|
|
66
66
|
<a id="adjusting-budgets-at-runtime"></a>
|
|
67
67
|
### Adjusting budgets at runtime
|
|
@@ -95,6 +95,8 @@ The executor is a Service Provider for the `ctx.shell` seam built on the subproc
|
|
|
95
95
|
|
|
96
96
|
A call runs through three steps: `resolve()` fills `workdir`/`timeoutMs`/`stdoutMaxBytes` from config (capping per-call overrides); `run` fuses the config-clamped timeout with the caller's abort signal into one deadline and spawns `['bash', '-c', command]` through `ctx.subprocess` with explicit byte caps and the `graceMs`; the settled subprocess outcome is classified — only the executor's own timeout reports `timedOut`, an upstream cancel reports `aborted`, a self-signaled command reports neither — and projected into a `ShellRunResult` with collected output.
|
|
97
97
|
|
|
98
|
+
The foreground deadline starts before argv preparation and retains the same signal and remaining budget through execution. Preparation timeout returns empty output, `timedOut: true`, and null `exitCode` and `signal`; caller cancellation before process publication still rejects. Late preparation success or failure cannot trigger a spawn.
|
|
99
|
+
|
|
98
100
|
### Invariants and ownership
|
|
99
101
|
|
|
100
102
|
- The `graceMs` budget must be positive, finite, and no greater than `MAX_TIMER_DELAY_MS` so Node can represent it with one timer; invalid values are refused where they are written.
|
package/README.zh.md
CHANGED
|
@@ -25,7 +25,7 @@ kind: "package-reference"
|
|
|
25
25
|
<a id="use-this-package"></a>
|
|
26
26
|
## 使用本包
|
|
27
27
|
|
|
28
|
-
当组合需要在 POSIX 上执行 Bash 命令且不需要隔离时,挂载此执行器。它注册为 `ctx.shell`,面向模型的 `bash` 工具会立即基于它工作:agent
|
|
28
|
+
当组合需要在 POSIX 上执行 Bash 命令且不需要隔离时,挂载此执行器。它注册为 `ctx.shell`,面向模型的 `bash` 工具会立即基于它工作:agent(智能体)调用工具,命令即以全新 `bash -c` 进程按下面的预算运行。
|
|
29
29
|
|
|
30
30
|
### 最小配置
|
|
31
31
|
|
|
@@ -61,7 +61,7 @@ if (result.timedOut) console.log('timed out after', result.timeoutMs)
|
|
|
61
61
|
|
|
62
62
|
### 后台进程
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
等待 `start` 即可在后台运行命令;它完成准备后返回进程句柄,且不应用执行超时。取消或准备失败会在发布句柄前拒绝调用。`readOutput()` 把流增量合并为一次消费式读取,并在 `[stderr]` 分段下标记 stderr;`kill()` 终止提供方管理的 range;`done` 在直接命令关闭时结算且绝不 reject。job id、所有权、轮询与通知属于通用 `ctx.jobs` 运行时,工具层会把句柄注册进去。
|
|
65
65
|
|
|
66
66
|
<a id="adjusting-budgets-at-runtime"></a>
|
|
67
67
|
### 运行时调整预算
|
|
@@ -87,7 +87,7 @@ if (result.timedOut) console.log('timed out after', result.timeoutMs)
|
|
|
87
87
|
| 文件 | 职责 |
|
|
88
88
|
|---|---|
|
|
89
89
|
| [`src/index.ts`](src/index.ts) | 插件入口:`LocalBashExecutor`、`Config`、设置段接线 |
|
|
90
|
-
| — |
|
|
90
|
+
| — | 不发布运行时不变式伴生入口;除由所属 seam 强制执行的约定外,本包不公开独立的事件序列或可变数据关系。 |
|
|
91
91
|
| `tests/executor.spec.ts` | 已演练的行为:预算、分类、后台句柄、归属 |
|
|
92
92
|
| `tests/settings.spec.ts` | 设置段叠加在组合条目之上 |
|
|
93
93
|
|
|
@@ -95,11 +95,13 @@ if (result.timedOut) console.log('timed out after', result.timeoutMs)
|
|
|
95
95
|
|
|
96
96
|
一次调用分三步:`resolve()` 从配置填充 `workdir`/`timeoutMs`/`stdoutMaxBytes`(并限制每次调用的覆盖值);`run` 把按配置钳位的超时与调用方的中止信号融合为一个 deadline,再以显式字节上限与 `graceMs` 通过 `ctx.subprocess` spawn `['bash', '-c', command]`;结算的 subprocess 结果被分类——只有执行器自身的超时报告 `timedOut`,上游取消报告 `aborted`,自身因信号终止的命令两者皆不报告——并投影为带收集输出的 `ShellRunResult`。
|
|
97
97
|
|
|
98
|
+
前台 deadline 从 argv 准备开始,并在准备与执行之间保持同一信号和剩余预算。准备阶段超时返回空输出、`timedOut: true`,且 `exitCode` 和 `signal` 均为 `null`;调用方在发布进程前取消仍会拒绝调用。准备晚到的成功或失败不会触发 spawn。
|
|
99
|
+
|
|
98
100
|
### 不变式与归属
|
|
99
101
|
|
|
100
102
|
- `graceMs` 预算必须为正有限值且不大于 `MAX_TIMER_DELAY_MS`,这样 Node 就能用一个定时器表示它;无效值在写入处被拒绝。
|
|
101
103
|
- 环境分层固定:先是终端覆盖值,然后是调用方的 `env`,最后才是受信任的 `dshEnv` 快照;subprocess 服务独立清除环境中的凭据与继承的 `DSH_*` 名称。
|
|
102
|
-
- 后台进程属于 subprocess 服务:它能在仅重载执行器后存活,并在服务 dispose
|
|
104
|
+
- 后台进程属于 subprocess 服务:它能在仅重载执行器后存活,并在服务 dispose 时被终止且等待退出。
|
|
103
105
|
|
|
104
106
|
</details>
|
|
105
107
|
|
|
@@ -108,10 +110,10 @@ if (result.timedOut) console.log('timed out after', result.timeoutMs)
|
|
|
108
110
|
<a id="further-exploration"></a>
|
|
109
111
|
## 进一步探索
|
|
110
112
|
|
|
111
|
-
|
|
113
|
+
当执行器约定不够用时阅读以下页面。这些页面从 seam 讲到提供隔离的同级包及其底层机制。
|
|
112
114
|
|
|
113
115
|
- [shell seam](../shell/README.zh.md) —— 本提供方实现的执行器约定,包括请求/spec 拆分。
|
|
114
|
-
- [bash-sandbox](../bash-sandbox/README.zh.md) ——
|
|
116
|
+
- [bash-sandbox](../bash-sandbox/README.zh.md) —— 需要沙箱能力时,应改为组合此隔离执行器。
|
|
115
117
|
- [tool-bash](../tool-bash/README.zh.md) —— 基于本执行器的面向模型 `bash` 工具。
|
|
116
118
|
- [Bash 执行器子系统](../../../docs/subsystems/shell.zh.md) —— 请求/spec 词汇、结果与完整的服务约定。
|
|
117
119
|
- [subprocess-local](../../subprocess/subprocess-local/README.zh.md) —— 本执行器背后的 managed-range 机制。
|
|
@@ -134,10 +136,10 @@ if (result.timedOut) console.log('timed out after', result.timeoutMs)
|
|
|
134
136
|
|
|
135
137
|
这些限制说明本执行器何时不合适。它们是当前包约束,不是路线图。
|
|
136
138
|
|
|
137
|
-
- **自身不提供隔离**——命令以 harness 进程的权限运行;需要隔离的部署组合 `dsh-bash-sandbox`,每次调用的 allow/deny/ask 策略则属于工具的 `pre-execute` waterfall
|
|
139
|
+
- **自身不提供隔离**——命令以 harness 进程的权限运行;需要隔离的部署组合 `dsh-bash-sandbox`,每次调用的 allow/deny/ask 策略则属于工具的 `pre-execute` waterfall(瀑布式事件)。
|
|
138
140
|
- **没有持久 shell 或 PTY**——每次调用都启动全新的非登录 `bash -c`;仅持久化 cwd 与交互式终端会话均继续延期,直到真实工作流需要它们。
|
|
139
141
|
- **仅支持 POSIX**——`bash` 二进制已硬编码,底层服务的进程组语义也是 POSIX 的;不支持 Windows。
|
|
140
|
-
-
|
|
142
|
+
- **后台提供方失败提示只交付一次**——`SubprocessHandle.done` 可能在目标命令开始执行前或后被拒绝,因此执行器把不声明失败阶段的 `subprocess failed before reporting an outcome: …` 注入恰好一个 `readOutput()` 增量;丢弃了该增量的读取方无法再恢复它。
|
|
141
143
|
|
|
142
144
|
<a id="dev-note"></a>
|
|
143
145
|
### 开发备注
|
|
@@ -145,6 +147,6 @@ if (result.timedOut) console.log('timed out after', result.timeoutMs)
|
|
|
145
147
|
<details>
|
|
146
148
|
<summary>维护者的工作上下文——点击展开</summary>
|
|
147
149
|
|
|
148
|
-
|
|
150
|
+
无。
|
|
149
151
|
|
|
150
152
|
</details>
|
package/lib/index.js
CHANGED
|
@@ -212,21 +212,21 @@ var LocalBashExecutor = class LocalBashExecutor extends ShellExecutor {
|
|
|
212
212
|
};
|
|
213
213
|
}
|
|
214
214
|
async run(spec) {
|
|
215
|
-
return this.runArgv(spec, [
|
|
215
|
+
return (await this.runArgv(spec, [
|
|
216
216
|
"bash",
|
|
217
217
|
"-c",
|
|
218
218
|
spec.command
|
|
219
|
-
]);
|
|
219
|
+
])).result;
|
|
220
220
|
}
|
|
221
221
|
/**
|
|
222
222
|
* Run an explicit argv with the foreground lifecycle, environment, output,
|
|
223
223
|
* timeout, and cancellation semantics of this executor. Subclasses use this
|
|
224
224
|
* after replacing the public command's shell argv at an execution boundary.
|
|
225
225
|
* @param spec - resolved execution settings and caller-owned command metadata.
|
|
226
|
-
* @param
|
|
227
|
-
* @returns the
|
|
226
|
+
* @param argvOrPrepare - exact argv, or preparation cancelled by the same deadline as execution.
|
|
227
|
+
* @returns the foreground result and whether argv reached the subprocess provider.
|
|
228
228
|
*/
|
|
229
|
-
async runArgv(spec,
|
|
229
|
+
async runArgv(spec, argvOrPrepare) {
|
|
230
230
|
const env_1 = {
|
|
231
231
|
stack: [],
|
|
232
232
|
error: void 0,
|
|
@@ -234,18 +234,58 @@ var LocalBashExecutor = class LocalBashExecutor extends ShellExecutor {
|
|
|
234
234
|
};
|
|
235
235
|
try {
|
|
236
236
|
const d = __addDisposableResource(env_1, deadline(spec.signal, spec.timeoutMs, "BASH_TIMEOUT"), false);
|
|
237
|
+
let argv;
|
|
238
|
+
if (typeof argvOrPrepare === "function") {
|
|
239
|
+
const cancelled = Promise.withResolvers();
|
|
240
|
+
const abort = () => {
|
|
241
|
+
cancelled.reject(d.signal.reason);
|
|
242
|
+
};
|
|
243
|
+
d.signal.addEventListener("abort", abort, { once: true });
|
|
244
|
+
try {
|
|
245
|
+
argv = await Promise.race([Promise.resolve().then(() => {
|
|
246
|
+
d.signal.throwIfAborted();
|
|
247
|
+
return argvOrPrepare(d.signal);
|
|
248
|
+
}), cancelled.promise]);
|
|
249
|
+
d.signal.throwIfAborted();
|
|
250
|
+
} catch (error) {
|
|
251
|
+
if (timeoutOf(d.signal, "BASH_TIMEOUT") === void 0) throw error;
|
|
252
|
+
return {
|
|
253
|
+
spawnRequested: false,
|
|
254
|
+
result: {
|
|
255
|
+
exitCode: null,
|
|
256
|
+
signal: null,
|
|
257
|
+
timedOut: true,
|
|
258
|
+
aborted: false,
|
|
259
|
+
timeoutMs: spec.timeoutMs,
|
|
260
|
+
stdout: {
|
|
261
|
+
text: "",
|
|
262
|
+
truncated: false
|
|
263
|
+
},
|
|
264
|
+
stderr: {
|
|
265
|
+
text: "",
|
|
266
|
+
truncated: false
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
} finally {
|
|
271
|
+
d.signal.removeEventListener("abort", abort);
|
|
272
|
+
}
|
|
273
|
+
} else argv = argvOrPrepare;
|
|
237
274
|
const handle = this.ctx.subprocess.spawn(this.spawnSpec(spec, argv, spec.stdoutMaxBytes, d.signal));
|
|
238
275
|
const outcome = await handle.done;
|
|
239
276
|
const collected = LocalBashExecutor.collected(handle);
|
|
240
277
|
const timedOut = timeoutOf(d.signal, "BASH_TIMEOUT") !== void 0;
|
|
241
278
|
const aborted = d.signal.aborted && !timedOut;
|
|
242
279
|
return {
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
280
|
+
spawnRequested: true,
|
|
281
|
+
result: {
|
|
282
|
+
...outcome,
|
|
283
|
+
timedOut,
|
|
284
|
+
aborted,
|
|
285
|
+
timeoutMs: spec.timeoutMs,
|
|
286
|
+
stdout: finalOutput(collected.stdout),
|
|
287
|
+
stderr: finalOutput(collected.stderr)
|
|
288
|
+
}
|
|
249
289
|
};
|
|
250
290
|
} catch (e_1) {
|
|
251
291
|
env_1.error = e_1;
|
|
@@ -254,12 +294,12 @@ var LocalBashExecutor = class LocalBashExecutor extends ShellExecutor {
|
|
|
254
294
|
__disposeResources(env_1);
|
|
255
295
|
}
|
|
256
296
|
}
|
|
257
|
-
start(spec) {
|
|
258
|
-
return this.startArgv(spec, [
|
|
297
|
+
async start(spec) {
|
|
298
|
+
return Promise.resolve(this.startArgv(spec, [
|
|
259
299
|
"bash",
|
|
260
300
|
"-c",
|
|
261
301
|
spec.command
|
|
262
|
-
]);
|
|
302
|
+
]));
|
|
263
303
|
}
|
|
264
304
|
/**
|
|
265
305
|
* Start an explicit argv with the background lifecycle, environment, output,
|
|
@@ -271,6 +311,7 @@ var LocalBashExecutor = class LocalBashExecutor extends ShellExecutor {
|
|
|
271
311
|
* @returns the live background handle; provider rejection settles it as killed.
|
|
272
312
|
*/
|
|
273
313
|
startArgv(spec, argv) {
|
|
314
|
+
spec.signal?.throwIfAborted();
|
|
274
315
|
const running = this.ctx.subprocess.spawn(this.spawnSpec(spec, argv, this.config.maxOutputBytes, spec.signal));
|
|
275
316
|
const collected = LocalBashExecutor.collected(running);
|
|
276
317
|
let providerFailureNote;
|
package/lib/types/index.d.ts
CHANGED
|
@@ -84,11 +84,14 @@ export declare class LocalBashExecutor extends ShellExecutor {
|
|
|
84
84
|
* timeout, and cancellation semantics of this executor. Subclasses use this
|
|
85
85
|
* after replacing the public command's shell argv at an execution boundary.
|
|
86
86
|
* @param spec - resolved execution settings and caller-owned command metadata.
|
|
87
|
-
* @param
|
|
88
|
-
* @returns the
|
|
87
|
+
* @param argvOrPrepare - exact argv, or preparation cancelled by the same deadline as execution.
|
|
88
|
+
* @returns the foreground result and whether argv reached the subprocess provider.
|
|
89
89
|
*/
|
|
90
|
-
protected runArgv(spec: ShellExecSpec,
|
|
91
|
-
|
|
90
|
+
protected runArgv(spec: ShellExecSpec, argvOrPrepare: readonly string[] | ((signal: AbortSignal) => Promise<readonly string[]>)): Promise<{
|
|
91
|
+
result: ShellRunResult;
|
|
92
|
+
spawnRequested: boolean;
|
|
93
|
+
}>;
|
|
94
|
+
start(spec: ShellExecSpec): Promise<ShellProcess>;
|
|
92
95
|
/**
|
|
93
96
|
* Start an explicit argv with the background lifecycle, environment, output,
|
|
94
97
|
* cancellation, and managed-range ownership semantics of this executor.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepseek-ai/dsh-bash-local",
|
|
3
3
|
"description": "Local-subprocess implementation of the DeepSeek Harness bash executor seam",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.6-alpha.2",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -27,21 +27,21 @@
|
|
|
27
27
|
],
|
|
28
28
|
"license": "MIT",
|
|
29
29
|
"peerDependencies": {
|
|
30
|
-
"@deepseek-ai/dsh-shell": "^0.1.
|
|
31
|
-
"@deepseek-ai/dsh-subprocess": "^0.1.
|
|
32
|
-
"@deepseek-ai/dsh-timeout": "^0.1.
|
|
30
|
+
"@deepseek-ai/dsh-shell": "^0.1.6-alpha.2",
|
|
31
|
+
"@deepseek-ai/dsh-subprocess": "^0.1.6-alpha.2",
|
|
32
|
+
"@deepseek-ai/dsh-timeout": "^0.1.6-alpha.2",
|
|
33
33
|
"@deepseek-ai/cordis": "^4.0.2",
|
|
34
|
-
"@deepseek-ai/dsh-settings": "^0.1.
|
|
34
|
+
"@deepseek-ai/dsh-settings": "^0.1.6-alpha.2"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@deepseek-ai/schemastery": "^3.18.2"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
|
-
"@deepseek-ai/dsh-shell": "^0.1.
|
|
41
|
-
"@deepseek-ai/dsh-subprocess": "^0.1.
|
|
42
|
-
"@deepseek-ai/dsh-
|
|
43
|
-
"@deepseek-ai/dsh-
|
|
44
|
-
"@deepseek-ai/
|
|
45
|
-
"@deepseek-ai/
|
|
40
|
+
"@deepseek-ai/dsh-shell": "^0.1.6-alpha.2",
|
|
41
|
+
"@deepseek-ai/dsh-subprocess-local": "^0.1.6-alpha.2",
|
|
42
|
+
"@deepseek-ai/dsh-timeout": "^0.1.6-alpha.2",
|
|
43
|
+
"@deepseek-ai/dsh-subprocess": "^0.1.6-alpha.2",
|
|
44
|
+
"@deepseek-ai/cordis": "^4.0.2",
|
|
45
|
+
"@deepseek-ai/dsh-settings": "^0.1.6-alpha.2"
|
|
46
46
|
}
|
|
47
47
|
}
|