panrouter 1.6.0 → 1.7.0

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.
Files changed (3) hide show
  1. package/daemon.mjs +27 -32
  2. package/package.json +1 -2
  3. package/tray-daemon.ps1 +39 -25
package/daemon.mjs CHANGED
@@ -1,14 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  /**
4
- * Pan Router Daemon (v4)
4
+ * Pan Router Daemon (v5)
5
5
  *
6
- * 一个 Node 进程同时:
7
- * 1. 隐藏启动 server.mjs(子进程)
8
- * 2. 隐藏启动 tray-daemon.ps1(子进程)
9
- * 3. 保持存活,守护两者
10
- *
11
- * 由 cli.mjs --tray 启动 (detached, 无窗口)。
6
+ * 1. spawn server.mjs (detached, hidden) — 正常
7
+ * 2. VBS 启动 PS tray(解决 detached 进程无法创建通知图标的问题)
8
+ * 3. 保持存活,30s 健康检查
12
9
  */
13
10
 
14
11
  import { spawn, execSync } from "node:child_process";
@@ -20,16 +17,15 @@ import http from "node:http";
20
17
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
21
18
  const serverPath = path.join(__dirname, "server.mjs");
22
19
  const trayPsPath = path.join(__dirname, "tray-daemon.ps1");
23
- const nodeExe = process.execPath; // ← 绝对路径!不依赖 PATH
20
+ const nodeExe = process.execPath;
24
21
  const logPath = path.join(process.env.TEMP || "/tmp", "panrouter-daemon.log");
25
22
 
26
23
  function log(msg) {
27
24
  try { fs.appendFileSync(logPath, `${new Date().toISOString().slice(11,19)} ${msg}\n`); } catch {}
28
25
  }
29
26
 
30
- log("=== Daemon v4 ===");
27
+ log("=== Daemon v5 ===");
31
28
  log(`nodeExe=${nodeExe}`);
32
- log(`serverPath=${serverPath}`);
33
29
 
34
30
  // ─── 1. 杀旧 server ──────────────────────────────
