claudemesh-cli 1.0.0 → 1.0.1

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.
@@ -88,7 +88,7 @@ __export(exports_urls, {
88
88
  VERSION: () => VERSION,
89
89
  URLS: () => URLS
90
90
  });
91
- var URLS, VERSION = "1.0.0", env;
91
+ var URLS, VERSION = "1.0.1", 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) {
@@ -6164,6 +6178,25 @@ async function withMesh(opts, fn) {
6164
6178
  await client.connect();
6165
6179
  const result = await fn(client, mesh);
6166
6180
  return result;
6181
+ } catch (e) {
6182
+ if (client.terminalClose) {
6183
+ const { code, reason } = client.terminalClose;
6184
+ if (code === 4002) {
6185
+ console.error(`
6186
+ ✘ ${reason}
6187
+ `);
6188
+ } else if (code === 4001) {
6189
+ console.error(`
6190
+ ✘ Kicked from this mesh. Run \`claudemesh\` to rejoin.
6191
+ `);
6192
+ } else {
6193
+ console.error(`
6194
+ ✘ Broker closed connection: ${reason}
6195
+ `);
6196
+ }
6197
+ process.exit(1);
6198
+ }
6199
+ throw e;
6167
6200
  } finally {
6168
6201
  client.close();
6169
6202
  }
@@ -6176,7 +6209,8 @@ var init_connect = __esm(() => {
6176
6209
  // src/commands/kick.ts
6177
6210
  var exports_kick = {};
6178
6211
  __export(exports_kick, {
6179
- runKick: () => runKick
6212
+ runKick: () => runKick,
6213
+ runDisconnect: () => runDisconnect
6180
6214
  });
6181
6215
  function parseStaleMs(input) {
6182
6216
  const m = input.match(/^(\d+)(s|m|h)$/);
@@ -6192,36 +6226,63 @@ function parseStaleMs(input) {
6192
6226
  return val * 3600000;
6193
6227
  return null;
6194
6228
  }
6195
- async function runKick(target, opts = {}) {
6229
+ function buildPayload(kind, target, opts) {
6230
+ if (opts.all)
6231
+ return { type: kind, all: true };
6232
+ if (opts.stale) {
6233
+ const ms = parseStaleMs(opts.stale);
6234
+ if (!ms)
6235
+ return { error: `Invalid stale duration: "${opts.stale}". Use e.g. 30m, 1h, 300s.` };
6236
+ return { type: kind, stale: ms };
6237
+ }
6238
+ if (target)
6239
+ return { type: kind, target };
6240
+ return { error: `Usage: claudemesh ${kind} <peer> | --stale 30m | --all` };
6241
+ }
6242
+ async function runDisconnect(target, opts = {}) {
6196
6243
  const config = readConfig();
6197
6244
  const meshSlug = opts.mesh ?? config.meshes[0]?.slug;
6198
6245
  if (!meshSlug) {
6199
6246
  render.err("No mesh joined.");
6200
6247
  return EXIT.NOT_FOUND;
6201
6248
  }
6249
+ const built = buildPayload("disconnect", target, opts);
6250
+ if ("error" in built) {
6251
+ render.err(String(built.error));
6252
+ return EXIT.INVALID_ARGS;
6253
+ }
6202
6254
  return await withMesh({ meshSlug }, async (client) => {
6203
- let payload;
6204
- if (opts.all) {
6205
- payload = { type: "kick", all: true };
6206
- } else if (opts.stale) {
6207
- const ms = parseStaleMs(opts.stale);
6208
- if (!ms) {
6209
- render.err(`Invalid stale duration: "${opts.stale}". Use e.g. 30m, 1h, 300s.`);
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;
6255
+ const result = await client.sendAndWait(built);
6256
+ const peers = result?.affected ?? result?.kicked ?? [];
6257
+ if (peers.length === 0)
6258
+ render.info("No peers matched.");
6259
+ else {
6260
+ render.ok(`Disconnected ${peers.length} peer(s): ${peers.join(", ")}`);
6261
+ render.hint("They will auto-reconnect within seconds. For a session-ending kick, use `claudemesh kick`.");
6218
6262
  }
6219
- const result = await client.sendAndWait(payload);
6220
- const kicked = result?.kicked ?? [];
6221
- if (kicked.length === 0) {
6263
+ return EXIT.SUCCESS;
6264
+ });
6265
+ }
6266
+ async function runKick(target, opts = {}) {
6267
+ const config = readConfig();
6268
+ const meshSlug = opts.mesh ?? config.meshes[0]?.slug;
6269
+ if (!meshSlug) {
6270
+ render.err("No mesh joined.");
6271
+ return EXIT.NOT_FOUND;
6272
+ }
6273
+ const built = buildPayload("kick", target, opts);
6274
+ if ("error" in built) {
6275
+ render.err(String(built.error));
6276
+ return EXIT.INVALID_ARGS;
6277
+ }
6278
+ return await withMesh({ meshSlug }, async (client) => {
6279
+ const result = await client.sendAndWait(built);
6280
+ const peers = result?.affected ?? result?.kicked ?? [];
6281
+ if (peers.length === 0)
6222
6282
  render.info("No peers matched.");
6223
- } else {
6224
- render.ok(`Kicked ${kicked.length} peer(s): ${kicked.join(", ")}`);
6283
+ else {
6284
+ render.ok(`Kicked ${peers.length} peer(s): ${peers.join(", ")}`);
6285
+ render.hint("Their Claude Code session ended. They can rejoin anytime by running `claudemesh`.");
6225
6286
  }
6226
6287
  return EXIT.SUCCESS;
6227
6288
  });
@@ -12412,9 +12473,10 @@ Mesh
12412
12473
  claudemesh delete [slug] delete a mesh (alias: rm)
12413
12474
  claudemesh rename <slug> <name> rename a mesh
12414
12475
  claudemesh share [email] share mesh (invite link / send email)
12415
- claudemesh kick <peer> disconnect a peer (can reconnect)
12416
- claudemesh kick --stale 30m disconnect idle peers (> duration)
12417
- claudemesh kick --all disconnect everyone except you
12476
+ claudemesh disconnect <peer> soft disconnect (peer auto-reconnects)
12477
+ claudemesh kick <peer> end session (peer must manually rejoin)
12478
+ claudemesh kick --stale 30m kick peers idle > duration
12479
+ claudemesh kick --all kick everyone except yourself
12418
12480
  claudemesh ban <peer> kick + permanently revoke (can't rejoin)
12419
12481
  claudemesh unban <peer> lift a ban
12420
12482
  claudemesh bans list banned members
@@ -12556,6 +12618,11 @@ async function main() {
12556
12618
  process.exit(await invite2(positionals[0], { mesh: flags.mesh, json: !!flags.json }));
12557
12619
  break;
12558
12620
  }
12621
+ case "disconnect": {
12622
+ const { runDisconnect: runDisconnect2 } = await Promise.resolve().then(() => (init_kick(), exports_kick));
12623
+ process.exit(await runDisconnect2(positionals[0], { mesh: flags.mesh, stale: flags.stale, all: !!flags.all }));
12624
+ break;
12625
+ }
12559
12626
  case "kick": {
12560
12627
  const { runKick: runKick2 } = await Promise.resolve().then(() => (init_kick(), exports_kick));
12561
12628
  process.exit(await runKick2(positionals[0], { mesh: flags.mesh, stale: flags.stale, all: !!flags.all }));
@@ -12763,4 +12830,4 @@ main().catch((err) => {
12763
12830
  process.exit(EXIT.INTERNAL_ERROR);
12764
12831
  });
12765
12832
 
12766
- //# debugId=BE63FC7A7529110A64756E2164756E21
12833
+ //# debugId=4199659439A09F6C64756E2164756E21