deepseek余额查询系统图标

caesar e7471d4138 test: 新增 AST 死代码门禁(函数逐项检查) 15 órája
.gitignore 4e29d3ab77 chore: 忽略并移除 Go 构建备份残留(*.exe~) 1 napja
LICENSE 975213867b Initial commit 4 hónapja
README.md ac6d552136 revert: v2.6.1 回退显示地址设计,菜单恢复纯短文本 15 órája
autostart_windows.go 70a8f52af1 feat: 重写为 dsh web 托盘守护程序(v2.0.0) 1 napja
build.ps1 ac6d552136 revert: v2.6.1 回退显示地址设计,菜单恢复纯短文本 15 órája
config.go 7f0dafd489 fix: v2.3.0 三次迭代(竞态修复 + 线程安全配置 + 更新前停服务) 1 napja
deadcode_test.go e7471d4138 test: 新增 AST 死代码门禁(函数逐项检查) 15 órája
go.mod 70a8f52af1 feat: 重写为 dsh web 托盘守护程序(v2.0.0) 1 napja
go.sum 36a1fa5c3e docs: update README.md 4 hónapja
icon.ico 36a1fa5c3e docs: update README.md 4 hónapja
logger.go 0c3ca2be35 refactor: v2.2.0 二次迭代(单元测试 + 修复 + 职责拆分) 1 napja
main.go 938bf63e18 feat: v2.5.0 依据使用反馈优化(菜单宽度 + 结果回显 + 版本注入) 16 órája
npm.go 38620f1f6e refactor: v2.1.0 自检优化(可靠性/安全/健壮性/效率) 1 napja
probe.go 0c3ca2be35 refactor: v2.2.0 二次迭代(单元测试 + 修复 + 职责拆分) 1 napja
proc_windows.go ac6d552136 revert: v2.6.1 回退显示地址设计,菜单恢复纯短文本 15 órája
supervisor.go 938bf63e18 feat: v2.5.0 依据使用反馈优化(菜单宽度 + 结果回显 + 版本注入) 16 órája
tray.go ac6d552136 revert: v2.6.1 回退显示地址设计,菜单恢复纯短文本 15 órája
updater.go 938bf63e18 feat: v2.5.0 依据使用反馈优化(菜单宽度 + 结果回显 + 版本注入) 16 órája
util.go 0c3ca2be35 refactor: v2.2.0 二次迭代(单元测试 + 修复 + 职责拆分) 1 napja
util_test.go 7f0dafd489 fix: v2.3.0 三次迭代(竞态修复 + 线程安全配置 + 更新前停服务) 1 napja

README.md

deepseek-tray

DeepSeek Harness Web 版桌面包装(Windows 系统托盘 + 守护进程)。

把 dsh web 变成常驻托盘应用:全程隐藏终端、异常自动重启、一键开机自启、一键更新。

开机自启为静默启动:不弹终端、不打开浏览器。需要时从托盘菜单"打开 Web 界面"(自动带 token,直接进入已认证界面)。

