🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

WSL 托盘管家 p455enger/dsh-web-tray

DeepSeek Harness
p455enger32 天前有提交已提供中文文档扫描:含敏感能力

在 Windows 托盘一键启停并监控 WSL 里的 DSH 服务

30/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/4 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add p455enger/dsh-web-tray
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么[目录]—
dsh 原生插件 · ui
暂无时间戳·判据 →
装得上吗[实装验证]✓
本站已在 dsh 0.2.1-rc.5 下真实安装成功
非静态推断
L5 · 运行时冒烟等级说明 →
数据截至 2026/11/04·判据 →
安全吗[自动扫描]—
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
数据截至 2026/11/05·判据 →
还在维护吗[仓库]—
更新放缓:最近一次提交在 32 天前
暂无时间戳·判据 →
图例:✓ 通过! 需注意— 未判定 / 无数据· 「未判定」= 本站尚无数据,不代表插件有问题
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →

可信度证据

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令读写/删除本地文件发起外部网络请求
查看扫描证据(共 48 处,展示前 19 条)
  • 读取本地文件
    bin/dsh-web-tray.mjs:165
    const text = mountsText ?? readFileSync('/proc/mounts', 'utf8')
  • 读取本地文件
    bin/dsh-web-tray.mjs:188
    if (candidate === 'powershell.exe' || existsSync(candidate)) return candidate
  • 执行外部命令来自配置/变量
    bin/dsh-web-tray.mjs:221
    const child = spawn(powershellPath(), ['-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Bypass', '-WindowStyle', 'Hidden', ...args], {
  • 写入本地文件
    bin/dsh-web-tray.mjs:274
    await mkdir(layout.targetDir, { recursive: true })
  • 读取本地文件
    bin/dsh-web-tray.mjs:277
    const body = await readFile(join(PACKAGE_ROOT, 'windows', name), 'utf8')
  • 写入本地文件
    bin/dsh-web-tray.mjs:279
    await writeFile(join(layout.targetDir, name), name.endsWith('.ps1') ? `\uFEFF${text}` : text, 'utf8')
  • 读取本地文件
    bin/dsh-web-tray.mjs:283
    await writeFile(join(layout.targetDir, name), await readFile(join(PACKAGE_ROOT, 'assets', name)))
  • 写入本地文件
    bin/dsh-web-tray.mjs:283
    await writeFile(join(layout.targetDir, name), await readFile(join(PACKAGE_ROOT, 'assets', name)))
  • 写入本地文件
    bin/dsh-web-tray.mjs:286
    await writeFile(layout.trayEnvPath, renderEnv(config), 'utf8')
  • 读取本地文件
    bin/dsh-web-tray.mjs:313
    if (!existsSync(profiles)) return
  • 读取本地文件
    bin/dsh-web-tray.mjs:314
    for (const profile of readdirSync(profiles)) {
  • 删除本地文件
    bin/dsh-web-tray.mjs:353
    rmSync(previous, { force: true })
  • 写入本地文件
    bin/dsh-web-tray.mjs:422
    await writeFile(layout.exitFlagPath, 'exit\n', 'utf8')
  • 删除本地文件
    bin/dsh-web-tray.mjs:432
    rmSync(layout.exitFlagPath, { force: true })
  • 发起网络请求
    bin/dsh-web-tray.mjs:545
    const response = await fetch(url, { signal: AbortSignal.timeout(timeoutMs) })
  • 执行外部命令来自配置/变量
    bin/dsh-web-tray.mjs:615
    const child = spawn(command.file, command.args, { detached: true, stdio: 'ignore', windowsHide: true })
  • 执行外部命令固定命令
    bin/dsh-web-tray.mjs:619
    const child = spawn('bash', [join(layout.targetDir, script)], { detached: true, stdio: 'ignore' })
  • 执行外部命令来自配置/变量
    bin/dsh-web-tray.mjs:628
    spawnSync(command.file, command.args, { stdio: 'inherit' })
  • 执行外部命令固定命令
    bin/dsh-web-tray.mjs:631
    spawnSync('bash', [join(layout.targetDir, script)], { stdio: 'inherit' })
扫描于 2026/11/5(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

社区实装还没有人打卡 · 装过的第一个就是你
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/dsh-client-ui-primitives
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 托盘一键启停服务
  • 监控实时状态
  • 切换自动启停

Windows 托盘 + 桌面快捷方式,在 WSL 里跑 dsh web,可切换自动启停并显示实时状态(dsh-wsl-tray 的分支)

README

由 DeepSeek 最新模型翻译生成
dsh-web-tray 为运行在 WSL 里的 DeepSeek Harness(DSH)提供 Windows 托盘 + 桌面快捷方式,带 可开关的自动启停 与 实时状态显示。 本仓库是 liyu34/dsh-wsl-tray 的 fork (上游 ff03276,v0.1.7,MIT)。上游那套「桌面快捷方式 + 隐藏托盘 + 守护进程」的架构完整保留;下面「与上游的差异」列出本 fork 新增与修正的内容。 与上游的差异 | 能力 | 上游 | 本 fork | | 自动启停 | 行为固定:托盘启动即拉起 DSH,退出即停止 | 四个开关,可随时开关:托盘启动时自动启动、退出托盘时停止、空闲自动停止、守护进程(自动重启) | | 开关生效方式 | 守护参数烧进生成的 PS1,改参数要重新生成 + 重启托盘 | 开关写在 tray-config.json,托盘每个 tick 重新读取;改变开关不重新生成任何产物(已验证 PS1 哈希不变) | | 状态显示 | 设置页只在打开时抓取一次;字段较少 | 设置页每 2 秒轮询(页面隐藏时暂停);新增 DSH 进程 PID / 运行时长 / 内存、授权链接、空闲计时与连接数、开关当前值、配置来源、最近 10 条动作 |
展开完整文档(README 剩余 1 节)
dsh-web-tray

为运行在 WSL 里的 DeepSeek Harness(DSH)提供 Windows 托盘 + 桌面快捷方式,带 可开关的自动启停 与 实时状态显示。

本仓库是 liyu34/dsh-wsl-tray 的 fork (上游 ff03276,v0.1.7,MIT)。上游那套「桌面快捷方式 + 隐藏托盘 + 守护进程」的架构完整保留;下面「与上游的差异」列出本 fork 新增与修正的内容。

与上游的差异

| 能力 | 上游 | 本 fork |
| 自动启停 | 行为固定:托盘启动即拉起 DSH,退出即停止 | 四个开关,可随时开关:托盘启动时自动启动、退出托盘时停止、空闲自动停止、守护进程(自动重启) |
| 开关生效方式 | 守护参数烧进生成的 PS1,改参数要重新生成 + 重启托盘 | 开关写在 tray-config.json,托盘每个 tick 重新读取;改变开关不重新生成任何产物(已验证 PS1 哈希不变) |
| 状态显示 | 设置页只在打开时抓取一次;字段较少 | 设置页每 2 秒轮询(页面隐藏时暂停);新增 DSH 进程 PID / 运行时长 / 内存、授权链接、空闲计时与连接数、开关当前值、配置来源、最近 10 条动作 |
| 空闲判断 | 无 | netstat -ano 统计 web 端口上属主不在排除表内的 ESTABLISHED 连接 |
| 打开网页 | 打开裸 URL,浏览器无 cookie 时会停在 401 | 从启动脚本日志里取本次进程的 ?token= 地址打开,顺手种 cookie |
| 环境适配 | 假设 Windows 目录在 PATH 上(appendWindowsPath = true) | 三个真实缺陷已修,见「本机环境适配」 |

功能

- 双击桌面「DSH Web」快捷方式:需要时启动 WSL 发行版,DSH 在后台启动(或复用已在运行的实例),就绪后浏览器自动打开一次(带授权 token)。
- 托盘图标(wscript.exe + VBS 隐藏启动,全程无控制台窗口)。右键菜单:
- 状态行:状态: 运行中 | 连接 2,30 分钟后停服
- 打开 DSH 网页 / 启动 DSH 服务 / 停止 DSH 服务 / 重启 DSH 服务
- 重新生成桌面快捷方式
- ☑ 托盘启动时自动启动 DSH
- ☑ 退出托盘时停止 DSH
- ☑ 守护进程(自动重启)
- 空闲自动停止 ▸ 关闭 / 5 / 15 / 30 / 60 分钟
- 退出
- 双击托盘图标也打开 DSH 网页。
- 守护进程:按 probeIntervalSec 探测 DSH 网址,连续 downThreshold 次失败则重启;连续 maxRestartFailures 次重启失败后暂停(不再无限重启),DSH 一旦恢复回答就自动恢复。全过程写入 tray.log。
- 主动停止语义:从托盘菜单点「停止 DSH 服务」或空闲自动停服后,进入 stopped 阶段 —— 守护进程不会把它再拉起来,直到 DSH 自己重新应答(例如你手动启动)。
- 设置页(设置 → WSL 桌面与托盘):开关、DSH 实例状态、守护进程状态、浏览器连接与空闲计时、生成文件清单、工程路径、托盘日志(可开自动刷新)。

环境要求

- DSH 本身运行在 WSL 中(WSL_DISTRO_NAME 已设置,或 /mnt/c 可访问)。
- Windows 侧可执行 wscript.exe、powershell.exe、wsl.exe(interop 开启)。
- DSH web 0.2.0-rc.2 验证通过(客户端 dsh.client.inject 已按 0.2.0 的包列表更新:上游列的 @deepseek-ai/dsh-client-runtime 在 0.2.0 里不存在)。

安装

三种方式任选。方式 B 是本次验证用的方式,不需要 pnpm。

方式 A:官方插件管理器

cd /path/to/dsh-web-tray
dsh plugin --profile web add "$PWD" # 需要 PATH 上有 pnpm(corepack enable)

方式 B:profile 里放符号链接(无需 pnpm)

P=~/.dsh/profiles/web
python3 - <<'PY'
import json, os
p = os.path.expanduser('~/.dsh/profiles/web/package.json')
d = json.load(open(p))
b = d['dsh']['profile']['bundles']
if 'dsh-web-tray' not in b:
b.append('dsh-web-tray')
json.dump(d, open(p, 'w'), indent=2)
PY
mkdir -p "$P/node_modules"
ln -sfn /path/to/dsh-web-tray "$P/node_modules/dsh-web-tray"

方式 C:打包成 tarball 再装

npm pack # 生成 dsh-web-tray-0.1.0.tgz
dsh plugin --profile web add ./dsh-web-tray-0.1.0.tgz

三种方式都需要重启 dsh web,插件才会挂载。首次挂载时 ensure() 会自动生成全部产物并在 Windows 桌面创建快捷方式。

生成的文件

| 文件 | 位置 |
| dsh-web-tray.ico / dsh-web-tray.ps1 / dsh-web-tray.vbs | %USERPROFILE%\.dsh\dsh-web-tray\ |
| tray-config.json(开关,唯一真相源) | 同上 |
| tray-status.json(托盘每 tick 覆盖写) | 同上 |
| tray.log(512 KB 轮转) | 同上 |
| start.sh / stop.sh / start.log / dsh.pid | ~/.dsh/dsh-web-tray/ |
| DSH Web.lnk | Windows 桌面 |

数据流:

设置页 ──POST /dsh-web-tray/config──▶ host ──原子写──▶ %USERPROFILE%\.dsh\dsh-web-tray\tray-config.json │ 每 tick 读取托盘菜单 ──直接写同一文件────────────────────────────────▶┤ ▼ 托盘 PS1(守护 + 空闲计数 + 动作) │ 每 tick 覆盖写 ▼ tray-status.json ──▶ host 读取 ──▶ 设置页轮询展示

开关放在 Windows 侧 是刻意的:dsh web 停着的时候设置页根本访问不到,但「托盘启动时自动启动 DSH」必须在那时仍然有效。

开关(tray-config.json)

| 键 | 默认 | 取值 | 作用 |
| autoStart | true | 布尔 | 托盘启动时若 DSH 未运行则拉起 |
| autoStopOnExit | true | 布尔 | 退出托盘时停止 DSH |
| autoStopIdleMinutes | 0 | 0–1440 | 无浏览器连接达到该分钟数后停止 DSH;0 = 关闭 |
| watchdogEnabled | true | 布尔 | 守护进程总开关(关闭后只探测,永不自动重启) |
| probeIntervalSec | 10 | 2–300 | 探测间隔 |
| probeTimeoutSec | 3 | 1–30 | 单次探测超时 |
| downThreshold | 3 | 1–10 | 连续失败多少次判定为 DOWN |
| restartWaitSec | 180 | 30–1800 | 重启后等待多久算失败 |
| maxRestartFailures | 3 | 1–10 | 连续重启失败多少次后暂停 |
| restartBackoffSec | 60 | 0–600 | 两次重启尝试之间的冷却 |
| idleProbeExcludeProcesses | powershell, pwsh, wscript, wsl, wslhost, wslrelay, conhost | 进程名数组 | 属主在此列表内的连接不计入空闲判断 |

越界值会被夹取并把原因回报到设置页;坏 JSON 时托盘保留上一次有效值(设置页显示 开关来自: 上次有效值)。文件缺失时用上面这套内置默认值。

空闲判断(为什么是 netstat)

netstat -ano → 取端口匹配 web 端口的行 → 只保留 ESTABLISHED → PID 映射进程名(缓存 60 秒)→ 丢掉排除表内的属主 → 计数

- 不用 Get-NetTCPConnection:在本机(WSL 3.0.1 + mirrored 网络)它对 -LocalPort 3080 返回 0 行,而同一时刻 netstat -ano 能列出 2 条 ESTABLISHED
+ 1 条 CLOSE_WAIT。已实测,故刻意改用 netstat。
- 排除表的意义:托盘自己的 HTTP 探测(属主 powershell)也会连 3080。若不过滤,空闲计时永远归零,空闲停服永远不会触发。
- 计数为 0 且达阈值 → 执行 stop.sh,阶段变 stopped,并写一条 actions 记录。
- netstat 取不到时把 idle.connections 记为 null 且跳过空闲停服,同时写日志。

HTTP 接口(/dsh-web-tray,环回 + 同源围栏)

| 方法 | 路径 | 说明 |
| GET | /status | 完整状态(平台、网址、授权链接、配置、生成文件、DSH 进程、托盘状态) |
| GET | /config | 当前开关 + 来源 + 文件路径 + 修复说明 |
| POST | /config | 部分开关(只写传入字段),返回生效值与修复说明 |
| GET | /watchdog | 托盘最近一次 tick 的状态(tray-status.json) |
| GET | /watchdog-log?lines=N | tray.log 尾部 |
| POST | /regenerate | 重写全部产物并重建桌面快捷方式 |
| GET/POST | /project-path | 源码 checkout 路径(留空 = 自动检测) |

本机环境适配(三个真实缺陷)

这三条都是在本机(%UserProfile%\.wslconfig 里 appendWindowsPath = false,dsh 由
npm 全局安装)上实测暴露的;上游在这种环境下无法工作:

1. powershell.exe 不在 PATH 上 → spawn('powershell.exe') 直接 ENOENT,创建快捷
方式、解析桌面目录、解析用户目录全部失败。修复:powershellPath() 先用 PATH,再回
退到绝对路径 /mnt/c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe。
2. 用户目录解析落到 Administrator → 只靠扫描 /mnt/c/Users 会取到字母序第一个目录,而它不可写(EACCES)。修复:先问 PowerShell
[Environment]::GetFolderPath('UserProfile'),扫描只作最后兜底。
3. PATH 安装的 dsh 被产物生成守卫拒绝 → 上游要求 process.argv[1] 以 .js 结尾或存在源码 checkout;而全局安装时 argv[1] 是无扩展名的 shim /usr/local/bin/dsh,于是报 "cannot locate a DSH launcher",一个产物都不生成。
修复:把「PATH 上有 dsh」也算作可用启动器(生成的 start.sh 本来就优先 command -v dsh)。

开发与验证

npm install
npm run typecheck # 宿主 + 客户端两半
npm test # 41 项(含 3 项真跑 Windows PowerShell 的集成测试)
npm run build # tsc + tsdown + banner 归一化
npm pack --dry-run

- 生成的 PS1 支持 -SelfTest:从 stdin 读 netstat 文本,输出连接计数与空闲判定用例 JSON,供 tests/tray-selftest.spec.ts 通过 Windows interop 真跑(无 interop 时自动跳过)。
- 验证记录(本机 WSL2 + Windows 11,dsh 0.2.0-rc.2):
- npm run typecheck / npm test(41 通过)/ npm run build / npm pack --dry-run 全绿;
- 真跑 PS1 语法检查通过;解析器对真实抓包样本给出 3(默认排除表)与 2(排除 system)两个预期结果;空闲判定 5 个用例全部符合预期;
- 在独立 DSH_HOME(3099 端口,不影响 3080 上的活动会话)里挂载插件:/status 返回 platform: wsl、正确用户目录、dsh.running/pid/uptimeSec/rssMb;产物与桌面 DSH Web.lnk 全部生成(快捷方式指向 wscript.exe + VBS + 图标);
- 首页 boot 载荷里出现 dsh-web-tray/client.js(客户端半边已注册);
- POST /config 改开关后写入 Windows 侧文件、GET /config 复读一致,且 PS1 哈希不变(证明开关不需要重新生成);越界值被夹取并回报,数组 body → 400,非环回 Host → 403。

已知限制

- 托盘必须在运行:守护进程与空闲停服都活在托盘进程里。退出托盘(且 autoStopOnExit 关闭时)DSH 继续运行,但没人守护它。
- Windows 原生(非 WSL)尚未实现:非 WSL 环境返回 platform: 'unsupported',设置页给出说明,不启动任何 Windows 进程。平台缝(platform.ts 规划为适配器)留在路线图上,本期只完成 WSL 适配。
- 空闲停服会中断后台作业:标签页关掉但后台任务还在跑时,达阈值会停掉 DSH(会话已落盘,历史不丢)。因此默认阈值是 0(关闭)。
- 不是由本插件启动的 DSH 实例没有 PID 文件,stop.sh 只靠括号化 pkill 模式兜底;模式覆盖 bin.js web 与 src/bin.ts web 两类。
- pkill -f 'dsh web' 类模式过宽的问题在上游就存在;本 fork 的守护逻辑不依赖它(只有 stop.sh 用括号化模式)。

与上游同步

git remote -v # upstream = liyu34/dsh-wsl-tray
git fetch upstream
git log --oneline upstream/master ^master # 看上游新增
git cherry-pick <commit> # 或 merge

许可

MIT(见 LICENSE)。原始版权声明保留自上游。
预览分享卡片长什么样 ↓p455enger/dsh-web-tray
分享 · DeepSeek Harness Hub
p455enger/dsh-web-tray

在 Windows 托盘一键启停并监控 WSL 里的 DSH 服务

这个插件是你维护的吗?
作者本人可认领并核对本条目;认领通过后,详情页会显示「作者已认领」标记。
认领条目 →
回到顶部