ai-notify 0.4.4 → 0.4.5
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 +1 -1
- package/src/notify.mjs +9 -4
- package/src/util.mjs +28 -12
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-notify",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.5",
|
|
4
4
|
"description": "Desktop, sound, and spoken notifications for terminal AI coding agents (Claude Code, Codex, Gemini, ...) — with one mute switch that covers all of them, across every terminal.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/notify.mjs
CHANGED
|
@@ -184,10 +184,15 @@ export const emit = ({ provider = 'default', event = 'done', label = '', message
|
|
|
184
184
|
setPaneWaiting(tty, event === 'waiting'); // waiting -> yellow menu bar status; done clears it
|
|
185
185
|
const pane = readPaneSetting(tty);
|
|
186
186
|
|
|
187
|
-
// Name this pane in the read-out
|
|
188
|
-
//
|
|
189
|
-
//
|
|
190
|
-
|
|
187
|
+
// Name this pane in the read-out, most-reliable identity first:
|
|
188
|
+
// 1. $AI_NOTIFY_LABEL — set in the pane's shell, inherited by the hook even
|
|
189
|
+
// when the agent runs it detached (no tty). Always spoken: setting it is
|
|
190
|
+
// explicit intent. The reliable way to name a pane for Claude Code.
|
|
191
|
+
// 2. pane.speakName — set from the menu bar, keyed by tty. Works only when
|
|
192
|
+
// the hook resolves to the pane's tty (see controllingTty's tree walk).
|
|
193
|
+
// 3. the auto-derived label — only when speakLabel is on (else slow filler).
|
|
194
|
+
const envName = (process.env.AI_NOTIFY_LABEL || '').trim();
|
|
195
|
+
const spokenName = envName || pane.speakName || (config.speakLabel === true && label ? label : '');
|
|
191
196
|
const speakText = spokenName ? `${spokenName}、${spokenBody}` : spokenBody;
|
|
192
197
|
|
|
193
198
|
// Per-pane voice (precedence: $AI_NOTIFY_* env > this pane's pick > global).
|
package/src/util.mjs
CHANGED
|
@@ -40,18 +40,34 @@ export const isEphemeralInstall = (cliPath) => /[/\\]_npx[/\\]/.test(cliPath);
|
|
|
40
40
|
|
|
41
41
|
export const MARKER = 'ai-notify'; // substring used to detect our own wiring
|
|
42
42
|
|
|
43
|
-
// The controlling terminal of
|
|
44
|
-
//
|
|
43
|
+
// The controlling terminal of the agent's pane (e.g. "/dev/ttys010"), used to
|
|
44
|
+
// scope per-pane settings. Returns null if none can be found.
|
|
45
|
+
//
|
|
46
|
+
// Agents often run the notify hook detached (Claude Code wires it `async`), so
|
|
47
|
+
// the hook process itself frequently has NO controlling tty — but its parent
|
|
48
|
+
// (the agent, e.g. `claude`) still owns the pane's terminal. So we walk up the
|
|
49
|
+
// process tree until we find a real tty, which makes the hook resolve to the
|
|
50
|
+
// SAME tty the menu bar lists the pane under (it scans the agent process).
|
|
45
51
|
export const controllingTty = () => {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
52
|
+
let pid = process.pid;
|
|
53
|
+
for (let depth = 0; depth < 8 && pid > 1; depth++) {
|
|
54
|
+
try {
|
|
55
|
+
const line = execFileSync('ps', ['-o', 'tty=', '-o', 'ppid=', '-p', String(pid)], {
|
|
56
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
57
|
+
})
|
|
58
|
+
.toString()
|
|
59
|
+
.trim();
|
|
60
|
+
if (!line) return null;
|
|
61
|
+
// "ttys010 1234" or "?? 1234" (no controlling tty for this pid)
|
|
62
|
+
const sp = line.lastIndexOf(' ');
|
|
63
|
+
const tty = line.slice(0, sp).trim();
|
|
64
|
+
const ppid = parseInt(line.slice(sp + 1).trim(), 10);
|
|
65
|
+
if (tty && tty !== '??' && tty !== '?') return tty.startsWith('/dev/') ? tty : `/dev/${tty}`;
|
|
66
|
+
if (!Number.isFinite(ppid) || ppid <= 1) return null;
|
|
67
|
+
pid = ppid;
|
|
68
|
+
} catch {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
56
71
|
}
|
|
72
|
+
return null;
|
|
57
73
|
};
|