DoctorxPriestess/dsh-status-indicator

dsh-status-indicator

A Windows system-tray indicator that monitors and controls a local DeepSeek Harness (DSH) web instance — the process started by dsh web

待分类

dsh-status-indicator

Windows 系统托盘状态指示器:监视并控制本机 DeepSeek Harness (DSH) 的 Web 实例, 即 dsh web 启动的那个进程(node .../@deepseek-ai/dsh/lib/bin.js web)。

托盘图标就是全部 UI:绿色=运行中,黄色=启动/停止中,红色=已停止/错误。 右键即可启动 / 重启 / 停止 / 打开 Web 界面。

English docs: README.md


功能

实时状态托盘颜色 + 提示文字(PID、端口、运行时间、内存);状态变化弹气泡
生命周期控制启动 / 以管理员启动(UAC) / 重启 / 停止
打开 Web 界面打开带鉴权令牌的 URL(见下文)
自我提权"以管理员重启指示器"会把单实例 Mutex 交接给提权副本
三种入口-Tray、-Once(单次状态报告)、控制台交互菜单
可配置日志级别 / 目录 / 轮转,由 status-indicator.config.json 控制
自启动直接可用的计划任务配方(登录触发 + 最高权限)

环境要求

  • Windows(使用 WinForms 托盘、CIM、Get-NetTCPConnection)
  • Windows PowerShell 5.1 或 PowerShell 7+ —— 脚本必须是 UTF-8 with BOM
  • Node.js 在 PATH 中
  • 已安装 DeepSeek Harness,即存在包含 node_modules\@deepseek-ai\dsh\lib\bin.js 的目录

快速开始

# 单次状态
powershell -NoProfile -ExecutionPolicy Bypass -File .\status-indicator.ps1 -Once

# 托盘模式
powershell -NoProfile -ExecutionPolicy Bypass -File .\status-indicator.ps1 -Tray

# 控制台交互菜单
powershell -NoProfile -ExecutionPolicy Bypass -File .\status-indicator.ps1

参数

参数默认值含义
-Port3000指示器自己启动 DSH 时使用的端口
-DshDir自动探测包含 node_modules\@deepseek-ai\dsh 的目录
-Once打印一次状态后退出
-Tray托盘模式

-DshDir 的自动探测顺序:

  1. -DshDir 参数
  2. 环境变量 DSH_INSTALL_DIR,其次 DSH_DIR
  3. dsh 命令所在目录(如 <安装目录>\dsh.cmd)及其上层目录
  4. %APPDATA%\npm\node_modules(npm 全局安装)

全部未命中时会给出明确错误,而不是猜测。

端口说明:-Port 只影响指示器自己启动的实例。 若你的 dsh web 配置为其它端口,请传入匹配的 -Port; 否则指示器会在 3000 上另起一个实例。

工作原理

UI(托盘/控制台) ──请求队列──▶ Worker(单一长期后台引擎) ──▶ Core(检测/进程控制)
     ▲                                                        │
     └────────────── StateStore(状态快照) ◀───────────────────┘
  • UI 线程零阻塞:托盘点击与 1 秒 Timer 只做入队和读快照。CIM 查询、TCP 探测、 启停进程、Start-Process 全部在后台 worker 执行,右键菜单永远立即响应。
  • 生命周期串行:启动/停止/重启经单一队列逐个执行,各带 operationId 关联日志。
  • 绝不假定成功:"创建了进程" ≠ "启动成功"。启动必须同时观察到进程和端口监听, 停止必须确认 PID 真的退出。
  • 端口归属由 PID → 命令行 → 监听端口关联判定。被无关程序占用的端口绝不判为 "运行中",只作为诊断;也只有指示器自己要绑定的那个端口才能提前判启动失败。
  • HTTP 401/403 不等于"已停止":TCP 连接成功即视为监听中。
  • 单实例用命名 Mutex(Local\DshStatusIndicatorTray),不用 PID 文件; 提权时新副本最多等待旧副本 30 秒。
  • 有界清理:退出时释放 Timer、NotifyIcon、菜单、native HICON、Mutex 与 worker; 退出不会杀掉正在运行的 Harness。

