Repository navigation
Releases: jingyingruodi/dsh-headless-display
Release list
v1.4.1 — 画面与音频双静默
画面与音频双静默
这个版本把「静默」从画面补齐到音频:隔离 display 里的程序可以正常出声,
但声音不会从用户的扬声器/耳机出来;同时保证用户自己正在听的音频完全不受影响。
音频静默(新)
- 每个隔离 display 建一个
node.hidden=true的 null sink(dsh-iso-<N>) iso_display_run起的进程注入PULSE_SINK,音频全部丢弃;iso_display_stop卸载 sink- 配置:
audio: 'null' | 'inherit'(默认null)
守住用户正在听的音频
- 本机实测:任何新增音频 sink 都会把用户默认声卡置为静音(不止本插件建的,Proton/Steam 中途建的也算)
- 250ms keeper:仅在「sink 数量增加」时把默认设备与静音状态拉回启动时的值;
用户自己手动静音不会被抢回 iso_display_start返回audio.{userDefaultSink,userDefaultMuted,keptUserAudioUnmuted}iso_display_stop返回userAudioRestores
实测证据(2026-10-21,黑盒智能体只给目标与工具定义、无源码)
- 渲染:Desynced 主菜单 1280x720,253,530 色(
via: grim) - 游戏音频:
application.name="Desynced"的流落在dsh-iso-2;
从dsh-iso-2.monitor录音 6.14s,max −24.2 dB—— 确实在出声,但被丢弃 - 用户音频:默认设备(蓝牙耳机)全程不变、
Mute: no、音量不变;
386 次采样 0 次静音 - 桌面窗口:整轮 0 条 Desynced/Windows 相关窗口
继承自 v1.3.x 的静默硬保证
- 隔离 display 编号按进程归属判定(不再把用户桌面
:1误判成隔离 display) - 子进程钉 X11(
GDK_BACKEND/QT_QPA_PLATFORM/SDL_VIDEODRIVER/
ELECTRON_OZONE_PLATFORM_HINT),Wayland 不泄漏到桌面 - 写操作只认本插件启动的 display(
allowForeignDisplays可放开) killClientsOnStop清理setsid孤儿进程- 泄漏可见化:
list给ageMinutes/stale,doctor点名
其它
iso_display_doctor:依赖 / GPU / 音频 / 桌面自检,按发行版给安装命令scripts/run-proton.sh:自动探测 Steam 库 / compatdata / Proton / exe- 修复:wayvnc 参数、
spawnENOENT 带崩、pkill -f误杀、并发 start 抢号
安装
plugin_manager(action: "install_bundle", target: "<本目录绝对路径>")
装完先跑 iso_display_doctor。
v1.3.2 — 静默硬保证 + Proton 游戏
静默硬保证 + Proton 游戏
修掉两个「会让命令/窗口跑到用户桌面」的严重问题
- 隔离 display 编号被误判:
xauthority配置过期时,旧实现会把用户桌面的:1
当成新建的隔离 display(实测iso_display_run返回DISPLAY=:1、1920x1200)。
现在改为按进程组归属认 Xwayland,并加两道安全网。 - Wayland 客户端泄漏:只删
WAYLAND_DISPLAY时 libwayland 会默认连
$XDG_RUNTIME_DIR/wayland-0(用户桌面)。现在子进程显式钉到 X11。
Proton / Steam 游戏
sway后端提供 DRI3,Vulkan/GL 直通 GPU- 新增
scripts/run-proton.sh:自动探测 Steam 库、compatdata 前缀、Proton 版本、exe - 实测 Desynced(UE / DX12)完整渲染、可注入键鼠、桌面零窗口
工具
- 新增
iso_display_doctor(依赖 / GPU / 目录 / 桌面自检 + 发行版安装命令) iso_display_start支持按次指定backend,auto失败回退 xvfbiso_display_run支持env(Proton 变量)并校验DISPLAY/WAYLAND_DISPLAYiso_display_stop清理setsid起的孤儿进程(killClientsOnStop)
安装
plugin_manager(action: "install_bundle", target: "<本目录绝对路径>")
v1.1.1 —— README 与代码同步 + 状态自愈
修复(由另一位维护者审阅发现)
1. README 与代码不同步
- 开头仍写「(Xephyr)…7 个工具」→ 实际默认后端是 Xvfb,工具 9 个
- HTTP 路由写成 6 条 → 实际 8 条(新增
/popout、/popin) stateDir默认值写错;配置表缺backend/vncPortBase- 仍描述「回退到
shell.overlay浮动面板」→ 该分支早已删除(它造成过 UI 被盖死的事故)
2. 命名不统一
新增「名称沿革」一节,说明改名的根本原因:dsh 宿主模块按包名做进程级缓存,
改 JS 后开关插件 / 重装 bundle / 改入口文件名 / 换目录路径都无法加载新代码,
只有换包名或重启 dsh。
3. 顺带修掉两处真问题
- 状态目录自愈:
listDisplays会清掉已死 display 的状态记录 visible改为探测进程(process.kill(pid,0)):原先只看有没有记过viewerPid,
查看器早已退出时 UI 仍显示「关闭真实窗口」
本机清理
删除遗留的 ~/.dsh-isolated-display、~/.dsh-isolated-x11、~/.dsh-gui-isolation,
只保留当前的 ~/.dsh-headless-display。
v1.1.0 —— 默认纯 headless(不再弹窗)
行为变更(重要)
之前隔离 display 用的是 Xephyr,会在用户桌面上开一个窗口,会打扰正在用电脑的人。
现在默认后端是 Xvfb(真 headless):桌面上零窗口,用户零感知;面板里照样能实时查看与操作。
需要看真实画面或亲手操作时,用面板上的 「打开真实窗口」(工具 iso_display_popout):
在该 display 上启动只监听本机回环的 x11vnc + VNC 查看器,关掉即回到静默,程序不重启。
实测(客观验证「静默」)
| 检查 | 结果 |
|---|---|
| 启动前后,用户桌面 :1 的顶层窗口数 | 133 → 133(完全没变) |
| 桌面上属于隔离 display 的窗口 | 0 |
顺带修复
POST /input 的 display 优先级 bug:query 缺失时 undefined 会覆盖 body 里的 display,
导致侧边栏面板的点击与输入一直返回 500。
已知限制
KDE Wayland 下 XWayland 窗口抬不到原生 Wayland 窗口之上,弹出的查看器可能不会自动到最前(可从任务栏点击)。
新增工具
iso_display_popout / iso_display_popin(HTTP 对应 /gui-isolation/popout、/popin)。
v1.0.1 —— 修复右栏标签页 + MIT 许可证
修复
右栏标签页永远不出现的根因:用 ctx.get("betterSidebar") 判断可用性。
better-sidebar 是通过 ctx.provide("betterSidebar", service) 发布服务的,晚于本插件 apply,
所以 ctx.get 拿到 undefined,代码直接 return,标签页从未注册。
改为直接 ctx.inject(["betterSidebar"], cb) —— Cordis 会等待依赖就绪;
真的没有 better-sidebar 时回调不执行,自然不注册任何 UI。
同时补上 TabDescriptor 的 description / order / single: true。
新增
- MIT 许可证(
LICENSE+ README 章节) - README「维护者必读」补第 4 个坑:
betterSidebar不在 Cordis Service 目录里,cordis_inspect_query查不到它,别因此以为它不存在
版本
package.json 1.0.0 → 1.0.1
v1.0.0 —— 首个可用版本
内容
- 7 个 Agent 工具:
iso_display_start/list/stop/run/capture/windows/input - 6 条 HTTP 路由:
/gui-isolation/{state,snapshot,windows,start,stop,input} - Web 侧边栏标签页:实时画面 + 点画面即点击 + 文本/按键注入 + 窗口列表
- 零 npm 依赖,无构建步骤
实测(2026-10-11)
| 项 | 结果 |
|---|---|
iso_display_start |
:9 1280x720 |
iso_display_capture |
1280x720 PNG |
iso_display_input(type --window) |
xev 收到 13 次 KeyPress,键序 dsh-plugin-ok |
GET /gui-isolation/state |
200 JSON |
GET /gui-isolation/snapshot |
200 image/png |
⚠️ 已知限制
- Xephyr 不提供 DRI3,跑不了 Vulkan/3D 程序(UE 启动即
EXCEPTION_INT_DIVIDE_BY_ZERO)。2D/X11 程序完全可用。 iso_display_run是同步的,GUI 程序请用sh -c "setsid <程序> &"。
📌 维护者必读
README 里记录了三个已踩过的坑:
- 插件
Config不能是裸 JSON Schema(Cordis 要 Standard Schema),否则激活失败 - 模块按包名做进程级缓存:改 JS 后重装/换目录/改入口文件名都无效,只有换包名或重启 dsh
- dsh 宿主进程不继承桌面的
DISPLAY/XAUTHORITY
另有一次事故记录:客户端曾把面板挂到 shell.overlay(frame-wide 浮层)导致整个 UI 被盖死,现已彻底移除该回退。