特性

  • 隐藏终端:以 node <dsh>/lib/bin.js web --no-open 直接启动(无 shell 包装),子进程使用 CREATE_NO_WINDOW + HideWindow
  • 守护重启:异常退出自动重启,指数退避(基准可配,封顶 2 分钟;稳定运行 30s 后复位),杜绝重启风暴
  • 端口预检:端口已被占用(例如已有实例)时不启动,改为温和等待(封顶 30s 轮询),避免端口冲突
  • 启停管理:托盘一键启动 / 停止 / 重启;停止为同步等待(最多 8s),重启前等待端口释放
  • 开机自启:托盘勾选或 autostart on|off(写 HKCU Run 键,无需管理员权限)
  • 一键更新:执行 npm install -g @deepseek-ai/dsh@latest --allow-scripts=...,先停服务再更新(避免 Windows 上 native 模块文件占用导致安装失败),无论成败都恢复原有运行状态;可开启定期后台更新(常驻单例循环:关闭仅暂停计时,再次开启立即恢复)
  • 带 token 打开:捕获 dsh web 输出的访问地址;菜单标题只显示 origin,token 只存内存
  • 安全:日志自动脱敏 token=***;打开 URL/路径不经 shell 解析(rundll32 / explorer)
  • 健壮:配置原子写入(临时文件 + rename)且写入线程安全、支持 UTF-8 BOM、损坏配置回退默认值;日志按天轮转;进程树终止失败时退化为直接终止;停止与启动过程的竞态已处理(停止请求落在启动窗口时不会残留进程)
  • 单实例:Local 命名互斥体(普通用户可创建,避免 Global 权限失败导致失效)
  • 可验证:11 个单元测试覆盖脱敏、URL 提取、配置读写与归一、端口探测、退避、日志轮转、守护生命周期
  • 低依赖:第三方仅 2 个(getlantern/systray、golang.org/x/sys),单文件分发约 5 MB

构建与测试

.\build.ps1          # 一键:格式检查 + go vet + go test + 构建

分步执行:

gofmt -l .          # 格式检查(应无输出)
go vet ./...        # 静态检查
go test ./...       # 单元测试
go build -trimpath -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 服务(可选)

nssm install DeepSeekTray "C:\path\to\deepseek-tray.exe" daemon
nssm start DeepSeekTray

托盘菜单

  • 状态:运行中 · PID / 启动中 · PID / 已停止 / 外部实例运行中 / 正在更新 (操作结果会在状态区临时回显,如"已是最新版本 x.y.z"、"更新完成"、"失败(详见日志)")
  • 打开 Web 界面(就绪前置灰;就绪后点击直达,自动带 token)
  • 启动 / 停止 / 重启服务
  • 开机自启(勾选)
  • 定期自动更新(勾选)、立即更新 DSH(已是最新则秒回,不重启服务)
  • 版本:当前安装的 dsh 版本
  • 查看日志 / 打开配置文件
  • 退出(停止服务并退出)

设计取舍:菜单与提示均不显示访问地址。 原因:地址(含 token)很长,一旦放进菜单标题就会撑宽整个菜单,视觉不协调;而 getlantern/systray 在 Windows 上又不支持菜单项悬停提示(只有图标 tooltip 有效)。 因此访问地址只用于两处:点击「打开 Web 界面」直接打开、以及写入日志便于排查。 需要原始地址时,可在日志中查看(token 已脱敏)或从浏览器地址栏获取。

配置

位置:%APPDATA%\deepseek-tray\config.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 重启退避的基准延迟(按失败次数指数放大,封顶 2 分钟)

修改配置文件后需重启程序生效。

源码结构

文件 职责
main.go 入口与 CLI 子命令(托盘 / daemon / status / autostart)
supervisor.go 守护核心:端口预检、隐藏启动、退避重启、状态快照
probe.go 环境探测:node 路径、dsh 入口、已装版本(带缓存与串行化)
updater.go 更新与定期更新循环
tray.go 托盘菜单与交互
config.go / logger.go / npm.go / util.go 配置、日志、npm 调用、纯工具
*_windows.go Win32 细节(隐藏窗口、进程树终止、单实例、控制台附加)
util_test.go 单元测试

日志

%APPDATA%\deepseek-tray\logs\tray-YYYYMMDD.log(按天轮转;含 dsh web 的 stdout/stderr;token 已脱敏)

验证结论

单元测试(go test)

测试 覆盖
TestRedact token 脱敏(多 token / 终止符 / 无 token / 空串)
TestExtractHTTPURL URL 提取与误报拒绝(httpx)
TestShortURL / TestHumanDuration 展示格式化
TestConfigNormalized 配置越界回退默认值
TestIsPortOpen 真实监听端口的探测
TestBackoff 退避序列与封顶(此测试发现并修复了上限未生效问题)
TestLoggerRotate 日志按天轮转
TestConfigRoundTrip 配置首次生成 / 保存重载 / BOM 容忍 / 损坏回退(隔离到临时目录)
TestSetAutoUpdatePersists 线程安全 setter 同时更新内存与磁盘
TestSupervisorLifecycle 守护状态机:启动 / 自动重启 / 停止

