Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9ae378c2e3 | ||
|
|
7381738f0b | ||
|
|
8c6b0c0e07 | ||
|
|
ec9626503c |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "claudemesh-cli",
|
||||
"version": "0.5.1",
|
||||
"version": "0.5.3",
|
||||
"description": "Claude Code MCP client for claudemesh — peer mesh messaging between Claude sessions.",
|
||||
"keywords": [
|
||||
"claude-code",
|
||||
|
||||
@@ -722,19 +722,23 @@ 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();
|
||||
if (buffered.length > 0) {
|
||||
process.stderr.write(`[claudemesh] poll: ${buffered.length} message(s) to push\n`);
|
||||
}
|
||||
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 +748,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 +770,14 @@ Your message mode is "${messageMode}".
|
||||
},
|
||||
},
|
||||
});
|
||||
} catch {
|
||||
/* channel push is best-effort; check_messages is the fallback */
|
||||
process.stderr.write(`[claudemesh] pushed: from=${fromName} content=${content.slice(0, 60)}\n`);
|
||||
} catch (pushErr) {
|
||||
process.stderr.write(`[claudemesh] push FAILED: ${pushErr}\n`);
|
||||
}
|
||||
}
|
||||
}, 1_000);
|
||||
pushPollTimer.unref();
|
||||
}
|
||||
});
|
||||
|
||||
client.onStreamData(async (evt) => {
|
||||
try {
|
||||
|
||||
@@ -25,6 +25,9 @@ ENV NEXT_PUBLIC_URL=$NEXT_PUBLIC_URL
|
||||
ENV NEXT_PUBLIC_PRODUCT_NAME=$NEXT_PUBLIC_PRODUCT_NAME
|
||||
ENV NEXT_PUBLIC_DEFAULT_LOCALE=$NEXT_PUBLIC_DEFAULT_LOCALE
|
||||
|
||||
# TURBOPACK=0 forces webpack for production build — Payload CMS's
|
||||
# richtext-lexical CSS imports fail under Turbopack.
|
||||
ENV TURBOPACK=0
|
||||
RUN npx turbo run build --filter=web...
|
||||
|
||||
# Stage 2: runtime — standalone output only
|
||||
|
||||
@@ -4,6 +4,8 @@ import { RootPage, generatePageMetadata } from "@payloadcms/next/views";
|
||||
import { importMap } from "../importMap";
|
||||
import config from "@payload-config";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
type Args = { params: Promise<{ segments: string[] }> };
|
||||
|
||||
export const generateMetadata = ({ params }: Args) =>
|
||||
|
||||
Reference in New Issue
Block a user