@stardustlc/dsh-docker 0.3.1 → 0.3.3
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.en.md +10 -6
- package/README.md +10 -6
- package/cordis.patch.yml +1 -0
- package/lib/config.d.ts +2 -0
- package/lib/config.js +2 -1
- package/lib/exec.d.ts +1 -0
- package/lib/exec.js +4 -1
- package/lib/index.d.ts +5 -5
- package/lib/index.js +26 -22
- package/lib/tools.d.ts +1 -1
- package/lib/tools.js +30 -20
- package/package.json +59 -59
package/README.en.md
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
# dsh-docker
|
|
4
4
|
|
|
5
|
-
> **Your agent can manage containers now**:
|
|
5
|
+
> **Your agent can manage containers now**: seven tools covering containers, images, logs, inspection, in-container exec, lifecycle management, and health checks.
|
|
6
6
|
|
|
7
|
-
DSH (DeepSeek Harness) container-management plugin: runs the docker CLI through the official subprocess service with shell-free argv arrays,
|
|
7
|
+
DSH (DeepSeek Harness) container-management plugin: runs the docker CLI through the official subprocess service with shell-free argv arrays, approval gates on `docker_exec` and destructive lifecycle actions, and **zero runtime dependencies**.
|
|
8
8
|
|
|
9
9
|
   
