claudemesh-cli 0.1.3 → 0.1.5
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 +186 -43
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -54990,6 +54990,7 @@ class BrokerClient {
|
|
|
54990
54990
|
outbound = [];
|
|
54991
54991
|
pushHandlers = new Set;
|
|
54992
54992
|
pushBuffer = [];
|
|
54993
|
+
listPeersResolvers = [];
|
|
54993
54994
|
closed = false;
|
|
54994
54995
|
reconnectAttempt = 0;
|
|
54995
54996
|
helloTimer = null;
|
|
@@ -55013,7 +55014,7 @@ class BrokerClient {
|
|
|
55013
55014
|
async connect() {
|
|
55014
55015
|
if (this.closed)
|
|
55015
55016
|
throw new Error("client is closed");
|
|
55016
|
-
this.
|
|
55017
|
+
this.setConnStatus("connecting");
|
|
55017
55018
|
const ws = new wrapper_default(this.mesh.brokerUrl);
|
|
55018
55019
|
this.ws = ws;
|
|
55019
55020
|
return new Promise((resolve, reject) => {
|
|
@@ -55053,7 +55054,7 @@ class BrokerClient {
|
|
|
55053
55054
|
if (this.helloTimer)
|
|
55054
55055
|
clearTimeout(this.helloTimer);
|
|
55055
55056
|
this.helloTimer = null;
|
|
55056
|
-
this.
|
|
55057
|
+
this.setConnStatus("open");
|
|
55057
55058
|
this.reconnectAttempt = 0;
|
|
55058
55059
|
this.flushOutbound();
|
|
55059
55060
|
resolve();
|
|
@@ -55072,7 +55073,7 @@ class BrokerClient {
|
|
|
55072
55073
|
if (!this.closed)
|
|
55073
55074
|
this.scheduleReconnect();
|
|
55074
55075
|
else
|
|
55075
|
-
this.
|
|
55076
|
+
this.setConnStatus("closed");
|
|
55076
55077
|
};
|
|
55077
55078
|
const onError = (err) => {
|
|
55078
55079
|
this.debug(`ws error: ${err.message}`);
|
|
@@ -55152,6 +55153,26 @@ class BrokerClient {
|
|
|
55152
55153
|
return;
|
|
55153
55154
|
this.ws.send(JSON.stringify({ type: "set_status", status }));
|
|
55154
55155
|
}
|
|
55156
|
+
async listPeers() {
|
|
55157
|
+
if (!this.ws || this.ws.readyState !== this.ws.OPEN)
|
|
55158
|
+
return [];
|
|
55159
|
+
return new Promise((resolve) => {
|
|
55160
|
+
this.listPeersResolvers.push(resolve);
|
|
55161
|
+
this.ws.send(JSON.stringify({ type: "list_peers" }));
|
|
55162
|
+
setTimeout(() => {
|
|
55163
|
+
const idx = this.listPeersResolvers.indexOf(resolve);
|
|
55164
|
+
if (idx !== -1) {
|
|
55165
|
+
this.listPeersResolvers.splice(idx, 1);
|
|
55166
|
+
resolve([]);
|
|
55167
|
+
}
|
|
55168
|
+
}, 5000);
|
|
55169
|
+
});
|
|
55170
|
+
}
|
|
55171
|
+
async setSummary(summary) {
|
|
55172
|
+
if (!this.ws || this.ws.readyState !== this.ws.OPEN)
|
|
55173
|
+
return;
|
|
55174
|
+
this.ws.send(JSON.stringify({ type: "set_summary", summary }));
|
|
55175
|
+
}
|
|
55155
55176
|
close() {
|
|
55156
55177
|
this.closed = true;
|
|
55157
55178
|
if (this.helloTimer)
|
|
@@ -55163,7 +55184,7 @@ class BrokerClient {
|
|
|
55163
55184
|
this.ws.close();
|
|
55164
55185
|
} catch {}
|
|
55165
55186
|
}
|
|
55166
|
-
this.
|
|
55187
|
+
this.setConnStatus("closed");
|
|
55167
55188
|
}
|
|
55168
55189
|
handleServerMessage(msg) {
|
|
55169
55190
|
if (msg.type === "ack") {
|
|
@@ -55177,6 +55198,13 @@ class BrokerClient {
|
|
|
55177
55198
|
}
|
|
55178
55199
|
return;
|
|
55179
55200
|
}
|
|
55201
|
+
if (msg.type === "peers_list") {
|
|
55202
|
+
const peers = msg.peers ?? [];
|
|
55203
|
+
const resolver = this.listPeersResolvers.shift();
|
|
55204
|
+
if (resolver)
|
|
55205
|
+
resolver(peers);
|
|
55206
|
+
return;
|
|
55207
|
+
}
|
|
55180
55208
|
if (msg.type === "push") {
|
|
55181
55209
|
const nonce = String(msg.nonce ?? "");
|
|
55182
55210
|
const ciphertext = String(msg.ciphertext ?? "");
|
|
@@ -55239,7 +55267,7 @@ class BrokerClient {
|
|
|
55239
55267
|
send();
|
|
55240
55268
|
}
|
|
55241
55269
|
scheduleReconnect() {
|
|
55242
|
-
this.
|
|
55270
|
+
this.setConnStatus("reconnecting");
|
|
55243
55271
|
const delay = BACKOFF_CAPS[Math.min(this.reconnectAttempt, BACKOFF_CAPS.length - 1)];
|
|
55244
55272
|
this.reconnectAttempt += 1;
|
|
55245
55273
|
this.debug(`reconnect in ${delay}ms (attempt ${this.reconnectAttempt})`);
|
|
@@ -55251,7 +55279,7 @@ class BrokerClient {
|
|
|
55251
55279
|
});
|
|
55252
55280
|
}, delay);
|
|
55253
55281
|
}
|
|
55254
|
-
|
|
55282
|
+
setConnStatus(s) {
|
|
55255
55283
|
if (this._status === s)
|
|
55256
55284
|
return;
|
|
55257
55285
|
this._status = s;
|
|
@@ -55344,7 +55372,7 @@ ${body}`;
|
|
|
55344
55372
|
}
|
|
55345
55373
|
async function startMcpServer() {
|
|
55346
55374
|
const config2 = loadConfig();
|
|
55347
|
-
const server = new Server({ name: "claudemesh", version: "0.1.
|
|
55375
|
+
const server = new Server({ name: "claudemesh", version: "0.1.4" }, {
|
|
55348
55376
|
capabilities: {
|
|
55349
55377
|
experimental: { "claude/channel": {} },
|
|
55350
55378
|
tools: {}
|
|
@@ -55395,12 +55423,26 @@ If you have multiple joined meshes, prefix the \`to\` argument of send_message w
|
|
|
55395
55423
|
const clients2 = mesh_slug ? [findClient(mesh_slug)].filter(Boolean) : allClients();
|
|
55396
55424
|
if (clients2.length === 0)
|
|
55397
55425
|
return text(mesh_slug ? `list_peers: no joined mesh "${mesh_slug}"` : "list_peers: no joined meshes", true);
|
|
55398
|
-
const
|
|
55399
|
-
|
|
55400
|
-
|
|
55401
|
-
|
|
55426
|
+
const sections = [];
|
|
55427
|
+
for (const c of clients2) {
|
|
55428
|
+
const peers = await c.listPeers();
|
|
55429
|
+
const header = `## ${c.meshSlug} (${c.status}, mesh ${c.meshId.slice(0, 8)}…)`;
|
|
55430
|
+
if (peers.length === 0) {
|
|
55431
|
+
sections.push(`${header}
|
|
55432
|
+
No peers connected.`);
|
|
55433
|
+
} else {
|
|
55434
|
+
const peerLines = peers.map((p) => {
|
|
55435
|
+
const summary = p.summary ? ` — "${p.summary}"` : "";
|
|
55436
|
+
return `- **${p.displayName}** [${p.status}] (${p.pubkey.slice(0, 12)}…)${summary}`;
|
|
55437
|
+
});
|
|
55438
|
+
sections.push(`${header}
|
|
55439
|
+
${peerLines.join(`
|
|
55440
|
+
`)}`);
|
|
55441
|
+
}
|
|
55442
|
+
}
|
|
55443
|
+
return text(sections.join(`
|
|
55402
55444
|
|
|
55403
|
-
|
|
55445
|
+
`));
|
|
55404
55446
|
}
|
|
55405
55447
|
case "check_messages": {
|
|
55406
55448
|
const drained = [];
|
|
@@ -55423,7 +55465,9 @@ ${drained.join(`
|
|
|
55423
55465
|
const { summary } = args ?? {};
|
|
55424
55466
|
if (!summary)
|
|
55425
55467
|
return text("set_summary: `summary` required", true);
|
|
55426
|
-
|
|
55468
|
+
for (const c of allClients())
|
|
55469
|
+
await c.setSummary(summary);
|
|
55470
|
+
return text(`Summary set: "${summary}" (visible to ${allClients().length} mesh(es)).`);
|
|
55427
55471
|
}
|
|
55428
55472
|
case "set_status": {
|
|
55429
55473
|
const { status } = args ?? {};
|
|
@@ -55477,6 +55521,7 @@ ${drained.join(`
|
|
|
55477
55521
|
// src/commands/install.ts
|
|
55478
55522
|
import {
|
|
55479
55523
|
chmodSync as chmodSync2,
|
|
55524
|
+
copyFileSync,
|
|
55480
55525
|
existsSync as existsSync2,
|
|
55481
55526
|
mkdirSync as mkdirSync2,
|
|
55482
55527
|
readFileSync as readFileSync2,
|
|
@@ -55504,7 +55549,49 @@ function readClaudeConfig() {
|
|
|
55504
55549
|
throw new Error(`failed to parse ${CLAUDE_CONFIG}: ${e instanceof Error ? e.message : String(e)}`);
|
|
55505
55550
|
}
|
|
55506
55551
|
}
|
|
55507
|
-
function
|
|
55552
|
+
function backupClaudeConfig() {
|
|
55553
|
+
if (!existsSync2(CLAUDE_CONFIG))
|
|
55554
|
+
return;
|
|
55555
|
+
const backupDir = join2(dirname2(CLAUDE_CONFIG), ".claude", "backups");
|
|
55556
|
+
mkdirSync2(backupDir, { recursive: true });
|
|
55557
|
+
const ts = Date.now();
|
|
55558
|
+
const dest = join2(backupDir, `.claude.json.pre-claudemesh.${ts}`);
|
|
55559
|
+
copyFileSync(CLAUDE_CONFIG, dest);
|
|
55560
|
+
}
|
|
55561
|
+
function patchMcpServer(entry) {
|
|
55562
|
+
backupClaudeConfig();
|
|
55563
|
+
const cfg = readClaudeConfig();
|
|
55564
|
+
const servers = cfg.mcpServers ?? {};
|
|
55565
|
+
if (!cfg.mcpServers)
|
|
55566
|
+
cfg.mcpServers = servers;
|
|
55567
|
+
const existing = servers[MCP_NAME];
|
|
55568
|
+
let action;
|
|
55569
|
+
if (!existing) {
|
|
55570
|
+
servers[MCP_NAME] = entry;
|
|
55571
|
+
action = "added";
|
|
55572
|
+
} else if (entriesEqual(existing, entry)) {
|
|
55573
|
+
return "unchanged";
|
|
55574
|
+
} else {
|
|
55575
|
+
servers[MCP_NAME] = entry;
|
|
55576
|
+
action = "updated";
|
|
55577
|
+
}
|
|
55578
|
+
flushClaudeConfig(cfg);
|
|
55579
|
+
return action;
|
|
55580
|
+
}
|
|
55581
|
+
function removeMcpServer() {
|
|
55582
|
+
if (!existsSync2(CLAUDE_CONFIG))
|
|
55583
|
+
return false;
|
|
55584
|
+
backupClaudeConfig();
|
|
55585
|
+
const cfg = readClaudeConfig();
|
|
55586
|
+
const servers = cfg.mcpServers;
|
|
55587
|
+
if (!servers || !(MCP_NAME in servers))
|
|
55588
|
+
return false;
|
|
55589
|
+
delete servers[MCP_NAME];
|
|
55590
|
+
cfg.mcpServers = servers;
|
|
55591
|
+
flushClaudeConfig(cfg);
|
|
55592
|
+
return true;
|
|
55593
|
+
}
|
|
55594
|
+
function flushClaudeConfig(obj) {
|
|
55508
55595
|
mkdirSync2(dirname2(CLAUDE_CONFIG), { recursive: true });
|
|
55509
55596
|
writeFileSync2(CLAUDE_CONFIG, JSON.stringify(obj, null, 2) + `
|
|
55510
55597
|
`, "utf-8");
|
|
@@ -55616,22 +55703,8 @@ function runInstall(args = []) {
|
|
|
55616
55703
|
console.error(`✗ MCP entry not found at ${entry}`);
|
|
55617
55704
|
process.exit(1);
|
|
55618
55705
|
}
|
|
55619
|
-
const cfg = readClaudeConfig();
|
|
55620
|
-
const servers = (cfg.mcpServers ??= {}) ?? {};
|
|
55621
55706
|
const desired = buildMcpEntry(entry);
|
|
55622
|
-
const
|
|
55623
|
-
let action;
|
|
55624
|
-
if (!existing) {
|
|
55625
|
-
servers[MCP_NAME] = desired;
|
|
55626
|
-
action = "added";
|
|
55627
|
-
} else if (entriesEqual(existing, desired)) {
|
|
55628
|
-
action = "unchanged";
|
|
55629
|
-
} else {
|
|
55630
|
-
servers[MCP_NAME] = desired;
|
|
55631
|
-
action = "updated";
|
|
55632
|
-
}
|
|
55633
|
-
cfg.mcpServers = servers;
|
|
55634
|
-
writeClaudeConfig(cfg);
|
|
55707
|
+
const action = patchMcpServer(desired);
|
|
55635
55708
|
const verify = readClaudeConfig();
|
|
55636
55709
|
const verifyServers = verify.mcpServers ?? {};
|
|
55637
55710
|
const stored = verifyServers[MCP_NAME];
|
|
@@ -55674,19 +55747,10 @@ function runInstall(args = []) {
|
|
|
55674
55747
|
function runUninstall() {
|
|
55675
55748
|
console.log("claudemesh uninstall");
|
|
55676
55749
|
console.log("--------------------");
|
|
55677
|
-
if (
|
|
55678
|
-
|
|
55679
|
-
const servers = cfg.mcpServers;
|
|
55680
|
-
if (servers && MCP_NAME in servers) {
|
|
55681
|
-
delete servers[MCP_NAME];
|
|
55682
|
-
cfg.mcpServers = servers;
|
|
55683
|
-
writeClaudeConfig(cfg);
|
|
55684
|
-
console.log(`✓ MCP server "${MCP_NAME}" removed`);
|
|
55685
|
-
} else {
|
|
55686
|
-
console.log(`· MCP server "${MCP_NAME}" not present`);
|
|
55687
|
-
}
|
|
55750
|
+
if (removeMcpServer()) {
|
|
55751
|
+
console.log(`✓ MCP server "${MCP_NAME}" removed`);
|
|
55688
55752
|
} else {
|
|
55689
|
-
console.log(`·
|
|
55753
|
+
console.log(`· MCP server "${MCP_NAME}" not present`);
|
|
55690
55754
|
}
|
|
55691
55755
|
try {
|
|
55692
55756
|
const removed = uninstallHooks();
|
|
@@ -56086,7 +56150,7 @@ import { statSync, existsSync as existsSync3 } from "node:fs";
|
|
|
56086
56150
|
// package.json
|
|
56087
56151
|
var package_default = {
|
|
56088
56152
|
name: "claudemesh-cli",
|
|
56089
|
-
version: "0.1.
|
|
56153
|
+
version: "0.1.5",
|
|
56090
56154
|
description: "Claude Code MCP client for claudemesh — peer mesh messaging between Claude sessions.",
|
|
56091
56155
|
keywords: [
|
|
56092
56156
|
"claude-code",
|
|
@@ -56414,6 +56478,83 @@ async function runDoctor() {
|
|
|
56414
56478
|
}
|
|
56415
56479
|
}
|
|
56416
56480
|
|
|
56481
|
+
// src/commands/welcome.ts
|
|
56482
|
+
import { existsSync as existsSync5, readFileSync as readFileSync4 } from "node:fs";
|
|
56483
|
+
import { homedir as homedir4 } from "node:os";
|
|
56484
|
+
import { join as join4 } from "node:path";
|
|
56485
|
+
function detectState() {
|
|
56486
|
+
const claudeConfig = join4(homedir4(), ".claude.json");
|
|
56487
|
+
let mcpRegistered = false;
|
|
56488
|
+
if (existsSync5(claudeConfig)) {
|
|
56489
|
+
try {
|
|
56490
|
+
const cfg = JSON.parse(readFileSync4(claudeConfig, "utf-8"));
|
|
56491
|
+
mcpRegistered = Boolean(cfg.mcpServers?.["claudemesh"]);
|
|
56492
|
+
} catch {}
|
|
56493
|
+
}
|
|
56494
|
+
if (!mcpRegistered)
|
|
56495
|
+
return "no-install";
|
|
56496
|
+
try {
|
|
56497
|
+
const cfg = loadConfig();
|
|
56498
|
+
return cfg.meshes.length === 0 ? "no-meshes" : "ready";
|
|
56499
|
+
} catch {
|
|
56500
|
+
return "broken-config";
|
|
56501
|
+
}
|
|
56502
|
+
}
|
|
56503
|
+
function runWelcome() {
|
|
56504
|
+
const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
|
|
56505
|
+
const bold = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
|
|
56506
|
+
const dim = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
|
|
56507
|
+
const green = (s) => useColor ? `\x1B[32m${s}\x1B[39m` : s;
|
|
56508
|
+
const yellow = (s) => useColor ? `\x1B[33m${s}\x1B[39m` : s;
|
|
56509
|
+
console.log(bold(`claudemesh v${VERSION}`) + dim(" — peer mesh for Claude Code"));
|
|
56510
|
+
console.log("─".repeat(60));
|
|
56511
|
+
const state = detectState();
|
|
56512
|
+
switch (state) {
|
|
56513
|
+
case "no-install":
|
|
56514
|
+
console.log("Welcome. Let's get you set up.");
|
|
56515
|
+
console.log("");
|
|
56516
|
+
console.log(bold("Step 1:") + " register the MCP server + status hooks");
|
|
56517
|
+
console.log(` ${green("$")} claudemesh install`);
|
|
56518
|
+
console.log("");
|
|
56519
|
+
console.log(dim("Step 2 (after restart): claudemesh join <invite-url>"));
|
|
56520
|
+
console.log(dim("Step 3: claudemesh launch"));
|
|
56521
|
+
break;
|
|
56522
|
+
case "no-meshes":
|
|
56523
|
+
console.log(green("✓") + " MCP registered. Now join a mesh.");
|
|
56524
|
+
console.log("");
|
|
56525
|
+
console.log(bold("Step 2:") + " join a mesh");
|
|
56526
|
+
console.log(` ${green("$")} claudemesh join https://claudemesh.com/join/<token>`);
|
|
56527
|
+
console.log("");
|
|
56528
|
+
console.log(dim(" Don't have an invite? Create one at ") + bold("https://claudemesh.com") + dim(" or ask a mesh owner."));
|
|
56529
|
+
console.log("");
|
|
56530
|
+
console.log(dim("Step 3 (after joining): claudemesh launch"));
|
|
56531
|
+
break;
|
|
56532
|
+
case "ready": {
|
|
56533
|
+
const cfg = loadConfig();
|
|
56534
|
+
const meshNames = cfg.meshes.map((m) => m.slug).join(", ");
|
|
56535
|
+
console.log(green("✓") + " MCP registered.");
|
|
56536
|
+
console.log(green("✓") + ` ${cfg.meshes.length} mesh(es) joined: ${meshNames}`);
|
|
56537
|
+
console.log("");
|
|
56538
|
+
console.log(bold("You're ready.") + " Launch Claude Code with real-time peer messages:");
|
|
56539
|
+
console.log(` ${green("$")} claudemesh launch`);
|
|
56540
|
+
console.log("");
|
|
56541
|
+
console.log(dim(" (Plain `claude` works too — messages pull-only via check_messages.)"));
|
|
56542
|
+
console.log("");
|
|
56543
|
+
console.log(dim("Health check: claudemesh status"));
|
|
56544
|
+
console.log(dim("Diagnostics: claudemesh doctor"));
|
|
56545
|
+
console.log(dim("All commands: claudemesh --help"));
|
|
56546
|
+
break;
|
|
56547
|
+
}
|
|
56548
|
+
case "broken-config":
|
|
56549
|
+
console.log(yellow("⚠") + " Your ~/.claudemesh/config.json is unreadable.");
|
|
56550
|
+
console.log("");
|
|
56551
|
+
console.log("Run diagnostics to see what's wrong:");
|
|
56552
|
+
console.log(` ${green("$")} claudemesh doctor`);
|
|
56553
|
+
break;
|
|
56554
|
+
}
|
|
56555
|
+
console.log("");
|
|
56556
|
+
}
|
|
56557
|
+
|
|
56417
56558
|
// src/index.ts
|
|
56418
56559
|
var HELP = `claudemesh v${VERSION} — peer mesh for Claude Code sessions
|
|
56419
56560
|
|
|
@@ -56487,9 +56628,11 @@ async function main() {
|
|
|
56487
56628
|
case "--help":
|
|
56488
56629
|
case "-h":
|
|
56489
56630
|
case "help":
|
|
56490
|
-
case undefined:
|
|
56491
56631
|
console.log(HELP);
|
|
56492
56632
|
return;
|
|
56633
|
+
case undefined:
|
|
56634
|
+
runWelcome();
|
|
56635
|
+
return;
|
|
56493
56636
|
default:
|
|
56494
56637
|
console.error(`Unknown command: ${cmd}`);
|
|
56495
56638
|
console.error("Run `claudemesh --help` for usage.");
|