patchcord 0.5.62 → 0.5.64
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/package.json +1 -1
- package/scripts/subscribe.mjs +22 -1
- package/skills/subscribe/SKILL.md +4 -2
package/package.json
CHANGED
package/scripts/subscribe.mjs
CHANGED
|
@@ -221,6 +221,25 @@ async function run() {
|
|
|
221
221
|
process.exit(0);
|
|
222
222
|
});
|
|
223
223
|
|
|
224
|
+
// Exit when our stdout consumer (Monitor) dies. Node ignores SIGPIPE by
|
|
225
|
+
// default, so the EPIPE error surfaces on the stream instead. Without this
|
|
226
|
+
// the process orphans after the session ends and the pidfile guard blocks
|
|
227
|
+
// the next session from starting a fresh listener.
|
|
228
|
+
process.stdout.on("error", (err) => {
|
|
229
|
+
if (err.code === "EPIPE") {
|
|
230
|
+
cleanup();
|
|
231
|
+
process.exit(0);
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
// Keepalive: write a line every 30 s so EPIPE is detected promptly even
|
|
236
|
+
// when no messages arrive. The Monitor command pipes through
|
|
237
|
+
// `grep --line-buffered '^PATCHCORD:'` which drops these lines silently.
|
|
238
|
+
const _keepaliveTimer = setInterval(() => {
|
|
239
|
+
try { process.stdout.write("HEARTBEAT\n"); } catch (_) {}
|
|
240
|
+
}, 30_000);
|
|
241
|
+
process.on("exit", () => clearInterval(_keepaliveTimer));
|
|
242
|
+
|
|
224
243
|
logErr(`subscribe: agent=${ticket.agent_id} namespaces=${ticket.namespace_ids.join(",")}`);
|
|
225
244
|
|
|
226
245
|
let backoffIdx = 0;
|
|
@@ -432,8 +451,10 @@ function runOnce(ticket, baseUrl, token, refreshTicket) {
|
|
|
432
451
|
return;
|
|
433
452
|
}
|
|
434
453
|
// Successful subscribe ack — log once for confirmation, then quiet.
|
|
454
|
+
// Replace Supabase's "Subscribed to PostgreSQL" with a user-facing label.
|
|
435
455
|
if (status === "ok" && message) {
|
|
436
|
-
|
|
456
|
+
const displayMsg = message.replace(/PostgreSQL/g, "Patchcord");
|
|
457
|
+
logErr(`subscribe: system ok on ${frame.topic}: ${displayMsg}`);
|
|
437
458
|
}
|
|
438
459
|
return;
|
|
439
460
|
}
|
|
@@ -20,10 +20,12 @@ User invoked /patchcord:subscribe — do NOT substitute `wait_for_message()`. Sp
|
|
|
20
20
|
description: "patchcord realtime listener",
|
|
21
21
|
persistent: true,
|
|
22
22
|
timeout_ms: 3600000,
|
|
23
|
-
command: "
|
|
23
|
+
command: "patchcord subscribe | grep --line-buffered '^PATCHCORD:'; exit ${PIPESTATUS[0]}"
|
|
24
24
|
)
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
+
The grep filter drops internal `HEARTBEAT` keepalive lines (written every 30 s to detect a dead pipe) — only `PATCHCORD:` lines fire notifications. `${PIPESTATUS[0]}` preserves subscribe's exit code through the pipe.
|
|
28
|
+
|
|
27
29
|
`subscribe.mjs` handles its own pidfile guard — if another listener is already active for this agent it exits with code 2 and stderr `already running (pid N)`. Monitor catches the stream-end event; read the output file and report.
|
|
28
30
|
|
|
29
31
|
3. **Tell the user one line:** *"Patchcord listener active — I'll pick up new messages as they arrive."*
|
|
@@ -57,4 +59,4 @@ Report the cause in one sentence. STOP.
|
|
|
57
59
|
|
|
58
60
|
**Forbidden on failure:** no `pgrep`/`ps`/`kill`/`pkill`/`killall`, no pidfile writes, no respawning. The script manages pidfile cleanup itself; respawning will not fix a config problem.
|
|
59
61
|
|
|
60
|
-
|
|
62
|
+
No matching error pattern = the listener exited cleanly (session ended, user killed it, or EPIPE detected). Nothing to do.
|