claudemesh-cli 1.0.0-alpha.14 → 1.0.0-alpha.16

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.
@@ -1078,11 +1078,23 @@ async function createMesh2(name, opts) {
1078
1078
  const auth = getStoredToken();
1079
1079
  if (!auth)
1080
1080
  throw new Error("Not signed in");
1081
- const result = await exports_my.createMesh(auth.session_token, { name, ...opts });
1081
+ let userId = "";
1082
+ try {
1083
+ const payload = JSON.parse(Buffer.from(auth.session_token.split(".")[1], "base64url").toString());
1084
+ userId = payload.sub ?? "";
1085
+ } catch {}
1086
+ if (!userId)
1087
+ throw new Error("Invalid token — run `claudemesh login` again");
1088
+ const result = await request({
1089
+ path: "/cli/mesh/create",
1090
+ method: "POST",
1091
+ body: { user_id: userId, name, ...opts },
1092
+ baseUrl: BROKER_HTTP2
1093
+ });
1082
1094
  const kp = await generateKeypair3();
1083
1095
  const mesh = {
1084
1096
  meshId: result.id,
1085
- memberId: "",
1097
+ memberId: result.member_id,
1086
1098
  slug: result.slug,
1087
1099
  name: result.name,
1088
1100
  pubkey: kp.publicKey,
@@ -1093,12 +1105,14 @@ async function createMesh2(name, opts) {
1093
1105
  setMeshConfig(result.slug, mesh);
1094
1106
  return { slug: result.slug, id: result.id };
1095
1107
  }
1108
+ var BROKER_HTTP2;
1096
1109
  var init_create = __esm(() => {
1097
1110
  init_facade3();
1098
1111
  init_facade6();
1099
1112
  init_facade7();
1100
1113
  init_facade();
1101
1114
  init_urls();
1115
+ BROKER_HTTP2 = URLS.BROKER.replace("wss://", "https://").replace("ws://", "http://").replace("/ws", "");
1102
1116
  });
1103
1117
 
1104
1118
  // src/services/mesh/rename.ts
@@ -1160,12 +1174,141 @@ var init_facade9 = __esm(() => {
1160
1174
  init_errors3();
1161
1175
  });
1162
1176
 
1177
+ // src/commands/login.ts
1178
+ var exports_login = {};
1179
+ __export(exports_login, {
1180
+ login: () => login
1181
+ });
1182
+ import { createInterface as createInterface2 } from "node:readline";
1183
+ function prompt(question) {
1184
+ const rl = createInterface2({ input: process.stdin, output: process.stdout });
1185
+ return new Promise((resolve) => {
1186
+ rl.question(question, (answer) => {
1187
+ rl.close();
1188
+ resolve(answer.trim());
1189
+ });
1190
+ });
1191
+ }
1192
+ async function loginWithToken() {
1193
+ console.log(`
1194
+ Paste a token from ${dim(URLS.API_BASE + "/token")}`);
1195
+ console.log(` ${dim("Generate one in your browser, then paste it here.")}
1196
+ `);
1197
+ const token = await prompt(" Token: ");
1198
+ if (!token) {
1199
+ console.error(` ${icons.cross} No token provided.`);
1200
+ return EXIT.AUTH_FAILED;
1201
+ }
1202
+ let user = { id: "", display_name: "", email: "" };
1203
+ try {
1204
+ const parts = token.split(".");
1205
+ if (parts[1]) {
1206
+ const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString());
1207
+ if (payload.exp && payload.exp < Date.now() / 1000) {
1208
+ console.error(` ${icons.cross} Token expired. Generate a new one.`);
1209
+ return EXIT.AUTH_FAILED;
1210
+ }
1211
+ user = {
1212
+ id: payload.sub ?? "",
1213
+ display_name: payload.name ?? payload.email ?? "",
1214
+ email: payload.email ?? ""
1215
+ };
1216
+ }
1217
+ } catch {
1218
+ console.error(` ${icons.cross} Invalid token format.`);
1219
+ return EXIT.AUTH_FAILED;
1220
+ }
1221
+ storeToken({ session_token: token, user, token_source: "manual" });
1222
+ console.log(` ${green(icons.check)} Signed in as ${user.display_name || user.email || "user"}.`);
1223
+ return EXIT.SUCCESS;
1224
+ }
1225
+ async function syncMeshes(token) {
1226
+ try {
1227
+ const meshes = await exports_my.getMeshes(token);
1228
+ if (meshes.length > 0) {
1229
+ const names = meshes.map((m) => m.slug).join(", ");
1230
+ console.log(` ${green(icons.check)} Synced ${meshes.length} mesh${meshes.length === 1 ? "" : "es"}: ${names}`);
1231
+ }
1232
+ } catch {}
1233
+ }
1234
+ async function login() {
1235
+ const existing = getStoredToken();
1236
+ if (existing) {
1237
+ const name = existing.user.display_name || existing.user.email || "unknown";
1238
+ console.log(`
1239
+ Already signed in as ${bold(name)}.`);
1240
+ console.log("");
1241
+ console.log(` ${bold("1)")} Continue as ${name}`);
1242
+ console.log(` ${bold("2)")} Sign in via browser`);
1243
+ console.log(` ${bold("3)")} Paste a token from ${dim("claudemesh.com/token")}`);
1244
+ console.log(` ${bold("4)")} Sign out`);
1245
+ console.log("");
1246
+ const choice = await prompt(" Choice [1]: ") || "1";
1247
+ if (choice === "1") {
1248
+ console.log(`
1249
+ ${green(icons.check)} Continuing as ${name}.`);
1250
+ return EXIT.SUCCESS;
1251
+ }
1252
+ if (choice === "4") {
1253
+ clearToken();
1254
+ console.log(` ${green(icons.check)} Signed out.`);
1255
+ return EXIT.SUCCESS;
1256
+ }
1257
+ if (choice === "3") {
1258
+ clearToken();
1259
+ return loginWithToken();
1260
+ }
1261
+ clearToken();
1262
+ console.log(` ${dim("Signing in…")}`);
1263
+ } else {
1264
+ console.log(`
1265
+ ${bold("claudemesh")} — sign in to connect your terminal`);
1266
+ console.log("");
1267
+ console.log(` ${bold("1)")} Sign in via browser ${dim("(opens automatically)")}`);
1268
+ console.log(` ${bold("2)")} Paste a token from ${dim("claudemesh.com/token")}`);
1269
+ console.log("");
1270
+ const choice = await prompt(" Choice [1]: ") || "1";
1271
+ if (choice === "2") {
1272
+ return loginWithToken();
1273
+ }
1274
+ }
1275
+ try {
1276
+ const result = await loginWithDeviceCode();
1277
+ console.log(` ${green(icons.check)} Signed in as ${result.user.display_name}.`);
1278
+ await syncMeshes(result.session_token);
1279
+ return EXIT.SUCCESS;
1280
+ } catch (err) {
1281
+ console.error(` ${icons.cross} Login failed: ${err instanceof Error ? err.message : err}`);
1282
+ return EXIT.AUTH_FAILED;
1283
+ }
1284
+ }
1285
+ var init_login = __esm(() => {
1286
+ init_facade6();
1287
+ init_facade3();
1288
+ init_styles();
1289
+ init_exit_codes();
1290
+ init_urls();
1291
+ });
1292
+
1163
1293
  // src/commands/new.ts
1164
1294
  var exports_new = {};
1165
1295
  __export(exports_new, {
1166
1296
  newMesh: () => newMesh
1167
1297
  });
1168
1298
  async function newMesh(name, opts) {
1299
+ if (!name) {
1300
+ console.error(" Usage: claudemesh mesh create <name>");
1301
+ return EXIT.INVALID_ARGS;
1302
+ }
1303
+ if (!getStoredToken()) {
1304
+ console.log(dim(` Not signed in — starting login…
1305
+ `));
1306
+ const { login: login2 } = await Promise.resolve().then(() => (init_login(), exports_login));
1307
+ const loginResult = await login2();
1308
+ if (loginResult !== EXIT.SUCCESS)
1309
+ return loginResult;
1310
+ console.log("");
1311
+ }
1169
1312
  try {
1170
1313
  const result = await createMesh2(name, {
1171
1314
  template: opts.template,
@@ -1179,22 +1322,23 @@ async function newMesh(name, opts) {
1179
1322
  console.log(` ${green(icons.check)} You're the owner`);
1180
1323
  console.log(` ${green(icons.check)} Joined locally`);
1181
1324
  console.log(`
1182
- Invite teammates with: claudemesh invite
1325
+ Share with: claudemesh mesh share
1183
1326
  `);
1184
1327
  }
1185
1328
  return EXIT.SUCCESS;
1186
1329
  } catch (err) {
1187
1330
  const msg = err instanceof Error ? err.message : String(err);
1188
- if (msg.includes("Not signed in")) {
1189
- console.error(" Not signed in. Run `claudemesh login` first.");
1190
- return EXIT.AUTH_FAILED;
1331
+ if (msg.includes("409") || msg.includes("already exists")) {
1332
+ console.error(` ${icons.cross} A mesh with this name already exists. Try a different name.`);
1333
+ } else {
1334
+ console.error(` ${icons.cross} Failed: ${msg}`);
1191
1335
  }
1192
- console.error(` ${icons.cross} Failed: ${msg}`);
1193
1336
  return EXIT.INTERNAL_ERROR;
1194
1337
  }
1195
1338
  }
1196
1339
  var init_new = __esm(() => {
1197
1340
  init_facade9();
1341
+ init_facade6();
1198
1342
  init_styles();
1199
1343
  init_exit_codes();
1200
1344
  });
@@ -3601,7 +3745,7 @@ var init_facade11 = __esm(() => {
3601
3745
  });
3602
3746
 
3603
3747
  // src/ui/screen.ts
3604
- import { createInterface as createInterface2 } from "node:readline";
3748
+ import { createInterface as createInterface3 } from "node:readline";
3605
3749
  function termSize() {
3606
3750
  return { cols: process.stdout.columns || 80, rows: process.stdout.rows || 24 };
3607
3751
  }
@@ -3629,7 +3773,7 @@ function enterFullScreen() {
3629
3773
  function exitFullScreen() {
3630
3774
  process.stdout.write(SHOW_CURSOR + CLEAR_SCREEN);
3631
3775
  }
3632
- async function menuSelect(itemsOrOpts, prompt = "Choice") {
3776
+ async function menuSelect(itemsOrOpts, prompt2 = "Choice") {
3633
3777
  const items = Array.isArray(itemsOrOpts) ? itemsOrOpts : itemsOrOpts.items;
3634
3778
  const title = !Array.isArray(itemsOrOpts) ? itemsOrOpts.title : undefined;
3635
3779
  if (title)
@@ -3637,9 +3781,9 @@ async function menuSelect(itemsOrOpts, prompt = "Choice") {
3637
3781
  ${title}`);
3638
3782
  items.forEach((item, i) => console.log(` ${bold(String(i + 1) + ")")} ${item}`));
3639
3783
  console.log("");
3640
- const rl = createInterface2({ input: process.stdin, output: process.stdout });
3784
+ const rl = createInterface3({ input: process.stdin, output: process.stdout });
3641
3785
  return new Promise((resolve) => {
3642
- rl.question(` ${prompt} [1]: `, (answer) => {
3786
+ rl.question(` ${prompt2} [1]: `, (answer) => {
3643
3787
  rl.close();
3644
3788
  const idx = parseInt(answer || "1", 10) - 1;
3645
3789
  resolve(idx >= 0 && idx < items.length ? idx : 0);
@@ -3649,7 +3793,7 @@ async function menuSelect(itemsOrOpts, prompt = "Choice") {
3649
3793
  async function textInput(promptOrOpts, defaultVal = "") {
3650
3794
  const label = typeof promptOrOpts === "string" ? promptOrOpts : promptOrOpts.label;
3651
3795
  const placeholder = typeof promptOrOpts === "object" ? promptOrOpts.placeholder : undefined;
3652
- const rl = createInterface2({ input: process.stdin, output: process.stdout });
3796
+ const rl = createInterface3({ input: process.stdin, output: process.stdout });
3653
3797
  return new Promise((resolve) => {
3654
3798
  const hint = placeholder ? ` (${placeholder})` : defaultVal ? ` [${defaultVal}]` : "";
3655
3799
  rl.question(` ${label}${hint}: `, (answer) => {
@@ -3661,7 +3805,7 @@ async function textInput(promptOrOpts, defaultVal = "") {
3661
3805
  async function confirmPrompt(promptOrOpts, defaultYes = true) {
3662
3806
  const message = typeof promptOrOpts === "string" ? promptOrOpts : promptOrOpts.message;
3663
3807
  const defYes = typeof promptOrOpts === "object" && promptOrOpts.defaultYes !== undefined ? promptOrOpts.defaultYes : defaultYes;
3664
- const rl = createInterface2({ input: process.stdin, output: process.stdout });
3808
+ const rl = createInterface3({ input: process.stdin, output: process.stdout });
3665
3809
  const hint = defYes ? "[Y/n]" : "[y/N]";
3666
3810
  return new Promise((resolve) => {
3667
3811
  rl.question(` ${message} ${hint}: `, (answer) => {
@@ -3776,7 +3920,7 @@ import { randomUUID } from "node:crypto";
3776
3920
  import { mkdtempSync, writeFileSync as writeFileSync4, rmSync, readdirSync, statSync, existsSync as existsSync4, readFileSync as readFileSync3 } from "node:fs";
3777
3921
  import { tmpdir, hostname as hostname3, homedir as homedir3 } from "node:os";
3778
3922
  import { join as join3 } from "node:path";
3779
- import { createInterface as createInterface3 } from "node:readline";
3923
+ import { createInterface as createInterface4 } from "node:readline";
3780
3924
  async function pickMesh(meshes) {
3781
3925
  if (meshes.length === 1)
3782
3926
  return meshes[0];
@@ -3786,7 +3930,7 @@ async function pickMesh(meshes) {
3786
3930
  console.log(` ${i + 1}) ${m.slug}`);
3787
3931
  });
3788
3932
  console.log("");
3789
- const rl = createInterface3({ input: process.stdin, output: process.stdout });
3933
+ const rl = createInterface4({ input: process.stdin, output: process.stdout });
3790
3934
  return new Promise((resolve) => {
3791
3935
  rl.question(" Choice [1]: ", (answer) => {
3792
3936
  rl.close();
@@ -4028,7 +4172,7 @@ async function runLaunch(flags, rawArgs) {
4028
4172
  console.log(` ${dim2(`Or join with invite: claudemesh launch --join <url>`)}
4029
4173
  `);
4030
4174
  const manualPromise = new Promise((resolve) => {
4031
- const rl = createInterface3({ input: process.stdin, output: process.stdout });
4175
+ const rl = createInterface4({ input: process.stdin, output: process.stdout });
4032
4176
  rl.question(" Paste sync token (or wait for browser): ", (answer) => {
4033
4177
  rl.close();
4034
4178
  if (answer.trim())
@@ -4345,7 +4489,7 @@ async function runList() {
4345
4489
  if (userId) {
4346
4490
  const res = await request({
4347
4491
  path: `/cli/meshes?user_id=${userId}`,
4348
- baseUrl: BROKER_HTTP2
4492
+ baseUrl: BROKER_HTTP3
4349
4493
  });
4350
4494
  serverMeshes = res.meshes ?? [];
4351
4495
  }
@@ -4401,14 +4545,14 @@ async function runList() {
4401
4545
  console.log(dim(` Config: ${getConfigPath()}`));
4402
4546
  console.log("");
4403
4547
  }
4404
- var BROKER_HTTP2;
4548
+ var BROKER_HTTP3;
4405
4549
  var init_list2 = __esm(() => {
4406
4550
  init_facade();
4407
4551
  init_facade6();
4408
4552
  init_facade3();
4409
4553
  init_urls();
4410
4554
  init_styles();
4411
- BROKER_HTTP2 = URLS.BROKER.replace("wss://", "https://").replace("ws://", "http://").replace("/ws", "");
4555
+ BROKER_HTTP3 = URLS.BROKER.replace("wss://", "https://").replace("ws://", "http://").replace("/ws", "");
4412
4556
  });
4413
4557
 
4414
4558
  // src/commands/delete-mesh.ts
@@ -4416,31 +4560,50 @@ var exports_delete_mesh = {};
4416
4560
  __export(exports_delete_mesh, {
4417
4561
  deleteMesh: () => deleteMesh
4418
4562
  });
4419
- import { createInterface as createInterface4 } from "node:readline";
4420
- function prompt(question) {
4421
- const rl = createInterface4({ input: process.stdin, output: process.stdout });
4563
+ import { createInterface as createInterface5 } from "node:readline";
4564
+ function prompt2(question) {
4565
+ const rl = createInterface5({ input: process.stdin, output: process.stdout });
4422
4566
  return new Promise((resolve) => {
4423
4567
  rl.question(question, (a) => {
4424
4568
  rl.close();
4425
- resolve(a.trim().toLowerCase());
4569
+ resolve(a.trim());
4426
4570
  });
4427
4571
  });
4428
4572
  }
4573
+ function getUserId(token) {
4574
+ try {
4575
+ const payload = JSON.parse(Buffer.from(token.split(".")[1], "base64url").toString());
4576
+ return payload.sub ?? "";
4577
+ } catch {
4578
+ return "";
4579
+ }
4580
+ }
4581
+ async function isOwner(slug, userId) {
4582
+ try {
4583
+ const res = await request({
4584
+ path: `/cli/meshes?user_id=${userId}`,
4585
+ baseUrl: BROKER_HTTP4
4586
+ });
4587
+ return res.meshes?.find((m) => m.slug === slug)?.is_owner ?? false;
4588
+ } catch {
4589
+ return false;
4590
+ }
4591
+ }
4429
4592
  async function deleteMesh(slug, opts = {}) {
4593
+ const config = readConfig();
4430
4594
  if (!slug) {
4431
- const config = readConfig();
4432
4595
  if (config.meshes.length === 0) {
4433
- console.error(" No meshes to delete.");
4596
+ console.error(" No meshes to remove.");
4434
4597
  return EXIT.NOT_FOUND;
4435
4598
  }
4436
4599
  console.log(`
4437
- Select mesh to delete:
4600
+ Select mesh to remove:
4438
4601
  `);
4439
4602
  config.meshes.forEach((m, i) => {
4440
4603
  console.log(` ${bold(String(i + 1) + ")")} ${m.slug} ${dim("(" + m.name + ")")}`);
4441
4604
  });
4442
4605
  console.log("");
4443
- const choice = await prompt(" Choice: ");
4606
+ const choice = await prompt2(" Choice: ");
4444
4607
  const idx = parseInt(choice, 10) - 1;
4445
4608
  if (idx < 0 || idx >= config.meshes.length) {
4446
4609
  console.log(" Cancelled.");
@@ -4448,48 +4611,72 @@ async function deleteMesh(slug, opts = {}) {
4448
4611
  }
4449
4612
  slug = config.meshes[idx].slug;
4450
4613
  }
4614
+ const auth = getStoredToken();
4615
+ const userId = auth ? getUserId(auth.session_token) : "";
4616
+ const ownerCheck = userId ? await isOwner(slug, userId) : false;
4451
4617
  if (!opts.yes) {
4452
4618
  console.log(`
4453
- ${red("Warning:")} This will permanently delete ${bold(slug)}.`);
4454
- const answer = await prompt(` Type "${slug}" to confirm: `);
4455
- if (answer !== slug.toLowerCase()) {
4456
- console.log(" Cancelled.");
4457
- return EXIT.USER_CANCELLED;
4458
- }
4459
- }
4460
- const auth = getStoredToken();
4461
- if (auth) {
4462
- try {
4463
- let userId = "";
4464
- try {
4465
- const payload = JSON.parse(Buffer.from(auth.session_token.split(".")[1], "base64url").toString());
4466
- userId = payload.sub ?? "";
4467
- } catch {}
4468
- if (userId) {
4469
- await request({
4470
- path: `/cli/mesh/${slug}`,
4471
- method: "DELETE",
4472
- body: { user_id: userId },
4473
- baseUrl: BROKER_HTTP3
4474
- });
4475
- console.log(` ${green(icons.check)} Deleted "${slug}" from server.`);
4476
- }
4477
- } catch (err) {
4478
- const msg = err instanceof Error ? err.message : String(err);
4479
- if (msg.includes("403")) {
4480
- console.log(` ${dim("Not the owner — removing from local config only.")}`);
4481
- } else if (msg.includes("404")) {
4482
- console.log(` ${dim("Mesh not found on server removing locally.")}`);
4483
- } else {
4484
- console.log(` ${dim("Could not delete from server: " + msg)}`);
4619
+ ${bold(slug)}
4620
+ `);
4621
+ if (ownerCheck) {
4622
+ console.log(` ${bold("1)")} Remove from this device only ${dim("(keep on server)")}`);
4623
+ console.log(` ${bold("2)")} ${red("Delete everywhere")} ${dim("(removes for all members)")}`);
4624
+ console.log(` ${bold("3)")} Cancel`);
4625
+ console.log("");
4626
+ const choice = await prompt2(" Choice [1]: ") || "1";
4627
+ if (choice === "3") {
4628
+ console.log(" Cancelled.");
4629
+ return EXIT.USER_CANCELLED;
4630
+ }
4631
+ if (choice === "2") {
4632
+ console.log(`
4633
+ ${red("Warning:")} This will delete ${bold(slug)} for all members.`);
4634
+ const confirm = await prompt2(` Type "${slug}" to confirm: `);
4635
+ if (confirm.toLowerCase() !== slug.toLowerCase()) {
4636
+ console.log(" Cancelled.");
4637
+ return EXIT.USER_CANCELLED;
4638
+ }
4639
+ try {
4640
+ await request({
4641
+ path: `/cli/mesh/${slug}`,
4642
+ method: "DELETE",
4643
+ body: { user_id: userId },
4644
+ baseUrl: BROKER_HTTP4
4645
+ });
4646
+ console.log(` ${green(icons.check)} Deleted "${slug}" from server.`);
4647
+ } catch (err) {
4648
+ const msg = err instanceof Error ? err.message : String(err);
4649
+ console.error(` ${icons.cross} Server delete failed: ${msg}`);
4650
+ }
4651
+ leaveMesh(slug);
4652
+ console.log(` ${green(icons.check)} Removed from local config.`);
4653
+ return EXIT.SUCCESS;
4654
+ }
4655
+ } else {
4656
+ console.log(` ${bold("1)")} Remove from this device ${dim("(you can re-add later)")}`);
4657
+ console.log(` ${bold("2)")} Cancel`);
4658
+ if (!ownerCheck && userId) {
4659
+ console.log(dim(`
4660
+ ${yellow(icons.warn)} Only the mesh owner can delete it from the server.`));
4661
+ }
4662
+ console.log("");
4663
+ const choice = await prompt2(" Choice [1]: ") || "1";
4664
+ if (choice === "2") {
4665
+ console.log(" Cancelled.");
4666
+ return EXIT.USER_CANCELLED;
4485
4667
  }
4486
4668
  }
4487
4669
  }
4488
- leaveMesh(slug);
4489
- console.log(` ${green(icons.check)} Removed "${slug}" from local config.`);
4670
+ const removed = leaveMesh(slug);
4671
+ if (removed) {
4672
+ console.log(` ${green(icons.check)} Removed "${slug}" from this device.`);
4673
+ console.log(dim(` Re-add anytime with: claudemesh mesh add <invite-url>`));
4674
+ } else {
4675
+ console.error(` Mesh "${slug}" not found in local config.`);
4676
+ }
4490
4677
  return EXIT.SUCCESS;
4491
4678
  }
4492
- var BROKER_HTTP3;
4679
+ var BROKER_HTTP4;
4493
4680
  var init_delete_mesh = __esm(() => {
4494
4681
  init_facade();
4495
4682
  init_facade9();
@@ -4498,7 +4685,7 @@ var init_delete_mesh = __esm(() => {
4498
4685
  init_urls();
4499
4686
  init_styles();
4500
4687
  init_exit_codes();
4501
- BROKER_HTTP3 = URLS.BROKER.replace("wss://", "https://").replace("ws://", "http://").replace("/ws", "");
4688
+ BROKER_HTTP4 = URLS.BROKER.replace("wss://", "https://").replace("ws://", "http://").replace("/ws", "");
4502
4689
  });
4503
4690
 
4504
4691
  // src/commands/rename.ts
@@ -4561,9 +4748,9 @@ var exports_invite = {};
4561
4748
  __export(exports_invite, {
4562
4749
  invite: () => invite
4563
4750
  });
4564
- import { createInterface as createInterface5 } from "node:readline";
4565
- function prompt2(question) {
4566
- const rl = createInterface5({ input: process.stdin, output: process.stdout });
4751
+ import { createInterface as createInterface6 } from "node:readline";
4752
+ function prompt3(question) {
4753
+ const rl = createInterface6({ input: process.stdin, output: process.stdout });
4567
4754
  return new Promise((resolve) => {
4568
4755
  rl.question(question, (a) => {
4569
4756
  rl.close();
@@ -4594,7 +4781,7 @@ async function invite(email, opts = {}) {
4594
4781
  console.log(` ${bold(String(i + 1) + ")")} ${m.slug} ${dim("(" + m.name + ")")}`);
4595
4782
  });
4596
4783
  console.log("");
4597
- const choice = await prompt2(" Choice [1]: ") || "1";
4784
+ const choice = await prompt3(" Choice [1]: ") || "1";
4598
4785
  const idx = parseInt(choice, 10) - 1;
4599
4786
  meshSlug = config.meshes[idx >= 0 && idx < config.meshes.length ? idx : 0].slug;
4600
4787
  }
@@ -4673,122 +4860,6 @@ var init_welcome = __esm(() => {
4673
4860
  init_MeshPickerStep();
4674
4861
  });
4675
4862
 
4676
- // src/commands/login.ts
4677
- var exports_login = {};
4678
- __export(exports_login, {
4679
- login: () => login
4680
- });
4681
- import { createInterface as createInterface6 } from "node:readline";
4682
- function prompt3(question) {
4683
- const rl = createInterface6({ input: process.stdin, output: process.stdout });
4684
- return new Promise((resolve) => {
4685
- rl.question(question, (answer) => {
4686
- rl.close();
4687
- resolve(answer.trim());
4688
- });
4689
- });
4690
- }
4691
- async function loginWithToken() {
4692
- console.log(`
4693
- Paste a token from ${dim(URLS.API_BASE + "/token")}`);
4694
- console.log(` ${dim("Generate one in your browser, then paste it here.")}
4695
- `);
4696
- const token = await prompt3(" Token: ");
4697
- if (!token) {
4698
- console.error(` ${icons.cross} No token provided.`);
4699
- return EXIT.AUTH_FAILED;
4700
- }
4701
- let user = { id: "", display_name: "", email: "" };
4702
- try {
4703
- const parts = token.split(".");
4704
- if (parts[1]) {
4705
- const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString());
4706
- if (payload.exp && payload.exp < Date.now() / 1000) {
4707
- console.error(` ${icons.cross} Token expired. Generate a new one.`);
4708
- return EXIT.AUTH_FAILED;
4709
- }
4710
- user = {
4711
- id: payload.sub ?? "",
4712
- display_name: payload.name ?? payload.email ?? "",
4713
- email: payload.email ?? ""
4714
- };
4715
- }
4716
- } catch {
4717
- console.error(` ${icons.cross} Invalid token format.`);
4718
- return EXIT.AUTH_FAILED;
4719
- }
4720
- storeToken({ session_token: token, user, token_source: "manual" });
4721
- console.log(` ${green(icons.check)} Signed in as ${user.display_name || user.email || "user"}.`);
4722
- return EXIT.SUCCESS;
4723
- }
4724
- async function syncMeshes(token) {
4725
- try {
4726
- const meshes = await exports_my.getMeshes(token);
4727
- if (meshes.length > 0) {
4728
- const names = meshes.map((m) => m.slug).join(", ");
4729
- console.log(` ${green(icons.check)} Synced ${meshes.length} mesh${meshes.length === 1 ? "" : "es"}: ${names}`);
4730
- }
4731
- } catch {}
4732
- }
4733
- async function login() {
4734
- const existing = getStoredToken();
4735
- if (existing) {
4736
- const name = existing.user.display_name || existing.user.email || "unknown";
4737
- console.log(`
4738
- Already signed in as ${bold(name)}.`);
4739
- console.log("");
4740
- console.log(` ${bold("1)")} Continue as ${name}`);
4741
- console.log(` ${bold("2)")} Sign in via browser`);
4742
- console.log(` ${bold("3)")} Paste a token from ${dim("claudemesh.com/token")}`);
4743
- console.log(` ${bold("4)")} Sign out`);
4744
- console.log("");
4745
- const choice = await prompt3(" Choice [1]: ") || "1";
4746
- if (choice === "1") {
4747
- console.log(`
4748
- ${green(icons.check)} Continuing as ${name}.`);
4749
- return EXIT.SUCCESS;
4750
- }
4751
- if (choice === "4") {
4752
- clearToken();
4753
- console.log(` ${green(icons.check)} Signed out.`);
4754
- return EXIT.SUCCESS;
4755
- }
4756
- if (choice === "3") {
4757
- clearToken();
4758
- return loginWithToken();
4759
- }
4760
- clearToken();
4761
- console.log(` ${dim("Signing in…")}`);
4762
- } else {
4763
- console.log(`
4764
- ${bold("claudemesh")} — sign in to connect your terminal`);
4765
- console.log("");
4766
- console.log(` ${bold("1)")} Sign in via browser ${dim("(opens automatically)")}`);
4767
- console.log(` ${bold("2)")} Paste a token from ${dim("claudemesh.com/token")}`);
4768
- console.log("");
4769
- const choice = await prompt3(" Choice [1]: ") || "1";
4770
- if (choice === "2") {
4771
- return loginWithToken();
4772
- }
4773
- }
4774
- try {
4775
- const result = await loginWithDeviceCode();
4776
- console.log(` ${green(icons.check)} Signed in as ${result.user.display_name}.`);
4777
- await syncMeshes(result.session_token);
4778
- return EXIT.SUCCESS;
4779
- } catch (err) {
4780
- console.error(` ${icons.cross} Login failed: ${err instanceof Error ? err.message : err}`);
4781
- return EXIT.AUTH_FAILED;
4782
- }
4783
- }
4784
- var init_login = __esm(() => {
4785
- init_facade6();
4786
- init_facade3();
4787
- init_styles();
4788
- init_exit_codes();
4789
- init_urls();
4790
- });
4791
-
4792
4863
  // src/commands/register.ts
4793
4864
  var exports_register = {};
4794
4865
  __export(exports_register, {
@@ -9876,4 +9947,4 @@ main().catch((err) => {
9876
9947
  process.exit(EXIT.INTERNAL_ERROR);
9877
9948
  });
9878
9949
 
9879
- //# debugId=E76259A581E1545264756E2164756E21
9950
+ //# debugId=7B7B5BCFBFB57ADE64756E2164756E21