运行时验证(v2.3.0;一次观测的实测结果,非持续保证)

维度 验证项 结果 证据形式
可靠性 隐藏终端 daemon / dsh web 的顶层窗口句柄为 0 进程属性测量
可靠性 自动重启 假命令下观测到 启动 6 / 退出 4 / 重启 4 日志计数
可靠性 单实例 第二个实例立即退出并记录 日志
可靠性 启动/停止竞态 已处理(停止请求落在启动窗口时终止该进程) 仅代码审查;窗口毫秒级,未确定性复现
健壮性 端口被占用 不启动冲突进程,退避 6s→12s→24s 日志时间戳
健壮性 配置损坏 / UTF-8 BOM 回退默认值 / 正确读取 单元测试 + CLI
安全性 日志 token 输出 token=***(真实值仅存内存) 日志
安全性 打开 URL/路径 不经 shell(ShellExecuteW) 探针测试通过
可靠性 打开日志/配置 窗口正常显示(不再被 SW_HIDE 隐藏) 探针调用成功(目视确认由用户完成)
效率 status 查询 / 二进制 0.4 秒 / 约 5.2 MB 计时与文件大小

复现方式:build.ps1 跑单元测试;上表运行时项可用 --port 3099 与假命令分别复现。未标注"实测"的行为代码审查结论。

环境要求

  • 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.6.1 — 回退"显示访问地址"的设计(长地址会撑宽菜单、视觉不协调):菜单恢复纯短文本、移除「复制 Web 地址」与图标 tooltip 中的地址;访问地址只用于打开与日志。firstLine 改用 ASCII 码 10,避免转义写法歧义
  • v2.6.0 — (已被 v2.6.1 推翻)尝试把地址放进 tooltip/剪贴板:查源码确认 getlantern/systray 在 Windows 上不支持菜单项 tooltip(MenuItem.SetTooltip 是空操作),改为把完整地址放进托盘图标 tooltip(地址置于首行,规避 128 字符上限截断),并新增「复制 Web 地址」(临时文件 + clip.exe,文本不经 shell 解析)
  • v2.5.0 — 依据实际使用反馈优化:菜单宽度(长 URL 移入悬停提示)、操作结果回显(解决"点更新没反应"的观感问题)、版本号改由构建脚本注入(避免源码与版本号不一致)、更新流程合并为唯一入口(去掉重复查询)、耗时操作防重入
  • v2.4.0 — 修复实测发现的三个问题:打开日志/配置无反应(误用 SW_HIDE 把 explorer 窗口隐藏了 → 改用 ShellExecuteW)、Web 界面启动期不可用(新增就绪状态,启动中禁用点击而非打开无效地址)、更新白等 5 分钟(版本相同时跳过整包重装与重启);菜单耗时操作后台执行不再阻塞;日志记录 Web 启动耗时
  • v2.3.0 — 三次迭代:修复停止/启动竞态(不再残留进程)、配置写入线程安全、更新前先停服务、配置读写单元测试与守护生命周期测试、build.ps1 一键构建
  • v2.2.0 — 二次迭代:新增单元测试(并借其修复退避上限问题)、修复定期更新"关闭后再开启"失效、职责拆分(probe/util)、日志按天轮转、进程终止兜底、daemon 优雅退出
  • v2.1.0 — 自检优化:端口预检 + 指数退避 + 定期更新单例 + Local 互斥体 + 日志脱敏 + 原子配置 + autostart 子命令
  • v2.0.0 — 重写为 dsh web 托盘守护(旧版余额查询功能归档于 legacy-v1 标签)

许可证

见 LICENSE。