claude-hook-notify 1.4.0 → 1.4.2
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/package.json
CHANGED
package/src/activate.js
CHANGED
|
@@ -26,6 +26,7 @@ const WIN_TERMINAL_NAMES = new Set([
|
|
|
26
26
|
"windowsterminal",
|
|
27
27
|
"code",
|
|
28
28
|
"cursor",
|
|
29
|
+
"claude",
|
|
29
30
|
"cmd",
|
|
30
31
|
"powershell",
|
|
31
32
|
"pwsh",
|
|
@@ -115,30 +116,21 @@ function detectMac() {
|
|
|
115
116
|
* Windows: 优先环境变量,回退单次 PowerShell 批量查询
|
|
116
117
|
*/
|
|
117
118
|
function detectWindows() {
|
|
118
|
-
// 1.
|
|
119
|
-
if (process.env.WT_SESSION) {
|
|
120
|
-
// Windows Terminal 设置了 WT_SESSION
|
|
121
|
-
const info = findProcessByName("WindowsTerminal");
|
|
122
|
-
if (info) return info;
|
|
123
|
-
}
|
|
119
|
+
// 1. 环境变量快速检测(仅保留精确 PID 的路径)
|
|
124
120
|
if (process.env.VSCODE_PID) {
|
|
125
121
|
const pid = parseInt(process.env.VSCODE_PID, 10);
|
|
126
122
|
if (pid > 0) return { name: "Code", pid, processName: "code.exe" };
|
|
127
123
|
}
|
|
128
|
-
if (process.env.TERM_PROGRAM === "vscode") {
|
|
129
|
-
const info = findProcessByName("Code");
|
|
130
|
-
if (info) return info;
|
|
131
|
-
}
|
|
132
124
|
|
|
133
|
-
// 2.
|
|
125
|
+
// 2. WMI 遍历进程树(OS 级 ParentProcessId 始终完整,不受 spawn 方式影响)
|
|
134
126
|
try {
|
|
135
127
|
const script = [
|
|
136
|
-
"$cpid=" + process.
|
|
137
|
-
"for($i=0;$i -lt
|
|
138
|
-
" $
|
|
139
|
-
" if(-not $
|
|
140
|
-
" Write-Output \"$($
|
|
141
|
-
" $cpid
|
|
128
|
+
"$cpid=" + process.pid,
|
|
129
|
+
"for($i=0;$i -lt 30 -and $cpid -gt 0;$i++){",
|
|
130
|
+
" $w=Get-CimInstance Win32_Process -Filter \"ProcessId=$cpid\" -EA SilentlyContinue",
|
|
131
|
+
" if(-not $w){break}",
|
|
132
|
+
" Write-Output \"$($w.Name)|$($w.ProcessId)|$($w.ParentProcessId)\"",
|
|
133
|
+
" $cpid=$w.ParentProcessId",
|
|
142
134
|
"}",
|
|
143
135
|
].join(";");
|
|
144
136
|
const output = execFileSync("powershell", ["-NoProfile", "-Command", script], {
|
|
@@ -146,41 +138,26 @@ function detectWindows() {
|
|
|
146
138
|
timeout: 8000,
|
|
147
139
|
}).trim();
|
|
148
140
|
|
|
141
|
+
// 遍历整棵进程树,取最高层级(最靠近根)的终端匹配
|
|
142
|
+
// 避免误取 powershell/cmd 等 shell 进程 —— 它们在 Windows Terminal 下不拥有窗口
|
|
143
|
+
let bestMatch = null;
|
|
149
144
|
for (const line of output.split("\n")) {
|
|
150
145
|
const parts = line.trim().split("|");
|
|
151
146
|
if (parts.length < 3) continue;
|
|
152
|
-
|
|
147
|
+
// WMI 返回的 Name 带 .exe 后缀,去掉再匹配
|
|
148
|
+
const name = parts[0].replace(/\.exe$/i, "").toLowerCase();
|
|
153
149
|
const pid = parseInt(parts[1], 10);
|
|
154
150
|
if (WIN_TERMINAL_NAMES.has(name)) {
|
|
155
|
-
|
|
151
|
+
bestMatch = { name: parts[0].replace(/\.exe$/i, ""), pid, processName: parts[0] };
|
|
156
152
|
}
|
|
157
153
|
}
|
|
154
|
+
return bestMatch;
|
|
158
155
|
} catch {
|
|
159
156
|
// PowerShell 调用失败
|
|
160
157
|
}
|
|
161
158
|
return null;
|
|
162
159
|
}
|
|
163
160
|
|
|
164
|
-
/**
|
|
165
|
-
* 按名称查找进程(Windows)
|
|
166
|
-
*/
|
|
167
|
-
function findProcessByName(name) {
|
|
168
|
-
try {
|
|
169
|
-
const script = `$p=Get-Process -Name '${name}' -EA SilentlyContinue | Select-Object -First 1; if($p){Write-Output "$($p.ProcessName)|$($p.Id)"}`;
|
|
170
|
-
const output = execFileSync("powershell", ["-NoProfile", "-Command", script], {
|
|
171
|
-
encoding: "utf-8",
|
|
172
|
-
timeout: 5000,
|
|
173
|
-
}).trim();
|
|
174
|
-
if (output) {
|
|
175
|
-
const parts = output.split("|");
|
|
176
|
-
return { name: parts[0], pid: parseInt(parts[1], 10), processName: parts[0].toLowerCase() + ".exe" };
|
|
177
|
-
}
|
|
178
|
-
} catch {
|
|
179
|
-
// 查找失败
|
|
180
|
-
}
|
|
181
|
-
return null;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
161
|
function detectLinux() {
|
|
185
162
|
// 1. 环境变量快速检测
|
|
186
163
|
if (process.env.VSCODE_PID) {
|
package/src/notify.js
CHANGED
|
@@ -254,8 +254,10 @@ async function sendNotification(options = {}) {
|
|
|
254
254
|
// Windows: notify-helper.exe 通知 + 点击激活终端(无控制台窗口)
|
|
255
255
|
method = "notify-helper";
|
|
256
256
|
command = path.join(__dirname, "..", "vendor", "notify-helper", "ClaudeCodeNotify.exe");
|
|
257
|
-
|
|
258
|
-
|
|
257
|
+
// 注意:此列表需与 activate.js 的 WIN_TERMINAL_NAMES 保持同步
|
|
258
|
+
const targetNames = ["WindowsTerminal", "Code", "cursor", "claude", "cmd", "pwsh", "powershell", "mintty"];
|
|
259
|
+
const pid = (terminalInfo && terminalInfo.pid) ? String(terminalInfo.pid) : "0";
|
|
260
|
+
args = [title, message, targetNames.join(","), pid];
|
|
259
261
|
}
|
|
260
262
|
|
|
261
263
|
const result = { sent: !dryRun, method, command, args, activate: !!activateCmd };
|
|
Binary file
|
|
@@ -16,6 +16,35 @@ class NotifyHelper
|
|
|
16
16
|
[DllImport("user32.dll")]
|
|
17
17
|
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
|
|
18
18
|
|
|
19
|
+
delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
|
|
20
|
+
|
|
21
|
+
[DllImport("user32.dll")]
|
|
22
|
+
static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);
|
|
23
|
+
|
|
24
|
+
[DllImport("user32.dll")]
|
|
25
|
+
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
|
|
26
|
+
|
|
27
|
+
[DllImport("user32.dll")]
|
|
28
|
+
static extern bool IsWindowVisible(IntPtr hWnd);
|
|
29
|
+
|
|
30
|
+
[DllImport("user32.dll", SetLastError = true)]
|
|
31
|
+
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
|
|
32
|
+
|
|
33
|
+
[DllImport("user32.dll")]
|
|
34
|
+
static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);
|
|
35
|
+
|
|
36
|
+
[DllImport("user32.dll")]
|
|
37
|
+
static extern IntPtr GetForegroundWindow();
|
|
38
|
+
|
|
39
|
+
[DllImport("kernel32.dll")]
|
|
40
|
+
static extern uint GetCurrentThreadId();
|
|
41
|
+
|
|
42
|
+
// 已知 GUI 终端的窗口类名(用于 PID 查找失败时的回退)
|
|
43
|
+
static string[] KnownWindowClasses = new string[] {
|
|
44
|
+
"CASCADIA_HOSTING_WINDOW_CLASS", // Windows Terminal
|
|
45
|
+
"mintty", // Git Bash / mintty
|
|
46
|
+
};
|
|
47
|
+
|
|
19
48
|
// Claude sparkle 图标 PNG(内嵌,无需外部文件)
|
|
20
49
|
static string IconBase64 = "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";
|
|
21
50
|
|
|
@@ -27,29 +56,80 @@ class NotifyHelper
|
|
|
27
56
|
string title = args.Length > 0 ? args[0] : "Claude Code";
|
|
28
57
|
string message = args.Length > 1 ? args[1] : "任务完成";
|
|
29
58
|
string targetName = args.Length > 2 ? args[2] : "";
|
|
59
|
+
int targetPid = 0;
|
|
60
|
+
if (args.Length > 3) int.TryParse(args[3], out targetPid);
|
|
61
|
+
|
|
62
|
+
// 策略 1:通过 PID 精确定位终端窗口(多实例场景)
|
|
63
|
+
if (targetPid > 0)
|
|
64
|
+
{
|
|
65
|
+
try
|
|
66
|
+
{
|
|
67
|
+
using (var proc = Process.GetProcessById(targetPid))
|
|
68
|
+
{
|
|
69
|
+
if (proc.MainWindowHandle != IntPtr.Zero)
|
|
70
|
+
{
|
|
71
|
+
targetHandle = proc.MainWindowHandle;
|
|
72
|
+
}
|
|
73
|
+
else
|
|
74
|
+
{
|
|
75
|
+
// MainWindowHandle 可能为零(如 Windows Terminal),用 EnumWindows 查找
|
|
76
|
+
targetHandle = FindWindowByPid(targetPid);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
catch { /* 进程可能已退出,回退到名称查找 */ }
|
|
81
|
+
}
|
|
30
82
|
|
|
31
|
-
//
|
|
32
|
-
if (!string.IsNullOrEmpty(targetName))
|
|
83
|
+
// 策略 2:通过进程名查找(回退方案)
|
|
84
|
+
if (targetHandle == IntPtr.Zero && !string.IsNullOrEmpty(targetName))
|
|
33
85
|
{
|
|
34
86
|
foreach (var name in targetName.Split(','))
|
|
35
87
|
{
|
|
36
88
|
try
|
|
37
89
|
{
|
|
38
90
|
var procs = Process.GetProcessesByName(name.Trim());
|
|
39
|
-
|
|
91
|
+
try
|
|
40
92
|
{
|
|
41
|
-
|
|
93
|
+
foreach (var p in procs)
|
|
42
94
|
{
|
|
43
|
-
|
|
44
|
-
|
|
95
|
+
if (p.MainWindowHandle != IntPtr.Zero)
|
|
96
|
+
{
|
|
97
|
+
targetHandle = p.MainWindowHandle;
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
// MainWindowHandle 为零时尝试 EnumWindows 查找
|
|
101
|
+
IntPtr hwnd = FindWindowByPid(p.Id);
|
|
102
|
+
if (hwnd != IntPtr.Zero)
|
|
103
|
+
{
|
|
104
|
+
targetHandle = hwnd;
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
45
107
|
}
|
|
46
108
|
}
|
|
109
|
+
finally
|
|
110
|
+
{
|
|
111
|
+
foreach (var p in procs) p.Dispose();
|
|
112
|
+
}
|
|
47
113
|
if (targetHandle != IntPtr.Zero) break;
|
|
48
114
|
}
|
|
49
115
|
catch { }
|
|
50
116
|
}
|
|
51
117
|
}
|
|
52
118
|
|
|
119
|
+
// 策略 3:通过已知窗口类名查找(兜底方案)
|
|
120
|
+
if (targetHandle == IntPtr.Zero)
|
|
121
|
+
{
|
|
122
|
+
foreach (var cls in KnownWindowClasses)
|
|
123
|
+
{
|
|
124
|
+
IntPtr hwnd = FindWindow(cls, null);
|
|
125
|
+
if (hwnd != IntPtr.Zero)
|
|
126
|
+
{
|
|
127
|
+
targetHandle = hwnd;
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
53
133
|
notify = new NotifyIcon();
|
|
54
134
|
notify.Icon = LoadEmbeddedIcon();
|
|
55
135
|
notify.Visible = true;
|
|
@@ -71,6 +151,23 @@ class NotifyHelper
|
|
|
71
151
|
Application.Run();
|
|
72
152
|
}
|
|
73
153
|
|
|
154
|
+
static IntPtr FindWindowByPid(int pid)
|
|
155
|
+
{
|
|
156
|
+
IntPtr found = IntPtr.Zero;
|
|
157
|
+
EnumWindows((hWnd, lParam) =>
|
|
158
|
+
{
|
|
159
|
+
uint procId;
|
|
160
|
+
GetWindowThreadProcessId(hWnd, out procId);
|
|
161
|
+
if ((int)procId == pid && IsWindowVisible(hWnd))
|
|
162
|
+
{
|
|
163
|
+
found = hWnd;
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
return true;
|
|
167
|
+
}, IntPtr.Zero);
|
|
168
|
+
return found;
|
|
169
|
+
}
|
|
170
|
+
|
|
74
171
|
static Icon LoadEmbeddedIcon()
|
|
75
172
|
{
|
|
76
173
|
try
|
|
@@ -93,8 +190,22 @@ class NotifyHelper
|
|
|
93
190
|
{
|
|
94
191
|
if (targetHandle != IntPtr.Zero)
|
|
95
192
|
{
|
|
96
|
-
ShowWindow(targetHandle, 9);
|
|
97
|
-
SetForegroundWindow
|
|
193
|
+
ShowWindow(targetHandle, 9); // SW_RESTORE
|
|
194
|
+
// 使用 AttachThreadInput 确保 SetForegroundWindow 成功
|
|
195
|
+
// (Windows 限制后台进程直接抢占前台焦点)
|
|
196
|
+
uint unusedPid;
|
|
197
|
+
uint targetThread = GetWindowThreadProcessId(targetHandle, out unusedPid);
|
|
198
|
+
uint curThread = GetCurrentThreadId();
|
|
199
|
+
if (curThread != targetThread)
|
|
200
|
+
{
|
|
201
|
+
AttachThreadInput(curThread, targetThread, true);
|
|
202
|
+
SetForegroundWindow(targetHandle);
|
|
203
|
+
AttachThreadInput(curThread, targetThread, false);
|
|
204
|
+
}
|
|
205
|
+
else
|
|
206
|
+
{
|
|
207
|
+
SetForegroundWindow(targetHandle);
|
|
208
|
+
}
|
|
98
209
|
}
|
|
99
210
|
Cleanup();
|
|
100
211
|
}
|