@banbolee/dsh-fish-shell 0.5.0 → 0.6.0
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.md +10 -3
- package/README.zh.md +63 -0
- package/index.js +60 -33
- package/job-kind.d.ts +24 -0
- package/local.js +13 -14
- package/package.json +45 -43
- package/persistent.js +238 -45
- package/policy.js +73 -14
- package/terminal-fish.js +146 -36
- package/tool.js +258 -60
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# @banbolee/dsh-fish-shell
|
|
2
2
|
|
|
3
|
+
**English** | [中文](./README.zh.md)
|
|
4
|
+
|
|
3
5
|
Fish shell executors and tool for DeepSeek Harness: run commands with
|
|
4
6
|
**fish** instead of bash. Distribution-ready and surface-agnostic: works in
|
|
5
7
|
any profile that mounts it — preset-roster based (dsh-tui, web) or
|
|
@@ -26,8 +28,10 @@ cordis, minimal, or a third-party preset).
|
|
|
26
28
|
(with shell wording swapped to fish):
|
|
27
29
|
- **Background execution**: `run_in_background: true` registers the command
|
|
28
30
|
with `ctx.jobs` (`kind: fish`) and returns `{kind: 'background', jobId}`;
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
the process's observed streams are handed to the registry as pull sources
|
|
32
|
+
(it owns the lossy-read reporting), the sandbox runner-failure/denial
|
|
33
|
+
facts join the job's terminal detail, and the job controller's
|
|
34
|
+
`job_output`/`job_kill` handle the rest.
|
|
31
35
|
- **Sandbox escalation**: when the mounted executor confines, the schema
|
|
32
36
|
advertises `sandbox_permissions` + `justification`; an escalation is
|
|
33
37
|
resolved through `ctx.approval` BEFORE anything executes (strictly wider
|
|
@@ -171,7 +175,10 @@ the profile tree).
|
|
|
171
175
|
contract.
|
|
172
176
|
- `run_in_background: true` starts long-running commands as background jobs
|
|
173
177
|
(`kind: fish`) and returns a job id immediately; read output with
|
|
174
|
-
`job_output` and stop it with `job_kill`.
|
|
178
|
+
`job_output` and stop it with `job_kill`. A background job arms **no
|
|
179
|
+
deadline** (the tool resolves it with `onExpiry: 'none'`, matching 0.1.5's
|
|
180
|
+
`start()` and the official `dsh-tool-bash`): it runs until `job_kill`,
|
|
181
|
+
cancellation, or composition teardown. Requires the jobs services
|
|
175
182
|
(`@deepseek-ai/dsh-jobs` + `@deepseek-ai/dsh-tool-jobs`) to be composed;
|
|
176
183
|
the tool fails loud when they are not.
|
|
177
184
|
- Under a sandboxing executor, a denied command can be re-run wider in the
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# @banbolee/dsh-fish-shell
|
|
2
|
+
|
|
3
|
+
[English](./README.md) | **中文**
|
|
4
|
+
|
|
5
|
+
DeepSeek Harness 的 fish shell executor 与工具:用 **fish** 而不是 bash 运行命令。可直接分发、与 surface 无关:任何挂载它的 profile 都能用——基于 preset roster 的(dsh-tui、web)或基于 host tool 的(headless)——并且在**任意 agent preset**(standard、ptc、cordis、minimal 或第三方 preset)下都能用。
|
|
6
|
+
|
|
7
|
+
## 这个 bundle 做什么
|
|
8
|
+
|
|
9
|
+
- **Executor(受限 / sandboxed)**(`index.js`,默认导出):`FishSandboxExecutor`,一个 `SandboxBashExecutor` 子类,把 `fish -c` 命令而不是 `bash -c` 关进 sandbox。它以 `ctx.shell` 的形式挂载,替代基础 `bash-sandbox` executor。sandbox 后端、拒绝分类、runner 失败事实,以及 `sandboxMode` 能力事实(`dsh-permission-presets` 需要)都继承而来。受限路径与 `danger-full-access` 路径都运行 fish(基类的 full-access 分支会落到硬编码的 bash,因此被覆盖)。
|
|
10
|
+
- **Executor(非受限 / unconfined)**(`local.js`,导出为 `@banbolee/dsh-fish-shell/local`):`FishLocalExecutor`,一个 `LocalBashExecutor` 子类,不带 sandbox 运行 `fish -c`。用于刻意在无 sandbox 下运行的自定义 composition;把它与 `dsh-permission-presets` 组合会在加载时 fail loud。
|
|
11
|
+
- **Tool**(`tool.js`,导出为 `@banbolee/dsh-fish-shell/tool`):一个面向模型的 `fish` 工具,以 host-global 方式挂载,通过 `ctx.shell` 执行。它的功能 surface 与官方 `@deepseek-ai/dsh-tool-bash` 对齐(只把 shell 措辞换成 fish):
|
|
12
|
+
- **后台执行**:`run_in_background: true` 会把命令注册到 `ctx.jobs`(`kind: fish`)并返回 `{kind: 'background', jobId}`;进程的 observed 流会作为 registry 的拉取源交给它(lossy-read 上报由 registry 负责),sandbox runner 失败/拒绝事实并入 job 终态 detail,其余由 job controller 的 `job_output`/`job_kill` 处理。
|
|
13
|
+
- **Sandbox 升级**:当挂载的 executor 会施加限制时,schema 会声明 `sandbox_permissions` + `justification`;升级会在**任何执行发生之前**通过 `ctx.approval` 裁决(只允许严格更宽的模式,fail-closed),被拒绝的结果会带上同一轮内的升级提示。Headless composition(没有 sandboxing executor)不会暴露这两个字段。
|
|
14
|
+
- **结果事实**:前台结果携带完整的规范事实集,包括 sandbox 的 `enforcement`/`runnerFailed` 字段。
|
|
15
|
+
- **UI 呈现**:`presentCall`/`presentResult` 把前台调用渲染成终端卡片(带 exit-status 状态胶囊),把后台/错误结果渲染成通用的围栏式控制台输出。
|
|
16
|
+
- **Exit-code 提示词小节**:在 `TOOL_BASH` 位置注册 `tool:fish` 小节(「Check the [exit code: N] marker on every fish result…」)。
|
|
17
|
+
- 除此之外,它还会传递调用方 session 已解析的 sandbox policy(因此 `/permission` 切换与 session workspace root 都会被遵守),从 `ctx.shellEnv` 收集受管理的 `DSH_*` 环境变量,渲染 harness marker 契约(`[exit code: N]`、`[stderr]`、`[sandbox: file access denied under <mode> mode]`、`[output truncated; full output: <path>]`),并且它的描述会用每条结果上的 `[fish syntax]` 提示教会模型 fish 语法。
|
|
18
|
+
- **Per-agent fish policy**(`policy.js`,导出为 `@banbolee/dsh-fish-shell/policy`):一个以 host 方式挂载的 Cordis plugin,让每个 agent 都看到 fish 而不是 bash,**无论它跑在哪个 agent preset 下**。bundle patch 会禁用基础 bash executor(`bash-sandbox`)与 host bash 工具(`tool-bash`),挂载 fish executor 与 host-global `fish` 工具,并且不改动 preset——它不再修改 roster 默认值、不再注入 preset root,也不再往 `$DSH_HOME/.agent-presets/` 下写副本。preset 仍会注册自己的 `bash` 同名工具(standard/minimal 就会),而在 `agent/created` 时(以及每次 `tools/change`,即 `/preset` 重新组合之后),policy 会通过 `agent.ctx.tools.restrict({ deny: ['bash'] })` 按 agent 隐藏这个继承来的 bash 工具,并用一个空的 agent 作用域小节遮蔽 preset 静态的 `tool:bash` 提示词指引。agent 最终只剩下唯一一个 shell 工具:`fish`。在 `minimal` 下——它常驻的 bash 是持久 PTY 形态(参数只带 `command`,输出 schema 是普通字符串)——policy 会先在 agent 作用域注册一个持久 `fish` 工具(遮蔽 one-shot fish),然后隐藏 bash,因此 minimal session 在 fish 下保持持久语义。
|
|
19
|
+
- **持久 fish terminal 后端**(`terminal-fish.js`,导出为 `@banbolee/dsh-fish-shell/terminal-fish`):一个库——**不**由 bundle patch 挂载——提供持久工具使用的 `fish` PTY 后端。它继承官方 `BashTerminalBackend`,启动 `fish --no-config -i`(可通过配置覆盖)并配上受控提示符——该提示符遵循 harness readiness 契约(OSC `133;D;<status>` + `dsh> `)——并通过同一套 sandbox policy 施加限制;官方 sandbox-mode fence 被复制进来(官方模块没有导出它;这份副本为自管理用途提供了一个可注入的 owner-activity 检查)。patch 刻意没有 `fish-terminal` host row:`terminals` service 是 `minimal` preset isolate realm 的 entry-local 资源,在 host 平面(headless / dsh-tui / composition 测试 profile)不可见,因此这样一行会永远停留在 pending。`apply` 会被导出,供直接装配与测试使用(或供显式挂载该 registry 的 composition 使用)。
|
|
20
|
+
- **持久 fish 工具**(`persistent.js`,导出为 `@banbolee/dsh-fish-shell/persistent`):官方 `dsh-tool-bash-persistent` 模式的 fish 版本——每个 agent 一个缓存的 PTY shell,其 cwd、变量与函数在多次调用之间存活,并支持 marker 包裹的命令、串行执行、deadline/timeout 重置与 scrollback 读取。它刻意不导出 Cordis `apply`:`policy.js` 会在 agent 边界为 persistent-bash preset 调用 `registerPersistentFish(ctx, agentCtx)`。PTY 是**自管理**的:工具自己持有一个 `FishTerminalBackend` 实例并直接驱动它的 session(`backend.spawn(...)`、`session.startSend/read/status/close`),而不经过 `terminals` registry——agent 作用域的工具解析不到它(该 registry 只存在于 minimal preset 的 entry-local realm 内)。命令的引号处理使用 fish 单引号转义,并用带单个字符串参数的 `eval`(fish 4 没有 `$'...'` ANSI-C 引号语法,也没有 `eval --`),已用真实 fish 4.0.0 验证。
|
|
21
|
+
|
|
22
|
+
## 安装
|
|
23
|
+
|
|
24
|
+
**从 npm 安装(推荐)**——无需 clone:
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
dsh plugin --profile <name> add @banbolee/dsh-fish-shell
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
从本仓库检出安装,按 profile 分别执行:
|
|
31
|
+
|
|
32
|
+
```sh
|
|
33
|
+
dsh plugin --profile <name> add ./plugins/fish-shell
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
把它加到每一个需要运行 fish 的 profile(dsh-tui、web、headless……)。bundle patch(`cordis.patch.yml`)是一个跨 surface 安全的 patch:它禁用 host bash executor 与 `tool-bash` row,挂载 fish executor 与 host-global `fish` 工具,并插入 `fish-preset-policy` row——该 row 会按 agent 隐藏 preset 继承来的 `bash` 工具(restriction + 空的 `tool:bash` 提示词遮蔽,在 `minimal` 下换成 persistent fish)。patch 不再改动 preset roster。
|
|
37
|
+
|
|
38
|
+
### 部署副本与 symlink 链
|
|
39
|
+
|
|
40
|
+
这些 executor 继承 `@deepseek-ai/dsh-bash-local` / `@deepseek-ai/dsh-bash-sandbox`。这些 import 必须解析到 harness 使用的同一个运行时实例——即 launcher 维护的 `profiles/node_modules/@deepseek-ai/*` symlink 链。直接 `link:` 到本仓库检出(位于 profile 树之外)将解析不到任何 `@deepseek-ai` 包,因此部署副本放在 `profiles/node_modules/@banbolee/dsh-fish-shell`(树内)。`scripts/sync-to-profile.sh` 会在改动后把插件复制到那里。pnpm 的 `file:` 依赖让每个 profile 指向该部署副本。发布到 npm 的包则正常安装(它的 realpath 本来就在 profile 树内)。
|
|
41
|
+
|
|
42
|
+
## 各 surface 的行为
|
|
43
|
+
|
|
44
|
+
- **基于 preset roster 的 surface**(dsh-tui、web):roster 默认值不被改动(`standard`)。`fish-preset-policy` plugin 按 agent 生效,因此**任意** preset 下的 agent——`standard`、`ptc`、`cordis`、`minimal` 或普通第三方 preset——其 preset 继承来的 `bash` 工具都会被隐藏,只能看到唯一一个 shell 工具:`fish`。preset 静态的 `tool:bash` 提示词指引会被遮蔽(空的 agent 作用域小节),因此模型不会被告知去「check the bash result」。在 `minimal` 下,policy 会检测到 preset 的持久 bash 并改换成持久 `fish` 工具,因此 minimal session 保持其持久语义。持久 PTY 由 policy 自管理(直接驱动一个 `FishTerminalBackend`,不经过 `terminals` registry),所以它在每个 surface 都能工作——该 registry 只在 minimal preset 的 entry-local realm 内可见,这也正是 bundle 不挂载任何 `fish-terminal` row 的原因。
|
|
45
|
+
- **基于 host tool 的 surface**(headless):agent 使用 host 平面的工具;被禁用的 host `tool-bash` 与 host-global `fish` 工具使 fish 成为 agent 唯一的 shell 工具。
|
|
46
|
+
|
|
47
|
+
## 行为
|
|
48
|
+
|
|
49
|
+
- **One-shot**(standard、ptc、cordis、第三方 preset 与 headless):每次 shell 调用都会新起一个 non-login shell(对 `FishSandboxExecutor` 而言是在配置的 sandbox 后端下);调用之间不保留任何状态(cwd、变量、函数、历史)。
|
|
50
|
+
- **Persistent**(`minimal` preset,它挂载了持久 PTY bash 机制):agent 的 `fish` 工具为每个 agent 维持一个存活的 fish session。当前目录、导出的变量与已定义的函数在调用之间保留;通过该工具运行的命令串行执行;超过工具 deadline 的命令会被打断并重置 shell(下一次调用会从 workspace 用一个全新的 shell 开始)。持久 fish PTY 由工具自己通过 `FishTerminalBackend` 启动并驱动(不涉及 `terminals` registry)。
|
|
51
|
+
- 每条流的输出都受 executor 配置的上限约束;超时会被钳到 executor 的上限;模型看到的是 harness marker 契约。
|
|
52
|
+
- `run_in_background: true` 会把长时间运行的命令作为后台 job 启动(`kind: fish`)并立即返回一个 job id;用 `job_output` 读取输出,用 `job_kill` 停止它。后台 job **不设 deadline**(工具以 `onExpiry: 'none'` 解析它,与 0.1.5 的 `start()` 及官方 `dsh-tool-bash` 一致):它会一直运行到 `job_kill`、取消或 composition teardown。需要组合 jobs service(`@deepseek-ai/dsh-jobs` + `@deepseek-ai/dsh-tool-jobs`);未组合时该工具会 fail loud。
|
|
53
|
+
- 在 sandboxing executor 下,被拒绝的命令可以在同一轮内用 `sandbox_permissions`(够用的最窄的更宽模式)加一句 `justification` 重新以更宽权限执行;这次重试弹出的 approval prompt 就是用户表示同意的方式。当 approval prompt 被禁用或升级被拒绝时,拒绝即为最终结果。
|
|
54
|
+
- 要求 PATH 中有 `fish`;缺失时 executor 会 fail loud。
|
|
55
|
+
|
|
56
|
+
## 已知限制
|
|
57
|
+
|
|
58
|
+
- 模型默认使用 bash 惯用法;`fish` 工具的描述会教 fish 语法,但用 bash 方言写出的命令在 fish 下会失败。这是更换 shell 的预期代价。
|
|
59
|
+
- **旧的 bundled `fish` agent preset 已被移除**:本 bundle 不再包含 `presets/fish/` 目录,sync 脚本不再部署它、也不再做 drift 检查,并且不会再往 `$DSH_HOME/.agent-presets/fish` 写用户副本。旧版 bundle 遗留的该目录用户副本不会起作用(roster 已不再指向它),可以手动删除。
|
|
60
|
+
- **`minimal` 下的持久语义**由持久 `fish` 工具提供(cwd、导出的变量与已定义的函数在调用之间保留)。与官方持久 bash 一样,超出 deadline 的命令会被打断并重置 shell;agent 作用域的 `fish` 工具遮蔽了 host-global 的 one-shot 工具,因此升级字段(`sandbox_permissions`/`justification`)与后台执行(`run_in_background`)不属于持久 surface。
|
|
61
|
+
- **第三方 preset 的边界**:policy 隐藏的是从 preset 继承来的 `bash` 同名工具。如果一个 preset 刻意排除全局 `fish` 工具(用 allowlist 把它过滤掉),或用别的名字注册自己的 shell 工具,那么它会被原样保留,只按 agent 给出一次警告——bundle 从不改动第三方 preset。
|
|
62
|
+
- `fish` 工具面向模型的 surface 与官方 bash 工具对齐:后台执行(通过 `ctx.jobs` 的 `run_in_background`)、sandbox 升级(通过 `ctx.approval` 的 `sandbox_permissions`/`justification`)、终端/通用 UI 呈现,以及 `tool:fish` exit-code 提示词小节,全都支持。
|
|
63
|
+
- 仅支持 POSIX:`fish` 二进制与底层 process-group 语义在 Windows 上不可用(Windows 由 pwsh 系列覆盖)。
|
package/index.js
CHANGED
|
@@ -3,12 +3,19 @@
|
|
|
3
3
|
* subclass that confines `fish -c` commands instead of `bash -c`. Mounted as
|
|
4
4
|
* the `ctx.shell` provider in place of the base `bash-sandbox` executor.
|
|
5
5
|
*
|
|
6
|
-
* `SandboxBashExecutor.
|
|
7
|
-
* `danger-full-access` mode and
|
|
8
|
-
* argv, so this subclass overrides both
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
6
|
+
* `SandboxBashExecutor.execute` bypasses `confine()` in
|
|
7
|
+
* `danger-full-access` mode and falls through to the hardcoded `bash -c`
|
|
8
|
+
* argv, so this subclass overrides both execution boundaries:
|
|
9
|
+
*
|
|
10
|
+
* - {@link FishSandboxExecutor.execute}: the full-access branch runs
|
|
11
|
+
* `fish -c` through the inherited `executeArgv()` hook (stamping the same
|
|
12
|
+
* `sandbox` fact the base class would); confined modes delegate to the
|
|
13
|
+
* base class, whose confined branch calls `confine()` polymorphically.
|
|
14
|
+
* - {@link FishSandboxExecutor.confine}: swaps the confined inner shell from
|
|
15
|
+
* `bash -c` to `fish -c` through the same `ctx.sandbox` provider — the
|
|
16
|
+
* ONLY hook that decides which argv the sandbox wraps.
|
|
17
|
+
*
|
|
18
|
+
* The sandbox backend, denial classification, runner-failure facts, and the
|
|
12
19
|
* `sandboxMode` capability fact (which `dsh-permission-presets` requires of
|
|
13
20
|
* the mounted executor) are all inherited.
|
|
14
21
|
*
|
|
@@ -26,49 +33,69 @@ import { SandboxBashExecutor } from '@deepseek-ai/dsh-bash-sandbox'
|
|
|
26
33
|
* Local fish executor under the configured sandbox backend. Reuses every
|
|
27
34
|
* bash-sandbox mechanic with the public command's shell swapped from bash to
|
|
28
35
|
* fish.
|
|
36
|
+
*
|
|
37
|
+
* The class body declares `confine()` as well, which TypeScript reports as
|
|
38
|
+
* TS2415 at the heritage clause: `SandboxBashExecutor` declares that hook
|
|
39
|
+
* `private` while still dispatching to it virtually, and a private member
|
|
40
|
+
* cannot be extended, so this one directive is the only way to express the
|
|
41
|
+
* override. The directive is deliberately on the class line (where TS2415 is
|
|
42
|
+
* reported) and stays narrow: every other member of the class is checked.
|
|
29
43
|
*/
|
|
44
|
+
// @ts-expect-error - overriding the base class's TS-private `confine()` execution boundary (see above).
|
|
30
45
|
export class FishSandboxExecutor extends SandboxBashExecutor {
|
|
31
46
|
/**
|
|
32
|
-
*
|
|
33
|
-
* unconfined
|
|
34
|
-
*
|
|
35
|
-
* {@
|
|
36
|
-
* @
|
|
37
|
-
* @returns the settled foreground result.
|
|
47
|
+
* Prepare and spawn one resolved command. Full-access calls run `fish -c`
|
|
48
|
+
* unconfined; other modes delegate to the base class, whose confinement
|
|
49
|
+
* preparation calls the polymorphic {@link confine}.
|
|
50
|
+
* @param {import('@deepseek-ai/dsh-shell').ShellExecSpec} spec - a resolved spec from `resolve()`.
|
|
51
|
+
* @returns {Promise<import('@deepseek-ai/dsh-shell').ShellExecution>} the live execution handle.
|
|
38
52
|
*/
|
|
39
|
-
|
|
53
|
+
async execute(spec) {
|
|
40
54
|
const policy = spec.sandboxPolicy
|
|
41
55
|
if (policy?.mode === 'danger-full-access') {
|
|
42
|
-
return this.
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
56
|
+
return this.decorateFishResult(
|
|
57
|
+
await this.executeArgv(spec, ['fish', '-c', spec.command]),
|
|
58
|
+
policy.mode,
|
|
59
|
+
)
|
|
46
60
|
}
|
|
47
|
-
return super.
|
|
61
|
+
return super.execute(spec)
|
|
48
62
|
}
|
|
49
63
|
|
|
50
64
|
/**
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
65
|
+
* Attach the sandbox facts the base class stamps for a full-access run:
|
|
66
|
+
* the handle keeps its identity and `result()` is memoized, exactly like
|
|
67
|
+
* the base class's own decoration (which this branch cannot reach, because
|
|
68
|
+
* it also swaps the shell argv).
|
|
69
|
+
* @param {import('@deepseek-ai/dsh-shell').ShellExecution} execution - the live handle from `executeArgv()`.
|
|
70
|
+
* @param {import('@deepseek-ai/dsh-sandbox').SandboxMode} mode - the mode the command ran under.
|
|
71
|
+
* @returns {import('@deepseek-ai/dsh-shell').ShellExecution} the same handle, its `result()` decorated once.
|
|
55
72
|
*/
|
|
56
|
-
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
73
|
+
decorateFishResult(execution, mode) {
|
|
74
|
+
const base = execution.result.bind(execution)
|
|
75
|
+
let decorated
|
|
76
|
+
execution.result = () => {
|
|
77
|
+
decorated ??= base().then((result) => ({
|
|
78
|
+
...result,
|
|
79
|
+
sandbox: { mode, denied: false },
|
|
80
|
+
}))
|
|
81
|
+
return decorated
|
|
60
82
|
}
|
|
61
|
-
return
|
|
83
|
+
return execution
|
|
62
84
|
}
|
|
63
85
|
|
|
64
86
|
/**
|
|
65
|
-
* Confine a `fish -c <command>` argv through the configured sandbox
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
87
|
+
* Confine a `fish -c <command>` argv through the configured sandbox
|
|
88
|
+
* backend. The base class's confined branch calls this method virtually
|
|
89
|
+
* (`this.confine(...)`), so overriding it is what makes every confined fish
|
|
90
|
+
* command run fish (see the heritage-clause note above for the TS2415
|
|
91
|
+
* directive this override needs).
|
|
92
|
+
* @param {string} command - the fish command text.
|
|
93
|
+
* @param {import('@deepseek-ai/dsh-sandbox').SandboxPolicy} policy - the resolved execution policy for this call.
|
|
94
|
+
* @param {AbortSignal} [signal] - cancellation of confinement preparation.
|
|
95
|
+
* @returns {Promise<import('@deepseek-ai/dsh-sandbox').ConfinedArgv>} the provider's confined argv and settlement-classification facts.
|
|
69
96
|
*/
|
|
70
|
-
confine(command, policy) {
|
|
71
|
-
return this.ctx.sandbox.confine(['fish', '-c', command], policy)
|
|
97
|
+
confine(command, policy, signal) {
|
|
98
|
+
return this.ctx.sandbox.confine(['fish', '-c', command], policy, signal)
|
|
72
99
|
}
|
|
73
100
|
}
|
|
74
101
|
|
package/job-kind.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The plugin-owned `JobKindMap` entry this plugin's background `fish` jobs
|
|
3
|
+
* register under.
|
|
4
|
+
*
|
|
5
|
+
* `@deepseek-ai/dsh-jobs`' `JobKind` is `JobKindMap[keyof JobKindMap]` over a
|
|
6
|
+
* merge-extensible map that carries only the harness's own producers, so every
|
|
7
|
+
* third-party producer declares its own kind in its own module. A
|
|
8
|
+
* `declare module` augmentation cannot live in a checked JavaScript file
|
|
9
|
+
* (TS8006), so it lives here and `tool.js` pulls it into the program with
|
|
10
|
+
* `/// <reference path="./job-kind.d.ts" />`.
|
|
11
|
+
*
|
|
12
|
+
* @module @banbolee/dsh-fish-shell/job-kind
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
declare module '@deepseek-ai/dsh-jobs/view' {
|
|
16
|
+
interface JobKindMap {
|
|
17
|
+
/** One background fish command registered by this plugin's `fish` tool. */
|
|
18
|
+
fish: 'fish'
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Makes this file a module, so the block above AUGMENTS the jobs declaration
|
|
23
|
+
// instead of declaring an ambient module of the same name.
|
|
24
|
+
export {}
|
package/local.js
CHANGED
|
@@ -8,6 +8,11 @@
|
|
|
8
8
|
* `ctx.subprocess` and reuses all of bash-local's mechanics (resolve and
|
|
9
9
|
* defaulting, deadline and cause classification, the model-friendly terminal
|
|
10
10
|
* environment, bounded output with spill files, background process groups).
|
|
11
|
+
* The shell swap happens at the `executeArgv()` injection point
|
|
12
|
+
* `LocalBashExecutor.execute` documents for subclasses: this executor
|
|
13
|
+
* replaces the public command's shell argv and keeps every other mechanic
|
|
14
|
+
* (including the single `execute()` entry the host calls for foreground AND
|
|
15
|
+
* background work).
|
|
11
16
|
*
|
|
12
17
|
* Prefer {@link FishSandboxExecutor} (this package's default export) in any
|
|
13
18
|
* composition that mounts `dsh-permission-presets`, which requires the
|
|
@@ -29,21 +34,15 @@ import { LocalBashExecutor } from '@deepseek-ai/dsh-bash-local'
|
|
|
29
34
|
*/
|
|
30
35
|
export class FishLocalExecutor extends LocalBashExecutor {
|
|
31
36
|
/**
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
37
|
+
* Prepare and spawn the command through `fish -c`. Foreground and
|
|
38
|
+
* background callers share this one entry: whoever awaits
|
|
39
|
+
* `result()` ran it in the foreground, whoever keeps the handle ran it in
|
|
40
|
+
* the background.
|
|
41
|
+
* @param {import('@deepseek-ai/dsh-shell').ShellExecSpec} spec - a resolved spec from `resolve()`.
|
|
42
|
+
* @returns {Promise<import('@deepseek-ai/dsh-shell').ShellExecution>} the live execution handle.
|
|
35
43
|
*/
|
|
36
|
-
|
|
37
|
-
return this.
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Start a background process through `fish -c`.
|
|
42
|
-
* @param spec - a resolved spec from `resolve()`.
|
|
43
|
-
* @returns the live background process handle.
|
|
44
|
-
*/
|
|
45
|
-
start(spec) {
|
|
46
|
-
return this.startArgv(spec, ['fish', '-c', spec.command])
|
|
44
|
+
async execute(spec) {
|
|
45
|
+
return this.executeArgv(spec, ['fish', '-c', spec.command])
|
|
47
46
|
}
|
|
48
47
|
}
|
|
49
48
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@banbolee/dsh-fish-shell",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Fish shell executors and tool for DeepSeek Harness: run commands with fish instead of bash.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -20,8 +20,10 @@
|
|
|
20
20
|
"policy.js",
|
|
21
21
|
"terminal-fish.js",
|
|
22
22
|
"persistent.js",
|
|
23
|
+
"job-kind.d.ts",
|
|
23
24
|
"cordis.patch.yml",
|
|
24
|
-
"README.md"
|
|
25
|
+
"README.md",
|
|
26
|
+
"README.zh.md"
|
|
25
27
|
],
|
|
26
28
|
"dsh": {
|
|
27
29
|
"bundle": {
|
|
@@ -29,49 +31,49 @@
|
|
|
29
31
|
}
|
|
30
32
|
},
|
|
31
33
|
"peerDependencies": {
|
|
32
|
-
"@deepseek-ai/cordis": "
|
|
33
|
-
"@deepseek-ai/dsh-agent": "^0.1.
|
|
34
|
-
"@deepseek-ai/dsh-bash-local": "^0.1.
|
|
35
|
-
"@deepseek-ai/dsh-bash-sandbox": "^0.1.
|
|
36
|
-
"@deepseek-ai/dsh-home-paths": "^0.1.
|
|
37
|
-
"@deepseek-ai/dsh-jobs": "^0.1.
|
|
38
|
-
"@deepseek-ai/dsh-llm": "^0.1.
|
|
39
|
-
"@deepseek-ai/dsh-sandbox": "^0.1.
|
|
40
|
-
"@deepseek-ai/dsh-sandbox-policy": "^0.1.
|
|
41
|
-
"@deepseek-ai/dsh-scope": "^0.1.
|
|
42
|
-
"@deepseek-ai/dsh-session-projection": "^0.1.
|
|
43
|
-
"@deepseek-ai/dsh-shell": "^0.1.
|
|
44
|
-
"@deepseek-ai/dsh-shell-env": "^0.1.
|
|
45
|
-
"@deepseek-ai/dsh-subprocess": "^0.1.
|
|
46
|
-
"@deepseek-ai/dsh-system-prompt": "^0.1.
|
|
47
|
-
"@deepseek-ai/dsh-terminal": "^0.1.
|
|
48
|
-
"@deepseek-ai/dsh-terminal-bash": "^0.1.
|
|
49
|
-
"@deepseek-ai/dsh-tools": "^0.1.
|
|
50
|
-
"@deepseek-ai/dsh-user-approval": "^0.1.
|
|
34
|
+
"@deepseek-ai/cordis": "~4.0.4",
|
|
35
|
+
"@deepseek-ai/dsh-agent": "^0.1.7-rc.2",
|
|
36
|
+
"@deepseek-ai/dsh-bash-local": "^0.1.7-rc.2",
|
|
37
|
+
"@deepseek-ai/dsh-bash-sandbox": "^0.1.7-rc.2",
|
|
38
|
+
"@deepseek-ai/dsh-home-paths": "^0.1.7-rc.2",
|
|
39
|
+
"@deepseek-ai/dsh-jobs": "^0.1.7-rc.2",
|
|
40
|
+
"@deepseek-ai/dsh-llm": "^0.1.7-rc.2",
|
|
41
|
+
"@deepseek-ai/dsh-sandbox": "^0.1.7-rc.2",
|
|
42
|
+
"@deepseek-ai/dsh-sandbox-policy": "^0.1.7-rc.2",
|
|
43
|
+
"@deepseek-ai/dsh-scope": "^0.1.7-rc.2",
|
|
44
|
+
"@deepseek-ai/dsh-session-projection": "^0.1.7-rc.2",
|
|
45
|
+
"@deepseek-ai/dsh-shell": "^0.1.7-rc.2",
|
|
46
|
+
"@deepseek-ai/dsh-shell-env": "^0.1.7-rc.2",
|
|
47
|
+
"@deepseek-ai/dsh-subprocess": "^0.1.7-rc.2",
|
|
48
|
+
"@deepseek-ai/dsh-system-prompt": "^0.1.7-rc.2",
|
|
49
|
+
"@deepseek-ai/dsh-terminal": "^0.1.7-rc.2",
|
|
50
|
+
"@deepseek-ai/dsh-terminal-bash": "^0.1.7-rc.2",
|
|
51
|
+
"@deepseek-ai/dsh-tools": "^0.1.7-rc.2",
|
|
52
|
+
"@deepseek-ai/dsh-user-approval": "^0.1.7-rc.2"
|
|
51
53
|
},
|
|
52
54
|
"devDependencies": {
|
|
53
|
-
"@deepseek-ai/cordis": "
|
|
54
|
-
"@deepseek-ai/dsh-agent": "^0.1.
|
|
55
|
-
"@deepseek-ai/dsh-bash-local": "^0.1.
|
|
56
|
-
"@deepseek-ai/dsh-bash-sandbox": "^0.1.
|
|
57
|
-
"@deepseek-ai/dsh-home-paths": "^0.1.
|
|
58
|
-
"@deepseek-ai/dsh-invariants": "^0.1.
|
|
59
|
-
"@deepseek-ai/dsh-jobs": "^0.1.
|
|
60
|
-
"@deepseek-ai/dsh-llm": "^0.1.
|
|
61
|
-
"@deepseek-ai/dsh-pwsh-local": "^0.1.
|
|
62
|
-
"@deepseek-ai/dsh-sandbox": "^0.1.
|
|
63
|
-
"@deepseek-ai/dsh-sandbox-policy": "^0.1.
|
|
64
|
-
"@deepseek-ai/dsh-scope": "^0.1.
|
|
65
|
-
"@deepseek-ai/dsh-session-projection": "^0.1.
|
|
66
|
-
"@deepseek-ai/dsh-shell": "^0.1.
|
|
67
|
-
"@deepseek-ai/dsh-shell-env": "^0.1.
|
|
68
|
-
"@deepseek-ai/dsh-subprocess": "^0.1.
|
|
69
|
-
"@deepseek-ai/dsh-subprocess-local": "^0.1.
|
|
70
|
-
"@deepseek-ai/dsh-system-prompt": "^0.1.
|
|
71
|
-
"@deepseek-ai/dsh-terminal": "^0.1.
|
|
72
|
-
"@deepseek-ai/dsh-terminal-bash": "^0.1.
|
|
73
|
-
"@deepseek-ai/dsh-tools": "^0.1.
|
|
74
|
-
"@deepseek-ai/dsh-user-approval": "^0.1.
|
|
55
|
+
"@deepseek-ai/cordis": "~4.0.4",
|
|
56
|
+
"@deepseek-ai/dsh-agent": "^0.1.7-rc.2",
|
|
57
|
+
"@deepseek-ai/dsh-bash-local": "^0.1.7-rc.2",
|
|
58
|
+
"@deepseek-ai/dsh-bash-sandbox": "^0.1.7-rc.2",
|
|
59
|
+
"@deepseek-ai/dsh-home-paths": "^0.1.7-rc.2",
|
|
60
|
+
"@deepseek-ai/dsh-invariants": "^0.1.7-rc.2",
|
|
61
|
+
"@deepseek-ai/dsh-jobs": "^0.1.7-rc.2",
|
|
62
|
+
"@deepseek-ai/dsh-llm": "^0.1.7-rc.2",
|
|
63
|
+
"@deepseek-ai/dsh-pwsh-local": "^0.1.7-rc.2",
|
|
64
|
+
"@deepseek-ai/dsh-sandbox": "^0.1.7-rc.2",
|
|
65
|
+
"@deepseek-ai/dsh-sandbox-policy": "^0.1.7-rc.2",
|
|
66
|
+
"@deepseek-ai/dsh-scope": "^0.1.7-rc.2",
|
|
67
|
+
"@deepseek-ai/dsh-session-projection": "^0.1.7-rc.2",
|
|
68
|
+
"@deepseek-ai/dsh-shell": "^0.1.7-rc.2",
|
|
69
|
+
"@deepseek-ai/dsh-shell-env": "^0.1.7-rc.2",
|
|
70
|
+
"@deepseek-ai/dsh-subprocess": "^0.1.7-rc.2",
|
|
71
|
+
"@deepseek-ai/dsh-subprocess-local": "^0.1.7-rc.2",
|
|
72
|
+
"@deepseek-ai/dsh-system-prompt": "^0.1.7-rc.2",
|
|
73
|
+
"@deepseek-ai/dsh-terminal": "^0.1.7-rc.2",
|
|
74
|
+
"@deepseek-ai/dsh-terminal-bash": "^0.1.7-rc.2",
|
|
75
|
+
"@deepseek-ai/dsh-tools": "^0.1.7-rc.2",
|
|
76
|
+
"@deepseek-ai/dsh-user-approval": "^0.1.7-rc.2",
|
|
75
77
|
"yaml": "^2.8.0"
|
|
76
78
|
},
|
|
77
79
|
"keywords": [
|