dsh-windows-tray 1.0.2 → 1.0.4

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.
@@ -12,7 +12,7 @@ $URL = "http://127.0.0.1:$PORT"
12
12
  $LOG_DIR = "$env:USERPROFILE\.dsh\logs"
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.2' # 托盘版本 (与 npm 包版本同步, 用于日志/排查)
15
+ $TRAY_VERSION = '1.0.4' # 托盘版本 (与 npm 包版本同步, 用于日志/排查)
16
16
  $TRAY_PKG = 'dsh-windows-tray' # npm 包名 (托盘自更新)
17
17
  $TRAY_SCRIPT = Join-Path $PSScriptRoot 'dsh-tray.ps1'
18
18
 
@@ -89,6 +89,13 @@ function Start-Tui {
89
89
  Write-Host "[tui] TUI 已在运行 (PID $($existing.ProcessId -join ',')), 不重复启动" -ForegroundColor Yellow
90
90
  return
91
91
  }
92
+ # 清理上次强杀残留的外壳 (node 已死但 pwsh -NoExit 窗口还在)
93
+ $stale = @(Get-TuiTree)
94
+ if ($stale.Count -gt 0) {
95
+ Write-Host '[tui] 清理上次残留的 TUI 外壳进程' -ForegroundColor DarkGray
96
+ foreach ($p in $stale) { & taskkill /PID $p.ProcessId /T /F 2>$null | Out-Null }
97
+ Start-Sleep -Milliseconds 500
98
+ }
92
99
  $cmdLine = "& '$DSH_CMD' --profile dsh-tui"
93
100
  if (Test-Path $WT) {
94
101
  $args = "new-tab --title `"DSH TUI`" pwsh -NoExit -Command `"$cmdLine`""
@@ -103,21 +110,53 @@ function Start-Tui {
103
110
  }
104
111
  }
105
112
 
113
+ # TUI 进程树: 外壳 pwsh(-NoExit) → cmd(dsh.cmd) → node(bin.js), 三层命令行都含 dsh-tui
114
+ # 按进程名白名单过滤, 防止误杀命令行里恰好含 dsh-tui 的其他程序 (如 WindowsTerminal.exe 本体)
115
+ function Get-TuiTree {
116
+ Get-CimInstance Win32_Process -ErrorAction SilentlyContinue | Where-Object {
117
+ $_.ProcessId -ne $PID -and $_.CommandLine -and
118
+ $_.CommandLine -match 'dsh-tui' -and $_.Name -match '^(node|cmd|pwsh|powershell)\.exe$'
119
+ }
120
+ }
121
+
122
+ # 真正的 TUI 主进程 (node) —— 供状态显示 / 防重复启动
106
123
  function Get-TuiProcesses {
107
- Get-CimInstance Win32_Process -Filter "Name='node.exe'" -ErrorAction SilentlyContinue |
108
- Where-Object { $_.CommandLine -match 'dsh-tui' }
124
+ @(Get-TuiTree | Where-Object { $_.Name -eq 'node.exe' })
109
125
  }
110
126
 
