claude-notification-plugin 1.0.92 → 1.0.94
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/.claude-plugin/plugin.json +1 -1
- package/README.md +3 -1
- package/bin/cli.js +9 -5
- package/bin/install.js +90 -66
- package/bin/uninstall.js +23 -10
- package/package.json +1 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-notification-plugin",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.94",
|
|
4
4
|
"description": "Claude Code task-completion notifications: Telegram, desktop notifications (Windows/macOS/Linux), sound, and voice",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Viacheslav Makarov",
|
package/README.md
CHANGED
|
@@ -30,9 +30,11 @@ Re-run `claude-notify install` anytime to reconfigure.
|
|
|
30
30
|
## Uninstall
|
|
31
31
|
|
|
32
32
|
```bash
|
|
33
|
-
|
|
33
|
+
claude-notify uninstall
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
+
This removes hooks, config, CLI wrappers, plugin registration, and the npm global package.
|
|
37
|
+
|
|
36
38
|
## Configuration
|
|
37
39
|
|
|
38
40
|
Config file: `~/.claude/notifier.config.json`
|
package/bin/cli.js
CHANGED
|
@@ -1,29 +1,33 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import { fileURLToPath } from 'url';
|
|
3
|
+
import { fileURLToPath, pathToFileURL } from 'url';
|
|
4
4
|
import path from 'path';
|
|
5
5
|
|
|
6
6
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
7
7
|
|
|
8
|
+
function toImportUrl (relativePath) {
|
|
9
|
+
return pathToFileURL(path.join(__dirname, relativePath)).href;
|
|
10
|
+
}
|
|
11
|
+
|
|
8
12
|
const command = process.argv[2];
|
|
9
13
|
|
|
10
14
|
switch (command) {
|
|
11
15
|
case 'install':
|
|
12
|
-
await import(
|
|
16
|
+
await import(toImportUrl('install.js'));
|
|
13
17
|
break;
|
|
14
18
|
case 'uninstall':
|
|
15
|
-
await import(
|
|
19
|
+
await import(toImportUrl('uninstall.js'));
|
|
16
20
|
break;
|
|
17
21
|
case 'listener': {
|
|
18
22
|
// Shift argv so listener-cli.js sees subcommand as argv[2]
|
|
19
23
|
process.argv = [process.argv[0], process.argv[1], ...process.argv.slice(3)];
|
|
20
|
-
await import(
|
|
24
|
+
await import(toImportUrl('listener-cli.js'));
|
|
21
25
|
break;
|
|
22
26
|
}
|
|
23
27
|
default:
|
|
24
28
|
// Hook mode: Claude Code pipes JSON to stdin with no args
|
|
25
29
|
if (!process.stdin.isTTY) {
|
|
26
|
-
await import(path.join(
|
|
30
|
+
await import(toImportUrl(path.join('..', 'notifier', 'notifier.js')));
|
|
27
31
|
} else {
|
|
28
32
|
console.log('Usage: claude-notify <command> [options]');
|
|
29
33
|
console.log('');
|
package/bin/install.js
CHANGED
|
@@ -233,6 +233,23 @@ function registerCli () {
|
|
|
233
233
|
// Helpers
|
|
234
234
|
// ──────────────────────────────────────
|
|
235
235
|
|
|
236
|
+
function openTtyInput () {
|
|
237
|
+
// If stdin is already a TTY (e.g. local `npm install`), use it directly
|
|
238
|
+
if (process.stdin.isTTY) {
|
|
239
|
+
return process.stdin;
|
|
240
|
+
}
|
|
241
|
+
// On Unix, try opening /dev/tty directly (works even when npm pipes stdin)
|
|
242
|
+
if (process.platform !== 'win32') {
|
|
243
|
+
try {
|
|
244
|
+
const fd = fs.openSync('/dev/tty', 'r');
|
|
245
|
+
return fs.createReadStream(null, { fd, encoding: 'utf-8' });
|
|
246
|
+
} catch {
|
|
247
|
+
// no TTY available (CI/CD, Docker, etc.)
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return null;
|
|
251
|
+
}
|
|
252
|
+
|
|
236
253
|
function ask (rl, question) {
|
|
237
254
|
return new Promise((resolve) => {
|
|
238
255
|
rl.question(question, (answer) => resolve(answer.trim()));
|
|
@@ -310,16 +327,6 @@ async function main () {
|
|
|
310
327
|
console.log(' Plugin registered.');
|
|
311
328
|
|
|
312
329
|
// 2. Interactive Telegram setup
|
|
313
|
-
const rl = readline.createInterface({
|
|
314
|
-
input: process.stdin,
|
|
315
|
-
output: process.stdout,
|
|
316
|
-
});
|
|
317
|
-
|
|
318
|
-
console.log('');
|
|
319
|
-
console.log('Claude Notification Plugin - Setup');
|
|
320
|
-
console.log('==================================');
|
|
321
|
-
console.log('');
|
|
322
|
-
|
|
323
330
|
let existing = {};
|
|
324
331
|
if (fs.existsSync(configPath)) {
|
|
325
332
|
try {
|
|
@@ -335,41 +342,61 @@ async function main () {
|
|
|
335
342
|
let token = existingToken;
|
|
336
343
|
let chatId = existingChatId;
|
|
337
344
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
chatId = '';
|
|
345
|
-
}
|
|
346
|
-
} else {
|
|
347
|
-
const useTelegram = await ask(rl, 'Configure Telegram? (y/N): ');
|
|
348
|
-
if (useTelegram.toLowerCase() === 'y') {
|
|
349
|
-
token = await ask(rl, 'Bot Token: ');
|
|
350
|
-
}
|
|
351
|
-
}
|
|
345
|
+
const ttyInput = openTtyInput();
|
|
346
|
+
if (ttyInput) {
|
|
347
|
+
const rl = readline.createInterface({
|
|
348
|
+
input: ttyInput,
|
|
349
|
+
output: process.stdout,
|
|
350
|
+
});
|
|
352
351
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
352
|
+
console.log(`
|
|
353
|
+
Claude Notification Plugin - Setup
|
|
354
|
+
==================================
|
|
355
|
+
`);
|
|
356
|
+
|
|
357
|
+
if (existingToken) {
|
|
358
|
+
const masked = existingToken.slice(0, 6) + '...' + existingToken.slice(-4);
|
|
359
|
+
console.log(`Telegram token found: ${masked}`);
|
|
360
|
+
const reuse = await ask(rl, 'Keep existing token? (Y/n): ');
|
|
361
|
+
if (reuse.toLowerCase() === 'n') {
|
|
362
|
+
token = await ask(rl, 'New Bot Token: ');
|
|
363
|
+
chatId = '';
|
|
364
|
+
}
|
|
365
|
+
} else {
|
|
366
|
+
const useTelegram = await ask(rl, 'Configure Telegram? (y/N): ');
|
|
367
|
+
if (useTelegram.toLowerCase() === 'y') {
|
|
368
|
+
token = await ask(rl, 'Bot Token: ');
|
|
369
|
+
}
|
|
370
|
+
}
|
|
357
371
|
|
|
358
|
-
|
|
359
|
-
|
|
372
|
+
if (token && !chatId) {
|
|
373
|
+
console.log('\nSend any message to your bot in Telegram, then press Enter.');
|
|
374
|
+
await ask(rl, '');
|
|
375
|
+
|
|
376
|
+
console.log('Fetching Chat ID...');
|
|
377
|
+
chatId = await fetchChatId(token);
|
|
378
|
+
|
|
379
|
+
if (chatId) {
|
|
380
|
+
console.log('Chat ID detected: ' + chatId);
|
|
381
|
+
} else {
|
|
382
|
+
console.log('Could not detect Chat ID automatically.');
|
|
383
|
+
chatId = await ask(rl, 'Enter Chat ID manually: ');
|
|
384
|
+
}
|
|
385
|
+
} else if (token && chatId) {
|
|
386
|
+
console.log(`Chat ID: ${chatId}`);
|
|
387
|
+
}
|
|
360
388
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
console.log('Could not detect Chat ID automatically.');
|
|
365
|
-
chatId = await ask(rl, 'Enter Chat ID manually: ');
|
|
389
|
+
rl.close();
|
|
390
|
+
if (ttyInput !== process.stdin) {
|
|
391
|
+
ttyInput.destroy();
|
|
366
392
|
}
|
|
367
|
-
} else
|
|
368
|
-
|
|
393
|
+
} else {
|
|
394
|
+
const telegramMsg = token && chatId
|
|
395
|
+
? 'Telegram: using existing config.'
|
|
396
|
+
: 'Telegram: skipped. Run "claude-notify install" to configure.';
|
|
397
|
+
console.log(`\nNon-interactive install (stdin is not a terminal).\n${telegramMsg}`);
|
|
369
398
|
}
|
|
370
399
|
|
|
371
|
-
rl.close();
|
|
372
|
-
|
|
373
400
|
// 3. Write config
|
|
374
401
|
fs.mkdirSync(claudeDir, { recursive: true });
|
|
375
402
|
|
|
@@ -451,38 +478,35 @@ async function main () {
|
|
|
451
478
|
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
452
479
|
|
|
453
480
|
// 5. Summary
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
console.log('Hooks registered:');
|
|
458
|
-
console.log(' - UserPromptSubmit (start timer)');
|
|
459
|
-
console.log(' - Stop (task finished)');
|
|
460
|
-
console.log(' - Notification (waiting for input)');
|
|
461
|
-
console.log('');
|
|
462
|
-
console.log('Config: ' + configPath);
|
|
463
|
-
|
|
464
|
-
if (config.telegram.token && config.telegram.chatId) {
|
|
465
|
-
console.log('Telegram: configured');
|
|
466
|
-
} else {
|
|
467
|
-
console.log('Telegram: not configured (edit config later)');
|
|
468
|
-
}
|
|
481
|
+
const telegramStatus = config.telegram.token && config.telegram.chatId
|
|
482
|
+
? 'Telegram: configured'
|
|
483
|
+
: 'Telegram: not configured (edit config later)';
|
|
469
484
|
|
|
485
|
+
let platformTip = '';
|
|
470
486
|
if (platform === 'darwin') {
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
487
|
+
platformTip = `\nTip: install terminal-notifier for better macOS notifications:
|
|
488
|
+
brew install terminal-notifier`;
|
|
489
|
+
} else if (platform === 'linux') {
|
|
490
|
+
platformTip = `\nTip: for voice announcements, install espeak:
|
|
491
|
+
sudo apt install espeak`;
|
|
474
492
|
}
|
|
475
493
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
console.log('Tip: for voice announcements, install espeak:');
|
|
479
|
-
console.log(' sudo apt install espeak');
|
|
480
|
-
}
|
|
494
|
+
console.log(`
|
|
495
|
+
Installed!
|
|
481
496
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
497
|
+
Hooks registered:
|
|
498
|
+
- UserPromptSubmit (start timer)
|
|
499
|
+
- Stop (task finished)
|
|
500
|
+
- Notification (waiting for input)
|
|
501
|
+
|
|
502
|
+
Config: ${configPath}
|
|
503
|
+
${telegramStatus}${platformTip}
|
|
504
|
+
|
|
505
|
+
To uninstall: claude-notify uninstall
|
|
506
|
+
|
|
507
|
+
To disable per project, add to .claude/settings.local.json:
|
|
508
|
+
{ "env": { "CLAUDE_NOTIFY_DISABLE": "1" } }
|
|
509
|
+
`);
|
|
486
510
|
}
|
|
487
511
|
|
|
488
512
|
main().then(() => 0);
|
package/bin/uninstall.js
CHANGED
|
@@ -104,14 +104,27 @@ if (fs.existsSync(pluginCacheDir)) {
|
|
|
104
104
|
cacheRemoved = true;
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
107
|
+
const extras = [
|
|
108
|
+
pluginEntryRemoved || cacheRemoved ? 'Plugin registration cleaned.' : '',
|
|
109
|
+
cliBinsRemoved ? 'CLI wrapper scripts removed.' : '',
|
|
110
|
+
].filter(Boolean).join('\n');
|
|
111
|
+
|
|
112
|
+
console.log(`
|
|
113
|
+
Claude Notification Plugin uninstalled.
|
|
114
|
+
Hooks removed from settings.json
|
|
115
|
+
Config files deleted.${extras ? `\n${extras}` : ''}
|
|
116
|
+
`);
|
|
117
|
+
|
|
118
|
+
// If run manually (not via npm lifecycle), remove the global npm package too
|
|
119
|
+
if (!process.env.npm_lifecycle_event) {
|
|
120
|
+
try {
|
|
121
|
+
console.log('Removing npm global package...');
|
|
122
|
+
execSync('npm uninstall -g claude-notification-plugin', {
|
|
123
|
+
stdio: 'inherit',
|
|
124
|
+
windowsHide: true,
|
|
125
|
+
});
|
|
126
|
+
console.log('');
|
|
127
|
+
} catch {
|
|
128
|
+
console.log('Could not remove npm package automatically.\nRun manually: npm uninstall -g claude-notification-plugin\n');
|
|
129
|
+
}
|
|
116
130
|
}
|
|
117
|
-
console.log('');
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-notification-plugin",
|
|
3
3
|
"productName": "claude-notification-plugin",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.94",
|
|
5
5
|
"description": "Claude Code task-completion notifications: Telegram, desktop notifications (Windows/macOS/Linux), sound, and voice",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"engines": {
|
|
@@ -20,7 +20,6 @@
|
|
|
20
20
|
"claude-notify": "bin/cli.js"
|
|
21
21
|
},
|
|
22
22
|
"scripts": {
|
|
23
|
-
"preuninstall": "node bin/uninstall.js",
|
|
24
23
|
"postinstall": "node bin/install.js",
|
|
25
24
|
"lint": "eslint .",
|
|
26
25
|
"lint:fix": "eslint --fix ."
|