claudemesh-cli 0.7.0 → 0.7.1
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/dist/index.js +81 -12
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -47478,6 +47478,10 @@ var TOOLS = [
|
|
|
47478
47478
|
required: ["name", "description", "inputSchema"]
|
|
47479
47479
|
},
|
|
47480
47480
|
description: "Tool definitions to expose"
|
|
47481
|
+
},
|
|
47482
|
+
persistent: {
|
|
47483
|
+
type: "boolean",
|
|
47484
|
+
description: "If true, registration survives peer disconnect. Other peers see it as 'offline' until you reconnect. Default: false"
|
|
47481
47485
|
}
|
|
47482
47486
|
},
|
|
47483
47487
|
required: ["server_name", "description", "tools"]
|
|
@@ -47810,6 +47814,7 @@ class BrokerClient {
|
|
|
47810
47814
|
sessionId: `${process.pid}-${Date.now()}`,
|
|
47811
47815
|
pid: process.pid,
|
|
47812
47816
|
cwd: process.cwd(),
|
|
47817
|
+
hostname: __require("os").hostname(),
|
|
47813
47818
|
peerType: "ai",
|
|
47814
47819
|
channel: "claude-code",
|
|
47815
47820
|
model: process.env.CLAUDE_MODEL || undefined,
|
|
@@ -47841,6 +47846,18 @@ class BrokerClient {
|
|
|
47841
47846
|
this.reconnectAttempt = 0;
|
|
47842
47847
|
this.flushOutbound();
|
|
47843
47848
|
this.startStatsReporting();
|
|
47849
|
+
if (msg.restored) {
|
|
47850
|
+
const groups = msg.restoredGroups ? msg.restoredGroups.map((g) => g.role ? `@${g.name}:${g.role}` : `@${g.name}`).join(", ") : "none";
|
|
47851
|
+
process.stderr.write(`[claudemesh] session restored — last seen ${msg.lastSeenAt ?? "unknown"}, groups: ${groups}
|
|
47852
|
+
`);
|
|
47853
|
+
if (msg.restoredStats) {
|
|
47854
|
+
const rs = msg.restoredStats;
|
|
47855
|
+
this._statsCounters.messagesIn = rs.messagesIn ?? 0;
|
|
47856
|
+
this._statsCounters.messagesOut = rs.messagesOut ?? 0;
|
|
47857
|
+
this._statsCounters.toolCalls = rs.toolCalls ?? 0;
|
|
47858
|
+
this._statsCounters.errors = rs.errors ?? 0;
|
|
47859
|
+
}
|
|
47860
|
+
}
|
|
47844
47861
|
resolve();
|
|
47845
47862
|
return;
|
|
47846
47863
|
}
|
|
@@ -48427,7 +48444,7 @@ class BrokerClient {
|
|
|
48427
48444
|
this.stateChangeHandlers.add(handler);
|
|
48428
48445
|
return () => this.stateChangeHandlers.delete(handler);
|
|
48429
48446
|
}
|
|
48430
|
-
async mcpRegister(serverName, description, tools) {
|
|
48447
|
+
async mcpRegister(serverName, description, tools, persistent) {
|
|
48431
48448
|
if (!this.ws || this.ws.readyState !== this.ws.OPEN)
|
|
48432
48449
|
return null;
|
|
48433
48450
|
return new Promise((resolve) => {
|
|
@@ -48436,7 +48453,7 @@ class BrokerClient {
|
|
|
48436
48453
|
if (this.mcpRegisterResolvers.delete(reqId))
|
|
48437
48454
|
resolve(null);
|
|
48438
48455
|
}, 5000) });
|
|
48439
|
-
this.ws.send(JSON.stringify({ type: "mcp_register", serverName, description, tools, _reqId: reqId }));
|
|
48456
|
+
this.ws.send(JSON.stringify({ type: "mcp_register", serverName, description, tools, ...persistent ? { persistent: true } : {}, _reqId: reqId }));
|
|
48440
48457
|
});
|
|
48441
48458
|
}
|
|
48442
48459
|
async mcpUnregister(serverName) {
|
|
@@ -49312,6 +49329,25 @@ function stopAll() {
|
|
|
49312
49329
|
}
|
|
49313
49330
|
|
|
49314
49331
|
// src/mcp/server.ts
|
|
49332
|
+
function relativeTime(isoStr) {
|
|
49333
|
+
const then = new Date(isoStr).getTime();
|
|
49334
|
+
if (isNaN(then))
|
|
49335
|
+
return "unknown";
|
|
49336
|
+
const diffMs = Date.now() - then;
|
|
49337
|
+
if (diffMs < 0)
|
|
49338
|
+
return "just now";
|
|
49339
|
+
const seconds = Math.floor(diffMs / 1000);
|
|
49340
|
+
if (seconds < 60)
|
|
49341
|
+
return `${seconds}s ago`;
|
|
49342
|
+
const minutes = Math.floor(seconds / 60);
|
|
49343
|
+
if (minutes < 60)
|
|
49344
|
+
return `${minutes}m ago`;
|
|
49345
|
+
const hours = Math.floor(minutes / 60);
|
|
49346
|
+
if (hours < 24)
|
|
49347
|
+
return `${hours}h ago`;
|
|
49348
|
+
const days = Math.floor(hours / 24);
|
|
49349
|
+
return `${days} day${days !== 1 ? "s" : ""} ago`;
|
|
49350
|
+
}
|
|
49315
49351
|
function text(msg, isError = false) {
|
|
49316
49352
|
return {
|
|
49317
49353
|
content: [{ type: "text", text: msg }],
|
|
@@ -49484,9 +49520,14 @@ Shared key-value store scoped to the mesh. Use get_state/set_state for live coor
|
|
|
49484
49520
|
## Memory
|
|
49485
49521
|
Persistent knowledge that survives across sessions. Use remember(content, tags?) to store lessons, decisions, and incidents. Use recall(query) to search before asking peers. New peers should recall at session start to load institutional knowledge.
|
|
49486
49522
|
|
|
49487
|
-
##
|
|
49488
|
-
|
|
49489
|
-
|
|
49523
|
+
## File access — decision guide
|
|
49524
|
+
Three ways to access files. Pick the right one:
|
|
49525
|
+
|
|
49526
|
+
1. **Local peer (same machine, [local] tag):** Read files directly via filesystem using their \`cwd\` path from list_peers. No limit, instant. This is the default for local peers.
|
|
49527
|
+
2. **Remote peer (different machine, [remote] tag):** Use \`read_peer_file(peer, path)\` — relays through the mesh. **1 MB limit**, base64 encoded. Use \`list_peer_files\` to browse first.
|
|
49528
|
+
3. **Persistent sharing (any peer):** Use \`share_file(path)\` — uploads to mesh storage (MinIO). **No size limit**. All peers can download anytime via \`get_file\`. Use for files that need to persist or be shared with multiple peers.
|
|
49529
|
+
|
|
49530
|
+
**Rule of thumb:** local peer → filesystem. Remote peer, small file → read_peer_file. Large file or needs to persist → share_file.
|
|
49490
49531
|
|
|
49491
49532
|
## Vectors
|
|
49492
49533
|
Store and search semantic embeddings. Use vector_store to index content, vector_search to find similar content.
|
|
@@ -49583,10 +49624,12 @@ No peers connected.`);
|
|
|
49583
49624
|
meta2.push(`model:${p.model}`);
|
|
49584
49625
|
const metaStr = meta2.length ? ` {${meta2.join(", ")}}` : "";
|
|
49585
49626
|
const cwdStr = p.cwd ? ` cwd:${p.cwd}` : "";
|
|
49627
|
+
const locality = p.hostname && p.hostname === __require("os").hostname() ? "local" : "remote";
|
|
49628
|
+
const localityTag = ` [${locality}]`;
|
|
49586
49629
|
const profileAvatar = p.profile?.avatar ? `${p.profile.avatar} ` : "";
|
|
49587
49630
|
const profileTitle = p.profile?.title ? ` (${p.profile.title})` : "";
|
|
49588
49631
|
const hiddenTag = p.visible === false ? " [hidden]" : "";
|
|
49589
|
-
return `- ${profileAvatar}**${p.displayName}**${profileTitle} [${p.status}]${hiddenTag}${groupsStr}${metaStr} (${p.pubkey.slice(0, 12)}…)${cwdStr}${summary}`;
|
|
49632
|
+
return `- ${profileAvatar}**${p.displayName}**${profileTitle} [${p.status}]${localityTag}${hiddenTag}${groupsStr}${metaStr} (${p.pubkey.slice(0, 12)}…)${cwdStr}${summary}`;
|
|
49590
49633
|
});
|
|
49591
49634
|
sections.push(`${header}
|
|
49592
49635
|
${peerLines.join(`
|
|
@@ -50423,16 +50466,17 @@ ${lines.join(`
|
|
|
50423
50466
|
`));
|
|
50424
50467
|
}
|
|
50425
50468
|
case "mesh_mcp_register": {
|
|
50426
|
-
const { server_name, description, tools: regTools } = args ?? {};
|
|
50469
|
+
const { server_name, description, tools: regTools, persistent: regPersistent } = args ?? {};
|
|
50427
50470
|
if (!server_name || !description || !regTools?.length)
|
|
50428
50471
|
return text("mesh_mcp_register: `server_name`, `description`, and `tools` required", true);
|
|
50429
50472
|
const client2 = allClients()[0];
|
|
50430
50473
|
if (!client2)
|
|
50431
50474
|
return text("mesh_mcp_register: not connected", true);
|
|
50432
|
-
const result = await client2.mcpRegister(server_name, description, regTools);
|
|
50475
|
+
const result = await client2.mcpRegister(server_name, description, regTools, regPersistent);
|
|
50433
50476
|
if (!result)
|
|
50434
50477
|
return text("mesh_mcp_register: broker did not acknowledge", true);
|
|
50435
|
-
|
|
50478
|
+
const persistLabel = regPersistent ? " (persistent — survives disconnect)" : "";
|
|
50479
|
+
return text(`Registered MCP server "${result.serverName}" with ${result.toolCount} tool(s)${persistLabel}. Other peers can now call its tools via mesh_tool_call.`);
|
|
50436
50480
|
}
|
|
50437
50481
|
case "mesh_mcp_list": {
|
|
50438
50482
|
const client2 = allClients()[0];
|
|
@@ -50444,7 +50488,8 @@ ${lines.join(`
|
|
|
50444
50488
|
const lines = servers.map((s) => {
|
|
50445
50489
|
const toolList = s.tools.map((t) => ` - **${t.name}**: ${t.description}`).join(`
|
|
50446
50490
|
`);
|
|
50447
|
-
|
|
50491
|
+
const status = s.online === false ? ` [OFFLINE${s.offlineSince ? ` since ${s.offlineSince}` : ""}]` : "";
|
|
50492
|
+
return `- **${s.name}** (hosted by ${s.hostedBy})${status}: ${s.description}
|
|
50448
50493
|
${toolList}`;
|
|
50449
50494
|
});
|
|
50450
50495
|
return text(`${servers.length} MCP server(s) in mesh:
|
|
@@ -50531,6 +50576,17 @@ ${lines.join(`
|
|
|
50531
50576
|
targetPubkey = match.pubkey;
|
|
50532
50577
|
}
|
|
50533
50578
|
}
|
|
50579
|
+
const resolvedPeer = peers.find((p) => p.pubkey === targetPubkey);
|
|
50580
|
+
const isLocal = resolvedPeer?.hostname && resolvedPeer.hostname === __require("os").hostname();
|
|
50581
|
+
let localHint = "";
|
|
50582
|
+
if (isLocal && resolvedPeer?.cwd) {
|
|
50583
|
+
const directPath = __require("path").resolve(resolvedPeer.cwd, filePath);
|
|
50584
|
+
localHint = `
|
|
50585
|
+
|
|
50586
|
+
> **Hint:** This peer is LOCAL (same machine). Next time, read directly: \`${directPath}\` — faster, no size limit.
|
|
50587
|
+
|
|
50588
|
+
`;
|
|
50589
|
+
}
|
|
50534
50590
|
const result = await client2.requestFile(targetPubkey, filePath);
|
|
50535
50591
|
if (result.error)
|
|
50536
50592
|
return text(`read_peer_file: ${result.error}`, true);
|
|
@@ -50538,7 +50594,7 @@ ${lines.join(`
|
|
|
50538
50594
|
return text("read_peer_file: empty response from peer", true);
|
|
50539
50595
|
try {
|
|
50540
50596
|
const decoded = Buffer.from(result.content, "base64").toString("utf-8");
|
|
50541
|
-
return text(decoded);
|
|
50597
|
+
return text(localHint + decoded);
|
|
50542
50598
|
} catch {
|
|
50543
50599
|
return text("read_peer_file: failed to decode file content (binary file?)", true);
|
|
50544
50600
|
}
|
|
@@ -50638,8 +50694,21 @@ ${lines.join(`
|
|
|
50638
50694
|
content2 = `[heartbeat] tick ${tick} | sim time: ${simTime} | speed: x${speed}`;
|
|
50639
50695
|
} else if (eventName === "peer_joined") {
|
|
50640
50696
|
content2 = `[system] Peer "${data.name ?? "unknown"}" joined the mesh`;
|
|
50697
|
+
} else if (eventName === "peer_returned") {
|
|
50698
|
+
const peerName = String(data.name ?? "unknown");
|
|
50699
|
+
const lastSeenAt = data.lastSeenAt ? relativeTime(String(data.lastSeenAt)) : "unknown";
|
|
50700
|
+
const groups = Array.isArray(data.groups) ? data.groups.map((g) => g.role ? `@${g.name}:${g.role}` : `@${g.name}`).join(", ") : "";
|
|
50701
|
+
const summary = data.summary ? ` Summary: "${data.summary}"` : "";
|
|
50702
|
+
content2 = `[system] Welcome back, "${peerName}"! Last seen ${lastSeenAt}.${groups ? ` Restored: ${groups}` : ""}${summary}`;
|
|
50641
50703
|
} else if (eventName === "peer_left") {
|
|
50642
50704
|
content2 = `[system] Peer "${data.name ?? "unknown"}" left the mesh`;
|
|
50705
|
+
} else if (eventName === "mcp_registered") {
|
|
50706
|
+
const tools = Array.isArray(data.tools) ? data.tools.join(", ") : "";
|
|
50707
|
+
content2 = `[system] New MCP server available: "${data.serverName}" (hosted by ${data.hostedBy}). Tools: ${tools}. Use mesh_tool_call to invoke.`;
|
|
50708
|
+
} else if (eventName === "mcp_unregistered") {
|
|
50709
|
+
content2 = `[system] MCP server "${data.serverName}" removed (was hosted by ${data.hostedBy})`;
|
|
50710
|
+
} else if (eventName === "mcp_restored") {
|
|
50711
|
+
content2 = `[system] MCP server "${data.serverName}" is back online (hosted by ${data.hostedBy})`;
|
|
50643
50712
|
} else {
|
|
50644
50713
|
content2 = `[system] ${eventName}: ${JSON.stringify(data)}`;
|
|
50645
50714
|
}
|
|
@@ -51739,7 +51808,7 @@ init_config();
|
|
|
51739
51808
|
// package.json
|
|
51740
51809
|
var package_default = {
|
|
51741
51810
|
name: "claudemesh-cli",
|
|
51742
|
-
version: "0.7.
|
|
51811
|
+
version: "0.7.1",
|
|
51743
51812
|
description: "Claude Code MCP client for claudemesh — peer mesh messaging between Claude sessions.",
|
|
51744
51813
|
keywords: [
|
|
51745
51814
|
"claude-code",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claudemesh-cli",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "Claude Code MCP client for claudemesh — peer mesh messaging between Claude sessions.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude-code",
|
|
@@ -48,10 +48,10 @@
|
|
|
48
48
|
"prettier": "3.6.2",
|
|
49
49
|
"typescript": "5.9.3",
|
|
50
50
|
"vitest": "4.0.14",
|
|
51
|
+
"@turbostarter/eslint-config": "0.1.0",
|
|
51
52
|
"@turbostarter/tsconfig": "0.1.0",
|
|
52
53
|
"@turbostarter/prettier-config": "0.1.0",
|
|
53
|
-
"@turbostarter/vitest-config": "0.1.0"
|
|
54
|
-
"@turbostarter/eslint-config": "0.1.0"
|
|
54
|
+
"@turbostarter/vitest-config": "0.1.0"
|
|
55
55
|
},
|
|
56
56
|
"scripts": {
|
|
57
57
|
"build": "bun build src/index.ts --target=node --outfile dist/index.js --banner \"#!/usr/bin/env node\" && chmod +x dist/index.js",
|