claudemesh-cli 0.9.3 → 0.9.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 +730 -267
  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, green2, 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
+ green2 = 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.5",
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,177 @@ 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(extra) {
53947
+ const { cols } = termSize();
53948
+ const bg = "\x1B[48;5;208m\x1B[30m";
53949
+ const reset = "\x1B[0m";
53950
+ const left = ` claudemesh v${VERSION}`;
53951
+ const right = `claudemesh.com `;
53952
+ const mid = extra ? ` ${extra}` : "";
53953
+ const gap = Math.max(1, cols - left.length - right.length - mid.length);
53954
+ process.stdout.write(moveTo(1, 1) + bg + left + mid + " ".repeat(gap) + right + reset);
53955
+ }
53956
+ function drawBottomBar(left, right) {
53957
+ const { cols, rows } = termSize();
53958
+ const bg = "\x1B[48;5;208m\x1B[30m";
53959
+ const reset = "\x1B[0m";
53960
+ const l = ` ${left}`;
53961
+ const r = right ? `${right} ` : "";
53962
+ const gap = Math.max(1, cols - l.length - r.length);
53963
+ process.stdout.write(moveTo(rows, 1) + bg + l + " ".repeat(gap) + r + reset);
53964
+ }
53965
+ function enterFullScreen() {
53966
+ process.stdout.write(HIDE_CURSOR + CLEAR_SCREEN);
53967
+ drawTopBar();
53968
+ }
53969
+ function exitFullScreen() {
53970
+ process.stdout.write(SHOW_CURSOR + CLEAR_SCREEN);
53971
+ }
53972
+ async function menuSelect(opts) {
53973
+ const { items, title, row } = opts;
53974
+ let selected = opts.defaultIndex ?? 0;
53975
+ writeCentered(row, bold2(orange(title)));
53976
+ const renderItems = () => {
53977
+ for (let i = 0;i < items.length; i++) {
53978
+ const prefix = i === selected ? boldOrange("▸ ") : " ";
53979
+ const text2 = i === selected ? bold2(items[i]) : dim(items[i]);
53980
+ writeCentered(row + 1 + i, prefix + text2 + CLEAR_LINE);
53981
+ }
53982
+ };
53983
+ renderItems();
53984
+ return new Promise((resolve2) => {
53985
+ const stdin = process.stdin;
53986
+ const wasRaw = stdin.isRaw;
53987
+ stdin.setRawMode(true);
53988
+ stdin.resume();
53989
+ stdin.setEncoding("utf8");
53990
+ const onData = (key) => {
53991
+ if (key === "\x1B[A" || key === "k") {
53992
+ selected = (selected - 1 + items.length) % items.length;
53993
+ renderItems();
53994
+ } else if (key === "\x1B[B" || key === "j") {
53995
+ selected = (selected + 1) % items.length;
53996
+ renderItems();
53997
+ } else if (key === "\r" || key === `
53998
+ `) {
53999
+ stdin.removeListener("data", onData);
54000
+ stdin.setRawMode(wasRaw ?? false);
54001
+ stdin.pause();
54002
+ resolve2(selected);
54003
+ } else if (key === "\x03") {
54004
+ stdin.removeListener("data", onData);
54005
+ stdin.setRawMode(wasRaw ?? false);
54006
+ exitFullScreen();
54007
+ process.exit(0);
54008
+ }
54009
+ };
54010
+ stdin.on("data", onData);
54011
+ });
54012
+ }
54013
+ async function textInput(opts) {
54014
+ const { label, row, placeholder } = opts;
54015
+ let value = "";
54016
+ const render = () => {
54017
+ const display = value || dim(placeholder ?? "");
54018
+ const cursor = SHOW_CURSOR;
54019
+ writeCentered(row, `${bold2(label)} ${display}${CLEAR_LINE}`);
54020
+ const fullText = `${label.replace(/\x1b\[[^m]*m/g, "")} ${value}`;
54021
+ const { cols } = termSize();
54022
+ const leftPad = Math.max(0, Math.floor((cols - fullText.length) / 2));
54023
+ process.stdout.write(moveTo(row, leftPad + fullText.length + 1) + cursor);
54024
+ };
54025
+ process.stdout.write(SHOW_CURSOR);
54026
+ render();
54027
+ return new Promise((resolve2) => {
54028
+ const stdin = process.stdin;
54029
+ const wasRaw = stdin.isRaw;
54030
+ stdin.setRawMode(true);
54031
+ stdin.resume();
54032
+ stdin.setEncoding("utf8");
54033
+ const onData = (key) => {
54034
+ if (key === "\r" || key === `
54035
+ `) {
54036
+ stdin.removeListener("data", onData);
54037
+ stdin.setRawMode(wasRaw ?? false);
54038
+ stdin.pause();
54039
+ process.stdout.write(HIDE_CURSOR);
54040
+ const final = value || dim("skipped");
54041
+ writeCentered(row, `${label} ${green("✓")} ${final}${CLEAR_LINE}`);
54042
+ resolve2(value);
54043
+ } else if (key === "" || key === "\b") {
54044
+ value = value.slice(0, -1);
54045
+ render();
54046
+ } else if (key === "\x03") {
54047
+ stdin.removeListener("data", onData);
54048
+ stdin.setRawMode(wasRaw ?? false);
54049
+ exitFullScreen();
54050
+ process.exit(0);
54051
+ } else if (key === "\x1B") {
54052
+ stdin.removeListener("data", onData);
54053
+ stdin.setRawMode(wasRaw ?? false);
54054
+ stdin.pause();
54055
+ process.stdout.write(HIDE_CURSOR);
54056
+ writeCentered(row, `${label} ${dim("skipped")}${CLEAR_LINE}`);
54057
+ resolve2("");
54058
+ } else if (key >= " " && key <= "~") {
54059
+ value += key;
54060
+ render();
54061
+ }
54062
+ };
54063
+ stdin.on("data", onData);
54064
+ });
54065
+ }
54066
+ async function confirmPrompt(opts) {
54067
+ const { message, row } = opts;
54068
+ const defaultYes = opts.defaultYes ?? true;
54069
+ const hint = defaultYes ? `${bold2("Y")}/${dim("n")}` : `${dim("y")}/${bold2("N")}`;
54070
+ writeCentered(row, `${message} [${hint}]`);
54071
+ process.stdout.write(SHOW_CURSOR);
54072
+ return new Promise((resolve2) => {
54073
+ const stdin = process.stdin;
54074
+ const wasRaw = stdin.isRaw;
54075
+ stdin.setRawMode(true);
54076
+ stdin.resume();
54077
+ stdin.setEncoding("utf8");
54078
+ const onData = (key) => {
54079
+ stdin.removeListener("data", onData);
54080
+ stdin.setRawMode(wasRaw ?? false);
54081
+ stdin.pause();
54082
+ process.stdout.write(HIDE_CURSOR);
54083
+ if (key === "\x03") {
54084
+ exitFullScreen();
54085
+ process.exit(0);
54086
+ }
54087
+ const yes = key === "y" || key === "Y" || key === "\r" && defaultYes;
54088
+ writeCentered(row, `${message} ${yes ? green("✓ yes") : dim("✗ no")}${CLEAR_LINE}`);
54089
+ resolve2(yes);
54090
+ };
54091
+ stdin.on("data", onData);
54092
+ });
54093
+ }
54094
+
54095
+ // src/commands/launch.ts
54096
+ init_spinner();
53716
54097
  async function pickMesh(meshes) {
53717
54098
  if (meshes.length === 1)
53718
54099
  return meshes[0];
@@ -53744,54 +54125,124 @@ function parseGroupsString(raw) {
53744
54125
  return { name: token.slice(0, idx), role: token.slice(idx + 1) };
53745
54126
  });
