claude-notification-plugin 1.0.101 → 1.0.103
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/bin/install.js +2 -1
- package/bin/uninstall.js +100 -59
- package/commit-sha +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-notification-plugin",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.103",
|
|
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/bin/install.js
CHANGED
|
@@ -379,7 +379,8 @@ Claude Notification Plugin - Setup
|
|
|
379
379
|
}
|
|
380
380
|
|
|
381
381
|
if (token && !chatId) {
|
|
382
|
-
console.log(
|
|
382
|
+
console.log(`\x1b[32m
|
|
383
|
+
Send any message to your bot in Telegram, then press Enter.\x1b[0m`);
|
|
383
384
|
await ask(rl, '');
|
|
384
385
|
|
|
385
386
|
console.log('Fetching Chat ID...');
|
package/bin/uninstall.js
CHANGED
|
@@ -9,48 +9,87 @@ const home = os.homedir();
|
|
|
9
9
|
const claudeDir = path.join(home, '.claude');
|
|
10
10
|
const configPath = path.join(claudeDir, 'notifier.config.json');
|
|
11
11
|
const settingsPath = path.join(claudeDir, 'settings.json');
|
|
12
|
-
const statePath = path.join(claudeDir, '.notifier_state.json');
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
12
|
+
const statePath = path.join(claudeDir, '.notifier_state.json');
|
|
13
|
+
const pidFile = path.join(claudeDir, '.listener.pid');
|
|
14
|
+
|
|
15
|
+
const HOOK_COMMAND = 'claude-notify';
|
|
16
|
+
const PLUGIN_KEY = 'claude-notification-plugin@bazilio-plugins';
|
|
17
|
+
const MARKETPLACE_KEY = 'bazilio-plugins';
|
|
18
|
+
|
|
19
|
+
function isPluginHookCommand (command) {
|
|
20
|
+
if (typeof command !== 'string') {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const normalized = command.trim().toLowerCase();
|
|
25
|
+
if (!normalized) {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return normalized === HOOK_COMMAND || normalized.startsWith(`${HOOK_COMMAND} `);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Stop listener daemon if running
|
|
33
|
+
let listenerStopped = false;
|
|
34
|
+
try {
|
|
35
|
+
if (fs.existsSync(pidFile)) {
|
|
36
|
+
const pid = parseInt(fs.readFileSync(pidFile, 'utf-8').trim(), 10);
|
|
37
|
+
if (!isNaN(pid)) {
|
|
38
|
+
try {
|
|
39
|
+
if (process.platform === 'win32') {
|
|
40
|
+
execSync(`taskkill /PID ${pid} /T /F`, { stdio: 'ignore', windowsHide: true });
|
|
41
|
+
} else {
|
|
42
|
+
process.kill(pid, 'SIGTERM');
|
|
43
|
+
let tries = 10;
|
|
44
|
+
const isAlive = (p) => {
|
|
45
|
+
try {
|
|
46
|
+
process.kill(p, 0);
|
|
47
|
+
return true;
|
|
48
|
+
} catch {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
while (tries-- > 0 && isAlive(pid)) {
|
|
53
|
+
execSync('sleep 0.5', { stdio: 'ignore' });
|
|
54
|
+
}
|
|
55
|
+
if (isAlive(pid)) {
|
|
56
|
+
process.kill(pid, 'SIGKILL');
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
listenerStopped = true;
|
|
60
|
+
} catch {
|
|
61
|
+
// process may already be dead
|
|
62
|
+
}
|
|
63
|
+
fs.unlinkSync(pidFile);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
} catch {
|
|
67
|
+
// ignore
|
|
68
|
+
}
|
|
30
69
|
|
|
31
70
|
// Remove hooks from settings.json
|
|
32
|
-
let hooksRemoved = false;
|
|
33
|
-
let hooksRemoveError = '';
|
|
34
|
-
if (fs.existsSync(settingsPath)) {
|
|
35
|
-
try {
|
|
36
|
-
const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));
|
|
37
|
-
let hadPluginHooks = false;
|
|
38
|
-
|
|
39
|
-
if (settings.hooks) {
|
|
40
|
-
for (const event of Object.keys(settings.hooks)) {
|
|
41
|
-
const eventHooks = Array.isArray(settings.hooks[event]) ? settings.hooks[event] : [];
|
|
42
|
-
const hadInEvent = eventHooks.some((matcher) =>
|
|
43
|
-
matcher.hooks?.some((h) => isPluginHookCommand(h.command)),
|
|
44
|
-
);
|
|
45
|
-
hadPluginHooks = hadPluginHooks || hadInEvent;
|
|
46
|
-
|
|
47
|
-
settings.hooks[event] = settings.hooks[event].filter((matcher) =>
|
|
48
|
-
!matcher.hooks?.some((h) => isPluginHookCommand(h.command)),
|
|
49
|
-
);
|
|
50
|
-
|
|
51
|
-
if (settings.hooks[event].length === 0) {
|
|
52
|
-
delete settings.hooks[event];
|
|
53
|
-
}
|
|
71
|
+
let hooksRemoved = false;
|
|
72
|
+
let hooksRemoveError = '';
|
|
73
|
+
if (fs.existsSync(settingsPath)) {
|
|
74
|
+
try {
|
|
75
|
+
const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));
|
|
76
|
+
let hadPluginHooks = false;
|
|
77
|
+
|
|
78
|
+
if (settings.hooks) {
|
|
79
|
+
for (const event of Object.keys(settings.hooks)) {
|
|
80
|
+
const eventHooks = Array.isArray(settings.hooks[event]) ? settings.hooks[event] : [];
|
|
81
|
+
const hadInEvent = eventHooks.some((matcher) =>
|
|
82
|
+
matcher.hooks?.some((h) => isPluginHookCommand(h.command)),
|
|
83
|
+
);
|
|
84
|
+
hadPluginHooks = hadPluginHooks || hadInEvent;
|
|
85
|
+
|
|
86
|
+
settings.hooks[event] = settings.hooks[event].filter((matcher) =>
|
|
87
|
+
!matcher.hooks?.some((h) => isPluginHookCommand(h.command)),
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
if (settings.hooks[event].length === 0) {
|
|
91
|
+
delete settings.hooks[event];
|
|
92
|
+
}
|
|
54
93
|
}
|
|
55
94
|
|
|
56
95
|
if (Object.keys(settings.hooks).length === 0) {
|
|
@@ -76,33 +115,34 @@ if (fs.existsSync(settingsPath)) {
|
|
|
76
115
|
|
|
77
116
|
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
78
117
|
|
|
79
|
-
// Verify hooks were actually removed
|
|
80
|
-
const verify = JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));
|
|
81
|
-
const remainingPluginHooks = verify.hooks
|
|
82
|
-
? Object.values(verify.hooks).some((matchers) =>
|
|
83
|
-
Array.isArray(matchers) &&
|
|
84
|
-
matchers.some((m) => m.hooks?.some((h) => isPluginHookCommand(h.command))),
|
|
85
|
-
)
|
|
86
|
-
: false;
|
|
87
|
-
hooksRemoved = hadPluginHooks && !remainingPluginHooks;
|
|
88
|
-
if (hadPluginHooks && remainingPluginHooks) {
|
|
89
|
-
hooksRemoveError = 'Hooks still present in settings.json after removal attempt';
|
|
90
|
-
}
|
|
91
|
-
} catch (err) {
|
|
92
|
-
hooksRemoveError = `Failed to update settings.json: ${err.message}`;
|
|
93
|
-
}
|
|
118
|
+
// Verify hooks were actually removed
|
|
119
|
+
const verify = JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));
|
|
120
|
+
const remainingPluginHooks = verify.hooks
|
|
121
|
+
? Object.values(verify.hooks).some((matchers) =>
|
|
122
|
+
Array.isArray(matchers) &&
|
|
123
|
+
matchers.some((m) => m.hooks?.some((h) => isPluginHookCommand(h.command))),
|
|
124
|
+
)
|
|
125
|
+
: false;
|
|
126
|
+
hooksRemoved = hadPluginHooks && !remainingPluginHooks;
|
|
127
|
+
if (hadPluginHooks && remainingPluginHooks) {
|
|
128
|
+
hooksRemoveError = 'Hooks still present in settings.json after removal attempt';
|
|
129
|
+
}
|
|
130
|
+
} catch (err) {
|
|
131
|
+
hooksRemoveError = `Failed to update settings.json: ${err.message}`;
|
|
132
|
+
}
|
|
94
133
|
}
|
|
95
134
|
|
|
96
|
-
// Remove config, state, and
|
|
135
|
+
// Remove config, state, resolver, and listener files
|
|
97
136
|
const resolverPath = path.join(claudeDir, 'claude-notify-resolve.js');
|
|
98
|
-
|
|
137
|
+
const listenerLogFile = path.join(claudeDir, '.cc-n-listener.log');
|
|
138
|
+
for (const file of [configPath, statePath, resolverPath, pidFile, listenerLogFile]) {
|
|
99
139
|
if (fs.existsSync(file)) {
|
|
100
140
|
fs.unlinkSync(file);
|
|
101
141
|
}
|
|
102
142
|
}
|
|
103
143
|
|
|
104
|
-
// Remove CLI wrapper script
|
|
105
|
-
const WRAPPER_NAMES = ['claude-notify'];
|
|
144
|
+
// Remove CLI wrapper script
|
|
145
|
+
const WRAPPER_NAMES = ['claude-notify'];
|
|
106
146
|
let cliBinsRemoved = false;
|
|
107
147
|
const ext = process.platform === 'win32' ? '.cmd' : '';
|
|
108
148
|
|
|
@@ -162,6 +202,7 @@ const hooksStatus = hooksRemoved
|
|
|
162
202
|
: 'No hooks found in settings.json';
|
|
163
203
|
|
|
164
204
|
const extras = [
|
|
205
|
+
listenerStopped ? 'Listener daemon stopped.' : '',
|
|
165
206
|
pluginEntryRemoved || cacheRemoved ? 'Plugin registration cleaned.' : '',
|
|
166
207
|
cliBinsRemoved ? 'CLI wrapper scripts removed.' : '',
|
|
167
208
|
].filter(Boolean).join('\n');
|
package/commit-sha
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
9d361842ca5f638701a8cd37f7655ff593a3efd5
|
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.103",
|
|
5
5
|
"description": "Claude Code task-completion notifications: Telegram, desktop notifications (Windows/macOS/Linux), sound, and voice",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"engines": {
|