claudemesh-cli 0.8.3 → 0.8.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.
Files changed (2) hide show
  1. package/dist/index.js +91 -10
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -47880,6 +47880,12 @@ class BrokerClient {
47880
47880
  getSessionSecretKey() {
47881
47881
  return this.sessionSecretKey;
47882
47882
  }
47883
+ getMeshPubkey() {
47884
+ return this.mesh.pubkey;
47885
+ }
47886
+ getMeshSecretKey() {
47887
+ return this.mesh.secretKey;
47888
+ }
47883
47889
  makeReqId() {
47884
47890
  return Math.random().toString(36).slice(2) + Date.now().toString(36);
47885
47891
  }
@@ -48817,6 +48823,17 @@ class BrokerClient {
48817
48823
  this.sendRaw({ type: "vault_delete", key, _reqId: reqId });
48818
48824
  });
48819
48825
  }
48826
+ async vaultGet(keys) {
48827
+ return new Promise((resolve) => {
48828
+ const reqId = `vget_${Date.now()}`;
48829
+ const timer = setTimeout(() => {
48830
+ this.vaultListResolvers.delete(reqId);
48831
+ resolve([]);
48832
+ }, 1e4);
48833
+ this.vaultListResolvers.set(reqId, { resolve, timer });
48834
+ this.sendRaw({ type: "vault_get", keys, _reqId: reqId });
48835
+ });
48836
+ }
48820
48837
  async mcpDeploy(serverName, source, config2, scope) {
48821
48838
  return new Promise((resolve) => {
48822
48839
  const reqId = `deploy_${Date.now()}`;
@@ -49435,6 +49452,15 @@ class BrokerClient {
49435
49452
  r.resolve(msg.entries ?? []);
49436
49453
  }
49437
49454
  }
49455
+ if (msg.type === "vault_get_result") {
49456
+ const reqId = msg._reqId;
49457
+ if (reqId && this.vaultListResolvers.has(reqId)) {
49458
+ const r = this.vaultListResolvers.get(reqId);
49459
+ clearTimeout(r.timer);
49460
+ this.vaultListResolvers.delete(reqId);
49461
+ r.resolve(msg.entries ?? []);
49462
+ }
49463
+ }
49438
49464
  if (msg.type === "mcp_deploy_status") {
49439
49465
  const reqId = msg._reqId;
49440
49466
  if (reqId && this.mcpDeployResolvers.has(reqId)) {
@@ -51002,18 +51028,25 @@ ${lines.join(`
51002
51028
  if (!client2)
51003
51029
  return text("vault_set: not connected", true);
51004
51030
  const entryType = vType ?? "env";
51005
- let plaintext = value;
51031
+ let plaintextBytes;
51006
51032
  if (entryType === "file") {
51007
51033
  const { existsSync: existsSync2, readFileSync: readFileSync2 } = await import("node:fs");
51008
51034
  if (!existsSync2(value))
51009
51035
  return text(`vault_set: file not found: ${value}`, true);
51010
- plaintext = readFileSync2(value, "base64");
51011
- }
51012
- const encoded = Buffer.from(plaintext).toString("base64");
51013
- const ok = await client2.vaultSet(key, encoded, "placeholder-nonce", "placeholder-sealed", entryType, mount_path, description);
51036
+ plaintextBytes = new Uint8Array(readFileSync2(value));
51037
+ } else {
51038
+ plaintextBytes = new TextEncoder().encode(value);
51039
+ }
51040
+ const { encryptFile: encryptFile2, sealKeyForPeer: sealKeyForPeer2 } = await Promise.resolve().then(() => (init_file_crypto(), exports_file_crypto));
51041
+ const { ciphertext, nonce, key: kf } = await encryptFile2(plaintextBytes);
51042
+ const sealedKey = await sealKeyForPeer2(kf, client2.getMeshPubkey());
51043
+ const { ensureSodium: ensureSodium2 } = await Promise.resolve().then(() => (init_keypair(), exports_keypair));
51044
+ const sodium2 = await ensureSodium2();
51045
+ const ciphertextB64 = sodium2.to_base64(ciphertext, sodium2.base64_variants.ORIGINAL);
51046
+ const ok = await client2.vaultSet(key, ciphertextB64, nonce, sealedKey, entryType, mount_path, description);
51014
51047
  if (!ok)
51015
51048
  return text("vault_set: broker did not acknowledge", true);
51016
- return text(`Vault entry "${key}" stored (${entryType}).`);
51049
+ return text(`Vault entry "${key}" stored (${entryType}, E2E encrypted).`);
51017
51050
  }
51018
51051
  case "vault_list": {
51019
51052
  const client2 = allClients()[0];
@@ -51047,9 +51080,51 @@ ${lines.join(`
51047
51080
  if (!client2)
51048
51081
  return text("mesh_mcp_deploy: not connected", true);
51049
51082
  const source = file_id ? { type: "zip", file_id } : { type: "git", url: git_url, branch: git_branch };
51083
+ const resolvedEnv = {};
51084
+ const vaultResolved = [];
51085
+ if (deployEnv) {
51086
+ const vaultRefs = [];
51087
+ for (const [envKey, envVal] of Object.entries(deployEnv)) {
51088
+ if (typeof envVal === "string" && envVal.startsWith("$vault:")) {
51089
+ const parts = envVal.slice(7).split(":");
51090
+ const vaultKey = parts[0];
51091
+ const isFile = parts[1] === "file";
51092
+ const mountPath = isFile ? parts.slice(2).join(":") : undefined;
51093
+ vaultRefs.push({ envKey, vaultKey, isFile, mountPath });
51094
+ } else {
51095
+ resolvedEnv[envKey] = envVal;
51096
+ }
51097
+ }
51098
+ if (vaultRefs.length > 0) {
51099
+ const { openSealedKey: openSealedKey2, decryptFile: decryptFile2 } = await Promise.resolve().then(() => (init_file_crypto(), exports_file_crypto));
51100
+ const { ensureSodium: ensureSodium2 } = await Promise.resolve().then(() => (init_keypair(), exports_keypair));
51101
+ const sodium2 = await ensureSodium2();
51102
+ const keys = vaultRefs.map((r) => r.vaultKey);
51103
+ const encryptedEntries = await client2.vaultGet(keys);
51104
+ for (const ref of vaultRefs) {
51105
+ const entry = encryptedEntries.find((e) => e.key === ref.vaultKey);
51106
+ if (!entry)
51107
+ return text(`mesh_mcp_deploy: vault key "${ref.vaultKey}" not found. Use vault_set first.`, true);
51108
+ const kf = await openSealedKey2(entry.sealed_key, client2.getMeshPubkey(), client2.getMeshSecretKey());
51109
+ if (!kf)
51110
+ return text(`mesh_mcp_deploy: failed to decrypt vault key "${ref.vaultKey}" — wrong keypair?`, true);
51111
+ const ciphertextBytes = sodium2.from_base64(entry.ciphertext, sodium2.base64_variants.ORIGINAL);
51112
+ const plainBytes = await decryptFile2(ciphertextBytes, entry.nonce, kf);
51113
+ if (!plainBytes)
51114
+ return text(`mesh_mcp_deploy: failed to decrypt vault entry "${ref.vaultKey}" — corrupted?`, true);
51115
+ if (ref.isFile && ref.mountPath) {
51116
+ resolvedEnv[ref.envKey] = `__vault_file__:${ref.mountPath}:${sodium2.to_base64(plainBytes, sodium2.base64_variants.ORIGINAL)}`;
51117
+ } else {
51118
+ resolvedEnv[ref.envKey] = new TextDecoder().decode(plainBytes);
51119
+ }
51120
+ vaultResolved.push(ref.vaultKey);
51121
+ }
51122
+ }
51123
+ }
51050
51124
  const config3 = {};
51051
- if (deployEnv)
51052
- config3.env = deployEnv;
51125
+ if (Object.keys(resolvedEnv).length > 0 || deployEnv && Object.keys(deployEnv).length > 0) {
51126
+ config3.env = Object.keys(resolvedEnv).length > 0 ? resolvedEnv : deployEnv;
51127
+ }
51053
51128
  if (runtime)
51054
51129
  config3.runtime = runtime;
51055
51130
  if (memory_mb)
@@ -51059,12 +51134,18 @@ ${lines.join(`
51059
51134
  const result = await client2.mcpDeploy(server_name, source, Object.keys(config3).length > 0 ? config3 : undefined, scope);
51060
51135
  const toolList = result.tools?.map((t) => ` - ${t.name}: ${t.description}`).join(`
51061
51136
  `) ?? " (pending)";
51137
+ let vaultNote = "";
51138
+ if (vaultResolved.length > 0) {
51139
+ vaultNote = `
51140
+
51141
+ Vault keys resolved: ${vaultResolved.join(", ")} (decrypted client-side, sent over TLS)`;
51142
+ }
51062
51143
  return text(`Deployed "${server_name}" (status: ${result.status}).
51063
51144
 
51064
51145
  Tools:
51065
51146
  ${toolList}
51066
51147
 
51067
- Default scope: peer (private). Use mesh_mcp_scope to share.`);
51148
+ Default scope: peer (private). Use mesh_mcp_scope to share.${vaultNote}`);
51068
51149
  }
51069
51150
  case "mesh_mcp_undeploy": {
51070
51151
  const { server_name } = args ?? {};
@@ -52522,7 +52603,7 @@ init_config();
52522
52603
  // package.json
52523
52604
  var package_default = {
52524
52605
  name: "claudemesh-cli",
52525
- version: "0.8.3",
52606
+ version: "0.8.5",
52526
52607
  description: "Claude Code MCP client for claudemesh — peer mesh messaging between Claude sessions.",
52527
52608
  keywords: [
52528
52609
  "claude-code",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudemesh-cli",
3
- "version": "0.8.3",
3
+ "version": "0.8.5",
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/tsconfig": "0.1.0",
52
- "@turbostarter/prettier-config": "0.1.0",
53
52
  "@turbostarter/eslint-config": "0.1.0",
53
+ "@turbostarter/prettier-config": "0.1.0",
54
54
  "@turbostarter/vitest-config": "0.1.0"
55
55
  },
56
56
  "scripts": {