fix(cli): v0.5.2 — poll-based push delivery (1s interval)
Some checks failed
CI / Lint (push) Has been cancelled
CI / Typecheck (push) Has been cancelled
CI / Broker tests (Postgres) (push) Has been cancelled
CI / Docker build (linux/amd64) (push) Has been cancelled
Release / Publish multi-arch images (push) Has been cancelled

Replace WS onPush→notification with timer-based buffer drain.
The old claude-intercom used 1s polling and worked reliably.
WS async callbacks may not flush stdio properly for MCP
notifications. Polling on a timer ensures consistent delivery.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Alejandro Gutiérrez
2026-04-06 16:33:26 +01:00
parent ec9626503c
commit 8c6b0c0e07
2 changed files with 49 additions and 47 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "claudemesh-cli",
"version": "0.5.1",
"version": "0.5.2",
"description": "Claude Code MCP client for claudemesh — peer mesh messaging between Claude sessions.",
"keywords": [
"claude-code",

View File

@@ -722,19 +722,20 @@ Your message mode is "${messageMode}".
// any mesh's broker connection becomes a <channel source="claudemesh">
// system reminder injected into Claude Code's context.
for (const client of allClients()) {
client.onPush(async (msg) => {
// In "off" mode, silently skip notification — messages are still
// buffered in pushBuffer and accessible via check_messages.
if (messageMode === "off") return;
// Poll-based push: drain pushBuffer every 1s and emit channel notifications.
// This is the proven approach from claude-intercom. The WS onPush handler
// fires instantly but server.notification() may not flush stdio reliably
// from an async WS callback. Polling on a timer ensures consistent delivery.
if (messageMode !== "off") {
const pushPollTimer = setInterval(async () => {
const buffered = client.drainPushBuffer();
for (const msg of buffered) {
const fromPubkey = msg.senderPubkey || "";
// Resolve sender's display name from the cached peer list.
const fromName = fromPubkey
? await resolvePeerName(client, fromPubkey)
: "unknown";
if (messageMode === "inbox") {
// Count-only notification, no content
try {
await server.notification({
method: "notifications/claude/channel",
@@ -744,10 +745,10 @@ Your message mode is "${messageMode}".
},
});
} catch { /* best effort */ }
return;
continue;
}
// push mode — full content notification
// push mode — full content
const content = msg.plaintext ?? decryptFailedWarning(fromPubkey);
try {
await server.notification({
@@ -766,10 +767,11 @@ Your message mode is "${messageMode}".
},
},
});
} catch {
/* channel push is best-effort; check_messages is the fallback */
} catch { /* best effort */ }
}
}, 1_000);
pushPollTimer.unref();
}
});
client.onStreamData(async (evt) => {
try {