claudemesh-cli 1.34.2 → 1.34.3

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.
@@ -81,7 +81,7 @@ __export(exports_urls, {
81
81
  VERSION: () => VERSION,
82
82
  URLS: () => URLS
83
83
  });
84
- var URLS, VERSION = "1.34.2", env;
84
+ var URLS, VERSION = "1.34.3", env;
85
85
  var init_urls = __esm(() => {
86
86
  URLS = {
87
87
  BROKER: process.env.CLAUDEMESH_BROKER_URL ?? "wss://ic.claudemesh.com/ws",
@@ -2632,6 +2632,44 @@ var init_facade3 = __esm(() => {
2632
2632
  init_errors();
2633
2633
  });
2634
2634
 
2635
+ // src/services/session/token.ts
2636
+ var exports_token = {};
2637
+ __export(exports_token, {
2638
+ readSessionTokenFromEnv: () => readSessionTokenFromEnv,
2639
+ mintSessionToken: () => mintSessionToken,
2640
+ TOKEN_FILE_ENV: () => TOKEN_FILE_ENV
2641
+ });
2642
+ import { randomBytes as randomBytes3 } from "node:crypto";
2643
+ import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
2644
+ function mintSessionToken(dir, fileName = "session-token") {
2645
+ const token = randomBytes3(32).toString("hex");
2646
+ const filePath = `${dir}/${fileName}`;
2647
+ writeFileSync2(filePath, token, { mode: 384 });
2648
+ return { token, filePath };
2649
+ }
2650
+ function readSessionTokenFromEnv(env2 = process.env) {
2651
+ const direct = env2.CLAUDEMESH_IPC_TOKEN;
2652
+ if (direct && /^[0-9a-f]{64}$/i.test(direct))
2653
+ return direct.toLowerCase();
2654
+ const path = env2[ENV_TOKEN_FILE];
2655
+ if (!path)
2656
+ return null;
2657
+ try {
2658
+ if (!existsSync2(path))
2659
+ return null;
2660
+ const raw = readFileSync2(path, "utf8").trim();
2661
+ if (/^[0-9a-f]{64}$/i.test(raw))
2662
+ return raw.toLowerCase();
2663
+ return null;
2664
+ } catch {
2665
+ return null;
2666
+ }
2667
+ }
2668
+ var ENV_TOKEN_FILE = "CLAUDEMESH_IPC_TOKEN_FILE", TOKEN_FILE_ENV;
2669
+ var init_token = __esm(() => {
2670
+ TOKEN_FILE_ENV = ENV_TOKEN_FILE;
2671
+ });
2672
+
2635
2673
  // src/mcp/server.ts
2636
2674
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2637
2675
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
@@ -2643,12 +2681,12 @@ import {
2643
2681
  ListResourcesRequestSchema,
2644
2682
  ReadResourceRequestSchema
2645
2683
  } from "@modelcontextprotocol/sdk/types.js";
2646
- import { existsSync as existsSync2, appendFileSync } from "node:fs";
2684
+ import { existsSync as existsSync3, appendFileSync } from "node:fs";
2647
2685
  import { request as httpRequest } from "node:http";
2648
2686
  import { join as join3 } from "node:path";
2649
2687
  async function daemonReady() {
2650
2688
  for (let i = 0;i < DAEMON_BOOT_RETRIES; i++) {
2651
- if (existsSync2(DAEMON_PATHS.SOCK_FILE))
2689
+ if (existsSync3(DAEMON_PATHS.SOCK_FILE))
2652
2690
  return true;
2653
2691
  await new Promise((r) => setTimeout(r, DAEMON_BOOT_RETRY_MS));
2654
2692
  }
@@ -2666,9 +2704,12 @@ function bailNoDaemon() {
2666
2704
  `);
2667
2705
  process.exit(1);
2668
2706
  }
2669
- function daemonGet(path) {
2707
+ function daemonGet(path, opts = {}) {
2670
2708
  return new Promise((resolve, reject) => {
2671
- const req = httpRequest({ socketPath: DAEMON_PATHS.SOCK_FILE, path, method: "GET", timeout: 5000 }, (res) => {
2709
+ const headers = {};
2710
+ if (opts.sessionToken)
2711
+ headers.Authorization = `ClaudeMesh-Session ${opts.sessionToken}`;
2712
+ const req = httpRequest({ socketPath: DAEMON_PATHS.SOCK_FILE, path, method: "GET", timeout: 5000, headers }, (res) => {
2672
2713
  const chunks = [];
2673
2714
  res.on("data", (c) => chunks.push(c));
2674
2715
  res.on("end", () => {
@@ -2965,9 +3006,8 @@ ${mf.allowed_tools.map((t) => ` - ${t}`).join(`
2965
3006
  const transport = new StdioServerTransport;
2966
3007
  await server.connect(transport);
2967
3008
  const WELCOME_DELAY_MS = 5000;
2968
- const WELCOME_LOOKBACK_MS = 24 * 60 * 60 * 1000;
2969
3009
  setTimeout(() => {
2970
- emitInboxWelcome(server, mcpLog, WELCOME_LOOKBACK_MS);
3010
+ emitMeshWelcome(server, mcpLog);
2971
3011
  }, WELCOME_DELAY_MS);
2972
3012
  const keepalive = setInterval(() => {}, 1000);
2973
3013
  const shutdown = () => {
@@ -2978,52 +3018,83 @@ ${mf.allowed_tools.map((t) => ` - ${t}`).join(`
2978
3018
  process.on("SIGTERM", shutdown);
2979
3019
  process.on("SIGINT", shutdown);
2980
3020
  }
2981
- async function emitInboxWelcome(server, mcpLog, lookbackMs) {
2982
- const sinceIso = new Date(Date.now() - lookbackMs).toISOString();
2983
- const path = `/v1/inbox?since=${encodeURIComponent(sinceIso)}&limit=20`;
2984
- let body;
3021
+ async function emitMeshWelcome(server, mcpLog) {
3022
+ const { readSessionTokenFromEnv: readSessionTokenFromEnv2 } = await Promise.resolve().then(() => (init_token(), exports_token));
3023
+ const sessionToken = readSessionTokenFromEnv2();
3024
+ let selfDisplayName;
3025
+ let selfSessionPubkey;
3026
+ let selfMeshSlug;
3027
+ let selfRole;
3028
+ if (sessionToken) {
3029
+ try {
3030
+ const { status, body } = await daemonGet("/v1/sessions/me", { sessionToken });
3031
+ if (status === 200 && body?.session) {
3032
+ selfDisplayName = body.session.displayName;
3033
+ selfMeshSlug = body.session.mesh;
3034
+ selfRole = body.session.role;
3035
+ selfSessionPubkey = body.session.presence?.sessionPubkey;
3036
+ }
3037
+ } catch (e) {
3038
+ mcpLog("welcome_self_lookup_failed", { err: String(e) });
3039
+ }
3040
+ }
3041
+ let peerCount = -1;
3042
+ let peerNames = [];
2985
3043
  try {
2986
- const res = await daemonGet(path);
2987
- if (res.status !== 200) {
2988
- mcpLog("welcome_skip", { reason: "ipc_status", status: res.status });
2989
- return;
3044
+ const path = selfMeshSlug ? `/v1/peers?mesh=${encodeURIComponent(selfMeshSlug)}` : "/v1/peers";
3045
+ const { status, body } = await daemonGet(path, { sessionToken });
3046
+ if (status === 200 && Array.isArray(body?.peers)) {
3047
+ const peers = body.peers;
3048
+ const real = peers.filter((p) => p.peerRole !== "control-plane" && p.pubkey !== selfSessionPubkey);
3049
+ peerCount = real.length;
3050
+ peerNames = real.map((p) => String(p.displayName ?? "unknown")).filter((n, i, arr) => arr.indexOf(n) === i).slice(0, 5);
2990
3051
  }
2991
- body = res.body;
2992
3052
  } catch (e) {
2993
- mcpLog("welcome_skip", { reason: "ipc_threw", err: String(e) });
2994
- return;
2995
- }
2996
- const items = Array.isArray(body.items) ? body.items : [];
2997
- if (items.length === 0) {
2998
- mcpLog("welcome_skip", { reason: "empty" });
2999
- return;
3000
- }
3001
- const byMesh = new Map;
3002
- for (const it of items) {
3003
- const meshSlug = String(it.mesh ?? "");
3004
- const arr = byMesh.get(meshSlug) ?? [];
3005
- arr.push(it);
3006
- byMesh.set(meshSlug, arr);
3007
- }
3008
- const preview = items.slice(0, 3).map((it) => {
3009
- const sender = String(it.sender_name ?? "unknown");
3010
- const senderPub = String(it.sender_pubkey ?? "").slice(0, 8);
3011
- const meshSlug = String(it.mesh ?? "");
3012
- const bodyText = (typeof it.body === "string" ? it.body : "(encrypted)").slice(0, 60);
3013
- const ts = String(it.received_at ?? "");
3014
- const time = ts ? new Date(ts).toLocaleTimeString() : "";
3015
- const tag = sender !== senderPub ? `${sender} (${senderPub})` : senderPub;
3016
- return ` ${tag} [${meshSlug}] ${time}: ${bodyText}`;
3017
- }).join(`
3053
+ mcpLog("welcome_peers_lookup_failed", { err: String(e) });
3054
+ }
3055
+ const sinceIso = new Date(Date.now() - 86400000).toISOString();
3056
+ const inboxPath = selfMeshSlug ? `/v1/inbox?mesh=${encodeURIComponent(selfMeshSlug)}&since=${encodeURIComponent(sinceIso)}&limit=20` : `/v1/inbox?since=${encodeURIComponent(sinceIso)}&limit=20`;
3057
+ let inboxItems = [];
3058
+ try {
3059
+ const { status, body } = await daemonGet(inboxPath, { sessionToken });
3060
+ if (status === 200 && Array.isArray(body?.items)) {
3061
+ inboxItems = body.items;
3062
+ }
3063
+ } catch (e) {
3064
+ mcpLog("welcome_inbox_lookup_failed", { err: String(e) });
3065
+ }
3066
+ const lines = [];
3067
+ const idTag = selfDisplayName ? `${selfDisplayName}${selfSessionPubkey ? ` (${selfSessionPubkey.slice(0, 8)})` : ""}${selfRole ? ` [${selfRole}]` : ""}` : "session";
3068
+ const meshTag = selfMeshSlug ? ` on mesh \`${selfMeshSlug}\`` : "";
3069
+ lines.push(`\uD83C\uDF10 [welcome] claudemesh connected you are **${idTag}**${meshTag}.`);
3070
+ if (peerCount === 0) {
3071
+ lines.push(`\uD83D\uDC65 No other peers online right now.`);
3072
+ } else if (peerCount > 0) {
3073
+ const namesPreview = peerNames.join(", ");
3074
+ const more = peerCount > peerNames.length ? ` …and ${peerCount - peerNames.length} more` : "";
3075
+ lines.push(`\uD83D\uDC65 ${peerCount} peer${peerCount === 1 ? "" : "s"} online: ${namesPreview}${more}`);
3076
+ } else {
3077
+ lines.push(`\uD83D\uDC65 Peer list unavailable (daemon query failed).`);
3078
+ }
3079
+ if (inboxItems.length === 0) {
3080
+ lines.push(`\uD83D\uDCE5 Inbox is empty (last 24h).`);
3081
+ } else {
3082
+ lines.push(`\uD83D\uDCE5 ${inboxItems.length} message${inboxItems.length === 1 ? "" : "s"} in inbox (last 24h):`);
3083
+ for (const it of inboxItems.slice(0, 3)) {
3084
+ const sender = String(it.sender_name ?? "unknown");
3085
+ const senderPub = String(it.sender_pubkey ?? "").slice(0, 8);
3086
+ const tag = sender !== senderPub ? `${sender} (${senderPub})` : senderPub;
3087
+ const bodyText = (typeof it.body === "string" ? it.body : "(encrypted)").slice(0, 60);
3088
+ const time = it.received_at ? new Date(String(it.received_at)).toLocaleTimeString() : "";
3089
+ lines.push(` ${tag} ${time}: ${bodyText}`);
3090
+ }
3091
+ if (inboxItems.length > 3)
3092
+ lines.push(` …and ${inboxItems.length - 3} more`);
3093
+ }
3094
+ lines.push(`\uD83D\uDCA1 Use: \`claudemesh peer list\` · \`claudemesh send <peer> <msg>\` · \`claudemesh inbox\``);
3095
+ lines.push(`\uD83D\uDCDA Read the \`claudemesh\` skill (SKILL.md) for full CLI / channel / inbox reference if not yet in context.`);
3096
+ const content = lines.join(`
3018
3097
  `);
3019
- const remainder = items.length > 3 ? `
3020
- …and ${items.length - 3} more` : "";
3021
- const meshList = [...byMesh.keys()].filter(Boolean).join(", ");
3022
- const header = `\uD83D\uDCE5 [welcome] ${items.length} message${items.length === 1 ? "" : "s"} in inbox from the last 24h${meshList ? ` (${meshList})` : ""}`;
3023
- const footer = `
3024
- Run \`claudemesh inbox\` for full content.`;
3025
- const content = `${header}
3026
- ${preview}${remainder}${footer}`;
3027
3098
  try {
3028
3099
  await server.notification({
3029
3100
  method: "notifications/claude/channel",
@@ -3031,13 +3102,22 @@ ${preview}${remainder}${footer}`;
3031
3102
  content,
3032
3103
  meta: {
3033
3104
  kind: "welcome",
3034
- unread_count: items.length,
3035
- meshes: [...byMesh.keys()],
3036
- latest_message_ids: items.slice(0, 10).map((it) => String(it.id ?? ""))
3105
+ self_display_name: selfDisplayName ?? "",
3106
+ self_session_pubkey: selfSessionPubkey ?? "",
3107
+ self_role: selfRole ?? "",
3108
+ mesh_slug: selfMeshSlug ?? "",
3109
+ peer_count: peerCount >= 0 ? peerCount : null,
3110
+ peer_names: peerNames,
3111
+ unread_count: inboxItems.length,
3112
+ latest_message_ids: inboxItems.slice(0, 10).map((it) => String(it.id ?? ""))
3037
3113
  }
3038
3114
  }
3039
3115
  });
3040
- mcpLog("welcome_emitted", { count: items.length, meshes: [...byMesh.keys()] });
3116
+ mcpLog("welcome_emitted", {
3117
+ mesh: selfMeshSlug ?? "",
3118
+ peer_count: peerCount,
3119
+ unread_count: inboxItems.length
3120
+ });
3041
3121
  } catch (err) {
3042
3122
  mcpLog("welcome_emit_failed", { err: String(err) });
3043
3123
  }
@@ -3154,4 +3234,4 @@ startMcpServer().catch((err) => {
3154
3234
  process.exit(1);
3155
3235
  });
3156
3236
 
3157
- //# debugId=BF4B7D5AF5C8B94C64756E2164756E21
3237
+ //# debugId=98C6934FA6FF511764756E2164756E21