claude-notification-plugin 1.1.105 → 1.1.108
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 +20 -20
- package/README.md +24 -10
- package/bin/cli.js +3 -2
- package/bin/install.js +10 -5
- package/commit-sha +1 -1
- package/listener/LISTENER-DETAILED.md +1 -1
- package/listener/listener.js +22 -3
- package/listener/pty-runner.js +14 -1
- package/listener/telegram-poller.js +80 -35
- package/notifier/notifier.js +15 -11
- package/package.json +69 -66
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "claude-notification-plugin",
|
|
3
|
-
"version": "1.1.
|
|
4
|
-
"description": "Claude Code task-completion notifications: Telegram, desktop notifications (Windows/macOS/Linux), sound, and voice",
|
|
5
|
-
"author": {
|
|
6
|
-
"name": "Viacheslav Makarov",
|
|
7
|
-
"email": "npmjs@bazilio.ru"
|
|
8
|
-
},
|
|
9
|
-
"homepage": "https://github.com/Bazilio-san/claude-notification-plugin#readme",
|
|
10
|
-
"repository": "https://github.com/Bazilio-san/claude-notification-plugin",
|
|
11
|
-
"license": "MIT",
|
|
12
|
-
"keywords": [
|
|
13
|
-
"notification",
|
|
14
|
-
"telegram",
|
|
15
|
-
"windows",
|
|
16
|
-
"sound",
|
|
17
|
-
"voice",
|
|
18
|
-
"hooks"
|
|
19
|
-
]
|
|
20
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "claude-notification-plugin",
|
|
3
|
+
"version": "1.1.108",
|
|
4
|
+
"description": "Telegram listener daemon + Claude Code task-completion notifications: Telegram, desktop notifications (Windows/macOS/Linux), sound, and voice",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Viacheslav Makarov",
|
|
7
|
+
"email": "npmjs@bazilio.ru"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://github.com/Bazilio-san/claude-notification-plugin#readme",
|
|
10
|
+
"repository": "https://github.com/Bazilio-san/claude-notification-plugin",
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"keywords": [
|
|
13
|
+
"notification",
|
|
14
|
+
"telegram",
|
|
15
|
+
"windows",
|
|
16
|
+
"sound",
|
|
17
|
+
"voice",
|
|
18
|
+
"hooks"
|
|
19
|
+
]
|
|
20
|
+
}
|
package/README.md
CHANGED
|
@@ -2,11 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
**Send a message in Telegram, and the task starts running on your PC.**
|
|
4
4
|
|
|
5
|
-
Cross-platform notifications for Claude Code task completion.
|
|
6
|
-
Sends alerts to Telegram and desktop (Windows, macOS, Linux) when Claude finishes working.
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
Cross-platform notifications for Claude Code task completion.
|
|
6
|
+
Sends alerts to Telegram and desktop (Windows, macOS, Linux) when Claude finishes working.
|
|
7
|
+
|
|
8
|
+
## Start Here (Listener)
|
|
9
|
+
|
|
10
|
+
If you want Telegram-first remote control, start with the Listener daemon:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
claude-notify listener setup
|
|
14
|
+
claude-notify listener start
|
|
15
|
+
claude-notify listener status
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Deep internals and troubleshooting: [Detailed Guide](listener/LISTENER-DETAILED.md)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
## Features
|
|
10
22
|
|
|
11
23
|
- **[Telegram Listener](#telegram-listener)** — your remote control for Claude (supports worktrees)
|
|
12
24
|
- Telegram bot messages with auto-delete
|
|
@@ -118,7 +130,7 @@ ENV: `CLAUDE_NOTIFY_TELEGRAM_TOKEN`
|
|
|
118
130
|
**telegram.chatId** — Chat ID to send messages to.
|
|
119
131
|
ENV: `CLAUDE_NOTIFY_TELEGRAM_CHAT_ID`
|
|
120
132
|
|
|
121
|
-
**telegram.deleteAfterHours** — Auto-delete old Telegram messages after N hours. `0` to disable. Default: **24**
|
|
133
|
+
**telegram.deleteAfterHours** — Auto-delete old Telegram messages after N hours (applies to notifier and listener bot messages). `0` to disable. Default: **24**
|
|
122
134
|
|
|
123
135
|
**telegram.includeLastCcMessageInTelegram** — Append Claude's last message to the notification (truncated to 3500 chars). Default: **true**
|
|
124
136
|
ENV: `CLAUDE_NOTIFY_INCLUDE_LAST_CC_MESSAGE_IN_TELEGRAM`
|
|
@@ -219,14 +231,16 @@ fix the login bug → runs in "default" project
|
|
|
219
231
|
&api/feature/auth implement OAuth2 → runs in a worktree (auto-created)
|
|
220
232
|
```
|
|
221
233
|
|
|
222
|
-
The bot replies with status and results:
|
|
234
|
+
The bot replies with status and results:
|
|
223
235
|
|
|
224
236
|
```
|
|
225
237
|
⏳ [&api] Running: add pagination to GET /users
|
|
226
238
|
...
|
|
227
|
-
✅ [&api] Done: add pagination to GET /users
|
|
228
|
-
<claude's output>
|
|
229
|
-
```
|
|
239
|
+
✅ [&api] Done: add pagination to GET /users
|
|
240
|
+
<claude's output>
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
If Claude returns a temporary API failure (`StopFailure`, e.g. `529 overloaded`), the listener saves the reported session ID and the next task for the same target auto-resumes it.
|
|
230
244
|
|
|
231
245
|
### 4. Manage the daemon
|
|
232
246
|
|
package/bin/cli.js
CHANGED
|
@@ -32,10 +32,11 @@ switch (command) {
|
|
|
32
32
|
console.log(`Usage: claude-notify <command> [options]
|
|
33
33
|
|
|
34
34
|
Commands:
|
|
35
|
+
listener <action> Manage the Telegram Listener daemon
|
|
36
|
+
Actions: start, stop, status, logs, restart
|
|
35
37
|
install Setup plugin registration, Telegram config, hooks
|
|
36
38
|
uninstall Remove plugin, hooks, config, CLI wrappers
|
|
37
|
-
|
|
38
|
-
Actions: start, stop, status, logs, restart`);
|
|
39
|
+
`);
|
|
39
40
|
process.exit(command ? 1 : 0);
|
|
40
41
|
}
|
|
41
42
|
}
|
package/bin/install.js
CHANGED
|
@@ -737,11 +737,16 @@ Plugin hooks (via hooks/hooks.json):
|
|
|
737
737
|
Config: ${CONFIG_PATH}
|
|
738
738
|
${telegramStatus}${platformTip}
|
|
739
739
|
|
|
740
|
-
Log: ${INSTALL_LOG_PATH}
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
740
|
+
Log: ${INSTALL_LOG_PATH}
|
|
741
|
+
|
|
742
|
+
Listener quick start:
|
|
743
|
+
claude-notify listener setup
|
|
744
|
+
claude-notify listener start
|
|
745
|
+
claude-notify listener status
|
|
746
|
+
|
|
747
|
+
To uninstall: claude-notify uninstall
|
|
748
|
+
|
|
749
|
+
To disable per project, add to .claude/settings.local.json: { "env": { "CLAUDE_NOTIFY_DISABLE": "1" } }`);
|
|
745
750
|
|
|
746
751
|
closeLog();
|
|
747
752
|
}
|
package/commit-sha
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
0daaa9a945591246c6de6c117d9cf9b4add7ab25
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Telegram Listener is a background daemon that receives tasks from a Telegram chat
|
|
4
4
|
and executes them on your machine via an interactive Claude Code PTY session. The result is sent back to Telegram.
|
|
5
5
|
|
|
6
|
-
**[Quick Start here](../
|
|
6
|
+
**[Quick Start here](../README.md#telegram-listener)**
|
|
7
7
|
|
|
8
8
|
# Detailed Guide
|
|
9
9
|
|
package/listener/listener.js
CHANGED
|
@@ -133,7 +133,9 @@ const resumeLastSessionEnabled = listenerConfig.resumeLastSession !== false; //
|
|
|
133
133
|
const sessionsListLimit = listenerConfig.sessionsListLimit || 5;
|
|
134
134
|
const sessionWorkingThresholdSec = listenerConfig.sessionWorkingThresholdSec || 2;
|
|
135
135
|
|
|
136
|
-
const poller = new TelegramPoller(token, chatId, logger
|
|
136
|
+
const poller = new TelegramPoller(token, chatId, logger, {
|
|
137
|
+
deleteAfterHours: config.telegram?.deleteAfterHours,
|
|
138
|
+
});
|
|
137
139
|
const queue = new WorkQueue(
|
|
138
140
|
logger,
|
|
139
141
|
listenerConfig.maxQueuePerWorkDir || 10,
|
|
@@ -304,7 +306,14 @@ async function notifyTaskCompletion (workDir, task, kind, payload = {}) {
|
|
|
304
306
|
let header;
|
|
305
307
|
let queueResult;
|
|
306
308
|
if (kind === 'error') {
|
|
307
|
-
|
|
309
|
+
const resumeSid = payload.resumeSessionId || payload.sessionId || null;
|
|
310
|
+
if (resumeSid) {
|
|
311
|
+
setStoredSessionId(workDir, resumeSid);
|
|
312
|
+
}
|
|
313
|
+
const resumeHint = resumeSid
|
|
314
|
+
? `\nSaved session: <code>${resumeSid}</code>\nNext task for this target will auto-resume it.`
|
|
315
|
+
: '';
|
|
316
|
+
header = `❌ <code>${label}</code>\nError${resumeHint}`;
|
|
308
317
|
queueResult = `ERROR: ${payload.errorMsg}`;
|
|
309
318
|
} else if (kind === 'timeout') {
|
|
310
319
|
const reason = payload.reason || `no activity for ${payload.timeoutMin} min`;
|
|
@@ -413,7 +422,17 @@ async function notifyTaskCompletion (workDir, task, kind, payload = {}) {
|
|
|
413
422
|
}
|
|
414
423
|
|
|
415
424
|
runner.on('complete', (workDir, task, result) => notifyTaskCompletion(workDir, task, 'complete', result));
|
|
416
|
-
runner.on('error', (workDir, task,
|
|
425
|
+
runner.on('error', (workDir, task, errorData) => {
|
|
426
|
+
if (typeof errorData === 'string') {
|
|
427
|
+
notifyTaskCompletion(workDir, task, 'error', { errorMsg: errorData });
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
notifyTaskCompletion(workDir, task, 'error', {
|
|
431
|
+
errorMsg: errorData?.message || 'Unknown error',
|
|
432
|
+
sessionId: errorData?.sessionId || null,
|
|
433
|
+
resumeSessionId: errorData?.resumeSessionId || null,
|
|
434
|
+
});
|
|
435
|
+
});
|
|
417
436
|
runner.on('timeout', (workDir, task) => notifyTaskCompletion(workDir, task, 'timeout', {
|
|
418
437
|
timeoutMin: Math.round(taskTimeout / 60000),
|
|
419
438
|
}));
|
package/listener/pty-runner.js
CHANGED
|
@@ -154,6 +154,8 @@ export class PtyRunner extends EventEmitter {
|
|
|
154
154
|
} else if (type === 'error') {
|
|
155
155
|
// StopFailure — emit error, abort task
|
|
156
156
|
this._unlinkSafe(filePath);
|
|
157
|
+
const errorSignalSessionId = marker.sessionId
|
|
158
|
+
|| (f.startsWith('err_') ? f.slice(4, -5) : null);
|
|
157
159
|
for (const [workDir, session] of this.sessions) {
|
|
158
160
|
if (session.state === 'busy' && this._normalizePath(session.workDir) === this._normalizePath(cwd)) {
|
|
159
161
|
if (session._pendingId && this.pendingMarkers.has(session._pendingId)) {
|
|
@@ -164,11 +166,22 @@ export class PtyRunner extends EventEmitter {
|
|
|
164
166
|
session.currentTask = null;
|
|
165
167
|
this._destroyPty(workDir);
|
|
166
168
|
const errorMsg = `API error: ${marker.error}${marker.errorDetails ? ' — ' + marker.errorDetails : ''}`;
|
|
169
|
+
const resumeMatch = (marker.errorDetails || marker.lastAssistantMessage || '')
|
|
170
|
+
.match(/(?:^|\s)--resume\s+([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/i);
|
|
171
|
+
const resumeSessionId = resumeMatch?.[1] || null;
|
|
167
172
|
this.logger.error(`Hook signal: ${errorMsg} in ${workDir}`);
|
|
168
173
|
if (this.taskLogger) {
|
|
169
174
|
this.taskLogger.logAnswer(task?.project || 'unknown', task?.branch || 'main', errorMsg, 1);
|
|
170
175
|
}
|
|
171
|
-
this.emit('error', workDir, task,
|
|
176
|
+
this.emit('error', workDir, task, {
|
|
177
|
+
message: errorMsg,
|
|
178
|
+
sessionId: errorSignalSessionId && errorSignalSessionId !== 'unknown'
|
|
179
|
+
? errorSignalSessionId
|
|
180
|
+
: null,
|
|
181
|
+
resumeSessionId,
|
|
182
|
+
errorType: marker.error || 'unknown',
|
|
183
|
+
errorDetails: marker.errorDetails || '',
|
|
184
|
+
});
|
|
172
185
|
break;
|
|
173
186
|
}
|
|
174
187
|
}
|
|
@@ -7,17 +7,22 @@ const MAX_MESSAGE_LENGTH = 4096;
|
|
|
7
7
|
// of looping silently.
|
|
8
8
|
const MAX_CONSECUTIVE_409 = 8;
|
|
9
9
|
|
|
10
|
-
export class TelegramPoller {
|
|
11
|
-
constructor (token, chatId, logger) {
|
|
12
|
-
this.token = token;
|
|
13
|
-
this.chatId = String(chatId);
|
|
14
|
-
this.logger = logger;
|
|
15
|
-
this.baseUrl = `https://api.telegram.org/bot${token}`;
|
|
16
|
-
this.offset = 0;
|
|
17
|
-
this._errorBackoff = 0; // current backoff in ms (0 = no backoff)
|
|
18
|
-
this._consecutiveErrors = 0;
|
|
19
|
-
this._consecutive409 = 0;
|
|
20
|
-
|
|
10
|
+
export class TelegramPoller {
|
|
11
|
+
constructor (token, chatId, logger, options = {}) {
|
|
12
|
+
this.token = token;
|
|
13
|
+
this.chatId = String(chatId);
|
|
14
|
+
this.logger = logger;
|
|
15
|
+
this.baseUrl = `https://api.telegram.org/bot${token}`;
|
|
16
|
+
this.offset = 0;
|
|
17
|
+
this._errorBackoff = 0; // current backoff in ms (0 = no backoff)
|
|
18
|
+
this._consecutiveErrors = 0;
|
|
19
|
+
this._consecutive409 = 0;
|
|
20
|
+
const deleteAfterHours = Number(options.deleteAfterHours);
|
|
21
|
+
this._deleteAfterMs = Number.isFinite(deleteAfterHours) && deleteAfterHours > 0
|
|
22
|
+
? deleteAfterHours * 3600_000
|
|
23
|
+
: 0;
|
|
24
|
+
this._sentMessages = [];
|
|
25
|
+
}
|
|
21
26
|
|
|
22
27
|
async flush () {
|
|
23
28
|
try {
|
|
@@ -153,9 +158,12 @@ export class TelegramPoller {
|
|
|
153
158
|
body: JSON.stringify({ ...base, parse_mode: 'HTML' }),
|
|
154
159
|
});
|
|
155
160
|
let data = await res.json();
|
|
156
|
-
if (data.ok) {
|
|
157
|
-
|
|
158
|
-
|
|
161
|
+
if (data.ok) {
|
|
162
|
+
const messageId = data.result.message_id;
|
|
163
|
+
this._trackSentMessage(messageId);
|
|
164
|
+
await this._cleanupOldMessages();
|
|
165
|
+
return messageId;
|
|
166
|
+
}
|
|
159
167
|
const htmlErr = data.description || `error_code ${data.error_code}`;
|
|
160
168
|
// Retry without HTML parse mode (covers entity-parsing errors)
|
|
161
169
|
res = await fetch(`${this.baseUrl}/sendMessage`, {
|
|
@@ -164,10 +172,13 @@ export class TelegramPoller {
|
|
|
164
172
|
body: JSON.stringify(base),
|
|
165
173
|
});
|
|
166
174
|
data = await res.json();
|
|
167
|
-
if (data.ok) {
|
|
168
|
-
this.logger.warn(`sendMessage: HTML failed (${htmlErr}), plain succeeded`);
|
|
169
|
-
|
|
170
|
-
|
|
175
|
+
if (data.ok) {
|
|
176
|
+
this.logger.warn(`sendMessage: HTML failed (${htmlErr}), plain succeeded`);
|
|
177
|
+
const messageId = data.result.message_id;
|
|
178
|
+
this._trackSentMessage(messageId);
|
|
179
|
+
await this._cleanupOldMessages();
|
|
180
|
+
return messageId;
|
|
181
|
+
}
|
|
171
182
|
this.logger.error(`sendMessage failed: HTML=${htmlErr}, plain=${data.description || data.error_code}`);
|
|
172
183
|
return null;
|
|
173
184
|
} catch (err) {
|
|
@@ -262,23 +273,57 @@ export class TelegramPoller {
|
|
|
262
273
|
}
|
|
263
274
|
}
|
|
264
275
|
|
|
265
|
-
async sendDocument (buffer, filename, caption) {
|
|
266
|
-
try {
|
|
267
|
-
const formData = new FormData();
|
|
268
|
-
formData.append('chat_id', this.chatId);
|
|
269
|
-
formData.append('document', new Blob([buffer]), filename);
|
|
270
|
-
if (caption) {
|
|
271
|
-
formData.append('caption', caption.slice(0, 1024));
|
|
272
|
-
}
|
|
273
|
-
await fetch(`${this.baseUrl}/sendDocument`, {
|
|
274
|
-
method: 'POST',
|
|
275
|
-
body: formData,
|
|
276
|
-
});
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
}
|
|
276
|
+
async sendDocument (buffer, filename, caption) {
|
|
277
|
+
try {
|
|
278
|
+
const formData = new FormData();
|
|
279
|
+
formData.append('chat_id', this.chatId);
|
|
280
|
+
formData.append('document', new Blob([buffer]), filename);
|
|
281
|
+
if (caption) {
|
|
282
|
+
formData.append('caption', caption.slice(0, 1024));
|
|
283
|
+
}
|
|
284
|
+
const res = await fetch(`${this.baseUrl}/sendDocument`, {
|
|
285
|
+
method: 'POST',
|
|
286
|
+
body: formData,
|
|
287
|
+
});
|
|
288
|
+
const data = await res.json();
|
|
289
|
+
if (data.ok && data.result?.message_id) {
|
|
290
|
+
this._trackSentMessage(data.result.message_id);
|
|
291
|
+
await this._cleanupOldMessages();
|
|
292
|
+
}
|
|
293
|
+
} catch (err) {
|
|
294
|
+
this.logger.error(`sendDocument error: ${err.message}`);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
_trackSentMessage (messageId) {
|
|
299
|
+
if (!messageId || this._deleteAfterMs <= 0) {
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
this._sentMessages.push({
|
|
303
|
+
id: messageId,
|
|
304
|
+
ts: Date.now(),
|
|
305
|
+
});
|
|
306
|
+
if (this._sentMessages.length > 1000) {
|
|
307
|
+
this._sentMessages = this._sentMessages.slice(-500);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
async _cleanupOldMessages () {
|
|
312
|
+
if (this._deleteAfterMs <= 0 || this._sentMessages.length === 0) {
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
const now = Date.now();
|
|
316
|
+
const keep = [];
|
|
317
|
+
for (const msg of this._sentMessages) {
|
|
318
|
+
if (now - msg.ts > this._deleteAfterMs) {
|
|
319
|
+
await this.deleteMessage(msg.id);
|
|
320
|
+
} else {
|
|
321
|
+
keep.push(msg);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
this._sentMessages = keep;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
282
327
|
|
|
283
328
|
function escapeHtml (text) {
|
|
284
329
|
return text
|
package/notifier/notifier.js
CHANGED
|
@@ -214,15 +214,16 @@ function writePtySignalFile (event) {
|
|
|
214
214
|
});
|
|
215
215
|
}
|
|
216
216
|
|
|
217
|
-
function writeErrorSignalFile (event) {
|
|
218
|
-
const sessionId = event.session_id || 'unknown';
|
|
219
|
-
writeSignalFile(`err_${sessionId}.json`, {
|
|
220
|
-
type: 'error',
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
217
|
+
function writeErrorSignalFile (event) {
|
|
218
|
+
const sessionId = event.session_id || 'unknown';
|
|
219
|
+
writeSignalFile(`err_${sessionId}.json`, {
|
|
220
|
+
type: 'error',
|
|
221
|
+
sessionId,
|
|
222
|
+
cwd: event.cwd || process.cwd(),
|
|
223
|
+
error: event.error || 'unknown',
|
|
224
|
+
errorDetails: event.error_details || '',
|
|
225
|
+
lastAssistantMessage: event.last_assistant_message || '',
|
|
226
|
+
timestamp: Date.now(),
|
|
226
227
|
});
|
|
227
228
|
}
|
|
228
229
|
|
|
@@ -413,8 +414,11 @@ async function sendTelegram (config, state) {
|
|
|
413
414
|
}
|
|
414
415
|
|
|
415
416
|
// Delete old messages
|
|
416
|
-
const
|
|
417
|
-
|
|
417
|
+
const deleteAfter = Number(config.telegram.deleteAfterHours);
|
|
418
|
+
const maxAge = Number.isFinite(deleteAfter) && deleteAfter > 0
|
|
419
|
+
? deleteAfter * 3600_000
|
|
420
|
+
: 0;
|
|
421
|
+
if (maxAge > 0 && state.sentMessages?.length) {
|
|
418
422
|
const now = Date.now();
|
|
419
423
|
const keep = [];
|
|
420
424
|
for (const msg of state.sentMessages) {
|
package/package.json
CHANGED
|
@@ -1,66 +1,69 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "claude-notification-plugin",
|
|
3
|
-
"productName": "claude-notification-plugin",
|
|
4
|
-
"version": "1.1.
|
|
5
|
-
"description": "Claude Code task-completion notifications: Telegram, desktop notifications (Windows/macOS/Linux), sound, and voice",
|
|
6
|
-
"type": "module",
|
|
7
|
-
"engines": {
|
|
8
|
-
"node": ">=18.0.0"
|
|
9
|
-
},
|
|
10
|
-
"files": [
|
|
11
|
-
".claude-plugin/",
|
|
12
|
-
"bin/",
|
|
13
|
-
"claude_img/claude.png",
|
|
14
|
-
"hooks/",
|
|
15
|
-
"listener/",
|
|
16
|
-
"notifier/",
|
|
17
|
-
"commit-sha",
|
|
18
|
-
"README.md",
|
|
19
|
-
"LICENSE"
|
|
20
|
-
],
|
|
21
|
-
"bin": {
|
|
22
|
-
"claude-notify": "bin/cli.js"
|
|
23
|
-
},
|
|
24
|
-
"scripts": {
|
|
25
|
-
"prepack": "git rev-parse HEAD > commit-sha",
|
|
26
|
-
"postinstall": "node bin/install.js",
|
|
27
|
-
"lint": "eslint .",
|
|
28
|
-
"lint:fix": "eslint --fix .",
|
|
29
|
-
"listener:restart": "claude-notify listener restart",
|
|
30
|
-
"listener:stop": "claude-notify listener stop",
|
|
31
|
-
"listener:start": "claude-notify listener start",
|
|
32
|
-
"listener:status": "claude-notify listener status"
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
"claude"
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
"
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
"
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "claude-notification-plugin",
|
|
3
|
+
"productName": "claude-notification-plugin",
|
|
4
|
+
"version": "1.1.108",
|
|
5
|
+
"description": "Telegram listener daemon + Claude Code task-completion notifications: Telegram, desktop notifications (Windows/macOS/Linux), sound, and voice",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=18.0.0"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
".claude-plugin/",
|
|
12
|
+
"bin/",
|
|
13
|
+
"claude_img/claude.png",
|
|
14
|
+
"hooks/",
|
|
15
|
+
"listener/",
|
|
16
|
+
"notifier/",
|
|
17
|
+
"commit-sha",
|
|
18
|
+
"README.md",
|
|
19
|
+
"LICENSE"
|
|
20
|
+
],
|
|
21
|
+
"bin": {
|
|
22
|
+
"claude-notify": "bin/cli.js"
|
|
23
|
+
},
|
|
24
|
+
"scripts": {
|
|
25
|
+
"prepack": "git rev-parse HEAD > commit-sha",
|
|
26
|
+
"postinstall": "node bin/install.js",
|
|
27
|
+
"lint": "eslint .",
|
|
28
|
+
"lint:fix": "eslint --fix .",
|
|
29
|
+
"listener:restart": "claude-notify listener restart",
|
|
30
|
+
"listener:stop": "claude-notify listener stop",
|
|
31
|
+
"listener:start": "claude-notify listener start",
|
|
32
|
+
"listener:status": "claude-notify listener status",
|
|
33
|
+
"agents:link": "node scripts/claude-2-agents-symlink.js setup",
|
|
34
|
+
"agents:link:status": "node scripts/claude-2-agents-symlink.js status",
|
|
35
|
+
"agents:link:remove": "node scripts/claude-2-agents-symlink.js remove"
|
|
36
|
+
},
|
|
37
|
+
"keywords": [
|
|
38
|
+
"claude",
|
|
39
|
+
"claude-code",
|
|
40
|
+
"notifications",
|
|
41
|
+
"telegram",
|
|
42
|
+
"hooks",
|
|
43
|
+
"macos",
|
|
44
|
+
"linux",
|
|
45
|
+
"cross-platform"
|
|
46
|
+
],
|
|
47
|
+
"author": {
|
|
48
|
+
"name": "Viacheslav Makarov",
|
|
49
|
+
"email": "npmjs@bazilio.ru"
|
|
50
|
+
},
|
|
51
|
+
"license": "MIT",
|
|
52
|
+
"repository": {
|
|
53
|
+
"type": "git",
|
|
54
|
+
"url": "git+https://github.com/Bazilio-san/claude-notification-plugin.git"
|
|
55
|
+
},
|
|
56
|
+
"homepage": "https://github.com/Bazilio-san/claude-notification-plugin#readme",
|
|
57
|
+
"publishConfig": {
|
|
58
|
+
"access": "public"
|
|
59
|
+
},
|
|
60
|
+
"dependencies": {
|
|
61
|
+
"@xterm/headless": "^6.0.0",
|
|
62
|
+
"node-notifier": "^10.0.1",
|
|
63
|
+
"node-pty": "^1.1.0"
|
|
64
|
+
},
|
|
65
|
+
"devDependencies": {
|
|
66
|
+
"eslint-plugin-import": "^2.31.0",
|
|
67
|
+
"eslint-plugin-unused-imports": "^4.4.1"
|
|
68
|
+
}
|
|
69
|
+
}
|