diff --git a/apps/cli/package.json b/apps/cli/package.json index 4e947c6..77a038e 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -1,6 +1,6 @@ { "name": "claudemesh-cli", - "version": "0.5.4", + "version": "0.5.5", "description": "Claude Code MCP client for claudemesh — peer mesh messaging between Claude sessions.", "keywords": [ "claude-code", diff --git a/apps/cli/src/mcp/server.ts b/apps/cli/src/mcp/server.ts index 8db5c38..74e7d62 100644 --- a/apps/cli/src/mcp/server.ts +++ b/apps/cli/src/mcp/server.ts @@ -707,6 +707,58 @@ Your message mode is "${messageMode}". return text(lines.join("\n")); } + case "ping_mesh": { + const { priorities: pingPriorities } = (args ?? {}) as { priorities?: string[] }; + const toTest = (pingPriorities ?? ["now", "next"]) as Priority[]; + const client = allClients()[0]; + if (!client) return text("ping_mesh: not connected", true); + const results: string[] = []; + + for (const prio of toTest) { + const sendTime = Date.now(); + const pingId = `ping-${sendTime}-${prio}`; + // Send to self (broadcast) — should bounce back through the broker + const sendResult = await client.send("*", `__ping__${pingId}`, prio); + const ackTime = Date.now(); + + if (!sendResult.ok) { + results.push(`[${prio}] SEND FAILED: ${sendResult.error}`); + continue; + } + + // Wait up to 10s for the ping to arrive in pushBuffer + let received = false; + let receiveTime = 0; + for (let i = 0; i < 100; i++) { + await new Promise(r => setTimeout(r, 100)); + const buffer = client.pushHistory; + const match = buffer.find(m => + m.plaintext?.includes(pingId) || false + ); + if (match) { + received = true; + receiveTime = Date.now(); + break; + } + } + + if (received) { + results.push( + `[${prio}] OK — send→ack: ${ackTime - sendTime}ms, send→receive: ${receiveTime - sendTime}ms` + ); + } else { + // Check peer status + const peers = await client.listPeers(); + const selfStatus = peers.find(p => p.displayName === myName)?.status ?? "unknown"; + results.push( + `[${prio}] NOT RECEIVED in 10s (your status: ${selfStatus}${selfStatus === "working" ? " — broker holds next/low" : ""})` + ); + } + } + + return text(`Ping results:\n${results.join("\n")}`); + } + default: return text(`Unknown tool: ${name}`, true); } diff --git a/apps/cli/src/mcp/tools.ts b/apps/cli/src/mcp/tools.ts index 77113ff..e78e8ed 100644 --- a/apps/cli/src/mcp/tools.ts +++ b/apps/cli/src/mcp/tools.ts @@ -555,4 +555,21 @@ export const TOOLS: Tool[] = [ "Get a complete overview of the mesh: peers, groups, state, memory, files, tasks, streams, tables. Call on session start for full situational awareness.", inputSchema: { type: "object", properties: {} }, }, + + // --- Diagnostics --- + { + name: "ping_mesh", + description: + "Send test messages through the full pipeline and measure round-trip timing per priority. Diagnoses push delivery issues.", + inputSchema: { + type: "object", + properties: { + priorities: { + type: "array", + items: { type: "string", enum: ["now", "next", "low"] }, + description: "Priorities to test (default: [\"now\", \"next\"])", + }, + }, + }, + }, ];