claude-notification-plugin 1.0.93 → 1.0.95

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.95",
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
@@ -38,6 +38,15 @@ function getVersion () {
38
38
  return pkg.version;
39
39
  }
40
40
 
41
+ function readCommitSha () {
42
+ const shaFile = path.join(PACKAGE_ROOT, 'commit-sha');
43
+ try {
44
+ return fs.readFileSync(shaFile, 'utf-8').trim();
45
+ } catch {
46
+ return '';
47
+ }
48
+ }
49
+
41
50
  function copyToCache (version) {
42
51
  const cacheBase = path.join(pluginsDir, 'cache', MARKETPLACE_KEY, 'claude-notification-plugin');
43
52
  const dest = path.join(cacheBase, version);
@@ -99,7 +108,7 @@ function updateInstalledPlugins (version, installPath) {
99
108
  version,
100
109
  installedAt: existing?.installedAt || now,
101
110
  lastUpdated: now,
102
- gitCommitSha: existing?.gitCommitSha || '',
111
+ gitCommitSha: readCommitSha(),
103
112
  }];
104
113
 
105
114
  fs.writeFileSync(installedPluginsPath, JSON.stringify(data, null, 2));
@@ -238,13 +247,16 @@ function openTtyInput () {
238
247
  if (process.stdin.isTTY) {
239
248
  return process.stdin;
240
249
  }
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;
250
+ // On Unix, try opening /dev/tty directly (works even when npm pipes stdin)
251
+ if (process.platform !== 'win32') {
252
+ try {
253
+ const fd = fs.openSync('/dev/tty', 'r');
254
+ return fs.createReadStream(null, { fd, encoding: 'utf-8' });
255
+ } catch {
256
+ // no TTY available (CI/CD, Docker, etc.)
257
+ }
247
258
  }
259
+ return null;
248
260
  }
249
261
 
250
262
  function ask (rl, question) {
@@ -346,10 +358,10 @@ async function main () {
346
358
  output: process.stdout,
347
359
  });
348
360
 
349
- console.log('');
350
- console.log('Claude Notification Plugin - Setup');
351
- console.log('==================================');
352
- console.log('');
361
+ console.log(`
362
+ Claude Notification Plugin - Setup
363
+ ==================================
364
+ `);
353
365
 
354
366
  if (existingToken) {
355
367
  const masked = existingToken.slice(0, 6) + '...' + existingToken.slice(-4);
@@ -367,8 +379,7 @@ async function main () {
367
379
  }
368
380
 
369
381
  if (token && !chatId) {
370
- console.log('');
371
- console.log('Send any message to your bot in Telegram, then press Enter.');
382
+ console.log('\nSend any message to your bot in Telegram, then press Enter.');
372
383
  await ask(rl, '');
373
384
 
374
385
  console.log('Fetching Chat ID...');
@@ -389,13 +400,10 @@ async function main () {
389
400
  ttyInput.destroy();
390
401
  }
391
402
  } 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
- }
403
+ const telegramMsg = token && chatId
404
+ ? 'Telegram: using existing config.'
405
+ : 'Telegram: skipped. Run "claude-notify install" to configure.';
406
+ console.log(`\nNon-interactive install (stdin is not a terminal).\n${telegramMsg}`);
399
407
  }
400
408
 
401
409
  // 3. Write config
@@ -479,38 +487,35 @@ async function main () {
479
487
  fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
480
488
 
481
489
  // 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
- }
490
+ const telegramStatus = config.telegram.token && config.telegram.chatId
491
+ ? 'Telegram: configured'
492
+ : 'Telegram: not configured (edit config later)';
497
493
 
494
+ let platformTip = '';
498
495
  if (platform === 'darwin') {
499
- console.log('');
500
- console.log('Tip: install terminal-notifier for better macOS notifications:');
501
- console.log(' brew install terminal-notifier');
496
+ platformTip = `\nTip: install terminal-notifier for better macOS notifications:
497
+ brew install terminal-notifier`;
498
+ } else if (platform === 'linux') {
499
+ platformTip = `\nTip: for voice announcements, install espeak:
500
+ sudo apt install espeak`;
502
501
  }
503
502
 
504
- if (platform === 'linux') {
505
- console.log('');
506
- console.log('Tip: for voice announcements, install espeak:');
507
- console.log(' sudo apt install espeak');
508
- }
503
+ console.log(`
504
+ Installed!
509
505
 
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('');
506
+ Hooks registered:
507
+ - UserPromptSubmit (start timer)
508
+ - Stop (task finished)
509
+ - Notification (waiting for input)
510
+
511
+ Config: ${configPath}
512
+ ${telegramStatus}${platformTip}
513
+
514
+ To uninstall: claude-notify uninstall
515
+
516
+ To disable per project, add to .claude/settings.local.json:
517
+ { "env": { "CLAUDE_NOTIFY_DISABLE": "1" } }
518
+ `);
514
519
  }
515
520
 
516
521
  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/commit-sha ADDED
@@ -0,0 +1 @@
1
+ 091d9986d9a8ce98517b69b613bd17c4a1db0eb0
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.95",
5
5
  "description": "Claude Code task-completion notifications: Telegram, desktop notifications (Windows/macOS/Linux), sound, and voice",
6
6
  "type": "module",
7
7
  "engines": {
@@ -13,6 +13,7 @@
13
13
  "hooks/",
14
14
  "listener/",
15
15
  "notifier/",
16
+ "commit-sha",
16
17
  "README.md",
17
18
  "LICENSE"
18
19
  ],
@@ -20,7 +21,7 @@
20
21
  "claude-notify": "bin/cli.js"
21
22
  },
22
23
  "scripts": {
23
- "preuninstall": "node bin/uninstall.js",
24
+ "prepack": "git rev-parse HEAD > commit-sha",
24
25
  "postinstall": "node bin/install.js",
25
26
  "lint": "eslint .",
26
27
  "lint:fix": "eslint --fix ."