claudemesh-cli 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/entrypoints/cli.js +442 -351
- package/dist/entrypoints/cli.js.map +24 -24
- package/dist/entrypoints/mcp.js +36 -3
- package/dist/entrypoints/mcp.js.map +4 -4
- package/package.json +1 -1
package/dist/entrypoints/cli.js
CHANGED
|
@@ -88,7 +88,7 @@ __export(exports_urls, {
|
|
|
88
88
|
VERSION: () => VERSION,
|
|
89
89
|
URLS: () => URLS
|
|
90
90
|
});
|
|
91
|
-
var URLS, VERSION = "1.0.
|
|
91
|
+
var URLS, VERSION = "1.0.2", env;
|
|
92
92
|
var init_urls = __esm(() => {
|
|
93
93
|
URLS = {
|
|
94
94
|
BROKER: process.env.CLAUDEMESH_BROKER_URL ?? "wss://ic.claudemesh.com/ws",
|
|
@@ -1150,6 +1150,7 @@ class BrokerClient {
|
|
|
1150
1150
|
return this._serviceCatalog;
|
|
1151
1151
|
}
|
|
1152
1152
|
closed = false;
|
|
1153
|
+
terminalClose = null;
|
|
1153
1154
|
reconnectAttempt = 0;
|
|
1154
1155
|
helloTimer = null;
|
|
1155
1156
|
reconnectTimer = null;
|
|
@@ -1277,12 +1278,22 @@ class BrokerClient {
|
|
|
1277
1278
|
}
|
|
1278
1279
|
this.handleServerMessage(msg);
|
|
1279
1280
|
};
|
|
1280
|
-
const onClose = () => {
|
|
1281
|
+
const onClose = (code, reasonBuf) => {
|
|
1281
1282
|
if (this.helloTimer)
|
|
1282
1283
|
clearTimeout(this.helloTimer);
|
|
1283
1284
|
this.helloTimer = null;
|
|
1284
1285
|
if (this.ws === ws)
|
|
1285
1286
|
this.ws = null;
|
|
1287
|
+
const reason = reasonBuf?.toString("utf-8") ?? "";
|
|
1288
|
+
if (code === 4001 || code === 4002) {
|
|
1289
|
+
this.closed = true;
|
|
1290
|
+
this.setConnStatus("closed");
|
|
1291
|
+
this.terminalClose = { code, reason };
|
|
1292
|
+
if (this._status !== "open") {
|
|
1293
|
+
reject(new Error(`ws terminal close ${code}: ${reason || "session ended"}`));
|
|
1294
|
+
}
|
|
1295
|
+
return;
|
|
1296
|
+
}
|
|
1286
1297
|
if (this._status !== "open" && this._status !== "reconnecting") {
|
|
1287
1298
|
reject(new Error("ws closed before hello_ack"));
|
|
1288
1299
|
}
|
|
@@ -2965,6 +2976,9 @@ class BrokerClient {
|
|
|
2965
2976
|
}
|
|
2966
2977
|
if (msg.type === "error") {
|
|
2967
2978
|
this.debug(`broker error: ${msg.code} ${msg.message}`);
|
|
2979
|
+
if (msg.code === "revoked") {
|
|
2980
|
+
this.terminalClose = { code: 4002, reason: String(msg.message ?? "revoked") };
|
|
2981
|
+
}
|
|
2968
2982
|
const id = msg.id ? String(msg.id) : null;
|
|
2969
2983
|
let handledByPendingSend = false;
|
|
2970
2984
|
if (id) {
|
|
@@ -3156,6 +3170,75 @@ var init_facade8 = __esm(() => {
|
|
|
3156
3170
|
init_errors3();
|
|
3157
3171
|
});
|
|
3158
3172
|
|
|
3173
|
+
// src/ui/render.ts
|
|
3174
|
+
var OUT, ERR, INDENT = " ", render;
|
|
3175
|
+
var init_render = __esm(() => {
|
|
3176
|
+
init_styles();
|
|
3177
|
+
OUT = process.stdout;
|
|
3178
|
+
ERR = process.stderr;
|
|
3179
|
+
render = {
|
|
3180
|
+
blank() {
|
|
3181
|
+
OUT.write(`
|
|
3182
|
+
`);
|
|
3183
|
+
},
|
|
3184
|
+
ok(msg, detail) {
|
|
3185
|
+
const d = detail ? ` ${dim("(" + detail + ")")}` : "";
|
|
3186
|
+
OUT.write(`${INDENT}${green(icons.check)} ${msg}${d}
|
|
3187
|
+
`);
|
|
3188
|
+
},
|
|
3189
|
+
warn(msg, hint) {
|
|
3190
|
+
OUT.write(`${INDENT}${yellow(icons.warn)} ${msg}
|
|
3191
|
+
`);
|
|
3192
|
+
if (hint)
|
|
3193
|
+
OUT.write(`${INDENT} ${dim(hint)}
|
|
3194
|
+
`);
|
|
3195
|
+
},
|
|
3196
|
+
err(msg, hint) {
|
|
3197
|
+
ERR.write(`${INDENT}${red(icons.cross)} ${msg}
|
|
3198
|
+
`);
|
|
3199
|
+
if (hint)
|
|
3200
|
+
ERR.write(`${INDENT} ${dim(hint)}
|
|
3201
|
+
`);
|
|
3202
|
+
},
|
|
3203
|
+
info(msg) {
|
|
3204
|
+
OUT.write(`${INDENT}${msg}
|
|
3205
|
+
`);
|
|
3206
|
+
},
|
|
3207
|
+
section(title) {
|
|
3208
|
+
OUT.write(`
|
|
3209
|
+
${INDENT}${dim("—")} ${clay(title)}
|
|
3210
|
+
|
|
3211
|
+
`);
|
|
3212
|
+
},
|
|
3213
|
+
heading(title) {
|
|
3214
|
+
OUT.write(`${INDENT}${bold(title)}
|
|
3215
|
+
`);
|
|
3216
|
+
},
|
|
3217
|
+
kv(pairs, opts) {
|
|
3218
|
+
const pad = opts?.padTo ?? Math.max(...pairs.map(([k]) => k.length)) + 2;
|
|
3219
|
+
for (const [k, v] of pairs) {
|
|
3220
|
+
OUT.write(`${INDENT}${dim(k.padEnd(pad, " "))}${v}
|
|
3221
|
+
`);
|
|
3222
|
+
}
|
|
3223
|
+
},
|
|
3224
|
+
code(snippet) {
|
|
3225
|
+
for (const line of snippet.split(`
|
|
3226
|
+
`)) {
|
|
3227
|
+
OUT.write(`${INDENT} ${cyan(line)}
|
|
3228
|
+
`);
|
|
3229
|
+
}
|
|
3230
|
+
},
|
|
3231
|
+
link(url) {
|
|
3232
|
+
OUT.write(`${INDENT}${clay(url)}
|
|
3233
|
+
`);
|
|
3234
|
+
},
|
|
3235
|
+
hint(msg) {
|
|
3236
|
+
OUT.write(`${INDENT}${dim(icons.arrow + " " + msg)}
|
|
3237
|
+
`);
|
|
3238
|
+
}
|
|
3239
|
+
};
|
|
3240
|
+
});
|
|
3241
|
+
|
|
3159
3242
|
// src/ui/screen.ts
|
|
3160
3243
|
import { createInterface as createInterface2 } from "node:readline";
|
|
3161
3244
|
function termSize() {
|
|
@@ -3512,7 +3595,7 @@ async function runLaunch(flags, rawArgs) {
|
|
|
3512
3595
|
claudeArgs: claudePassthrough
|
|
3513
3596
|
};
|
|
3514
3597
|
if (args.joinLink) {
|
|
3515
|
-
|
|
3598
|
+
render.info(dim("Joining mesh…"));
|
|
3516
3599
|
const invite = await parseInviteLink(args.joinLink);
|
|
3517
3600
|
const keypair = await generateKeypair();
|
|
3518
3601
|
const displayName2 = args.name ?? process.env.USER ?? process.env.USERNAME ?? hostname2();
|
|
@@ -3537,7 +3620,7 @@ async function runLaunch(flags, rawArgs) {
|
|
|
3537
3620
|
});
|
|
3538
3621
|
const { writeConfig: writeConfig2 } = await Promise.resolve().then(() => (init_facade(), exports_facade));
|
|
3539
3622
|
writeConfig2(config2);
|
|
3540
|
-
|
|
3623
|
+
render.ok(`joined ${bold(invite.payload.mesh_slug)}`, enroll.alreadyMember ? "already member" : undefined);
|
|
3541
3624
|
}
|
|
3542
3625
|
const config = readConfig();
|
|
3543
3626
|
let justSynced = false;
|
|
@@ -3608,14 +3691,14 @@ async function runLaunch(flags, rawArgs) {
|
|
|
3608
3691
|
`);
|
|
3609
3692
|
}
|
|
3610
3693
|
if (config.meshes.length === 0) {
|
|
3611
|
-
|
|
3694
|
+
render.err("No meshes joined.", "Run `claudemesh join <url>` or use --join <url>.");
|
|
3612
3695
|
process.exit(1);
|
|
3613
3696
|
}
|
|
3614
3697
|
let mesh;
|
|
3615
3698
|
if (args.meshSlug) {
|
|
3616
3699
|
const found = config.meshes.find((m) => m.slug === args.meshSlug);
|
|
3617
3700
|
if (!found) {
|
|
3618
|
-
|
|
3701
|
+
render.err(`Mesh "${args.meshSlug}" not found.`, `Joined: ${config.meshes.map((m) => m.slug).join(", ")}`);
|
|
3619
3702
|
process.exit(1);
|
|
3620
3703
|
}
|
|
3621
3704
|
mesh = found;
|
|
@@ -3838,9 +3921,9 @@ async function runLaunch(flags, rawArgs) {
|
|
|
3838
3921
|
if (result.error) {
|
|
3839
3922
|
const err = result.error;
|
|
3840
3923
|
if (err.code === "ENOENT") {
|
|
3841
|
-
|
|
3924
|
+
render.err("`claude` not found on PATH.", "Install Claude Code first.");
|
|
3842
3925
|
} else {
|
|
3843
|
-
|
|
3926
|
+
render.err(`failed to launch claude: ${err.message}`);
|
|
3844
3927
|
}
|
|
3845
3928
|
process.exit(1);
|
|
3846
3929
|
}
|
|
@@ -3855,6 +3938,7 @@ var init_launch = __esm(() => {
|
|
|
3855
3938
|
init_facade6();
|
|
3856
3939
|
init_facade5();
|
|
3857
3940
|
init_facade8();
|
|
3941
|
+
init_render();
|
|
3858
3942
|
init_styles();
|
|
3859
3943
|
init_screen();
|
|
3860
3944
|
init_spinner();
|
|
@@ -3904,13 +3988,13 @@ function prompt(question) {
|
|
|
3904
3988
|
});
|
|
3905
3989
|
}
|
|
3906
3990
|
async function loginWithToken() {
|
|
3907
|
-
|
|
3908
|
-
Paste a token from ${dim(URLS.API_BASE + "/token")}`);
|
|
3909
|
-
|
|
3910
|
-
|
|
3991
|
+
render.blank();
|
|
3992
|
+
render.info(`Paste a token from ${dim(URLS.API_BASE + "/token")}`);
|
|
3993
|
+
render.info(dim("Generate one in your browser, then paste it here."));
|
|
3994
|
+
render.blank();
|
|
3911
3995
|
const token = await prompt(" Token: ");
|
|
3912
3996
|
if (!token) {
|
|
3913
|
-
|
|
3997
|
+
render.err("No token provided.");
|
|
3914
3998
|
return EXIT.AUTH_FAILED;
|
|
3915
3999
|
}
|
|
3916
4000
|
let user = { id: "", display_name: "", email: "" };
|
|
@@ -3919,7 +4003,7 @@ async function loginWithToken() {
|
|
|
3919
4003
|
if (parts[1]) {
|
|
3920
4004
|
const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString());
|
|
3921
4005
|
if (payload.exp && payload.exp < Date.now() / 1000) {
|
|
3922
|
-
|
|
4006
|
+
render.err("Token expired.", "Generate a new one.");
|
|
3923
4007
|
return EXIT.AUTH_FAILED;
|
|
3924
4008
|
}
|
|
3925
4009
|
user = {
|
|
@@ -3929,11 +4013,11 @@ async function loginWithToken() {
|
|
|
3929
4013
|
};
|
|
3930
4014
|
}
|
|
3931
4015
|
} catch {
|
|
3932
|
-
|
|
4016
|
+
render.err("Invalid token format.");
|
|
3933
4017
|
return EXIT.AUTH_FAILED;
|
|
3934
4018
|
}
|
|
3935
4019
|
storeToken({ session_token: token, user, token_source: "manual" });
|
|
3936
|
-
|
|
4020
|
+
render.ok(`signed in as ${bold(user.display_name || user.email || "user")}`);
|
|
3937
4021
|
return EXIT.SUCCESS;
|
|
3938
4022
|
}
|
|
3939
4023
|
async function syncMeshes(token) {
|
|
@@ -3941,7 +4025,7 @@ async function syncMeshes(token) {
|
|
|
3941
4025
|
const meshes = await exports_my.getMeshes(token);
|
|
3942
4026
|
if (meshes.length > 0) {
|
|
3943
4027
|
const names = meshes.map((m) => m.slug).join(", ");
|
|
3944
|
-
|
|
4028
|
+
render.ok(`synced ${meshes.length} mesh${meshes.length === 1 ? "" : "es"}`, names);
|
|
3945
4029
|
}
|
|
3946
4030
|
} catch {}
|
|
3947
4031
|
}
|
|
@@ -3949,23 +4033,27 @@ async function login() {
|
|
|
3949
4033
|
const existing = getStoredToken();
|
|
3950
4034
|
if (existing) {
|
|
3951
4035
|
const name = existing.user.display_name || existing.user.email || "unknown";
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
|
|
3955
|
-
|
|
3956
|
-
|
|
3957
|
-
|
|
3958
|
-
|
|
3959
|
-
|
|
4036
|
+
render.blank();
|
|
4037
|
+
render.info(`Already signed in as ${bold(name)}.`);
|
|
4038
|
+
render.blank();
|
|
4039
|
+
process.stdout.write(` ${bold("1)")} Continue as ${name}
|
|
4040
|
+
`);
|
|
4041
|
+
process.stdout.write(` ${bold("2)")} Sign in via browser
|
|
4042
|
+
`);
|
|
4043
|
+
process.stdout.write(` ${bold("3)")} Paste a token from ${dim("claudemesh.com/token")}
|
|
4044
|
+
`);
|
|
4045
|
+
process.stdout.write(` ${bold("4)")} Sign out
|
|
4046
|
+
`);
|
|
4047
|
+
render.blank();
|
|
3960
4048
|
const choice = await prompt(" Choice [1]: ") || "1";
|
|
3961
4049
|
if (choice === "1") {
|
|
3962
|
-
|
|
3963
|
-
|
|
4050
|
+
render.blank();
|
|
4051
|
+
render.ok(`continuing as ${bold(name)}`);
|
|
3964
4052
|
return EXIT.SUCCESS;
|
|
3965
4053
|
}
|
|
3966
4054
|
if (choice === "4") {
|
|
3967
4055
|
clearToken();
|
|
3968
|
-
|
|
4056
|
+
render.ok("signed out");
|
|
3969
4057
|
return EXIT.SUCCESS;
|
|
3970
4058
|
}
|
|
3971
4059
|
if (choice === "3") {
|
|
@@ -3973,14 +4061,16 @@ async function login() {
|
|
|
3973
4061
|
return loginWithToken();
|
|
3974
4062
|
}
|
|
3975
4063
|
clearToken();
|
|
3976
|
-
|
|
4064
|
+
render.info(dim("Signing in…"));
|
|
3977
4065
|
} else {
|
|
3978
|
-
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
|
|
4066
|
+
render.blank();
|
|
4067
|
+
render.heading(`${bold("claudemesh")} — sign in to connect your terminal`);
|
|
4068
|
+
render.blank();
|
|
4069
|
+
process.stdout.write(` ${bold("1)")} Sign in via browser ${dim("(opens automatically)")}
|
|
4070
|
+
`);
|
|
4071
|
+
process.stdout.write(` ${bold("2)")} Paste a token from ${dim("claudemesh.com/token")}
|
|
4072
|
+
`);
|
|
4073
|
+
render.blank();
|
|
3984
4074
|
const choice = await prompt(" Choice [1]: ") || "1";
|
|
3985
4075
|
if (choice === "2") {
|
|
3986
4076
|
return loginWithToken();
|
|
@@ -3988,91 +4078,23 @@ async function login() {
|
|
|
3988
4078
|
}
|
|
3989
4079
|
try {
|
|
3990
4080
|
const result = await loginWithDeviceCode();
|
|
3991
|
-
|
|
4081
|
+
render.ok(`signed in as ${bold(result.user.display_name)}`);
|
|
3992
4082
|
await syncMeshes(result.session_token);
|
|
3993
4083
|
return EXIT.SUCCESS;
|
|
3994
4084
|
} catch (err) {
|
|
3995
|
-
|
|
4085
|
+
render.err(`Login failed: ${err instanceof Error ? err.message : err}`);
|
|
3996
4086
|
return EXIT.AUTH_FAILED;
|
|
3997
4087
|
}
|
|
3998
4088
|
}
|
|
3999
4089
|
var init_login = __esm(() => {
|
|
4000
4090
|
init_facade6();
|
|
4001
4091
|
init_facade3();
|
|
4092
|
+
init_render();
|
|
4002
4093
|
init_styles();
|
|
4003
4094
|
init_exit_codes();
|
|
4004
4095
|
init_urls();
|
|
4005
4096
|
});
|
|
4006
4097
|
|
|
4007
|
-
// src/ui/render.ts
|
|
4008
|
-
var OUT, ERR, INDENT = " ", render;
|
|
4009
|
-
var init_render = __esm(() => {
|
|
4010
|
-
init_styles();
|
|
4011
|
-
OUT = process.stdout;
|
|
4012
|
-
ERR = process.stderr;
|
|
4013
|
-
render = {
|
|
4014
|
-
blank() {
|
|
4015
|
-
OUT.write(`
|
|
4016
|
-
`);
|
|
4017
|
-
},
|
|
4018
|
-
ok(msg, detail) {
|
|
4019
|
-
const d = detail ? ` ${dim("(" + detail + ")")}` : "";
|
|
4020
|
-
OUT.write(`${INDENT}${green(icons.check)} ${msg}${d}
|
|
4021
|
-
`);
|
|
4022
|
-
},
|
|
4023
|
-
warn(msg, hint) {
|
|
4024
|
-
OUT.write(`${INDENT}${yellow(icons.warn)} ${msg}
|
|
4025
|
-
`);
|
|
4026
|
-
if (hint)
|
|
4027
|
-
OUT.write(`${INDENT} ${dim(hint)}
|
|
4028
|
-
`);
|
|
4029
|
-
},
|
|
4030
|
-
err(msg, hint) {
|
|
4031
|
-
ERR.write(`${INDENT}${red(icons.cross)} ${msg}
|
|
4032
|
-
`);
|
|
4033
|
-
if (hint)
|
|
4034
|
-
ERR.write(`${INDENT} ${dim(hint)}
|
|
4035
|
-
`);
|
|
4036
|
-
},
|
|
4037
|
-
info(msg) {
|
|
4038
|
-
OUT.write(`${INDENT}${msg}
|
|
4039
|
-
`);
|
|
4040
|
-
},
|
|
4041
|
-
section(title) {
|
|
4042
|
-
OUT.write(`
|
|
4043
|
-
${INDENT}${dim("—")} ${clay(title)}
|
|
4044
|
-
|
|
4045
|
-
`);
|
|
4046
|
-
},
|
|
4047
|
-
heading(title) {
|
|
4048
|
-
OUT.write(`${INDENT}${bold(title)}
|
|
4049
|
-
`);
|
|
4050
|
-
},
|
|
4051
|
-
kv(pairs, opts) {
|
|
4052
|
-
const pad = opts?.padTo ?? Math.max(...pairs.map(([k]) => k.length)) + 2;
|
|
4053
|
-
for (const [k, v] of pairs) {
|
|
4054
|
-
OUT.write(`${INDENT}${dim(k.padEnd(pad, " "))}${v}
|
|
4055
|
-
`);
|
|
4056
|
-
}
|
|
4057
|
-
},
|
|
4058
|
-
code(snippet) {
|
|
4059
|
-
for (const line of snippet.split(`
|
|
4060
|
-
`)) {
|
|
4061
|
-
OUT.write(`${INDENT} ${cyan(line)}
|
|
4062
|
-
`);
|
|
4063
|
-
}
|
|
4064
|
-
},
|
|
4065
|
-
link(url) {
|
|
4066
|
-
OUT.write(`${INDENT}${clay(url)}
|
|
4067
|
-
`);
|
|
4068
|
-
},
|
|
4069
|
-
hint(msg) {
|
|
4070
|
-
OUT.write(`${INDENT}${dim(icons.arrow + " " + msg)}
|
|
4071
|
-
`);
|
|
4072
|
-
}
|
|
4073
|
-
};
|
|
4074
|
-
});
|
|
4075
|
-
|
|
4076
4098
|
// src/commands/welcome.ts
|
|
4077
4099
|
var exports_welcome = {};
|
|
4078
4100
|
__export(exports_welcome, {
|
|
@@ -4237,17 +4259,17 @@ __export(exports_new, {
|
|
|
4237
4259
|
});
|
|
4238
4260
|
async function newMesh(name, opts) {
|
|
4239
4261
|
if (!name) {
|
|
4240
|
-
|
|
4262
|
+
render.err("Usage: claudemesh create <name>");
|
|
4241
4263
|
return EXIT.INVALID_ARGS;
|
|
4242
4264
|
}
|
|
4243
4265
|
if (!getStoredToken()) {
|
|
4244
|
-
|
|
4245
|
-
|
|
4266
|
+
render.info(dim("not signed in — starting login…"));
|
|
4267
|
+
render.blank();
|
|
4246
4268
|
const { login: login2 } = await Promise.resolve().then(() => (init_login(), exports_login));
|
|
4247
4269
|
const loginResult = await login2();
|
|
4248
4270
|
if (loginResult !== EXIT.SUCCESS)
|
|
4249
4271
|
return loginResult;
|
|
4250
|
-
|
|
4272
|
+
render.blank();
|
|
4251
4273
|
}
|
|
4252
4274
|
try {
|
|
4253
4275
|
const result = await createMesh2(name, {
|
|
@@ -4256,22 +4278,24 @@ async function newMesh(name, opts) {
|
|
|
4256
4278
|
});
|
|
4257
4279
|
if (opts.json) {
|
|
4258
4280
|
console.log(JSON.stringify({ schema_version: "1.0", ...result }, null, 2));
|
|
4259
|
-
|
|
4260
|
-
console.log(`
|
|
4261
|
-
${green(icons.check)} Created "${result.slug}" (id: ${result.id})`);
|
|
4262
|
-
console.log(` ${green(icons.check)} You're the owner`);
|
|
4263
|
-
console.log(` ${green(icons.check)} Joined locally`);
|
|
4264
|
-
console.log(`
|
|
4265
|
-
Share with: claudemesh mesh share
|
|
4266
|
-
`);
|
|
4281
|
+
return EXIT.SUCCESS;
|
|
4267
4282
|
}
|
|
4283
|
+
render.section(`created ${bold(result.slug)}`);
|
|
4284
|
+
render.kv([
|
|
4285
|
+
["id", dim(result.id)],
|
|
4286
|
+
["role", clay("owner")],
|
|
4287
|
+
["local", "joined"]
|
|
4288
|
+
]);
|
|
4289
|
+
render.blank();
|
|
4290
|
+
render.hint(`share with: ${bold("claudemesh share")}`);
|
|
4291
|
+
render.blank();
|
|
4268
4292
|
return EXIT.SUCCESS;
|
|
4269
4293
|
} catch (err) {
|
|
4270
4294
|
const msg = err instanceof Error ? err.message : String(err);
|
|
4271
4295
|
if (msg.includes("409") || msg.includes("already exists")) {
|
|
4272
|
-
|
|
4296
|
+
render.err("A mesh with this name already exists.", "Try a different name.");
|
|
4273
4297
|
} else {
|
|
4274
|
-
|
|
4298
|
+
render.err(`Failed: ${msg}`);
|
|
4275
4299
|
}
|
|
4276
4300
|
return EXIT.INTERNAL_ERROR;
|
|
4277
4301
|
}
|
|
@@ -4279,6 +4303,7 @@ async function newMesh(name, opts) {
|
|
|
4279
4303
|
var init_new = __esm(() => {
|
|
4280
4304
|
init_facade10();
|
|
4281
4305
|
init_facade6();
|
|
4306
|
+
init_render();
|
|
4282
4307
|
init_styles();
|
|
4283
4308
|
init_exit_codes();
|
|
4284
4309
|
});
|
|
@@ -4723,24 +4748,20 @@ async function runList() {
|
|
|
4723
4748
|
const serverSlugs = new Set(serverMeshes.map((m) => m.slug));
|
|
4724
4749
|
const allSlugs = new Set([...localSlugs, ...serverSlugs]);
|
|
4725
4750
|
if (allSlugs.size === 0) {
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
`);
|
|
4729
|
-
|
|
4730
|
-
console.log(` Join one: claudemesh mesh add <invite-url>
|
|
4731
|
-
`);
|
|
4751
|
+
render.section("no meshes yet");
|
|
4752
|
+
render.info(`${dim("create one:")} ${bold("claudemesh create")} ${clay("<name>")}`);
|
|
4753
|
+
render.info(`${dim("join one:")} ${bold("claudemesh")} ${clay("<invite-url>")}`);
|
|
4754
|
+
render.blank();
|
|
4732
4755
|
return;
|
|
4733
4756
|
}
|
|
4734
|
-
|
|
4735
|
-
Your meshes:
|
|
4736
|
-
`);
|
|
4757
|
+
render.section(`your meshes (${allSlugs.size})`);
|
|
4737
4758
|
for (const slug of allSlugs) {
|
|
4738
4759
|
const local = config.meshes.find((m) => m.slug === slug);
|
|
4739
4760
|
const server = serverMeshes.find((m) => m.slug === slug);
|
|
4740
4761
|
const name = server?.name ?? local?.name ?? slug;
|
|
4741
4762
|
const role = server?.role ?? "member";
|
|
4742
4763
|
const isOwner = server?.is_owner ?? false;
|
|
4743
|
-
const roleLabel = isOwner ? "owner" : role;
|
|
4764
|
+
const roleLabel = isOwner ? clay("owner") : dim(role);
|
|
4744
4765
|
const memberCount = server?.member_count;
|
|
4745
4766
|
const activePeers = server?.active_peers ?? 0;
|
|
4746
4767
|
const inLocal = localSlugs.has(slug);
|
|
@@ -4759,15 +4780,18 @@ async function runList() {
|
|
|
4759
4780
|
}
|
|
4760
4781
|
const memberInfo = memberCount ? dim(`${memberCount} member${memberCount !== 1 ? "s" : ""}`) : "";
|
|
4761
4782
|
const parts = [roleLabel, memberInfo, status].filter(Boolean);
|
|
4762
|
-
|
|
4763
|
-
|
|
4783
|
+
process.stdout.write(` ${icon} ${bold(name)} ${dim(slug)}
|
|
4784
|
+
`);
|
|
4785
|
+
process.stdout.write(` ${parts.join(dim(" · "))}
|
|
4786
|
+
`);
|
|
4764
4787
|
}
|
|
4765
|
-
|
|
4788
|
+
process.stdout.write(`
|
|
4789
|
+
`);
|
|
4766
4790
|
if (serverMeshes.some((m) => !localSlugs.has(m.slug))) {
|
|
4767
|
-
|
|
4791
|
+
render.hint(`${dim("○")} = server only — run ${bold("claudemesh join")} to use locally`);
|
|
4768
4792
|
}
|
|
4769
|
-
|
|
4770
|
-
|
|
4793
|
+
render.hint(`config: ${dim(getConfigPath())}`);
|
|
4794
|
+
render.blank();
|
|
4771
4795
|
}
|
|
4772
4796
|
var BROKER_HTTP4;
|
|
4773
4797
|
var init_list2 = __esm(() => {
|
|
@@ -4776,6 +4800,7 @@ var init_list2 = __esm(() => {
|
|
|
4776
4800
|
init_facade3();
|
|
4777
4801
|
init_urls();
|
|
4778
4802
|
init_styles();
|
|
4803
|
+
init_render();
|
|
4779
4804
|
BROKER_HTTP4 = URLS.BROKER.replace("wss://", "https://").replace("ws://", "http://").replace("/ws", "");
|
|
4780
4805
|
});
|
|
4781
4806
|
|
|
@@ -4802,11 +4827,12 @@ function getUserId(token) {
|
|
|
4802
4827
|
return "";
|
|
4803
4828
|
}
|
|
4804
4829
|
}
|
|
4805
|
-
async function isOwner(slug,
|
|
4830
|
+
async function isOwner(slug, auth) {
|
|
4806
4831
|
try {
|
|
4807
4832
|
const res = await request({
|
|
4808
|
-
path: `/cli/meshes
|
|
4809
|
-
baseUrl: BROKER_HTTP5
|
|
4833
|
+
path: `/cli/meshes`,
|
|
4834
|
+
baseUrl: BROKER_HTTP5,
|
|
4835
|
+
token: auth.session_token
|
|
4810
4836
|
});
|
|
4811
4837
|
return res.meshes?.find((m) => m.slug === slug)?.is_owner ?? false;
|
|
4812
4838
|
} catch {
|
|
@@ -4817,86 +4843,88 @@ async function deleteMesh(slug, opts = {}) {
|
|
|
4817
4843
|
const config = readConfig();
|
|
4818
4844
|
if (!slug) {
|
|
4819
4845
|
if (config.meshes.length === 0) {
|
|
4820
|
-
|
|
4846
|
+
render.err("No meshes to remove.");
|
|
4821
4847
|
return EXIT.NOT_FOUND;
|
|
4822
4848
|
}
|
|
4823
|
-
|
|
4824
|
-
Select mesh to remove:
|
|
4825
|
-
`);
|
|
4849
|
+
render.section("select mesh to remove");
|
|
4826
4850
|
config.meshes.forEach((m, i) => {
|
|
4827
|
-
|
|
4851
|
+
process.stdout.write(` ${bold(String(i + 1) + ")")} ${clay(m.slug)} ${dim("(" + m.name + ")")}
|
|
4852
|
+
`);
|
|
4828
4853
|
});
|
|
4829
|
-
|
|
4830
|
-
const choice = await prompt3("
|
|
4854
|
+
render.blank();
|
|
4855
|
+
const choice = await prompt3(` ${dim("choice:")} `);
|
|
4831
4856
|
const idx = parseInt(choice, 10) - 1;
|
|
4832
4857
|
if (idx < 0 || idx >= config.meshes.length) {
|
|
4833
|
-
|
|
4858
|
+
render.info(dim("cancelled."));
|
|
4834
4859
|
return EXIT.USER_CANCELLED;
|
|
4835
4860
|
}
|
|
4836
4861
|
slug = config.meshes[idx].slug;
|
|
4837
4862
|
}
|
|
4838
4863
|
const auth = getStoredToken();
|
|
4839
4864
|
const userId = auth ? getUserId(auth.session_token) : "";
|
|
4840
|
-
const ownerCheck =
|
|
4865
|
+
const ownerCheck = auth ? await isOwner(slug, auth) : false;
|
|
4841
4866
|
if (!opts.yes) {
|
|
4842
|
-
|
|
4843
|
-
${bold(slug)}
|
|
4844
|
-
`);
|
|
4867
|
+
render.section(slug);
|
|
4845
4868
|
if (ownerCheck) {
|
|
4846
|
-
|
|
4847
|
-
|
|
4848
|
-
|
|
4849
|
-
|
|
4850
|
-
|
|
4869
|
+
process.stdout.write(` ${bold("1)")} remove from this device only ${dim("(keep on server)")}
|
|
4870
|
+
`);
|
|
4871
|
+
process.stdout.write(` ${bold("2)")} ${red("delete everywhere")} ${dim("(removes for all members)")}
|
|
4872
|
+
`);
|
|
4873
|
+
process.stdout.write(` ${bold("3)")} cancel
|
|
4874
|
+
`);
|
|
4875
|
+
render.blank();
|
|
4876
|
+
const choice = await prompt3(` ${dim("choice [1]:")} `) || "1";
|
|
4851
4877
|
if (choice === "3") {
|
|
4852
|
-
|
|
4878
|
+
render.info(dim("cancelled."));
|
|
4853
4879
|
return EXIT.USER_CANCELLED;
|
|
4854
4880
|
}
|
|
4855
4881
|
if (choice === "2") {
|
|
4856
|
-
|
|
4857
|
-
|
|
4858
|
-
const confirm = await prompt3(`
|
|
4882
|
+
render.blank();
|
|
4883
|
+
render.warn(`this will delete ${bold(slug)} for all members.`);
|
|
4884
|
+
const confirm = await prompt3(` ${dim(`type "${slug}" to confirm:`)} `);
|
|
4859
4885
|
if (confirm.toLowerCase() !== slug.toLowerCase()) {
|
|
4860
|
-
|
|
4886
|
+
render.info(dim("cancelled."));
|
|
4861
4887
|
return EXIT.USER_CANCELLED;
|
|
4862
4888
|
}
|
|
4863
4889
|
try {
|
|
4864
4890
|
await request({
|
|
4865
4891
|
path: `/cli/mesh/${slug}`,
|
|
4866
4892
|
method: "DELETE",
|
|
4867
|
-
|
|
4868
|
-
|
|
4893
|
+
baseUrl: BROKER_HTTP5,
|
|
4894
|
+
token: auth?.session_token,
|
|
4895
|
+
body: { user_id: userId }
|
|
4869
4896
|
});
|
|
4870
|
-
|
|
4897
|
+
render.ok(`deleted ${bold(slug)} from server.`);
|
|
4871
4898
|
} catch (err) {
|
|
4872
|
-
|
|
4873
|
-
console.error(` ${icons.cross} Server delete failed: ${msg}`);
|
|
4899
|
+
render.err(`server delete failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
4874
4900
|
}
|
|
4875
4901
|
leaveMesh(slug);
|
|
4876
|
-
|
|
4902
|
+
render.ok("removed from local config.");
|
|
4877
4903
|
return EXIT.SUCCESS;
|
|
4878
4904
|
}
|
|
4879
4905
|
} else {
|
|
4880
|
-
|
|
4881
|
-
|
|
4882
|
-
|
|
4883
|
-
|
|
4884
|
-
|
|
4906
|
+
process.stdout.write(` ${bold("1)")} remove from this device ${dim("(you can re-add later)")}
|
|
4907
|
+
`);
|
|
4908
|
+
process.stdout.write(` ${bold("2)")} cancel
|
|
4909
|
+
`);
|
|
4910
|
+
if (userId) {
|
|
4911
|
+
render.blank();
|
|
4912
|
+
render.warn("only the mesh owner can delete it from the server.");
|
|
4885
4913
|
}
|
|
4886
|
-
|
|
4887
|
-
const choice = await prompt3("
|
|
4914
|
+
render.blank();
|
|
4915
|
+
const choice = await prompt3(` ${dim("choice [1]:")} `) || "1";
|
|
4888
4916
|
if (choice === "2") {
|
|
4889
|
-
|
|
4917
|
+
render.info(dim("cancelled."));
|
|
4890
4918
|
return EXIT.USER_CANCELLED;
|
|
4891
4919
|
}
|
|
4892
4920
|
}
|
|
4893
4921
|
}
|
|
4894
4922
|
const removed = leaveMesh(slug);
|
|
4895
4923
|
if (removed) {
|
|
4896
|
-
|
|
4897
|
-
|
|
4924
|
+
render.ok(`removed ${bold(slug)} from this device.`);
|
|
4925
|
+
render.hint(`re-add anytime with: ${bold("claudemesh")} ${clay("<invite-url>")}`);
|
|
4898
4926
|
} else {
|
|
4899
|
-
|
|
4927
|
+
render.err(`mesh "${slug}" not found in local config.`);
|
|
4900
4928
|
}
|
|
4901
4929
|
return EXIT.SUCCESS;
|
|
4902
4930
|
}
|
|
@@ -4907,6 +4935,7 @@ var init_delete_mesh = __esm(() => {
|
|
|
4907
4935
|
init_facade6();
|
|
4908
4936
|
init_facade3();
|
|
4909
4937
|
init_urls();
|
|
4938
|
+
init_render();
|
|
4910
4939
|
init_styles();
|
|
4911
4940
|
init_exit_codes();
|
|
4912
4941
|
BROKER_HTTP5 = URLS.BROKER.replace("wss://", "https://").replace("ws://", "http://").replace("/ws", "");
|
|
@@ -6164,6 +6193,25 @@ async function withMesh(opts, fn) {
|
|
|
6164
6193
|
await client.connect();
|
|
6165
6194
|
const result = await fn(client, mesh);
|
|
6166
6195
|
return result;
|
|
6196
|
+
} catch (e) {
|
|
6197
|
+
if (client.terminalClose) {
|
|
6198
|
+
const { code, reason } = client.terminalClose;
|
|
6199
|
+
if (code === 4002) {
|
|
6200
|
+
console.error(`
|
|
6201
|
+
✘ ${reason}
|
|
6202
|
+
`);
|
|
6203
|
+
} else if (code === 4001) {
|
|
6204
|
+
console.error(`
|
|
6205
|
+
✘ Kicked from this mesh. Run \`claudemesh\` to rejoin.
|
|
6206
|
+
`);
|
|
6207
|
+
} else {
|
|
6208
|
+
console.error(`
|
|
6209
|
+
✘ Broker closed connection: ${reason}
|
|
6210
|
+
`);
|
|
6211
|
+
}
|
|
6212
|
+
process.exit(1);
|
|
6213
|
+
}
|
|
6214
|
+
throw e;
|
|
6167
6215
|
} finally {
|
|
6168
6216
|
client.close();
|
|
6169
6217
|
}
|
|
@@ -6176,7 +6224,8 @@ var init_connect = __esm(() => {
|
|
|
6176
6224
|
// src/commands/kick.ts
|
|
6177
6225
|
var exports_kick = {};
|
|
6178
6226
|
__export(exports_kick, {
|
|
6179
|
-
runKick: () => runKick
|
|
6227
|
+
runKick: () => runKick,
|
|
6228
|
+
runDisconnect: () => runDisconnect
|
|
6180
6229
|
});
|
|
6181
6230
|
function parseStaleMs(input) {
|
|
6182
6231
|
const m = input.match(/^(\d+)(s|m|h)$/);
|
|
@@ -6192,36 +6241,63 @@ function parseStaleMs(input) {
|
|
|
6192
6241
|
return val * 3600000;
|
|
6193
6242
|
return null;
|
|
6194
6243
|
}
|
|
6195
|
-
|
|
6244
|
+
function buildPayload(kind, target, opts) {
|
|
6245
|
+
if (opts.all)
|
|
6246
|
+
return { type: kind, all: true };
|
|
6247
|
+
if (opts.stale) {
|
|
6248
|
+
const ms = parseStaleMs(opts.stale);
|
|
6249
|
+
if (!ms)
|
|
6250
|
+
return { error: `Invalid stale duration: "${opts.stale}". Use e.g. 30m, 1h, 300s.` };
|
|
6251
|
+
return { type: kind, stale: ms };
|
|
6252
|
+
}
|
|
6253
|
+
if (target)
|
|
6254
|
+
return { type: kind, target };
|
|
6255
|
+
return { error: `Usage: claudemesh ${kind} <peer> | --stale 30m | --all` };
|
|
6256
|
+
}
|
|
6257
|
+
async function runDisconnect(target, opts = {}) {
|
|
6196
6258
|
const config = readConfig();
|
|
6197
6259
|
const meshSlug = opts.mesh ?? config.meshes[0]?.slug;
|
|
6198
6260
|
if (!meshSlug) {
|
|
6199
6261
|
render.err("No mesh joined.");
|
|
6200
6262
|
return EXIT.NOT_FOUND;
|
|
6201
6263
|
}
|
|
6264
|
+
const built = buildPayload("disconnect", target, opts);
|
|
6265
|
+
if ("error" in built) {
|
|
6266
|
+
render.err(String(built.error));
|
|
6267
|
+
return EXIT.INVALID_ARGS;
|
|
6268
|
+
}
|
|
6202
6269
|
return await withMesh({ meshSlug }, async (client) => {
|
|
6203
|
-
|
|
6204
|
-
|
|
6205
|
-
|
|
6206
|
-
|
|
6207
|
-
|
|
6208
|
-
|
|
6209
|
-
|
|
6210
|
-
return EXIT.INVALID_ARGS;
|
|
6211
|
-
}
|
|
6212
|
-
payload = { type: "kick", stale: ms };
|
|
6213
|
-
} else if (target) {
|
|
6214
|
-
payload = { type: "kick", target };
|
|
6215
|
-
} else {
|
|
6216
|
-
render.err("Usage: claudemesh kick <peer> | --stale 30m | --all");
|
|
6217
|
-
return EXIT.INVALID_ARGS;
|
|
6270
|
+
const result = await client.sendAndWait(built);
|
|
6271
|
+
const peers = result?.affected ?? result?.kicked ?? [];
|
|
6272
|
+
if (peers.length === 0)
|
|
6273
|
+
render.info("No peers matched.");
|
|
6274
|
+
else {
|
|
6275
|
+
render.ok(`Disconnected ${peers.length} peer(s): ${peers.join(", ")}`);
|
|
6276
|
+
render.hint("They will auto-reconnect within seconds. For a session-ending kick, use `claudemesh kick`.");
|
|
6218
6277
|
}
|
|
6219
|
-
|
|
6220
|
-
|
|
6221
|
-
|
|
6278
|
+
return EXIT.SUCCESS;
|
|
6279
|
+
});
|
|
6280
|
+
}
|
|
6281
|
+
async function runKick(target, opts = {}) {
|
|
6282
|
+
const config = readConfig();
|
|
6283
|
+
const meshSlug = opts.mesh ?? config.meshes[0]?.slug;
|
|
6284
|
+
if (!meshSlug) {
|
|
6285
|
+
render.err("No mesh joined.");
|
|
6286
|
+
return EXIT.NOT_FOUND;
|
|
6287
|
+
}
|
|
6288
|
+
const built = buildPayload("kick", target, opts);
|
|
6289
|
+
if ("error" in built) {
|
|
6290
|
+
render.err(String(built.error));
|
|
6291
|
+
return EXIT.INVALID_ARGS;
|
|
6292
|
+
}
|
|
6293
|
+
return await withMesh({ meshSlug }, async (client) => {
|
|
6294
|
+
const result = await client.sendAndWait(built);
|
|
6295
|
+
const peers = result?.affected ?? result?.kicked ?? [];
|
|
6296
|
+
if (peers.length === 0)
|
|
6222
6297
|
render.info("No peers matched.");
|
|
6223
|
-
|
|
6224
|
-
render.ok(`Kicked ${
|
|
6298
|
+
else {
|
|
6299
|
+
render.ok(`Kicked ${peers.length} peer(s): ${peers.join(", ")}`);
|
|
6300
|
+
render.hint("Their Claude Code session ended. They can rejoin anytime by running `claudemesh`.");
|
|
6225
6301
|
}
|
|
6226
6302
|
return EXIT.SUCCESS;
|
|
6227
6303
|
});
|
|
@@ -6461,12 +6537,10 @@ __export(exports_state, {
|
|
|
6461
6537
|
runStateGet: () => runStateGet
|
|
6462
6538
|
});
|
|
6463
6539
|
async function runStateGet(flags, key) {
|
|
6464
|
-
const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
|
|
6465
|
-
const dim2 = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
|
|
6466
6540
|
await withMesh({ meshSlug: flags.mesh ?? null }, async (client) => {
|
|
6467
6541
|
const entry = await client.getState(key);
|
|
6468
6542
|
if (!entry) {
|
|
6469
|
-
|
|
6543
|
+
render.info(dim("(not set)"));
|
|
6470
6544
|
return;
|
|
6471
6545
|
}
|
|
6472
6546
|
if (flags.json) {
|
|
@@ -6474,8 +6548,8 @@ async function runStateGet(flags, key) {
|
|
|
6474
6548
|
return;
|
|
6475
6549
|
}
|
|
6476
6550
|
const val = typeof entry.value === "string" ? entry.value : JSON.stringify(entry.value);
|
|
6477
|
-
|
|
6478
|
-
|
|
6551
|
+
render.info(val);
|
|
6552
|
+
render.info(dim(` set by ${entry.updatedBy} at ${new Date(entry.updatedAt).toLocaleString()}`));
|
|
6479
6553
|
});
|
|
6480
6554
|
}
|
|
6481
6555
|
async function runStateSet(flags, key, value) {
|
|
@@ -6487,13 +6561,10 @@ async function runStateSet(flags, key, value) {
|
|
|
6487
6561
|
}
|
|
6488
6562
|
await withMesh({ meshSlug: flags.mesh ?? null }, async (client) => {
|
|
6489
6563
|
await client.setState(key, parsed);
|
|
6490
|
-
|
|
6564
|
+
render.ok(`${bold(key)} = ${JSON.stringify(parsed)}`);
|
|
6491
6565
|
});
|
|
6492
6566
|
}
|
|
6493
6567
|
async function runStateList(flags) {
|
|
6494
|
-
const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
|
|
6495
|
-
const dim2 = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
|
|
6496
|
-
const bold2 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
|
|
6497
6568
|
await withMesh({ meshSlug: flags.mesh ?? null }, async (client, mesh) => {
|
|
6498
6569
|
const entries = await client.listState();
|
|
6499
6570
|
if (flags.json) {
|
|
@@ -6501,18 +6572,23 @@ async function runStateList(flags) {
|
|
|
6501
6572
|
return;
|
|
6502
6573
|
}
|
|
6503
6574
|
if (entries.length === 0) {
|
|
6504
|
-
|
|
6575
|
+
render.info(dim(`No state on mesh "${mesh.slug}".`));
|
|
6505
6576
|
return;
|
|
6506
6577
|
}
|
|
6578
|
+
render.section(`state (${entries.length})`);
|
|
6507
6579
|
for (const e of entries) {
|
|
6508
6580
|
const val = typeof e.value === "string" ? e.value : JSON.stringify(e.value);
|
|
6509
|
-
|
|
6510
|
-
|
|
6581
|
+
process.stdout.write(` ${bold(e.key)}: ${val}
|
|
6582
|
+
`);
|
|
6583
|
+
process.stdout.write(` ${dim(e.updatedBy + " · " + new Date(e.updatedAt).toLocaleString())}
|
|
6584
|
+
`);
|
|
6511
6585
|
}
|
|
6512
6586
|
});
|
|
6513
6587
|
}
|
|
6514
6588
|
var init_state = __esm(() => {
|
|
6515
6589
|
init_connect();
|
|
6590
|
+
init_render();
|
|
6591
|
+
init_styles();
|
|
6516
6592
|
});
|
|
6517
6593
|
|
|
6518
6594
|
// src/commands/info.ts
|
|
@@ -6576,7 +6652,7 @@ __export(exports_remember, {
|
|
|
6576
6652
|
async function remember(content, opts = {}) {
|
|
6577
6653
|
const client = allClients()[0];
|
|
6578
6654
|
if (!client) {
|
|
6579
|
-
|
|
6655
|
+
render.err("Not connected to any mesh.");
|
|
6580
6656
|
return EXIT.NETWORK_ERROR;
|
|
6581
6657
|
}
|
|
6582
6658
|
const tags = opts.tags?.split(",").map((t) => t.trim()).filter(Boolean);
|
|
@@ -6586,14 +6662,16 @@ async function remember(content, opts = {}) {
|
|
|
6586
6662
|
return EXIT.SUCCESS;
|
|
6587
6663
|
}
|
|
6588
6664
|
if (id) {
|
|
6589
|
-
|
|
6665
|
+
render.ok("remembered", dim(id.slice(0, 8)));
|
|
6590
6666
|
return EXIT.SUCCESS;
|
|
6591
6667
|
}
|
|
6592
|
-
|
|
6668
|
+
render.err("failed to store memory");
|
|
6593
6669
|
return EXIT.INTERNAL_ERROR;
|
|
6594
6670
|
}
|
|
6595
6671
|
var init_remember = __esm(() => {
|
|
6596
6672
|
init_facade8();
|
|
6673
|
+
init_render();
|
|
6674
|
+
init_styles();
|
|
6597
6675
|
init_exit_codes();
|
|
6598
6676
|
});
|
|
6599
6677
|
|
|
@@ -6605,7 +6683,7 @@ __export(exports_recall, {
|
|
|
6605
6683
|
async function recall(query, opts = {}) {
|
|
6606
6684
|
const client = allClients()[0];
|
|
6607
6685
|
if (!client) {
|
|
6608
|
-
|
|
6686
|
+
render.err("Not connected to any mesh.");
|
|
6609
6687
|
return EXIT.NETWORK_ERROR;
|
|
6610
6688
|
}
|
|
6611
6689
|
const memories = await client.recall(query);
|
|
@@ -6614,20 +6692,25 @@ async function recall(query, opts = {}) {
|
|
|
6614
6692
|
return EXIT.SUCCESS;
|
|
6615
6693
|
}
|
|
6616
6694
|
if (memories.length === 0) {
|
|
6617
|
-
|
|
6695
|
+
render.info(dim("no memories found."));
|
|
6618
6696
|
return EXIT.SUCCESS;
|
|
6619
6697
|
}
|
|
6698
|
+
render.section(`memories (${memories.length})`);
|
|
6620
6699
|
for (const m of memories) {
|
|
6621
|
-
const tags = m.tags.length ? dim(` [${m.tags.join(", ")}]`) : "";
|
|
6622
|
-
|
|
6623
|
-
|
|
6624
|
-
|
|
6625
|
-
|
|
6700
|
+
const tags = m.tags.length ? dim(` [${m.tags.map((t) => clay(t)).join(dim(", "))}]`) : "";
|
|
6701
|
+
process.stdout.write(` ${bold(m.id.slice(0, 8))}${tags}
|
|
6702
|
+
`);
|
|
6703
|
+
process.stdout.write(` ${m.content}
|
|
6704
|
+
`);
|
|
6705
|
+
process.stdout.write(` ${dim(m.rememberedBy + " · " + new Date(m.rememberedAt).toLocaleString())}
|
|
6706
|
+
|
|
6707
|
+
`);
|
|
6626
6708
|
}
|
|
6627
6709
|
return EXIT.SUCCESS;
|
|
6628
6710
|
}
|
|
6629
6711
|
var init_recall = __esm(() => {
|
|
6630
6712
|
init_facade8();
|
|
6713
|
+
init_render();
|
|
6631
6714
|
init_styles();
|
|
6632
6715
|
init_exit_codes();
|
|
6633
6716
|
});
|
|
@@ -6674,9 +6757,6 @@ function parseDeliverAt(flags) {
|
|
|
6674
6757
|
return null;
|
|
6675
6758
|
}
|
|
6676
6759
|
async function runRemind(flags, positional) {
|
|
6677
|
-
const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
|
|
6678
|
-
const dim2 = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
|
|
6679
|
-
const bold2 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
|
|
6680
6760
|
const action = positional[0];
|
|
6681
6761
|
if (action === "list") {
|
|
6682
6762
|
await withMesh({ meshSlug: flags.mesh ?? null }, async (client) => {
|
|
@@ -6686,15 +6766,18 @@ async function runRemind(flags, positional) {
|
|
|
6686
6766
|
return;
|
|
6687
6767
|
}
|
|
6688
6768
|
if (scheduled.length === 0) {
|
|
6689
|
-
|
|
6769
|
+
render.info(dim("No pending reminders."));
|
|
6690
6770
|
return;
|
|
6691
6771
|
}
|
|
6772
|
+
render.section(`reminders (${scheduled.length})`);
|
|
6692
6773
|
for (const m of scheduled) {
|
|
6693
6774
|
const when = new Date(m.deliverAt).toLocaleString();
|
|
6694
|
-
const to = m.to === client.getSessionPubkey() ?
|
|
6695
|
-
|
|
6696
|
-
|
|
6697
|
-
|
|
6775
|
+
const to = m.to === client.getSessionPubkey() ? dim("(self)") : m.to;
|
|
6776
|
+
process.stdout.write(` ${bold(m.id.slice(0, 8))} ${dim("→")} ${to} ${dim("at")} ${when}
|
|
6777
|
+
`);
|
|
6778
|
+
process.stdout.write(` ${dim(m.message.slice(0, 80))}
|
|
6779
|
+
|
|
6780
|
+
`);
|
|
6698
6781
|
}
|
|
6699
6782
|
});
|
|
6700
6783
|
return;
|
|
@@ -6702,15 +6785,15 @@ async function runRemind(flags, positional) {
|
|
|
6702
6785
|
if (action === "cancel") {
|
|
6703
6786
|
const id = positional[1];
|
|
6704
6787
|
if (!id) {
|
|
6705
|
-
|
|
6788
|
+
render.err("Usage: claudemesh remind cancel <id>");
|
|
6706
6789
|
process.exit(1);
|
|
6707
6790
|
}
|
|
6708
6791
|
await withMesh({ meshSlug: flags.mesh ?? null }, async (client) => {
|
|
6709
6792
|
const ok = await client.cancelScheduled(id);
|
|
6710
6793
|
if (ok)
|
|
6711
|
-
|
|
6794
|
+
render.ok(`cancelled ${bold(id.slice(0, 8))}`);
|
|
6712
6795
|
else {
|
|
6713
|
-
|
|
6796
|
+
render.err(`not found or already fired: ${id}`);
|
|
6714
6797
|
process.exit(1);
|
|
6715
6798
|
}
|
|
6716
6799
|
});
|
|
@@ -6718,17 +6801,17 @@ async function runRemind(flags, positional) {
|
|
|
6718
6801
|
}
|
|
6719
6802
|
const message = action ?? positional.join(" ");
|
|
6720
6803
|
if (!message) {
|
|
6721
|
-
|
|
6722
|
-
|
|
6723
|
-
|
|
6724
|
-
|
|
6725
|
-
|
|
6804
|
+
render.err("Usage: claudemesh remind <message> --in <duration>");
|
|
6805
|
+
render.info(dim(" claudemesh remind <message> --at <time>"));
|
|
6806
|
+
render.info(dim(' claudemesh remind <message> --cron "0 */2 * * *"'));
|
|
6807
|
+
render.info(dim(" claudemesh remind list"));
|
|
6808
|
+
render.info(dim(" claudemesh remind cancel <id>"));
|
|
6726
6809
|
process.exit(1);
|
|
6727
6810
|
}
|
|
6728
6811
|
const isCron = !!flags.cron;
|
|
6729
6812
|
const deliverAt = isCron ? 0 : parseDeliverAt(flags);
|
|
6730
6813
|
if (!isCron && deliverAt === null) {
|
|
6731
|
-
|
|
6814
|
+
render.err("Specify when", 'use --in <duration> (e.g. "2h", "30m"), --at <time> (e.g. "15:00"), or --cron <expression>');
|
|
6732
6815
|
process.exit(1);
|
|
6733
6816
|
}
|
|
6734
6817
|
await withMesh({ meshSlug: flags.mesh ?? null }, async (client) => {
|
|
@@ -6740,7 +6823,7 @@ async function runRemind(flags, positional) {
|
|
|
6740
6823
|
const peers = await client.listPeers();
|
|
6741
6824
|
const match = peers.find((p) => p.displayName.toLowerCase() === flags.to.toLowerCase());
|
|
6742
6825
|
if (!match) {
|
|
6743
|
-
|
|
6826
|
+
render.err(`Peer "${flags.to}" not found`, `online: ${peers.map((p) => p.displayName).join(", ") || "(none)"}`);
|
|
6744
6827
|
process.exit(1);
|
|
6745
6828
|
}
|
|
6746
6829
|
targetSpec = match.pubkey;
|
|
@@ -6750,7 +6833,7 @@ async function runRemind(flags, positional) {
|
|
|
6750
6833
|
}
|
|
6751
6834
|
const result = await client.scheduleMessage(targetSpec, message, deliverAt ?? 0, false, flags.cron);
|
|
6752
6835
|
if (!result) {
|
|
6753
|
-
|
|
6836
|
+
render.err("Broker did not acknowledge — check connection");
|
|
6754
6837
|
process.exit(1);
|
|
6755
6838
|
}
|
|
6756
6839
|
if (flags.json) {
|
|
@@ -6760,15 +6843,17 @@ async function runRemind(flags, positional) {
|
|
|
6760
6843
|
const toLabel = !flags.to || flags.to === "self" ? "yourself" : flags.to;
|
|
6761
6844
|
if (isCron) {
|
|
6762
6845
|
const nextFire = new Date(result.deliverAt).toLocaleString();
|
|
6763
|
-
|
|
6846
|
+
render.ok(`recurring reminder set`, `${result.scheduledId.slice(0, 8)} · ${clay(message)} → ${toLabel} · cron ${flags.cron} · next ${nextFire}`);
|
|
6764
6847
|
} else {
|
|
6765
6848
|
const when = new Date(result.deliverAt).toLocaleString();
|
|
6766
|
-
|
|
6849
|
+
render.ok(`reminder set`, `${result.scheduledId.slice(0, 8)} · ${clay(message)} → ${toLabel} at ${when}`);
|
|
6767
6850
|
}
|
|
6768
6851
|
});
|
|
6769
6852
|
}
|
|
6770
6853
|
var init_remind = __esm(() => {
|
|
6771
6854
|
init_connect();
|
|
6855
|
+
init_render();
|
|
6856
|
+
init_styles();
|
|
6772
6857
|
});
|
|
6773
6858
|
|
|
6774
6859
|
// src/commands/profile.ts
|
|
@@ -6908,20 +6993,21 @@ async function whoami(opts) {
|
|
|
6908
6993
|
return EXIT.SUCCESS;
|
|
6909
6994
|
}
|
|
6910
6995
|
if (!result.signed_in) {
|
|
6911
|
-
|
|
6996
|
+
render.err("Not signed in", "Run `claudemesh login` to sign in.");
|
|
6912
6997
|
return EXIT.AUTH_FAILED;
|
|
6913
6998
|
}
|
|
6914
|
-
|
|
6915
|
-
|
|
6916
|
-
|
|
6917
|
-
|
|
6918
|
-
|
|
6919
|
-
|
|
6920
|
-
|
|
6999
|
+
render.section("whoami");
|
|
7000
|
+
render.kv([
|
|
7001
|
+
["user", `${bold(result.user.display_name)} ${dim(`(${result.user.email})`)}`],
|
|
7002
|
+
["token", `${result.token_source} ${dim("(~/.claudemesh/auth.json)")}`],
|
|
7003
|
+
...result.meshes ? [["meshes", `${result.meshes.owned} owned · ${result.meshes.guest} guest`]] : []
|
|
7004
|
+
]);
|
|
7005
|
+
render.blank();
|
|
6921
7006
|
return EXIT.SUCCESS;
|
|
6922
7007
|
}
|
|
6923
7008
|
var init_whoami = __esm(() => {
|
|
6924
7009
|
init_facade6();
|
|
7010
|
+
init_render();
|
|
6925
7011
|
init_styles();
|
|
6926
7012
|
init_exit_codes();
|
|
6927
7013
|
});
|
|
@@ -7137,16 +7223,15 @@ function installStatusLine() {
|
|
|
7137
7223
|
function runInstall(args = []) {
|
|
7138
7224
|
const skipHooks = args.includes("--no-hooks");
|
|
7139
7225
|
const wantStatusLine = args.includes("--status-line");
|
|
7140
|
-
|
|
7141
|
-
console.log("------------------");
|
|
7226
|
+
render.section("claudemesh install");
|
|
7142
7227
|
const entry = resolveEntry();
|
|
7143
7228
|
const isBundled = entry.endsWith("/dist/index.js") || entry.endsWith("\\dist\\index.js");
|
|
7144
7229
|
if (!isBundled && !bunAvailable()) {
|
|
7145
|
-
|
|
7230
|
+
render.err("`bun` is not on PATH.", "Install Bun first: https://bun.com");
|
|
7146
7231
|
process.exit(1);
|
|
7147
7232
|
}
|
|
7148
7233
|
if (!existsSync5(entry)) {
|
|
7149
|
-
|
|
7234
|
+
render.err(`MCP entry not found at ${entry}`);
|
|
7150
7235
|
process.exit(1);
|
|
7151
7236
|
}
|
|
7152
7237
|
const desired = buildMcpEntry(entry);
|
|
@@ -7155,56 +7240,53 @@ function runInstall(args = []) {
|
|
|
7155
7240
|
const verifyServers = verify2.mcpServers ?? {};
|
|
7156
7241
|
const stored = verifyServers[MCP_NAME];
|
|
7157
7242
|
if (!stored || !entriesEqual(stored, desired)) {
|
|
7158
|
-
|
|
7243
|
+
render.err("post-write verification failed", `${CLAUDE_CONFIG} may be corrupt`);
|
|
7159
7244
|
process.exit(1);
|
|
7160
7245
|
}
|
|
7161
|
-
|
|
7162
|
-
|
|
7163
|
-
|
|
7164
|
-
|
|
7165
|
-
|
|
7166
|
-
console.log(dim2(` config: ${CLAUDE_CONFIG}`));
|
|
7167
|
-
console.log(dim2(` command: ${desired.command}${desired.args?.length ? " " + desired.args.join(" ") : ""}`));
|
|
7246
|
+
render.ok(`MCP server "${bold(MCP_NAME)}" ${action}`);
|
|
7247
|
+
render.kv([
|
|
7248
|
+
["config", dim(CLAUDE_CONFIG)],
|
|
7249
|
+
["command", dim(`${desired.command}${desired.args?.length ? " " + desired.args.join(" ") : ""}`)]
|
|
7250
|
+
]);
|
|
7168
7251
|
try {
|
|
7169
7252
|
const { added, unchanged } = installAllowedTools();
|
|
7170
7253
|
if (added.length > 0) {
|
|
7171
|
-
|
|
7172
|
-
|
|
7173
|
-
|
|
7254
|
+
render.ok(`allowedTools: ${added.length} claudemesh tools pre-approved`, unchanged > 0 ? `${unchanged} already present` : undefined);
|
|
7255
|
+
render.info(dim("This lets claudemesh tools run without --dangerously-skip-permissions."));
|
|
7256
|
+
render.info(dim("Your existing allowedTools entries were preserved."));
|
|
7174
7257
|
} else {
|
|
7175
|
-
|
|
7258
|
+
render.ok(`allowedTools: all ${unchanged} claudemesh tools already pre-approved`);
|
|
7176
7259
|
}
|
|
7177
|
-
|
|
7260
|
+
render.info(dim(` config: ${CLAUDE_SETTINGS}`));
|
|
7178
7261
|
} catch (e) {
|
|
7179
|
-
|
|
7262
|
+
render.warn(`allowedTools update failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
7180
7263
|
}
|
|
7181
7264
|
if (!skipHooks) {
|
|
7182
7265
|
try {
|
|
7183
7266
|
const { added, unchanged } = installHooks();
|
|
7184
7267
|
if (added > 0) {
|
|
7185
|
-
|
|
7268
|
+
render.ok(`Hooks registered (Stop + UserPromptSubmit)`, `${added} added, ${unchanged} already present`);
|
|
7186
7269
|
} else {
|
|
7187
|
-
|
|
7270
|
+
render.ok(`Hooks already registered`, `${unchanged} present`);
|
|
7188
7271
|
}
|
|
7189
|
-
|
|
7272
|
+
render.info(dim(` config: ${CLAUDE_SETTINGS}`));
|
|
7190
7273
|
} catch (e) {
|
|
7191
|
-
|
|
7192
|
-
console.error(" (MCP is still installed — hooks just skip. Retry with --no-hooks to suppress.)");
|
|
7274
|
+
render.warn(`hook registration failed: ${e instanceof Error ? e.message : String(e)}`, "MCP is still installed — hooks just skip. Retry with --no-hooks to suppress.");
|
|
7193
7275
|
}
|
|
7194
7276
|
} else {
|
|
7195
|
-
|
|
7277
|
+
render.info(dim("· Hooks skipped (--no-hooks)"));
|
|
7196
7278
|
}
|
|
7197
7279
|
if (wantStatusLine) {
|
|
7198
7280
|
try {
|
|
7199
7281
|
const { installed } = installStatusLine();
|
|
7200
7282
|
if (installed) {
|
|
7201
|
-
|
|
7202
|
-
|
|
7283
|
+
render.ok(`Claude Code statusLine → ${clay("claudemesh status-line")}`);
|
|
7284
|
+
render.info(dim(" Shows: ◇ <mesh> · <online>/<total> online · <you>"));
|
|
7203
7285
|
} else {
|
|
7204
|
-
|
|
7286
|
+
render.info(dim("· statusLine already set to a custom command — left alone"));
|
|
7205
7287
|
}
|
|
7206
7288
|
} catch (e) {
|
|
7207
|
-
|
|
7289
|
+
render.warn(`statusLine install failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
7208
7290
|
}
|
|
7209
7291
|
}
|
|
7210
7292
|
let hasMeshes = false;
|
|
@@ -7212,57 +7294,58 @@ function runInstall(args = []) {
|
|
|
7212
7294
|
const meshConfig = readConfig();
|
|
7213
7295
|
hasMeshes = meshConfig.meshes.length > 0;
|
|
7214
7296
|
} catch {}
|
|
7215
|
-
|
|
7216
|
-
|
|
7297
|
+
render.blank();
|
|
7298
|
+
render.warn(`${bold("RESTART CLAUDE CODE")} ${yellow("for MCP tools to appear.")}`);
|
|
7217
7299
|
if (!hasMeshes) {
|
|
7218
|
-
|
|
7219
|
-
|
|
7220
|
-
|
|
7221
|
-
|
|
7300
|
+
render.blank();
|
|
7301
|
+
render.info(`${yellow("No meshes joined.")} To connect with peers:`);
|
|
7302
|
+
render.info(` ${bold("claudemesh <invite-url>")}${dim(" — joins + launches in one step")}`);
|
|
7303
|
+
render.info(` ${dim("Create one at")} ${bold("https://claudemesh.com/dashboard")}`);
|
|
7222
7304
|
} else {
|
|
7223
|
-
|
|
7224
|
-
|
|
7305
|
+
render.blank();
|
|
7306
|
+
render.info(`Next: ${bold("claudemesh")}${dim(" — launch with your joined mesh")}`);
|
|
7225
7307
|
}
|
|
7226
|
-
|
|
7227
|
-
|
|
7228
|
-
|
|
7229
|
-
|
|
7230
|
-
|
|
7308
|
+
render.blank();
|
|
7309
|
+
render.info(dim("Optional:"));
|
|
7310
|
+
render.info(dim(` claudemesh url-handler install # click-to-launch from email`));
|
|
7311
|
+
render.info(dim(` claudemesh install --status-line # live peer count in Claude Code`));
|
|
7312
|
+
render.info(dim(` claudemesh completions zsh # shell completions`));
|
|
7231
7313
|
}
|
|
7232
7314
|
function runUninstall() {
|
|
7233
|
-
|
|
7234
|
-
console.log("--------------------");
|
|
7315
|
+
render.section("claudemesh uninstall");
|
|
7235
7316
|
if (removeMcpServer()) {
|
|
7236
|
-
|
|
7317
|
+
render.ok(`MCP server "${bold(MCP_NAME)}" removed`);
|
|
7237
7318
|
} else {
|
|
7238
|
-
|
|
7319
|
+
render.info(dim(`· MCP server "${MCP_NAME}" not present`));
|
|
7239
7320
|
}
|
|
7240
7321
|
try {
|
|
7241
7322
|
const removed = uninstallAllowedTools();
|
|
7242
7323
|
if (removed > 0) {
|
|
7243
|
-
|
|
7324
|
+
render.ok(`allowedTools: ${removed} claudemesh tools removed`);
|
|
7244
7325
|
} else {
|
|
7245
|
-
|
|
7326
|
+
render.info(dim("· No claudemesh allowedTools to remove"));
|
|
7246
7327
|
}
|
|
7247
7328
|
} catch (e) {
|
|
7248
|
-
|
|
7329
|
+
render.warn(`allowedTools removal failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
7249
7330
|
}
|
|
7250
7331
|
try {
|
|
7251
7332
|
const removed = uninstallHooks();
|
|
7252
7333
|
if (removed > 0) {
|
|
7253
|
-
|
|
7334
|
+
render.ok(`Hooks removed`, `${removed} entries`);
|
|
7254
7335
|
} else {
|
|
7255
|
-
|
|
7336
|
+
render.info(dim("· No claudemesh hooks to remove"));
|
|
7256
7337
|
}
|
|
7257
7338
|
} catch (e) {
|
|
7258
|
-
|
|
7339
|
+
render.warn(`hook removal failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
7259
7340
|
}
|
|
7260
|
-
|
|
7261
|
-
|
|
7341
|
+
render.blank();
|
|
7342
|
+
render.info("Restart Claude Code to drop the MCP connection + hooks.");
|
|
7262
7343
|
}
|
|
7263
7344
|
var MCP_NAME = "claudemesh", CLAUDE_CONFIG, CLAUDE_SETTINGS, HOOK_COMMAND_STOP = "claudemesh hook idle", HOOK_COMMAND_USER_PROMPT = "claudemesh hook working", HOOK_MARKER = "claudemesh hook ", CLAUDEMESH_TOOLS;
|
|
7264
7345
|
var init_install = __esm(() => {
|
|
7265
7346
|
init_facade();
|
|
7347
|
+
init_render();
|
|
7348
|
+
init_styles();
|
|
7266
7349
|
CLAUDE_CONFIG = join4(homedir4(), ".claude.json");
|
|
7267
7350
|
CLAUDE_SETTINGS = join4(homedir4(), ".claude", "settings.json");
|
|
7268
7351
|
CLAUDEMESH_TOOLS = [
|
|
@@ -7331,7 +7414,7 @@ async function uninstall() {
|
|
|
7331
7414
|
delete servers.claudemesh;
|
|
7332
7415
|
writeFileSync6(PATHS.CLAUDE_JSON, JSON.stringify(config, null, 2) + `
|
|
7333
7416
|
`, "utf-8");
|
|
7334
|
-
|
|
7417
|
+
render.ok("removed MCP server", dim("~/.claude.json"));
|
|
7335
7418
|
removed++;
|
|
7336
7419
|
}
|
|
7337
7420
|
} catch {}
|
|
@@ -7361,19 +7444,20 @@ async function uninstall() {
|
|
|
7361
7444
|
if (removedHooks > 0) {
|
|
7362
7445
|
writeFileSync6(PATHS.CLAUDE_SETTINGS, JSON.stringify(config, null, 2) + `
|
|
7363
7446
|
`, "utf-8");
|
|
7364
|
-
|
|
7447
|
+
render.ok(`removed ${removedHooks} claudemesh hook${removedHooks === 1 ? "" : "s"}`, dim("settings.json"));
|
|
7365
7448
|
removed++;
|
|
7366
7449
|
}
|
|
7367
7450
|
}
|
|
7368
7451
|
} catch {}
|
|
7369
7452
|
}
|
|
7370
7453
|
if (removed === 0) {
|
|
7371
|
-
|
|
7454
|
+
render.info(dim("Nothing to remove — claudemesh was not installed."));
|
|
7372
7455
|
}
|
|
7373
7456
|
return EXIT.SUCCESS;
|
|
7374
7457
|
}
|
|
7375
7458
|
var init_uninstall = __esm(() => {
|
|
7376
7459
|
init_paths();
|
|
7460
|
+
init_render();
|
|
7377
7461
|
init_styles();
|
|
7378
7462
|
init_exit_codes();
|
|
7379
7463
|
});
|
|
@@ -7603,7 +7687,7 @@ async function runDoctor() {
|
|
|
7603
7687
|
const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
|
|
7604
7688
|
const dim2 = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
|
|
7605
7689
|
const green3 = (s) => useColor ? `\x1B[32m${s}\x1B[39m` : s;
|
|
7606
|
-
const
|
|
7690
|
+
const red2 = (s) => useColor ? `\x1B[31m${s}\x1B[39m` : s;
|
|
7607
7691
|
console.log(`claudemesh doctor (v${VERSION})`);
|
|
7608
7692
|
console.log("─".repeat(60));
|
|
7609
7693
|
const checks = [
|
|
@@ -7617,7 +7701,7 @@ async function runDoctor() {
|
|
|
7617
7701
|
await checkNpmLatest()
|
|
7618
7702
|
];
|
|
7619
7703
|
for (const c of checks) {
|
|
7620
|
-
const mark = c.pass ? green3("✓") :
|
|
7704
|
+
const mark = c.pass ? green3("✓") : red2("✗");
|
|
7621
7705
|
const detail = c.detail ? dim2(` (${c.detail})`) : "";
|
|
7622
7706
|
console.log(`${mark} ${c.name}${detail}`);
|
|
7623
7707
|
if (!c.pass && c.fix) {
|
|
@@ -7630,7 +7714,7 @@ async function runDoctor() {
|
|
|
7630
7714
|
console.log(green3("All checks passed."));
|
|
7631
7715
|
process.exit(0);
|
|
7632
7716
|
} else {
|
|
7633
|
-
console.log(
|
|
7717
|
+
console.log(red2(`${failing.length} check(s) failed.`));
|
|
7634
7718
|
process.exit(1);
|
|
7635
7719
|
}
|
|
7636
7720
|
}
|
|
@@ -8208,7 +8292,7 @@ complete -c claudemesh -l join -d 'invite url'
|
|
|
8208
8292
|
}
|
|
8209
8293
|
async function runCompletions(shell) {
|
|
8210
8294
|
if (!shell) {
|
|
8211
|
-
|
|
8295
|
+
render.err("Usage: claudemesh completions <bash|zsh|fish>");
|
|
8212
8296
|
return EXIT.INVALID_ARGS;
|
|
8213
8297
|
}
|
|
8214
8298
|
switch (shell.toLowerCase()) {
|
|
@@ -8222,13 +8306,14 @@ async function runCompletions(shell) {
|
|
|
8222
8306
|
process.stdout.write(fish());
|
|
8223
8307
|
return EXIT.SUCCESS;
|
|
8224
8308
|
default:
|
|
8225
|
-
|
|
8309
|
+
render.err(`Unsupported shell: ${shell}`, "use bash, zsh, or fish.");
|
|
8226
8310
|
return EXIT.INVALID_ARGS;
|
|
8227
8311
|
}
|
|
8228
8312
|
}
|
|
8229
8313
|
var COMMANDS, FLAGS;
|
|
8230
8314
|
var init_completions = __esm(() => {
|
|
8231
8315
|
init_exit_codes();
|
|
8316
|
+
init_render();
|
|
8232
8317
|
COMMANDS = [
|
|
8233
8318
|
"create",
|
|
8234
8319
|
"new",
|
|
@@ -8311,26 +8396,22 @@ function safetyNumber(myPubkey, peerPubkey) {
|
|
|
8311
8396
|
return groups.join(" ");
|
|
8312
8397
|
}
|
|
8313
8398
|
async function runVerify(target, opts = {}) {
|
|
8314
|
-
const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
|
|
8315
|
-
const bold2 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
|
|
8316
|
-
const dim2 = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
|
|
8317
|
-
const clay2 = (s) => useColor ? `\x1B[38;2;217;119;87m${s}\x1B[39m` : s;
|
|
8318
8399
|
const config = readConfig();
|
|
8319
8400
|
const meshSlug = opts.mesh ?? config.meshes[0]?.slug;
|
|
8320
8401
|
if (!meshSlug) {
|
|
8321
|
-
|
|
8402
|
+
render.err("No meshes joined.", "Run `claudemesh join <url>` first.");
|
|
8322
8403
|
return EXIT.NOT_FOUND;
|
|
8323
8404
|
}
|
|
8324
8405
|
const mesh = config.meshes.find((m) => m.slug === meshSlug);
|
|
8325
8406
|
if (!mesh) {
|
|
8326
|
-
|
|
8407
|
+
render.err(`Mesh "${meshSlug}" not found locally.`);
|
|
8327
8408
|
return EXIT.NOT_FOUND;
|
|
8328
8409
|
}
|
|
8329
8410
|
return await withMesh({ meshSlug }, async (client) => {
|
|
8330
8411
|
const peers = await client.listPeers();
|
|
8331
8412
|
const targets = target ? peers.filter((p) => p.displayName === target || p.pubkey === target || p.pubkey.startsWith(target)) : peers;
|
|
8332
8413
|
if (targets.length === 0) {
|
|
8333
|
-
|
|
8414
|
+
render.err(`No peer matching "${target ?? "(all)"}" on mesh ${meshSlug}.`);
|
|
8334
8415
|
return EXIT.NOT_FOUND;
|
|
8335
8416
|
}
|
|
8336
8417
|
if (opts.json) {
|
|
@@ -8342,19 +8423,20 @@ async function runVerify(target, opts = {}) {
|
|
|
8342
8423
|
})), null, 2));
|
|
8343
8424
|
return EXIT.SUCCESS;
|
|
8344
8425
|
}
|
|
8345
|
-
|
|
8346
|
-
console.log(` ${dim2("— safety numbers on")} ${bold2(meshSlug)}`);
|
|
8347
|
-
console.log("");
|
|
8426
|
+
render.section(`safety numbers on ${meshSlug}`);
|
|
8348
8427
|
for (const p of targets) {
|
|
8349
8428
|
const sn = safetyNumber(mesh.pubkey, p.pubkey);
|
|
8350
|
-
|
|
8351
|
-
|
|
8352
|
-
|
|
8353
|
-
|
|
8429
|
+
process.stdout.write(` ${bold(p.displayName)}
|
|
8430
|
+
`);
|
|
8431
|
+
process.stdout.write(` ${clay(sn)}
|
|
8432
|
+
`);
|
|
8433
|
+
process.stdout.write(` ${dim(`pubkey ${p.pubkey.slice(0, 16)}…`)}
|
|
8434
|
+
|
|
8435
|
+
`);
|
|
8354
8436
|
}
|
|
8355
|
-
|
|
8356
|
-
|
|
8357
|
-
|
|
8437
|
+
render.hint("Compare these digits with your peer (phone, in person — not chat).");
|
|
8438
|
+
render.hint("If they match on both sides, the channel is not being intercepted.");
|
|
8439
|
+
render.blank();
|
|
8358
8440
|
return EXIT.SUCCESS;
|
|
8359
8441
|
});
|
|
8360
8442
|
}
|
|
@@ -8362,6 +8444,8 @@ var init_verify = __esm(() => {
|
|
|
8362
8444
|
init_connect();
|
|
8363
8445
|
init_facade();
|
|
8364
8446
|
init_exit_codes();
|
|
8447
|
+
init_render();
|
|
8448
|
+
init_styles();
|
|
8365
8449
|
});
|
|
8366
8450
|
|
|
8367
8451
|
// src/commands/url-handler.ts
|
|
@@ -8423,10 +8507,9 @@ EOF
|
|
|
8423
8507
|
chmodSync4(shimPath, 493);
|
|
8424
8508
|
const lsreg = spawnSync5("/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister", ["-f", appDir], { encoding: "utf-8" });
|
|
8425
8509
|
if (lsreg.status !== 0) {
|
|
8426
|
-
|
|
8510
|
+
render.warn("lsregister returned non-zero", "scheme may not activate until Finder rescans.");
|
|
8427
8511
|
}
|
|
8428
|
-
|
|
8429
|
-
console.log(` app bundle: ${appDir}`);
|
|
8512
|
+
render.ok("registered claudemesh:// scheme on macOS", dim(appDir));
|
|
8430
8513
|
return EXIT.SUCCESS;
|
|
8431
8514
|
}
|
|
8432
8515
|
function installLinux() {
|
|
@@ -8447,12 +8530,11 @@ NoDisplay=true
|
|
|
8447
8530
|
writeFileSync7(desktopPath, desktop);
|
|
8448
8531
|
const xdg1 = spawnSync5("xdg-mime", ["default", "claudemesh.desktop", "x-scheme-handler/claudemesh"], { encoding: "utf-8" });
|
|
8449
8532
|
if (xdg1.status !== 0) {
|
|
8450
|
-
|
|
8533
|
+
render.warn("xdg-mime not available — skipped mime default registration");
|
|
8451
8534
|
}
|
|
8452
8535
|
const xdg2 = spawnSync5("update-desktop-database", [appsDir], { encoding: "utf-8" });
|
|
8453
8536
|
xdg2.status;
|
|
8454
|
-
|
|
8455
|
-
console.log(` desktop entry: ${desktopPath}`);
|
|
8537
|
+
render.ok("registered claudemesh:// scheme on Linux", dim(desktopPath));
|
|
8456
8538
|
return EXIT.SUCCESS;
|
|
8457
8539
|
}
|
|
8458
8540
|
function installWindows() {
|
|
@@ -8472,29 +8554,29 @@ function installWindows() {
|
|
|
8472
8554
|
`));
|
|
8473
8555
|
const res = spawnSync5("reg.exe", ["import", regPath], { encoding: "utf-8" });
|
|
8474
8556
|
if (res.status !== 0) {
|
|
8475
|
-
|
|
8557
|
+
render.warn("reg.exe import failed", `manual: double-click ${regPath}`);
|
|
8476
8558
|
return EXIT.INTERNAL_ERROR;
|
|
8477
8559
|
}
|
|
8478
|
-
|
|
8560
|
+
render.ok("registered claudemesh:// scheme on Windows");
|
|
8479
8561
|
return EXIT.SUCCESS;
|
|
8480
8562
|
}
|
|
8481
8563
|
function uninstallDarwin() {
|
|
8482
8564
|
const appDir = join6(homedir6(), "Library", "Application Support", "claudemesh", "ClaudemeshHandler.app");
|
|
8483
8565
|
if (existsSync13(appDir))
|
|
8484
8566
|
rmSync2(appDir, { recursive: true, force: true });
|
|
8485
|
-
|
|
8567
|
+
render.ok("removed claudemesh:// handler on macOS");
|
|
8486
8568
|
return EXIT.SUCCESS;
|
|
8487
8569
|
}
|
|
8488
8570
|
function uninstallLinux() {
|
|
8489
8571
|
const desktopPath = join6(homedir6(), ".local", "share", "applications", "claudemesh.desktop");
|
|
8490
8572
|
if (existsSync13(desktopPath))
|
|
8491
8573
|
rmSync2(desktopPath, { force: true });
|
|
8492
|
-
|
|
8574
|
+
render.ok("removed claudemesh:// handler on Linux");
|
|
8493
8575
|
return EXIT.SUCCESS;
|
|
8494
8576
|
}
|
|
8495
8577
|
function uninstallWindows() {
|
|
8496
8578
|
spawnSync5("reg.exe", ["delete", "HKCU\\Software\\Classes\\claudemesh", "/f"], { encoding: "utf-8" });
|
|
8497
|
-
|
|
8579
|
+
render.ok("removed claudemesh:// handler on Windows");
|
|
8498
8580
|
return EXIT.SUCCESS;
|
|
8499
8581
|
}
|
|
8500
8582
|
async function runUrlHandler(action) {
|
|
@@ -8515,14 +8597,16 @@ async function runUrlHandler(action) {
|
|
|
8515
8597
|
if (p === "win32")
|
|
8516
8598
|
return uninstallWindows();
|
|
8517
8599
|
} else {
|
|
8518
|
-
|
|
8600
|
+
render.err("Usage: claudemesh url-handler <install|uninstall>");
|
|
8519
8601
|
return EXIT.INVALID_ARGS;
|
|
8520
8602
|
}
|
|
8521
|
-
|
|
8603
|
+
render.err(`Unsupported platform: ${p}`);
|
|
8522
8604
|
return EXIT.INTERNAL_ERROR;
|
|
8523
8605
|
}
|
|
8524
8606
|
var init_url_handler = __esm(() => {
|
|
8525
8607
|
init_exit_codes();
|
|
8608
|
+
init_render();
|
|
8609
|
+
init_styles();
|
|
8526
8610
|
});
|
|
8527
8611
|
|
|
8528
8612
|
// src/commands/status-line.ts
|
|
@@ -12240,9 +12324,8 @@ __export(exports_seed_test_mesh, {
|
|
|
12240
12324
|
function runSeedTestMesh(args) {
|
|
12241
12325
|
const [brokerUrl, meshId, memberId, pubkey, slug] = args;
|
|
12242
12326
|
if (!brokerUrl || !meshId || !memberId || !pubkey || !slug) {
|
|
12243
|
-
|
|
12244
|
-
|
|
12245
|
-
console.error('Example: claudemesh seed-test-mesh "ws://localhost:7900/ws" mesh-123 member-abc aaa..aaa smoke-test');
|
|
12327
|
+
render.err("Usage: claudemesh seed-test-mesh <broker-ws-url> <mesh-id> <member-id> <pubkey> <slug>");
|
|
12328
|
+
render.info(dim('Example: claudemesh seed-test-mesh "ws://localhost:7900/ws" mesh-123 member-abc aaa..aaa smoke-test'));
|
|
12246
12329
|
process.exit(1);
|
|
12247
12330
|
}
|
|
12248
12331
|
const config = readConfig();
|
|
@@ -12258,11 +12341,13 @@ function runSeedTestMesh(args) {
|
|
|
12258
12341
|
joinedAt: new Date().toISOString()
|
|
12259
12342
|
});
|
|
12260
12343
|
writeConfig(config);
|
|
12261
|
-
|
|
12262
|
-
|
|
12344
|
+
render.ok(`seeded ${bold(slug)}`, dim(meshId));
|
|
12345
|
+
render.hint(`run ${bold("claudemesh mcp")} to connect, or register with Claude Code via ${bold("claudemesh install")}`);
|
|
12263
12346
|
}
|
|
12264
12347
|
var init_seed_test_mesh = __esm(() => {
|
|
12265
12348
|
init_facade();
|
|
12349
|
+
init_render();
|
|
12350
|
+
init_styles();
|
|
12266
12351
|
});
|
|
12267
12352
|
|
|
12268
12353
|
// src/cli/argv.ts
|
|
@@ -12412,9 +12497,10 @@ Mesh
|
|
|
12412
12497
|
claudemesh delete [slug] delete a mesh (alias: rm)
|
|
12413
12498
|
claudemesh rename <slug> <name> rename a mesh
|
|
12414
12499
|
claudemesh share [email] share mesh (invite link / send email)
|
|
12415
|
-
claudemesh
|
|
12416
|
-
claudemesh kick
|
|
12417
|
-
claudemesh kick --
|
|
12500
|
+
claudemesh disconnect <peer> soft disconnect (peer auto-reconnects)
|
|
12501
|
+
claudemesh kick <peer> end session (peer must manually rejoin)
|
|
12502
|
+
claudemesh kick --stale 30m kick peers idle > duration
|
|
12503
|
+
claudemesh kick --all kick everyone except yourself
|
|
12418
12504
|
claudemesh ban <peer> kick + permanently revoke (can't rejoin)
|
|
12419
12505
|
claudemesh unban <peer> lift a ban
|
|
12420
12506
|
claudemesh bans list banned members
|
|
@@ -12556,6 +12642,11 @@ async function main() {
|
|
|
12556
12642
|
process.exit(await invite2(positionals[0], { mesh: flags.mesh, json: !!flags.json }));
|
|
12557
12643
|
break;
|
|
12558
12644
|
}
|
|
12645
|
+
case "disconnect": {
|
|
12646
|
+
const { runDisconnect: runDisconnect2 } = await Promise.resolve().then(() => (init_kick(), exports_kick));
|
|
12647
|
+
process.exit(await runDisconnect2(positionals[0], { mesh: flags.mesh, stale: flags.stale, all: !!flags.all }));
|
|
12648
|
+
break;
|
|
12649
|
+
}
|
|
12559
12650
|
case "kick": {
|
|
12560
12651
|
const { runKick: runKick2 } = await Promise.resolve().then(() => (init_kick(), exports_kick));
|
|
12561
12652
|
process.exit(await runKick2(positionals[0], { mesh: flags.mesh, stale: flags.stale, all: !!flags.all }));
|
|
@@ -12763,4 +12854,4 @@ main().catch((err) => {
|
|
|
12763
12854
|
process.exit(EXIT.INTERNAL_ERROR);
|
|
12764
12855
|
});
|
|
12765
12856
|
|
|
12766
|
-
//# debugId=
|
|
12857
|
+
//# debugId=80234995420998CA64756E2164756E21
|