# deepseek-tray DeepSeek Harness **Web 版桌面包装**(Windows 系统托盘 + 守护进程)。 把 `dsh web` 变成常驻托盘应用:**全程隐藏终端**、异常自动重启、一键开机自启、一键更新。 > 开机自启为**静默启动**:不弹终端、不打开浏览器。需要时从托盘菜单"打开 Web 界面"(自动带 token,直接进入已认证界面)。 ## 特性 - **隐藏终端**:以 `node /lib/bin.js web --no-open` 直接启动(无 shell 包装),子进程使用 `CREATE_NO_WINDOW` + `HideWindow` - **守护重启**:异常退出自动重启,采用**指数退避**(基准 5s,上限 2 分钟;稳定运行 30s 后复位),杜绝重启风暴 - **端口预检**:目标端口已被占用(例如已有实例在运行)时不启动,改为温和等待(上限 30s 轮询),避免端口冲突 - **启停管理**:托盘一键启动 / 停止 / 重启;停止为**同步等待**(最多 8s),重启前等待端口释放 - **开机自启**:托盘勾选或 `autostart on|off`(写 HKCU Run 键,无需管理员权限) - **一键更新**:执行 `npm install -g @deepseek-ai/dsh@latest --allow-scripts=...`;可开启定期后台更新(**单例循环**,有新版才更新并重启) - **带 token 打开**:捕获 `dsh web` 输出的访问地址;菜单标题只显示 origin,token 只存内存 - **安全**:日志自动脱敏 `token=***`;打开 URL/路径不经 shell 解析(`rundll32` / `explorer`) - **健壮**:配置原子写入(临时文件 + rename)、支持 UTF-8 BOM、损坏配置回退默认值 - **单实例**:`Local\` 命名互斥体(普通用户可创建,避免 `Global\` 权限失败导致失效) - **低依赖**:第三方仅 2 个(`getlantern/systray`、`golang.org/x/sys`),单文件分发约 5 MB ## 构建 ```powershell go build -ldflags "-H=windowsgui -s -w" -o deepseek-tray.exe . ``` ## 运行方式 | 命令 | 说明 | |---|---| | `deepseek-tray.exe` | 托盘模式(默认) | | `deepseek-tray.exe --silent` | 静默托盘(开机自启使用,无窗口、不打开浏览器) | | `deepseek-tray.exe daemon` | 无 UI 守护模式(适合注册为 Windows 服务) | | `deepseek-tray.exe status` | 状态查询(同时写日志) | | `deepseek-tray.exe autostart [on\|off]` | 查看/设置开机自启 | | `deepseek-tray.exe version` | 版本号 | > CLI 子命令在真实终端中输出(通过 `AttachConsole`);无终端场景可从日志回溯。 ### 注册为 Windows 服务(可选) ```powershell nssm install DeepSeekTray "C:\path\to\deepseek-tray.exe" daemon nssm start DeepSeekTray ``` ## 托盘菜单 - 状态:运行中 (PID) / 已停止 / 外部实例运行中 / 正在更新(含运行时长与重启次数提示) - 打开 Web 界面(带 token,直接进入) - 启动 / 停止 / 重启服务 - 开机自启(勾选) - 定期自动更新(勾选)、立即更新 DSH - 版本:当前安装的 dsh 版本 - 查看日志 / 打开配置文件 - 退出(停止服务并退出) ## 配置 位置:`%APPDATA%\deepseek-tray\config.json`(首次运行自动生成,原子写入) ```json { "webPort": 3080, "webHost": "127.0.0.1", "nodePath": "", "dshBinJs": "", "autoStart": false, "autoUpdate": false, "updateIntervalHours": 24, "restartDelaySeconds": 5 } ``` | 字段 | 说明 | |---|---| | `webPort` / `webHost` | dsh web 监听端口与地址(默认 3080 / 127.0.0.1) | | `nodePath` / `dshBinJs` | 留空自动探测(`node` + `npm root -g` 下的 dsh 入口) | | `autoStart` | 开机自启(与托盘勾选同步) | | `autoUpdate` / `updateIntervalHours` | 定期后台更新开关与间隔 | | `restartDelaySeconds` | 重启退避的基准延迟(实际按失败次数指数放大) | ## 日志 `%APPDATA%\deepseek-tray\logs\tray-YYYYMMDD.log`(含 dsh web 的 stdout/stderr;**token 已脱敏**) ## 验证结论(v2.1.0) | 维度 | 验证项 | 结果 | |---|---|---| | 可靠性 | 隐藏终端(daemon / dsh web 窗口句柄) | 均为 0 | | 可靠性 | 自动重启(假命令立即退出) | 启动 6 次 / 退出 4 次 / 重启 4 次 | | 可靠性 | 单实例(第二个实例启动) | 立即退出并记录 | | 健壮性 | 端口被占用 | 不启动冲突进程,退避递增 6s→12s→24s | | 健壮性 | 配置损坏 / UTF-8 BOM | 回退默认值 / 正确读取 | | 安全性 | 日志 token | 输出为 `token=***` | | 安全性 | 打开 URL/路径 | 不经 shell 解析 | | 效率 | status 查询 / 二进制 | 0.4 秒 / 约 5 MB | | 效率 | 状态轮询 | 仅在值变化时刷新 UI | ## 环境要求 - Windows 10/11 - 已全局安装 dsh:`npm install -g @deepseek-ai/dsh@latest --allow-scripts='@deepseek-ai/dsh-subprocess-local,koffi,node-pty,@google/genai,protobufjs'` - `node` 在 PATH 中 ## 版本 - v2.1.0 — 自检优化:端口预检 + 指数退避 + 定期更新单例 + `Local` 互斥体 + 日志脱敏 + 原子配置 + `autostart` 子命令 - v2.0.0 — 重写为 `dsh web` 托盘守护(旧版余额查询功能归档于 `legacy-v1` 标签) ## 许可证 见 [LICENSE](LICENSE)。