111
127
  function Stop-Tui {
112
- $tui = @(Get-TuiProcesses)
113
- if ($tui.Count -eq 0) { Write-Host '[tui] TUI: 未在运行'; return }
114
- foreach ($p in $tui) {
115
- Write-Host "[tui] 停止 TUI 进程 $($p.ProcessId)"
116
- & taskkill /PID $p.ProcessId /T /F 2>$null | Out-Null
128
+ $tree = @(Get-TuiTree)
129
+ if ($tree.Count -eq 0) { Write-Host '[tui] TUI: 未在运行'; return }
130
+ # 从树根整树终止 (根 = 父进程不在树中的进程, 即 pwsh -NoExit 外壳)。
131
+ # 只杀 node 会导致外壳与窗口残留, 终端停在 raw mode 刷乱码且关不掉
132
+ $ids = @($tree | ForEach-Object { $_.ProcessId })
133
+ $roots = @($tree | Where-Object { $ids -notcontains $_.ParentProcessId })
134
+ foreach ($r in $roots) {
135
+ Write-Host "[tui] 停止 TUI 进程树 (根 PID $($r.ProcessId) $($r.Name))"
136
+ & taskkill /PID $r.ProcessId /T /F 2>$null | Out-Null
137
+ }
138
+ for ($i = 0; $i -lt 5; $i++) {
139
+ Start-Sleep -Milliseconds 600
140
+ if (@(Get-TuiTree).Count -eq 0) { break }
141
+ }
142
+ if (@(Get-TuiTree).Count -gt 0) { Write-Host '[tui] TUI 进程未完全退出,请稍后重试' -ForegroundColor Red }
143
+ else {
144
+ # 收尾: 关闭专为 TUI 开的 Windows Terminal 窗口。
145
+ # 强杀外壳退出码非 0, WT 默认 closeOnExit=graceful 不自动关标签, 会留死面板;
146
+ # 仅当该 WT 已无任何存活子进程时才关 — 用户在窗口里另开的标签仍在, 此时不动
147
+ $wts = @(Get-CimInstance Win32_Process -Filter "Name='WindowsTerminal.exe'" -ErrorAction SilentlyContinue |
148
+ Where-Object { $_.CommandLine -and $_.CommandLine -match 'dsh-tui' })
149
+ foreach ($w in $wts) {
150
+ $kids = @(Get-CimInstance Win32_Process -ErrorAction SilentlyContinue | Where-Object { $_.ParentProcessId -eq $w.ProcessId })
151
+ if ($kids.Count -eq 0) {
152
+ Write-Host "[tui] 关闭 TUI 终端窗口 (PID $($w.ProcessId))"
153
+ & taskkill /PID $w.ProcessId /F 2>$null | Out-Null
154
+ } else {
155
+ Write-Host "[tui] 终端窗口 (PID $($w.ProcessId)) 还有其他标签页, 保留" -ForegroundColor DarkGray
156
+ }
157
+ }
158
+ Write-Host '[tui] TUI 已停止' -ForegroundColor Yellow
117
159
  }
118
- Start-Sleep -Seconds 1
119
- if (@(Get-TuiProcesses).Count -gt 0) { Write-Host '[tui] TUI 进程未完全退出,请稍后重试' -ForegroundColor Red }
120
- else { Write-Host '[tui] TUI 已停止' -ForegroundColor Yellow }
121
160
  }
122
161
 
123
162
  function Show-Status {
@@ -1,93 +1,93 @@
1
- # dsh (DeepSeek Harness) 启动器 —— 公司机部署 2026-08-14
2
- # 用法:
3
- # 交互菜单: 双击 dsh-menu.bat
4
- # 非交互: dsh-menu.ps1 -Cmd start|stop|status
5
- # 坑: 不要在本脚本内对 Start-Process 用 -RedirectStandardOutput
6
- # (父进程 stdout 被重定向时挂起, 见 LEARNED #53)
7
- param(
8
- [string]$Cmd
9
- )
10
- $ErrorActionPreference = 'Stop'
11
-
12
- $DSH_CMD = 'D:\Program Files (x86)\dsh\dsh.cmd'
13
- $PORT = 3080
14
- $URL = 'http://127.0.0.1:3080'
15
-
16
- function Test-Port([int]$port) {
17
- $client = New-Object System.Net.Sockets.TcpClient
18
- try {
19
- $async = $client.BeginConnect('127.0.0.1', $port, $null, $null)
20
- if ($async.AsyncWaitHandle.WaitOne(500) -and $client.Connected) { return $true }
21
- return $false
22
- } catch { return $false }
23
- finally { $client.Close() }
24
- }
25
-
26
- function Start-Dsh {
27
- if (Test-Port $PORT) {
28
- Write-Output "[dsh] 端口 $PORT 已监听, 服务已在运行, 不重复启动"
29
- return
30
- }
31
- Start-Process -FilePath $DSH_CMD -ArgumentList 'web' -WindowStyle Hidden
32
- Start-Sleep -Seconds 6
33
- if (Test-Port $PORT) {
34
- Write-Output "[dsh] 启动成功: $URL"
35
- } else {
36
- Start-Sleep -Seconds 5
37
- if (Test-Port $PORT) {
38
- Write-Output "[dsh] 启动成功: $URL"
39
- } else {
40
- Write-Output "[dsh] 启动失败: 端口 $PORT 未监听, 请手工运行 dsh web 查看报错"
41
- }
42
- }
43
- }
44
-
45
- function Stop-Dsh {
46
- $pids = @((Get-NetTCPConnection -LocalPort $PORT -State Listen -ErrorAction SilentlyContinue).OwningProcess | Select-Object -Unique)
47
- if ($pids.Count -eq 0) {
48
- Write-Output '[dsh] 服务未在运行'
49
- return
50
- }
51
- foreach ($p in $pids) {
52
- Write-Output "[dsh] 停止进程 $p"
53
- & taskkill /PID $p /T /F 2>$null | Out-Null
54
- }
55
- Start-Sleep -Seconds 2
56
- if (Test-Port $PORT) { Write-Output '[dsh] 停止失败: 端口仍在监听' }
57
- else { Write-Output '[dsh] 已停止' }
58
- }
59
-
60
- function Show-Status {
61
- if (Test-Port $PORT) { Write-Output "[dsh] 运行中: $URL" }
62
- else { Write-Output '[dsh] 未运行' }
63
- }
64
-
65
- # ---------- 非交互模式 ----------
66
- if ($Cmd) {
67
- switch ($Cmd.ToLower()) {
68
- 'start' { Start-Dsh }
69
- 'stop' { Stop-Dsh }
70
- 'status' { Show-Status }
71
- default { Write-Output '用法: dsh-menu.ps1 -Cmd start|stop|status' }
72
- }
73
- exit
74
- }
75
-
76
- # ---------- 交互菜单 ----------
77
- while ($true) {
78
- Write-Output ''
79
- Write-Output '======== dsh 启动器 ========'
80
- Show-Status
81
- Write-Output '[1] 启动并打开浏览器'
82
- Write-Output '[2] 停止'
83
- Write-Output '[3] 状态'
84
- Write-Output '[0] 退出'
85
- $choice = Read-Host '请选择'
86
- switch ($choice) {
87
- '1' { Start-Dsh; Start-Process $URL; }
88
- '2' { Stop-Dsh }
89
- '3' { Show-Status }
90
- '0' { exit }
91
- default { Write-Output '无效选择' }
92
- }
93
- }
1
+ # dsh (DeepSeek Harness) 启动器 —— 公司机部署 2026-08-14
2
+ # 用法:
3
+ # 交互菜单: 双击 dsh-menu.bat
4
+ # 非交互: dsh-menu.ps1 -Cmd start|stop|status
5
+ # 坑: 不要在本脚本内对 Start-Process 用 -RedirectStandardOutput
6
+ # (父进程 stdout 被重定向时挂起, 见 LEARNED #53)
7
+ param(
8
+ [string]$Cmd
9
+ )
10
+ $ErrorActionPreference = 'Stop'
11
+
12
+ $DSH_CMD = 'D:\Program Files (x86)\dsh\dsh.cmd'
13
+ $PORT = 3080
14
+ $URL = 'http://127.0.0.1:3080'
15
+
16
+ function Test-Port([int]$port) {
17
+ $client = New-Object System.Net.Sockets.TcpClient
18
+ try {
19
+ $async = $client.BeginConnect('127.0.0.1', $port, $null, $null)
20
+ if ($async.AsyncWaitHandle.WaitOne(500) -and $client.Connected) { return $true }
21
+ return $false
22
+ } catch { return $false }
23
+ finally { $client.Close() }
24
+ }
25
+
26
+ function Start-Dsh {
27
+ if (Test-Port $PORT) {
28
+ Write-Output "[dsh] 端口 $PORT 已监听, 服务已在运行, 不重复启动"
29
+ return
30
+ }
31
+ Start-Process -FilePath $DSH_CMD -ArgumentList 'web' -WindowStyle Hidden
32
+ Start-Sleep -Seconds 6
33
+ if (Test-Port $PORT) {
34
+ Write-Output "[dsh] 启动成功: $URL"
35
+ } else {
36
+ Start-Sleep -Seconds 5
37
+ if (Test-Port $PORT) {
38
+ Write-Output "[dsh] 启动成功: $URL"
39
+ } else {
40
+ Write-Output "[dsh] 启动失败: 端口 $PORT 未监听, 请手工运行 dsh web 查看报错"
41
+ }
42
+ }
43
+ }
44
+
45
+ function Stop-Dsh {
46
+ $pids = @((Get-NetTCPConnection -LocalPort $PORT -State Listen -ErrorAction SilentlyContinue).OwningProcess | Select-Object -Unique)
47
+ if ($pids.Count -eq 0) {
48
+ Write-Output '[dsh] 服务未在运行'
49
+ return
50
+ }
51
+ foreach ($p in $pids) {
52
+ Write-Output "[dsh] 停止进程 $p"
53
+ & taskkill /PID $p /T /F 2>$null | Out-Null
54
+ }
55
+ Start-Sleep -Seconds 2
56
+ if (Test-Port $PORT) { Write-Output '[dsh] 停止失败: 端口仍在监听' }
57
+ else { Write-Output '[dsh] 已停止' }
58
+ }
59
+
60
+ function Show-Status {
61
+ if (Test-Port $PORT) { Write-Output "[dsh] 运行中: $URL" }
62
+ else { Write-Output '[dsh] 未运行' }
63
+ }
64
+
65
+ # ---------- 非交互模式 ----------
66
+ if ($Cmd) {
67
+ switch ($Cmd.ToLower()) {
68
+ 'start' { Start-Dsh }
69
+ 'stop' { Stop-Dsh }
70
+ 'status' { Show-Status }
71
+ default { Write-Output '用法: dsh-menu.ps1 -Cmd start|stop|status' }
72
+ }
73
+ exit
74
+ }
75
+
76
+ # ---------- 交互菜单 ----------
77
+ while ($true) {
78
+ Write-Output ''
79
+ Write-Output '======== dsh 启动器 ========'
80
+ Show-Status
81
+ Write-Output '[1] 启动并打开浏览器'
82
+ Write-Output '[2] 停止'
83
+ Write-Output '[3] 状态'
84
+ Write-Output '[0] 退出'
85
+ $choice = Read-Host '请选择'
86
+ switch ($choice) {
87
+ '1' { Start-Dsh; Start-Process $URL; }
88
+ '2' { Stop-Dsh }
89
+ '3' { Show-Status }
90
+ '0' { exit }
91
+ default { Write-Output '无效选择' }
92
+ }
93
+ }
@@ -1,10 +1,10 @@
1
- @echo off
2
- chcp 65001 >nul
3
- rem DSH 系统托盘 - double click to start (blue whale = running, gray = stopped)
4
- rem prefer pwsh (PowerShell 7), fallback to powershell 5.1
5
- where pwsh >nul 2>nul
6
- if %errorlevel%==0 (
7
- start "" pwsh -NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File "%~dp0dsh-tray.ps1"
8
- ) else (
9
- start "" powershell -NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File "%~dp0dsh-tray.ps1"
10
- )
1
+ @echo off
2
+ chcp 65001 >nul
3
+ rem DSH 系统托盘 - double click to start (blue whale = running, gray = stopped)
4
+ rem prefer pwsh (PowerShell 7), fallback to powershell 5.1
5
+ where pwsh >nul 2>nul
6
+ if %errorlevel%==0 (
7
+ start "" pwsh -NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File "%~dp0dsh-tray.ps1"
8
+ ) else (
9
+ start "" powershell -NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File "%~dp0dsh-tray.ps1"
10
+ )