claudemesh-cli 0.7.1 → 0.8.0
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 +531 -20
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -47663,6 +47663,75 @@ var TOOLS = [
|
|
|
47663
47663
|
},
|
|
47664
47664
|
required: ["name"]
|
|
47665
47665
|
}
|
|
47666
|
+
},
|
|
47667
|
+
{
|
|
47668
|
+
name: "mesh_mcp_deploy",
|
|
47669
|
+
description: "Deploy an MCP server to the mesh from a zip file or git repo. Runs on the broker VPS, persists across peer sessions. Default scope: private (only you).",
|
|
47670
|
+
inputSchema: {
|
|
47671
|
+
type: "object",
|
|
47672
|
+
properties: {
|
|
47673
|
+
server_name: { type: "string", description: "Unique name for the server in this mesh" },
|
|
47674
|
+
file_id: { type: "string", description: "File ID of uploaded zip (from share_file)" },
|
|
47675
|
+
git_url: { type: "string", description: "Git repo URL" },
|
|
47676
|
+
git_branch: { type: "string", description: "Branch to clone (default: main)" },
|
|
47677
|
+
env: { type: "object", description: "Environment variables. Use $vault:<key> for vault secrets." },
|
|
47678
|
+
runtime: { type: "string", enum: ["node", "python", "bun"], description: "Runtime (auto-detected if omitted)" },
|
|
47679
|
+
memory_mb: { type: "number", description: "Memory limit in MB (default: 256)" },
|
|
47680
|
+
network_allow: { type: "array", items: { type: "string" }, description: "Allowed outbound hosts (default: none)" },
|
|
47681
|
+
scope: { description: "Visibility: 'peer' (default), 'mesh', or {group/groups/role/peers}" }
|
|
47682
|
+
},
|
|
47683
|
+
required: ["server_name"]
|
|
47684
|
+
}
|
|
47685
|
+
},
|
|
47686
|
+
{
|
|
47687
|
+
name: "mesh_mcp_undeploy",
|
|
47688
|
+
description: "Stop and remove a managed MCP server from the mesh.",
|
|
47689
|
+
inputSchema: { type: "object", properties: { server_name: { type: "string" } }, required: ["server_name"] }
|
|
47690
|
+
},
|
|
47691
|
+
{
|
|
47692
|
+
name: "mesh_mcp_update",
|
|
47693
|
+
description: "Pull latest code and restart a git-sourced MCP server.",
|
|
47694
|
+
inputSchema: { type: "object", properties: { server_name: { type: "string" } }, required: ["server_name"] }
|
|
47695
|
+
},
|
|
47696
|
+
{
|
|
47697
|
+
name: "mesh_mcp_logs",
|
|
47698
|
+
description: "View recent logs from a managed MCP server.",
|
|
47699
|
+
inputSchema: { type: "object", properties: { server_name: { type: "string" }, lines: { type: "number", description: "Lines (default: 50, max: 1000)" } }, required: ["server_name"] }
|
|
47700
|
+
},
|
|
47701
|
+
{
|
|
47702
|
+
name: "mesh_mcp_scope",
|
|
47703
|
+
description: "Get or set the visibility scope of a deployed MCP server.",
|
|
47704
|
+
inputSchema: { type: "object", properties: { server_name: { type: "string" }, scope: { description: "New scope to set. Omit to read current." } }, required: ["server_name"] }
|
|
47705
|
+
},
|
|
47706
|
+
{
|
|
47707
|
+
name: "mesh_mcp_schema",
|
|
47708
|
+
description: "Inspect tool schemas for a deployed MCP server.",
|
|
47709
|
+
inputSchema: { type: "object", properties: { server_name: { type: "string" }, tool_name: { type: "string", description: "Specific tool (omit for all)" } }, required: ["server_name"] }
|
|
47710
|
+
},
|
|
47711
|
+
{
|
|
47712
|
+
name: "mesh_mcp_catalog",
|
|
47713
|
+
description: "List all deployed services in the mesh with status, scope, and tool count.",
|
|
47714
|
+
inputSchema: { type: "object", properties: {} }
|
|
47715
|
+
},
|
|
47716
|
+
{
|
|
47717
|
+
name: "mesh_skill_deploy",
|
|
47718
|
+
description: "Deploy a multi-file skill bundle from a zip or git repo.",
|
|
47719
|
+
inputSchema: { type: "object", properties: { file_id: { type: "string" }, git_url: { type: "string" }, git_branch: { type: "string" } } }
|
|
47720
|
+
},
|
|
47721
|
+
{
|
|
47722
|
+
name: "vault_set",
|
|
47723
|
+
description: "Store an encrypted credential in your vault. Reference in mesh_mcp_deploy with $vault:<key>.",
|
|
47724
|
+
inputSchema: { type: "object", properties: { key: { type: "string" }, value: { type: "string", description: "Secret value or local file path (for type=file)" }, type: { type: "string", enum: ["env", "file"] }, mount_path: { type: "string" }, description: { type: "string" } }, required: ["key", "value"] }
|
|
47725
|
+
},
|
|
47726
|
+
{
|
|
47727
|
+
name: "vault_list",
|
|
47728
|
+
description: "List your vault entries (keys and metadata only, no secret values).",
|
|
47729
|
+
inputSchema: { type: "object", properties: {} }
|
|
47730
|
+
},
|
|
47731
|
+
{
|
|
47732
|
+
name: "vault_delete",
|
|
47733
|
+
description: "Remove a credential from your vault.",
|
|
47734
|
+
inputSchema: { type: "object", properties: { key: { type: "string" } }, required: ["key"] }
|
|
47666
47735
|
}
|
|
47667
47736
|
];
|
|
47668
47737
|
|
|
@@ -47751,6 +47820,10 @@ class BrokerClient {
|
|
|
47751
47820
|
peerFileResponseResolvers = new Map;
|
|
47752
47821
|
peerDirResponseResolvers = new Map;
|
|
47753
47822
|
sharedDirs = [process.cwd()];
|
|
47823
|
+
_serviceCatalog = [];
|
|
47824
|
+
get serviceCatalog() {
|
|
47825
|
+
return this._serviceCatalog;
|
|
47826
|
+
}
|
|
47754
47827
|
closed = false;
|
|
47755
47828
|
reconnectAttempt = 0;
|
|
47756
47829
|
helloTimer = null;
|
|
@@ -47858,6 +47931,9 @@ class BrokerClient {
|
|
|
47858
47931
|
this._statsCounters.errors = rs.errors ?? 0;
|
|
47859
47932
|
}
|
|
47860
47933
|
}
|
|
47934
|
+
if (msg.services) {
|
|
47935
|
+
this._serviceCatalog = msg.services;
|
|
47936
|
+
}
|
|
47861
47937
|
resolve();
|
|
47862
47938
|
return;
|
|
47863
47939
|
}
|
|
@@ -48146,6 +48222,14 @@ class BrokerClient {
|
|
|
48146
48222
|
mcpListResolvers = new Map;
|
|
48147
48223
|
mcpCallResolvers = new Map;
|
|
48148
48224
|
mcpCallForwardHandler = null;
|
|
48225
|
+
vaultAckResolvers = new Map;
|
|
48226
|
+
vaultListResolvers = new Map;
|
|
48227
|
+
mcpDeployResolvers = new Map;
|
|
48228
|
+
mcpLogsResolvers = new Map;
|
|
48229
|
+
mcpSchemaServiceResolvers = new Map;
|
|
48230
|
+
mcpCatalogResolvers = new Map;
|
|
48231
|
+
mcpScopeResolvers = new Map;
|
|
48232
|
+
skillDeployResolvers = new Map;
|
|
48149
48233
|
async messageStatus(messageId) {
|
|
48150
48234
|
if (!this.ws || this.ws.readyState !== this.ws.OPEN)
|
|
48151
48235
|
return null;
|
|
@@ -48678,6 +48762,138 @@ class BrokerClient {
|
|
|
48678
48762
|
this.ws.send(JSON.stringify({ type: "peer_dir_request", targetPubkey, dirPath, ...pattern ? { pattern } : {}, _reqId: reqId }));
|
|
48679
48763
|
});
|
|
48680
48764
|
}
|
|
48765
|
+
async vaultSet(key, ciphertext, nonce, sealedKey, entryType, mountPath, description) {
|
|
48766
|
+
return new Promise((resolve) => {
|
|
48767
|
+
const reqId = `vset_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
48768
|
+
const timer = setTimeout(() => {
|
|
48769
|
+
this.vaultAckResolvers.delete(reqId);
|
|
48770
|
+
resolve(false);
|
|
48771
|
+
}, 1e4);
|
|
48772
|
+
this.vaultAckResolvers.set(reqId, { resolve, timer });
|
|
48773
|
+
this.sendRaw({ type: "vault_set", key, ciphertext, nonce, sealed_key: sealedKey, entry_type: entryType, mount_path: mountPath, description, _reqId: reqId });
|
|
48774
|
+
});
|
|
48775
|
+
}
|
|
48776
|
+
async vaultList() {
|
|
48777
|
+
return new Promise((resolve) => {
|
|
48778
|
+
const reqId = `vlist_${Date.now()}`;
|
|
48779
|
+
const timer = setTimeout(() => {
|
|
48780
|
+
this.vaultListResolvers.delete(reqId);
|
|
48781
|
+
resolve([]);
|
|
48782
|
+
}, 1e4);
|
|
48783
|
+
this.vaultListResolvers.set(reqId, { resolve, timer });
|
|
48784
|
+
this.sendRaw({ type: "vault_list", _reqId: reqId });
|
|
48785
|
+
});
|
|
48786
|
+
}
|
|
48787
|
+
async vaultDelete(key) {
|
|
48788
|
+
return new Promise((resolve) => {
|
|
48789
|
+
const reqId = `vdel_${Date.now()}`;
|
|
48790
|
+
const timer = setTimeout(() => {
|
|
48791
|
+
this.vaultAckResolvers.delete(reqId);
|
|
48792
|
+
resolve(false);
|
|
48793
|
+
}, 1e4);
|
|
48794
|
+
this.vaultAckResolvers.set(reqId, { resolve, timer });
|
|
48795
|
+
this.sendRaw({ type: "vault_delete", key, _reqId: reqId });
|
|
48796
|
+
});
|
|
48797
|
+
}
|
|
48798
|
+
async mcpDeploy(serverName, source, config2, scope) {
|
|
48799
|
+
return new Promise((resolve) => {
|
|
48800
|
+
const reqId = `deploy_${Date.now()}`;
|
|
48801
|
+
const timer = setTimeout(() => {
|
|
48802
|
+
this.mcpDeployResolvers.delete(reqId);
|
|
48803
|
+
resolve({ status: "timeout" });
|
|
48804
|
+
}, 60000);
|
|
48805
|
+
this.mcpDeployResolvers.set(reqId, { resolve, timer });
|
|
48806
|
+
this.sendRaw({ type: "mcp_deploy", server_name: serverName, source, config: config2, scope, _reqId: reqId });
|
|
48807
|
+
});
|
|
48808
|
+
}
|
|
48809
|
+
async mcpUndeploy(serverName) {
|
|
48810
|
+
return new Promise((resolve) => {
|
|
48811
|
+
const reqId = `undeploy_${Date.now()}`;
|
|
48812
|
+
const timer = setTimeout(() => {
|
|
48813
|
+
this.mcpDeployResolvers.delete(reqId);
|
|
48814
|
+
resolve(false);
|
|
48815
|
+
}, 1e4);
|
|
48816
|
+
this.mcpDeployResolvers.set(reqId, { resolve: (r) => resolve(r.status === "stopped"), timer });
|
|
48817
|
+
this.sendRaw({ type: "mcp_undeploy", server_name: serverName, _reqId: reqId });
|
|
48818
|
+
});
|
|
48819
|
+
}
|
|
48820
|
+
async mcpUpdate(serverName) {
|
|
48821
|
+
return new Promise((resolve) => {
|
|
48822
|
+
const reqId = `update_${Date.now()}`;
|
|
48823
|
+
const timer = setTimeout(() => {
|
|
48824
|
+
this.mcpDeployResolvers.delete(reqId);
|
|
48825
|
+
resolve({ status: "timeout" });
|
|
48826
|
+
}, 60000);
|
|
48827
|
+
this.mcpDeployResolvers.set(reqId, { resolve, timer });
|
|
48828
|
+
this.sendRaw({ type: "mcp_update", server_name: serverName, _reqId: reqId });
|
|
48829
|
+
});
|
|
48830
|
+
}
|
|
48831
|
+
async mcpLogs(serverName, lines) {
|
|
48832
|
+
return new Promise((resolve) => {
|
|
48833
|
+
const reqId = `logs_${Date.now()}`;
|
|
48834
|
+
const timer = setTimeout(() => {
|
|
48835
|
+
this.mcpLogsResolvers.delete(reqId);
|
|
48836
|
+
resolve([]);
|
|
48837
|
+
}, 1e4);
|
|
48838
|
+
this.mcpLogsResolvers.set(reqId, { resolve, timer });
|
|
48839
|
+
this.sendRaw({ type: "mcp_logs", server_name: serverName, lines, _reqId: reqId });
|
|
48840
|
+
});
|
|
48841
|
+
}
|
|
48842
|
+
async mcpScope(serverName, scope) {
|
|
48843
|
+
return new Promise((resolve) => {
|
|
48844
|
+
const reqId = `scope_${Date.now()}`;
|
|
48845
|
+
const timer = setTimeout(() => {
|
|
48846
|
+
this.mcpScopeResolvers.delete(reqId);
|
|
48847
|
+
resolve({ scope: { type: "peer" }, deployed_by: "unknown" });
|
|
48848
|
+
}, 1e4);
|
|
48849
|
+
this.mcpScopeResolvers.set(reqId, { resolve, timer });
|
|
48850
|
+
this.sendRaw({ type: "mcp_scope", server_name: serverName, scope, _reqId: reqId });
|
|
48851
|
+
});
|
|
48852
|
+
}
|
|
48853
|
+
async mcpServiceSchema(serverName, toolName) {
|
|
48854
|
+
return new Promise((resolve) => {
|
|
48855
|
+
const reqId = `schema_${Date.now()}`;
|
|
48856
|
+
const timer = setTimeout(() => {
|
|
48857
|
+
this.mcpSchemaServiceResolvers.delete(reqId);
|
|
48858
|
+
resolve([]);
|
|
48859
|
+
}, 1e4);
|
|
48860
|
+
this.mcpSchemaServiceResolvers.set(reqId, { resolve, timer });
|
|
48861
|
+
this.sendRaw({ type: "mcp_schema", server_name: serverName, tool_name: toolName, _reqId: reqId });
|
|
48862
|
+
});
|
|
48863
|
+
}
|
|
48864
|
+
async mcpCatalog() {
|
|
48865
|
+
return new Promise((resolve) => {
|
|
48866
|
+
const reqId = `catalog_${Date.now()}`;
|
|
48867
|
+
const timer = setTimeout(() => {
|
|
48868
|
+
this.mcpCatalogResolvers.delete(reqId);
|
|
48869
|
+
resolve([]);
|
|
48870
|
+
}, 1e4);
|
|
48871
|
+
this.mcpCatalogResolvers.set(reqId, { resolve, timer });
|
|
48872
|
+
this.sendRaw({ type: "mcp_catalog", _reqId: reqId });
|
|
48873
|
+
});
|
|
48874
|
+
}
|
|
48875
|
+
async skillDeploy(source) {
|
|
48876
|
+
return new Promise((resolve) => {
|
|
48877
|
+
const reqId = `skilldeploy_${Date.now()}`;
|
|
48878
|
+
const timer = setTimeout(() => {
|
|
48879
|
+
this.skillDeployResolvers.delete(reqId);
|
|
48880
|
+
resolve({ name: "unknown", files: [] });
|
|
48881
|
+
}, 30000);
|
|
48882
|
+
this.skillDeployResolvers.set(reqId, { resolve, timer });
|
|
48883
|
+
this.sendRaw({ type: "skill_deploy", source, _reqId: reqId });
|
|
48884
|
+
});
|
|
48885
|
+
}
|
|
48886
|
+
async getServiceTools(serviceName) {
|
|
48887
|
+
const cached2 = this._serviceCatalog.find((s) => s.name === serviceName);
|
|
48888
|
+
if (cached2?.tools?.length)
|
|
48889
|
+
return cached2.tools;
|
|
48890
|
+
return this.mcpServiceSchema(serviceName);
|
|
48891
|
+
}
|
|
48892
|
+
sendRaw(payload) {
|
|
48893
|
+
if (!this.ws || this.ws.readyState !== this.ws.OPEN)
|
|
48894
|
+
return;
|
|
48895
|
+
this.ws.send(JSON.stringify(payload));
|
|
48896
|
+
}
|
|
48681
48897
|
close() {
|
|
48682
48898
|
this.closed = true;
|
|
48683
48899
|
this.stopStatsReporting();
|
|
@@ -49179,6 +49395,78 @@ class BrokerClient {
|
|
|
49179
49395
|
this.resolveFromMap(this.webhookListResolvers, msgReqId, webhooks);
|
|
49180
49396
|
return;
|
|
49181
49397
|
}
|
|
49398
|
+
if (msg.type === "vault_ack") {
|
|
49399
|
+
const reqId = msg._reqId;
|
|
49400
|
+
if (reqId && this.vaultAckResolvers.has(reqId)) {
|
|
49401
|
+
const r = this.vaultAckResolvers.get(reqId);
|
|
49402
|
+
clearTimeout(r.timer);
|
|
49403
|
+
this.vaultAckResolvers.delete(reqId);
|
|
49404
|
+
r.resolve(msg.action !== "not_found");
|
|
49405
|
+
}
|
|
49406
|
+
}
|
|
49407
|
+
if (msg.type === "vault_list_result") {
|
|
49408
|
+
const reqId = msg._reqId;
|
|
49409
|
+
if (reqId && this.vaultListResolvers.has(reqId)) {
|
|
49410
|
+
const r = this.vaultListResolvers.get(reqId);
|
|
49411
|
+
clearTimeout(r.timer);
|
|
49412
|
+
this.vaultListResolvers.delete(reqId);
|
|
49413
|
+
r.resolve(msg.entries ?? []);
|
|
49414
|
+
}
|
|
49415
|
+
}
|
|
49416
|
+
if (msg.type === "mcp_deploy_status") {
|
|
49417
|
+
const reqId = msg._reqId;
|
|
49418
|
+
if (reqId && this.mcpDeployResolvers.has(reqId)) {
|
|
49419
|
+
const r = this.mcpDeployResolvers.get(reqId);
|
|
49420
|
+
clearTimeout(r.timer);
|
|
49421
|
+
this.mcpDeployResolvers.delete(reqId);
|
|
49422
|
+
r.resolve({ status: msg.status, tools: msg.tools, error: msg.error });
|
|
49423
|
+
}
|
|
49424
|
+
}
|
|
49425
|
+
if (msg.type === "mcp_logs_result") {
|
|
49426
|
+
const reqId = msg._reqId;
|
|
49427
|
+
if (reqId && this.mcpLogsResolvers.has(reqId)) {
|
|
49428
|
+
const r = this.mcpLogsResolvers.get(reqId);
|
|
49429
|
+
clearTimeout(r.timer);
|
|
49430
|
+
this.mcpLogsResolvers.delete(reqId);
|
|
49431
|
+
r.resolve(msg.lines ?? []);
|
|
49432
|
+
}
|
|
49433
|
+
}
|
|
49434
|
+
if (msg.type === "mcp_schema_result") {
|
|
49435
|
+
const reqId = msg._reqId;
|
|
49436
|
+
if (reqId && this.mcpSchemaServiceResolvers.has(reqId)) {
|
|
49437
|
+
const r = this.mcpSchemaServiceResolvers.get(reqId);
|
|
49438
|
+
clearTimeout(r.timer);
|
|
49439
|
+
this.mcpSchemaServiceResolvers.delete(reqId);
|
|
49440
|
+
r.resolve(msg.tools ?? []);
|
|
49441
|
+
}
|
|
49442
|
+
}
|
|
49443
|
+
if (msg.type === "mcp_catalog_result") {
|
|
49444
|
+
const reqId = msg._reqId;
|
|
49445
|
+
if (reqId && this.mcpCatalogResolvers.has(reqId)) {
|
|
49446
|
+
const r = this.mcpCatalogResolvers.get(reqId);
|
|
49447
|
+
clearTimeout(r.timer);
|
|
49448
|
+
this.mcpCatalogResolvers.delete(reqId);
|
|
49449
|
+
r.resolve(msg.services ?? []);
|
|
49450
|
+
}
|
|
49451
|
+
}
|
|
49452
|
+
if (msg.type === "mcp_scope_result") {
|
|
49453
|
+
const reqId = msg._reqId;
|
|
49454
|
+
if (reqId && this.mcpScopeResolvers.has(reqId)) {
|
|
49455
|
+
const r = this.mcpScopeResolvers.get(reqId);
|
|
49456
|
+
clearTimeout(r.timer);
|
|
49457
|
+
this.mcpScopeResolvers.delete(reqId);
|
|
49458
|
+
r.resolve({ scope: msg.scope, deployed_by: msg.deployed_by });
|
|
49459
|
+
}
|
|
49460
|
+
}
|
|
49461
|
+
if (msg.type === "skill_deploy_ack") {
|
|
49462
|
+
const reqId = msg._reqId;
|
|
49463
|
+
if (reqId && this.skillDeployResolvers.has(reqId)) {
|
|
49464
|
+
const r = this.skillDeployResolvers.get(reqId);
|
|
49465
|
+
clearTimeout(r.timer);
|
|
49466
|
+
this.skillDeployResolvers.delete(reqId);
|
|
49467
|
+
r.resolve({ name: msg.name, files: msg.files ?? [] });
|
|
49468
|
+
}
|
|
49469
|
+
}
|
|
49182
49470
|
if (msg.type === "error") {
|
|
49183
49471
|
this.debug(`broker error: ${msg.code} ${msg.message}`);
|
|
49184
49472
|
const id = msg.id ? String(msg.id) : null;
|
|
@@ -49232,7 +49520,15 @@ class BrokerClient {
|
|
|
49232
49520
|
[this.peerFileResponseResolvers, { error: "broker error" }],
|
|
49233
49521
|
[this.peerDirResponseResolvers, { error: "broker error" }],
|
|
49234
49522
|
[this.webhookAckResolvers, null],
|
|
49235
|
-
[this.webhookListResolvers, []]
|
|
49523
|
+
[this.webhookListResolvers, []],
|
|
49524
|
+
[this.vaultAckResolvers, false],
|
|
49525
|
+
[this.vaultListResolvers, []],
|
|
49526
|
+
[this.mcpDeployResolvers, { status: "error" }],
|
|
49527
|
+
[this.mcpLogsResolvers, []],
|
|
49528
|
+
[this.mcpSchemaServiceResolvers, []],
|
|
49529
|
+
[this.mcpCatalogResolvers, []],
|
|
49530
|
+
[this.mcpScopeResolvers, { scope: { type: "peer" }, deployed_by: "unknown" }],
|
|
49531
|
+
[this.skillDeployResolvers, { name: "unknown", files: [] }]
|
|
49236
49532
|
];
|
|
49237
49533
|
for (const [map2, defaultVal] of allMaps) {
|
|
49238
49534
|
const first = map2.entries().next().value;
|
|
@@ -49428,6 +49724,10 @@ function formatPush(p, meshSlug) {
|
|
|
49428
49724
|
${body}`;
|
|
49429
49725
|
}
|
|
49430
49726
|
async function startMcpServer() {
|
|
49727
|
+
const serviceIdx = process.argv.indexOf("--service");
|
|
49728
|
+
if (serviceIdx !== -1 && process.argv[serviceIdx + 1]) {
|
|
49729
|
+
return startServiceProxy(process.argv[serviceIdx + 1]);
|
|
49730
|
+
}
|
|
49431
49731
|
const config2 = loadConfig();
|
|
49432
49732
|
const myName = config2.displayName ?? "unnamed";
|
|
49433
49733
|
const myRole = config2.role ?? process.env.CLAUDEMESH_ROLE ?? null;
|
|
@@ -50830,6 +51130,120 @@ ${lines.join(`
|
|
|
50830
51130
|
process.on("SIGTERM", shutdown);
|
|
50831
51131
|
process.on("SIGINT", shutdown);
|
|
50832
51132
|
}
|
|
51133
|
+
async function startServiceProxy(serviceName) {
|
|
51134
|
+
const config2 = loadConfig();
|
|
51135
|
+
if (config2.meshes.length === 0) {
|
|
51136
|
+
process.stderr.write(`[mesh:${serviceName}] no meshes joined
|
|
51137
|
+
`);
|
|
51138
|
+
process.exit(1);
|
|
51139
|
+
}
|
|
51140
|
+
const mesh = config2.meshes[0];
|
|
51141
|
+
const client2 = new BrokerClient(mesh, {
|
|
51142
|
+
displayName: config2.displayName ?? `proxy:${serviceName}`
|
|
51143
|
+
});
|
|
51144
|
+
try {
|
|
51145
|
+
await client2.connect();
|
|
51146
|
+
} catch (e) {
|
|
51147
|
+
process.stderr.write(`[mesh:${serviceName}] broker connect failed: ${e instanceof Error ? e.message : String(e)}
|
|
51148
|
+
`);
|
|
51149
|
+
process.exit(1);
|
|
51150
|
+
}
|
|
51151
|
+
await new Promise((r) => setTimeout(r, 1500));
|
|
51152
|
+
let tools = [];
|
|
51153
|
+
try {
|
|
51154
|
+
const fetched = await client2.getServiceTools(serviceName);
|
|
51155
|
+
tools = fetched;
|
|
51156
|
+
} catch {
|
|
51157
|
+
const cached2 = client2.serviceCatalog.find((s) => s.name === serviceName);
|
|
51158
|
+
if (cached2) {
|
|
51159
|
+
tools = cached2.tools;
|
|
51160
|
+
}
|
|
51161
|
+
}
|
|
51162
|
+
if (tools.length === 0) {
|
|
51163
|
+
process.stderr.write(`[mesh:${serviceName}] no tools found — service may not be running
|
|
51164
|
+
`);
|
|
51165
|
+
}
|
|
51166
|
+
const server = new Server({ name: `mesh:${serviceName}`, version: "0.1.0" }, { capabilities: { tools: {} } });
|
|
51167
|
+
server.setRequestHandler(ListToolsRequestSchema, () => ({
|
|
51168
|
+
tools: tools.map((t) => ({
|
|
51169
|
+
name: t.name,
|
|
51170
|
+
description: `[mesh:${serviceName}] ${t.description}`,
|
|
51171
|
+
inputSchema: t.inputSchema
|
|
51172
|
+
}))
|
|
51173
|
+
}));
|
|
51174
|
+
server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
51175
|
+
const toolName = req.params.name;
|
|
51176
|
+
const args = req.params.arguments ?? {};
|
|
51177
|
+
if (client2.status !== "open") {
|
|
51178
|
+
let waited = 0;
|
|
51179
|
+
while (client2.status !== "open" && waited < 1e4) {
|
|
51180
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
51181
|
+
waited += 500;
|
|
51182
|
+
}
|
|
51183
|
+
if (client2.status !== "open") {
|
|
51184
|
+
return {
|
|
51185
|
+
content: [
|
|
51186
|
+
{
|
|
51187
|
+
type: "text",
|
|
51188
|
+
text: `Service temporarily unavailable — broker reconnecting. Retry in a few seconds.`
|
|
51189
|
+
}
|
|
51190
|
+
],
|
|
51191
|
+
isError: true
|
|
51192
|
+
};
|
|
51193
|
+
}
|
|
51194
|
+
}
|
|
51195
|
+
try {
|
|
51196
|
+
const result = await client2.mcpCall(serviceName, toolName, args);
|
|
51197
|
+
if (result.error) {
|
|
51198
|
+
return {
|
|
51199
|
+
content: [{ type: "text", text: `Error: ${result.error}` }],
|
|
51200
|
+
isError: true
|
|
51201
|
+
};
|
|
51202
|
+
}
|
|
51203
|
+
const resultText = typeof result.result === "string" ? result.result : JSON.stringify(result.result, null, 2);
|
|
51204
|
+
return {
|
|
51205
|
+
content: [{ type: "text", text: resultText }]
|
|
51206
|
+
};
|
|
51207
|
+
} catch (e) {
|
|
51208
|
+
return {
|
|
51209
|
+
content: [
|
|
51210
|
+
{
|
|
51211
|
+
type: "text",
|
|
51212
|
+
text: `Call failed: ${e instanceof Error ? e.message : String(e)}`
|
|
51213
|
+
}
|
|
51214
|
+
],
|
|
51215
|
+
isError: true
|
|
51216
|
+
};
|
|
51217
|
+
}
|
|
51218
|
+
});
|
|
51219
|
+
client2.onPush((push) => {
|
|
51220
|
+
if (push.event === "mcp_undeployed" && push.eventData?.name === serviceName) {
|
|
51221
|
+
process.stderr.write(`[mesh:${serviceName}] service undeployed — exiting
|
|
51222
|
+
`);
|
|
51223
|
+
client2.close();
|
|
51224
|
+
process.exit(0);
|
|
51225
|
+
}
|
|
51226
|
+
if (push.event === "mcp_updated" && push.eventData?.name === serviceName) {
|
|
51227
|
+
const newTools = push.eventData?.tools;
|
|
51228
|
+
if (Array.isArray(newTools)) {
|
|
51229
|
+
tools = newTools;
|
|
51230
|
+
server.notification({
|
|
51231
|
+
method: "notifications/tools/list_changed"
|
|
51232
|
+
}).catch(() => {});
|
|
51233
|
+
}
|
|
51234
|
+
}
|
|
51235
|
+
});
|
|
51236
|
+
const transport = new StdioServerTransport;
|
|
51237
|
+
await server.connect(transport);
|
|
51238
|
+
const keepalive = setInterval(() => {}, 1000);
|
|
51239
|
+
const shutdown = () => {
|
|
51240
|
+
clearInterval(keepalive);
|
|
51241
|
+
client2.close();
|
|
51242
|
+
process.exit(0);
|
|
51243
|
+
};
|
|
51244
|
+
process.on("SIGTERM", shutdown);
|
|
51245
|
+
process.on("SIGINT", shutdown);
|
|
51246
|
+
}
|
|
50833
51247
|
|
|
50834
51248
|
// src/commands/install.ts
|
|
50835
51249
|
init_config();
|
|
@@ -51526,8 +51940,8 @@ async function runHook(args) {
|
|
|
51526
51940
|
// src/commands/launch.ts
|
|
51527
51941
|
init_config();
|
|
51528
51942
|
import { spawn } from "node:child_process";
|
|
51529
|
-
import { mkdtempSync, writeFileSync as writeFileSync4, rmSync, readdirSync, statSync } from "node:fs";
|
|
51530
|
-
import { tmpdir, hostname as hostname2 } from "node:os";
|
|
51943
|
+
import { mkdtempSync, writeFileSync as writeFileSync4, rmSync, readdirSync, statSync, existsSync as existsSync3, readFileSync as readFileSync3 } from "node:fs";
|
|
51944
|
+
import { tmpdir, hostname as hostname2, homedir as homedir4 } from "node:os";
|
|
51531
51945
|
import { join as join4 } from "node:path";
|
|
51532
51946
|
import { createInterface } from "node:readline";
|
|
51533
51947
|
async function pickMesh(meshes) {
|
|
@@ -51726,6 +52140,44 @@ async function runLaunch(flags, rawArgs) {
|
|
|
51726
52140
|
rmSync(full, { recursive: true, force: true });
|
|
51727
52141
|
}
|
|
51728
52142
|
} catch {}
|
|
52143
|
+
try {
|
|
52144
|
+
const claudeConfigPath = join4(homedir4(), ".claude.json");
|
|
52145
|
+
if (existsSync3(claudeConfigPath)) {
|
|
52146
|
+
const claudeConfig = JSON.parse(readFileSync3(claudeConfigPath, "utf-8"));
|
|
52147
|
+
const mcpServers = claudeConfig.mcpServers ?? {};
|
|
52148
|
+
let cleaned = 0;
|
|
52149
|
+
for (const key of Object.keys(mcpServers)) {
|
|
52150
|
+
if (!key.startsWith("mesh:"))
|
|
52151
|
+
continue;
|
|
52152
|
+
const meta2 = mcpServers[key]?._meshSession;
|
|
52153
|
+
if (!meta2?.pid)
|
|
52154
|
+
continue;
|
|
52155
|
+
try {
|
|
52156
|
+
process.kill(meta2.pid, 0);
|
|
52157
|
+
} catch {
|
|
52158
|
+
delete mcpServers[key];
|
|
52159
|
+
cleaned++;
|
|
52160
|
+
}
|
|
52161
|
+
}
|
|
52162
|
+
if (cleaned > 0) {
|
|
52163
|
+
claudeConfig.mcpServers = mcpServers;
|
|
52164
|
+
writeFileSync4(claudeConfigPath, JSON.stringify(claudeConfig, null, 2) + `
|
|
52165
|
+
`, "utf-8");
|
|
52166
|
+
}
|
|
52167
|
+
}
|
|
52168
|
+
} catch {}
|
|
52169
|
+
let serviceCatalog = [];
|
|
52170
|
+
try {
|
|
52171
|
+
const tmpClient = new BrokerClient(mesh, { displayName });
|
|
52172
|
+
await tmpClient.connect();
|
|
52173
|
+
await new Promise((r) => setTimeout(r, 2000));
|
|
52174
|
+
serviceCatalog = tmpClient.serviceCatalog;
|
|
52175
|
+
tmpClient.close();
|
|
52176
|
+
} catch {
|
|
52177
|
+
if (!args.quiet) {
|
|
52178
|
+
console.log(" (Could not fetch service catalog — mesh services won't be natively available)");
|
|
52179
|
+
}
|
|
52180
|
+
}
|
|
51729
52181
|
const tmpDir = mkdtempSync(join4(tmpdir(), "claudemesh-"));
|
|
51730
52182
|
const sessionConfig = {
|
|
51731
52183
|
version: 1,
|
|
@@ -51743,6 +52195,50 @@ async function runLaunch(flags, rawArgs) {
|
|
|
51743
52195
|
await confirmPermissions();
|
|
51744
52196
|
}
|
|
51745
52197
|
}
|
|
52198
|
+
const meshMcpEntries = [];
|
|
52199
|
+
if (serviceCatalog.length > 0) {
|
|
52200
|
+
const claudeConfigPath = join4(homedir4(), ".claude.json");
|
|
52201
|
+
let claudeConfig = {};
|
|
52202
|
+
try {
|
|
52203
|
+
claudeConfig = JSON.parse(readFileSync3(claudeConfigPath, "utf-8"));
|
|
52204
|
+
} catch {
|
|
52205
|
+
claudeConfig = {};
|
|
52206
|
+
}
|
|
52207
|
+
const mcpServers = claudeConfig.mcpServers ?? {};
|
|
52208
|
+
const sessionTag = `${process.pid}`;
|
|
52209
|
+
for (const svc of serviceCatalog) {
|
|
52210
|
+
if (svc.status !== "running")
|
|
52211
|
+
continue;
|
|
52212
|
+
const entryKey = `mesh:${svc.name}:${sessionTag}`;
|
|
52213
|
+
const entry = {
|
|
52214
|
+
command: "claudemesh",
|
|
52215
|
+
args: ["mcp", "--service", svc.name],
|
|
52216
|
+
env: {
|
|
52217
|
+
CLAUDEMESH_CONFIG_DIR: tmpDir
|
|
52218
|
+
},
|
|
52219
|
+
_meshSession: {
|
|
52220
|
+
pid: process.pid,
|
|
52221
|
+
meshSlug: mesh.slug,
|
|
52222
|
+
serviceName: svc.name,
|
|
52223
|
+
createdAt: new Date().toISOString()
|
|
52224
|
+
}
|
|
52225
|
+
};
|
|
52226
|
+
mcpServers[entryKey] = entry;
|
|
52227
|
+
meshMcpEntries.push({ key: entryKey, entry });
|
|
52228
|
+
}
|
|
52229
|
+
claudeConfig.mcpServers = mcpServers;
|
|
52230
|
+
writeFileSync4(claudeConfigPath, JSON.stringify(claudeConfig, null, 2) + `
|
|
52231
|
+
`, "utf-8");
|
|
52232
|
+
if (!args.quiet && meshMcpEntries.length > 0) {
|
|
52233
|
+
console.log(` ${meshMcpEntries.length} mesh service(s) registered as native MCPs:`);
|
|
52234
|
+
for (const { key } of meshMcpEntries) {
|
|
52235
|
+
const svcName = key.split(":")[1];
|
|
52236
|
+
const svc = serviceCatalog.find((s) => s.name === svcName);
|
|
52237
|
+
console.log(` ${svcName} (${svc?.tools.length ?? 0} tools)`);
|
|
52238
|
+
}
|
|
52239
|
+
console.log("");
|
|
52240
|
+
}
|
|
52241
|
+
}
|
|
51746
52242
|
const filtered = [];
|
|
51747
52243
|
for (let i = 0;i < args.claudeArgs.length; i++) {
|
|
51748
52244
|
if (args.claudeArgs[i] === "--dangerously-load-development-channels" || args.claudeArgs[i] === "--dangerously-skip-permissions") {
|
|
@@ -51767,10 +52263,25 @@ async function runLaunch(flags, rawArgs) {
|
|
|
51767
52263
|
...process.env,
|
|
51768
52264
|
CLAUDEMESH_CONFIG_DIR: tmpDir,
|
|
51769
52265
|
CLAUDEMESH_DISPLAY_NAME: displayName,
|
|
52266
|
+
MCP_TIMEOUT: process.env.MCP_TIMEOUT ?? "30000",
|
|
52267
|
+
MAX_MCP_OUTPUT_TOKENS: process.env.MAX_MCP_OUTPUT_TOKENS ?? "50000",
|
|
51770
52268
|
...role ? { CLAUDEMESH_ROLE: role } : {}
|
|
51771
52269
|
}
|
|
51772
52270
|
});
|
|
51773
52271
|
const cleanup = () => {
|
|
52272
|
+
if (meshMcpEntries.length > 0) {
|
|
52273
|
+
try {
|
|
52274
|
+
const claudeConfigPath = join4(homedir4(), ".claude.json");
|
|
52275
|
+
const claudeConfig = JSON.parse(readFileSync3(claudeConfigPath, "utf-8"));
|
|
52276
|
+
const mcpServers = claudeConfig.mcpServers ?? {};
|
|
52277
|
+
for (const { key } of meshMcpEntries) {
|
|
52278
|
+
delete mcpServers[key];
|
|
52279
|
+
}
|
|
52280
|
+
claudeConfig.mcpServers = mcpServers;
|
|
52281
|
+
writeFileSync4(claudeConfigPath, JSON.stringify(claudeConfig, null, 2) + `
|
|
52282
|
+
`, "utf-8");
|
|
52283
|
+
} catch {}
|
|
52284
|
+
}
|
|
51774
52285
|
try {
|
|
51775
52286
|
rmSync(tmpDir, { recursive: true, force: true });
|
|
51776
52287
|
} catch {}
|
|
@@ -51803,12 +52314,12 @@ async function runLaunch(flags, rawArgs) {
|
|
|
51803
52314
|
}
|
|
51804
52315
|
|
|
51805
52316
|
// src/commands/status.ts
|
|
51806
|
-
import { statSync as statSync2, existsSync as
|
|
52317
|
+
import { statSync as statSync2, existsSync as existsSync4 } from "node:fs";
|
|
51807
52318
|
init_config();
|
|
51808
52319
|
// package.json
|
|
51809
52320
|
var package_default = {
|
|
51810
52321
|
name: "claudemesh-cli",
|
|
51811
|
-
version: "0.
|
|
52322
|
+
version: "0.8.0",
|
|
51812
52323
|
description: "Claude Code MCP client for claudemesh — peer mesh messaging between Claude sessions.",
|
|
51813
52324
|
keywords: [
|
|
51814
52325
|
"claude-code",
|
|
@@ -51909,7 +52420,7 @@ async function runStatus() {
|
|
|
51909
52420
|
console.log("─".repeat(60));
|
|
51910
52421
|
const configPath = getConfigPath();
|
|
51911
52422
|
let configPerms = "missing";
|
|
51912
|
-
if (
|
|
52423
|
+
if (existsSync4(configPath)) {
|
|
51913
52424
|
const st = statSync2(configPath);
|
|
51914
52425
|
const mode = (st.mode & 511).toString(8).padStart(4, "0");
|
|
51915
52426
|
configPerms = mode === "0600" ? `${mode} ✓` : `${mode} ⚠ (expected 0600)`;
|
|
@@ -51958,8 +52469,8 @@ async function runStatus() {
|
|
|
51958
52469
|
|
|
51959
52470
|
// src/commands/doctor.ts
|
|
51960
52471
|
init_config();
|
|
51961
|
-
import { existsSync as
|
|
51962
|
-
import { homedir as
|
|
52472
|
+
import { existsSync as existsSync5, readFileSync as readFileSync4, statSync as statSync3 } from "node:fs";
|
|
52473
|
+
import { homedir as homedir5, platform as platform2 } from "node:os";
|
|
51963
52474
|
import { join as join5 } from "node:path";
|
|
51964
52475
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
51965
52476
|
function checkNode() {
|
|
@@ -51984,8 +52495,8 @@ function checkClaudeOnPath() {
|
|
|
51984
52495
|
};
|
|
51985
52496
|
}
|
|
51986
52497
|
function checkMcpRegistered() {
|
|
51987
|
-
const claudeConfig = join5(
|
|
51988
|
-
if (!
|
|
52498
|
+
const claudeConfig = join5(homedir5(), ".claude.json");
|
|
52499
|
+
if (!existsSync5(claudeConfig)) {
|
|
51989
52500
|
return {
|
|
51990
52501
|
name: "claudemesh MCP registered in ~/.claude.json",
|
|
51991
52502
|
pass: false,
|
|
@@ -51993,7 +52504,7 @@ function checkMcpRegistered() {
|
|
|
51993
52504
|
};
|
|
51994
52505
|
}
|
|
51995
52506
|
try {
|
|
51996
|
-
const cfg = JSON.parse(
|
|
52507
|
+
const cfg = JSON.parse(readFileSync4(claudeConfig, "utf-8"));
|
|
51997
52508
|
const registered = Boolean(cfg.mcpServers?.["claudemesh"]);
|
|
51998
52509
|
return {
|
|
51999
52510
|
name: "claudemesh MCP registered in ~/.claude.json",
|
|
@@ -52010,8 +52521,8 @@ function checkMcpRegistered() {
|
|
|
52010
52521
|
}
|
|
52011
52522
|
}
|
|
52012
52523
|
function checkHooksRegistered() {
|
|
52013
|
-
const settings = join5(
|
|
52014
|
-
if (!
|
|
52524
|
+
const settings = join5(homedir5(), ".claude", "settings.json");
|
|
52525
|
+
if (!existsSync5(settings)) {
|
|
52015
52526
|
return {
|
|
52016
52527
|
name: "Status hooks registered in ~/.claude/settings.json",
|
|
52017
52528
|
pass: false,
|
|
@@ -52019,7 +52530,7 @@ function checkHooksRegistered() {
|
|
|
52019
52530
|
};
|
|
52020
52531
|
}
|
|
52021
52532
|
try {
|
|
52022
|
-
const raw =
|
|
52533
|
+
const raw = readFileSync4(settings, "utf-8");
|
|
52023
52534
|
const has = raw.includes("claudemesh hook ");
|
|
52024
52535
|
return {
|
|
52025
52536
|
name: "Status hooks registered in ~/.claude/settings.json",
|
|
@@ -52036,7 +52547,7 @@ function checkHooksRegistered() {
|
|
|
52036
52547
|
}
|
|
52037
52548
|
function checkConfigFile() {
|
|
52038
52549
|
const path = getConfigPath();
|
|
52039
|
-
if (!
|
|
52550
|
+
if (!existsSync5(path)) {
|
|
52040
52551
|
return {
|
|
52041
52552
|
name: "~/.claudemesh/config.json exists and parses",
|
|
52042
52553
|
pass: true,
|
|
@@ -52140,15 +52651,15 @@ async function runDoctor() {
|
|
|
52140
52651
|
|
|
52141
52652
|
// src/commands/welcome.ts
|
|
52142
52653
|
init_config();
|
|
52143
|
-
import { existsSync as
|
|
52144
|
-
import { homedir as
|
|
52654
|
+
import { existsSync as existsSync6, readFileSync as readFileSync5 } from "node:fs";
|
|
52655
|
+
import { homedir as homedir6 } from "node:os";
|
|
52145
52656
|
import { join as join6 } from "node:path";
|
|
52146
52657
|
function detectState() {
|
|
52147
|
-
const claudeConfig = join6(
|
|
52658
|
+
const claudeConfig = join6(homedir6(), ".claude.json");
|
|
52148
52659
|
let mcpRegistered = false;
|
|
52149
|
-
if (
|
|
52660
|
+
if (existsSync6(claudeConfig)) {
|
|
52150
52661
|
try {
|
|
52151
|
-
const cfg = JSON.parse(
|
|
52662
|
+
const cfg = JSON.parse(readFileSync5(claudeConfig, "utf-8"));
|
|
52152
52663
|
mcpRegistered = Boolean(cfg.mcpServers?.["claudemesh"]);
|
|
52153
52664
|
} catch {}
|
|
52154
52665
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claudemesh-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Claude Code MCP client for claudemesh — peer mesh messaging between Claude sessions.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude-code",
|
|
@@ -49,8 +49,8 @@
|
|
|
49
49
|
"typescript": "5.9.3",
|
|
50
50
|
"vitest": "4.0.14",
|
|
51
51
|
"@turbostarter/eslint-config": "0.1.0",
|
|
52
|
-
"@turbostarter/tsconfig": "0.1.0",
|
|
53
52
|
"@turbostarter/prettier-config": "0.1.0",
|
|
53
|
+
"@turbostarter/tsconfig": "0.1.0",
|
|
54
54
|
"@turbostarter/vitest-config": "0.1.0"
|
|
55
55
|
},
|
|
56
56
|
"scripts": {
|