dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
DeepSeek Harness 的 Linux 原生桌面集成:XDG 桌面入口、纯净无边框独立窗口、关窗自动停服务。Native Linux desktop integration for DSH.
让 DeepSeek Harness 在 Linux 桌面上像一个原生应用:从程序启动器点开、独立无边框窗口、关窗即停服务。 不打包浏览器、不引入新前端、不碰 dsh web 本身。
English | 中文
dsh web 的界面很好用,但以 Linux 桌面的日常习惯来看,它有三个别扭的地方:
dsh web,关掉终端服务就没了;放后台跑,又没有一个顺手的入口去唤起。本插件补上这一块。
| 纯净窗口 | 用 Chromium 的 --app 模式,窗口里只有 dsh web ui —— 没有地址栏、标签页、书签栏 |
| 真·桌面集成 | 标准 XDG .desktop 入口 + 高分辨率矢量图标 + 正确的 StartupWMClass 映射,任务栏/Alt-Tab 显示鲸鱼图标而不是通用的黄色占位图标 |
| 自动生命周期 | 关掉窗口,后台 dsh web 自动停止;绝不动不是自己启动的服务 |
| 零额外运行时 | 复用系统已有的 Chromium 系浏览器,不打包 Electron/Tauri,插件本体 < 100 KB |
| 零配置 | 装完插件后,dsh web 每次启动都会幂等地安装/自愈桌面集成 |
| 可回退 | 覆盖任何已有文件前先备份成 *.dsh-backup;卸载幂等且保留配置 |
dsh 已安装并可在 PATH 中找到curl(没有则退回 bash 内建 /dev/tcp 探测)Firefox 不支持。 Firefox 官方已经移除了 SSB(Site Specific Browser),无法提供无地址栏的独立窗口。降级成
firefox --new-window会带上地址栏和标签页,直接违背本插件的核心目标,所以我们选择明确报错而不是静默降级。
本插件是一个标准 DSH bundle,用社区通用的 dsh plugin 安装即可:
# 从 npm(已发布)
dsh plugin --profile web add dsh-plugin-linux-desktop
# 从 GitHub
dsh plugin --profile web add github:<你的用户名>/dsh-plugin-linux-desktop
# 从本地检出
dsh plugin --profile web add /path/to/dsh-plugin-linux-desktop
安装完重启一次 dsh web。之后:
dsh web 启动时自动把桌面入口、图标、启动脚本、KWin 窗口规则同步到最新版本(内容没变就不碰文件)。本项目是纯 ESM JavaScript,没有构建步骤。所以从 GitHub 安装时不需要给 pnpm 授予
allowBuilds执行构建脚本的权限 —— 装下来就能直接跑。
安装时会在 ~/.local/bin/dsh-desktop 放一个 CLI 垫片,所以命令可以直接用:
dsh-desktop install # 安装 / 修复
dsh-desktop status # 查看状态
dsh-desktop doctor # 诊断 + 修复建议
dsh-desktop stop # 停止当前正在运行的 dsh web
dsh-desktop restart # 重启 dsh web(装完插件后需要重启才生效)
dsh-desktop uninstall # 卸载
dsh-desktop这个 bin 本身装在 profile 的node_modules/.bin/里,不在你的 PATH 上。 垫片把绝对路径固化下来,让命令真的能用;每次安装/自愈都会刷新它。 不想用垫片的话,等价写法是dsh plugin --profile web exec dsh-desktop <子命令>。
stop 和 restart 是你明确发起的操作,所以它们会动手,但仍然先确认目标进程真的是
dsh web(读 /proc/<pid>/cmdline 校验),不是就拒绝并提示 --force。桌面启动器则相反 ——
它是自动的,所以永远只碰自己启动的服务。
装好之后就是「点图标」这一件事:
dsh web 是否已在监听:
--app 模式打开独立窗口。SIGTERM,超时才 SIGKILL)。dsh web 有一道鉴权围栏:不带 cookie 访问 / 会直接返回 HTTP 401(dsh web authentication required)。它每个进程随机生成一个 launch token,只有 GET /?token=... 这一次交换会种下一个绑定 host+port、有效期 30 天的签名 cookie,之后裸地址才能用。
所以首次启动、cookie 过期后、或换了一个干净的浏览器配置目录时,都必须拿到 token。本插件的做法是:让运行在 dsh web 进程内部的插件行调用官方的 ctx.connection.authenticatedUrl(),把结果写进运行时文件。这比「去 grep 自己写的日志」可靠得多 —— 因为无论服务是谁启动的(你手动在终端启的也算),插件都能拿到 token。
配置文件:~/.config/dsh-desktop/config.json(首次安装时自动生成)。
{
"configVersion": 1,
"host": "127.0.0.1",
"port": 3080,
"window": { "width": 1200, "height": 750 },
"browser": "auto",
"profileMode": "dedicated",
"autoInstall": true,
"manageKwinRules": true,
"desktopName": "DeepSeek Harness",
"desktopNameZh": "DeepSeek Harness",
"terminalAction": true,
"terminalCommand": ""
}
| 键 | 说明 |
|---|---|
host / port | 启动器拉起 dsh web 时使用的地址。 |
window | 独立窗口的初始尺寸(逻辑像素)。 |
browser | auto,或 chrome / chromium / brave / edge / vivaldi / opera,或浏览器可执行文件的绝对路径。 |
profileMode | dedicated(默认)或 shared,见下节。 |
autoInstall | 是否在 dsh web 启动时自动安装/自愈。 |
manageKwinRules | 是否托管 KWin 窗口规则(仅 KDE 生效)。 |
terminalAction / terminalCommand | 桌面入口右键菜单里的「以终端界面运行」。留空则自动探测已安装的终端。 |
改配置有两种方式:
# 直接编辑后重新安装
$EDITOR ~/.config/dsh-desktop/config.json
dsh plugin --profile web exec dsh-desktop install
# 或用 CLI 改(会自动重新安装)
dsh plugin --profile web exec dsh-desktop set window 1400x900
dsh plugin --profile web exec dsh-desktop set port 8080
profileMode:一个必须理解的取舍「关闭窗口 → 停止服务」这件事,在 Chrome 已经开着的时候有个坑:此时执行 chrome --app=URL 会移交给既有浏览器进程,启动器进程立刻退出,于是无法通过等待进程来感知窗口何时关闭(这是实测结论)。
| 模式 | 行为 | 代价 |
|---|---|---|
dedicated(默认) | 用 --user-data-dir 指向独立配置目录 → 浏览器进程与窗口同生共死 → 关窗即停服务,跨 DE/WM 100% 可靠 | 多一个浏览器进程;独立的 cookie 罐(首次靠 token 地址登录,之后 30 天免登录) |
shared | 复用你默认的浏览器配置目录 | 共享登录态、零额外进程;但 Chrome 已开时无法感知窗口关闭,因此不会自动停服务(会弹通知说明) |
如果你不需要「关窗即停」,只想在现有浏览器环境里开个干净窗口,就选 shared。
dsh plugin --profile web remove dsh-plugin-linux-desktop
dsh plugin --profile web exec dsh-desktop uninstall # 若上面那条已把包删掉,可跳过
uninstall 会移除:启动脚本、dsh.desktop、app_id 别名入口、图标、KWin 规则。
保留:~/.config/dsh-desktop/(配置 + 备份),以便你手工还原或重新安装。
| 维度 | 状态 |
|---|---|
| 桌面环境 | KDE Plasma(含 KWin 窗口规则)、GNOME、Hyprland/Sway 等 wlroots 系、Xfce/MATE/Cinnamon/i3 —— 窗口与入口是标准 XDG,任何 DE 都能用;KWin 规则只在 KDE 下写入 |
| 显示协议 | Wayland(实测环境)、X11 |
| 浏览器 | Chromium 系全部;Firefox 明确不支持 |
| 发行版 | 任何有 bash + Chromium 系浏览器的发行版(Arch / Debian / Fedora / openSUSE …) |
实测环境:Arch Linux、KDE Plasma 6、Wayland、200% 缩放(逻辑分辨率 1536×960)。
你点程序启动器
│
▼
~/.local/bin/dsh-desktop-app ← 插件生成的 bash 启动器
│ 1. flock 拿单实例锁(只有拿到锁的实例管生命周期)
│ 2. 探测 127.0.0.1:3080 是否有 HTTP 响应(401 也算「在」)
│ 3. 没在 → setsid 拉起 `dsh web --no-open`,记下「是我启的」
│ 4. 轮询等「带 token 的地址」出现
│ 5. chrome --app=<带 token 的地址> --user-data-dir=<独立配置目录>
│ 6. wait 窗口进程
▼
窗口关闭 → 若「是我启的」→ SIGTERM 进程组 → 必要时 SIGKILL
运行时状态的来源:
dsh web 进程
└── 插件行 linux-desktop(inject: connection + webServer)
├── ctx.connection.authenticatedUrl() → 带 token 的地址
├── ctx.webServer.port → 实际端口
└── 写入 $XDG_RUNTIME_DIR/dsh-desktop/runtime.env (0600)
pid=… / host=… / port=… / url=…
↑ 启动器读它;同时写一份 runtime.json 给工具用
这些不是从文档抄的,是在 KDE Wayland 上用 KWin 脚本 dump 真实窗口属性、反复试验得出的:
Chromium 的 Wayland app_id 规则是 chrome-<hostname>_<pathname 中 / 换成 _>-<profile 目录名>,且与端口无关。
实测:http://127.0.0.1/ 和 http://127.0.0.1:3080 都得到 chrome-127.0.0.1__-Default。
→ 所以端口可以自由配置而不破坏图标映射;而 host 一旦改动,StartupWMClass 必须跟着改(插件会自动处理)。
只写 StartupWMClass 不够,还必须有一个文件名等于 app_id 的 .desktop,以及同名的图标。
合成器按「StartupWMClass → 文件名等于 app_id 的 .desktop → 图标名等于 app_id 的图标」依次查找,全部落空就退化成 Wayland 通用的黄色占位图标。
Chrome 已在运行时,--app 会移交,启动器进程立刻退出。
这是选择 dedicated 模式作为默认的根本原因。
inject: ['connection', 'webServer'] 声明依赖。在 tui、headless 等没有这两个服务的 profile 里,这一行会停在 PENDING 不激活 —— 桌面集成天然只作用于 web 界面。try/catch 里,任何一步失败只写日志,绝不向上抛。自动安装失败也不会让 dsh web 起不来。kwinrulesrc,而且:
[General] 的两行;kwinrulesrc.dsh-backup;count + 1(用户删过规则时后者会撞号覆盖别人的规则)。dsh plugin --profile web exec dsh-desktop doctor
常见情况:
| 现象 | 原因与处理 |
|---|---|
| 任务栏是黄色圆圈白 W 图标 | app_id 别名入口或别名图标缺失。跑 dsh-desktop install --force。 |
窗口里显示 dsh web authentication required | 没拿到带 token 的地址,且独立配置目录里也没有有效 cookie。重启一次 dsh web(让插件加载并发布运行时状态)即可根治。 |
| 窗口开在了你的默认浏览器配置里,而不是独立窗口 | 这是有意的兜底:拿不到 token 且独立配置目录从未登录过时,改用默认配置以免出现 401。重启一次 dsh web 后就会回到独立窗口。 |
| 窗口纵向拉满、贴住上下边缘 | KWin 规则没生效。确认 ~/.config/kwinrulesrc 里有 DeepSeek Harness Window Rule,并 qdbus6 org.kde.KWin /KWin reconfigure。 |
| 启动器没反应 | 用 DSH_DESKTOP_DEBUG=1 ~/.local/bin/dsh-desktop-app 看调试输出;日志在 $XDG_RUNTIME_DIR/dsh-desktop-web.log。 |
| 关闭窗口后服务还在 | 你用的是 shared 模式,或服务是别处启动的(本插件刻意不接管)。改用 dedicated,并确保服务由桌面图标启动。 |
调试输出里的 token 会被打码成 <REDACTED>,不会泄漏到日志。
git clone <repo> && cd dsh-plugin-linux-desktop
node test/smoke.mjs # 61 项冒烟测试,零依赖
node scripts/prepublish-check.mjs # 发布前校验
node bin/dsh-desktop.js install --root /tmp/sandbox # 沙箱安装,不碰真实目录
发版流程(git 身份、建仓库、npm 发布、提交社区注册表)见 docs/release-checklist.md。
--root <目录>(或环境变量 DSH_DESKTOP_ROOT)会把全部读写重定向到沙箱,包括 HOME 与所有 XDG_* 路径。开发时请始终用它。
目录结构:
src/
index.js Cordis 宿主插件行(运行时状态发布 + 幂等自愈)
installer.js install / uninstall / status 编排
cli.js dsh-desktop 命令行
paths.js XDG 路径推导(含沙箱隔离)
detect.js 桌面环境 / 会话 / 浏览器探测
config.js 配置默认值、校验、读写
desktop-entry.js .desktop 渲染 + app_id 推导
kwin.js kwinrulesrc 安全读写
runtime.js 运行时状态发布
assets/ 图标 SVG + 启动器 bash 模板
bin/dsh-desktop.js CLI 可执行入口
scripts/ 发布前校验
test/smoke.mjs 冒烟测试
docs/ 方案书、勘误、发布清单
MIT