@claude-sync/cli 0.1.4 → 0.1.6

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/src/index.js CHANGED
@@ -4524,12 +4524,18 @@ var init_config = __esm({
4524
4524
  });
4525
4525
 
4526
4526
  // src/lib/api-client.ts
4527
- var ApiClient;
4527
+ var AuthExpiredError, ApiClient;
4528
4528
  var init_api_client = __esm({
4529
4529
  "src/lib/api-client.ts"() {
4530
4530
  "use strict";
4531
4531
  init_esm_shims();
4532
4532
  init_auth();
4533
+ AuthExpiredError = class extends Error {
4534
+ constructor() {
4535
+ super("Session expired");
4536
+ this.name = "AuthExpiredError";
4537
+ }
4538
+ };
4533
4539
  ApiClient = class {
4534
4540
  baseUrl;
4535
4541
  constructor(baseUrl) {
@@ -4554,7 +4560,7 @@ var init_api_client = __esm({
4554
4560
  clearTimeout(timeout);
4555
4561
  if (!response.ok) {
4556
4562
  if (response.status === 401) {
4557
- throw new Error("Session expired. Run `claude-sync login` to re-authenticate.");
4563
+ throw new AuthExpiredError();
4558
4564
  }
4559
4565
  const error2 = await response.json().catch(() => ({
4560
4566
  statusCode: response.status,
@@ -4659,8 +4665,8 @@ var init_auth = __esm({
4659
4665
  // src/lib/progress.ts
4660
4666
  import ora from "ora";
4661
4667
  import chalk from "chalk";
4662
- function createSpinner(text3) {
4663
- return ora({ text: brandColor(text3), spinner: "dots", color: "magenta" });
4668
+ function createSpinner(text4) {
4669
+ return ora({ text: brandColor(text4), spinner: "dots", color: "magenta" });
4664
4670
  }
4665
4671
  function formatBytes(bytes) {
4666
4672
  if (bytes === 0) return "0 B";
@@ -4926,6 +4932,7 @@ function deviceCommand() {
4926
4932
  printLabel("ID", response.id);
4927
4933
  } catch (err) {
4928
4934
  spinner.stop();
4935
+ if (err instanceof AuthExpiredError) throw err;
4929
4936
  printError(`Failed: ${err instanceof Error ? err.message : "Unknown error"}`);
4930
4937
  process.exit(1);
4931
4938
  }
@@ -4954,6 +4961,7 @@ function deviceCommand() {
4954
4961
  console.log();
4955
4962
  } catch (err) {
4956
4963
  spinner.stop();
4964
+ if (err instanceof AuthExpiredError) throw err;
4957
4965
  printError(`Failed: ${err instanceof Error ? err.message : "Unknown error"}`);
4958
4966
  process.exit(1);
4959
4967
  }
@@ -4972,6 +4980,7 @@ function deviceCommand() {
4972
4980
  printSuccess("Device removed.");
4973
4981
  } catch (err) {
4974
4982
  spinner.stop();
4983
+ if (err instanceof AuthExpiredError) throw err;
4975
4984
  printError(`Failed: ${err instanceof Error ? err.message : "Unknown error"}`);
4976
4985
  process.exit(1);
4977
4986
  }
@@ -4992,6 +5001,7 @@ function deviceCommand() {
4992
5001
  printSuccess(`Device renamed to ${brandBold(`"${response.name}"`)}`);
4993
5002
  } catch (err) {
4994
5003
  spinner.stop();
5004
+ if (err instanceof AuthExpiredError) throw err;
4995
5005
  printError(`Failed: ${err instanceof Error ? err.message : "Unknown error"}`);
4996
5006
  process.exit(1);
4997
5007
  }
@@ -5215,7 +5225,8 @@ async function handleFirstRun(client, config, cwd, ctx, manifest, projectDir, pr
5215
5225
  let devices;
5216
5226
  try {
5217
5227
  devices = await client.get("/api/devices");
5218
- } catch {
5228
+ } catch (err) {
5229
+ if (err instanceof AuthExpiredError) throw err;
5219
5230
  devices = [];
5220
5231
  }
5221
5232
  devicesSpinner.stop();
@@ -5276,8 +5287,9 @@ async function handleFirstRun(client, config, cwd, ctx, manifest, projectDir, pr
5276
5287
  let projects;
5277
5288
  try {
5278
5289
  projects = await client.get(`/api/devices/${deviceChoice}/projects`);
5279
- } catch {
5290
+ } catch (err) {
5280
5291
  spinner.stop();
5292
+ if (err instanceof AuthExpiredError) throw err;
5281
5293
  printError("Failed to load projects from device.");
5282
5294
  return "cancelled";
5283
5295
  }
@@ -5350,6 +5362,7 @@ async function crossMachinePull(client, deviceId, projectPath, fromDeviceId, pro
5350
5362
  });
5351
5363
  } catch (err) {
5352
5364
  spinner.stop();
5365
+ if (err instanceof AuthExpiredError) throw err;
5353
5366
  printError(`Pull failed: ${err instanceof Error ? err.message : "Unknown error"}`);
5354
5367
  return 0;
5355
5368
  }
@@ -5410,6 +5423,7 @@ async function pushPhase(client, deviceId, projectPath, manifest, projectDir, pr
5410
5423
  });
5411
5424
  } catch (err) {
5412
5425
  spinner.stop();
5426
+ if (err instanceof AuthExpiredError) throw err;
5413
5427
  printError(`Push failed: ${err instanceof Error ? err.message : "Unknown error"}`);
5414
5428
  return { uploaded: 0, projectId: projectId || "", failed: true };
5415
5429
  }
@@ -5471,6 +5485,7 @@ async function pullPhase(client, deviceId, projectPath, projectDir, projectId, o
5471
5485
  });
5472
5486
  } catch (err) {
5473
5487
  spinner.stop();
5488
+ if (err instanceof AuthExpiredError) throw err;
5474
5489
  printError(`Pull failed: ${err instanceof Error ? err.message : "Unknown error"}`);
5475
5490
  return { downloaded: 0, failed: true };
5476
5491
  }
@@ -5605,8 +5620,9 @@ function whoamiCommand() {
5605
5620
  printDivider();
5606
5621
  printLabel("Device", config.deviceName || dim("none"));
5607
5622
  printLabel("Device ID", config.deviceId || dim("not registered"));
5608
- } catch {
5623
+ } catch (err) {
5609
5624
  spinner.stop();
5625
+ if (err instanceof AuthExpiredError) throw err;
5610
5626
  printLabel("Email", config.email || dim("unknown"));
5611
5627
  printLabel("Device", config.deviceName || dim("none"));
5612
5628
  }
@@ -5638,7 +5654,8 @@ import { Command as Command7 } from "commander";
5638
5654
  init_esm_shims();
5639
5655
  init_theme();
5640
5656
  init_config();
5641
- import { select as select3, isCancel as isCancel4 } from "@clack/prompts";
5657
+ init_api_client();
5658
+ import { select as select3, text as text3, isCancel as isCancel4 } from "@clack/prompts";
5642
5659
  import chalk3 from "chalk";
5643
5660
  function buildMenu(loggedIn) {
5644
5661
  if (!loggedIn) {
@@ -5659,18 +5676,22 @@ function buildMenu(loggedIn) {
5659
5676
  }
5660
5677
  async function runTui() {
5661
5678
  printBanner();
5662
- const config = await loadConfig();
5663
- const loggedIn = isAuthenticated(config);
5664
- if (loggedIn) {
5665
- console.log(` ${dim("user")} ${brand(config.email || "unknown")}`);
5666
- if (config.deviceName) {
5667
- console.log(` ${dim("device")} ${brand(config.deviceName)}`);
5679
+ let loggedIn = isAuthenticated(await loadConfig());
5680
+ const printStatus = async () => {
5681
+ const config = await loadConfig();
5682
+ loggedIn = isAuthenticated(config);
5683
+ if (loggedIn) {
5684
+ console.log(` ${dim("user")} ${brand(config.email || "unknown")}`);
5685
+ if (config.deviceName) {
5686
+ console.log(` ${dim("device")} ${brand(config.deviceName)}`);
5687
+ }
5688
+ console.log();
5689
+ } else {
5690
+ console.log(` ${dim("Not logged in")}`);
5691
+ console.log();
5668
5692
  }
5669
- console.log();
5670
- } else {
5671
- console.log(` ${dim("Not logged in")}`);
5672
- console.log();
5673
- }
5693
+ };
5694
+ await printStatus();
5674
5695
  while (true) {
5675
5696
  const items = buildMenu(loggedIn);
5676
5697
  const options = [
@@ -5689,10 +5710,49 @@ async function runTui() {
5689
5710
  printOutro("Goodbye!");
5690
5711
  return;
5691
5712
  }
5692
- await executeCommand(choice);
5713
+ try {
5714
+ await executeCommand(choice);
5715
+ } catch (err) {
5716
+ if (err instanceof AuthExpiredError) {
5717
+ printError("Session expired. Please log in again.");
5718
+ console.log();
5719
+ try {
5720
+ const { loginCommand: loginCommand2 } = await Promise.resolve().then(() => (init_login(), login_exports));
5721
+ await loginCommand2().parseAsync(["", ""]);
5722
+ await printStatus();
5723
+ } catch {
5724
+ printError("Login failed.");
5725
+ }
5726
+ }
5727
+ }
5693
5728
  console.log();
5694
5729
  }
5695
5730
  }
5731
+ async function promptDeviceSelection(config) {
5732
+ const client = new ApiClient(config.apiUrl);
5733
+ let devices;
5734
+ try {
5735
+ devices = await client.get("/api/devices");
5736
+ } catch (err) {
5737
+ if (err instanceof AuthExpiredError) throw err;
5738
+ printError("Failed to fetch devices.");
5739
+ return null;
5740
+ }
5741
+ if (devices.length === 0) {
5742
+ printError("No devices registered.");
5743
+ return null;
5744
+ }
5745
+ const choice = await select3({
5746
+ message: brand("Select device"),
5747
+ options: devices.map((d) => ({
5748
+ value: d.id,
5749
+ label: d.name,
5750
+ hint: d.id === config.deviceId ? dim("current") : void 0
5751
+ }))
5752
+ });
5753
+ if (isCancel4(choice)) return null;
5754
+ return choice;
5755
+ }
5696
5756
  async function executeCommand(command) {
5697
5757
  const { loginCommand: loginCommand2 } = await Promise.resolve().then(() => (init_login(), login_exports));
5698
5758
  const { logoutCommand: logoutCommand2 } = await Promise.resolve().then(() => (init_logout(), logout_exports));
@@ -5700,23 +5760,29 @@ async function executeCommand(command) {
5700
5760
  const { syncCommand: syncCommand2 } = await Promise.resolve().then(() => (init_sync(), sync_exports));
5701
5761
  const { statusCommand: statusCommand2 } = await Promise.resolve().then(() => (init_status(), status_exports));
5702
5762
  const { whoamiCommand: whoamiCommand2 } = await Promise.resolve().then(() => (init_whoami(), whoami_exports));
5763
+ const config = await loadConfig();
5703
5764
  const handlers = {
5704
- login: () => loginCommand2().parseAsync(["", "", "login"]),
5705
- logout: () => logoutCommand2().parseAsync(["", "", "logout"]),
5706
- sync: () => syncCommand2().parseAsync(["", "", "sync"]),
5707
- status: () => statusCommand2().parseAsync(["", "", "status"]),
5708
- whoami: () => whoamiCommand2().parseAsync(["", "", "whoami"]),
5709
- "device:add": () => deviceCommand2().parseAsync(["", "", "device", "add"]),
5710
- "device:list": () => deviceCommand2().parseAsync(["", "", "device", "list"]),
5711
- "device:remove": () => deviceCommand2().parseAsync(["", "", "device", "remove"]),
5712
- "device:rename": () => deviceCommand2().parseAsync(["", "", "device", "rename"])
5765
+ login: () => loginCommand2().parseAsync(["", ""]),
5766
+ logout: () => logoutCommand2().parseAsync(["", ""]),
5767
+ sync: () => syncCommand2().parseAsync(["", ""]),
5768
+ status: () => statusCommand2().parseAsync(["", ""]),
5769
+ whoami: () => whoamiCommand2().parseAsync(["", ""]),
5770
+ "device:add": () => deviceCommand2().parseAsync(["", "", "add"]),
5771
+ "device:list": () => deviceCommand2().parseAsync(["", "", "list"]),
5772
+ "device:remove": async () => {
5773
+ const deviceId = await promptDeviceSelection(config);
5774
+ if (!deviceId) return;
5775
+ await deviceCommand2().parseAsync(["", "", "remove", deviceId]);
5776
+ },
5777
+ "device:rename": async () => {
5778
+ const name = await text3({ message: `${brand("New device name")}:` });
5779
+ if (isCancel4(name)) return;
5780
+ await deviceCommand2().parseAsync(["", "", "rename", name]);
5781
+ }
5713
5782
  };
5714
5783
  const handler = handlers[command];
5715
5784
  if (handler) {
5716
- try {
5717
- await handler();
5718
- } catch {
5719
- }
5785
+ await handler();
5720
5786
  }
5721
5787
  }
5722
5788