|
|
10
10
|
|
|
@@ -12,7 +12,9 @@ DSH (DeepSeek Harness) container-management plugin: runs the docker CLI through
|
|
|
12
12
|
|
|
13
13
|
## Compatibility
|
|
14
14
|
|
|
15
|
-
Verified
|
|
15
|
+
Verified with official `@deepseek-ai/dsh@0.1.5-rc.1` and Node `24.16.0` on 2026-09-11: all 18 components load alongside Modlens, with passing tool-schema, skill-registration and offline read-only invocation checks. Uses the `cordis.patch.yml` + `dsh.bundle.patch` bundle model. Node requirements match this Harness release: 22.19 or later within 22.x, or 24 or later. Live external-service workflows require separate configuration and validation.
|
|
16
|
+
|
|
17
|
+
2026-09-13 fix: retain the service receiver when calling `subprocess.spawn`, preventing failures caused by passing the method as an unbound callback. Verified with official `0.1.5-rc.1` and `0.1.5-rc.2` on Node `24.16.0`. `docker_ps` passes through the real host subprocess service with a Node child producing fixed Docker output. A live Docker daemon was not used.
|
|
16
18
|
|
|
17
19
|
## Installation
|
|
18
20
|
|
|
@@ -41,6 +43,7 @@ Then restart the web service. To clean up fully, also remove the plugin entry fr
|
|
|
41
43
|
dockerPath: docker # optional; or use the DSH_DOCKER_PATH env var
|
|
42
44
|
timeoutMs: 60000 # per-operation timeout (default 60s, 5s - 10min)
|
|
43
45
|
# execApproval: false # disable the docker_exec approval gate (default true)
|
|
46
|
+
# manageApproval: false # disable approval for stop/restart/rm (default true; not recommended)
|
|
44
47
|
```
|
|
45
48
|
|
|
46
49
|
## Tools
|
|
@@ -52,7 +55,8 @@ Then restart the web service. To clean up fully, also remove the plugin entry fr
|
|
|
52
55
|
| `docker_logs` | Tail container logs (line clamp, short follow) | — |
|
|
53
56
|
| `docker_inspect` | Container details (image/state/ports) | — |
|
|
54
57
|
| `docker_exec` | Run a command inside a container | Approval gate + container-name validation |
|
|
55
|
-
| `docker_manage` | start / stop / restart / rm |
|
|
58
|
+
| `docker_manage` | start / stop / restart / rm | Approval gate for stop/restart/rm |
|
|
59
|
+
| `docker_health` | Check Docker daemon and safety settings | — |
|
|
56
60
|
|
|
57
61
|
### Examples
|
|
58
62
|
|
|
@@ -69,7 +73,7 @@ docker_manage { container: web, action: restart }
|
|
|
69
73
|
## Safety
|
|
70
74
|
|
|
71
75
|
- **No shell**: every argument is its own argv element — command injection is impossible
|
|
72
|
-
- **Approval
|
|
76
|
+
- **Approval gates**: docker_exec and docker_manage stop/restart/rm ask first; headless environments without an approval channel are denied
|
|
73
77
|
- **Container-name validation**: only `[A-Za-z0-9][A-Za-z0-9_.:-]*` accepted — no argument injection
|
|
74
78
|
- **Timeout clamps**: 5s - 10min per operation; follow mode capped at an extra 30s
|
|
75
79
|
- **Log clamping**: tail 1-2000 lines
|
|
@@ -78,7 +82,7 @@ docker_manage { container: web, action: restart }
|
|
|
78
82
|
|
|
79
83
|
```bash
|
|
80
84
|
pnpm install
|
|
81
|
-
pnpm test # build +
|
|
85
|
+
pnpm test # build + 35 tests
|
|
82
86
|
```
|
|
83
87
|
|
|
84
88
|
## License
|
package/README.md
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
# dsh-docker
|
|
4
4
|
|
|
5
|
-
> **你的 agent
|
|
5
|
+
> **你的 agent 会管容器了**:七个工具覆盖容器/镜像列表、日志、详情、容器内执行、生命周期管理与健康检查。
|
|
6
6
|
|
|
7
|
-
DSH(DeepSeek Harness)容器管理插件:走官方 subprocess 服务跑 docker CLI,argv 数组无 shell 注入,`docker_exec`
|
|
7
|
+
DSH(DeepSeek Harness)容器管理插件:走官方 subprocess 服务跑 docker CLI,argv 数组无 shell 注入,`docker_exec` 与破坏性生命周期操作默认审批门,**零运行时依赖**。
|
|
8
8
|
|
|
9
9
|
   
|
|
10
10
|
|
|
@@ -12,7 +12,9 @@ DSH(DeepSeek Harness)容器管理插件:走官方 subprocess 服务跑 doc
|
|
|
12
12
|
|
|
13
13
|
## 兼容性
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
已在官方 `@deepseek-ai/dsh@0.1.5-rc.1`、Node `24.16.0` 上验证(2026-09-11):18 个组件与 Modlens 同载,工具 schema、技能注册及离线只读调用检查通过。采用 `cordis.patch.yml` + `dsh.bundle.patch` 组合包模型。Node 要求与该版本 Harness 一致:22.19 及以上的 22.x,或 24 及以上。外部服务的实际业务操作需按各组件配置单独验证。
|
|
16
|
+
|
|
17
|
+
2026-09-13 修复:保留宿主 `subprocess.spawn` 的服务对象,避免方法独立传递后因 `this` 丢失而报错。已在官方 `0.1.5-rc.1` 和 `0.1.5-rc.2`、Node `24.16.0` 上验证。`docker_ps` 已通过真实宿主进程服务验证;Docker 输出由 Node 子进程生成的固定测试数据提供,未连接真实 Docker daemon。
|
|
16
18
|
|
|
17
19
|
## 安装
|
|
18
20
|
|
|
@@ -41,6 +43,7 @@ dsh plugin --profile web remove @stardustlc/dsh-docker
|
|
|
41
43
|
dockerPath: docker # 可选;也可用环境变量 DSH_DOCKER_PATH
|
|
42
44
|
timeoutMs: 60000 # 单次操作超时(默认 60 秒,5 秒 - 10 分钟)
|
|
43
45
|
# execApproval: false # 关闭 docker_exec 审批门(默认 true)
|
|
46
|
+
# manageApproval: false # 关闭 stop/restart/rm 审批门(默认 true,不推荐)
|
|
44
47
|
```
|
|
45
48
|
|
|
46
49
|
## 工具一览
|
|
@@ -52,7 +55,8 @@ dsh plugin --profile web remove @stardustlc/dsh-docker
|
|
|
52
55
|
| `docker_logs` | 查看日志尾部(行数钳制,可短时 follow)| — |
|
|
53
56
|
| `docker_inspect` | 容器详情(镜像/状态/端口)| — |
|
|
54
57
|
| `docker_exec` | 容器内执行命令 | 审批门 + 容器名白名单校验 |
|
|
55
|
-
| `docker_manage` | start / stop / restart / rm |
|
|
58
|
+
| `docker_manage` | start / stop / restart / rm | stop/restart/rm 审批门 |
|
|
59
|
+
| `docker_health` | Docker daemon 与安全配置自检 | — |
|
|
56
60
|
|
|
57
61
|
### 示例
|
|
58
62
|
|
|
@@ -69,7 +73,7 @@ docker_manage { container: web, action: restart }
|
|
|
69
73
|
## 安全设计
|
|
70
74
|
|
|
71
75
|
- **无 shell**:全部参数独立 argv 数组,命令注入不可能
|
|
72
|
-
- **审批门**:docker_exec
|
|
76
|
+
- **审批门**:docker_exec 与 docker_manage 的 stop/restart/rm 默认弹审批;headless 无审批通道时拒绝
|
|
73
77
|
- **容器名校验**:只允许 `[A-Za-z0-9][A-Za-z0-9_.:-]*`,杜绝参数注入
|
|
74
78
|
- **超时钳制**:单次操作 5 秒 - 10 分钟;follow 模式额外限 30 秒
|
|
75
79
|
- **日志钳制**:tail 1-2000 行
|
|
@@ -78,7 +82,7 @@ docker_manage { container: web, action: restart }
|
|
|
78
82
|
|
|
79
83
|
```bash
|
|
80
84
|
pnpm install
|
|
81
|
-
pnpm test # 构建 +
|
|
85
|
+
pnpm test # 构建 + 35 个测试
|
|
82
86
|
```
|
|
83
87
|
|
|
84
88
|
## License
|
package/cordis.patch.yml
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
# # dockerPath: C:\Program Files\Docker\Docker\resources\bin\docker.exe
|
|
10
10
|
# timeoutMs: 60000 # 单次操作超时(默认 60 秒,5 秒 - 10 分钟)
|
|
11
11
|
# # execApproval: false # 关闭 docker_exec 的审批门(默认 true)
|
|
12
|
+
# # manageApproval: false # 关闭 stop/restart/rm 审批门(默认 true,不推荐)
|
|
12
13
|
#
|
|
13
14
|
- insert:
|
|
14
15
|
- id: docker
|
package/lib/config.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export interface DockerConfig {
|
|
|
9
9
|
timeoutMs?: number;
|
|
10
10
|
graceMs?: number;
|
|
11
11
|
execApproval?: boolean;
|
|
12
|
+
manageApproval?: boolean;
|
|
12
13
|
}
|
|
13
14
|
/** 解析后的配置。 */
|
|
14
15
|
export interface ResolvedDockerConfig {
|
|
@@ -16,6 +17,7 @@ export interface ResolvedDockerConfig {
|
|
|
16
17
|
timeoutMs: number;
|
|
17
18
|
graceMs: number;
|
|
18
19
|
execApproval: boolean;
|
|
20
|
+
manageApproval: boolean;
|
|
19
21
|
}
|
|
20
22
|
/**
|
|
21
23
|
* 解析并校验配置。
|
package/lib/config.js
CHANGED
|
@@ -22,7 +22,8 @@ export function resolveConfig(config, env = process.env) {
|
|
|
22
22
|
graceMs = Math.min(120000, Math.max(1000, Math.round(cfg.graceMs)));
|
|
23
23
|
}
|
|
24
24
|
const execApproval = cfg.execApproval !== false;
|
|
25
|
-
|
|
25
|
+
const manageApproval = cfg.manageApproval !== false;
|
|
26
|
+
return { dockerPath, timeoutMs, graceMs, execApproval, manageApproval };
|
|
26
27
|
}
|
|
27
28
|
/** 校验容器名/ID,防参数注入(只允许字母数字与 _-.:/ 之外的拒绝)。 */
|
|
28
29
|
export function assertContainerRef(value) {
|
package/lib/exec.d.ts
CHANGED
package/lib/exec.js
CHANGED
|
@@ -12,6 +12,9 @@ export function createSubprocessRunner(spawn, graceMs, defaultTimeoutMs) {
|
|
|
12
12
|
const timeoutMs = options?.timeoutMs ?? defaultTimeoutMs;
|
|
13
13
|
const controller = new AbortController();
|
|
14
14
|
const timer = setTimeout(() => controller.abort(new Error('docker operation timed out')), timeoutMs);
|
|
15
|
+
const signal = options?.signal === undefined
|
|
16
|
+
? controller.signal
|
|
17
|
+
: AbortSignal.any([options.signal, controller.signal]);
|
|
15
18
|
let handle;
|
|
16
19
|
try {
|
|
17
20
|
handle = spawn({
|
|
@@ -23,7 +26,7 @@ export function createSubprocessRunner(spawn, graceMs, defaultTimeoutMs) {
|
|
|
23
26
|
stderr: { maxBytes: COLLECT_BYTES },
|
|
24
27
|
},
|
|
25
28
|
graceMs,
|
|
26
|
-
signal
|
|
29
|
+
signal,
|
|
27
30
|
});
|
|
28
31
|
const outcome = await handle.done;
|
|
29
32
|
const stdout = handle.collected.stdout?.readFrom(0).text ?? '';
|
package/lib/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* dsh-docker —— 容器管理工具插件(node 半身,配置走 cordis.patch.yml)。
|
|
3
3
|
*
|
|
4
|
-
* 插件导出 apply(ctx, config)
|
|
5
|
-
* docker_images / docker_inspect / docker_exec / docker_manage)。进程执行走 DSH 官方 subprocess 服务
|
|
6
|
-
* (argv 数组、无 shell),docker_exec 默认走宿主审批门。零运行时依赖。
|
|
4
|
+
* 插件导出 apply(ctx, config):注册七个面向模型的工具(docker_ps / docker_logs /
|
|
5
|
+
* docker_images / docker_inspect / docker_exec / docker_manage / docker_health)。进程执行走 DSH 官方 subprocess 服务
|
|
6
|
+
* (argv 数组、无 shell),docker_exec 与破坏性 docker_manage 默认走宿主审批门。零运行时依赖。
|
|
7
7
|
*
|
|
8
8
|
* @module dsh-docker
|
|
9
9
|
*/
|
|
@@ -23,7 +23,7 @@ type DockerPreToolDecision = {
|
|
|
23
23
|
kind: 'ask';
|
|
24
24
|
reason?: string;
|
|
25
25
|
};
|
|
26
|
-
/**
|
|
26
|
+
/** 审批策略需要读取的工具执行字段。 */
|
|
27
27
|
interface DockerToolExecution {
|
|
28
28
|
readonly name: string;
|
|
29
29
|
readonly arguments: unknown;
|
|
@@ -42,7 +42,7 @@ export interface DockerPluginContext {
|
|
|
42
42
|
on(event: 'dispose', listener: () => void): () => void;
|
|
43
43
|
}
|
|
44
44
|
/**
|
|
45
|
-
*
|
|
45
|
+
* 插件入口:解析配置、封装执行器、注册七工具;为 docker_exec 与破坏性 docker_manage 注入审批门。
|
|
46
46
|
*/
|
|
47
47
|
export declare function apply(ctx: DockerPluginContext, config?: DockerConfig | null): void;
|
|
48
48
|
export * from './args.js';
|
package/lib/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* dsh-docker —— 容器管理工具插件(node 半身,配置走 cordis.patch.yml)。
|
|
3
3
|
*
|
|
4
|
-
* 插件导出 apply(ctx, config)
|
|
5
|
-
* docker_images / docker_inspect / docker_exec / docker_manage)。进程执行走 DSH 官方 subprocess 服务
|
|
6
|
-
* (argv 数组、无 shell),docker_exec 默认走宿主审批门。零运行时依赖。
|
|
4
|
+
* 插件导出 apply(ctx, config):注册七个面向模型的工具(docker_ps / docker_logs /
|
|
5
|
+
* docker_images / docker_inspect / docker_exec / docker_manage / docker_health)。进程执行走 DSH 官方 subprocess 服务
|
|
6
|
+
* (argv 数组、无 shell),docker_exec 与破坏性 docker_manage 默认走宿主审批门。零运行时依赖。
|
|
7
7
|
*
|
|
8
8
|
* @module dsh-docker
|
|
9
9
|
*/
|
|
@@ -14,30 +14,34 @@ import { buildDockerTools } from './tools.js';
|
|
|
14
14
|
export const name = 'docker';
|
|
15
15
|
export const inject = ['subprocess', 'tools'];
|
|
16
16
|
/**
|
|
17
|
-
*
|
|
17
|
+
* 插件入口:解析配置、封装执行器、注册七工具;为 docker_exec 与破坏性 docker_manage 注入审批门。
|
|
18
18
|
*/
|
|
19
19
|
export function apply(ctx, config) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
cfg = resolveConfig(config);
|
|
23
|
-
}
|
|
24
|
-
catch (error) {
|
|
25
|
-
console.warn('[dsh-docker] ' + (error instanceof Error ? error.message : String(error)));
|
|
26
|
-
cfg = resolveConfig(null);
|
|
27
|
-
}
|
|
28
|
-
const runner = createSubprocessRunner(ctx.subprocess.spawn, cfg.graceMs, cfg.timeoutMs);
|
|
20
|
+
const cfg = resolveConfig(config);
|
|
21
|
+
const runner = createSubprocessRunner((spec) => ctx.subprocess.spawn(spec), cfg.graceMs, cfg.timeoutMs);
|
|
29
22
|
const tools = buildDockerTools(cfg, runner);
|
|
30
|
-
if (cfg.execApproval) {
|
|
23
|
+
if (cfg.execApproval || cfg.manageApproval) {
|
|
31
24
|
ctx.on('tools/pre-execute', async (exec, next) => {
|
|
32
|
-
if (exec.name !== 'docker_exec')
|
|
33
|
-
return next();
|
|
34
25
|
const args = (typeof exec.arguments === 'object' && exec.arguments !== null ? exec.arguments : {});
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
26
|
+
if (exec.name === 'docker_exec' && cfg.execApproval) {
|
|
27
|
+
const command = typeof args.command === 'string' ? args.command : '';
|
|
28
|
+
const container = typeof args.container === 'string' ? args.container : '';
|
|
29
|
+
return {
|
|
30
|
+
kind: 'ask',
|
|
31
|
+
reason: 'docker_exec 需要确认:在容器 ' + (container || '(未指定)') + ' 内执行:' + command.slice(0, 200) + (command.length > 200 ? '…' : ''),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
if (exec.name === 'docker_manage' && cfg.manageApproval) {
|
|
35
|
+
const action = typeof args.action === 'string' ? args.action : '';
|
|
36
|
+
if (action === 'stop' || action === 'restart' || action === 'rm') {
|
|
37
|
+
const container = typeof args.container === 'string' ? args.container : '';
|
|
38
|
+
return {
|
|
39
|
+
kind: 'ask',
|
|
40
|
+
reason: 'docker_manage 需要确认:对容器 ' + (container || '(未指定)') + ' 执行破坏性操作 ' + action + '。',
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return next();
|
|
41
45
|
});
|
|
42
46
|
}
|
|
43
47
|
const disposers = [];
|
package/lib/tools.d.ts
CHANGED
|
@@ -19,5 +19,5 @@ export interface DockerToolDefinition {
|
|
|
19
19
|
execute(args: unknown, exec: unknown): Promise<unknown>;
|
|
20
20
|
timeoutMs?: number;
|
|
21
21
|
}
|
|
22
|
-
/**
|
|
22
|
+
/** 构建七个工具定义。 */
|
|
23
23
|
export declare function buildDockerTools(config: ResolvedDockerConfig, runner: ProcessRunner): DockerToolDefinition[];
|
package/lib/tools.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* 七个面向模型的容器工具:docker_ps / docker_logs / docker_images / docker_inspect /
|
|
3
|
+
* docker_exec / docker_manage / docker_health。
|
|
3
4
|
*
|
|
4
5
|
* @module dsh-docker/tools
|
|
5
6
|
*/
|
|
@@ -34,8 +35,14 @@ function requiredString(args, key, label) {
|
|
|
34
35
|
throw new Error(label + '(参数 ' + key + ')为必填,请提供非空字符串。');
|
|
35
36
|
return value;
|
|
36
37
|
}
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
function executionSignal(exec) {
|
|
39
|
+
if (typeof exec !== 'object' || exec === null)
|
|
40
|
+
return undefined;
|
|
41
|
+
const signal = exec.signal;
|
|
42
|
+
return signal instanceof AbortSignal ? signal : undefined;
|
|
43
|
+
}
|
|
44
|
+
async function runChecked(runner, argv, timeoutMs, label, signal) {
|
|
45
|
+
const result = await runner.run(argv, { timeoutMs, ...(signal === undefined ? {} : { signal }) });
|
|
39
46
|
if (result.exitCode !== 0) {
|
|
40
47
|
const tail = result.stderr.trim().split(/\r?\n/).slice(-6).join(' | ');
|
|
41
48
|
throw new Error(label + '失败(退出码 ' + String(result.exitCode ?? 'null') + '):' + (tail || '无错误输出') + '。请确认 docker 可用(docker version)。');
|
|
@@ -77,7 +84,7 @@ const manageSchema = {
|
|
|
77
84
|
properties: { container: { type: 'string' }, action: { type: 'string' }, output: { type: 'string' } },
|
|
78
85
|
additionalProperties: true,
|
|
79
86
|
};
|
|
80
|
-
/**
|
|
87
|
+
/** 构建七个工具定义。 */
|
|
81
88
|
export function buildDockerTools(config, runner) {
|
|
82
89
|
const cfg = config;
|
|
83
90
|
const timeout = cfg.timeoutMs;
|
|
@@ -101,10 +108,10 @@ export function buildDockerTools(config, runner) {
|
|
|
101
108
|
return [{ type: 'text', text: lines.join('\n') }];
|
|
102
109
|
},
|
|
103
110
|
},
|
|
104
|
-
async execute(rawArgs) {
|
|
111
|
+
async execute(rawArgs, exec) {
|
|
105
112
|
const args = asRecord(rawArgs);
|
|
106
113
|
const all = args.all === true;
|
|
107
|
-
const result = await runChecked(runner, psArgs(cfg.dockerPath, all, optionalString(args, 'name')), timeout, 'docker ps');
|
|
114
|
+
const result = await runChecked(runner, psArgs(cfg.dockerPath, all, optionalString(args, 'name')), timeout, 'docker ps', executionSignal(exec));
|
|
108
115
|
const containers = parsePsJson(result.stdout);
|
|
109
116
|
return { count: containers.length, all, containers };
|
|
110
117
|
},
|
|
@@ -125,13 +132,13 @@ export function buildDockerTools(config, runner) {
|
|
|
125
132
|
return [{ type: 'text', text: '容器 ' + rec.container + ' 最近日志:\n' + rec.text }];
|
|
126
133
|
},
|
|
127
134
|
},
|
|
128
|
-
async execute(rawArgs) {
|
|
135
|
+
async execute(rawArgs, exec) {
|
|
129
136
|
const args = asRecord(rawArgs);
|
|
130
137
|
const container = assertContainerRef(requiredString(args, 'container', '容器名'));
|
|
131
138
|
const tailRaw = args.tail;
|
|
132
139
|
const tail = typeof tailRaw === 'number' && Number.isInteger(tailRaw) ? Math.min(2000, Math.max(1, tailRaw)) : 100;
|
|
133
140
|
const follow = args.follow === true;
|
|
134
|
-
const result = await runChecked(runner, logsArgs(cfg.dockerPath, container, tail, follow), follow ? Math.min(timeout, 30000) : timeout, 'docker logs');
|
|
141
|
+
const result = await runChecked(runner, logsArgs(cfg.dockerPath, container, tail, follow), follow ? Math.min(timeout, 30000) : timeout, 'docker logs', executionSignal(exec));
|
|
135
142
|
return { container, tail, text: result.stdout };
|
|
136
143
|
},
|
|
137
144
|
timeoutMs: timeout,
|
|
@@ -155,10 +162,10 @@ export function buildDockerTools(config, runner) {
|
|
|
155
162
|
return [{ type: 'text', text: lines.join('\n') }];
|
|
156
163
|
},
|
|
157
164
|
},
|
|
158
|
-
async execute(rawArgs) {
|
|
165
|
+
async execute(rawArgs, exec) {
|
|
159
166
|
const args = asRecord(rawArgs);
|
|
160
167
|
const dangling = args.dangling === true;
|
|
161
|
-
const result = await runChecked(runner, imagesArgs(cfg.dockerPath, dangling), timeout, 'docker images');
|
|
168
|
+
const result = await runChecked(runner, imagesArgs(cfg.dockerPath, dangling), timeout, 'docker images', executionSignal(exec));
|
|
162
169
|
const images = parseImagesJson(result.stdout);
|
|
163
170
|
return { count: images.length, dangling, images };
|
|
164
171
|
},
|
|
@@ -178,10 +185,10 @@ export function buildDockerTools(config, runner) {
|
|
|
178
185
|
return [{ type: 'text', text: '容器 ' + info.name + '(' + info.image + '):' + (info.running === true ? '运行中' : '已停止') + ',端口:' + (Array.isArray(info.ports) ? info.ports.join(', ') : '无') }];
|
|
179
186
|
},
|
|
180
187
|
},
|
|
181
|
-
async execute(rawArgs) {
|
|
188
|
+
async execute(rawArgs, exec) {
|
|
182
189
|
const args = asRecord(rawArgs);
|
|
183
190
|
const container = assertContainerRef(requiredString(args, 'container', '容器名'));
|
|
184
|
-
const result = await runChecked(runner, inspectArgs(cfg.dockerPath, container), timeout, 'docker inspect');
|
|
191
|
+
const result = await runChecked(runner, inspectArgs(cfg.dockerPath, container), timeout, 'docker inspect', executionSignal(exec));
|
|
185
192
|
return { container, info: parseInspectJson(result.stdout) };
|
|
186
193
|
},
|
|
187
194
|
timeoutMs: timeout,
|
|
@@ -200,20 +207,20 @@ export function buildDockerTools(config, runner) {
|
|
|
200
207
|
return [{ type: 'text', text: '容器 ' + rec.container + ' 执行完成(退出码 ' + rec.exitCode + '):\n' + rec.stdout }];
|
|
201
208
|
},
|
|
202
209
|
},
|
|
203
|
-
async execute(rawArgs) {
|
|
210
|
+
async execute(rawArgs, exec) {
|
|
204
211
|
const args = asRecord(rawArgs);
|
|
205
212
|
const container = assertContainerRef(requiredString(args, 'container', '容器名'));
|
|
206
213
|
const command = splitCommand(requiredString(args, 'command', '命令'));
|
|
207
214
|
if (command.length === 0)
|
|
208
215
|
throw new Error('command 不能为空。');
|
|
209
|
-
const result = await runChecked(runner, execArgs(cfg.dockerPath, container, command), timeout, 'docker exec');
|
|
216
|
+
const result = await runChecked(runner, execArgs(cfg.dockerPath, container, command), timeout, 'docker exec', executionSignal(exec));
|
|
210
217
|
return { container, exitCode: result.exitCode, stdout: result.stdout };
|
|
211
218
|
},
|
|
212
219
|
timeoutMs: timeout,
|
|
213
220
|
};
|
|
214
221
|
const dockerManage = {
|
|
215
222
|
name: 'docker_manage',
|
|
216
|
-
description: '容器生命周期管理:start / stop / restart / rm(rm
|
|
223
|
+
description: '容器生命周期管理:start / stop / restart / rm(rm 强制删除)。stop/restart/rm 默认进入审批门,批准后才执行。',
|
|
217
224
|
parameters: compileParameters({
|
|
218
225
|
container: { type: 'string', required: true, description: '容器名或 ID(必填)。' },
|
|
219
226
|
action: { type: 'string', required: true, description: '操作:start / stop / restart / rm(必填)。' },
|
|
@@ -225,20 +232,20 @@ export function buildDockerTools(config, runner) {
|
|
|
225
232
|
return [{ type: 'text', text: '容器 ' + rec.container + ' 已执行 ' + rec.action + '。' }];
|
|
226
233
|
},
|
|
227
234
|
},
|
|
228
|
-
async execute(rawArgs) {
|
|
235
|
+
async execute(rawArgs, exec) {
|
|
229
236
|
const args = asRecord(rawArgs);
|
|
230
237
|
const container = assertContainerRef(requiredString(args, 'container', '容器名'));
|
|
231
238
|
const action = requiredString(args, 'action', '操作');
|
|
232
239
|
if (!['start', 'stop', 'restart', 'rm'].includes(action))
|
|
233
240
|
throw new Error('action 必须是 start / stop / restart / rm 之一(当前:' + action + ')。');
|
|
234
|
-
const result = await runChecked(runner, manageArgs(cfg.dockerPath, action, container), timeout, 'docker ' + action);
|
|
241
|
+
const result = await runChecked(runner, manageArgs(cfg.dockerPath, action, container), timeout, 'docker ' + action, executionSignal(exec));
|
|
235
242
|
return { container, action, output: result.stdout.trim() };
|
|
236
243
|
},
|
|
237
244
|
timeoutMs: timeout,
|
|
238
245
|
};
|
|
239
246
|
const dockerHealth = {
|
|
240
247
|
name: 'docker_health',
|
|
241
|
-
description: 'dsh-docker 自检:验证 docker CLI 与守护进程是否可用(执行 docker version),并汇总安全配置(exec 审批门、超时)。遇到问题时先运行本工具定位。',
|
|
248
|
+
description: 'dsh-docker 自检:验证 docker CLI 与守护进程是否可用(执行 docker version),并汇总安全配置(exec/破坏性 manage 审批门、超时)。遇到问题时先运行本工具定位。',
|
|
242
249
|
parameters: compileParameters({}),
|
|
243
250
|
output: {
|
|
244
251
|
schema: { type: 'object', additionalProperties: true },
|
|
@@ -253,18 +260,21 @@ export function buildDockerTools(config, runner) {
|
|
|
253
260
|
return [{ type: 'text', text: lines.join('\n') }];
|
|
254
261
|
},
|
|
255
262
|
},
|
|
256
|
-
async execute() {
|
|
263
|
+
async execute(_rawArgs, exec) {
|
|
257
264
|
const checks = [];
|
|
258
265
|
let ok = true;
|
|
259
266
|
try {
|
|
260
|
-
const result = await runChecked(runner, [cfg.dockerPath, 'version', '--format', '{{.Server.Version}}'], 15000, 'docker version');
|
|
267
|
+
const result = await runChecked(runner, [cfg.dockerPath, 'version', '--format', '{{.Server.Version}}'], 15000, 'docker version', executionSignal(exec));
|
|
261
268
|
checks.push({ name: 'docker daemon', ok: true, detail: 'server ' + result.stdout.trim() });
|
|
262
269
|
}
|
|
263
270
|
catch (error) {
|
|
271
|
+
if (executionSignal(exec)?.aborted === true)
|
|
272
|
+
throw error;
|
|
264
273
|
ok = false;
|
|
265
274
|
checks.push({ name: 'docker daemon', ok: false, detail: error instanceof Error ? error.message : String(error) });
|
|
266
275
|
}
|
|
267
276
|
checks.push({ name: 'exec 审批门', ok: true, detail: cfg.execApproval === true ? '开启' : '关闭' });
|
|
277
|
+
checks.push({ name: 'manage 审批门', ok: true, detail: cfg.manageApproval === true ? '开启' : '关闭' });
|
|
268
278
|
checks.push({ name: '超时配置', ok: true, detail: 'timeoutMs=' + cfg.timeoutMs + ', graceMs=' + cfg.graceMs });
|
|
269
279
|
return { ok, plugin: 'dsh-docker', checks };
|
|
270
280
|
},
|
package/package.json
CHANGED
|
@@ -1,59 +1,59 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@stardustlc/dsh-docker",
|
|
3
|
-
"version": "0.3.
|
|
4
|
-
"description": "DSH
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "lib/index.js",
|
|
7
|
-
"types": "lib/index.d.ts",
|
|
8
|
-
"exports": {
|
|
9
|
-
".": {
|
|
10
|
-
"types": "./lib/index.d.ts",
|
|
11
|
-
"default": "./lib/index.js"
|
|
12
|
-
},
|
|
13
|
-
"./cordis.patch.yml": "./cordis.patch.yml",
|
|
14
|
-
"./package.json": "./package.json"
|
|
15
|
-
},
|
|
16
|
-
"files": [
|
|
17
|
-
"lib",
|
|
18
|
-
"cordis.patch.yml",
|
|
19
|
-
"README.md",
|
|
20
|
-
"README.en.md"
|
|
21
|
-
],
|
|
22
|
-
"scripts": {
|
|
23
|
-
"build": "tsc -p tsconfig.json",
|
|
24
|
-
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
25
|
-
"test": "pnpm run build && node --test \"test/*.test.mjs\"",
|
|
26
|
-
"prepublishOnly": "pnpm run build"
|
|
27
|
-
},
|
|
28
|
-
"dsh": {
|
|
29
|
-
"bundle": {
|
|
30
|
-
"patch": "./cordis.patch.yml"
|
|
31
|
-
}
|
|
32
|
-
},
|
|
33
|
-
"keywords": [
|
|
34
|
-
"dsh",
|
|
35
|
-
"deepseek-harness",
|
|
36
|
-
"plugin",
|
|
37
|
-
"docker",
|
|
38
|
-
"container",
|
|
39
|
-
"devops"
|
|
40
|
-
],
|
|
41
|
-
"license": "MIT",
|
|
42
|
-
"engines": {
|
|
43
|
-
"node": ">=
|
|
44
|
-
},
|
|
45
|
-
"devDependencies": {
|
|
46
|
-
"@types/node": "^24.0.0",
|
|
47
|
-
"typescript": "^5.6.0"
|
|
48
|
-
},
|
|
49
|
-
"repository": {
|
|
50
|
-
"type": "git",
|
|
51
|
-
"url": "git+https://github.com/STARDUSTLC666/dsh-docker.git"
|
|
52
|
-
},
|
|
53
|
-
"bugs": {
|
|
54
|
-
"url": "https://github.com/STARDUSTLC666/dsh-docker/issues"
|
|
55
|
-
},
|
|
56
|
-
"homepage": "https://github.com/STARDUSTLC666/dsh-docker#readme",
|
|
57
|
-
"author": "stardustlc",
|
|
58
|
-
"packageManager": "pnpm@11.7.0"
|
|
59
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@stardustlc/dsh-docker",
|
|
3
|
+
"version": "0.3.3",
|
|
4
|
+
"description": "DSH 容器管理插件:七工具覆盖容器与镜像管理,走官方 subprocess 服务、argv 无 shell 注入,exec 与破坏性 manage 默认审批。",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "lib/index.js",
|
|
7
|
+
"types": "lib/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./lib/index.d.ts",
|
|
11
|
+
"default": "./lib/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./cordis.patch.yml": "./cordis.patch.yml",
|
|
14
|
+
"./package.json": "./package.json"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"lib",
|
|
18
|
+
"cordis.patch.yml",
|
|
19
|
+
"README.md",
|
|
20
|
+
"README.en.md"
|
|
21
|
+
],
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsc -p tsconfig.json",
|
|
24
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
25
|
+
"test": "pnpm run build && node --test \"test/*.test.mjs\"",
|
|
26
|
+
"prepublishOnly": "pnpm run build"
|
|
27
|
+
},
|
|
28
|
+
"dsh": {
|
|
29
|
+
"bundle": {
|
|
30
|
+
"patch": "./cordis.patch.yml"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"keywords": [
|
|
34
|
+
"dsh",
|
|
35
|
+
"deepseek-harness",
|
|
36
|
+
"plugin",
|
|
37
|
+
"docker",
|
|
38
|
+
"container",
|
|
39
|
+
"devops"
|
|
40
|
+
],
|
|
41
|
+
"license": "MIT",
|
|
42
|
+
"engines": {
|
|
43
|
+
"node": "^22.19.0 || >=24.0.0"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@types/node": "^24.0.0",
|
|
47
|
+
"typescript": "^5.6.0"
|
|
48
|
+
},
|
|
49
|
+
"repository": {
|
|
50
|
+
"type": "git",
|
|
51
|
+
"url": "git+https://github.com/STARDUSTLC666/dsh-docker.git"
|
|
52
|
+
},
|
|
53
|
+
"bugs": {
|
|
54
|
+
"url": "https://github.com/STARDUSTLC666/dsh-docker/issues"
|
|
55
|
+
},
|
|
56
|
+
"homepage": "https://github.com/STARDUSTLC666/dsh-docker#readme",
|
|
57
|
+
"author": "stardustlc",
|
|
58
|
+
"packageManager": "pnpm@11.7.0"
|
|
59
|
+
}
|