DeepSeek Harness Hub
← 返回列表

Compose 面板yizhixiaokong/dsh-compose-panel

DeepSeek 客户端兼容 / 相关生态spec-screened在 GitHub 查看 ↗
未验证

在侧栏分组管理 Compose 项目并查看实时日志

尚未跑自动兼容性验证,可查看页面内的依赖与入口分析。 · 最近上游提交 2026/9/16 · 已提供中文文档
综合分
30
GitHub 分
30
用户评分
★ Stars
0
周下载量
兼容 / 相关生态插件(非 dsh 原生,请按其对应运行时安装)
git clone https://github.com/yizhixiaokong/dsh-compose-panel.git
数据截至 2026/9/16(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis
用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动

README

dsh-compose-panel

DSH
CI
license: MIT
dsh-plugin

一个 DeepSeek Harness 插件:把 Docker
Compose 项目放进原生右侧栏——每个项目目录一组、每个容器实时状态、悬停即可
启停或重启、每个服务一个流式日志标签页。

它针对的正是单文件容器面板会做错的那种工作区布局:一个仓库里的多个子目录各自
拥有自己的 compose.yaml。

工作区 ~/work/shop
├── compose.yaml            → 分组 “shop”           2/2 运行中
├── services/api/compose.yaml  → 分组 “services/api” 1/3 运行中
└── tools/mail/compose.yaml    → 分组 “tools/mail”  未启动

截图

右侧栏里的面板:每个项目目录一个可折叠分组,容器状态汇总在标题右侧。

容器面板:每个项目目录一组,每个容器一行,状态右对齐

鼠标停在某行时,状态单元格会被该行适用的操作替代——分组标题上是项目级操作,容器行上是单服务操作。

悬停时操作按钮替代状态栏,结果由横幅提示

点击容器行即为该服务打开流式日志标签页。

单服务日志页,带回放行数、时间戳与换行控制

功能

- 每个项目目录一组。 项目以目录为键,绝不用 compose 项目名,因此 -p、
COMPOSE_PROJECT_NAME 和 .env 都无法把两套不同的栈合并成一行。
- 三种发现来源。 运行中与已停止的容器、Docker 已知但当前没有容器的项目、
以及从未启动过的 compose 文件——三者都会出现,所以一个没动过的
compose.yaml 也会显示为“未启动”的项目,而不是消失。
- 限定在工作区内。 只列出 DSH 工作区内的项目;目录归属按最长匹配确定,工作区
之外的容器会被统计出来而不是被悄悄丢弃。
- 可折叠分组、状态右对齐、行高固定(指针划过时页面不会跳动)。
- 悬停操作。 鼠标停在某行时,状态单元格会换成该行适用的操作:项目级的
up -d / restart / stop,或单个服务的同样三项。任何命令都不会在未点击时执行。
- 实时日志流。 点击服务行即为该服务打开日志标签页;点击项目标题则为整个项目
打开。每个目标保留自己的标签页。
- 静默刷新。 空闲时每 45 秒、仍有服务在启动时每 8 秒重新读取一次,且不会丢失
滚动位置、已展开的分组或当前选择。
- 与产品一致的样式:只用 Harness 自己的主题变量,因此自动跟随浅色/深色模式与强调色,
不需要额外设置页。

环境要求

| 要求 | 说明 |
| --- | --- |
| 带 web profile 的 DSH | 插件注册一个右侧栏标签类型和一条 HTTP 路由,二者都由 webServer 提供。 |
| 宿主进程 的 PATH 中有 Docker CLI | docker ps、docker compose ls 以子进程方式执行;需要 compose v2 插件(docker compose,不是 docker-compose)。 |
| POSIX 系统 | 路径按 POSIX 处理;Windows 未经验证。 |
| 至少一个 DSH 工作区 | 只列出已注册工作区之内的目录。 |

安装

直接从 GitHub 安装——不必克隆(想固定版本就钉一个 tag):

dsh plugin --profile web add "github:yizhixiaokong/dsh-compose-panel"
钉版本:dsh plugin --profile web add "github:yizhixiaokong/dsh-compose-panel#v0.1.1"

从克隆安装(需要改代码时):

git clone https://github.com/yizhixiaokong/dsh-compose-panel.git
cd dsh-compose-panel
dsh plugin --profile web add "$PWD"

从 npm 安装:

dsh plugin --profile web add dsh-compose-panel

三种方式结果一致,也都不需要手工登记:dsh plugin 先跑 pnpm,再读取每个已安装依赖的
package.json——声明了 dsh.bundle 的包,其名字会被追加进
dsh.profile.bundles,由它挂载旁边的 cordis.patch.yml。
(没有该声明的依赖只会作为普通库安装并给出警告。)同样没有构建步骤——客户端部分是随
lib/ 一起发布的手写产物。

随后重启 Harness 以加载客户端产物:

dsh web

卸载:

dsh plugin --profile web remove dsh-compose-panel

客户端部分在宿主启动时完成基线化。在运行中的实例里修改 lib/client.js
不会生效,直到 dsh web 重启——刷新浏览器不够。

使用

1. 打开右侧栏,在引导页选择 🐳 容器 胶囊。
2. 每个工作区是一个区块,每个项目目录是一个可折叠分组,标题为目录路径,右侧是
容器状态的汇总。
3. 悬停在项目标题上可对整个项目操作;悬停在容器行上只对该服务操作。指针在行上时,
操作按钮会替代状态单元格,结果通过一条短横幅提示。
4. 点击容器行(不是按钮)为该服务打开日志标签页;点击分组标题打开整个项目的日志。

日志标签页有自己的控件:回放行数(tail)、重新打开流、时间戳开关、自动换行,以及
(整项目标签页的)服务名列。

项目如何被发现

一次 list 调用执行三条命令并按目录合并结果:

| 来源 | 命令 | 贡献 |
| --- | --- | --- |
| 容器 | docker ps -a --format '{{json .}}' | 所有容器,按 com.docker.compose.project.working_dir 标签分组。 |
| 已知项目 | docker compose ls --all --format json | 已存在但当前没有容器的项目(其 ConfigFiles 为绝对路径)。 |
| 未动过的文件 | 每个工作区一次有界的 find | 从未启动过的 compose 文件:深度 4,并剪掉 node_modules、.git、vendor、dist、build、target、.venv、venv、__pycache__、.next、.cache、.tox。 |

项目目录就是连接键。扫描识别的 compose 文件名包括 compose.yml、
compose.yaml、docker-compose.yml、docker-compose.yaml,以及
compose..yml / docker-compose..yml 变体。

HTTP 接口

宿主部分注册一条前缀路由 /compose/api。所有响应使用同一信封:
成功为 {"ok":true,"value":…},失败为
{"ok":false,"error":{"code","message"}}。

任何命令执行之前,请求先经过围栏校验。两个 POST 方法要求 Host 为 loopback
地址(localhost、127.0.0.1、::1、.localhost,可带端口)或位于 web
runtime 的信任列表中;被浏览器标记为 Sec-Fetch-Site: cross-site 的请求会被拒绝;
如果带 Origin,其 host 必须等于 Host。日志流使用读侧变体:socket 对端必须是
loopback(或 Host 受信任)、不得携带转发头(forwarded、x-forwarded-for、
x-real-ip),且允许缺少 Origin——浏览器在同源 EventSource 上不会发送它。

POST /compose/api/list

// 请求——root 可选,不传即列出所有工作区
{ "root": "/home/me/work/shop" }

// 响应 value
{
"workspaces": [{ "path": "/home/me/work/shop", "title": "shop" }],
"groups": [{
"root": "/home/me/work/shop",
"title": "shop",
"scanError": "",
"projects": [/ … /]
}],
"total": 7,       // 所选工作区内的容器数
"outside": 2,     // 找到但在任何工作区之外的容器数
"standalone": 1,  // 没有 compose 项目标签的容器数
"notices": []
}

POST /compose/api/action

{
"action": "restart",          // "up" | "stop" | "restart",封闭集合
"dir": "/home/me/work/shop",  // 项目目录,必须在某个工作区内
"service": "api",             // 可选;省略表示整个项目
"files": ["/home/me/work/shop/compose.yaml"]  // 可选,传给 -f 的 compose 文件
}

// 响应 value;code 是 docker 的退出码,output 是其合并输出
{ "action": "restart", "dir": "…", "service": "api", "code": 0, "output": "" }

这里刻意没有 down:删除容器与数据卷不属于一次侧栏点击该做的事。service 必须匹配
^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$,每个 -f 路径都必须位于 dir 之内。argv
直接交给 spawn,从不经过 shell。

GET /compose/api/logs(Server-Sent Events)

| 参数 | 含义 |
| --- | --- |
| dir | 项目目录(必填,必须在工作区内)。 |
| service | 单个服务;省略即整个项目。 |
| tail | 首次回放行数:默认 200,限制在 1…5000。 |
| timestamps | 为 1 时加上 --timestamps;默认关闭。 |
| file | compose 文件(-f),可重复。不传时宿主从 docker compose ls 推导,再退化为浅层 find。 |

帧为 data: JSON 对象:

{ "open": true, "command": "docker compose -f … logs -f --tail 200 api" }
{ "out": "api-1  | listening on :3000\n" }   // stdout 分片,已按 UTF-8 安全切分
{ "err": "…" }                               // stderr 分片,结构相同
{ "eof": true, "code": 0 }                   // docker 退出
{ "error": "spawn failed: …" }

日志流带 NO_COLOR=1,每 15 秒发送一次注释 ping 以便发现断开的对端,累计 4MB 后停止;
标签页关闭、刷新或跳转时立即结束 docker 进程——logs -f 自己永远不会退出。

限制与已知行为

- 其余操作只读。 只有 up -d、stop、restart 可达,侧栏不会以其他方式改变状态。
- 标签解析。 docker ps 把 compose 项目标签作为逗号分隔字符串返回;compose 标签
从不包含逗号,因此按 , 切分在此是安全的。
- 日志前缀。 Docker 自带的  |  前缀在整项目标签页中保留;在单服务
标签页中默认隐藏,因为它只是在重复标签页标题。
- 首次加载。 首次 list 会为每个工作区执行一次 find;目录树极大时面板需要一点
时间才填满,之后的刷新会复用上次结果。
- 不依赖 shell 插件。 容器状态来自 Docker CLI,因此 Docker 守护进程停止时会显示
错误提示,而不是一个空面板。

开发

lib/index.js        宿主部分——路由、发现、docker 调用
lib/client.js       客户端产物——侧栏标签页、列表、日志查看器
cordis.patch.yml    本包贡献的那一行宿主配置
scripts/smoke.mjs   离线检查(不需要 Docker、Harness 或网络)

npm test          # node scripts/smoke.mjs

冒烟测试会用桩全局变量物化客户端产物,并把宿主部分应用到桩上下文。它锁定两类在线
排查代价很高的故障:工厂内绑定在声明之前被读取(会在 profile 启动时抛错并连带卸载
其后的每个插件行),以及侧栏座位或路由集合发生变化。

修改 lib/client.js 或 lib/index.js 之后需要重启 dsh web——客户端产物在启动时
完成基线化。

仓库说明

版本 tag 与 package.json 保持一致——当前这棵树是 v0.1.1。

package.json、CHANGELOG.md、徽章以及上文安装命令中的 yizhixiaokong 占位符代表本仓库
将要推送到的 GitHub 账号,发布前请替换。本仓库的提交使用中性的
dsh-plugins  身份,以免把个人邮箱带进公开历史;若希望署自己
的名字,可设置 git config user.name / user.email 后在推送前执行
git commit --amend --reset-author。

进入插件市场

awesome-dsh-plugin
的插件列表由「一个插件一个 YAML 文件」生成,其 CI 会拿本仓库核对提交的形式。机械
层面的要求本仓库已经满足:package.json 中与 cordis.patch.yml 并列声明了
dsh.bundle;官方的 @deepseek-ai/ 包按规范声明为 peerDependencies(本包并未
导入它们,但本包是一个 Cordis 插件);没有任何需要安装的依赖,也没有构建步骤。剩下
的属于仓库所有者的操作:

1. 加上 dsh-plugin topic——
gh repo edit yizhixiaokong/dsh-compose-panel --add-topic dsh-plugin;
2. 让仓库创建满 1 天(列表的 CI 会拒绝更年轻的仓库);
3. 提一个 PR,只新增 data/plugins/yizhixiaokong__dsh-compose-panel.yml:

url: https://github.com/yizhixiaokong/dsh-compose-panel
name: yizhixiaokong/dsh-compose-panel
category: dev
description:
en: 'Lists the Docker Compose projects of your DSH workspaces in the right sidebar, one group per project directory, with container status, project- and service-level up/stop/restart, and streamed per-service logs.'
zh: '在右侧栏列出各 DSH 工作区中的 Docker Compose 项目,按项目目录分组,显示容器状态,支持项目级与服务级 up/stop/restart 以及单服务日志流。'

市场详情页的截图条读取与 package.json 并列的 screenshots.json(1–8 张图);本仓库
声明的是 assets/01-projects.png、assets/02-actions.png、assets/03-logs.png,按此
顺序展示。

发布到 npm

npm login --registry=https://registry.npmjs.org   # 镜像既不能登录,也不能发布
npm publish --registry=https://registry.npmjs.org

npm publish --dry-run 只打印将要上传的内容而不上传;prepublishOnly 会先跑一遍
npm test。已发布包的 repository 字段指回本仓库——列表据此把 npm 包与条目关联,
随后展示的就是更短的 dsh plugin --profile web add dsh-compose-panel,而不是 GitHub 形式。

许可证

MIT

上游仓库有新提交时邮件通知你(每天最多一封,无更新不打扰),随时一键退订。

💬 加入 DPharness 群聊

插件用法、部署报错、新插件第一时间同步——群里问,比一个人翻文档快。

点击加入 QQ 群
DPharness 群聊二维码,手机 QQ 扫码进群
扫码进群