@hyzyn/dsh-docker 0.6.1 → 0.6.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 +6 -3
- package/README.md +8 -3
- package/client.js +26 -23
- package/lib/index.js +19 -19
- package/lib/index.js.map +1 -1
- package/lib/ssh-exec.js +1 -1
- package/lib/ssh-exec.js.map +1 -1
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -57,7 +57,7 @@ const KNOWN_CONFIG_KEYS = new Set([
|
|
|
57
57
|
* ------------------------------------------------------------------ */
|
|
58
58
|
const ROUTE_PREFIX = '/api/dsh-docker';
|
|
59
59
|
const BODY_LIMIT = 1024 * 1024;
|
|
60
|
-
const DOCKER_GUIDANCE = '本机已安装 dsh-docker 插件(Docker 容器面板):Web GUI 侧边栏「容器」入口可查看各目标(本机 / SSH 主机)上的容器列表(含 Compose 项目视图、事件「活动」条)、状态、端口、日志(含实时跟随)与资源占用(含实时跟随 + 迷你趋势图),以及镜像列表与镜像详情(层 / 大小 / 构建历史、拉取进度流)、网络与卷(列表 + 详情;删除 / 清理同样在开关之后);目标在
|
|
60
|
+
const DOCKER_GUIDANCE = '本机已安装 dsh-docker 插件(Docker 容器面板):Web GUI 侧边栏「容器」入口可查看各目标(本机 / SSH 主机)上的容器列表(含 Compose 项目视图、事件「活动」条)、状态、端口、日志(含实时跟随)与资源占用(含实时跟随 + 迷你趋势图),以及镜像列表与镜像详情(层 / 大小 / 构建历史、拉取进度流)、网络与卷(列表 + 详情;删除 / 清理同样在开关之后);目标在 插件配置 → Docker 容器面板 里维护(SSH 目标可直接引用 tty 终端面板的连接簿条目)。**默认只读**:启动/停止/重启/删除容器、删除镜像 / 清理 dangling / 拉取镜像、docker exec,都需要用户在设置里显式打开「允许变更操作」「允许 exec」后才有对应工具与按钮。agent 侧配套只读工具 docker_targets(列目标)、docker_ps(列容器,含 compose 项目与服务;**target 传 `*` 可一次列出所有目标**)、docker_attention(**需关注汇总**:unhealthy / 反复重启 / OOM / 非零退出 / 僵死,同样支持 `*` 跨目标)、docker_inspect(容器详情)、docker_logs(日志快照)、docker_stats(CPU/内存/IO 快照)、docker_images(镜像列表)、docker_image_inspect(镜像详情 + 构建历史)、docker_events(容器事件快照,见面板容器列表的「活动」条)、docker_networks(网络列表)、docker_volumes(卷列表);排障推荐顺序:不确定从哪台/哪个容器看起时先 docker_attention(可 `*` 跨目标)→ docker_ps → docker_logs → docker_inspect → docker_stats → docker_events,镜像排查用 docker_images → docker_image_inspect。docker_action(容器生命周期)、docker_image_remove(删镜像)、docker_image_prune(清理 dangling)、docker_image_pull(拉取镜像)、docker_exec 仅在用户打开对应开关后可用,执行前须确认目标,破坏性操作(容器 remove / 镜像删除与清理)要向用户复述后果。网络 / 卷的删除与 prune 目前只提供面板按钮(HTTP 端点),没有对应的 agent 工具——不要在 agent 侧绕过面板做这些变更。docker socket 等价于目标主机的 root 权限,不要在用户未明确要求时执行变更操作。';
|
|
61
61
|
/**
|
|
62
62
|
* SSE 帧封装:data 一律 `JSON.stringify` 成**单行**——换行 / 引号被转义,
|
|
63
63
|
* 多字节字符也不会被 SSE 的 `\n` 行边界截断(客户端 JSON.parse 还原)。
|
|
@@ -441,7 +441,7 @@ const plugin = definePlugin({
|
|
|
441
441
|
return { name: fallback };
|
|
442
442
|
const list = targetsNow();
|
|
443
443
|
if (list.length === 0)
|
|
444
|
-
return { error: '尚未配置任何 Docker
|
|
444
|
+
return { error: '尚未配置任何 Docker 目标(插件配置 → Docker 容器面板)' };
|
|
445
445
|
return { error: 'target 必填(已配置多个目标:' + list.map((item) => item.name).join('、') + ')' };
|
|
446
446
|
};
|
|
447
447
|
/**
|
|
@@ -673,7 +673,7 @@ const plugin = definePlugin({
|
|
|
673
673
|
let registeredNames = [];
|
|
674
674
|
const renderTargets = (rows) => {
|
|
675
675
|
if (rows.length === 0)
|
|
676
|
-
return '尚未配置任何 Docker
|
|
676
|
+
return '尚未配置任何 Docker 目标(插件配置 → Docker 容器面板 → 目标)。';
|
|
677
677
|
return 'Docker 目标:' + rows.map((row) => {
|
|
678
678
|
const state = row.ok === undefined ? '' : row.ok ? ' [可达]' : ` [不可用:${row.error ?? '未知'}]`;
|
|
679
679
|
return `\n- ${row.name} (${row.kind}) ${row.label}${state}`;
|
|
@@ -697,7 +697,7 @@ const plugin = definePlugin({
|
|
|
697
697
|
/** 跨目标容器渲染:按目标分组,失败的目标单独一行说明(部分成功也要可读)。 */
|
|
698
698
|
const renderAggregatedContainers = (groups) => {
|
|
699
699
|
if (groups.length === 0)
|
|
700
|
-
return '尚未配置任何 Docker
|
|
700
|
+
return '尚未配置任何 Docker 目标(插件配置 → Docker 容器面板)。';
|
|
701
701
|
const total = groups.reduce((sum, group) => sum + (group.containers?.length ?? 0), 0);
|
|
702
702
|
const failed = groups.filter((group) => !group.ok);
|
|
703
703
|
const head = `所有目标共 ${String(total)} 个容器(${String(groups.length)} 个目标${failed.length > 0 ? `,${String(failed.length)} 个不可达` : ''}):`;
|
|
@@ -1553,7 +1553,7 @@ const plugin = definePlugin({
|
|
|
1553
1553
|
},
|
|
1554
1554
|
async execute(args) {
|
|
1555
1555
|
if (!live.allowMutations)
|
|
1556
|
-
throw new Error('
|
|
1556
|
+
throw new Error('变更操作未启用(插件配置 → Docker 容器面板 → 允许变更操作)');
|
|
1557
1557
|
const input = (args ?? {});
|
|
1558
1558
|
const picked = pickTarget(input.target);
|
|
1559
1559
|
if (picked.name === undefined)
|
|
@@ -1595,7 +1595,7 @@ const plugin = definePlugin({
|
|
|
1595
1595
|
},
|
|
1596
1596
|
async execute(args) {
|
|
1597
1597
|
if (!live.allowMutations)
|
|
1598
|
-
throw new Error('
|
|
1598
|
+
throw new Error('变更操作未启用(插件配置 → Docker 容器面板 → 允许变更操作)');
|
|
1599
1599
|
const input = (args ?? {});
|
|
1600
1600
|
const picked = pickTarget(input.target);
|
|
1601
1601
|
if (picked.name === undefined)
|
|
@@ -1629,7 +1629,7 @@ const plugin = definePlugin({
|
|
|
1629
1629
|
},
|
|
1630
1630
|
async execute(args) {
|
|
1631
1631
|
if (!live.allowMutations)
|
|
1632
|
-
throw new Error('
|
|
1632
|
+
throw new Error('变更操作未启用(插件配置 → Docker 容器面板 → 允许变更操作)');
|
|
1633
1633
|
const input = (args ?? {});
|
|
1634
1634
|
const picked = pickTarget(input.target);
|
|
1635
1635
|
if (picked.name === undefined)
|
|
@@ -1669,7 +1669,7 @@ const plugin = definePlugin({
|
|
|
1669
1669
|
},
|
|
1670
1670
|
async execute(args) {
|
|
1671
1671
|
if (!live.allowMutations)
|
|
1672
|
-
throw new Error('
|
|
1672
|
+
throw new Error('变更操作未启用(插件配置 → Docker 容器面板 → 允许变更操作)');
|
|
1673
1673
|
const input = (args ?? {});
|
|
1674
1674
|
const picked = pickTarget(input.target);
|
|
1675
1675
|
if (picked.name === undefined)
|
|
@@ -1728,7 +1728,7 @@ const plugin = definePlugin({
|
|
|
1728
1728
|
},
|
|
1729
1729
|
async execute(args) {
|
|
1730
1730
|
if (!live.allowExec)
|
|
1731
|
-
throw new Error('exec
|
|
1731
|
+
throw new Error('exec 未启用(插件配置 → Docker 容器面板 → 允许 exec)');
|
|
1732
1732
|
const input = (args ?? {});
|
|
1733
1733
|
const picked = pickTarget(input.target);
|
|
1734
1734
|
if (picked.name === undefined)
|
|
@@ -2041,7 +2041,7 @@ const plugin = definePlugin({
|
|
|
2041
2041
|
*/
|
|
2042
2042
|
const servePullStream = async (req, res, params) => {
|
|
2043
2043
|
if (!live.allowMutations) {
|
|
2044
|
-
writeJson(res, 403, { error: '
|
|
2044
|
+
writeJson(res, 403, { error: '变更操作未启用(插件配置 → Docker 容器面板 → 允许变更操作)' });
|
|
2045
2045
|
return;
|
|
2046
2046
|
}
|
|
2047
2047
|
const picked = pickTarget(params.get('target'));
|
|
@@ -2098,7 +2098,7 @@ const plugin = definePlugin({
|
|
|
2098
2098
|
// UI 入口(不能一并关掉,否则卡片消失就没有恢复路径了);其余数据路由一律
|
|
2099
2099
|
// 403——agent 工具已由 refreshTools 同步清空,这里只管 HTTP 半体。
|
|
2100
2100
|
if (!live.enabled && sub !== '/config') {
|
|
2101
|
-
writeJson(res, 403, { error: '
|
|
2101
|
+
writeJson(res, 403, { error: '插件已禁用(插件配置 → Docker 容器面板 → 启用插件)' });
|
|
2102
2102
|
return;
|
|
2103
2103
|
}
|
|
2104
2104
|
if (sub === '/config') {
|
|
@@ -2307,7 +2307,7 @@ const plugin = definePlugin({
|
|
|
2307
2307
|
}
|
|
2308
2308
|
case '/images/remove': {
|
|
2309
2309
|
if (!live.allowMutations) {
|
|
2310
|
-
writeJson(res, 403, { error: '
|
|
2310
|
+
writeJson(res, 403, { error: '变更操作未启用(插件配置 → Docker 容器面板 → 允许变更操作)' });
|
|
2311
2311
|
return;
|
|
2312
2312
|
}
|
|
2313
2313
|
if (typeof body.ref !== 'string' || body.ref.trim() === '') {
|
|
@@ -2319,7 +2319,7 @@ const plugin = definePlugin({
|
|
|
2319
2319
|
}
|
|
2320
2320
|
case '/images/prune': {
|
|
2321
2321
|
if (!live.allowMutations) {
|
|
2322
|
-
writeJson(res, 403, { error: '
|
|
2322
|
+
writeJson(res, 403, { error: '变更操作未启用(插件配置 → Docker 容器面板 → 允许变更操作)' });
|
|
2323
2323
|
return;
|
|
2324
2324
|
}
|
|
2325
2325
|
writeJson(res, 200, { ok: true, result: await api.imagePrune() });
|
|
@@ -2339,7 +2339,7 @@ const plugin = definePlugin({
|
|
|
2339
2339
|
}
|
|
2340
2340
|
case '/networks/remove': {
|
|
2341
2341
|
if (!live.allowMutations) {
|
|
2342
|
-
writeJson(res, 403, { error: '
|
|
2342
|
+
writeJson(res, 403, { error: '变更操作未启用(插件配置 → Docker 容器面板 → 允许变更操作)' });
|
|
2343
2343
|
return;
|
|
2344
2344
|
}
|
|
2345
2345
|
if (typeof body.name !== 'string' || body.name.trim() === '') {
|
|
@@ -2351,7 +2351,7 @@ const plugin = definePlugin({
|
|
|
2351
2351
|
}
|
|
2352
2352
|
case '/networks/prune': {
|
|
2353
2353
|
if (!live.allowMutations) {
|
|
2354
|
-
writeJson(res, 403, { error: '
|
|
2354
|
+
writeJson(res, 403, { error: '变更操作未启用(插件配置 → Docker 容器面板 → 允许变更操作)' });
|
|
2355
2355
|
return;
|
|
2356
2356
|
}
|
|
2357
2357
|
writeJson(res, 200, { ok: true, result: await api.networkPrune() });
|
|
@@ -2371,7 +2371,7 @@ const plugin = definePlugin({
|
|
|
2371
2371
|
}
|
|
2372
2372
|
case '/volumes/remove': {
|
|
2373
2373
|
if (!live.allowMutations) {
|
|
2374
|
-
writeJson(res, 403, { error: '
|
|
2374
|
+
writeJson(res, 403, { error: '变更操作未启用(插件配置 → Docker 容器面板 → 允许变更操作)' });
|
|
2375
2375
|
return;
|
|
2376
2376
|
}
|
|
2377
2377
|
if (typeof body.name !== 'string' || body.name.trim() === '') {
|
|
@@ -2383,7 +2383,7 @@ const plugin = definePlugin({
|
|
|
2383
2383
|
}
|
|
2384
2384
|
case '/volumes/prune': {
|
|
2385
2385
|
if (!live.allowMutations) {
|
|
2386
|
-
writeJson(res, 403, { error: '
|
|
2386
|
+
writeJson(res, 403, { error: '变更操作未启用(插件配置 → Docker 容器面板 → 允许变更操作)' });
|
|
2387
2387
|
return;
|
|
2388
2388
|
}
|
|
2389
2389
|
writeJson(res, 200, { ok: true, result: await api.volumePrune() });
|
|
@@ -2391,7 +2391,7 @@ const plugin = definePlugin({
|
|
|
2391
2391
|
}
|
|
2392
2392
|
case '/action': {
|
|
2393
2393
|
if (!live.allowMutations) {
|
|
2394
|
-
writeJson(res, 403, { error: '
|
|
2394
|
+
writeJson(res, 403, { error: '变更操作未启用(插件配置 → Docker 容器面板 → 允许变更操作)' });
|
|
2395
2395
|
return;
|
|
2396
2396
|
}
|
|
2397
2397
|
if (typeof body.id !== 'string') {
|
|
@@ -2408,7 +2408,7 @@ const plugin = definePlugin({
|
|
|
2408
2408
|
}
|
|
2409
2409
|
case '/exec': {
|
|
2410
2410
|
if (!live.allowExec) {
|
|
2411
|
-
writeJson(res, 403, { error: 'exec
|
|
2411
|
+
writeJson(res, 403, { error: 'exec 未启用(插件配置 → Docker 容器面板 → 允许 exec)' });
|
|
2412
2412
|
return;
|
|
2413
2413
|
}
|
|
2414
2414
|
if (typeof body.id !== 'string' || typeof body.command !== 'string') {
|