fix(cli): v0.5.2 — poll-based push delivery (1s interval)
Some checks failed
Some checks failed
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:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "claudemesh-cli",
|
"name": "claudemesh-cli",
|
||||||
"version": "0.5.1",
|
"version": "0.5.2",
|
||||||
"description": "Claude Code MCP client for claudemesh — peer mesh messaging between Claude sessions.",
|
"description": "Claude Code MCP client for claudemesh — peer mesh messaging between Claude sessions.",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"claude-code",
|
"claude-code",
|
||||||
|
|||||||
@@ -722,54 +722,56 @@ Your message mode is "${messageMode}".
|
|||||||
// any mesh's broker connection becomes a <channel source="claudemesh">
|
// any mesh's broker connection becomes a <channel source="claudemesh">
|
||||||
// system reminder injected into Claude Code's context.
|
// system reminder injected into Claude Code's context.
|
||||||
for (const client of allClients()) {
|
for (const client of allClients()) {
|
||||||
client.onPush(async (msg) => {
|
// Poll-based push: drain pushBuffer every 1s and emit channel notifications.
|
||||||
// In "off" mode, silently skip notification — messages are still
|
// This is the proven approach from claude-intercom. The WS onPush handler
|
||||||
// buffered in pushBuffer and accessible via check_messages.
|
// fires instantly but server.notification() may not flush stdio reliably
|
||||||
if (messageMode === "off") return;
|
// 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 || "";
|
||||||
|
const fromName = fromPubkey
|
||||||
|
? await resolvePeerName(client, fromPubkey)
|
||||||
|
: "unknown";
|
||||||
|
|
||||||
const fromPubkey = msg.senderPubkey || "";
|
if (messageMode === "inbox") {
|
||||||
// Resolve sender's display name from the cached peer list.
|
try {
|
||||||
const fromName = fromPubkey
|
await server.notification({
|
||||||
? await resolvePeerName(client, fromPubkey)
|
method: "notifications/claude/channel",
|
||||||
: "unknown";
|
params: {
|
||||||
|
content: `[inbox] New message from ${fromName}. Use check_messages to read.`,
|
||||||
|
meta: { kind: "inbox_notification", from_name: fromName },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch { /* best effort */ }
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (messageMode === "inbox") {
|
// push mode — full content
|
||||||
// Count-only notification, no content
|
const content = msg.plaintext ?? decryptFailedWarning(fromPubkey);
|
||||||
try {
|
try {
|
||||||
await server.notification({
|
await server.notification({
|
||||||
method: "notifications/claude/channel",
|
method: "notifications/claude/channel",
|
||||||
params: {
|
params: {
|
||||||
content: `[inbox] New message from ${fromName}. Use check_messages to read.`,
|
content,
|
||||||
meta: { kind: "inbox_notification", from_name: fromName },
|
meta: {
|
||||||
},
|
from_id: fromPubkey,
|
||||||
});
|
from_name: fromName,
|
||||||
} catch { /* best effort */ }
|
mesh_slug: client.meshSlug,
|
||||||
return;
|
mesh_id: client.meshId,
|
||||||
}
|
priority: msg.priority,
|
||||||
|
sent_at: msg.createdAt,
|
||||||
// push mode — full content notification
|
delivered_at: msg.receivedAt,
|
||||||
const content = msg.plaintext ?? decryptFailedWarning(fromPubkey);
|
kind: msg.kind,
|
||||||
try {
|
},
|
||||||
await server.notification({
|
},
|
||||||
method: "notifications/claude/channel",
|
});
|
||||||
params: {
|
} catch { /* best effort */ }
|
||||||
content,
|
}
|
||||||
meta: {
|
}, 1_000);
|
||||||
from_id: fromPubkey,
|
pushPollTimer.unref();
|
||||||
from_name: fromName,
|
}
|
||||||
mesh_slug: client.meshSlug,
|
|
||||||
mesh_id: client.meshId,
|
|
||||||
priority: msg.priority,
|
|
||||||
sent_at: msg.createdAt,
|
|
||||||
delivered_at: msg.receivedAt,
|
|
||||||
kind: msg.kind,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} catch {
|
|
||||||
/* channel push is best-effort; check_messages is the fallback */
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
client.onStreamData(async (evt) => {
|
client.onStreamData(async (evt) => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
Reference in New Issue
Block a user