带鉴权的 Web URL

dsh web 会生成一个每进程随机、只存在于内存的启动令牌,并在启动时打印一次:

dsh web: http://127.0.0.1:3080/?token=<43 字符 base64url>

访问该 URL 会下发签名 HttpOnly Cookie(默认 30 天,绑定 host:port)。 没有令牌也没有 Cookie 的请求一律返回 401 dsh web authentication required。

由于令牌从不落盘,指示器会重定向被启动进程的 stdout 到捕获文件并从中解析 URL:

  • 捕获文件名为项目根目录下的 .dsh-web-url-*.txt,最多保留 5 个,实例停止时删除;
  • 令牌只存在内存,绝不写入日志;
  • .dsh-web-url-*.txt 已在 .gitignore 中 —— 切勿提交;
  • 若未能捕获到令牌 URL,则回退到裸 URL(浏览器若已持有 Cookie 仍可用)。

配置

status-indicator.config.json(首次运行自动生成默认值;改动下次启动生效,无热加载):

{
  "logging": {
    "enabled": true,      // false = 完全关闭(零 IO / 零线程)
    "level": "INFO",      // DEBUG / INFO / WARN / ERROR
    "directory": "logs",  // 相对项目根目录;绝对路径会被拒绝
    "maxFileSizeMB": 5,   // 1-100
    "maxFiles": 5         // 1-50
  }
}

非法值回退默认并记录,坏配置不会导致程序无法启动。日志为低开销旁路: 内存队列 + 单一 writer 线程,UI 线程不写盘;退出时有界 flush。

自启动(登录触发 + 提权)

在以管理员身份运行的 PowerShell 中执行一次:

schtasks /Create /F /TN "dsh-status-indicator" /SC ONLOGON /RL HIGHEST /DELAY 0000:05 `
  /TR "powershell.exe -NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File \"C:\path\to\status-indicator.ps1\" -Tray -Port 3000"

/RL HIGHEST 让托盘以管理员权限运行,因此启动 DSH 时不会再弹 UAC。 删除:schtasks /Delete /F /TN "dsh-status-indicator"。

测试

三套测试均为隔离设计,绝不触碰真实的、正在运行的 DSH 实例。

powershell -NoProfile -ExecutionPolicy Bypass -File .\test\run-lifecycle-tests.ps1
powershell -NoProfile -ExecutionPolicy Bypass -File .\test\run-logging-tests.ps1
powershell -NoProfile -ExecutionPolicy Bypass -File .\test\run-token-url-tests.ps1
套件覆盖
run-lifecycle-tests.ps1启动验证、停止验证、重启、启动失败 → ERROR、端口冲突诊断。使用假 Harness(test\dsh\...\bin.js),并把进程过滤器限定在该假 Harness 上,绝不匹配真实进程。
run-logging-tests.ps1日志开关、坏 JSON 回退、非法级别、绝对路径拒绝、轮转、恢复。
run-token-url-tests.ps1在空闲端口(-TestPort,默认 3999)启动真实 DSH,断言令牌 URL 被捕获,并验证 裸 URL → 401 / 带令牌 URL → 303。清理只杀该测试端口上的 PID。

预期结果:14/14、12/12、9/9。

排错

现象原因 / 处理
浏览器显示 dsh web authentication required打开的是裸 URL。让指示器启动/重启该实例以捕获令牌,或先手动打开一次 dsh web 打印的 URL 以写入 Cookie。
未找到 DSH 安装目录自动探测失败。传入 -DshDir,或设置 DSH_INSTALL_DIR。
托盘图标不出现已有副本持有单实例 Mutex —— 查日志;重复副本会在 30 秒后自行退出。
DSH 明明在跑却显示红色DSH 监听的端口不在候选集(-Port、3000、3080)内。用匹配的 -Port 启动指示器。
中文显示为乱码脚本必须保持 UTF-8 with BOM;编辑后请带 BOM 重新保存。

许可证

MIT