dsh-windows-tray 1.0.11 → 1.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +147 -146
- package/bin/dsh-tray.js +6 -1
- package/docs/system-tray-guide.md +16 -11
- package/docs/tray-dev-archive.md +6 -4
- package/install.ps1 +32 -5
- package/launcher/dsh-boot.ps1 +56 -0
- package/launcher/dsh-control.ps1 +1 -1
- package/launcher/dsh-lib.ps1 +17 -7
- package/launcher/dsh-tray.ps1 +53 -17
- package/package.json +7 -2
package/README.md
CHANGED
|
@@ -1,146 +1,147 @@
|
|
|
1
|
-
# dsh-windows-tray
|
|
2
|
-
|
|
3
|
-
> DeepSeek Harness(dsh)的 Windows 系统托盘管家:**官方鲸鱼状态图标 + Web/TUI 双状态显示 + 一键启停**。
|
|
4
|
-
> 纯 PowerShell + WinForms 实现,零依赖、无编译、不改 dsh 源码,卸载即还原。
|
|
5
|
-
|
|
6
|
-
[](https://www.npmjs.com/package/dsh-windows-tray)
|
|
7
|
-
[](https://www.npmjs.com/package/dsh-windows-tray)
|
|
8
|
-
[](https://www.npmjs.com/package/dsh-windows-tray)
|
|
9
|
-
[](https://github.com/)
|
|
10
|
-
|
|
11
|
-
## 是什么
|
|
12
|
-
|
|
13
|
-
dsh 默认在终端前台运行 `dsh web`——必须留着一个命令行窗口。本工具把它变成**一个标准的 Windows 托盘应用**:
|
|
14
|
-
|
|
15
|
-
- 🐋 **状态一目了然**:品牌蓝鲸鱼 = Web 运行中;灰鲸鱼 = 未运行(图标由官方 favicon 渲染生成)
|
|
16
|
-
- 📊 **DSH / TUI 双状态**:菜单顶部同屏显示 Web 与 TUI 各自的运行状态(含 PID),互不干扰
|
|
17
|
-
- 🖱️ **零窗口操作**:双击开界面,右键通过 DSH / TUI 分组子菜单一键启停,不用再碰命令行
|
|
18
|
-
- 👁️ **独立旁观者**:托盘是独立常驻进程,dsh 停止时它依然在(显示未运行 + 一键启动),退出托盘不影响 dsh
|
|
19
|
-
- 🎨 **浅色圆角菜单**:白底、圆角、投影阴影,贴合现代桌面应用审美
|
|
20
|
-
|
|
21
|
-
## 功能特性
|
|
22
|
-
|
|
23
|
-
| 交互 | 行为 |
|
|
24
|
-
| :--- | :--- |
|
|
25
|
-
| **图标** | 蓝鲸鱼 = Web 运行中(PID);灰鲸鱼 = 未运行 |
|
|
26
|
-
| **悬停提示** | `Web UI 运行中 · 127.0.0.1:
|
|
27
|
-
| **双击** | 打开 Web UI(未运行先提示启动) |
|
|
28
|
-
| **右键菜单** | 顶部 `Web UI 状态` / `TUI 状态` 双状态行;`Web UI ▸`(打开 Web UI / 启动 / 停止(带确认) / 重启);`TUI ▸`(启动 / 停止);打开日志目录 / `版本信息 ▸`(版本 / 检查更新 / 更新到最新版)/ 退出托盘 |
|
|
29
|
-
| **菜单智能禁用** | Web 运行中禁用「启动 Web UI」;TUI 运行中禁用「启动 TUI」 |
|
|
30
|
-
| **自更新** | 「版本信息 ▸」子菜单(位于退出托盘上方,非日常功能区):查看版本 / 检查更新 / 一键更新到最新版(自动重部署 + 重启托盘) |
|
|
31
|
-
| **状态通知** | Web/TUI 启动与停止瞬间弹系统通知;托盘就绪弹一次提示 |
|
|
32
|
-
| **开机自启** |
|
|
33
|
-
|
|
34
|
-
## 适配与依赖
|
|
35
|
-
|
|
36
|
-
| 项 | 说明 |
|
|
37
|
-
| :--- | :--- |
|
|
38
|
-
| **dsh 内核** |
|
|
39
|
-
| **Web 服务** | dsh web 默认监听 `127.0.0.1:
|
|
40
|
-
| **TUI 插件** | 适配 `@deepseek-harness-tui/dsh-tui` **^0.9.2
|
|
41
|
-
| **Node.js** | ≥ 18(dsh 本体运行所需) |
|
|
42
|
-
| **PowerShell** | 7(托盘常驻进程;缺省回退 Windows PowerShell 5.1) |
|
|
43
|
-
| **运行时依赖** | **零 npm 依赖**——纯 PowerShell + WinForms + 系统 API;托盘不修改 dsh、不注入任何内容,纯旁观者 |
|
|
44
|
-
|
|
45
|
-
## 界面预览
|
|
46
|
-
|
|
47
|
-
| 运行中(品牌蓝 `#4176E6`) | 未运行(中性灰 `#81858C`) |
|
|
48
|
-
| :---: | :---: |
|
|
49
|
-
|  |  |
|
|
50
|
-
|
|
51
|
-
> 图标源 = dsh Web 前端官方 favicon(鲸鱼),多尺寸 16~256px;可随时用 `dsh-tray icons` 重新生成。
|
|
52
|
-
|
|
53
|
-
## 快速开始
|
|
54
|
-
|
|
55
|
-
前置:Windows 10/11 + [PowerShell 7](https://github.com/PowerShell/PowerShell/releases)(7.x;缺失时自动回退 Windows PowerShell 5.1)+ Node.js **≥ 18** + 已安装 dsh(任意位置)。
|
|
56
|
-
|
|
57
|
-
```powershell
|
|
58
|
-
# 1. 全局安装
|
|
59
|
-
npm i -g dsh-windows-tray
|
|
60
|
-
|
|
61
|
-
# 2. 一键部署(自动探测 dsh/pwsh/node 路径 → 安装到 ~\.dsh\launcher
|
|
62
|
-
# → 按本机路径改写配置 →
|
|
63
|
-
dsh-tray install
|
|
64
|
-
|
|
65
|
-
# 3. 首次使用:把任务栏 ^ 溢出区里的鲸鱼拖到任务栏(一次性,Windows 会记住)
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
部署完成后即可双击鲸鱼打开 Web UI,右键管理一切。
|
|
69
|
-
|
|
70
|
-
## 常用命令
|
|
71
|
-
|
|
72
|
-
| 命令 | 作用 |
|
|
73
|
-
| :--- | :--- |
|
|
74
|
-
| `dsh-tray` | 启动托盘(已有实例则提示,不重复启动) |
|
|
75
|
-
| `dsh-tray install` | 一键部署 / 重新部署(可透传 `-DshRoot` 等参数) |
|
|
76
|
-
| `dsh-tray icons` | 重新生成鲸鱼图标(内置 512px 源图,无需浏览器) |
|
|
77
|
-
| `dsh-tray info` | 查看版本 / 安装位置 / 部署状态 |
|
|
78
|
-
| `npm up -g dsh-windows-tray` | 命令行更新(更新后建议 `dsh-tray install` 重部署) |
|
|
79
|
-
|
|
80
|
-
## 如何更新
|
|
81
|
-
|
|
82
|
-
两种方式任选:
|
|
83
|
-
|
|
84
|
-
**方式一:托盘一键更新(推荐)**——托盘菜单「版本信息 ▸」→「检查更新」对比 npm 最新版,发现新版后点「更新到最新版」:自动 `npm install -g` → 重新部署(含本机路径改写)→ 自动重启托盘,全程约 1 分钟,失败不影响当前托盘。
|
|
85
|
-
|
|
86
|
-
**方式二:npm 标准流程**——与普通 npm 包一致:
|
|
87
|
-
|
|
88
|
-
```powershell
|
|
89
|
-
npm up -g dsh-windows-tray # 拉取最新版
|
|
90
|
-
dsh-tray install # 重新部署(自动改写本机路径 + 刷新快捷方式)
|
|
91
|
-
dsh-tray # 重启托盘(或右键「退出托盘」后重新登录/双击快捷方式)
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
> 部署目录固定为 `~\.dsh\launcher`,重装/更新都会覆盖旧文件,不会残留;`dsh-tray info` 可查看当前版本与部署状态。
|
|
95
|
-
|
|
96
|
-
## 卸载
|
|
97
|
-
|
|
98
|
-
```powershell
|
|
99
|
-
npm rm -g dsh-windows-tray # ① 移除 npm 包本体
|
|
100
|
-
# ② 删除快捷方式: 启动文件夹 + 桌面
|
|
101
|
-
# ③ 删除部署目录 ~\.dsh\launcher (如与 dsh 控制台共用, 确认无需保留再删)
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
## 工作原理
|
|
105
|
-
|
|
106
|
-
```
|
|
107
|
-
托盘(pwsh 常驻) ──2s 轮询──► 127.0.0.1:
|
|
108
|
-
│ └──────────────► node 进程命令行含 'dsh-tui' (TUI 进程)
|
|
109
|
-
├── 菜单动作 ──► dsh-actions.ps1 (独立隐藏进程, 不卡 UI)
|
|
110
|
-
├── 自更新 ──► dsh-update.ps1 (npm 安装→重部署→重启)
|
|
111
|
-
└── 单实例 ──► 命名互斥锁 (被强杀遗留的锁自动接管)
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
- **状态检测**:Web 用 TCP 端口探测(物理单实例);TUI 按命令行匹配(多实例安全:全查全杀);TUI 检测 20s 节流,打开菜单时强制刷新
|
|
115
|
-
- **动作隔离**:启动/停止/重启在独立进程执行,托盘 UI 永不卡顿
|
|
116
|
-
- **日志**:`~\.dsh\logs\dsh-tray.log
|
|
117
|
-
- **单点配置**:端口/路径等常量集中在 `launcher/dsh-lib.ps1`,安装时按本机自动改写——**包本身与机器无关**
|
|
118
|
-
|
|
119
|
-
## 配置
|
|
120
|
-
|
|
121
|
-
| 项 | 位置 | 默认 |
|
|
122
|
-
| :--- | :--- | :--- |
|
|
123
|
-
| 监控端口 | `~\.dsh\launcher\dsh-lib.ps1` 顶部 `$PORT` | `
|
|
124
|
-
| dsh 路径 | 同上(安装时自动改写) | 自动探测 |
|
|
125
|
-
| 图标颜色 | `build/build-tray-icons.ps1`(运行蓝/停止灰) | `#4176E6` / `#81858C` |
|
|
126
|
-
|
|
127
|
-
## 常见问题
|
|
128
|
-
|
|
129
|
-
| 问题 | 处理 |
|
|
130
|
-
| :--- | :--- |
|
|
131
|
-
| 任务栏看不到鲸鱼 | 点开 `^` 溢出区,把鲸鱼拖到任务栏(一次性) |
|
|
132
|
-
| 停止 Web UI 会关掉浏览器界面 | 对——停止前有确认框;Web 与当前会话在
|
|
133
|
-
| 托盘退出了怎么唤回 | 双击桌面「DSH 系统托盘」快捷方式 / 重新登录(开机自启)/ `dsh-tray` |
|
|
134
|
-
| 怎么更新到新版 | 托盘菜单「版本信息 ▸ → 更新到最新版」一键完成;或 `npm up -g dsh-windows-tray` + `dsh-tray install`(见「如何更新」) |
|
|
135
|
-
| 检查更新失败 | 网络或 npm 不可用;托盘继续正常工作,稍后再试 |
|
|
136
|
-
| dsh 内核升级了,托盘要动吗 | 不用——托盘只探测
|
|
137
|
-
| 想彻底卸载 | `npm rm -g dsh-windows-tray` +
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
- `docs/tray-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
1
|
+
# dsh-windows-tray
|
|
2
|
+
|
|
3
|
+
> DeepSeek Harness(dsh)的 Windows 系统托盘管家:**官方鲸鱼状态图标 + Web/TUI 双状态显示 + 一键启停**。
|
|
4
|
+
> 纯 PowerShell + WinForms 实现,零依赖、无编译、不改 dsh 源码,卸载即还原。
|
|
5
|
+
|
|
6
|
+
[](https://www.npmjs.com/package/dsh-windows-tray)
|
|
7
|
+
[](https://www.npmjs.com/package/dsh-windows-tray)
|
|
8
|
+
[](https://www.npmjs.com/package/dsh-windows-tray)
|
|
9
|
+
[](https://github.com/)
|
|
10
|
+
|
|
11
|
+
## 是什么
|
|
12
|
+
|
|
13
|
+
dsh 默认在终端前台运行 `dsh web`——必须留着一个命令行窗口。本工具把它变成**一个标准的 Windows 托盘应用**:
|
|
14
|
+
|
|
15
|
+
- 🐋 **状态一目了然**:品牌蓝鲸鱼 = Web 运行中;灰鲸鱼 = 未运行(图标由官方 favicon 渲染生成)
|
|
16
|
+
- 📊 **DSH / TUI 双状态**:菜单顶部同屏显示 Web 与 TUI 各自的运行状态(含 PID),互不干扰
|
|
17
|
+
- 🖱️ **零窗口操作**:双击开界面,右键通过 DSH / TUI 分组子菜单一键启停,不用再碰命令行
|
|
18
|
+
- 👁️ **独立旁观者**:托盘是独立常驻进程,dsh 停止时它依然在(显示未运行 + 一键启动),退出托盘不影响 dsh
|
|
19
|
+
- 🎨 **浅色圆角菜单**:白底、圆角、投影阴影,贴合现代桌面应用审美
|
|
20
|
+
|
|
21
|
+
## 功能特性
|
|
22
|
+
|
|
23
|
+
| 交互 | 行为 |
|
|
24
|
+
| :--- | :--- |
|
|
25
|
+
| **图标** | 蓝鲸鱼 = Web 运行中(PID);灰鲸鱼 = 未运行 |
|
|
26
|
+
| **悬停提示** | `Web UI 运行中 · 127.0.0.1:3080` / `Web UI 未运行 · 右键可启动` |
|
|
27
|
+
| **双击** | 打开 Web UI(未运行先提示启动) |
|
|
28
|
+
| **右键菜单** | 顶部 `Web UI 状态` / `TUI 状态` 双状态行;`Web UI ▸`(打开 Web UI / 启动 / 停止(带确认) / 重启);`TUI ▸`(启动 / 停止);打开日志目录 / `版本信息 ▸`(版本 / 检查更新 / 更新到最新版)/ 退出托盘 |
|
|
29
|
+
| **菜单智能禁用** | Web 运行中禁用「启动 Web UI」;TUI 运行中禁用「启动 TUI」 |
|
|
30
|
+
| **自更新** | 「版本信息 ▸」子菜单(位于退出托盘上方,非日常功能区):查看版本 / 检查更新 / 一键更新到最新版(自动重部署 + 重启托盘) |
|
|
31
|
+
| **状态通知** | Web/TUI 启动与停止瞬间弹系统通知;托盘就绪弹一次提示 |
|
|
32
|
+
| **开机自启** | 登录后托盘自动出现 + dsh Web 静默拉起(两个启动文件夹快捷方式,安装时自动创建):「DSH 系统托盘.lnk」→ `dsh-tray.ps1`;「DeepSeek Harness (dsh).lnk」→ `dsh-boot.ps1` |
|
|
33
|
+
|
|
34
|
+
## 适配与依赖
|
|
35
|
+
|
|
36
|
+
| 项 | 说明 |
|
|
37
|
+
| :--- | :--- |
|
|
38
|
+
| **dsh 内核** | **声明**(`package.json` → `dshCompatibility`):`range` = `>=0.1.1-rc.2 <0.2.0`,`testedVersions` = **0.1.1-rc.2 / 0.1.2-rc.1 / 0.1.5-rc.1 / 0.1.5-rc.2**;`install.ps1` 会做**软校验**(不在实测清单→黄字提醒,不阻断)。口径说明:本包是**外部工具**(不 import 任何 `@deepseek-ai` 代码),故不声明 `@deepseek-ai` peerDependencies。适配 `@deepseek-ai/dsh` **v0.1.1-rc.2 起系列**;**rc.1 起引入一次性 launch token 鉴权**(打开 Web UI 必须用启动横幅 `?token=` URL 首次签发持久 cookie)→ **打开/重启 Web UI 需托盘 ≥1.0.11**(自动解析 `web-menu.out.log` 的 token 并探活;无 token/失效回退裸 URL = 向后兼容);1.0.10 及更早在 rc.1+ 上打开的是裸 URL,会看到 `dsh web authentication required` 提示页 |
|
|
39
|
+
| **Web 服务** | dsh web 默认监听 `127.0.0.1:3080`(即浏览器里的 Web UI)——托盘通过 TCP 探测该端口判断 Web 状态(端口被改时同步修改 `dsh-lib.ps1` 的 `$PORT` 即可) |
|
|
40
|
+
| **TUI 插件** | 适配 `@deepseek-harness-tui/dsh-tui` **^0.9.2(含 0.10.0-beta.4,2026-09-03 实测兼容)**(通过 dsh-profile `dsh-profile-dsh-tui` 挂载);托盘按进程命令行 `dsh-tui` 检测,与插件版本解耦 |
|
|
41
|
+
| **Node.js** | ≥ 18(dsh 本体运行所需) |
|
|
42
|
+
| **PowerShell** | 7(托盘常驻进程;缺省回退 Windows PowerShell 5.1) |
|
|
43
|
+
| **运行时依赖** | **零 npm 依赖**——纯 PowerShell + WinForms + 系统 API;托盘不修改 dsh、不注入任何内容,纯旁观者 |
|
|
44
|
+
|
|
45
|
+
## 界面预览
|
|
46
|
+
|
|
47
|
+
| 运行中(品牌蓝 `#4176E6`) | 未运行(中性灰 `#81858C`) |
|
|
48
|
+
| :---: | :---: |
|
|
49
|
+
|  |  |
|
|
50
|
+
|
|
51
|
+
> 图标源 = dsh Web 前端官方 favicon(鲸鱼),多尺寸 16~256px;可随时用 `dsh-tray icons` 重新生成。
|
|
52
|
+
|
|
53
|
+
## 快速开始
|
|
54
|
+
|
|
55
|
+
前置:Windows 10/11 + [PowerShell 7](https://github.com/PowerShell/PowerShell/releases)(7.x;缺失时自动回退 Windows PowerShell 5.1)+ Node.js **≥ 18** + 已安装 dsh(任意位置)。
|
|
56
|
+
|
|
57
|
+
```powershell
|
|
58
|
+
# 1. 全局安装
|
|
59
|
+
npm i -g dsh-windows-tray
|
|
60
|
+
|
|
61
|
+
# 2. 一键部署(自动探测 dsh/pwsh/node 路径 → 安装到 ~\.dsh\launcher
|
|
62
|
+
# → 按本机路径改写配置 → 创建开机自启(托盘 + harness Web)+ 桌面快捷方式 → 启动托盘)
|
|
63
|
+
dsh-tray install
|
|
64
|
+
|
|
65
|
+
# 3. 首次使用:把任务栏 ^ 溢出区里的鲸鱼拖到任务栏(一次性,Windows 会记住)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
部署完成后即可双击鲸鱼打开 Web UI,右键管理一切。
|
|
69
|
+
|
|
70
|
+
## 常用命令
|
|
71
|
+
|
|
72
|
+
| 命令 | 作用 |
|
|
73
|
+
| :--- | :--- |
|
|
74
|
+
| `dsh-tray` | 启动托盘(已有实例则提示,不重复启动) |
|
|
75
|
+
| `dsh-tray install` | 一键部署 / 重新部署(可透传 `-DshRoot` 等参数) |
|
|
76
|
+
| `dsh-tray icons` | 重新生成鲸鱼图标(内置 512px 源图,无需浏览器) |
|
|
77
|
+
| `dsh-tray info` | 查看版本 / 安装位置 / 部署状态 |
|
|
78
|
+
| `npm up -g dsh-windows-tray` | 命令行更新(更新后建议 `dsh-tray install` 重部署) |
|
|
79
|
+
|
|
80
|
+
## 如何更新
|
|
81
|
+
|
|
82
|
+
两种方式任选:
|
|
83
|
+
|
|
84
|
+
**方式一:托盘一键更新(推荐)**——托盘菜单「版本信息 ▸」→「检查更新」对比 npm 最新版,发现新版后点「更新到最新版」:自动 `npm install -g` → 重新部署(含本机路径改写)→ 自动重启托盘,全程约 1 分钟,失败不影响当前托盘。
|
|
85
|
+
|
|
86
|
+
**方式二:npm 标准流程**——与普通 npm 包一致:
|
|
87
|
+
|
|
88
|
+
```powershell
|
|
89
|
+
npm up -g dsh-windows-tray # 拉取最新版
|
|
90
|
+
dsh-tray install # 重新部署(自动改写本机路径 + 刷新快捷方式)
|
|
91
|
+
dsh-tray # 重启托盘(或右键「退出托盘」后重新登录/双击快捷方式)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
> 部署目录固定为 `~\.dsh\launcher`,重装/更新都会覆盖旧文件,不会残留;`dsh-tray info` 可查看当前版本与部署状态。
|
|
95
|
+
|
|
96
|
+
## 卸载
|
|
97
|
+
|
|
98
|
+
```powershell
|
|
99
|
+
npm rm -g dsh-windows-tray # ① 移除 npm 包本体
|
|
100
|
+
# ② 删除快捷方式: 「DSH 系统托盘.lnk」(启动文件夹 + 桌面) + 「DeepSeek Harness (dsh).lnk」(启动文件夹)
|
|
101
|
+
# ③ 删除部署目录 ~\.dsh\launcher (如与 dsh 控制台共用, 确认无需保留再删)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## 工作原理
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
托盘(pwsh 常驻) ──2s 轮询──► 127.0.0.1:3080 (Web UI 端口)
|
|
108
|
+
│ └──────────────► node 进程命令行含 'dsh-tui' (TUI 进程)
|
|
109
|
+
├── 菜单动作 ──► dsh-actions.ps1 (独立隐藏进程, 不卡 UI)
|
|
110
|
+
├── 自更新 ──► dsh-update.ps1 (npm 安装→重部署→重启)
|
|
111
|
+
└── 单实例 ──► 命名互斥锁 (被强杀遗留的锁自动接管)
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
- **状态检测**:Web 用 TCP 端口探测(物理单实例);TUI 按命令行匹配(多实例安全:全查全杀);TUI 检测 20s 节流,打开菜单时强制刷新
|
|
115
|
+
- **动作隔离**:启动/停止/重启在独立进程执行,托盘 UI 永不卡顿
|
|
116
|
+
- **日志**:`~\.dsh\logs\dsh-windows-tray\`(`dsh-tray.log` 状态变化 / `dsh-tray-actions.log` 菜单动作 / `dsh-boot.log` 开机自启)
|
|
117
|
+
- **单点配置**:端口/路径等常量集中在 `launcher/dsh-lib.ps1`,安装时按本机自动改写——**包本身与机器无关**
|
|
118
|
+
|
|
119
|
+
## 配置
|
|
120
|
+
|
|
121
|
+
| 项 | 位置 | 默认 |
|
|
122
|
+
| :--- | :--- | :--- |
|
|
123
|
+
| 监控端口 | `~\.dsh\launcher\dsh-lib.ps1` 顶部 `$PORT` | `3080` |
|
|
124
|
+
| dsh 路径 | 同上(安装时自动改写) | 自动探测 |
|
|
125
|
+
| 图标颜色 | `build/build-tray-icons.ps1`(运行蓝/停止灰) | `#4176E6` / `#81858C` |
|
|
126
|
+
|
|
127
|
+
## 常见问题
|
|
128
|
+
|
|
129
|
+
| 问题 | 处理 |
|
|
130
|
+
| :--- | :--- |
|
|
131
|
+
| 任务栏看不到鲸鱼 | 点开 `^` 溢出区,把鲸鱼拖到任务栏(一次性) |
|
|
132
|
+
| 停止 Web UI 会关掉浏览器界面 | 对——停止前有确认框;Web 与当前会话在 3080 端口上 |
|
|
133
|
+
| 托盘退出了怎么唤回 | 双击桌面「DSH 系统托盘」快捷方式 / 重新登录(开机自启)/ `dsh-tray` |
|
|
134
|
+
| 怎么更新到新版 | 托盘菜单「版本信息 ▸ → 更新到最新版」一键完成;或 `npm up -g dsh-windows-tray` + `dsh-tray install`(见「如何更新」) |
|
|
135
|
+
| 检查更新失败 | 网络或 npm 不可用;托盘继续正常工作,稍后再试 |
|
|
136
|
+
| dsh 内核升级了,托盘要动吗 | 不用——托盘只探测 3080 端口与 TUI 进程命令行,与内核版本解耦 |
|
|
137
|
+
| 想彻底卸载 | `npm rm -g dsh-windows-tray` + 删除「DSH 系统托盘.lnk」与「DeepSeek Harness (dsh).lnk」+ 删除 `~\.dsh\launcher` |
|
|
138
|
+
| 开机后 dsh Web 没自动起 | 看 `~\.dsh\logs\dsh-windows-tray\dsh-boot.log`:末行 `boot ok (started)` = 正常;`boot FAILED` 后跟的错误即原因(隐藏窗口下日志是唯一线索),常见是 `~\.dsh\launcher` 被移动/删除 |
|
|
139
|
+
|
|
140
|
+
## 文档
|
|
141
|
+
|
|
142
|
+
- `docs/system-tray-guide.md` — 使用手册(安装部署 / 功能一览 / 更新 / 卸载 / 故障排查)
|
|
143
|
+
- `docs/tray-dev-archive.md` — 开发归档(架构决策与历史记录)
|
|
144
|
+
|
|
145
|
+
## 许可
|
|
146
|
+
|
|
147
|
+
MIT
|
package/bin/dsh-tray.js
CHANGED
|
@@ -38,8 +38,13 @@ switch (cmd) {
|
|
|
38
38
|
break;
|
|
39
39
|
|
|
40
40
|
case 'icons':
|
|
41
|
+
// 2026-09-12 修 wart:脚本默认 -OutDir = $PSScriptRoot\icons(包内 build/icons),**不刷新已部署目录**;
|
|
42
|
+
// 已部署时显式指到 <deployDir>\icons,未部署则落包内 launcher\icons(与发货路径一致)。
|
|
41
43
|
spawn(pwsh, ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-File',
|
|
42
|
-
path.join(root, 'build', 'build-tray-icons.ps1')
|
|
44
|
+
path.join(root, 'build', 'build-tray-icons.ps1'),
|
|
45
|
+
'-OutDir', fs.existsSync(path.join(deployDir, 'dsh-tray.ps1'))
|
|
46
|
+
? path.join(deployDir, 'icons')
|
|
47
|
+
: path.join(root, 'launcher', 'icons')],
|
|
43
48
|
{ stdio: 'inherit', windowsHide: true })
|
|
44
49
|
.on('exit', (code) => process.exit(code == null ? 1 : code));
|
|
45
50
|
break;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
# DSH 系统托盘(Windows)—— npm 包使用手册
|
|
2
2
|
|
|
3
3
|
> 包名: **`dsh-windows-tray`** · 部署位置: `~\.dsh\launcher` · 技术栈: PowerShell 7 + WinForms,零 npm 依赖、纯旁观者、不改 dsh 源码。
|
|
4
|
-
> 安装 / 更新 / 卸载全部走 npm 标准流程;开发归档见 [tray-dev-archive.md](tray-dev-archive.md),相关踩坑见 [powershell-pitfalls.md](powershell-pitfalls.md)。
|
|
4
|
+
> 安装 / 更新 / 卸载全部走 npm 标准流程;开发归档见 [tray-dev-archive.md](tray-dev-archive.md),相关踩坑见 [../../../docs/powershell-pitfalls.md](../../../docs/powershell-pitfalls.md)。
|
|
5
|
+
>
|
|
6
|
+
> **端口(2026-09-07 起)**:本包默认监控/使用端口为 **3080**。
|
|
5
7
|
|
|
6
8
|
---
|
|
7
9
|
|
|
@@ -14,7 +16,7 @@
|
|
|
14
16
|
npm i -g dsh-windows-tray
|
|
15
17
|
|
|
16
18
|
# 2. 一键部署:自动探测 dsh/pwsh/node 路径 → 安装到 ~\.dsh\launcher
|
|
17
|
-
# → 按本机路径改写配置 →
|
|
19
|
+
# → 按本机路径改写配置 → 创建开机自启(托盘 + harness Web)+ 桌面快捷方式 → 启动托盘
|
|
18
20
|
dsh-tray install
|
|
19
21
|
|
|
20
22
|
# 3. 首次使用:把任务栏 ^ 溢出区里的鲸鱼拖到任务栏(一次性,Windows 会记住)
|
|
@@ -22,6 +24,8 @@ dsh-tray install
|
|
|
22
24
|
|
|
23
25
|
### 安装后必做:本机参数探测 → 确认 → 回填(不要信默认值)
|
|
24
26
|
|
|
27
|
+
> **v1.0.2 起 install 已自动完成本节的探测与回填**(探测运行中 web 进程的端口与数据目录 → 展示确认 → 回填全部读取点 + 自动建日志目录)。以下命令仅用于**排查**或手动核对;旧版本(≤1.0.1)部署的机器仍需按此手工适配一次。
|
|
28
|
+
|
|
25
29
|
install 只自动改写 dsh/pwsh/node **路径**;**端口、数据目录按包默认值写入且不改**。与本机实际不一致时,症状是托盘永远灰鲸(探测错端口)或托盘/控制台启动的 web 落到空数据目录。先实测,人工确认数值,再回填到 §六 列出的**全部**填充点(只改一处会被另一处覆盖):
|
|
26
30
|
|
|
27
31
|
```powershell
|
|
@@ -48,21 +52,21 @@ Test-Path "$env:USERPROFILE\.dsh\settings.yaml" # True=默认目录;False=
|
|
|
48
52
|
| 交互 | 行为 |
|
|
49
53
|
| :--- | :--- |
|
|
50
54
|
| **图标** | 🐋 品牌蓝鲸鱼 = Web 运行中;灰鲸鱼 = 未运行(官方 favicon 渲染,多尺寸 16~256px) |
|
|
51
|
-
| **悬停提示** | `Web UI 运行中 · 127.0.0.1:
|
|
55
|
+
| **悬停提示** | `Web UI 运行中 · 127.0.0.1:3080` / `Web UI 未运行 · 右键可启动` |
|
|
52
56
|
| **双击** | 打开 Web UI(未运行时提示先启动) |
|
|
53
57
|
| **右键菜单** | 顶部 `Web UI 状态` / `TUI 状态` 双状态行(含 PID);`Web UI ▸`(打开 Web UI / 启动 / 停止(带确认) / 重启);`TUI ▸`(启动 / 停止);打开日志目录 / `版本信息 ▸`(版本 / 检查更新 / 更新到最新版)/ 退出托盘 |
|
|
54
58
|
| **菜单智能禁用** | Web 运行中禁用「启动 Web UI」;TUI 运行中禁用「启动 TUI」 |
|
|
55
59
|
| **状态通知** | Web/TUI 启动与停止瞬间弹系统通知;托盘就绪弹一次提示 |
|
|
56
|
-
| **开机自启** |
|
|
60
|
+
| **开机自启** | 登录后托盘自动出现 + dsh Web 静默拉起(两个启动文件夹快捷方式,安装时自动创建):「DSH 系统托盘.lnk」→ `dsh-tray.ps1`;「DeepSeek Harness (dsh).lnk」→ `dsh-boot.ps1`(点源 `dsh-lib.ps1` → `Start-Dsh -OpenBrowser:$false`) |
|
|
57
61
|
|
|
58
|
-
托盘每 2 秒探测一次 `127.0.0.1:
|
|
62
|
+
托盘每 2 秒探测一次 `127.0.0.1:3080`(TCP 连接,500ms 超时,开销可忽略);菜单动作在独立隐藏进程执行,托盘 UI 永不卡顿。
|
|
59
63
|
|
|
60
64
|
## 三、日常使用
|
|
61
65
|
|
|
62
66
|
1. **自动跟随**:在 dsh 控制台(`~\.dsh\launcher\dsh-control.ps1`)执行 启动/重启 Web 时,托盘会自动拉起(幂等)。
|
|
63
67
|
2. **手动唤起**:双击桌面「DSH 系统托盘」快捷方式;或 `dsh-tray`。
|
|
64
68
|
3. **退出托盘**:右键 → 退出托盘(只退出托盘本身,不影响 dsh;下次登录/双击快捷方式可重新唤起)。
|
|
65
|
-
4. **取消自启**:删除启动文件夹里的「DSH 系统托盘.lnk
|
|
69
|
+
4. **取消自启**:删除启动文件夹里的「DSH 系统托盘.lnk」与「DeepSeek Harness (dsh).lnk」(后者只关 dsh Web 的静默自启;托盘仍可从桌面快捷方式/控制台唤起)。
|
|
66
70
|
|
|
67
71
|
## 四、更新
|
|
68
72
|
|
|
@@ -85,7 +89,7 @@ dsh-tray # 重启托盘
|
|
|
85
89
|
|
|
86
90
|
```powershell
|
|
87
91
|
npm rm -g dsh-windows-tray # 移除 npm 包本体
|
|
88
|
-
#
|
|
92
|
+
# 删除三个「DSH 系统托盘.lnk」(启动文件夹 + 桌面)与启动文件夹里的「DeepSeek Harness (dsh).lnk」
|
|
89
93
|
# 删除 ~\.dsh\launcher 目录(托盘部署文件;如与 dsh 控制台共用,确认无需保留再删)
|
|
90
94
|
```
|
|
91
95
|
|
|
@@ -95,7 +99,7 @@ npm rm -g dsh-windows-tray # 移除 npm 包本体
|
|
|
95
99
|
|
|
96
100
|
| 项 | 位置 | 包默认 | 说明 |
|
|
97
101
|
| :--- | :--- | :--- | :--- |
|
|
98
|
-
| 监控端口 | ① `~\.dsh\launcher\dsh-lib.ps1` 顶部 `$PORT`;② `dsh-tray.ps1` 顶部 `param([int]$Port = …)` | `
|
|
102
|
+
| 监控端口 | ① `~\.dsh\launcher\dsh-lib.ps1` 顶部 `$PORT`;② `dsh-tray.ps1` 顶部 `param([int]$Port = …)` | `3080` | **两处必须一致**:托盘启动时先点源 lib 再执行 `$PORT = $Port`,**param 默认值会把 lib 改好的端口覆盖回去**(dsh-tray.ps1 第 27 行)——只改 lib 不改 param,托盘仍按默认端口探测 |
|
|
99
103
|
| dsh 路径 | `dsh-lib.ps1` 顶部 `$DSH_CMD / $NODE / $BIN` | 自动探测 | install 已改写,一般不用动 |
|
|
100
104
|
| 数据目录 | `dsh-lib.ps1` `$WORKDIR` + `$env:DSH_HOME` | **不设置** | 不设 DSH_HOME 时 web 默认落 `~\.dsh`——自定义数据目录的机器(如 `D:\dsh`)必须在 lib 里补 `$env:DSH_HOME`,否则托盘/控制台启动的 web 指向空目录 |
|
|
101
105
|
| 日志目录 | `dsh-lib.ps1` `$LOG_DIR`(`~\.dsh\logs`) | — | **目录须存在**:不存在时托盘 `Add-Content -ErrorAction SilentlyContinue` 静默吞日志,零日志不是没在记 |
|
|
@@ -107,7 +111,7 @@ npm rm -g dsh-windows-tray # 移除 npm 包本体
|
|
|
107
111
|
|
|
108
112
|
| 项 | 包默认 | 笔记本实际(2026-08-27 实测) | 填充点 |
|
|
109
113
|
| :--- | :--- | :--- | :--- |
|
|
110
|
-
| Web 端口 |
|
|
114
|
+
| Web 端口 | 3080 | **3080** | dsh-lib.ps1 `$PORT` + dsh-tray.ps1 param 默认值(两处) |
|
|
111
115
|
| 数据目录 | 不设→`~\.dsh` | **D:\dsh** | dsh-lib.ps1 `$WORKDIR='D:\dsh'` + `$env:DSH_HOME='D:\dsh'` |
|
|
112
116
|
| 日志目录 | `~\.dsh\logs`(可能不存在) | 已手动创建 | — |
|
|
113
117
|
| 旧控制台 | — | `D:\dsh\launcher\dsh-control.ps1` 与托盘部署并存,端口同为 3080 | 无需合并 |
|
|
@@ -124,10 +128,11 @@ npm rm -g dsh-windows-tray # 移除 npm 包本体
|
|
|
124
128
|
| 动作没反应 | 看 `~\.dsh\logs\dsh-tray-actions.log`(菜单动作)与 `dsh-tray.log`(状态变化)。 |
|
|
125
129
|
| 重复实例 | 命名互斥锁单实例保护(被强杀遗留的锁自动接管),正常不会重复。 |
|
|
126
130
|
| 检查更新失败 | 网络或 npm 不可用;托盘继续正常工作,稍后再试。 |
|
|
127
|
-
| dsh
|
|
131
|
+
| 开机后 dsh Web 没自动起 | 看 `~\.dsh\logs\dsh-windows-tray\dsh-boot.log`:末行 `boot ok (started)` = 正常;`boot FAILED` 后跟的错误即原因(自启是隐藏窗口,日志是唯一线索),常见是 `~\.dsh\launcher` 被移动/删除或 `dsh-boot.ps1` 被手工改名 |
|
|
132
|
+
| dsh 内核升级了,托盘要动吗 | 不用——托盘只探测 3080 端口与 TUI 进程命令行,与内核版本解耦。 |
|
|
128
133
|
|
|
129
134
|
## 八、已知边界
|
|
130
135
|
|
|
131
136
|
- 通知弹窗受 Windows「通知设置/专注助手」控制,被系统屏蔽时图标与菜单不受影响。
|
|
132
137
|
- 托盘进程是 `pwsh`,`taskkill /T` 杀进程树会连托盘一起结束(下次登录/快捷方式/控制台操作时恢复)。
|
|
133
|
-
- 端口探测只区分 运行/停止:
|
|
138
|
+
- 端口探测只区分 运行/停止:3080 被其他程序占用时会误判"运行中"。
|
package/docs/tray-dev-archive.md
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
# 系统托盘开发归档(v1.0.0 · 2026-08-27)
|
|
2
2
|
|
|
3
3
|
> 托盘已发布为 npm 包 **`dsh-windows-tray`**,日常安装 / 使用 / 更新 / 卸载见 [system-tray-guide.md](system-tray-guide.md)。
|
|
4
|
-
> 本文仅归档开发期的**架构决策与历史记录**(源码细节、文件清单不再维护);通用踩坑已归入 [powershell-pitfalls.md](powershell-pitfalls.md)。
|
|
4
|
+
> 本文仅归档开发期的**架构决策与历史记录**(源码细节、文件清单不再维护);通用踩坑已归入 [../../../docs/powershell-pitfalls.md](../../../docs/powershell-pitfalls.md)。
|
|
5
|
+
>
|
|
6
|
+
> **端口(2026-09-07 起)**:本包默认探测端口为 **3080**。
|
|
5
7
|
|
|
6
8
|
---
|
|
7
9
|
|
|
@@ -10,7 +12,7 @@
|
|
|
10
12
|
| 决策 | 理由 |
|
|
11
13
|
| :--- | :--- |
|
|
12
14
|
| **独立常驻进程**(不嵌入 dsh) | 需求是"看到未启动状态"——进程内嵌图标会随 dsh 消失;旁观者进程才能表达 运行/停止 两态,且能重启已死的 dsh |
|
|
13
|
-
| **端口探测**(每 2s TCP 连 127.0.0.1:
|
|
15
|
+
| **端口探测**(每 2s TCP 连 127.0.0.1:3080,500ms 超时) | 不持有进程句柄;dsh 重启 PID 变化也不误判;对 dsh 实现零依赖 |
|
|
14
16
|
| **动作独立进程**(隐藏执行) | 菜单动作(含 taskkill、等待轮询)不阻塞托盘 UI 线程 |
|
|
15
17
|
| **静态 .ico 图标资源** | 不依赖 dsh 运行时接口;缺失时 `New-FallbackIcon` 画纯色圆点兜底 |
|
|
16
18
|
| **命名互斥锁单实例** | 替代 WMI 扫描,无竞态;被强杀遗留的锁自动接管(AbandonedMutexException) |
|
|
@@ -19,7 +21,7 @@
|
|
|
19
21
|
进程模型:
|
|
20
22
|
|
|
21
23
|
```
|
|
22
|
-
托盘(pwsh) ──2s 轮询──► 端口
|
|
24
|
+
托盘(pwsh) ──2s 轮询──► 端口 3080 (dsh web)
|
|
23
25
|
│ └──────────────► node 进程命令行含 'dsh-tui' (TUI)
|
|
24
26
|
├── 菜单动作 ──► 独立隐藏进程 (带日志)
|
|
25
27
|
└── 自更新 ──► npm install -g → 重部署 → 重启托盘
|
|
@@ -51,7 +53,7 @@ npm 上两个同思路项目(`dsh-tray`、`dsh-tray-launcher`,均一周内
|
|
|
51
53
|
|
|
52
54
|
## 5. 已知边界
|
|
53
55
|
|
|
54
|
-
1.
|
|
56
|
+
1. 3080 被其他程序占用时托盘误判"运行中"(属端口问题,与托盘无关)
|
|
55
57
|
2. 二态检测:只区分 运行/停止,无法区分"忙/卡死"(可扩展 HTTP 探测做三态)
|
|
56
58
|
3. TUI 单实例是策略而非物理限制(见 §1 决策表)
|
|
57
59
|
4. 单实例互斥锁在极端竞态下仍有极小双启动概率(影响可忽略)
|
package/install.ps1
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# install.ps1 —— DSH 系统托盘
|
|
1
|
+
# install.ps1 —— DSH 系统托盘 一键部署(npm 包内运行;**唯一权威安装器**,无第二份副本)
|
|
2
2
|
# 用法: pwsh -NoProfile -ExecutionPolicy Bypass -File .\install.ps1 [-DshRoot <目录>] [-PwshPath <路径>] [-NodePath <路径>] [-Port <端口>] [-DshHome <数据目录>] [-Auto] [-NoTrayStart] [-NoShortcuts]
|
|
3
3
|
# 流程: 探测本机路径 -> 探测端口/数据目录并确认 -> 安装到 ~\.dsh\launcher -> 回填全部读取点(含端口两处+DSH_HOME) -> 创建快捷方式 -> 启动托盘
|
|
4
4
|
# v1.0.2: 端口/数据目录实测探测 + 展示确认 + 回填全部读取点 + 自动创建日志目录 (修: param 默认值覆盖 lib 端口 / DSH_HOME 不设 / 日志目录缺失静默丢日志)
|
|
@@ -91,7 +91,20 @@ if (-not $PwshPath -or -not (Test-Path $PwshPath)) { throw "未找到 pwsh (Powe
|
|
|
91
91
|
# 版本校验: 托盘常驻进程依赖 PowerShell 7.x (5.1 只能降级运行)
|
|
92
92
|
$pwshVer = & $PwshPath -NoProfile -Command '$PSVersionTable.PSVersion.ToString()' 2>$null
|
|
93
93
|
if ($pwshVer -notmatch '^7\.') { throw "pwsh 必须是 PowerShell 7.x (检测到: $pwshVer)。请安装 PowerShell 7 或用 -PwshPath 指定。" }
|
|
94
|
-
Write-Host "[2/7] pwsh: $PwshPath (v$pwshVer)" -ForegroundColor Green
|
|
94
|
+
Write-Host "[2/7] pwsh: $PwshPath (v$pwshVer)" -ForegroundColor Green
|
|
95
|
+
|
|
96
|
+
# 内核兼容软校验(release-standards §5.5 / package.json dshCompatibility):
|
|
97
|
+
# 只提醒不阻断——本包是外部工具,内核超出实测范围时多数功能仍可用(探测/启停与版本解耦)
|
|
98
|
+
$tested = @('0.1.1-rc.2', '0.1.2-rc.1', '0.1.5-rc.1', '0.1.5-rc.2')
|
|
99
|
+
$corePkg = Join-Path $DshRoot 'node_modules\@deepseek-ai\dsh\package.json'
|
|
100
|
+
if (Test-Path $corePkg) {
|
|
101
|
+
$coreVer = (Get-Content $corePkg -Raw | ConvertFrom-Json).version
|
|
102
|
+
if ($tested -notcontains $coreVer) {
|
|
103
|
+
Write-Host "[warn] dsh 内核 $coreVer 不在本包实测清单($($tested -join ' / '))——功能大概率可用,异常请先对照 CHANGELOG 的 dshCompatibility 再报。" -ForegroundColor Yellow
|
|
104
|
+
} else {
|
|
105
|
+
Write-Host "[2/7] dsh 内核 $coreVer 在实测清单内" -ForegroundColor Green
|
|
106
|
+
}
|
|
107
|
+
}
|
|
95
108
|
|
|
96
109
|
# 3) 探测 node
|
|
97
110
|
if (-not $NodePath) {
|
|
@@ -115,7 +128,7 @@ if (-not $DshHome) {
|
|
|
115
128
|
$probed = Find-DshHome
|
|
116
129
|
if ($probed) { $DshHome = $probed }
|
|
117
130
|
}
|
|
118
|
-
if ($Port -eq 0) { $Port =
|
|
131
|
+
if ($Port -eq 0) { $Port = 3080; Write-Host '警告: 未检测到运行中的 web 进程, 端口取包默认 3080 (如不符请用 -Port 指定)' -ForegroundColor Yellow }
|
|
119
132
|
if (-not $DshHome) { $DshHome = Join-Path $env:USERPROFILE '.dsh'; Write-Host "警告: 未探测到数据目录 (无 settings.yaml), 取默认 $DshHome (如不符请用 -DshHome 指定)" -ForegroundColor Yellow }
|
|
120
133
|
$Port = [int](Confirm-Value 'Web 端口' "$Port")
|
|
121
134
|
$DshHome = Confirm-Value '数据目录' $DshHome
|
|
@@ -227,7 +240,21 @@ namespace DSH.Shortcut {
|
|
|
227
240
|
New-Item -Path $nsKey -Force | Out-Null
|
|
228
241
|
Set-ItemProperty -Path $nsKey -Name 'Enabled' -Value 1 -Type DWord
|
|
229
242
|
Set-ItemProperty -Path $nsKey -Name 'ShowInActionCenter' -Value 1 -Type DWord
|
|
230
|
-
|
|
243
|
+
# harness (web) 开机自启 (2026-09-12): 与托盘同一战斗路径 —— dsh-boot.ps1 → dsh-lib Start-Dsh。
|
|
244
|
+
# 不走 dsh-menu.ps1 的原因: 它启动 node 时不重定向日志, dsh 0.1.2+ 的 launch token 落不到
|
|
245
|
+
# logs\dsh-windows-tray\web-menu.out.log, 托盘「打开 Web UI」只能回退裸 URL → 每次开机后见鉴权页。
|
|
246
|
+
# AUMID 与托盘同款: AUMID 由子进程继承, 开机时本脚本经 Ensure-DshTray 拉起的托盘通知身份不变。
|
|
247
|
+
$bootLnk = Join-Path ([Environment]::GetFolderPath('Startup')) 'DeepSeek Harness (dsh).lnk'
|
|
248
|
+
$boot = $ws.CreateShortcut($bootLnk)
|
|
249
|
+
$boot.TargetPath = $PwshPath
|
|
250
|
+
$boot.Arguments = '-NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File "' + (Join-Path $dst 'dsh-boot.ps1') + '"'
|
|
251
|
+
$boot.WorkingDirectory = $dst
|
|
252
|
+
$boot.IconLocation = $icon
|
|
253
|
+
$boot.WindowStyle = 7
|
|
254
|
+
$boot.Description = 'DeepSeek Harness (dsh) - 开机静默启动 dsh Web'
|
|
255
|
+
$boot.Save()
|
|
256
|
+
[DSH.Shortcut.Helper]::SetAumid($bootLnk, 'DSH.WindowsTray')
|
|
257
|
+
Write-Host '快捷方式: 开机自启(托盘 + harness) + 桌面 + 开始菜单 已创建 (AUMID=DSH.WindowsTray, 通知已预授权)' -ForegroundColor Green
|
|
231
258
|
}
|
|
232
259
|
|
|
233
260
|
# 启动托盘
|
|
@@ -239,6 +266,6 @@ if (-not $NoTrayStart) {
|
|
|
239
266
|
Write-Host ''
|
|
240
267
|
Write-Host '部署完成! 常用命令:' -ForegroundColor Cyan
|
|
241
268
|
Write-Host " 手动唤起托盘: 桌面「DSH 系统托盘」/ 控制台选项 5"
|
|
242
|
-
Write-Host ' 取消自启: 删除启动文件夹里的「DSH 系统托盘.lnk」'
|
|
269
|
+
Write-Host ' 取消自启: 删除启动文件夹里的「DSH 系统托盘.lnk」与「DeepSeek Harness (dsh).lnk」'
|
|
243
270
|
Write-Host ' 卸载: 删除快捷方式 + 删除 ~\.dsh\launcher'
|
|
244
271
|
Write-Host " 验证: $logDir\dsh-tray.log 首行「托盘启动 (…端口 $Port)」" -ForegroundColor Cyan
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# dsh-boot.ps1 -- DSH (DeepSeek Harness) logon autostart: bring up dsh web silently.
|
|
2
|
+
#
|
|
3
|
+
# Used by the Startup shortcut "DeepSeek Harness (dsh).lnk":
|
|
4
|
+
# pwsh.exe -NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File <this file>
|
|
5
|
+
#
|
|
6
|
+
# Why this file exists instead of calling dsh-menu.ps1 -Cmd start:
|
|
7
|
+
# dsh-menu.ps1 starts node WITHOUT redirecting stdout, so the dsh 0.1.2+ launch token
|
|
8
|
+
# never lands in logs\dsh-windows-tray\web-menu.out.log. The tray parses that file to
|
|
9
|
+
# open an ALREADY authorized Web UI tab; without it the tray falls back to the naked
|
|
10
|
+
# URL and the user gets the "authentication required" page after every boot.
|
|
11
|
+
# Routing through dsh-lib.ps1's Start-Dsh = the exact path the tray menu uses
|
|
12
|
+
# (hidden node, correct working dir, redirected logs, idempotent tray ensure).
|
|
13
|
+
#
|
|
14
|
+
# ASCII-ONLY ON PURPOSE: this file must stay parseable by Windows PowerShell 5.1 as well
|
|
15
|
+
# as pwsh 7. A no-BOM UTF-8 file with non-ASCII text is silently mis-parsed by 5.1
|
|
16
|
+
# (ParserError) -- that failure mode already cost one machine its autostart
|
|
17
|
+
# (see personal-docs dsh/docs/install-ledger.md, 2026-09-10 entry). Do not add non-ASCII here.
|
|
18
|
+
#
|
|
19
|
+
# Contract / boundaries:
|
|
20
|
+
# - exits 0 when web is up (started here or already running); exits 1 on any failure
|
|
21
|
+
# - every outcome is appended to dsh-boot.log (in the tray log dir once dsh-lib loads,
|
|
22
|
+
# else %TEMP%) -- hidden window means the log is the only diagnostic channel
|
|
23
|
+
# - idempotent: safe to run next to the tray's own autostart shortcut (dsh-lib reuses
|
|
24
|
+
# the existing listener; dsh-tray.ps1 is mutex-guarded)
|
|
25
|
+
|
|
26
|
+
$ErrorActionPreference = 'Stop'
|
|
27
|
+
$script:LogPath = Join-Path $env:TEMP 'dsh-boot.log'
|
|
28
|
+
|
|
29
|
+
function Write-BootLog([string]$Message) {
|
|
30
|
+
try {
|
|
31
|
+
Add-Content -LiteralPath $script:LogPath -Value ('[{0}] {1}' -f (Get-Date -Format 'yyyy-MM-dd HH:mm:ss'), $Message) -ErrorAction SilentlyContinue
|
|
32
|
+
} catch { }
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
$lib = Join-Path $PSScriptRoot 'dsh-lib.ps1'
|
|
37
|
+
if (-not (Test-Path -LiteralPath $lib)) { throw "dsh-lib.ps1 not found next to dsh-boot.ps1: $lib" }
|
|
38
|
+
. $lib
|
|
39
|
+
if ($LOG_DIR) { $script:LogPath = Join-Path $LOG_DIR 'dsh-boot.log' }
|
|
40
|
+
|
|
41
|
+
Write-BootLog ('boot begin (pid {0})' -f $PID)
|
|
42
|
+
$before = @(Get-WebPid)
|
|
43
|
+
Start-Dsh -OpenBrowser:$false
|
|
44
|
+
$after = @(Get-WebPid)
|
|
45
|
+
if ($after.Count -gt 0) {
|
|
46
|
+
$how = 'started'
|
|
47
|
+
if ($before.Count -gt 0) { $how = 'already running' }
|
|
48
|
+
Write-BootLog ('boot ok ({0}), web pid: {1}' -f $how, ($after -join ','))
|
|
49
|
+
} else {
|
|
50
|
+
Write-BootLog ('boot FAILED: port {0} not listening after start (see web-menu.err.log)' -f $PORT)
|
|
51
|
+
exit 1
|
|
52
|
+
}
|
|
53
|
+
} catch {
|
|
54
|
+
Write-BootLog ('boot FAILED: ' + $_.Exception.Message)
|
|
55
|
+
exit 1
|
|
56
|
+
}
|
package/launcher/dsh-control.ps1
CHANGED
|
@@ -13,7 +13,7 @@ while ($true) {
|
|
|
13
13
|
Write-Host ' ┌──────────────────────────────┐'
|
|
14
14
|
Write-Host ' │ DSH 控制台 │'
|
|
15
15
|
Write-Host ' ├──────────────────────────────┤'
|
|
16
|
-
Write-Host ' │ 1) 启动 / 打开 Web (
|
|
16
|
+
Write-Host ' │ 1) 启动 / 打开 Web (3080) │'
|
|
17
17
|
Write-Host ' │ 2) 重启 Web │'
|
|
18
18
|
Write-Host ' │ 3) 启动 TUI(新终端窗口) │'
|
|
19
19
|
Write-Host ' │ 4) 查看状态 │'
|
package/launcher/dsh-lib.ps1
CHANGED
|
@@ -7,12 +7,12 @@ $DSH_CMD = 'D:\Program Files (x86)\dsh\dsh.cmd'
|
|
|
7
7
|
$NODE = 'C:\Program Files\nodejs\node.exe'
|
|
8
8
|
$BIN = 'D:\Program Files (x86)\dsh\node_modules\@deepseek-ai\dsh\lib\bin.js'
|
|
9
9
|
$WORKDIR = 'D:\Program Files (x86)\dsh'
|
|
10
|
-
$PORT =
|
|
10
|
+
$PORT = 3080
|
|
11
11
|
$URL = "http://127.0.0.1:$PORT"
|
|
12
12
|
$LOG_DIR = Join-Path (Join-Path $env:USERPROFILE '.dsh\logs') 'dsh-windows-tray' # 本插件专属日志目录 (logs\<插件名>\, 边界规则见 release-standards §3.1)
|
|
13
13
|
$WT = "$env:LOCALAPPDATA\Microsoft\WindowsApps\wt.exe"
|
|
14
14
|
$PWSH = 'D:\Program Files (x86)\PowerShell-7.6.4\pwsh.exe'
|
|
15
|
-
$TRAY_VERSION = '1.0.
|
|
15
|
+
$TRAY_VERSION = '1.0.13' # 托盘版本 (与 npm 包版本同步, 用于日志/排查)
|
|
16
16
|
$TRAY_PKG = 'dsh-windows-tray' # npm 包名 (托盘自更新)
|
|
17
17
|
$TRAY_SCRIPT = Join-Path $PSScriptRoot 'dsh-tray.ps1'
|
|
18
18
|
|
|
@@ -75,6 +75,15 @@ function Initialize-LogDir {
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
function Get-WebPid {
|
|
78
|
+
# 优化(1.0.12): netstat 解析优先 (原 Get-NetTCPConnection 在本机 727 进程下 avg 1.3s,
|
|
79
|
+
# 直接拖慢右键菜单转态路径); 解析失败回退 CIM 查询
|
|
80
|
+
try {
|
|
81
|
+
$pids = @()
|
|
82
|
+
foreach ($row in (& netstat -ano -p tcp 2>$null)) {
|
|
83
|
+
if ($row -match ":$PORT\s+\S+\s+LISTENING\s+(\d+)\s*$") { $pids += $Matches[1] }
|
|
84
|
+
}
|
|
85
|
+
if ($pids.Count -gt 0) { return @($pids | Sort-Object -Unique) }
|
|
86
|
+
} catch { }
|
|
78
87
|
@((Get-NetTCPConnection -LocalPort $PORT -State Listen -ErrorAction SilentlyContinue).OwningProcess | Select-Object -Unique)
|
|
79
88
|
}
|
|
80
89
|
|
|
@@ -160,10 +169,12 @@ function Start-Tui {
|
|
|
160
169
|
|
|
161
170
|
# TUI 进程树: 外壳 pwsh(-NoExit) → cmd(dsh.cmd) → node(bin.js), 三层命令行都含 dsh-tui
|
|
162
171
|
# 按进程名白名单过滤, 防止误杀命令行里恰好含 dsh-tui 的其他程序 (如 WindowsTerminal.exe 本体)
|
|
172
|
+
# 优化(1.0.12): WQL 先按 Name 窄集 (原全量枚举会拉全部进程的 CommandLine);
|
|
173
|
+
# ⚠️ 本机实测任何 Win32_Process 查询固定 ~450-570ms (WinRM 不可用, DCOM/持久会话均无效)——
|
|
174
|
+
# **调用方 (托盘状态刷新) 必须在 ThreadJob 里异步跑, 禁止在 UI/菜单路径同步调用** (见 dsh-tray.ps1)
|
|
163
175
|
function Get-TuiTree {
|
|
164
|
-
Get-CimInstance Win32_Process -ErrorAction SilentlyContinue | Where-Object {
|
|
165
|
-
$_.ProcessId -ne $PID -and $_.CommandLine -and
|
|
166
|
-
$_.CommandLine -match 'dsh-tui' -and $_.Name -match '^(node|cmd|pwsh|powershell)\.exe$'
|
|
176
|
+
Get-CimInstance Win32_Process -Filter "Name='node.exe' OR Name='cmd.exe' OR Name='pwsh.exe' OR Name='powershell.exe'" -ErrorAction SilentlyContinue | Where-Object {
|
|
177
|
+
$_.ProcessId -ne $PID -and $_.CommandLine -and $_.CommandLine -match 'dsh-tui'
|
|
167
178
|
}
|
|
168
179
|
}
|
|
169
180
|
|
|
@@ -342,8 +353,7 @@ function Show-Status {
|
|
|
342
353
|
# ---- 系统托盘 ----
|
|
343
354
|
|
|
344
355
|
function Get-TrayProcesses {
|
|
345
|
-
Get-CimInstance Win32_Process -ErrorAction SilentlyContinue | Where-Object {
|
|
346
|
-
($_.Name -eq 'pwsh.exe' -or $_.Name -eq 'powershell.exe') -and
|
|
356
|
+
Get-CimInstance Win32_Process -Filter "Name='pwsh.exe' OR Name='powershell.exe'" -ErrorAction SilentlyContinue | Where-Object {
|
|
347
357
|
$_.CommandLine -and $_.CommandLine -match 'dsh-tray\.ps1' -and
|
|
348
358
|
$_.ProcessId -ne $PID
|
|
349
359
|
}
|
package/launcher/dsh-tray.ps1
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
# - TUI 状态独立检测: 菜单项按 TUI 是否运行自动禁用/启用
|
|
13
13
|
# - 浅色圆角菜单(借鉴社区 dsh-tray 方案) + npm 自更新(借鉴 dsh-tray-launcher 方案)
|
|
14
14
|
param(
|
|
15
|
-
[int]$Port =
|
|
15
|
+
[int]$Port = 3080,
|
|
16
16
|
[switch]$NoBalloon
|
|
17
17
|
)
|
|
18
18
|
$ErrorActionPreference = 'Stop'
|
|
@@ -354,31 +354,66 @@ $script:prevState = $null # $null=初始; $true=运行; $false=停止
|
|
|
354
354
|
$script:prevTui = $null # TUI 状态 ($null=初始; $true=运行; $false=停止)
|
|
355
355
|
$script:firstRun = $true # 首次刷新只设图标, 不弹变化通知
|
|
356
356
|
$script:lastTuiCheck = 0 # TUI 检测节流 (常规 20s 一次, 打开菜单时强制)
|
|
357
|
+
$script:tuiJob = $null # 运行中的 TUI 检测任务 (1.0.12 异步化)
|
|
358
|
+
$script:tuiRefreshQueued = $false # 任务在跑期间又到期/强制刷新 → 完成后立即再刷
|
|
359
|
+
|
|
360
|
+
# ThreadJob 异步化 (1.0.12): 本机实测任何 Win32_Process WMI 查询固定 ~450-570ms
|
|
361
|
+
# (WinRM 不可用, WSMAN/DCOM 持久会话均无效) —— 若在菜单 Opening / 状态 tick 同步跑,
|
|
362
|
+
# 右键菜单会被 WinForms 卡住 (Opening 未返回不渲染)。TUI 检测改为后台任务,
|
|
363
|
+
# 结果由 2s 定时器在 UI 线程回收应用; ThreadJob 模块缺失时降级同步 (旧行为)。
|
|
364
|
+
Import-Module Microsoft.PowerShell.ThreadJob -ErrorAction SilentlyContinue
|
|
365
|
+
$script:threadJobOk = $null -ne (Get-Command Start-ThreadJob -ErrorAction SilentlyContinue)
|
|
366
|
+
|
|
367
|
+
function Apply-TuiStatus {
|
|
368
|
+
param([object[]]$tuiProcs)
|
|
369
|
+
$tuiRunning = $tuiProcs.Count -gt 0
|
|
370
|
+
if ($tuiRunning) {
|
|
371
|
+
$itemTuiStatus.Text = "TUI 状态: 运行中 (PID $(($tuiProcs.ProcessId) -join ','))"
|
|
372
|
+
} else {
|
|
373
|
+
$itemTuiStatus.Text = 'TUI 状态: 未运行'
|
|
374
|
+
}
|
|
375
|
+
if ($tuiRunning -ne $script:prevTui) {
|
|
376
|
+
$script:prevTui = $tuiRunning
|
|
377
|
+
$itemTuiStart.Enabled = -not $tuiRunning
|
|
378
|
+
$itemTuiStop.Enabled = $tuiRunning
|
|
379
|
+
if ($tuiRunning) {
|
|
380
|
+
Log "TUI: 运行中 (PID $(($tuiProcs.ProcessId) -join ','))"
|
|
381
|
+
} else {
|
|
382
|
+
Log 'TUI: 未运行'
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
357
386
|
|
|
358
387
|
function Update-State {
|
|
359
388
|
param([switch]$ForceTui)
|
|
360
389
|
try {
|
|
361
|
-
# TUI
|
|
362
|
-
if ($
|
|
363
|
-
$script:
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
$
|
|
368
|
-
|
|
369
|
-
$
|
|
390
|
+
# --- TUI 检测: 异步, 绝不阻塞 UI —— 先回收已完成任务, 再按需排程 ---
|
|
391
|
+
if ($script:threadJobOk) {
|
|
392
|
+
if ($script:tuiJob -and $script:tuiJob.State -ne 'Running') {
|
|
393
|
+
$tuiProcs = @(Receive-Job -Job $script:tuiJob -ErrorAction SilentlyContinue)
|
|
394
|
+
Remove-Job $script:tuiJob -Force -ErrorAction SilentlyContinue
|
|
395
|
+
$script:tuiJob = $null
|
|
396
|
+
$script:lastTuiCheck = [Environment]::TickCount
|
|
397
|
+
Apply-TuiStatus $tuiProcs
|
|
398
|
+
if ($script:tuiRefreshQueued) { $script:tuiRefreshQueued = $false; $script:lastTuiCheck = 0 }
|
|
370
399
|
}
|
|
371
|
-
if ($
|
|
372
|
-
$script:
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
400
|
+
if ($ForceTui -or (([Environment]::TickCount - $script:lastTuiCheck) -gt 20000)) {
|
|
401
|
+
if (-not $script:tuiJob) {
|
|
402
|
+
$libPath = Join-Path $PSScriptRoot 'dsh-lib.ps1'
|
|
403
|
+
$script:tuiJob = Start-ThreadJob -ScriptBlock {
|
|
404
|
+
param($lib)
|
|
405
|
+
. $lib
|
|
406
|
+
@(Get-TuiProcesses)
|
|
407
|
+
} -ArgumentList $libPath
|
|
377
408
|
} else {
|
|
378
|
-
|
|
409
|
+
$script:tuiRefreshQueued = $true
|
|
379
410
|
}
|
|
380
411
|
}
|
|
412
|
+
} elseif ($ForceTui -or (([Environment]::TickCount - $script:lastTuiCheck) -gt 20000)) {
|
|
413
|
+
$script:lastTuiCheck = [Environment]::TickCount
|
|
414
|
+
Apply-TuiStatus (@(Get-TuiProcesses))
|
|
381
415
|
}
|
|
416
|
+
# --- Web 状态: Test-Port ~11ms + 转态才查 PID (netstat ~42ms), 保持在 UI 线程 ---
|
|
382
417
|
$running = Test-Port $PORT
|
|
383
418
|
if ($running -eq $script:prevState -and -not $script:firstRun) { return } # 无变化
|
|
384
419
|
$script:prevState = $running
|
|
@@ -426,5 +461,6 @@ $timer.Dispose()
|
|
|
426
461
|
$menu.Dispose()
|
|
427
462
|
$iconRun.Dispose(); $iconStop.Dispose()
|
|
428
463
|
try { $mutex.ReleaseMutex() } catch { }
|
|
464
|
+
try { if ($script:tuiJob) { Remove-Job $script:tuiJob -Force -ErrorAction SilentlyContinue; $script:tuiJob = $null } } catch { }
|
|
429
465
|
Log '托盘已退出'
|
|
430
466
|
|
package/package.json
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-windows-tray",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.13",
|
|
4
4
|
"description": "DSH (DeepSeek Harness) Windows 系统托盘: 蓝/灰鲸鱼状态图标 + Web/TUI 一键启停控制。纯 PowerShell + WinForms, 零依赖。",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "jankin_lv",
|
|
7
|
-
|
|
7
|
+
"dshCompatibility": {
|
|
8
|
+
"testedVersions": ["0.1.1-rc.2", "0.1.2-rc.1", "0.1.5-rc.1", "0.1.5-rc.2"],
|
|
9
|
+
"range": ">=0.1.1-rc.2 <0.2.0",
|
|
10
|
+
"scope": "external-tool(本包不 import 任何 @deepseek-ai 代码:只拉起 dsh 的 bin.js web、探测 3080 端口、按进程命令行识别 TUI;故不声明 @deepseek-ai peerDependencies——那只会给用户刷 unmet peer 警告而买不到任何真实校验)",
|
|
11
|
+
"note": "dsh ≥0.1.2-rc.1 起 web 用一次性 launch token;托盘 ≥1.0.11 才会解析它(本包 1.0.13)"
|
|
12
|
+
},"keywords": [
|
|
8
13
|
"dsh",
|
|
9
14
|
"deepseek",
|
|
10
15
|
"harness",
|