53746
54127
  }
53747
- function askLine(prompt) {
53748
- const rl = createInterface({ input: process.stdin, output: process.stdout });
53749
- return new Promise((resolve2) => {
53750
- rl.question(prompt, (answer) => {
53751
- rl.close();
53752
- resolve2(answer.trim());
53753
- });
53754
- });
53755
- }
53756
- async function confirmPermissions() {
53757
- 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")));
53762
- console.log("");
53763
- console.log(" Claude will run with --dangerously-skip-permissions, bypassing");
53764
- console.log(" ALL permission prompts — not just claudemesh tools.");
53765
- console.log(" Peers exchange text only — no file access, no tool calls.");
53766
- 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."));
53769
- console.log("");
53770
- const rl = createInterface({ input: process.stdin, output: process.stdout });
53771
- return new Promise((resolve2, reject) => {
53772
- rl.question(` ${bold2("Continue?")} [Y/n] `, (answer) => {
53773
- rl.close();
53774
- const a = answer.trim().toLowerCase();
53775
- if (a === "" || a === "y" || a === "yes") {
53776
- resolve2();
53777
- } else {
53778
- console.log(`
53779
- Aborted. Run without autonomous mode:`);
53780
- console.log(` claude --dangerously-load-development-channels server:claudemesh
53781
- `);
53782
- process.exit(0);
54128
+ async function runLaunchWizard(opts) {
54129
+ if (!process.stdout.isTTY) {
54130
+ return {
54131
+ role: opts.existingRole,
54132
+ groups: opts.existingGroups,
54133
+ messageMode: opts.existingMessageMode ?? "push",
54134
+ skipPermissions: opts.skipPermConfirm
54135
+ };
54136
+ }
54137
+ const { rows } = termSize();
54138
+ enterFullScreen();
54139
+ drawTopBar();
54140
+ drawBottomBar("↑↓ navigate ⏎ select esc skip ctrl-c quit", `mesh: ${opts.meshSlug}`);
54141
+ const logoTop = Math.floor((rows - FRAME_HEIGHT - 16) / 2);
54142
+ const brandRow = logoTop + FRAME_HEIGHT + 1;
54143
+ const subtitleRow = brandRow + 1;
54144
+ const formRow = subtitleRow + 2;
54145
+ writeCentered(brandRow, boldOrange("claudemesh"));
54146
+ writeCentered(subtitleRow, dim("peer mesh for Claude Code"));
54147
+ const spinner = createSpinner({
54148
+ render(lines) {
54149
+ for (let i = 0;i < lines.length; i++) {
54150
+ writeCentered(logoTop + i, lines[i]);
53783
54151
  }
53784
- });
54152
+ },
54153
+ interval: 70
53785
54154
  });
54155
+ spinner.start();
54156
+ let row = formRow;
54157
+ writeCentered(row, `Directory ${green2("✓")} ${process.cwd()}`);
54158
+ row++;
54159
+ writeCentered(row, `Name ${green2("✓")} ${opts.displayName}`);
54160
+ row++;
54161
+ writeCentered(row, `Mesh ${green2("✓")} ${opts.meshSlug}`);
54162
+ row += 2;
54163
+ let role = opts.existingRole;
54164
+ let groups = opts.existingGroups;
54165
+ let messageMode = opts.existingMessageMode ?? "push";
54166
+ if (role === null) {
54167
+ spinner.stop();
54168
+ const answer = await textInput({ label: "Role", row, placeholder: "optional — press Enter to skip" });
54169
+ if (answer)
54170
+ role = answer;
54171
+ spinner.start();
54172
+ row++;
54173
+ } else {
54174
+ writeCentered(row, `Role ${green2("✓")} ${role}`);
54175
+ row++;
54176
+ }
54177
+ if (groups.length === 0) {
54178
+ spinner.stop();
54179
+ const answer = await textInput({ label: "Groups", row, placeholder: "comma-separated, optional" });
54180
+ if (answer)
54181
+ groups = parseGroupsString(answer);
54182
+ spinner.start();
54183
+ row++;
54184
+ } else {
54185
+ const tags = groups.map((g) => `@${g.name}${g.role ? `:${g.role}` : ""}`).join(", ");
54186
+ writeCentered(row, `Groups ${green2("✓")} ${tags}`);
54187
+ row++;
54188
+ }
54189
+ if (opts.existingMessageMode === null) {
54190
+ row++;
54191
+ spinner.stop();
54192
+ const choice = await menuSelect({
54193
+ title: "Message mode",
54194
+ items: [
54195
+ "Push (real-time, peers can interrupt)",
54196
+ "Inbox (held until you check)",
54197
+ "Off (tools only, no messages)"
54198
+ ],
54199
+ row
54200
+ });
54201
+ messageMode = ["push", "inbox", "off"][choice];
54202
+ spinner.start();
54203
+ row += 5;
54204
+ } else {
54205
+ writeCentered(row, `Messages ${green2("✓")} ${messageMode}`);
54206
+ row++;
54207
+ }
54208
+ let skipPermissions = opts.skipPermConfirm;
54209
+ if (!skipPermissions) {
54210
+ row++;
54211
+ spinner.stop();
54212
+ writeCentered(row, dim("Claude will run with --dangerously-skip-permissions,"));
54213
+ writeCentered(row + 1, dim("bypassing ALL permission prompts — not just claudemesh."));
54214
+ row += 3;
54215
+ const confirmed = await confirmPrompt({
54216
+ message: boldOrange("Autonomous mode?"),
54217
+ row,
54218
+ defaultYes: true
54219
+ });
54220
+ if (!confirmed) {
54221
+ exitFullScreen();
54222
+ console.log(" Run without autonomous mode:");
54223
+ console.log(` claude --dangerously-load-development-channels server:claudemesh
54224
+ `);
54225
+ process.exit(0);
54226
+ }
54227
+ skipPermissions = true;
54228
+ spinner.start();
54229
+ }
54230
+ row += 2;
54231
+ writeCentered(row, dim("Launching Claude Code..."));
54232
+ drawBottomBar(`${opts.displayName} on ${opts.meshSlug}`, `mode: ${messageMode}`);
54233
+ await new Promise((r) => setTimeout(r, 800));
54234
+ spinner.stop();
54235
+ exitFullScreen();
54236
+ return { role, groups, messageMode, skipPermissions };
53786
54237
  }
53787
54238
  function printBanner(name, meshSlug, role, groups, messageMode) {
53788
54239
  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;
54240
+ const dim2 = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
54241
+ const bold3 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
53791
54242
  const roleSuffix = role ? ` (${role})` : "";
53792
54243
  const groupTags = groups.length ? " [" + groups.map((g) => `@${g.name}${g.role ? `:${g.role}` : ""}`).join(", ") + "]" : "";
53793
54244
  const rule = "─".repeat(60);
53794
- console.log(bold2(`claudemesh launch`) + dim(` — as ${name}${roleSuffix} on ${meshSlug}${groupTags} [${messageMode}]`));
54245
+ console.log(bold3(`claudemesh launch`) + dim2(` — as ${name}${roleSuffix} on ${meshSlug}${groupTags} [${messageMode}]`));
53795
54246
  console.log(rule);
53796
54247
  if (messageMode === "push") {
53797
54248
  console.log("Peer messages arrive as <channel> reminders in real-time.");
@@ -53801,7 +54252,7 @@ function printBanner(name, meshSlug, role, groups, messageMode) {
53801
54252
  console.log("Messages off. Use check_messages to poll manually.");
53802
54253
  }
53803
54254
  console.log("Peers send text only — they cannot call tools or read files.");
53804
- console.log(dim(`Config: ${getConfigPath()}`));
54255
+ console.log(dim2(`Config: ${getConfigPath()}`));
53805
54256
  console.log(rule);
53806
54257
  console.log("");
53807
54258
  }
@@ -53854,22 +54305,22 @@ async function runLaunch(flags, rawArgs) {
53854
54305
  let justSynced = false;
53855
54306
  if (config2.meshes.length === 0 && !args.joinLink) {
53856
54307
  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;
54308
+ const bold3 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
54309
+ const dim2 = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
54310
+ const green3 = (s) => useColor ? `\x1B[32m${s}\x1B[39m` : s;
53860
54311
  const code = generatePairingCode();
53861
54312
  const listener = await startCallbackListener();
53862
54313
  const url = `https://claudemesh.com/cli-auth?port=${listener.port}&code=${code}&action=sync`;
53863
54314
  console.log(`
53864
- ${bold2("Welcome to claudemesh!")} No meshes found.`);
54315
+ ${bold3("Welcome to claudemesh!")} No meshes found.`);
53865
54316
  console.log(` Opening browser to sign in...
53866
54317
  `);
53867
54318
  const opened = await openBrowser(url);
53868
54319
  if (!opened) {
53869
54320
  console.log(` Couldn't open browser automatically.`);
53870
54321
  }
53871
- console.log(` ${dim(`Visit: ${url}`)}`);
53872
- console.log(` ${dim(`Or join with invite: claudemesh launch --join <url>`)}
54322
+ console.log(` ${dim2(`Visit: ${url}`)}`);
54323
+ console.log(` ${dim2(`Or join with invite: claudemesh launch --join <url>`)}
53873
54324
  `);
53874
54325
  const manualPromise = new Promise((resolve2) => {
53875
54326
  const rl = createInterface({ input: process.stdin, output: process.stdout });
@@ -53915,7 +54366,7 @@ async function runLaunch(flags, rawArgs) {
53915
54366
  saveConfig2(config2);
53916
54367
  justSynced = true;
53917
54368
  console.log(`
53918
- ${green("✓")} Synced ${result.meshes.length} mesh(es): ${result.meshes.map((m) => m.slug).join(", ")}
54369
+ ${green3("✓")} Synced ${result.meshes.length} mesh(es): ${result.meshes.map((m) => m.slug).join(", ")}
53919
54370
  `);
53920
54371
  }
53921
54372
  if (config2.meshes.length === 0) {
@@ -53938,34 +54389,18 @@ async function runLaunch(flags, rawArgs) {
53938
54389
  let parsedGroups = args.groups ? parseGroupsString(args.groups) : [];
53939
54390
  let messageMode = args.messageMode ?? "push";
53940
54391
  if (!args.quiet && !justSynced) {
53941
- if (role === null) {
53942
- const answer = await askLine(" Role (optional): ");
53943
- if (answer)
53944
- role = answer;
53945
- }
53946
- if (parsedGroups.length === 0 && args.groups === null) {
53947
- const answer = await askLine(" Groups (comma-separated, optional): ");
53948
- if (answer)
53949
- parsedGroups = parseGroupsString(answer);
53950
- }
53951
- if (args.messageMode === null) {
53952
- console.log(`
53953
- Message mode:`);
53954
- console.log(" 1) Push (real-time, peers can interrupt your work)");
53955
- console.log(" 2) Inbox (held until you check, notification only)");
53956
- console.log(" 3) Off (tools only, no messages)");
53957
- console.log("");
53958
- const answer = await askLine(" Choice [1]: ");
53959
- const choice = parseInt(answer || "1", 10);
53960
- if (choice === 2)
53961
- messageMode = "inbox";
53962
- else if (choice === 3)
53963
- messageMode = "off";
53964
- else
53965
- messageMode = "push";
53966
- }
53967
- if (role || parsedGroups.length)
53968
- console.log("");
54392
+ const wizardResult = await runLaunchWizard({
54393
+ displayName,
54394
+ meshSlug: mesh.slug,
54395
+ existingRole: args.role,
54396
+ existingGroups: parsedGroups,
54397
+ existingMessageMode: args.messageMode ?? null,
54398
+ skipPermConfirm: args.skipPermConfirm
54399
+ });
54400
+ role = wizardResult.role;
54401
+ parsedGroups = wizardResult.groups;
54402
+ messageMode = wizardResult.messageMode;
54403
+ args.skipPermConfirm = wizardResult.skipPermissions;
53969
54404
  }
53970
54405
  const tmpBase = tmpdir();
53971
54406
  try {
@@ -54029,9 +54464,6 @@ async function runLaunch(flags, rawArgs) {
54029
54464
  `, "utf-8");
54030
54465
  if (!args.quiet) {
54031
54466
  printBanner(displayName, mesh.slug, role, parsedGroups, messageMode);
54032
- if (!args.skipPermConfirm) {
54033
- await confirmPermissions();
54034
- }
54035
54467
  }
54036
54468
  const meshMcpEntries = [];
54037
54469
  if (serviceCatalog.length > 0) {
@@ -54174,79 +54606,7 @@ async function runLaunch(flags, rawArgs) {
54174
54606
  // src/commands/status.ts
54175
54607
  import { statSync as statSync2, existsSync as existsSync4 } from "node:fs";
54176
54608
  init_config();
54177
- // package.json
54178
- var package_default = {
54179
- name: "claudemesh-cli",
54180
- version: "0.9.3",
54181
- description: "Claude Code MCP client for claudemesh — peer mesh messaging between Claude sessions.",
54182
- keywords: [
54183
- "claude-code",
54184
- "mcp",
54185
- "model-context-protocol",
54186
- "claudemesh",
54187
- "peer-messaging",
54188
- "multi-agent"
54189
- ],
54190
- author: "Alejandro Gutiérrez",
54191
- license: "MIT",
54192
- homepage: "https://claudemesh.com",
54193
- repository: {
54194
- type: "git",
54195
- url: "https://github.com/alezmad/claudemesh.git",
54196
- directory: "apps/cli"
54197
- },
54198
- type: "module",
54199
- bin: {
54200
- claudemesh: "./dist/index.js"
54201
- },
54202
- files: [
54203
- "dist",
54204
- "README.md",
54205
- "LICENSE"
54206
- ],
54207
- publishConfig: {
54208
- access: "public"
54209
- },
54210
- scripts: {
54211
- build: 'bun build src/index.ts --target=node --outfile dist/index.js --banner "#!/usr/bin/env node" && chmod +x dist/index.js',
54212
- clean: "git clean -xdf .cache .turbo dist node_modules",
54213
- dev: "bun --hot src/index.ts",
54214
- start: "bun src/index.ts",
54215
- format: "prettier --check . --ignore-path ../../.gitignore",
54216
- lint: "eslint",
54217
- prepublishOnly: "bun run build",
54218
- test: "vitest run",
54219
- typecheck: "tsc --noEmit"
54220
- },
54221
- prettier: "@turbostarter/prettier-config",
54222
- engines: {
54223
- node: ">=20"
54224
- },
54225
- dependencies: {
54226
- "@modelcontextprotocol/sdk": "1.27.1",
54227
- citty: "0.2.2",
54228
- "libsodium-wrappers": "0.7.15",
54229
- ws: "8.20.0",
54230
- zod: "4.1.13"
54231
- },
54232
- devDependencies: {
54233
- "@turbostarter/eslint-config": "workspace:*",
54234
- "@turbostarter/prettier-config": "workspace:*",
54235
- "@turbostarter/tsconfig": "workspace:*",
54236
- "@turbostarter/vitest-config": "workspace:*",
54237
- "@types/libsodium-wrappers": "0.7.14",
54238
- "@types/ws": "8.5.13",
54239
- eslint: "catalog:",
54240
- prettier: "catalog:",
54241
- typescript: "catalog:",
54242
- vitest: "catalog:"
54243
- }
54244
- };
54245
-
54246
- // src/version.ts
54247
- var VERSION = package_default.version;
54248
-
54249
- // src/commands/status.ts
54609
+ init_version();
54250
54610
  async function probeBroker(url, timeoutMs = 4000) {
54251
54611
  return new Promise((resolve2) => {
54252
54612
  const ws = new wrapper_default(url);
@@ -54271,9 +54631,9 @@ async function probeBroker(url, timeoutMs = 4000) {
54271
54631
  }
54272
54632
  async function runStatus() {
54273
54633
  const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
54274
- const dim = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
54275
- const green = (s) => useColor ? `\x1B[32m${s}\x1B[39m` : s;
54276
- const red = (s) => useColor ? `\x1B[31m${s}\x1B[39m` : s;
54634
+ const dim2 = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
54635
+ const green3 = (s) => useColor ? `\x1B[32m${s}\x1B[39m` : s;
54636
+ const red2 = (s) => useColor ? `\x1B[31m${s}\x1B[39m` : s;
54277
54637
  console.log(`claudemesh status (v${VERSION})`);
54278
54638
  console.log("─".repeat(60));
54279
54639
  const configPath = getConfigPath();
@@ -54287,7 +54647,7 @@ async function runStatus() {
54287
54647
  const config2 = loadConfig();
54288
54648
  if (config2.meshes.length === 0) {
54289
54649
  console.log("");
54290
- console.log(dim("No meshes joined. Run `claudemesh join <invite-url>` to get started."));
54650
+ console.log(dim2("No meshes joined. Run `claudemesh join <invite-url>` to get started."));
54291
54651
  process.exit(0);
54292
54652
  }
54293
54653
  console.log("");
@@ -54304,29 +54664,30 @@ async function runStatus() {
54304
54664
  error: probe.error
54305
54665
  });
54306
54666
  if (probe.ok) {
54307
- console.log(green("reachable"));
54667
+ console.log(green3("reachable"));
54308
54668
  } else {
54309
- console.log(red(`unreachable (${probe.error})`));
54669
+ console.log(red2(`unreachable (${probe.error})`));
54310
54670
  }
54311
54671
  }
54312
54672
  console.log("");
54313
54673
  for (const r of results) {
54314
- console.log(dim(` ${r.slug}: pubkey ${r.pubkey.slice(0, 16)}…`));
54674
+ console.log(dim2(` ${r.slug}: pubkey ${r.pubkey.slice(0, 16)}…`));
54315
54675
  }
54316
54676
  const allOk = results.every((r) => r.reachable);
54317
54677
  console.log("");
54318
54678
  if (allOk) {
54319
- console.log(green("All meshes reachable."));
54679
+ console.log(green3("All meshes reachable."));
54320
54680
  process.exit(0);
54321
54681
  } else {
54322
54682
  const broken = results.filter((r) => !r.reachable).length;
54323
- console.log(red(`${broken} of ${results.length} mesh(es) unreachable.`));
54683
+ console.log(red2(`${broken} of ${results.length} mesh(es) unreachable.`));
54324
54684
  process.exit(1);
54325
54685
  }
54326
54686
  }
54327
54687
 
54328
54688
  // src/commands/doctor.ts
54329
54689
  init_config();
54690
+ init_version();
54330
54691
  import { existsSync as existsSync5, readFileSync as readFileSync4, statSync as statSync3 } from "node:fs";
54331
54692
  import { homedir as homedir5, platform as platform2 } from "node:os";
54332
54693
  import { join as join5 } from "node:path";
@@ -54475,9 +54836,9 @@ function checkKeypairs() {
54475
54836
  }
54476
54837
  async function runDoctor() {
54477
54838
  const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
54478
- const dim = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
54479
- const green = (s) => useColor ? `\x1B[32m${s}\x1B[39m` : s;
54480
- const red = (s) => useColor ? `\x1B[31m${s}\x1B[39m` : s;
54839
+ const dim2 = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
54840
+ const green3 = (s) => useColor ? `\x1B[32m${s}\x1B[39m` : s;
54841
+ const red2 = (s) => useColor ? `\x1B[31m${s}\x1B[39m` : s;
54481
54842
  console.log(`claudemesh doctor (v${VERSION})`);
54482
54843
  console.log("─".repeat(60));
54483
54844
  const checks3 = [
@@ -54489,20 +54850,20 @@ async function runDoctor() {
54489
54850
  checkKeypairs()
54490
54851
  ];
54491
54852
  for (const c of checks3) {
54492
- const mark = c.pass ? green("✓") : red("✗");
54493
- const detail = c.detail ? dim(` (${c.detail})`) : "";
54853
+ const mark = c.pass ? green3("✓") : red2("✗");
54854
+ const detail = c.detail ? dim2(` (${c.detail})`) : "";
54494
54855
  console.log(`${mark} ${c.name}${detail}`);
54495
54856
  if (!c.pass && c.fix) {
54496
- console.log(dim(` → ${c.fix}`));
54857
+ console.log(dim2(` → ${c.fix}`));
54497
54858
  }
54498
54859
  }
54499
54860
  const failing = checks3.filter((c) => !c.pass);
54500
54861
  console.log("");
54501
54862
  if (failing.length === 0) {
54502
- console.log(green("All checks passed."));
54863
+ console.log(green3("All checks passed."));
54503
54864
  process.exit(0);
54504
54865
  } else {
54505
- console.log(red(`${failing.length} check(s) failed.`));
54866
+ console.log(red2(`${failing.length} check(s) failed.`));
54506
54867
  process.exit(1);
54507
54868
  }
54508
54869
  }
@@ -54512,6 +54873,8 @@ init_config();
54512
54873
  import { existsSync as existsSync6, readFileSync as readFileSync5 } from "node:fs";
54513
54874
  import { homedir as homedir6 } from "node:os";
54514
54875
  import { join as join6 } from "node:path";
54876
+ init_colors();
54877
+ init_spinner();
54515
54878
  function detectState() {
54516
54879
  const claudeConfig = join6(homedir6(), ".claude.json");
54517
54880
  let mcpRegistered = false;
@@ -54530,56 +54893,155 @@ function detectState() {
54530
54893
  return "broken-config";
54531
54894
  }
54532
54895
  }
54533
- function runWelcome() {
54534
- const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
54535
- const bold2 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
54536
- const dim = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
54537
- const green = (s) => useColor ? `\x1B[32m${s}\x1B[39m` : s;
54538
- const yellow = (s) => useColor ? `\x1B[33m${s}\x1B[39m` : s;
54539
- console.log(bold2(`claudemesh v${VERSION}`) + dim(" — peer mesh for Claude Code"));
54896
+ async function runWelcome() {
54897
+ if (!process.stdout.isTTY) {
54898
+ return runWelcomePlain();
54899
+ }
54900
+ const state = detectState();
54901
+ const { rows } = termSize();
54902
+ enterFullScreen();
54903
+ drawTopBar();
54904
+ drawBottomBar("↑↓ navigate ⏎ select ctrl-c quit", "claudemesh.com");
54905
+ const logoTop = Math.floor((rows - FRAME_HEIGHT - 10) / 2);
54906
+ const brandRow = logoTop + FRAME_HEIGHT + 1;
54907
+ const subtitleRow = brandRow + 1;
54908
+ const contentRow = subtitleRow + 2;
54909
+ writeCentered(brandRow, boldOrange("claudemesh"));
54910
+ writeCentered(subtitleRow, dim("peer mesh for Claude Code"));
54911
+ const spinner = createSpinner({
54912
+ render(lines) {
54913
+ for (let i = 0;i < lines.length; i++) {
54914
+ writeCentered(logoTop + i, lines[i]);
54915
+ }
54916
+ },
54917
+ interval: 70
54918
+ });
54919
+ spinner.start();
54920
+ let menuRow = contentRow;
54921
+ switch (state) {
54922
+ case "no-install": {
54923
+ writeCentered(contentRow, "Welcome. Let's get you set up.");
54924
+ writeCentered(contentRow + 1, "");
54925
+ writeCentered(contentRow + 2, dim("MCP server ") + yellow("○") + dim(" not registered"));
54926
+ writeCentered(contentRow + 3, dim("Mesh ") + dim("○") + dim(" waiting"));
54927
+ menuRow = contentRow + 5;
54928
+ spinner.stop();
54929
+ const choice = await menuSelect({
54930
+ title: "Get started",
54931
+ items: ["Install MCP server", "Cancel"],
54932
+ row: menuRow
54933
+ });
54934
+ exitFullScreen();
54935
+ if (choice === 0) {
54936
+ console.log(green2("$") + ` claudemesh install
54937
+ `);
54938
+ }
54939
+ break;
54940
+ }
54941
+ case "no-meshes": {
54942
+ writeCentered(contentRow, green2("✓") + " MCP registered. Now join a mesh.");
54943
+ writeCentered(contentRow + 2, dim("MCP server ") + green2("✓") + dim(" registered"));
54944
+ writeCentered(contentRow + 3, dim("Mesh ") + yellow("○") + dim(" none joined"));
54945
+ menuRow = contentRow + 5;
54946
+ spinner.stop();
54947
+ const choice = await menuSelect({
54948
+ title: "Next step",
54949
+ items: [
54950
+ "Join with invite URL",
54951
+ "Create a new mesh",
54952
+ "Cancel"
54953
+ ],
54954
+ row: menuRow
54955
+ });
54956
+ exitFullScreen();
54957
+ if (choice === 0) {
54958
+ console.log(green2("$") + ` claudemesh join https://claudemesh.com/join/<token>
54959
+ `);
54960
+ console.log(dim(" Don't have an invite? Create one at ") + bold2("https://claudemesh.com") + dim(" or ask a mesh owner."));
54961
+ } else if (choice === 1) {
54962
+ console.log(green2("$") + ` claudemesh create
54963
+ `);
54964
+ }
54965
+ break;
54966
+ }
54967
+ case "ready": {
54968
+ const cfg = loadConfig();
54969
+ const meshNames = cfg.meshes.map((m) => m.slug).join(", ");
54970
+ writeCentered(contentRow, green2("✓") + " MCP registered");
54971
+ writeCentered(contentRow + 1, green2("✓") + ` ${cfg.meshes.length} mesh(es): ${meshNames}`);
54972
+ writeCentered(contentRow + 2, "");
54973
+ writeCentered(contentRow + 3, bold2("Ready to launch."));
54974
+ menuRow = contentRow + 5;
54975
+ spinner.stop();
54976
+ const choice = await menuSelect({
54977
+ title: "What next?",
54978
+ items: [
54979
+ "Launch Claude Code session",
54980
+ "View peers",
54981
+ "Check status",
54982
+ "Run diagnostics",
54983
+ "Exit"
54984
+ ],
54985
+ row: menuRow
54986
+ });
54987
+ exitFullScreen();
54988
+ switch (choice) {
54989
+ case 0:
54990
+ console.log(green2("$") + ` claudemesh launch
54991
+ `);
54992
+ break;
54993
+ case 1:
54994
+ console.log(green2("$") + ` claudemesh peers
54995
+ `);
54996
+ break;
54997
+ case 2:
54998
+ console.log(green2("$") + ` claudemesh status
54999
+ `);
55000
+ break;
55001
+ case 3:
55002
+ console.log(green2("$") + ` claudemesh doctor
55003
+ `);
55004
+ break;
55005
+ }
55006
+ break;
55007
+ }
55008
+ case "broken-config": {
55009
+ writeCentered(contentRow, yellow("⚠") + " ~/.claudemesh/config.json is unreadable.");
55010
+ menuRow = contentRow + 2;
55011
+ spinner.stop();
55012
+ const choice = await menuSelect({
55013
+ title: "Recover",
55014
+ items: ["Run diagnostics", "Cancel"],
55015
+ row: menuRow
55016
+ });
55017
+ exitFullScreen();
55018
+ if (choice === 0) {
55019
+ console.log(green2("$") + ` claudemesh doctor
55020
+ `);
55021
+ }
55022
+ break;
55023
+ }
55024
+ }
55025
+ }
55026
+ function runWelcomePlain() {
55027
+ const { VERSION: VERSION2 } = (init_version(), __toCommonJS(exports_version));
55028
+ console.log(`claudemesh v${VERSION2} — peer mesh for Claude Code`);
54540
55029
  console.log("─".repeat(60));
54541
55030
  const state = detectState();
54542
55031
  switch (state) {
54543
55032
  case "no-install":
54544
- console.log("Welcome. Let's get you set up.");
54545
- console.log("");
54546
- console.log(bold2("Step 1:") + " register the MCP server + status hooks");
54547
- console.log(` ${green("$")} claudemesh install`);
54548
- console.log("");
54549
- console.log(dim("Step 2 (after restart): claudemesh join <invite-url>"));
54550
- console.log(dim("Step 3: claudemesh launch"));
55033
+ console.log("MCP not registered. Run: claudemesh install");
54551
55034
  break;
54552
55035
  case "no-meshes":
54553
- console.log(green("✓") + " MCP registered. Now join a mesh.");
54554
- console.log("");
54555
- console.log(bold2("Step 2:") + " join a mesh");
54556
- console.log(` ${green("$")} claudemesh join https://claudemesh.com/join/<token>`);
54557
- console.log("");
54558
- console.log(dim(" Don't have an invite? Create one at ") + bold2("https://claudemesh.com") + dim(" or ask a mesh owner."));
54559
- console.log("");
54560
- console.log(dim("Step 3 (after joining): claudemesh launch"));
55036
+ console.log("No meshes joined. Run: claudemesh join <invite-url>");
54561
55037
  break;
54562
55038
  case "ready": {
54563
55039
  const cfg = loadConfig();
54564
- const meshNames = cfg.meshes.map((m) => m.slug).join(", ");
54565
- console.log(green("✓") + " MCP registered.");
54566
- console.log(green("✓") + ` ${cfg.meshes.length} mesh(es) joined: ${meshNames}`);
54567
- console.log("");
54568
- console.log(bold2("You're ready.") + " Launch Claude Code with real-time peer messages:");
54569
- console.log(` ${green("$")} claudemesh launch`);
54570
- console.log("");
54571
- console.log(dim(" (Plain `claude` works too — messages pull-only via check_messages.)"));
54572
- console.log("");
54573
- console.log(dim("Health check: claudemesh status"));
54574
- console.log(dim("Diagnostics: claudemesh doctor"));
54575
- console.log(dim("All commands: claudemesh --help"));
55040
+ console.log(`${cfg.meshes.length} mesh(es) joined. Run: claudemesh launch`);
54576
55041
  break;
54577
55042
  }
54578
55043
  case "broken-config":
54579
- console.log(yellow("⚠") + " Your ~/.claudemesh/config.json is unreadable.");
54580
- console.log("");
54581
- console.log("Run diagnostics to see what's wrong:");
54582
- console.log(` ${green("$")} claudemesh doctor`);
55044
+ console.log("Config unreadable. Run: claudemesh doctor");
54583
55045
  break;
54584
55046
  }
54585
55047
  console.log("");
@@ -54623,10 +55085,10 @@ Joined: ${config2.meshes.map((m) => m.slug).join(", ")}`);
54623
55085
  // src/commands/peers.ts
54624
55086
  async function runPeers(flags) {
54625
55087
  const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
54626
- const dim = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
54627
- const bold2 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
54628
- const green = (s) => useColor ? `\x1B[32m${s}\x1B[39m` : s;
54629
- const yellow = (s) => useColor ? `\x1B[33m${s}\x1B[39m` : s;
55088
+ const dim2 = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
55089
+ const bold3 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
55090
+ const green3 = (s) => useColor ? `\x1B[32m${s}\x1B[39m` : s;
55091
+ const yellow2 = (s) => useColor ? `\x1B[33m${s}\x1B[39m` : s;
54630
55092
  await withMesh({ meshSlug: flags.mesh ?? null }, async (client2, mesh) => {
54631
55093
  const peers = await client2.listPeers();
54632
55094
  if (flags.json) {
@@ -54634,15 +55096,15 @@ async function runPeers(flags) {
54634
55096
  return;
54635
55097
  }
54636
55098
  if (peers.length === 0) {
54637
- console.log(dim(`No peers connected on mesh "${mesh.slug}".`));
55099
+ console.log(dim2(`No peers connected on mesh "${mesh.slug}".`));
54638
55100
  return;
54639
55101
  }
54640
- console.log(bold2(`Peers on ${mesh.slug}`) + dim(` (${peers.length})`));
55102
+ console.log(bold3(`Peers on ${mesh.slug}`) + dim2(` (${peers.length})`));
54641
55103
  console.log("");
54642
55104
  for (const p of peers) {
54643
55105
  const groups = p.groups.length ? " [" + p.groups.map((g) => `@${g.name}${g.role ? `:${g.role}` : ""}`).join(", ") + "]" : "";
54644
- const statusIcon = p.status === "working" ? yellow("●") : green("●");
54645
- const name = bold2(p.displayName);
55106
+ const statusIcon = p.status === "working" ? yellow2("●") : green3("●");
55107
+ const name = bold3(p.displayName);
54646
55108
  const meta2 = [];
54647
55109
  if (p.peerType)
54648
55110
  meta2.push(p.peerType);
@@ -54650,9 +55112,9 @@ async function runPeers(flags) {
54650
55112
  meta2.push(p.channel);
54651
55113
  if (p.model)
54652
55114
  meta2.push(p.model);
54653
- const metaStr = meta2.length ? dim(` (${meta2.join(", ")})`) : "";
54654
- const cwdStr = p.cwd ? dim(` cwd: ${p.cwd}`) : "";
54655
- const summary = p.summary ? dim(` ${p.summary}`) : "";
55115
+ const metaStr = meta2.length ? dim2(` (${meta2.join(", ")})`) : "";
55116
+ const cwdStr = p.cwd ? dim2(` cwd: ${p.cwd}`) : "";
55117
+ const summary = p.summary ? dim2(` ${p.summary}`) : "";
54656
55118
  console.log(` ${statusIcon} ${name}${groups}${metaStr}${summary}`);
54657
55119
  if (cwdStr)
54658
55120
  console.log(` ${cwdStr}`);
@@ -54688,19 +55150,19 @@ async function runSend(flags, to, message) {
54688
55150
 
54689
55151
  // src/commands/inbox.ts
54690
55152
  function formatMessage(msg, useColor) {
54691
- const dim = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
54692
- const bold2 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
55153
+ const dim2 = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
55154
+ const bold3 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
54693
55155
  const text2 = msg.plaintext ?? `[encrypted: ${msg.ciphertext.slice(0, 32)}…]`;
54694
55156
  const from = msg.senderPubkey.slice(0, 8);
54695
55157
  const time3 = new Date(msg.createdAt).toLocaleTimeString();
54696
55158
  const kindTag = msg.kind === "direct" ? "→ direct" : msg.kind;
54697
- return ` ${bold2(from)} ${dim(`[${kindTag}] ${time3}`)}
55159
+ return ` ${bold3(from)} ${dim2(`[${kindTag}] ${time3}`)}
54698
55160
  ${text2}`;
54699
55161
  }
54700
55162
  async function runInbox(flags) {
54701
55163
  const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
54702
- const dim = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
54703
- const bold2 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
55164
+ const dim2 = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
55165
+ const bold3 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
54704
55166
  const waitMs = (flags.wait ?? 1) * 1000;
54705
55167
  await withMesh({ meshSlug: flags.mesh ?? null }, async (client2, mesh) => {
54706
55168
  await new Promise((resolve2) => setTimeout(resolve2, waitMs));
@@ -54710,10 +55172,10 @@ async function runInbox(flags) {
54710
55172
  return;
54711
55173
  }
54712
55174
  if (messages.length === 0) {
54713
- console.log(dim(`No messages on mesh "${mesh.slug}".`));
55175
+ console.log(dim2(`No messages on mesh "${mesh.slug}".`));
54714
55176
  return;
54715
55177
  }
54716
- console.log(bold2(`Inbox — ${mesh.slug}`) + dim(` (${messages.length} message${messages.length === 1 ? "" : "s"})`));
55178
+ console.log(bold3(`Inbox — ${mesh.slug}`) + dim2(` (${messages.length} message${messages.length === 1 ? "" : "s"})`));
54717
55179
  console.log("");
54718
55180
  for (const msg of messages) {
54719
55181
  console.log(formatMessage(msg, useColor));
@@ -54725,11 +55187,11 @@ async function runInbox(flags) {
54725
55187
  // src/commands/state.ts
54726
55188
  async function runStateGet(flags, key) {
54727
55189
  const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
54728
- const dim = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
55190
+ const dim2 = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
54729
55191
  await withMesh({ meshSlug: flags.mesh ?? null }, async (client2) => {
54730
55192
  const entry = await client2.getState(key);
54731
55193
  if (!entry) {
54732
- console.log(dim(`(not set)`));
55194
+ console.log(dim2(`(not set)`));
54733
55195
  return;
54734
55196
  }
54735
55197
  if (flags.json) {
@@ -54738,7 +55200,7 @@ async function runStateGet(flags, key) {
54738
55200
  }
54739
55201
  const val = typeof entry.value === "string" ? entry.value : JSON.stringify(entry.value);
54740
55202
  console.log(val);
54741
- console.log(dim(` set by ${entry.updatedBy} at ${new Date(entry.updatedAt).toLocaleString()}`));
55203
+ console.log(dim2(` set by ${entry.updatedBy} at ${new Date(entry.updatedAt).toLocaleString()}`));
54742
55204
  });
54743
55205
  }
54744
55206
  async function runStateSet(flags, key, value) {
@@ -54755,8 +55217,8 @@ async function runStateSet(flags, key, value) {
54755
55217
  }
54756
55218
  async function runStateList(flags) {
54757
55219
  const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
54758
- const dim = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
54759
- const bold2 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
55220
+ const dim2 = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
55221
+ const bold3 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
54760
55222
  await withMesh({ meshSlug: flags.mesh ?? null }, async (client2, mesh) => {
54761
55223
  const entries = await client2.listState();
54762
55224
  if (flags.json) {
@@ -54764,13 +55226,13 @@ async function runStateList(flags) {
54764
55226
  return;
54765
55227
  }
54766
55228
  if (entries.length === 0) {
54767
- console.log(dim(`No state on mesh "${mesh.slug}".`));
55229
+ console.log(dim2(`No state on mesh "${mesh.slug}".`));
54768
55230
  return;
54769
55231
  }
54770
55232
  for (const e of entries) {
54771
55233
  const val = typeof e.value === "string" ? e.value : JSON.stringify(e.value);
54772
- console.log(`${bold2(e.key)}: ${val}`);
54773
- console.log(dim(` ${e.updatedBy} · ${new Date(e.updatedAt).toLocaleString()}`));
55234
+ console.log(`${bold3(e.key)}: ${val}`);
55235
+ console.log(dim2(` ${e.updatedBy} · ${new Date(e.updatedAt).toLocaleString()}`));
54774
55236
  }
54775
55237
  });
54776
55238
  }
@@ -54794,8 +55256,8 @@ async function runRemember(flags, content) {
54794
55256
  }
54795
55257
  async function runRecall(flags, query) {
54796
55258
  const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
54797
- const dim = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
54798
- 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;
54799
55261
  await withMesh({ meshSlug: flags.mesh ?? null }, async (client2) => {
54800
55262
  const memories = await client2.recall(query);
54801
55263
  if (flags.json) {
@@ -54803,14 +55265,14 @@ async function runRecall(flags, query) {
54803
55265
  return;
54804
55266
  }
54805
55267
  if (memories.length === 0) {
54806
- console.log(dim("No memories found."));
55268
+ console.log(dim2("No memories found."));
54807
55269
  return;
54808
55270
  }
54809
55271
  for (const m of memories) {
54810
- const tags = m.tags.length ? dim(` [${m.tags.join(", ")}]`) : "";
54811
- console.log(`${bold2(m.id.slice(0, 8))}${tags}`);
55272
+ const tags = m.tags.length ? dim2(` [${m.tags.join(", ")}]`) : "";
55273
+ console.log(`${bold3(m.id.slice(0, 8))}${tags}`);
54812
55274
  console.log(` ${m.content}`);
54813
- console.log(dim(` ${m.rememberedBy} · ${new Date(m.rememberedAt).toLocaleString()}`));
55275
+ console.log(dim2(` ${m.rememberedBy} · ${new Date(m.rememberedAt).toLocaleString()}`));
54814
55276
  console.log("");
54815
55277
  }
54816
55278
  });
@@ -54820,8 +55282,8 @@ async function runRecall(flags, query) {
54820
55282
  init_config();
54821
55283
  async function runInfo(flags) {
54822
55284
  const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
54823
- const dim = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
54824
- const bold2 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
55285
+ const dim2 = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
55286
+ const bold3 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
54825
55287
  const config2 = loadConfig();
54826
55288
  await withMesh({ meshSlug: flags.mesh ?? null }, async (client2, mesh) => {
54827
55289
  const [brokerInfo, peers, state] = await Promise.all([
@@ -54843,16 +55305,16 @@ async function runInfo(flags) {
54843
55305
  console.log(JSON.stringify(output, null, 2));
54844
55306
  return;
54845
55307
  }
54846
- console.log(bold2(mesh.slug) + dim(` · ${mesh.brokerUrl}`));
54847
- console.log(dim(` mesh: ${mesh.meshId}`));
54848
- console.log(dim(` member: ${mesh.memberId}`));
55308
+ console.log(bold3(mesh.slug) + dim2(` · ${mesh.brokerUrl}`));
55309
+ console.log(dim2(` mesh: ${mesh.meshId}`));
55310
+ console.log(dim2(` member: ${mesh.memberId}`));
54849
55311
  console.log(` peers: ${peers.length} connected`);
54850
55312
  console.log(` state: ${state.length} keys`);
54851
55313
  if (brokerInfo && typeof brokerInfo === "object") {
54852
55314
  for (const [k, v] of Object.entries(brokerInfo)) {
54853
55315
  if (["slug", "meshId", "brokerUrl"].includes(k))
54854
55316
  continue;
54855
- console.log(dim(` ${k}: ${JSON.stringify(v)}`));
55317
+ console.log(dim2(` ${k}: ${JSON.stringify(v)}`));
54856
55318
  }
54857
55319
  }
54858
55320
  });
@@ -54897,8 +55359,8 @@ function parseDeliverAt(flags) {
54897
55359
  }
54898
55360
  async function runRemind(flags, positional) {
54899
55361
  const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
54900
- const dim = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
54901
- const bold2 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
55362
+ const dim2 = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
55363
+ const bold3 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
54902
55364
  const action = positional[0];
54903
55365
  if (action === "list") {
54904
55366
  await withMesh({ meshSlug: flags.mesh ?? null }, async (client2) => {
@@ -54908,14 +55370,14 @@ async function runRemind(flags, positional) {
54908
55370
  return;
54909
55371
  }
54910
55372
  if (scheduled.length === 0) {
54911
- console.log(dim("No pending reminders."));
55373
+ console.log(dim2("No pending reminders."));
54912
55374
  return;
54913
55375
  }
54914
55376
  for (const m of scheduled) {
54915
55377
  const when = new Date(m.deliverAt).toLocaleString();
54916
- const to = m.to === client2.getSessionPubkey() ? dim("(self)") : m.to;
54917
- console.log(` ${bold2(m.id.slice(0, 8))} → ${to} at ${when}`);
54918
- console.log(` ${dim(m.message.slice(0, 80))}`);
55378
+ const to = m.to === client2.getSessionPubkey() ? dim2("(self)") : m.to;
55379
+ console.log(` ${bold3(m.id.slice(0, 8))} → ${to} at ${when}`);
55380
+ console.log(` ${dim2(m.message.slice(0, 80))}`);
54919
55381
  console.log("");
54920
55382
  }
54921
55383
  });
@@ -55128,14 +55590,14 @@ import { hostname as hostname4 } from "node:os";
55128
55590
  init_keypair();
55129
55591
  async function runSync(args) {
55130
55592
  const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
55131
- const dim = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
55132
- const green = (s) => useColor ? `\x1B[32m${s}\x1B[39m` : s;
55593
+ const dim2 = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
55594
+ const green3 = (s) => useColor ? `\x1B[32m${s}\x1B[39m` : s;
55133
55595
  const config2 = loadConfig();
55134
55596
  const code = generatePairingCode();
55135
55597
  const listener = await startCallbackListener();
55136
55598
  const url = `https://claudemesh.com/cli-auth?port=${listener.port}&code=${code}&action=sync`;
55137
55599
  console.log(`Opening browser to sync meshes...`);
55138
- console.log(dim(`Visit: ${url}`));
55600
+ console.log(dim2(`Visit: ${url}`));
55139
55601
  await openBrowser(url);
55140
55602
  const manualPromise = new Promise((resolve2) => {
55141
55603
  const rl = createInterface2({ input: process.stdin, output: process.stdout });
@@ -55180,7 +55642,7 @@ async function runSync(args) {
55180
55642
  config2.accountId = result.account_id;
55181
55643
  saveConfig(config2);
55182
55644
  if (added > 0) {
55183
- console.log(green(`✓ Added ${added} new mesh(es)`));
55645
+ console.log(green3(`✓ Added ${added} new mesh(es)`));
55184
55646
  } else {
55185
55647
  console.log(`Already up to date (${config2.meshes.length} meshes)`);
55186
55648
  }
@@ -55190,8 +55652,8 @@ async function runSync(args) {
55190
55652
  init_config();
55191
55653
  async function runProfile(flags) {
55192
55654
  const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
55193
- const dim = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
55194
- const green = (s) => useColor ? `\x1B[32m${s}\x1B[39m` : s;
55655
+ const dim2 = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
55656
+ const green3 = (s) => useColor ? `\x1B[32m${s}\x1B[39m` : s;
55195
55657
  const config2 = loadConfig();
55196
55658
  if (config2.meshes.length === 0) {
55197
55659
  console.error("No meshes joined. Run `claudemesh join <url>` first.");
@@ -55231,9 +55693,9 @@ async function runProfile(flags) {
55231
55693
  if (flags.json) {
55232
55694
  console.log(JSON.stringify(result, null, 2));
55233
55695
  } else if (result.ok) {
55234
- console.log(green("✓ Profile updated"));
55696
+ console.log(green3("✓ Profile updated"));
55235
55697
  const member = result.member;
55236
- printProfile(member, dim);
55698
+ printProfile(member, dim2);
55237
55699
  } else {
55238
55700
  console.error(`Error: ${result.error}`);
55239
55701
  process.exit(1);
@@ -55249,21 +55711,21 @@ async function runProfile(flags) {
55249
55711
  if (flags.json) {
55250
55712
  console.log(JSON.stringify(me ?? {}, null, 2));
55251
55713
  } else if (me) {
55252
- printProfile(me, dim);
55714
+ printProfile(me, dim2);
55253
55715
  } else {
55254
55716
  console.log("Member not found in mesh.");
55255
55717
  }
55256
55718
  }
55257
55719
  }
55258
- function printProfile(member, dim) {
55720
+ function printProfile(member, dim2) {
55259
55721
  const groups = member.groups;
55260
- const groupStr = groups?.length ? groups.map((g) => g.role ? `${g.name} (${g.role})` : g.name).join(", ") : dim("(none)");
55261
- console.log(` Name: ${member.displayName ?? dim("(not set)")}`);
55262
- console.log(` Role: ${member.roleTag ?? dim("(not set)")}`);
55722
+ const groupStr = groups?.length ? groups.map((g) => g.role ? `${g.name} (${g.role})` : g.name).join(", ") : dim2("(none)");
55723
+ console.log(` Name: ${member.displayName ?? dim2("(not set)")}`);
55724
+ console.log(` Role: ${member.roleTag ?? dim2("(not set)")}`);
55263
55725
  console.log(` Groups: ${groupStr}`);
55264
55726
  console.log(` Messages: ${member.messageMode ?? "push"}`);
55265
55727
  console.log(` Access: ${member.permission ?? "member"}`);
55266
- console.log(` Mesh: ${dim(String(member.id ?? ""))}`);
55728
+ console.log(` Mesh: ${dim2(String(member.id ?? ""))}`);
55267
55729
  }
55268
55730
 
55269
55731
  // src/commands/connect-telegram.ts
@@ -55323,6 +55785,7 @@ async function disconnectTelegram() {
55323
55785
  }
55324
55786
 
55325
55787
  // src/index.ts
55788
+ init_version();
55326
55789
  var launch = defineCommand({
55327
55790
  meta: {
55328
55791
  name: "launch",
@@ -55657,8 +56120,8 @@ var main = defineCommand({
55657
56120
  }
55658
56121
  })
55659
56122
  },
55660
- run() {
55661
- runWelcome();
56123
+ async run() {
56124
+ await runWelcome();
55662
56125
  }
55663
56126
  });
55664
56127
  runMain(main);