claudemesh-cli 1.0.0-alpha.36 → 1.0.0-alpha.37

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-alpha.36", env;
91
+ var URLS, VERSION = "1.0.0-alpha.37", env;
92
92
  var init_urls = __esm(() => {
93
93
  URLS = {
94
94
  BROKER: process.env.CLAUDEMESH_BROKER_URL ?? "wss://ic.claudemesh.com/ws",
@@ -2277,6 +2277,22 @@ class BrokerClient {
2277
2277
  return;
2278
2278
  this.ws.send(JSON.stringify(payload));
2279
2279
  }
2280
+ async sendAndWait(payload, timeoutMs = 1e4) {
2281
+ const reqId = `rw-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
2282
+ return new Promise((resolve, reject) => {
2283
+ const timer = setTimeout(() => {
2284
+ this.genericResolvers.delete(reqId);
2285
+ reject(new Error("sendAndWait timeout"));
2286
+ }, timeoutMs);
2287
+ this.genericResolvers.set(reqId, (msg) => {
2288
+ clearTimeout(timer);
2289
+ this.genericResolvers.delete(reqId);
2290
+ resolve(msg);
2291
+ });
2292
+ this.sendRaw({ ...payload, _reqId: reqId });
2293
+ });
2294
+ }
2295
+ genericResolvers = new Map;
2280
2296
  close() {
2281
2297
  this.closed = true;
2282
2298
  this.stopStatsReporting();
@@ -2477,6 +2493,11 @@ class BrokerClient {
2477
2493
  }
2478
2494
  handleServerMessage(msg) {
2479
2495
  const msgReqId = msg._reqId;
2496
+ if (msgReqId && this.genericResolvers.has(msgReqId)) {
2497
+ const resolve = this.genericResolvers.get(msgReqId);
2498
+ resolve(msg);
2499
+ return;
2500
+ }
2480
2501
  if (msg.type === "ack") {
2481
2502
  const pending = this.pendingSends.get(String(msg.id ?? ""));
2482
2503
  if (pending) {
@@ -6137,6 +6158,149 @@ var init_connect = __esm(() => {
6137
6158
  init_facade();
6138
6159
  });
6139
6160
 
6161
+ // src/commands/kick.ts
6162
+ var exports_kick = {};
6163
+ __export(exports_kick, {
6164
+ runKick: () => runKick
6165
+ });
6166
+ function parseStaleMs(input) {
6167
+ const m = input.match(/^(\d+)(s|m|h)$/);
6168
+ if (!m)
6169
+ return null;
6170
+ const val = parseInt(m[1], 10);
6171
+ const unit = m[2];
6172
+ if (unit === "s")
6173
+ return val * 1000;
6174
+ if (unit === "m")
6175
+ return val * 60000;
6176
+ if (unit === "h")
6177
+ return val * 3600000;
6178
+ return null;
6179
+ }
6180
+ async function runKick(target, opts = {}) {
6181
+ const config = readConfig();
6182
+ const meshSlug = opts.mesh ?? config.meshes[0]?.slug;
6183
+ if (!meshSlug) {
6184
+ render.err("No mesh joined.");
6185
+ return EXIT.NOT_FOUND;
6186
+ }
6187
+ return await withMesh({ meshSlug }, async (client) => {
6188
+ let payload;
6189
+ if (opts.all) {
6190
+ payload = { type: "kick", all: true };
6191
+ } else if (opts.stale) {
6192
+ const ms = parseStaleMs(opts.stale);
6193
+ if (!ms) {
6194
+ render.err(`Invalid stale duration: "${opts.stale}". Use e.g. 30m, 1h, 300s.`);
6195
+ return EXIT.INVALID_ARGS;
6196
+ }
6197
+ payload = { type: "kick", stale: ms };
6198
+ } else if (target) {
6199
+ payload = { type: "kick", target };
6200
+ } else {
6201
+ render.err("Usage: claudemesh kick <peer> | --stale 30m | --all");
6202
+ return EXIT.INVALID_ARGS;
6203
+ }
6204
+ const result = await client.sendAndWait(payload);
6205
+ const kicked = result?.kicked ?? [];
6206
+ if (kicked.length === 0) {
6207
+ render.info("No peers matched.");
6208
+ } else {
6209
+ render.ok(`Kicked ${kicked.length} peer(s): ${kicked.join(", ")}`);
6210
+ }
6211
+ return EXIT.SUCCESS;
6212
+ });
6213
+ }
6214
+ var init_kick = __esm(() => {
6215
+ init_connect();
6216
+ init_facade();
6217
+ init_render();
6218
+ init_exit_codes();
6219
+ });
6220
+
6221
+ // src/commands/ban.ts
6222
+ var exports_ban = {};
6223
+ __export(exports_ban, {
6224
+ runUnban: () => runUnban,
6225
+ runBans: () => runBans,
6226
+ runBan: () => runBan
6227
+ });
6228
+ async function runBan(target, opts = {}) {
6229
+ if (!target) {
6230
+ render.err("Usage: claudemesh ban <peer-name-or-pubkey>");
6231
+ return EXIT.INVALID_ARGS;
6232
+ }
6233
+ const config = readConfig();
6234
+ const meshSlug = opts.mesh ?? config.meshes[0]?.slug;
6235
+ if (!meshSlug) {
6236
+ render.err("No mesh joined.");
6237
+ return EXIT.NOT_FOUND;
6238
+ }
6239
+ return await withMesh({ meshSlug }, async (client) => {
6240
+ const result = await client.sendAndWait({ type: "ban", target });
6241
+ if (result?.banned) {
6242
+ render.ok(`Banned ${result.banned} from ${meshSlug}. They cannot reconnect until unbanned.`);
6243
+ render.hint(`Undo: claudemesh unban ${result.banned} --mesh ${meshSlug}`);
6244
+ } else {
6245
+ render.err(result?.error ?? "ban failed");
6246
+ }
6247
+ return result?.banned ? EXIT.SUCCESS : EXIT.INTERNAL_ERROR;
6248
+ });
6249
+ }
6250
+ async function runUnban(target, opts = {}) {
6251
+ if (!target) {
6252
+ render.err("Usage: claudemesh unban <peer-name-or-pubkey>");
6253
+ return EXIT.INVALID_ARGS;
6254
+ }
6255
+ const config = readConfig();
6256
+ const meshSlug = opts.mesh ?? config.meshes[0]?.slug;
6257
+ if (!meshSlug) {
6258
+ render.err("No mesh joined.");
6259
+ return EXIT.NOT_FOUND;
6260
+ }
6261
+ return await withMesh({ meshSlug }, async (client) => {
6262
+ const result = await client.sendAndWait({ type: "unban", target });
6263
+ if (result?.unbanned) {
6264
+ render.ok(`Unbanned ${result.unbanned} from ${meshSlug}. They can rejoin.`);
6265
+ } else {
6266
+ render.err(result?.error ?? "unban failed");
6267
+ }
6268
+ return result?.unbanned ? EXIT.SUCCESS : EXIT.INTERNAL_ERROR;
6269
+ });
6270
+ }
6271
+ async function runBans(opts = {}) {
6272
+ const config = readConfig();
6273
+ const meshSlug = opts.mesh ?? config.meshes[0]?.slug;
6274
+ if (!meshSlug) {
6275
+ render.err("No mesh joined.");
6276
+ return EXIT.NOT_FOUND;
6277
+ }
6278
+ return await withMesh({ meshSlug }, async (client) => {
6279
+ const result = await client.sendAndWait({ type: "list_bans" });
6280
+ const bans = result?.bans ?? [];
6281
+ if (opts.json) {
6282
+ process.stdout.write(JSON.stringify(bans, null, 2) + `
6283
+ `);
6284
+ return EXIT.SUCCESS;
6285
+ }
6286
+ if (bans.length === 0) {
6287
+ render.info("No banned members.");
6288
+ return EXIT.SUCCESS;
6289
+ }
6290
+ render.section(`banned members on ${meshSlug}`);
6291
+ for (const b of bans) {
6292
+ render.kv([[b.name, `${b.pubkey.slice(0, 16)}… · banned ${new Date(b.revokedAt).toLocaleDateString()}`]]);
6293
+ }
6294
+ return EXIT.SUCCESS;
6295
+ });
6296
+ }
6297
+ var init_ban = __esm(() => {
6298
+ init_connect();
6299
+ init_facade();
6300
+ init_render();
6301
+ init_exit_codes();
6302
+ });
6303
+
6140
6304
  // src/commands/peers.ts
6141
6305
  var exports_peers = {};
6142
6306
  __export(exports_peers, {
@@ -12156,6 +12320,12 @@ Mesh
12156
12320
  claudemesh delete [slug] delete a mesh (alias: rm)
12157
12321
  claudemesh rename <slug> <name> rename a mesh
12158
12322
  claudemesh share [email] share mesh (invite link / send email)
12323
+ claudemesh kick <peer> disconnect a peer (can reconnect)
12324
+ claudemesh kick --stale 30m disconnect idle peers (> duration)
12325
+ claudemesh kick --all disconnect everyone except you
12326
+ claudemesh ban <peer> kick + permanently revoke (can't rejoin)
12327
+ claudemesh unban <peer> lift a ban
12328
+ claudemesh bans list banned members
12159
12329
 
12160
12330
  Messaging
12161
12331
  claudemesh peers see who's online
@@ -12294,6 +12464,26 @@ async function main() {
12294
12464
  process.exit(await invite2(positionals[0], { mesh: flags.mesh, json: !!flags.json }));
12295
12465
  break;
12296
12466
  }
12467
+ case "kick": {
12468
+ const { runKick: runKick2 } = await Promise.resolve().then(() => (init_kick(), exports_kick));
12469
+ process.exit(await runKick2(positionals[0], { mesh: flags.mesh, stale: flags.stale, all: !!flags.all }));
12470
+ break;
12471
+ }
12472
+ case "ban": {
12473
+ const { runBan: runBan2 } = await Promise.resolve().then(() => (init_ban(), exports_ban));
12474
+ process.exit(await runBan2(positionals[0], { mesh: flags.mesh }));
12475
+ break;
12476
+ }
12477
+ case "unban": {
12478
+ const { runUnban: runUnban2 } = await Promise.resolve().then(() => (init_ban(), exports_ban));
12479
+ process.exit(await runUnban2(positionals[0], { mesh: flags.mesh }));
12480
+ break;
12481
+ }
12482
+ case "bans": {
12483
+ const { runBans: runBans2 } = await Promise.resolve().then(() => (init_ban(), exports_ban));
12484
+ process.exit(await runBans2({ mesh: flags.mesh, json: !!flags.json }));
12485
+ break;
12486
+ }
12297
12487
  case "peers": {
12298
12488
  const { runPeers: runPeers2 } = await Promise.resolve().then(() => (init_peers(), exports_peers));
12299
12489
  await runPeers2({ mesh: flags.mesh, json: !!flags.json });
@@ -12481,4 +12671,4 @@ main().catch((err) => {
12481
12671
  process.exit(EXIT.INTERNAL_ERROR);
12482
12672
  });
12483
12673
 
12484
- //# debugId=7F65AA4EF7F0222264756E2164756E21
12674
+ //# debugId=95D625F3B4CFD9EA64756E2164756E21