claudemesh-cli 0.9.2 → 0.9.4

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 +581 -207
  2. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -4,6 +4,7 @@ var __create = Object.create;
4
4
  var __getProtoOf = Object.getPrototypeOf;
5
5
  var __defProp = Object.defineProperty;
6
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
7
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
9
  var __toESM = (mod, isNodeMode, target) => {
9
10
  target = mod != null ? __create(__getProtoOf(mod)) : {};
@@ -16,6 +17,20 @@ var __toESM = (mod, isNodeMode, target) => {
16
17
  });
17
18
  return to;
18
19
  };
20
+ var __moduleCache = /* @__PURE__ */ new WeakMap;
21
+ var __toCommonJS = (from) => {
22
+ var entry = __moduleCache.get(from), desc;
23
+ if (entry)
24
+ return entry;
25
+ entry = __defProp({}, "__esModule", { value: true });
26
+ if (from && typeof from === "object" || typeof from === "function")
27
+ __getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
28
+ get: () => from[key],
29
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
30
+ }));
31
+ __moduleCache.set(from, entry);
32
+ return entry;
33
+ };
19
34
  var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
20
35
  var __export = (target, all) => {
21
36
  for (var name in all)
@@ -40047,6 +40062,201 @@ function deriveHttpUrl(wssUrl) {
40047
40062
  return url.toString().replace(/\/$/, "");
40048
40063
  }
40049
40064
 
40065
+ // src/tui/colors.ts
40066
+ function moveTo(row, col) {
40067
+ return isTTY ? `\x1B[${row};${col}H` : "";
40068
+ }
40069
+ function visibleLength(s) {
40070
+ return s.replace(/\x1b\[[^m]*m/g, "").length;
40071
+ }
40072
+ var isTTY, esc2 = (code) => (s) => isTTY ? `${code}${s}\x1B[0m` : s, orange, clay, amber, bold2, dim, green, yellow, red, cyan2, boldOrange, HIDE_CURSOR, SHOW_CURSOR, CLEAR_SCREEN, CLEAR_LINE;
40073
+ var init_colors = __esm(() => {
40074
+ isTTY = process.stdout.isTTY && !process.env.NO_COLOR && process.env.TERM !== "dumb";
40075
+ orange = esc2("\x1B[38;5;208m");
40076
+ clay = esc2("\x1B[38;5;173m");
40077
+ amber = esc2("\x1B[38;5;214m");
40078
+ bold2 = esc2("\x1B[1m");
40079
+ dim = esc2("\x1B[2m");
40080
+ green = esc2("\x1B[32m");
40081
+ yellow = esc2("\x1B[33m");
40082
+ red = esc2("\x1B[31m");
40083
+ cyan2 = esc2("\x1B[36m");
40084
+ boldOrange = esc2("\x1B[1m\x1B[38;5;208m");
40085
+ HIDE_CURSOR = isTTY ? "\x1B[?25l" : "";
40086
+ SHOW_CURSOR = isTTY ? "\x1B[?25h" : "";
40087
+ CLEAR_SCREEN = isTTY ? "\x1B[2J\x1B[H" : "";
40088
+ CLEAR_LINE = isTTY ? "\x1B[K" : "";
40089
+ });
40090
+
40091
+ // package.json
40092
+ var package_default;
40093
+ var init_package = __esm(() => {
40094
+ package_default = {
40095
+ name: "claudemesh-cli",
40096
+ version: "0.9.4",
40097
+ description: "Claude Code MCP client for claudemesh — peer mesh messaging between Claude sessions.",
40098
+ keywords: [
40099
+ "claude-code",
40100
+ "mcp",
40101
+ "model-context-protocol",
40102
+ "claudemesh",
40103
+ "peer-messaging",
40104
+ "multi-agent"
40105
+ ],
40106
+ author: "Alejandro Gutiérrez",
40107
+ license: "MIT",
40108
+ homepage: "https://claudemesh.com",
40109
+ repository: {
40110
+ type: "git",
40111
+ url: "https://github.com/alezmad/claudemesh.git",
40112
+ directory: "apps/cli"
40113
+ },
40114
+ type: "module",
40115
+ bin: {
40116
+ claudemesh: "./dist/index.js"
40117
+ },
40118
+ files: [
40119
+ "dist",
40120
+ "README.md",
40121
+ "LICENSE"
40122
+ ],
40123
+ publishConfig: {
40124
+ access: "public"
40125
+ },
40126
+ scripts: {
40127
+ build: 'bun build src/index.ts --target=node --outfile dist/index.js --banner "#!/usr/bin/env node" && chmod +x dist/index.js',
40128
+ clean: "git clean -xdf .cache .turbo dist node_modules",
40129
+ dev: "bun --hot src/index.ts",
40130
+ start: "bun src/index.ts",
40131
+ format: "prettier --check . --ignore-path ../../.gitignore",
40132
+ lint: "eslint",
40133
+ prepublishOnly: "bun run build",
40134
+ test: "vitest run",
40135
+ typecheck: "tsc --noEmit"
40136
+ },
40137
+ prettier: "@turbostarter/prettier-config",
40138
+ engines: {
40139
+ node: ">=20"
40140
+ },
40141
+ dependencies: {
40142
+ "@modelcontextprotocol/sdk": "1.27.1",
40143
+ citty: "0.2.2",
40144
+ "libsodium-wrappers": "0.7.15",
40145
+ ws: "8.20.0",
40146
+ zod: "4.1.13"
40147
+ },
40148
+ devDependencies: {
40149
+ "@turbostarter/eslint-config": "workspace:*",
40150
+ "@turbostarter/prettier-config": "workspace:*",
40151
+ "@turbostarter/tsconfig": "workspace:*",
40152
+ "@turbostarter/vitest-config": "workspace:*",
40153
+ "@types/libsodium-wrappers": "0.7.14",
40154
+ "@types/ws": "8.5.13",
40155
+ eslint: "catalog:",
40156
+ prettier: "catalog:",
40157
+ typescript: "catalog:",
40158
+ vitest: "catalog:"
40159
+ }
40160
+ };
40161
+ });
40162
+
40163
+ // src/version.ts
40164
+ var exports_version = {};
40165
+ __export(exports_version, {
40166
+ VERSION: () => VERSION
40167
+ });
40168
+ var VERSION;
40169
+ var init_version = __esm(() => {
40170
+ init_package();
40171
+ VERSION = package_default.version;
40172
+ });
40173
+
40174
+ // src/tui/spinner.ts
40175
+ function edgeChar(dx, dy) {
40176
+ const a = Math.abs(dx), b = Math.abs(dy);
40177
+ if (b < a * 0.4)
40178
+ return "-";
40179
+ if (a < b * 0.4)
40180
+ return "|";
40181
+ return dx > 0 === dy > 0 ? "\\" : "/";
40182
+ }
40183
+ function drawLine(grid, x0, y0, x1, y1) {
40184
+ const dx = x1 - x0, dy = y1 - y0;
40185
+ const steps = Math.max(Math.abs(dx), Math.abs(dy));
40186
+ for (let s = 1;s < steps; s++) {
40187
+ const x = Math.round(x0 + dx * s / steps);
40188
+ const y = Math.round(y0 + dy * s / steps);
40189
+ if (y >= 0 && y < H && x >= 0 && x < W) {
40190
+ const c = grid[y][x];
40191
+ if (c === " ")
40192
+ grid[y][x] = edgeChar(dx, dy);
40193
+ else if (c !== edgeChar(dx, dy) && c !== "●")
40194
+ grid[y][x] = "+";
40195
+ }
40196
+ }
40197
+ }
40198
+ function buildFrame(i) {
40199
+ const grid = Array.from({ length: H }, () => Array(W).fill(" "));
40200
+ const base = i / TOTAL * Math.PI * 2;
40201
+ const nodes = [0, 1, 2, 3].map((n) => {
40202
+ const a = base + n * Math.PI / 2 - Math.PI / 2;
40203
+ return { x: Math.round(CX + RX * Math.cos(a)), y: Math.round(CY + RY * Math.sin(a)) };
40204
+ });
40205
+ for (let a = 0;a < 4; a++)
40206
+ for (let b = a + 1;b < 4; b++)
40207
+ drawLine(grid, nodes[a].x, nodes[a].y, nodes[b].x, nodes[b].y);
40208
+ for (const { x, y } of nodes)
40209
+ if (y >= 0 && y < H && x >= 0 && x < W)
40210
+ grid[y][x] = "●";
40211
+ return grid.map((r) => r.join(""));
40212
+ }
40213
+ function colorize(line) {
40214
+ return line.replace(/●/g, boldOrange("●")).replace(/[-|/\\+]/g, (c) => dim(clay(c)));
40215
+ }
40216
+ function getFrame(index) {
40217
+ return RAW_FRAMES[index % RAW_FRAMES.length].map(colorize);
40218
+ }
40219
+ function createSpinner(opts) {
40220
+ let frame = 0;
40221
+ let timer = null;
40222
+ return {
40223
+ start() {
40224
+ if (timer)
40225
+ return;
40226
+ timer = setInterval(() => {
40227
+ opts.render(getFrame(frame++));
40228
+ }, opts.interval ?? 70);
40229
+ opts.render(getFrame(frame++));
40230
+ },
40231
+ stop() {
40232
+ if (timer) {
40233
+ clearInterval(timer);
40234
+ timer = null;
40235
+ }
40236
+ },
40237
+ get isRunning() {
40238
+ return timer !== null;
40239
+ }
40240
+ };
40241
+ }
40242
+ var W = 7, H = 5, CX = 3, CY = 2, RX = 3, RY = 2, TOTAL = 12, seen, RAW_FRAMES, FRAME_COUNT, FRAME_HEIGHT;
40243
+ var init_spinner = __esm(() => {
40244
+ init_colors();
40245
+ seen = new Set;
40246
+ RAW_FRAMES = [];
40247
+ for (let i = 0;i < TOTAL; i++) {
40248
+ const f = buildFrame(i);
40249
+ const key = f.join(`
40250
+ `);
40251
+ if (!seen.has(key)) {
40252
+ seen.add(key);
40253
+ RAW_FRAMES.push(f);
40254
+ }
40255
+ }
40256
+ FRAME_COUNT = RAW_FRAMES.length;
40257
+ FRAME_HEIGHT = H;
40258
+ });
40259
+
40050
40260
  // ../../node_modules/qrcode-terminal/vendor/QRCode/QRMode.js
40051
40261
  var require_QRMode = __commonJS((exports, module) => {
40052
40262
  module.exports = {
@@ -53713,6 +53923,86 @@ function generatePairingCode() {
53713
53923
  return Array.from(bytes, (b) => CHARS[b % CHARS.length]).join("");
53714
53924
  }
53715
53925
  // src/commands/launch.ts
53926
+ init_colors();
53927
+
53928
+ // src/tui/screen.ts
53929
+ init_version();
53930
+ init_colors();
53931
+ function termSize() {
53932
+ return {
53933
+ cols: process.stdout.columns || 80,
53934
+ rows: process.stdout.rows || 24
53935
+ };
53936
+ }
53937
+ function center(s) {
53938
+ const { cols } = termSize();
53939
+ const vis = visibleLength(s);
53940
+ const pad = Math.max(0, Math.floor((cols - vis) / 2));
53941
+ return " ".repeat(pad) + s;
53942
+ }
53943
+ function writeCentered(row, s) {
53944
+ process.stdout.write(moveTo(row, 1) + center(s) + CLEAR_LINE);
53945
+ }
53946
+ function drawTopBar() {
53947
+ const { cols } = termSize();
53948
+ const left = orange(`claudemesh v${VERSION}`);
53949
+ const right = dim("claudemesh.com");
53950
+ const leftVis = visibleLength(left);
53951
+ const rightVis = visibleLength(right);
53952
+ const gap = Math.max(1, cols - leftVis - rightVis);
53953
+ process.stdout.write(moveTo(1, 1) + left + " ".repeat(gap) + right + CLEAR_LINE);
53954
+ }
53955
+ function enterFullScreen() {
53956
+ process.stdout.write(HIDE_CURSOR + CLEAR_SCREEN);
53957
+ drawTopBar();
53958
+ }
53959
+ function exitFullScreen() {
53960
+ process.stdout.write(SHOW_CURSOR + CLEAR_SCREEN);
53961
+ }
53962
+ async function menuSelect(opts) {
53963
+ const { items, title, row } = opts;
53964
+ let selected = opts.defaultIndex ?? 0;
53965
+ writeCentered(row, bold2(orange(title)));
53966
+ const renderItems = () => {
53967
+ for (let i = 0;i < items.length; i++) {
53968
+ const prefix = i === selected ? boldOrange("▸ ") : " ";
53969
+ const text2 = i === selected ? bold2(items[i]) : dim(items[i]);
53970
+ writeCentered(row + 1 + i, prefix + text2 + CLEAR_LINE);
53971
+ }
53972
+ };
53973
+ renderItems();
53974
+ return new Promise((resolve2) => {
53975
+ const stdin = process.stdin;
53976
+ const wasRaw = stdin.isRaw;
53977
+ stdin.setRawMode(true);
53978
+ stdin.resume();
53979
+ stdin.setEncoding("utf8");
53980
+ const onData = (key) => {
53981
+ if (key === "\x1B[A" || key === "k") {
53982
+ selected = (selected - 1 + items.length) % items.length;
53983
+ renderItems();
53984
+ } else if (key === "\x1B[B" || key === "j") {
53985
+ selected = (selected + 1) % items.length;
53986
+ renderItems();
53987
+ } else if (key === "\r" || key === `
53988
+ `) {
53989
+ stdin.removeListener("data", onData);
53990
+ stdin.setRawMode(wasRaw ?? false);
53991
+ stdin.pause();
53992
+ resolve2(selected);
53993
+ } else if (key === "\x03") {
53994
+ stdin.removeListener("data", onData);
53995
+ stdin.setRawMode(wasRaw ?? false);
53996
+ exitFullScreen();
53997
+ process.exit(0);
53998
+ }
53999
+ };
54000
+ stdin.on("data", onData);
54001
+ });
54002
+ }
54003
+
54004
+ // src/commands/launch.ts
54005
+ init_spinner();
53716
54006
  async function pickMesh(meshes) {
53717
54007
  if (meshes.length === 1)
53718
54008
  return meshes[0];
@@ -53755,21 +54045,21 @@ function askLine(prompt) {
53755
54045
  }
53756
54046
  async function confirmPermissions() {
53757
54047
  const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
53758
- const bold2 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
53759
- const dim = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
53760
- const yellow = (s) => useColor ? `\x1B[33m${s}\x1B[39m` : s;
53761
- console.log(yellow(bold2(" Autonomous mode")));
54048
+ const bold3 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
54049
+ const dim2 = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
54050
+ const yellow2 = (s) => useColor ? `\x1B[33m${s}\x1B[39m` : s;
54051
+ console.log(yellow2(bold3(" Autonomous mode")));
53762
54052
  console.log("");
53763
54053
  console.log(" Claude will run with --dangerously-skip-permissions, bypassing");
53764
54054
  console.log(" ALL permission prompts — not just claudemesh tools.");
53765
54055
  console.log(" Peers exchange text only — no file access, no tool calls.");
53766
54056
  console.log("");
53767
- console.log(dim(" Without -y: only claudemesh tools are pre-approved (via allowedTools)."));
53768
- console.log(dim(" Use -y for autonomous agents. Omit it for shared/multi-person meshes."));
54057
+ console.log(dim2(" Without -y: only claudemesh tools are pre-approved (via allowedTools)."));
54058
+ console.log(dim2(" Use -y for autonomous agents. Omit it for shared/multi-person meshes."));
53769
54059
  console.log("");
53770
54060
  const rl = createInterface({ input: process.stdin, output: process.stdout });
53771
54061
  return new Promise((resolve2, reject) => {
53772
- rl.question(` ${bold2("Continue?")} [Y/n] `, (answer) => {
54062
+ rl.question(` ${bold3("Continue?")} [Y/n] `, (answer) => {
53773
54063
  rl.close();
53774
54064
  const a = answer.trim().toLowerCase();
53775
54065
  if (a === "" || a === "y" || a === "yes") {
@@ -53786,12 +54076,12 @@ async function confirmPermissions() {
53786
54076
  }
53787
54077
  function printBanner(name, meshSlug, role, groups, messageMode) {
53788
54078
  const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
53789
- const dim = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
53790
- const bold2 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
54079
+ const dim2 = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
54080
+ const bold3 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
53791
54081
  const roleSuffix = role ? ` (${role})` : "";
53792
54082
  const groupTags = groups.length ? " [" + groups.map((g) => `@${g.name}${g.role ? `:${g.role}` : ""}`).join(", ") + "]" : "";
53793
54083
  const rule = "─".repeat(60);
53794
- console.log(bold2(`claudemesh launch`) + dim(` — as ${name}${roleSuffix} on ${meshSlug}${groupTags} [${messageMode}]`));
54084
+ console.log(bold3(`claudemesh launch`) + dim2(` — as ${name}${roleSuffix} on ${meshSlug}${groupTags} [${messageMode}]`));
53795
54085
  console.log(rule);
53796
54086
  if (messageMode === "push") {
53797
54087
  console.log("Peer messages arrive as <channel> reminders in real-time.");
@@ -53801,10 +54091,48 @@ function printBanner(name, meshSlug, role, groups, messageMode) {
53801
54091
  console.log("Messages off. Use check_messages to poll manually.");
53802
54092
  }
53803
54093
  console.log("Peers send text only — they cannot call tools or read files.");
53804
- console.log(dim(`Config: ${getConfigPath()}`));
54094
+ console.log(dim2(`Config: ${getConfigPath()}`));
53805
54095
  console.log(rule);
53806
54096
  console.log("");
53807
54097
  }
54098
+ async function showLaunchSplash(name, meshSlug, role, groups, messageMode) {
54099
+ if (!process.stdout.isTTY)
54100
+ return;
54101
+ const { rows } = termSize();
54102
+ enterFullScreen();
54103
+ drawTopBar();
54104
+ const logoTop = Math.floor((rows - FRAME_HEIGHT - 10) / 2);
54105
+ const brandRow = logoTop + FRAME_HEIGHT + 1;
54106
+ const subtitleRow = brandRow + 1;
54107
+ const infoRow = subtitleRow + 2;
54108
+ writeCentered(brandRow, boldOrange("claudemesh"));
54109
+ writeCentered(subtitleRow, dim("peer mesh for Claude Code"));
54110
+ const spinner = createSpinner({
54111
+ render(lines) {
54112
+ for (let i = 0;i < lines.length; i++) {
54113
+ writeCentered(logoTop + i, lines[i]);
54114
+ }
54115
+ },
54116
+ interval: 70
54117
+ });
54118
+ spinner.start();
54119
+ const roleSuffix = role ? ` (${role})` : "";
54120
+ const groupStr = groups.length ? " " + groups.map((g) => dim(`@${g.name}`)).join(", ") : "";
54121
+ const steps = [
54122
+ { label: `Identity`, value: `${name}${roleSuffix}` },
54123
+ { label: `Mesh`, value: meshSlug },
54124
+ { label: `Messages`, value: messageMode }
54125
+ ];
54126
+ for (let i = 0;i < steps.length; i++) {
54127
+ await new Promise((r) => setTimeout(r, 300));
54128
+ writeCentered(infoRow + i, `${steps[i].label} ${green("✓")} ${steps[i].value}${i === 0 ? groupStr : ""}`);
54129
+ }
54130
+ await new Promise((r) => setTimeout(r, 400));
54131
+ writeCentered(infoRow + steps.length + 1, dim("Launching Claude Code..."));
54132
+ await new Promise((r) => setTimeout(r, 600));
54133
+ spinner.stop();
54134
+ exitFullScreen();
54135
+ }
53808
54136
  async function runLaunch(flags, rawArgs) {
53809
54137
  const dashIdx = rawArgs.indexOf("--");
53810
54138
  const claudePassthrough = dashIdx >= 0 ? rawArgs.slice(dashIdx + 1) : [];
@@ -53854,22 +54182,22 @@ async function runLaunch(flags, rawArgs) {
53854
54182
  let justSynced = false;
53855
54183
  if (config2.meshes.length === 0 && !args.joinLink) {
53856
54184
  const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
53857
- const bold2 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
53858
- const dim = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
53859
- const green = (s) => useColor ? `\x1B[32m${s}\x1B[39m` : s;
54185
+ const bold3 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
54186
+ const dim2 = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
54187
+ const green2 = (s) => useColor ? `\x1B[32m${s}\x1B[39m` : s;
53860
54188
  const code = generatePairingCode();
53861
54189
  const listener = await startCallbackListener();
53862
54190
  const url = `https://claudemesh.com/cli-auth?port=${listener.port}&code=${code}&action=sync`;
53863
54191
  console.log(`
53864
- ${bold2("Welcome to claudemesh!")} No meshes found.`);
54192
+ ${bold3("Welcome to claudemesh!")} No meshes found.`);
53865
54193
  console.log(` Opening browser to sign in...
53866
54194
  `);
53867
54195
  const opened = await openBrowser(url);
53868
54196
  if (!opened) {
53869
54197
  console.log(` Couldn't open browser automatically.`);
53870
54198
  }
53871
- console.log(` ${dim(`Visit: ${url}`)}`);
53872
- console.log(` ${dim(`Or join with invite: claudemesh launch --join <url>`)}
54199
+ console.log(` ${dim2(`Visit: ${url}`)}`);
54200
+ console.log(` ${dim2(`Or join with invite: claudemesh launch --join <url>`)}
53873
54201
  `);
53874
54202
  const manualPromise = new Promise((resolve2) => {
53875
54203
  const rl = createInterface({ input: process.stdin, output: process.stdout });
@@ -53915,7 +54243,7 @@ async function runLaunch(flags, rawArgs) {
53915
54243
  saveConfig2(config2);
53916
54244
  justSynced = true;
53917
54245
  console.log(`
53918
- ${green("✓")} Synced ${result.meshes.length} mesh(es): ${result.meshes.map((m) => m.slug).join(", ")}
54246
+ ${green2("✓")} Synced ${result.meshes.length} mesh(es): ${result.meshes.map((m) => m.slug).join(", ")}
53919
54247
  `);
53920
54248
  }
53921
54249
  if (config2.meshes.length === 0) {
@@ -54028,9 +54356,11 @@ async function runLaunch(flags, rawArgs) {
54028
54356
  writeFileSync4(join4(tmpDir, "config.json"), JSON.stringify(sessionConfig, null, 2) + `
54029
54357
  `, "utf-8");
54030
54358
  if (!args.quiet) {
54359
+ await showLaunchSplash(displayName, mesh.slug, role, parsedGroups, messageMode);
54031
54360
  printBanner(displayName, mesh.slug, role, parsedGroups, messageMode);
54032
54361
  if (!args.skipPermConfirm) {
54033
54362
  await confirmPermissions();
54363
+ args.skipPermConfirm = true;
54034
54364
  }
54035
54365
  }
54036
54366
  const meshMcpEntries = [];
@@ -54099,7 +54429,21 @@ async function runLaunch(flags, rawArgs) {
54099
54429
  ...filtered
54100
54430
  ];
54101
54431
  const isWindows = process.platform === "win32";
54102
- const child = spawn("claude", claudeArgs, {
54432
+ let claudeBin = "claude";
54433
+ if (!isWindows) {
54434
+ const candidates = [
54435
+ join4(homedir4(), ".local", "bin", "claude"),
54436
+ "/usr/local/bin/claude",
54437
+ join4(homedir4(), ".claude", "bin", "claude")
54438
+ ];
54439
+ for (const c of candidates) {
54440
+ if (existsSync3(c)) {
54441
+ claudeBin = c;
54442
+ break;
54443
+ }
54444
+ }
54445
+ }
54446
+ const child = spawn(claudeBin, claudeArgs, {
54103
54447
  stdio: "inherit",
54104
54448
  shell: isWindows,
54105
54449
  env: {
@@ -54160,79 +54504,7 @@ async function runLaunch(flags, rawArgs) {
54160
54504
  // src/commands/status.ts
54161
54505
  import { statSync as statSync2, existsSync as existsSync4 } from "node:fs";
54162
54506
  init_config();
54163
- // package.json
54164
- var package_default = {
54165
- name: "claudemesh-cli",
54166
- version: "0.9.2",
54167
- description: "Claude Code MCP client for claudemesh — peer mesh messaging between Claude sessions.",
54168
- keywords: [
54169
- "claude-code",
54170
- "mcp",
54171
- "model-context-protocol",
54172
- "claudemesh",
54173
- "peer-messaging",
54174
- "multi-agent"
54175
- ],
54176
- author: "Alejandro Gutiérrez",
54177
- license: "MIT",
54178
- homepage: "https://claudemesh.com",
54179
- repository: {
54180
- type: "git",
54181
- url: "https://github.com/alezmad/claudemesh.git",
54182
- directory: "apps/cli"
54183
- },
54184
- type: "module",
54185
- bin: {
54186
- claudemesh: "./dist/index.js"
54187
- },
54188
- files: [
54189
- "dist",
54190
- "README.md",
54191
- "LICENSE"
54192
- ],
54193
- publishConfig: {
54194
- access: "public"
54195
- },
54196
- scripts: {
54197
- build: 'bun build src/index.ts --target=node --outfile dist/index.js --banner "#!/usr/bin/env node" && chmod +x dist/index.js',
54198
- clean: "git clean -xdf .cache .turbo dist node_modules",
54199
- dev: "bun --hot src/index.ts",
54200
- start: "bun src/index.ts",
54201
- format: "prettier --check . --ignore-path ../../.gitignore",
54202
- lint: "eslint",
54203
- prepublishOnly: "bun run build",
54204
- test: "vitest run",
54205
- typecheck: "tsc --noEmit"
54206
- },
54207
- prettier: "@turbostarter/prettier-config",
54208
- engines: {
54209
- node: ">=20"
54210
- },
54211
- dependencies: {
54212
- "@modelcontextprotocol/sdk": "1.27.1",
54213
- citty: "0.2.2",
54214
- "libsodium-wrappers": "0.7.15",
54215
- ws: "8.20.0",
54216
- zod: "4.1.13"
54217
- },
54218
- devDependencies: {
54219
- "@turbostarter/eslint-config": "workspace:*",
54220
- "@turbostarter/prettier-config": "workspace:*",
54221
- "@turbostarter/tsconfig": "workspace:*",
54222
- "@turbostarter/vitest-config": "workspace:*",
54223
- "@types/libsodium-wrappers": "0.7.14",
54224
- "@types/ws": "8.5.13",
54225
- eslint: "catalog:",
54226
- prettier: "catalog:",
54227
- typescript: "catalog:",
54228
- vitest: "catalog:"
54229
- }
54230
- };
54231
-
54232
- // src/version.ts
54233
- var VERSION = package_default.version;
54234
-
54235
- // src/commands/status.ts
54507
+ init_version();
54236
54508
  async function probeBroker(url, timeoutMs = 4000) {
54237
54509
  return new Promise((resolve2) => {
54238
54510
  const ws = new wrapper_default(url);
@@ -54257,9 +54529,9 @@ async function probeBroker(url, timeoutMs = 4000) {
54257
54529
  }
54258
54530
  async function runStatus() {
54259
54531
  const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
54260
- const dim = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
54261
- const green = (s) => useColor ? `\x1B[32m${s}\x1B[39m` : s;
54262
- const red = (s) => useColor ? `\x1B[31m${s}\x1B[39m` : s;
54532
+ const dim2 = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
54533
+ const green2 = (s) => useColor ? `\x1B[32m${s}\x1B[39m` : s;
54534
+ const red2 = (s) => useColor ? `\x1B[31m${s}\x1B[39m` : s;
54263
54535
  console.log(`claudemesh status (v${VERSION})`);
54264
54536
  console.log("─".repeat(60));
54265
54537
  const configPath = getConfigPath();
@@ -54273,7 +54545,7 @@ async function runStatus() {
54273
54545
  const config2 = loadConfig();
54274
54546
  if (config2.meshes.length === 0) {
54275
54547
  console.log("");
54276
- console.log(dim("No meshes joined. Run `claudemesh join <invite-url>` to get started."));
54548
+ console.log(dim2("No meshes joined. Run `claudemesh join <invite-url>` to get started."));
54277
54549
  process.exit(0);
54278
54550
  }
54279
54551
  console.log("");
@@ -54290,29 +54562,30 @@ async function runStatus() {
54290
54562
  error: probe.error
54291
54563
  });
54292
54564
  if (probe.ok) {
54293
- console.log(green("reachable"));
54565
+ console.log(green2("reachable"));
54294
54566
  } else {
54295
- console.log(red(`unreachable (${probe.error})`));
54567
+ console.log(red2(`unreachable (${probe.error})`));
54296
54568
  }
54297
54569
  }
54298
54570
  console.log("");
54299
54571
  for (const r of results) {
54300
- console.log(dim(` ${r.slug}: pubkey ${r.pubkey.slice(0, 16)}…`));
54572
+ console.log(dim2(` ${r.slug}: pubkey ${r.pubkey.slice(0, 16)}…`));
54301
54573
  }
54302
54574
  const allOk = results.every((r) => r.reachable);
54303
54575
  console.log("");
54304
54576
  if (allOk) {
54305
- console.log(green("All meshes reachable."));
54577
+ console.log(green2("All meshes reachable."));
54306
54578
  process.exit(0);
54307
54579
  } else {
54308
54580
  const broken = results.filter((r) => !r.reachable).length;
54309
- console.log(red(`${broken} of ${results.length} mesh(es) unreachable.`));
54581
+ console.log(red2(`${broken} of ${results.length} mesh(es) unreachable.`));
54310
54582
  process.exit(1);
54311
54583
  }
54312
54584
  }
54313
54585
 
54314
54586
  // src/commands/doctor.ts
54315
54587
  init_config();
54588
+ init_version();
54316
54589
  import { existsSync as existsSync5, readFileSync as readFileSync4, statSync as statSync3 } from "node:fs";
54317
54590
  import { homedir as homedir5, platform as platform2 } from "node:os";
54318
54591
  import { join as join5 } from "node:path";
@@ -54461,9 +54734,9 @@ function checkKeypairs() {
54461
54734
  }
54462
54735
  async function runDoctor() {
54463
54736
  const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
54464
- const dim = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
54465
- const green = (s) => useColor ? `\x1B[32m${s}\x1B[39m` : s;
54466
- const red = (s) => useColor ? `\x1B[31m${s}\x1B[39m` : s;
54737
+ const dim2 = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
54738
+ const green2 = (s) => useColor ? `\x1B[32m${s}\x1B[39m` : s;
54739
+ const red2 = (s) => useColor ? `\x1B[31m${s}\x1B[39m` : s;
54467
54740
  console.log(`claudemesh doctor (v${VERSION})`);
54468
54741
  console.log("─".repeat(60));
54469
54742
  const checks3 = [
@@ -54475,20 +54748,20 @@ async function runDoctor() {
54475
54748
  checkKeypairs()
54476
54749
  ];
54477
54750
  for (const c of checks3) {
54478
- const mark = c.pass ? green("✓") : red("✗");
54479
- const detail = c.detail ? dim(` (${c.detail})`) : "";
54751
+ const mark = c.pass ? green2("✓") : red2("✗");
54752
+ const detail = c.detail ? dim2(` (${c.detail})`) : "";
54480
54753
  console.log(`${mark} ${c.name}${detail}`);
54481
54754
  if (!c.pass && c.fix) {
54482
- console.log(dim(` → ${c.fix}`));
54755
+ console.log(dim2(` → ${c.fix}`));
54483
54756
  }
54484
54757
  }
54485
54758
  const failing = checks3.filter((c) => !c.pass);
54486
54759
  console.log("");
54487
54760
  if (failing.length === 0) {
54488
- console.log(green("All checks passed."));
54761
+ console.log(green2("All checks passed."));
54489
54762
  process.exit(0);
54490
54763
  } else {
54491
- console.log(red(`${failing.length} check(s) failed.`));
54764
+ console.log(red2(`${failing.length} check(s) failed.`));
54492
54765
  process.exit(1);
54493
54766
  }
54494
54767
  }
@@ -54498,6 +54771,8 @@ init_config();
54498
54771
  import { existsSync as existsSync6, readFileSync as readFileSync5 } from "node:fs";
54499
54772
  import { homedir as homedir6 } from "node:os";
54500
54773
  import { join as join6 } from "node:path";
54774
+ init_colors();
54775
+ init_spinner();
54501
54776
  function detectState() {
54502
54777
  const claudeConfig = join6(homedir6(), ".claude.json");
54503
54778
  let mcpRegistered = false;
@@ -54516,56 +54791,154 @@ function detectState() {
54516
54791
  return "broken-config";
54517
54792
  }
54518
54793
  }
54519
- function runWelcome() {
54520
- const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
54521
- const bold2 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
54522
- const dim = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
54523
- const green = (s) => useColor ? `\x1B[32m${s}\x1B[39m` : s;
54524
- const yellow = (s) => useColor ? `\x1B[33m${s}\x1B[39m` : s;
54525
- console.log(bold2(`claudemesh v${VERSION}`) + dim(" — peer mesh for Claude Code"));
54794
+ async function runWelcome() {
54795
+ if (!process.stdout.isTTY) {
54796
+ return runWelcomePlain();
54797
+ }
54798
+ const state = detectState();
54799
+ const { rows } = termSize();
54800
+ enterFullScreen();
54801
+ drawTopBar();
54802
+ const logoTop = Math.floor((rows - FRAME_HEIGHT - 10) / 2);
54803
+ const brandRow = logoTop + FRAME_HEIGHT + 1;
54804
+ const subtitleRow = brandRow + 1;
54805
+ const contentRow = subtitleRow + 2;
54806
+ writeCentered(brandRow, boldOrange("claudemesh"));
54807
+ writeCentered(subtitleRow, dim("peer mesh for Claude Code"));
54808
+ const spinner = createSpinner({
54809
+ render(lines) {
54810
+ for (let i = 0;i < lines.length; i++) {
54811
+ writeCentered(logoTop + i, lines[i]);
54812
+ }
54813
+ },
54814
+ interval: 70
54815
+ });
54816
+ spinner.start();
54817
+ let menuRow = contentRow;
54818
+ switch (state) {
54819
+ case "no-install": {
54820
+ writeCentered(contentRow, "Welcome. Let's get you set up.");
54821
+ writeCentered(contentRow + 1, "");
54822
+ writeCentered(contentRow + 2, dim("MCP server ") + yellow("○") + dim(" not registered"));
54823
+ writeCentered(contentRow + 3, dim("Mesh ") + dim("○") + dim(" waiting"));
54824
+ menuRow = contentRow + 5;
54825
+ spinner.stop();
54826
+ const choice = await menuSelect({
54827
+ title: "Get started",
54828
+ items: ["Install MCP server", "Cancel"],
54829
+ row: menuRow
54830
+ });
54831
+ exitFullScreen();
54832
+ if (choice === 0) {
54833
+ console.log(green("$") + ` claudemesh install
54834
+ `);
54835
+ }
54836
+ break;
54837
+ }
54838
+ case "no-meshes": {
54839
+ writeCentered(contentRow, green("✓") + " MCP registered. Now join a mesh.");
54840
+ writeCentered(contentRow + 2, dim("MCP server ") + green("✓") + dim(" registered"));
54841
+ writeCentered(contentRow + 3, dim("Mesh ") + yellow("○") + dim(" none joined"));
54842
+ menuRow = contentRow + 5;
54843
+ spinner.stop();
54844
+ const choice = await menuSelect({
54845
+ title: "Next step",
54846
+ items: [
54847
+ "Join with invite URL",
54848
+ "Create a new mesh",
54849
+ "Cancel"
54850
+ ],
54851
+ row: menuRow
54852
+ });
54853
+ exitFullScreen();
54854
+ if (choice === 0) {
54855
+ console.log(green("$") + ` claudemesh join https://claudemesh.com/join/<token>
54856
+ `);
54857
+ console.log(dim(" Don't have an invite? Create one at ") + bold2("https://claudemesh.com") + dim(" or ask a mesh owner."));
54858
+ } else if (choice === 1) {
54859
+ console.log(green("$") + ` claudemesh create
54860
+ `);
54861
+ }
54862
+ break;
54863
+ }
54864
+ case "ready": {
54865
+ const cfg = loadConfig();
54866
+ const meshNames = cfg.meshes.map((m) => m.slug).join(", ");
54867
+ writeCentered(contentRow, green("✓") + " MCP registered");
54868
+ writeCentered(contentRow + 1, green("✓") + ` ${cfg.meshes.length} mesh(es): ${meshNames}`);
54869
+ writeCentered(contentRow + 2, "");
54870
+ writeCentered(contentRow + 3, bold2("Ready to launch."));
54871
+ menuRow = contentRow + 5;
54872
+ spinner.stop();
54873
+ const choice = await menuSelect({
54874
+ title: "What next?",
54875
+ items: [
54876
+ "Launch Claude Code session",
54877
+ "View peers",
54878
+ "Check status",
54879
+ "Run diagnostics",
54880
+ "Exit"
54881
+ ],
54882
+ row: menuRow
54883
+ });
54884
+ exitFullScreen();
54885
+ switch (choice) {
54886
+ case 0:
54887
+ console.log(green("$") + ` claudemesh launch
54888
+ `);
54889
+ break;
54890
+ case 1:
54891
+ console.log(green("$") + ` claudemesh peers
54892
+ `);
54893
+ break;
54894
+ case 2:
54895
+ console.log(green("$") + ` claudemesh status
54896
+ `);
54897
+ break;
54898
+ case 3:
54899
+ console.log(green("$") + ` claudemesh doctor
54900
+ `);
54901
+ break;
54902
+ }
54903
+ break;
54904
+ }
54905
+ case "broken-config": {
54906
+ writeCentered(contentRow, yellow("⚠") + " ~/.claudemesh/config.json is unreadable.");
54907
+ menuRow = contentRow + 2;
54908
+ spinner.stop();
54909
+ const choice = await menuSelect({
54910
+ title: "Recover",
54911
+ items: ["Run diagnostics", "Cancel"],
54912
+ row: menuRow
54913
+ });
54914
+ exitFullScreen();
54915
+ if (choice === 0) {
54916
+ console.log(green("$") + ` claudemesh doctor
54917
+ `);
54918
+ }
54919
+ break;
54920
+ }
54921
+ }
54922
+ }
54923
+ function runWelcomePlain() {
54924
+ const { VERSION: VERSION2 } = (init_version(), __toCommonJS(exports_version));
54925
+ console.log(`claudemesh v${VERSION2} — peer mesh for Claude Code`);
54526
54926
  console.log("─".repeat(60));
54527
54927
  const state = detectState();
54528
54928
  switch (state) {
54529
54929
  case "no-install":
54530
- console.log("Welcome. Let's get you set up.");
54531
- console.log("");
54532
- console.log(bold2("Step 1:") + " register the MCP server + status hooks");
54533
- console.log(` ${green("$")} claudemesh install`);
54534
- console.log("");
54535
- console.log(dim("Step 2 (after restart): claudemesh join <invite-url>"));
54536
- console.log(dim("Step 3: claudemesh launch"));
54930
+ console.log("MCP not registered. Run: claudemesh install");
54537
54931
  break;
54538
54932
  case "no-meshes":
54539
- console.log(green("✓") + " MCP registered. Now join a mesh.");
54540
- console.log("");
54541
- console.log(bold2("Step 2:") + " join a mesh");
54542
- console.log(` ${green("$")} claudemesh join https://claudemesh.com/join/<token>`);
54543
- console.log("");
54544
- console.log(dim(" Don't have an invite? Create one at ") + bold2("https://claudemesh.com") + dim(" or ask a mesh owner."));
54545
- console.log("");
54546
- console.log(dim("Step 3 (after joining): claudemesh launch"));
54933
+ console.log("No meshes joined. Run: claudemesh join <invite-url>");
54547
54934
  break;
54548
54935
  case "ready": {
54549
54936
  const cfg = loadConfig();
54550
- const meshNames = cfg.meshes.map((m) => m.slug).join(", ");
54551
- console.log(green("✓") + " MCP registered.");
54552
- console.log(green("✓") + ` ${cfg.meshes.length} mesh(es) joined: ${meshNames}`);
54553
- console.log("");
54554
- console.log(bold2("You're ready.") + " Launch Claude Code with real-time peer messages:");
54555
- console.log(` ${green("$")} claudemesh launch`);
54556
- console.log("");
54557
- console.log(dim(" (Plain `claude` works too — messages pull-only via check_messages.)"));
54558
- console.log("");
54559
- console.log(dim("Health check: claudemesh status"));
54560
- console.log(dim("Diagnostics: claudemesh doctor"));
54561
- console.log(dim("All commands: claudemesh --help"));
54937
+ console.log(`${cfg.meshes.length} mesh(es) joined. Run: claudemesh launch`);
54562
54938
  break;
54563
54939
  }
54564
54940
  case "broken-config":
54565
- console.log(yellow("⚠") + " Your ~/.claudemesh/config.json is unreadable.");
54566
- console.log("");
54567
- console.log("Run diagnostics to see what's wrong:");
54568
- console.log(` ${green("$")} claudemesh doctor`);
54941
+ console.log("Config unreadable. Run: claudemesh doctor");
54569
54942
  break;
54570
54943
  }
54571
54944
  console.log("");
@@ -54609,10 +54982,10 @@ Joined: ${config2.meshes.map((m) => m.slug).join(", ")}`);
54609
54982
  // src/commands/peers.ts
54610
54983
  async function runPeers(flags) {
54611
54984
  const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
54612
- const dim = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
54613
- const bold2 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
54614
- const green = (s) => useColor ? `\x1B[32m${s}\x1B[39m` : s;
54615
- const yellow = (s) => useColor ? `\x1B[33m${s}\x1B[39m` : s;
54985
+ const dim2 = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
54986
+ const bold3 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
54987
+ const green2 = (s) => useColor ? `\x1B[32m${s}\x1B[39m` : s;
54988
+ const yellow2 = (s) => useColor ? `\x1B[33m${s}\x1B[39m` : s;
54616
54989
  await withMesh({ meshSlug: flags.mesh ?? null }, async (client2, mesh) => {
54617
54990
  const peers = await client2.listPeers();
54618
54991
  if (flags.json) {
@@ -54620,15 +54993,15 @@ async function runPeers(flags) {
54620
54993
  return;
54621
54994
  }
54622
54995
  if (peers.length === 0) {
54623
- console.log(dim(`No peers connected on mesh "${mesh.slug}".`));
54996
+ console.log(dim2(`No peers connected on mesh "${mesh.slug}".`));
54624
54997
  return;
54625
54998
  }
54626
- console.log(bold2(`Peers on ${mesh.slug}`) + dim(` (${peers.length})`));
54999
+ console.log(bold3(`Peers on ${mesh.slug}`) + dim2(` (${peers.length})`));
54627
55000
  console.log("");
54628
55001
  for (const p of peers) {
54629
55002
  const groups = p.groups.length ? " [" + p.groups.map((g) => `@${g.name}${g.role ? `:${g.role}` : ""}`).join(", ") + "]" : "";
54630
- const statusIcon = p.status === "working" ? yellow("●") : green("●");
54631
- const name = bold2(p.displayName);
55003
+ const statusIcon = p.status === "working" ? yellow2("●") : green2("●");
55004
+ const name = bold3(p.displayName);
54632
55005
  const meta2 = [];
54633
55006
  if (p.peerType)
54634
55007
  meta2.push(p.peerType);
@@ -54636,9 +55009,9 @@ async function runPeers(flags) {
54636
55009
  meta2.push(p.channel);
54637
55010
  if (p.model)
54638
55011
  meta2.push(p.model);
54639
- const metaStr = meta2.length ? dim(` (${meta2.join(", ")})`) : "";
54640
- const cwdStr = p.cwd ? dim(` cwd: ${p.cwd}`) : "";
54641
- const summary = p.summary ? dim(` ${p.summary}`) : "";
55012
+ const metaStr = meta2.length ? dim2(` (${meta2.join(", ")})`) : "";
55013
+ const cwdStr = p.cwd ? dim2(` cwd: ${p.cwd}`) : "";
55014
+ const summary = p.summary ? dim2(` ${p.summary}`) : "";
54642
55015
  console.log(` ${statusIcon} ${name}${groups}${metaStr}${summary}`);
54643
55016
  if (cwdStr)
54644
55017
  console.log(` ${cwdStr}`);
@@ -54674,19 +55047,19 @@ async function runSend(flags, to, message) {
54674
55047
 
54675
55048
  // src/commands/inbox.ts
54676
55049
  function formatMessage(msg, useColor) {
54677
- const dim = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
54678
- const bold2 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
55050
+ const dim2 = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
55051
+ const bold3 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
54679
55052
  const text2 = msg.plaintext ?? `[encrypted: ${msg.ciphertext.slice(0, 32)}…]`;
54680
55053
  const from = msg.senderPubkey.slice(0, 8);
54681
55054
  const time3 = new Date(msg.createdAt).toLocaleTimeString();
54682
55055
  const kindTag = msg.kind === "direct" ? "→ direct" : msg.kind;
54683
- return ` ${bold2(from)} ${dim(`[${kindTag}] ${time3}`)}
55056
+ return ` ${bold3(from)} ${dim2(`[${kindTag}] ${time3}`)}
54684
55057
  ${text2}`;
54685
55058
  }
54686
55059
  async function runInbox(flags) {
54687
55060
  const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
54688
- const dim = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
54689
- const bold2 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
55061
+ const dim2 = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
55062
+ const bold3 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
54690
55063
  const waitMs = (flags.wait ?? 1) * 1000;
54691
55064
  await withMesh({ meshSlug: flags.mesh ?? null }, async (client2, mesh) => {
54692
55065
  await new Promise((resolve2) => setTimeout(resolve2, waitMs));
@@ -54696,10 +55069,10 @@ async function runInbox(flags) {
54696
55069
  return;
54697
55070
  }
54698
55071
  if (messages.length === 0) {
54699
- console.log(dim(`No messages on mesh "${mesh.slug}".`));
55072
+ console.log(dim2(`No messages on mesh "${mesh.slug}".`));
54700
55073
  return;
54701
55074
  }
54702
- console.log(bold2(`Inbox — ${mesh.slug}`) + dim(` (${messages.length} message${messages.length === 1 ? "" : "s"})`));
55075
+ console.log(bold3(`Inbox — ${mesh.slug}`) + dim2(` (${messages.length} message${messages.length === 1 ? "" : "s"})`));
54703
55076
  console.log("");
54704
55077
  for (const msg of messages) {
54705
55078
  console.log(formatMessage(msg, useColor));
@@ -54711,11 +55084,11 @@ async function runInbox(flags) {
54711
55084
  // src/commands/state.ts
54712
55085
  async function runStateGet(flags, key) {
54713
55086
  const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
54714
- const dim = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
55087
+ const dim2 = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
54715
55088
  await withMesh({ meshSlug: flags.mesh ?? null }, async (client2) => {
54716
55089
  const entry = await client2.getState(key);
54717
55090
  if (!entry) {
54718
- console.log(dim(`(not set)`));
55091
+ console.log(dim2(`(not set)`));
54719
55092
  return;
54720
55093
  }
54721
55094
  if (flags.json) {
@@ -54724,7 +55097,7 @@ async function runStateGet(flags, key) {
54724
55097
  }
54725
55098
  const val = typeof entry.value === "string" ? entry.value : JSON.stringify(entry.value);
54726
55099
  console.log(val);
54727
- console.log(dim(` set by ${entry.updatedBy} at ${new Date(entry.updatedAt).toLocaleString()}`));
55100
+ console.log(dim2(` set by ${entry.updatedBy} at ${new Date(entry.updatedAt).toLocaleString()}`));
54728
55101
  });
54729
55102
  }
54730
55103
  async function runStateSet(flags, key, value) {
@@ -54741,8 +55114,8 @@ async function runStateSet(flags, key, value) {
54741
55114
  }
54742
55115
  async function runStateList(flags) {
54743
55116
  const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
54744
- const dim = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
54745
- const bold2 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
55117
+ const dim2 = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
55118
+ const bold3 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
54746
55119
  await withMesh({ meshSlug: flags.mesh ?? null }, async (client2, mesh) => {
54747
55120
  const entries = await client2.listState();
54748
55121
  if (flags.json) {
@@ -54750,13 +55123,13 @@ async function runStateList(flags) {
54750
55123
  return;
54751
55124
  }
54752
55125
  if (entries.length === 0) {
54753
- console.log(dim(`No state on mesh "${mesh.slug}".`));
55126
+ console.log(dim2(`No state on mesh "${mesh.slug}".`));
54754
55127
  return;
54755
55128
  }
54756
55129
  for (const e of entries) {
54757
55130
  const val = typeof e.value === "string" ? e.value : JSON.stringify(e.value);
54758
- console.log(`${bold2(e.key)}: ${val}`);
54759
- console.log(dim(` ${e.updatedBy} · ${new Date(e.updatedAt).toLocaleString()}`));
55131
+ console.log(`${bold3(e.key)}: ${val}`);
55132
+ console.log(dim2(` ${e.updatedBy} · ${new Date(e.updatedAt).toLocaleString()}`));
54760
55133
  }
54761
55134
  });
54762
55135
  }
@@ -54780,8 +55153,8 @@ async function runRemember(flags, content) {
54780
55153
  }
54781
55154
  async function runRecall(flags, query) {
54782
55155
  const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
54783
- const dim = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
54784
- const bold2 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
55156
+ const dim2 = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
55157
+ const bold3 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
54785
55158
  await withMesh({ meshSlug: flags.mesh ?? null }, async (client2) => {
54786
55159
  const memories = await client2.recall(query);
54787
55160
  if (flags.json) {
@@ -54789,14 +55162,14 @@ async function runRecall(flags, query) {
54789
55162
  return;
54790
55163
  }
54791
55164
  if (memories.length === 0) {
54792
- console.log(dim("No memories found."));
55165
+ console.log(dim2("No memories found."));
54793
55166
  return;
54794
55167
  }
54795
55168
  for (const m of memories) {
54796
- const tags = m.tags.length ? dim(` [${m.tags.join(", ")}]`) : "";
54797
- console.log(`${bold2(m.id.slice(0, 8))}${tags}`);
55169
+ const tags = m.tags.length ? dim2(` [${m.tags.join(", ")}]`) : "";
55170
+ console.log(`${bold3(m.id.slice(0, 8))}${tags}`);
54798
55171
  console.log(` ${m.content}`);
54799
- console.log(dim(` ${m.rememberedBy} · ${new Date(m.rememberedAt).toLocaleString()}`));
55172
+ console.log(dim2(` ${m.rememberedBy} · ${new Date(m.rememberedAt).toLocaleString()}`));
54800
55173
  console.log("");
54801
55174
  }
54802
55175
  });
@@ -54806,8 +55179,8 @@ async function runRecall(flags, query) {
54806
55179
  init_config();
54807
55180
  async function runInfo(flags) {
54808
55181
  const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
54809
- const dim = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
54810
- const bold2 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
55182
+ const dim2 = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
55183
+ const bold3 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
54811
55184
  const config2 = loadConfig();
54812
55185
  await withMesh({ meshSlug: flags.mesh ?? null }, async (client2, mesh) => {
54813
55186
  const [brokerInfo, peers, state] = await Promise.all([
@@ -54829,16 +55202,16 @@ async function runInfo(flags) {
54829
55202
  console.log(JSON.stringify(output, null, 2));
54830
55203
  return;
54831
55204
  }
54832
- console.log(bold2(mesh.slug) + dim(` · ${mesh.brokerUrl}`));
54833
- console.log(dim(` mesh: ${mesh.meshId}`));
54834
- console.log(dim(` member: ${mesh.memberId}`));
55205
+ console.log(bold3(mesh.slug) + dim2(` · ${mesh.brokerUrl}`));
55206
+ console.log(dim2(` mesh: ${mesh.meshId}`));
55207
+ console.log(dim2(` member: ${mesh.memberId}`));
54835
55208
  console.log(` peers: ${peers.length} connected`);
54836
55209
  console.log(` state: ${state.length} keys`);
54837
55210
  if (brokerInfo && typeof brokerInfo === "object") {
54838
55211
  for (const [k, v] of Object.entries(brokerInfo)) {
54839
55212
  if (["slug", "meshId", "brokerUrl"].includes(k))
54840
55213
  continue;
54841
- console.log(dim(` ${k}: ${JSON.stringify(v)}`));
55214
+ console.log(dim2(` ${k}: ${JSON.stringify(v)}`));
54842
55215
  }
54843
55216
  }
54844
55217
  });
@@ -54883,8 +55256,8 @@ function parseDeliverAt(flags) {
54883
55256
  }
54884
55257
  async function runRemind(flags, positional) {
54885
55258
  const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
54886
- const dim = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
54887
- const bold2 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
55259
+ const dim2 = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
55260
+ const bold3 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
54888
55261
  const action = positional[0];
54889
55262
  if (action === "list") {
54890
55263
  await withMesh({ meshSlug: flags.mesh ?? null }, async (client2) => {
@@ -54894,14 +55267,14 @@ async function runRemind(flags, positional) {
54894
55267
  return;
54895
55268
  }
54896
55269
  if (scheduled.length === 0) {
54897
- console.log(dim("No pending reminders."));
55270
+ console.log(dim2("No pending reminders."));
54898
55271
  return;
54899
55272
  }
54900
55273
  for (const m of scheduled) {
54901
55274
  const when = new Date(m.deliverAt).toLocaleString();
54902
- const to = m.to === client2.getSessionPubkey() ? dim("(self)") : m.to;
54903
- console.log(` ${bold2(m.id.slice(0, 8))} → ${to} at ${when}`);
54904
- console.log(` ${dim(m.message.slice(0, 80))}`);
55275
+ const to = m.to === client2.getSessionPubkey() ? dim2("(self)") : m.to;
55276
+ console.log(` ${bold3(m.id.slice(0, 8))} → ${to} at ${when}`);
55277
+ console.log(` ${dim2(m.message.slice(0, 80))}`);
54905
55278
  console.log("");
54906
55279
  }
54907
55280
  });
@@ -55114,14 +55487,14 @@ import { hostname as hostname4 } from "node:os";
55114
55487
  init_keypair();
55115
55488
  async function runSync(args) {
55116
55489
  const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
55117
- const dim = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
55118
- const green = (s) => useColor ? `\x1B[32m${s}\x1B[39m` : s;
55490
+ const dim2 = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
55491
+ const green2 = (s) => useColor ? `\x1B[32m${s}\x1B[39m` : s;
55119
55492
  const config2 = loadConfig();
55120
55493
  const code = generatePairingCode();
55121
55494
  const listener = await startCallbackListener();
55122
55495
  const url = `https://claudemesh.com/cli-auth?port=${listener.port}&code=${code}&action=sync`;
55123
55496
  console.log(`Opening browser to sync meshes...`);
55124
- console.log(dim(`Visit: ${url}`));
55497
+ console.log(dim2(`Visit: ${url}`));
55125
55498
  await openBrowser(url);
55126
55499
  const manualPromise = new Promise((resolve2) => {
55127
55500
  const rl = createInterface2({ input: process.stdin, output: process.stdout });
@@ -55166,7 +55539,7 @@ async function runSync(args) {
55166
55539
  config2.accountId = result.account_id;
55167
55540
  saveConfig(config2);
55168
55541
  if (added > 0) {
55169
- console.log(green(`✓ Added ${added} new mesh(es)`));
55542
+ console.log(green2(`✓ Added ${added} new mesh(es)`));
55170
55543
  } else {
55171
55544
  console.log(`Already up to date (${config2.meshes.length} meshes)`);
55172
55545
  }
@@ -55176,8 +55549,8 @@ async function runSync(args) {
55176
55549
  init_config();
55177
55550
  async function runProfile(flags) {
55178
55551
  const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
55179
- const dim = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
55180
- const green = (s) => useColor ? `\x1B[32m${s}\x1B[39m` : s;
55552
+ const dim2 = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
55553
+ const green2 = (s) => useColor ? `\x1B[32m${s}\x1B[39m` : s;
55181
55554
  const config2 = loadConfig();
55182
55555
  if (config2.meshes.length === 0) {
55183
55556
  console.error("No meshes joined. Run `claudemesh join <url>` first.");
@@ -55217,9 +55590,9 @@ async function runProfile(flags) {
55217
55590
  if (flags.json) {
55218
55591
  console.log(JSON.stringify(result, null, 2));
55219
55592
  } else if (result.ok) {
55220
- console.log(green("✓ Profile updated"));
55593
+ console.log(green2("✓ Profile updated"));
55221
55594
  const member = result.member;
55222
- printProfile(member, dim);
55595
+ printProfile(member, dim2);
55223
55596
  } else {
55224
55597
  console.error(`Error: ${result.error}`);
55225
55598
  process.exit(1);
@@ -55235,21 +55608,21 @@ async function runProfile(flags) {
55235
55608
  if (flags.json) {
55236
55609
  console.log(JSON.stringify(me ?? {}, null, 2));
55237
55610
  } else if (me) {
55238
- printProfile(me, dim);
55611
+ printProfile(me, dim2);
55239
55612
  } else {
55240
55613
  console.log("Member not found in mesh.");
55241
55614
  }
55242
55615
  }
55243
55616
  }
55244
- function printProfile(member, dim) {
55617
+ function printProfile(member, dim2) {
55245
55618
  const groups = member.groups;
55246
- const groupStr = groups?.length ? groups.map((g) => g.role ? `${g.name} (${g.role})` : g.name).join(", ") : dim("(none)");
55247
- console.log(` Name: ${member.displayName ?? dim("(not set)")}`);
55248
- console.log(` Role: ${member.roleTag ?? dim("(not set)")}`);
55619
+ const groupStr = groups?.length ? groups.map((g) => g.role ? `${g.name} (${g.role})` : g.name).join(", ") : dim2("(none)");
55620
+ console.log(` Name: ${member.displayName ?? dim2("(not set)")}`);
55621
+ console.log(` Role: ${member.roleTag ?? dim2("(not set)")}`);
55249
55622
  console.log(` Groups: ${groupStr}`);
55250
55623
  console.log(` Messages: ${member.messageMode ?? "push"}`);
55251
55624
  console.log(` Access: ${member.permission ?? "member"}`);
55252
- console.log(` Mesh: ${dim(String(member.id ?? ""))}`);
55625
+ console.log(` Mesh: ${dim2(String(member.id ?? ""))}`);
55253
55626
  }
55254
55627
 
55255
55628
  // src/commands/connect-telegram.ts
@@ -55309,6 +55682,7 @@ async function disconnectTelegram() {
55309
55682
  }
55310
55683
 
55311
55684
  // src/index.ts
55685
+ init_version();
55312
55686
  var launch = defineCommand({
55313
55687
  meta: {
55314
55688
  name: "launch",
@@ -55643,8 +56017,8 @@ var main = defineCommand({
55643
56017
  }
55644
56018
  })
55645
56019
  },
55646
- run() {
55647
- runWelcome();
56020
+ async run() {
56021
+ await runWelcome();
55648
56022
  }
55649
56023
  });
55650
56024
  runMain(main);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudemesh-cli",
3
- "version": "0.9.2",
3
+ "version": "0.9.4",
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",
52
51
  "@turbostarter/prettier-config": "0.1.0",
53
- "@turbostarter/tsconfig": "0.1.0",
54
- "@turbostarter/vitest-config": "0.1.0"
52
+ "@turbostarter/eslint-config": "0.1.0",
53
+ "@turbostarter/vitest-config": "0.1.0",
54
+ "@turbostarter/tsconfig": "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",