dsh-windows-tray 1.0.6 → 1.0.8

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/install.ps1 CHANGED
@@ -16,7 +16,7 @@ param(
16
16
  $ErrorActionPreference = 'Stop'
17
17
  $pkgRoot = $PSScriptRoot
18
18
  $dst = Join-Path $env:USERPROFILE '.dsh\launcher'
19
- $logDir = Join-Path $env:USERPROFILE '.dsh\logs'
19
+ $logDir = Join-Path (Join-Path $env:USERPROFILE '.dsh\logs') 'dsh-windows-tray' # 插件专属日志目录 (release-standards §3.1)
20
20
 
21
21
  Write-Host '== DSH 系统托盘 一键部署 ==' -ForegroundColor Cyan
22
22
 
@@ -11,9 +11,9 @@ $ErrorActionPreference = 'Stop'
11
11
  . (Join-Path $PSScriptRoot 'dsh-lib.ps1')
12
12
 
13
13
  $logFile = Join-Path $LOG_DIR 'dsh-tray-actions.log'
14
+ Initialize-LogDir
14
15
  function Log([string]$msg) {
15
- $line = ('[{0}] {1}' -f (Get-Date -Format 'yyyy-MM-dd HH:mm:ss'), $msg)
16
- Add-Content -Path $logFile -Value $line -ErrorAction SilentlyContinue
16
+ Write-DshLog -Path $logFile -Message $msg
17
17
  }
18
18
 
19
19
  try {
@@ -9,10 +9,10 @@ $BIN = 'D:\Program Files (x86)\dsh\node_modules\@deepseek-ai\dsh\lib\bin.js'
9
9
  $WORKDIR = 'D:\Program Files (x86)\dsh'
10
10
  $PORT = 3088
11
11
  $URL = "http://127.0.0.1:$PORT"
12
- $LOG_DIR = "$env:USERPROFILE\.dsh\logs"
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.6' # 托盘版本 (与 npm 包版本同步, 用于日志/排查)
15
+ $TRAY_VERSION = '1.0.8' # 托盘版本 (与 npm 包版本同步, 用于日志/排查)
16
16
  $TRAY_PKG = 'dsh-windows-tray' # npm 包名 (托盘自更新)
17
17
  $TRAY_SCRIPT = Join-Path $PSScriptRoot 'dsh-tray.ps1'
18
18
 
@@ -26,6 +26,54 @@ function Test-Port([int]$port) {
26
26
  finally { $client.Close() }
27
27
  }
28
28
 
29
+ # ---- 可观测性: 统一日志写入/轮转/迁移 (release-standards §3.1 模板 v1, 2026-08-30) ----
30
+ $LOG_ROTATE_BYTES = 5MB # 轮转阈值 (保险机制: 托盘日志量级一年几十 KB, 极少触发; 设计原则=失败就放弃, 简单优先)
31
+ $LOG_ARCHIVE_KEEP = 5 # 归档保留数
32
+
33
+ # 带轮转的日志写入: 任何失败静默降级, 绝不阻断主流程
34
+ function Write-DshLog([string]$Path, [string]$Message) {
35
+ try {
36
+ if ((Test-Path $Path) -and (Get-Item $Path).Length -gt $LOG_ROTATE_BYTES) { Invoke-LogRotate $Path }
37
+ } catch { }
38
+ try {
39
+ Add-Content -Path $Path -Value ('[{0}] {1}' -f (Get-Date -Format 'yyyy-MM-dd HH:mm:ss'), $Message) -ErrorAction SilentlyContinue
40
+ } catch { }
41
+ }
42
+
43
+ # 大小超限归档: rename 失败(被占用/权限)=本轮放弃继续追加, 下次写入重试; 同秒冲突追加 -PID 兜底; 成功后立即 trim 归档
44
+ function Invoke-LogRotate([string]$Path) {
45
+ try {
46
+ $dir = Split-Path $Path -Parent
47
+ $base = [System.IO.Path]::GetFileNameWithoutExtension($Path)
48
+ $newName = "$base-$(Get-Date -Format 'yyyyMMdd-HHmmss').log"
49
+ if (Test-Path (Join-Path $dir $newName)) { $newName = "$base-$(Get-Date -Format 'yyyyMMdd-HHmmss')-$PID.log" }
50
+ Rename-Item -LiteralPath $Path -NewName $newName -ErrorAction Stop
51
+ $archives = @(Get-ChildItem $dir -Filter "$base-*.log" -ErrorAction SilentlyContinue | Sort-Object LastWriteTime)
52
+ if ($archives.Count -gt $LOG_ARCHIVE_KEEP) {
53
+ $archives | Select-Object -First ($archives.Count - $LOG_ARCHIVE_KEEP) | Remove-Item -Force -ErrorAction SilentlyContinue
54
+ }
55
+ } catch { }
56
+ }
57
+
58
+ # 幂等启动清扫: 把 logs 根目录的已知遗留文件迁入本插件目录。
59
+ # 必须每次启动执行而非一次性迁移——自更新过渡窗口内, 旧版代码(升级前拉起的 updater)仍往根目录写
60
+ function Initialize-LogDir {
61
+ param(
62
+ [string]$Root = (Join-Path $env:USERPROFILE '.dsh\logs'),
63
+ [string]$Target = $LOG_DIR,
64
+ [string[]]$Legacy = @('dsh-tray.log', 'dsh-tray-actions.log', 'dsh-update-npm.log', 'dsh-update-deploy.log', 'web-menu.out.log', 'web-menu.err.log')
65
+ )
66
+ New-Item -ItemType Directory -Force -Path $Target | Out-Null
67
+ if ([System.IO.Path]::GetFullPath($Root) -eq [System.IO.Path]::GetFullPath($Target)) { return }
68
+ foreach ($name in $Legacy) {
69
+ $src = Join-Path $Root $name
70
+ if (-not (Test-Path $src)) { continue }
71
+ $dst = Join-Path $Target $name
72
+ if (Test-Path $dst) { $dst = Join-Path $Target ("$([System.IO.Path]::GetFileNameWithoutExtension($name))-root-$(Get-Date -Format 'yyyyMMdd-HHmmss').log") }
73
+ Move-Item -LiteralPath $src -Destination $dst -Force -ErrorAction SilentlyContinue
74
+ }
75
+ }
76
+
29
77
  function Get-WebPid {
30
78
  @((Get-NetTCPConnection -LocalPort $PORT -State Listen -ErrorAction SilentlyContinue).OwningProcess | Select-Object -Unique)
31
79
  }
@@ -42,9 +42,9 @@ public static extern int SetCurrentProcessExplicitAppUserModelID([MarshalAs(Unma
42
42
  [void][DSH.NativeShell]::SetCurrentProcessExplicitAppUserModelID('DSH.WindowsTray')
43
43
 
44
44
  $logFile = Join-Path $LOG_DIR 'dsh-tray.log'
45
+ Initialize-LogDir
45
46
  function Log([string]$msg) {
46
- $line = ('[{0}] {1}' -f (Get-Date -Format 'yyyy-MM-dd HH:mm:ss'), $msg)
47
- Add-Content -Path $logFile -Value $line -ErrorAction SilentlyContinue
47
+ Write-DshLog -Path $logFile -Message $msg
48
48
  }
49
49
 
50
50
  # ---- 图标: 官方鲸鱼 .ico; 缺失时回退为纯色圆点 ----
@@ -272,7 +272,7 @@ function Find-NpmCmd {
272
272
  function Get-LatestTrayVersion {
273
273
  $npm = Find-NpmCmd
274
274
  if (-not $npm) { Log '自更新: npm 未找到'; return '' }
275
- $tmp = Join-Path $LOG_DIR 'tray-npm-view.txt'
275
+ $tmp = Join-Path $env:TEMP 'tray-npm-view.txt'
276
276
  Remove-Item $tmp -Force -ErrorAction SilentlyContinue
277
277
  $cmdLine = '/c ""' + $npm + '" view ' + $TRAY_PKG + ' version > "' + $tmp + '" 2>nul "'
278
278
  $psi = New-Object System.Diagnostics.ProcessStartInfo
@@ -11,8 +11,9 @@ $ErrorActionPreference = 'Stop'
11
11
  . (Join-Path $PSScriptRoot 'dsh-lib.ps1')
12
12
 
13
13
  $logFile = Join-Path $LOG_DIR 'dsh-tray-actions.log'
14
+ Initialize-LogDir
14
15
  function Log([string]$msg) {
15
- Add-Content -Path $logFile -Value ('[{0}] {1}' -f (Get-Date -Format 'yyyy-MM-dd HH:mm:ss'), $msg) -ErrorAction SilentlyContinue
16
+ Write-DshLog -Path $logFile -Message $msg
16
17
  }
17
18
 
18
19
  function Find-NpmCmd {
@@ -44,6 +45,22 @@ function Run-HiddenCmd([string]$cmdLine, [int]$timeoutMs = 0) {
44
45
  return $p.ExitCode
45
46
  }
46
47
 
48
+ # pwsh 版隐藏执行: $ArgList 为 -NoProfile 之后的完整参数串 (如 '-ExecutionPolicy Bypass -Command "..."');
49
+ # 输出经 Out-File 统一 UTF-8 (cmd >> 重定向会写 GBK, 含中文的输出回读成乱码); 退出码由命令文本自行 exit 决定
50
+ function Run-HiddenPwsh([string]$PwshExe, [string]$ArgList, [int]$timeoutMs = 0) {
51
+ $psi = New-Object System.Diagnostics.ProcessStartInfo
52
+ $psi.FileName = $PwshExe
53
+ $psi.Arguments = "-NoProfile " + $ArgList
54
+ $psi.UseShellExecute = $false
55
+ $psi.CreateNoWindow = $true
56
+ $p = [System.Diagnostics.Process]::Start($psi)
57
+ if ($timeoutMs -gt 0) {
58
+ $p.WaitForExit($timeoutMs) | Out-Null
59
+ if (-not $p.HasExited) { $p.Kill(); return -1 }
60
+ } else { $p.WaitForExit() }
61
+ return $p.ExitCode
62
+ }
63
+
47
64
  # 结果气泡 (临时 NotifyIcon, 更新脚本自身无托盘)
48
65
  function Show-Balloon([string]$text, [string]$icon = 'Info') {
49
66
  try {
@@ -71,6 +88,7 @@ if (-not $npm) {
71
88
  }
72
89
 
73
90
  # 1) 安装最新包 (全局; 输出落盘, 失败可查因 — 旧版 2>nul 黑洞)
91
+ # npm 输出为英文, cmd 重定向 ANSI 编码即 ASCII, 无乱码风险; 含中文输出的 deploy 步骤走 Run-HiddenPwsh (UTF-8)
74
92
  $npmLog = Join-Path $LOG_DIR 'dsh-update-npm.log'
75
93
  Remove-Item $npmLog -Force -ErrorAction SilentlyContinue
76
94
  $installCmd = '/c ""' + $npm + '" install -g ' + $TRAY_PKG + ' >> "' + $npmLog + '" 2>&1 "'
@@ -83,8 +101,8 @@ if ($code -ne 0) {
83
101
  }
84
102
  Log 'npm install -g 完成'
85
103
 
86
- # 2) 定位新包根目录
87
- $rootTmp = Join-Path $LOG_DIR 'tray-npm-root.txt'
104
+ # 2) 定位新包根目录 (临时文件走 TEMP, 不落日志目录 — logs 根/插件目录禁止散文件)
105
+ $rootTmp = Join-Path $env:TEMP 'tray-npm-root.txt'
88
106
  Remove-Item $rootTmp -Force -ErrorAction SilentlyContinue
89
107
  $rootCmd = '/c ""' + $npm + '" root -g > "' + $rootTmp + '" 2>nul "'
90
108
  Run-HiddenCmd $rootCmd | Out-Null
@@ -101,17 +119,18 @@ if (-not (Test-Path $newInstall)) {
101
119
  }
102
120
 
103
121
  # 3) 运行新包 install.ps1 (重新部署 + 快捷方式, 不启动托盘; -Auto=隐藏窗口非交互)
122
+ # v1.0.8: 改用全流合并 *>&1 — 2>&1 捕不到 Write-Host 信息流, 中文经隐形控制台编码变 '?';
123
+ # $InformationPreference='Continue' 让信息流进管道, Out-File 统一 UTF-8
104
124
  # v1.0.5: 显式传本机适配值 (取自点源的 dsh-lib, install 不必重新探测; 自定义安装位置必需)
105
125
  $dshRoot = Split-Path $DSH_CMD -Parent
106
126
  $deployLog = Join-Path $LOG_DIR 'dsh-update-deploy.log'
107
127
  Remove-Item $deployLog -Force -ErrorAction SilentlyContinue
108
- $deployCmd = '/c ""' + $PWSH + '" -NoProfile -ExecutionPolicy Bypass -File "' + $newInstall + '" -Auto -NoTrayStart' +
109
- ' -DshRoot "' + $dshRoot + '"' +
110
- ' -Port ' + $PORT +
111
- ' -NodePath "' + $NODE + '"' +
112
- ' -PwshPath "' + $PWSH + '"' +
113
- ' >> "' + $deployLog + '" 2>&1 "'
114
- $code = Run-HiddenCmd $deployCmd 120000
128
+ $deployPwsh = '-ExecutionPolicy Bypass -Command "$InformationPreference=''Continue''; $ErrorActionPreference=''Continue''; try { & ''' + $newInstall + ''' -Auto -NoTrayStart' +
129
+ ' -DshRoot ''' + $dshRoot + ''' -Port ' + $PORT +
130
+ ' -NodePath ''' + $NODE + ''' -PwshPath ''' + $PWSH + ''' *>&1 |' +
131
+ ' Out-File -FilePath ''' + $deployLog + ''' -Encoding utf8 } catch {' +
132
+ ' $_ | Out-File -FilePath ''' + $deployLog + ''' -Append -Encoding utf8; exit 1 }; exit 0'
133
+ $code = Run-HiddenPwsh $PWSH $deployPwsh 120000
115
134
  if ($code -ne 0) {
116
135
  Log "自更新失败: install.ps1 退出码 $code (输出: $deployLog)"
117
136
  Get-Content $deployLog -Tail 5 -ErrorAction SilentlyContinue | ForEach-Object { Log " deploy> $_" }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-windows-tray",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "description": "DSH (DeepSeek Harness) Windows 系统托盘: 蓝/灰鲸鱼状态图标 + Web/TUI 一键启停控制。纯 PowerShell + WinForms, 零依赖。",
5
5
  "license": "MIT",
6
6
  "author": "jankin_lv",