claude-notification-plugin 1.1.88 → 1.1.89

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.1.88",
3
+ "version": "1.1.89",
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/commit-sha CHANGED
@@ -1 +1 @@
1
- 7e575c0a21e90d7fd6cc207bc231c9256cb95e35
1
+ 0bd678de06dbe99bc95ce19ee702c72549a29536
@@ -172,14 +172,55 @@ for (const alias of Object.keys(listenerConfig.projects)) {
172
172
  // WATCHDOG + ORPHAN RECOVERY
173
173
  // ----------------------
174
174
 
175
- // 1. Clean up tasks that exceeded taskTimeout
176
- const recovered = queue.watchdog(taskTimeout);
177
- for (const { workDir, next } of recovered) {
178
- if (next) {
179
- startTask(workDir, next);
175
+ // Wall-clock watchdog: kills PTY sessions whose active task exceeded taskTimeout
176
+ // since startedAt. Complements the inactivity-based marker timeout in pty-runner —
177
+ // catches the case where Claude keeps emitting bytes (update checks, spinners)
178
+ // but never produces a Stop hook signal, so inactivity never accumulates.
179
+ async function runWatchdog () {
180
+ for (const [workDir, entry] of Object.entries(queue.queues)) {
181
+ if (!entry.active) {
182
+ continue;
183
+ }
184
+ const startedAt = entry.active.startedAt ? new Date(entry.active.startedAt).getTime() : 0;
185
+ if (startedAt <= 0 || (Date.now() - startedAt) <= taskTimeout) {
186
+ continue;
187
+ }
188
+ const task = entry.active;
189
+ const label = formatLabel(entry);
190
+ const elapsedMin = Math.round((Date.now() - startedAt) / 60000);
191
+ const timeoutMin = Math.round(taskTimeout / 60000);
192
+ logger.warn(`Watchdog: stale task "${task.id}" in ${workDir} (${elapsedMin}min) — killing PTY`);
193
+ if (runner.isRunning(workDir)) {
194
+ try {
195
+ runner.cancel(workDir);
196
+ } catch (err) {
197
+ logger.error(`Watchdog: cancel PTY failed in ${workDir}: ${err.message}`);
198
+ }
199
+ }
200
+ stopLiveConsole(workDir);
201
+ runner.cleanActivitySignal(workDir);
202
+ try {
203
+ if (task.runningMessageId) {
204
+ await poller.deleteMessage(task.runningMessageId);
205
+ }
206
+ const header = `⏰ <code>${label}</code>\nTask forcefully stopped — exceeded ${timeoutMin} min wall-clock limit`;
207
+ const sentId = await poller.sendMessage(header, task.telegramMessageId);
208
+ if (!sentId && task.telegramMessageId) {
209
+ await poller.sendMessage(`${header}: ${escapeHtml(task.text)}`);
210
+ }
211
+ } catch (err) {
212
+ logger.error(`Watchdog: notify failed: ${err.message}`);
213
+ }
214
+ const next = queue.onTaskComplete(workDir, 'STALE (watchdog cleanup)');
215
+ if (next) {
216
+ startTask(workDir, next);
217
+ }
180
218
  }
181
219
  }
182
220
 
221
+ // 1. Initial watchdog sweep on startup
222
+ runWatchdog();
223
+
183
224
  // 2. Re-start orphaned active tasks (PTY sessions lost on restart)
184
225
  for (const [workDir, entry] of Object.entries(queue.queues)) {
185
226
  if (entry.active && !runner.isRunning(workDir)) {
@@ -188,6 +229,9 @@ for (const [workDir, entry] of Object.entries(queue.queues)) {
188
229
  }
189
230
  }
190
231
 
232
+ // 3. Periodic watchdog — wall-clock check every minute
233
+ setInterval(runWatchdog, 60_000);
234
+
191
235
  // ----------------------
192
236
  // TASK RUNNER EVENTS
193
237
  // ----------------------
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.1.88",
4
+ "version": "1.1.89",
5
5
  "description": "Claude Code task-completion notifications: Telegram, desktop notifications (Windows/macOS/Linux), sound, and voice",
6
6
  "type": "module",
7
7
  "engines": {