claude-notification-plugin 1.0.93 → 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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-notification-plugin",
3
- "version": "1.0.93",
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
- npm uninstall -g claude-notification-plugin
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(path.join(__dirname, 'install.js'));
16
+ await import(toImportUrl('install.js'));
13
17
  break;
14
18
  case 'uninstall':
15
- await import(path.join(__dirname, 'uninstall.js'));
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(path.join(__dirname, 'listener-cli.js'));
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(__dirname, '..', 'notifier', 'notifier.js'));
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
@@ -238,13 +238,16 @@ function openTtyInput () {
238
238
  if (process.stdin.isTTY) {
239
239
  return process.stdin;
240
240
  }
241
- // Otherwise try to open the TTY device directly (works even when npm pipes stdin)
242
- try {
243
- const ttyPath = process.platform === 'win32' ? '\\\\.\\CON' : '/dev/tty';
244
- return fs.createReadStream(ttyPath, { encoding: 'utf-8' });
245
- } catch {
246
- return null;
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
+ }
247
249
  }
250
+ return null;
248
251
  }
249
252
 
250
253
  function ask (rl, question) {
@@ -346,10 +349,10 @@ async function main () {
346
349
  output: process.stdout,
347
350
  });
348
351
 
349
- console.log('');
350
- console.log('Claude Notification Plugin - Setup');
351
- console.log('==================================');
352
- console.log('');
352
+ console.log(`
353
+ Claude Notification Plugin - Setup
354
+ ==================================
355
+ `);
353
356
 
354
357
  if (existingToken) {
355
358
  const masked = existingToken.slice(0, 6) + '...' + existingToken.slice(-4);
@@ -367,8 +370,7 @@ async function main () {
367
370
  }
368
371
 
369
372
  if (token && !chatId) {
370
- console.log('');
371
- console.log('Send any message to your bot in Telegram, then press Enter.');
373
+ console.log('\nSend any message to your bot in Telegram, then press Enter.');
372
374
  await ask(rl, '');
373
375
 
374
376
  console.log('Fetching Chat ID...');
@@ -389,13 +391,10 @@ async function main () {
389
391
  ttyInput.destroy();
390
392
  }
391
393
  } else {
392
- console.log('');
393
- console.log('Non-interactive install (stdin is not a terminal).');
394
- if (token && chatId) {
395
- console.log('Telegram: using existing config.');
396
- } else {
397
- console.log('Telegram: skipped. Run "claude-notify install" to configure.');
398
- }
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}`);
399
398
  }
400
399
 
401
400
  // 3. Write config
@@ -479,38 +478,35 @@ async function main () {
479
478
  fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
480
479
 
481
480
  // 5. Summary
482
- console.log('');
483
- console.log('Installed!');
484
- console.log('');
485
- console.log('Hooks registered:');
486
- console.log(' - UserPromptSubmit (start timer)');
487
- console.log(' - Stop (task finished)');
488
- console.log(' - Notification (waiting for input)');
489
- console.log('');
490
- console.log('Config: ' + configPath);
491
-
492
- if (config.telegram.token && config.telegram.chatId) {
493
- console.log('Telegram: configured');
494
- } else {
495
- console.log('Telegram: not configured (edit config later)');
496
- }
481
+ const telegramStatus = config.telegram.token && config.telegram.chatId
482
+ ? 'Telegram: configured'
483
+ : 'Telegram: not configured (edit config later)';
497
484
 
485
+ let platformTip = '';
498
486
  if (platform === 'darwin') {
499
- console.log('');
500
- console.log('Tip: install terminal-notifier for better macOS notifications:');
501
- console.log(' brew install terminal-notifier');
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`;
502
492
  }
503
493
 
504
- if (platform === 'linux') {
505
- console.log('');
506
- console.log('Tip: for voice announcements, install espeak:');
507
- console.log(' sudo apt install espeak');
508
- }
494
+ console.log(`
495
+ Installed!
509
496
 
510
- console.log('');
511
- console.log('To disable per project, add to .claude/settings.local.json:');
512
- console.log(' { "env": { "CLAUDE_NOTIFY_DISABLE": "1" } }');
513
- console.log('');
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
+ `);
514
510
  }
515
511
 
516
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
- console.log('');
108
- console.log('Claude Notification Plugin uninstalled.');
109
- console.log('Hooks removed from settings.json');
110
- console.log('Config files deleted.');
111
- if (pluginEntryRemoved || cacheRemoved) {
112
- console.log('Plugin registration cleaned.');
113
- }
114
- if (cliBinsRemoved) {
115
- console.log('CLI wrapper scripts removed.');
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.93",
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 ."