35
31
  try {
@@ -40,19 +36,14 @@ try {
40
36
  for (const line of out.split("\n")) {
41
37
  if (line.includes("server.mjs")) {
42
38
  const m = line.match(/(\d+),.*?server\.mjs/);
43
- if (m) { try { process.kill(parseInt(m[1]), "SIGKILL"); log(`Killed old server PID=${m[1]}`); } catch {} }
39
+ if (m) { try { process.kill(parseInt(m[1]), "SIGKILL"); log(`Killed old PID=${m[1]}`); } catch {} }
44
40
  }
45
41
  }
46
42
  } catch {}
47
43
 
48
44
  // ─── 2. 启动 server.mjs ──────────────────────────
49
- // 关键: 用 process.execPath (绝对路径), 不用 "node" (可能找不到 PATH)
50
45
  const server = spawn(nodeExe, [serverPath], {
51
- cwd: __dirname,
52
- stdio: "ignore",
53
- windowsHide: true,
54
- detached: true,
55
- shell: false,
46
+ cwd: __dirname, stdio: "ignore", windowsHide: true, detached: true, shell: false,
56
47
  });
57
48
  server.unref();
58
49
  log(`Server spawned PID=${server.pid || "??"}`);
@@ -77,29 +68,33 @@ function isOnline() {
77
68
  }
78
69
  log(`Server online=${ready}`);
79
70
 
80
- // ─── 4. 启动 PS 托盘 ────────────────────────────
71
+ // ─── 4. 用 VBS 启动 PS 托盘 ─────────────────────
72
+ // 关键: spawn 的 detached 进程没有 Window Station 访问权限,
73
+ // 无法创建 NotifyIcon。WScript.Shell.Run 0 是可靠的解决方式。
81
74
  if (fs.existsSync(trayPsPath)) {
82
- log("Starting PS tray...");
83
- const ps = spawn("powershell.exe", [
84
- "-NoProfile", "-ExecutionPolicy", "Bypass",
85
- "-WindowStyle", "Hidden",
86
- "-File", trayPsPath,
87
- ], {
88
- stdio: "ignore",
89
- windowsHide: true,
90
- shell: false,
75
+ // 创建临时的 VBS 启动器
76
+ const vbsContent = `Set WshShell = CreateObject("WScript.Shell")
77
+ WshShell.Run "powershell -ExecutionPolicy Bypass -WindowStyle Hidden -STA -File """ & "${trayPsPath.replace(/\\/g, "\\\\")}" & """", 0, False
78
+ `;
79
+ const vbsPath = path.join(process.env.TEMP || "/tmp", "panrouter-tray-launcher.vbs");
80
+ try { fs.writeFileSync(vbsPath, vbsContent, "utf8"); } catch {}
81
+
82
+ log(`VBS launcher: ${vbsPath}`);
83
+
84
+ // wscript //B = 批处理模式, 无交互
85
+ const vbs = spawn("wscript.exe", ["//B", "//NoLogo", vbsPath], {
86
+ stdio: "ignore", windowsHide: true, shell: false,
91
87
  });
92
- ps.unref();
93
- log(`PS spawned PID=${ps.pid || "??"}`);
88
+ vbs.unref();
89
+ log(`VBS launched`);
94
90
  } else {
95
- log(`WARN: tray-daemon.ps1 not found at ${trayPsPath}`);
91
+ log(`WARN: ${trayPsPath} not found`);
96
92
  }
97
93
 
98
94
  // ─── 5. 保持存活 ────────────────────────────────
99
- log("Daemon running, keeping session alive");
95
+ log("Daemon running");
100
96
  process.stdin.resume();
101
97
 
102
- // 定时检查 server, 挂了就重启
103
98
  setInterval(() => {
104
99
  isOnline().then(ok => {
105
100
  if (!ok) {
package/package.json CHANGED
@@ -1,12 +1,11 @@
1
1
  {
2
2
  "name": "panrouter",
3
- "version": "1.5.2",
3
+ "version": "1.7.0",
4
4
  "description": "让 Claude Code 免费使用 DeepSeek 等模型,无需 API Key",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "panrouter": "cli.mjs"
8
8
  },
9
- "version": "1.6.0",
10
9
  "files": [
11
10
  "cli.mjs",
12
11
  "daemon.mjs",
package/tray-daemon.ps1 CHANGED
@@ -42,10 +42,46 @@ $bmp.Dispose()
42
42
  $notifyIcon = New-Object System.Windows.Forms.NotifyIcon
43
43
  $notifyIcon.Icon = $icon
44
44
  $notifyIcon.Text = "Pan Router | 端口 50816"
45
- $notifyIcon.Visible = $true
46
- Write-Log "NotifyIcon visible"
47
45
 
48
- # ─── 健康检查 ──────────────────────────────────────
46
+ # ─── 右键菜单 (PS5.1 用 .GetNewClosure()) ─────────
47
+ $menu = New-Object System.Windows.Forms.ContextMenuStrip
48
+
49
+ $titleItem = New-Object System.Windows.Forms.ToolStripMenuItem
50
+ $titleItem.Text = "Pan Router - :50816"
51
+ $titleItem.Enabled = $false
52
+ $titleItem.Font = New-Object System.Drawing.Font("Segoe UI", 9, [System.Drawing.FontStyle]::Bold)
53
+ [void]$menu.Items.Add($titleItem)
54
+ [void]$menu.Items.Add((New-Object System.Windows.Forms.ToolStripSeparator))
55
+
56
+ $autoItem = New-Object System.Windows.Forms.ToolStripMenuItem
57
+ $autoItem.Text = "开机自启动"
58
+ $autoItem.Checked = Get-Autostart
59
+ $autoItem.Add_Click({
60
+ $ni = $notifyIcon
61
+ $ai = $autoItem
62
+ if ($ai.Checked) {
63
+ Set-Autostart $false; $ai.Checked = $false
64
+ $ni.ShowBalloonTip(2000, "Pan Router", "开机自启动已关闭", [System.Windows.Forms.ToolTipIcon]::Info)
65
+ } else {
66
+ Set-Autostart $true; $ai.Checked = $true
67
+ $ni.ShowBalloonTip(2000, "Pan Router", "开机自启动已开启 ✓", [System.Windows.Forms.ToolTipIcon]::Info)
68
+ }
69
+ }.GetNewClosure())
70
+ [void]$menu.Items.Add($autoItem)
71
+ [void]$menu.Items.Add((New-Object System.Windows.Forms.ToolStripSeparator))
72
+
73
+ $exitItem = New-Object System.Windows.Forms.ToolStripMenuItem
74
+ $exitItem.Text = "退出"
75
+ $exitItem.Add_Click({
76
+ Write-Log "Exit clicked"
77
+ $notifyIcon.Visible = $false
78
+ [System.Windows.Forms.Application]::Exit()
79
+ }.GetNewClosure())
80
+ [void]$menu.Items.Add($exitItem)
81
+
82
+ $notifyIcon.ContextMenuStrip = $menu
83
+ $notifyIcon.Visible = $true
84
+ Write-Log "NotifyIcon visible with menu"
49
85
  function Test-Online {
50
86
  try {
51
87
  $req = [System.Net.WebRequest]::Create("http://127.0.0.1:50816/health")
@@ -115,28 +151,6 @@ if ($ready) {
115
151
  }
116
152
  }
117
153
 
118
- # 右键菜单
119
- $menu = New-Object System.Windows.Forms.ContextMenuStrip
120
- $titleItem = New-Object System.Windows.Forms.ToolStripMenuItem("Pan Router - :50816")
121
- $titleItem.Enabled = $false
122
- $titleItem.Font = New-Object System.Drawing.Font("Segoe UI", 9, [System.Drawing.FontStyle]::Bold)
123
- $menu.Items.Add($titleItem)
124
- $menu.Items.Add("-")
125
-
126
- $autoItem = New-Object System.Windows.Forms.ToolStripMenuItem("开机自启动")
127
- $autoItem.Checked = Get-Autostart
128
- $autoItem.Add_Click({
129
- if ($autoItem.Checked) { Set-Autostart $false; $autoItem.Checked = $false; $notifyIcon.ShowBalloonTip(2000, "Pan Router", "开机自启动已关闭", [System.Windows.Forms.ToolTipIcon]::Info) }
130
- else { Set-Autostart $true; $autoItem.Checked = $true; $notifyIcon.ShowBalloonTip(2000, "Pan Router", "开机自启动已开启 ✓", [System.Windows.Forms.ToolTipIcon]::Info) }
131
- })
132
- $menu.Items.Add($autoItem)
133
- $menu.Items.Add("-")
134
-
135
- $exitItem = New-Object System.Windows.Forms.ToolStripMenuItem("退出")
136
- $exitItem.Add_Click({ Write-Log "Exit"; $notifyIcon.Visible = $false; [System.Windows.Forms.Application]::Exit() })
137
- $menu.Items.Add($exitItem)
138
- $notifyIcon.ContextMenuStrip = $menu
139
-
140
154
  # 左键: 状态
141
155
  $notifyIcon.Add_MouseClick({
142
156
  if ($_.Button -eq [System.Windows.Forms.MouseButtons]::Left) {