@involvex/syncstuff-cli 0.0.3 → 0.0.5

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/cli.js CHANGED
@@ -9641,7 +9641,7 @@ function createTable(data, headers) {
9641
9641
  });
9642
9642
  }
9643
9643
  function printHeader() {
9644
- const packagePath = join(__dirname, "../../../../package.json");
9644
+ const packagePath = join(__dirname, "../../package.json");
9645
9645
  const packageJson = JSON.parse(readFileSync(packagePath, "utf-8"));
9646
9646
  const version = packageJson.version;
9647
9647
  const header = source_default.cyan.bold(`
@@ -20411,7 +20411,7 @@ var init_RemoveFileError = __esm(() => {
20411
20411
 
20412
20412
  // ../../node_modules/.bun/@inquirer+external-editor@2.0.2+cda980ff03d0f389/node_modules/@inquirer/external-editor/dist/index.js
20413
20413
  import { spawn, spawnSync } from "child_process";
20414
- import { readFileSync as readFileSync2, unlinkSync, writeFileSync } from "fs";
20414
+ import { readFileSync as readFileSync3, unlinkSync, writeFileSync } from "fs";
20415
20415
  import path from "node:path";
20416
20416
  import os2 from "node:os";
20417
20417
  import { randomUUID } from "node:crypto";
@@ -20527,7 +20527,7 @@ class ExternalEditor {
20527
20527
  }
20528
20528
  readTemporaryFile() {
20529
20529
  try {
20530
- const tempFileBuffer = readFileSync2(this.tempFile);
20530
+ const tempFileBuffer = readFileSync3(this.tempFile);
20531
20531
  if (tempFileBuffer.length === 0) {
20532
20532
  this.text = "";
20533
20533
  } else {
@@ -30801,9 +30801,9 @@ var init_dist16 = __esm(() => {
30801
30801
  });
30802
30802
 
30803
30803
  // src/utils/config.ts
30804
- import { mkdirSync, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
30804
+ import { mkdirSync, readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "fs";
30805
30805
  import { homedir } from "os";
30806
- import { join as join2 } from "path";
30806
+ import { join as join3 } from "path";
30807
30807
  function ensureConfigDir() {
30808
30808
  try {
30809
30809
  mkdirSync(CONFIG_DIR, { recursive: true });
@@ -30812,7 +30812,7 @@ function ensureConfigDir() {
30812
30812
  function readConfig() {
30813
30813
  ensureConfigDir();
30814
30814
  try {
30815
- const content = readFileSync3(CONFIG_FILE, "utf-8");
30815
+ const content = readFileSync4(CONFIG_FILE, "utf-8");
30816
30816
  return JSON.parse(content);
30817
30817
  } catch {
30818
30818
  return {};
@@ -30824,8 +30824,8 @@ function writeConfig(config) {
30824
30824
  }
30825
30825
  var CONFIG_DIR, CONFIG_FILE;
30826
30826
  var init_config = __esm(() => {
30827
- CONFIG_DIR = join2(homedir(), ".syncstuff");
30828
- CONFIG_FILE = join2(CONFIG_DIR, "config.json");
30827
+ CONFIG_DIR = join3(homedir(), ".syncstuff");
30828
+ CONFIG_FILE = join3(CONFIG_DIR, "config.json");
30829
30829
  });
30830
30830
 
30831
30831
  // src/utils/api-client.ts
@@ -31079,8 +31079,17 @@ var exports_devices = {};
31079
31079
  __export(exports_devices, {
31080
31080
  listDevices: () => listDevices
31081
31081
  });
31082
- async function listDevices(ctx) {
31083
- printHeader();
31082
+ async function listDevices(args, ctx) {
31083
+ const isLoop = args.includes("--loop") || args.includes("-l");
31084
+ debugLog(ctx, "Devices command", { loop: isLoop });
31085
+ if (isLoop) {
31086
+ await loopDevices(ctx);
31087
+ } else {
31088
+ printHeader();
31089
+ await fetchAndDisplayDevices(ctx);
31090
+ }
31091
+ }
31092
+ async function fetchAndDisplayDevices(ctx) {
31084
31093
  debugLog(ctx, "Fetching devices list");
31085
31094
  if (!apiClient.isAuthenticated()) {
31086
31095
  error2("You are not logged in. Please run 'syncstuff login' first.");
@@ -31096,7 +31105,7 @@ async function listDevices(ctx) {
31096
31105
  if (response.data.length === 0) {
31097
31106
  info2("No devices found. Connect a device to get started.");
31098
31107
  printSeparator();
31099
- return;
31108
+ return true;
31100
31109
  }
31101
31110
  const tableData = response.data.map((device) => [
31102
31111
  device.id.substring(0, 8) + "...",
@@ -31118,6 +31127,7 @@ async function listDevices(ctx) {
31118
31127
  printSeparator();
31119
31128
  success2(`Found ${response.data.length} device(s)`);
31120
31129
  printSeparator();
31130
+ return true;
31121
31131
  } else {
31122
31132
  spinner.fail("Failed to fetch devices");
31123
31133
  if (response.error?.includes("404") || response.error?.includes("Not found")) {
@@ -31126,13 +31136,39 @@ async function listDevices(ctx) {
31126
31136
  } else {
31127
31137
  error2(response.error || "Unknown error");
31128
31138
  }
31139
+ return false;
31129
31140
  }
31130
31141
  } catch (err) {
31131
31142
  spinner.fail("Error fetching devices");
31132
31143
  error2(`Error: ${err instanceof Error ? err.message : String(err)}`);
31133
- process.exit(1);
31144
+ return false;
31134
31145
  }
31135
31146
  }
31147
+ async function loopDevices(ctx) {
31148
+ const REFRESH_INTERVAL = 5000;
31149
+ console.clear();
31150
+ printHeader();
31151
+ console.log(source_default.cyan("Loop mode enabled. Press Ctrl+C to exit."));
31152
+ console.log(source_default.gray(`Refreshing every ${REFRESH_INTERVAL / 1000} seconds...
31153
+ `));
31154
+ process.on("SIGINT", () => {
31155
+ console.log(`
31156
+ `);
31157
+ info2("Loop stopped by user");
31158
+ process.exit(0);
31159
+ });
31160
+ await fetchAndDisplayDevices(ctx);
31161
+ const interval = setInterval(async () => {
31162
+ console.clear();
31163
+ printHeader();
31164
+ console.log(source_default.cyan("Loop mode enabled. Press Ctrl+C to exit."));
31165
+ console.log(source_default.gray(`Last refresh: ${new Date().toLocaleTimeString()}
31166
+ `));
31167
+ await fetchAndDisplayDevices(ctx);
31168
+ }, REFRESH_INTERVAL);
31169
+ await new Promise(() => {});
31170
+ clearInterval(interval);
31171
+ }
31136
31172
  var init_devices = __esm(() => {
31137
31173
  init_source();
31138
31174
  init_api_client();
@@ -31460,20 +31496,33 @@ var init_transfer = __esm(() => {
31460
31496
  init_ui();
31461
31497
  });
31462
31498
 
31499
+ // src/core.ts
31500
+ var DebugMode;
31501
+ var init_core = __esm(() => {
31502
+ DebugMode = {
31503
+ enabled: false
31504
+ };
31505
+ });
31506
+
31463
31507
  // src/cli/commands/version.ts
31464
31508
  var exports_version = {};
31465
31509
  __export(exports_version, {
31466
31510
  showversion: () => showversion
31467
31511
  });
31468
- import { readFileSync as readFileSync4 } from "fs";
31469
- import { dirname, join as join3 } from "path";
31470
- import { fileURLToPath } from "url";
31512
+ import { readFileSync as readFileSync5 } from "fs";
31513
+ import { dirname as dirname2, join as join4 } from "path";
31514
+ import { fileURLToPath as fileURLToPath2 } from "url";
31471
31515
  function showversion() {
31472
31516
  printHeader();
31473
31517
  try {
31474
- const packagePath = join3(__dirname2, "../../../package.json");
31475
- const packageJson = JSON.parse(readFileSync4(packagePath, "utf-8"));
31518
+ const packagePath = join4(__dirname3, "../../../package.json");
31519
+ const packageJson = JSON.parse(readFileSync5(packagePath, "utf-8"));
31476
31520
  const version = packageJson.version;
31521
+ if (DebugMode.enabled === true) {
31522
+ console.log(source_default.yellow("Debug mode enabled"));
31523
+ console.log("Package path: " + packagePath);
31524
+ console.log("Version: " + version);
31525
+ }
31477
31526
  const versionBox = createBox(source_default.cyan.bold(`Syncstuff CLI
31478
31527
 
31479
31528
  `) + source_default.bold("Version:") + ` ${source_default.green(version)}
@@ -31484,23 +31533,80 @@ function showversion() {
31484
31533
  console.log(versionBox);
31485
31534
  printSeparator();
31486
31535
  } catch {
31487
- console.log(source_default.yellow("Version: 0.0.1 (unable to read package.json)"));
31536
+ if (DebugMode.enabled === true) {
31537
+ const packagePath = join4(__dirname3, "../../../package.json");
31538
+ console.log(source_default.yellow("Debug mode enabled"));
31539
+ console.log("Packagepath: " + packagePath);
31540
+ console.log(source_default.yellow("Version: 0.0.1 (unable to read package.json)"));
31541
+ }
31488
31542
  }
31489
31543
  }
31490
- var __filename2, __dirname2;
31544
+ var __filename3, __dirname3;
31491
31545
  var init_version = __esm(() => {
31492
31546
  init_source();
31547
+ init_core();
31493
31548
  init_ui();
31494
- __filename2 = fileURLToPath(import.meta.url);
31495
- __dirname2 = dirname(__filename2);
31549
+ __filename3 = fileURLToPath2(import.meta.url);
31550
+ __dirname3 = dirname2(__filename3);
31496
31551
  });
31497
31552
 
31498
31553
  // src/cli/index.ts
31499
31554
  init_ui();
31555
+
31556
+ // src/utils/update-checker.ts
31557
+ init_source();
31558
+ import { readFileSync as readFileSync2 } from "fs";
31559
+ import { dirname, join as join2 } from "path";
31560
+ import { fileURLToPath } from "url";
31561
+ var __filename2 = fileURLToPath(import.meta.url);
31562
+ var __dirname2 = dirname(__filename2);
31563
+ async function checkForUpdates() {
31564
+ try {
31565
+ const packagePath = join2(__dirname2, "../../package.json");
31566
+ const packageJson = JSON.parse(readFileSync2(packagePath, "utf-8"));
31567
+ const currentVersion = packageJson.version;
31568
+ const packageName = packageJson.name;
31569
+ const response = await fetch(`https://registry.npmjs.org/${packageName}/latest`, {
31570
+ headers: { Accept: "application/json" },
31571
+ signal: AbortSignal.timeout(3000)
31572
+ });
31573
+ if (!response.ok) {
31574
+ return;
31575
+ }
31576
+ const data = await response.json();
31577
+ const latestVersion = data.version;
31578
+ if (latestVersion && latestVersion !== currentVersion) {
31579
+ const isNewer = compareVersions(latestVersion, currentVersion) > 0;
31580
+ if (isNewer) {
31581
+ console.log("");
31582
+ console.log(source_default.yellow.bold("╭─────────────────────────────────────────╮"));
31583
+ console.log(source_default.yellow.bold("│") + source_default.yellow(" Update available! ") + source_default.gray(`${currentVersion}`) + source_default.yellow(" → ") + source_default.green.bold(`${latestVersion}`) + source_default.yellow.bold(" │"));
31584
+ console.log(source_default.yellow.bold("│") + source_default.cyan(` Run: npm i -g ${packageName}`) + " ".repeat(7) + source_default.yellow.bold("│"));
31585
+ console.log(source_default.yellow.bold("╰─────────────────────────────────────────╯"));
31586
+ console.log("");
31587
+ }
31588
+ }
31589
+ } catch {}
31590
+ }
31591
+ function compareVersions(a, b) {
31592
+ const partsA = a.split(".").map(Number);
31593
+ const partsB = b.split(".").map(Number);
31594
+ for (let i = 0;i < 3; i++) {
31595
+ const partA = partsA[i] || 0;
31596
+ const partB = partsB[i] || 0;
31597
+ if (partA !== partB) {
31598
+ return partA - partB;
31599
+ }
31600
+ }
31601
+ return 0;
31602
+ }
31603
+
31604
+ // src/cli/index.ts
31500
31605
  async function run() {
31501
31606
  const args = process.argv.slice(2);
31502
31607
  const { command, flags, commandArgs } = parseArgs(args);
31503
31608
  const ctx = { debug: flags.debug };
31609
+ checkForUpdates();
31504
31610
  debugLog(ctx, "Parsed arguments:", { command, flags, commandArgs });
31505
31611
  if (flags.help) {
31506
31612
  const { showHelp: showHelp2 } = await Promise.resolve().then(() => (init_help(), exports_help));
@@ -31534,7 +31640,7 @@ async function run() {
31534
31640
  case "devices":
31535
31641
  {
31536
31642
  const { listDevices: listDevices2 } = await Promise.resolve().then(() => (init_devices(), exports_devices));
31537
- await listDevices2(ctx);
31643
+ await listDevices2(commandArgs, ctx);
31538
31644
  }
31539
31645
  break;
31540
31646
  case "device":
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@involvex/syncstuff-cli",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "type": "module",
5
5
  "homepage": "https://syncstuff-web.involvex.workers.dev/",
6
6
  "sponsor": {
@@ -1,7 +1,7 @@
1
- import type { DebugMode } from "../../core";
1
+ import { DebugMode } from "../../core";
2
2
 
3
- export const showDebug = (debugMode: DebugMode) => {
4
- if (!debugMode.enabled) {
3
+ export const showDebug = () => {
4
+ if (!DebugMode.enabled) {
5
5
  return;
6
6
  } else {
7
7
  console.log("Debug mode enabled");
@@ -11,8 +11,31 @@ import {
11
11
  success,
12
12
  } from "../../utils/ui.js";
13
13
 
14
- export async function listDevices(ctx: CommandContext): Promise<void> {
15
- printHeader();
14
+ /**
15
+ * List devices command
16
+ * Options:
17
+ * --loop Continuously refresh devices until Ctrl+C
18
+ */
19
+ export async function listDevices(
20
+ args: string[],
21
+ ctx: CommandContext,
22
+ ): Promise<void> {
23
+ const isLoop = args.includes("--loop") || args.includes("-l");
24
+
25
+ debugLog(ctx, "Devices command", { loop: isLoop });
26
+
27
+ if (isLoop) {
28
+ await loopDevices(ctx);
29
+ } else {
30
+ printHeader();
31
+ await fetchAndDisplayDevices(ctx);
32
+ }
33
+ }
34
+
35
+ /**
36
+ * Fetch and display devices once
37
+ */
38
+ async function fetchAndDisplayDevices(ctx: CommandContext): Promise<boolean> {
16
39
  debugLog(ctx, "Fetching devices list");
17
40
 
18
41
  if (!apiClient.isAuthenticated()) {
@@ -33,7 +56,7 @@ export async function listDevices(ctx: CommandContext): Promise<void> {
33
56
  if (response.data.length === 0) {
34
57
  info("No devices found. Connect a device to get started.");
35
58
  printSeparator();
36
- return;
59
+ return true;
37
60
  }
38
61
 
39
62
  const tableData = response.data.map(device => [
@@ -58,6 +81,7 @@ export async function listDevices(ctx: CommandContext): Promise<void> {
58
81
  printSeparator();
59
82
  success(`Found ${response.data.length} device(s)`);
60
83
  printSeparator();
84
+ return true;
61
85
  } else {
62
86
  spinner.fail("Failed to fetch devices");
63
87
  if (
@@ -69,10 +93,53 @@ export async function listDevices(ctx: CommandContext): Promise<void> {
69
93
  } else {
70
94
  error(response.error || "Unknown error");
71
95
  }
96
+ return false;
72
97
  }
73
98
  } catch (err) {
74
99
  spinner.fail("Error fetching devices");
75
100
  error(`Error: ${err instanceof Error ? err.message : String(err)}`);
76
- process.exit(1);
101
+ return false;
77
102
  }
78
103
  }
104
+
105
+ /**
106
+ * Loop mode: continuously refresh devices
107
+ */
108
+ async function loopDevices(ctx: CommandContext): Promise<void> {
109
+ const REFRESH_INTERVAL = 5000; // 5 seconds
110
+
111
+ console.clear();
112
+ printHeader();
113
+ console.log(chalk.cyan("Loop mode enabled. Press Ctrl+C to exit."));
114
+ console.log(
115
+ chalk.gray(`Refreshing every ${REFRESH_INTERVAL / 1000} seconds...\n`),
116
+ );
117
+
118
+ // Handle Ctrl+C gracefully
119
+ process.on("SIGINT", () => {
120
+ console.log("\n");
121
+ info("Loop stopped by user");
122
+ process.exit(0);
123
+ });
124
+
125
+ // Initial fetch
126
+ await fetchAndDisplayDevices(ctx);
127
+
128
+ // Set up refresh loop
129
+ const interval = setInterval(async () => {
130
+ console.clear();
131
+ printHeader();
132
+ console.log(chalk.cyan("Loop mode enabled. Press Ctrl+C to exit."));
133
+ console.log(
134
+ chalk.gray(`Last refresh: ${new Date().toLocaleTimeString()}\n`),
135
+ );
136
+ await fetchAndDisplayDevices(ctx);
137
+ }, REFRESH_INTERVAL);
138
+
139
+ // Keep the process running
140
+ await new Promise(() => {
141
+ // This promise never resolves - we wait for SIGINT
142
+ });
143
+
144
+ clearInterval(interval);
145
+ }
@@ -2,6 +2,7 @@ import chalk from "chalk";
2
2
  import { readFileSync } from "fs";
3
3
  import { dirname, join } from "path";
4
4
  import { fileURLToPath } from "url";
5
+ import { DebugMode } from "../../core.js";
5
6
  import { createBox, printHeader, printSeparator } from "../../utils/ui.js";
6
7
 
7
8
  const __filename = fileURLToPath(import.meta.url);
@@ -15,6 +16,12 @@ export function showversion() {
15
16
  const packageJson = JSON.parse(readFileSync(packagePath, "utf-8"));
16
17
  const version = packageJson.version;
17
18
 
19
+ if (DebugMode.enabled === true) {
20
+ console.log(chalk.yellow("Debug mode enabled"));
21
+ console.log("Package path: " + packagePath);
22
+ console.log("Version: " + version);
23
+ }
24
+
18
25
  const versionBox = createBox(
19
26
  chalk.cyan.bold("Syncstuff CLI\n\n") +
20
27
  chalk.bold("Version:") +
@@ -30,6 +37,11 @@ export function showversion() {
30
37
  console.log(versionBox);
31
38
  printSeparator();
32
39
  } catch {
33
- console.log(chalk.yellow("Version: 0.0.1 (unable to read package.json)"));
40
+ if (DebugMode.enabled === true) {
41
+ const packagePath = join(__dirname, "../../../package.json");
42
+ console.log(chalk.yellow("Debug mode enabled"));
43
+ console.log("Packagepath: " + packagePath);
44
+ console.log(chalk.yellow("Version: 0.0.1 (unable to read package.json)"));
45
+ }
34
46
  }
35
47
  }
package/src/cli/index.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { debugLog, parseArgs, type CommandContext } from "../utils/context.js";
3
3
  import { printHeader } from "../utils/ui.js";
4
+ import { checkForUpdates } from "../utils/update-checker.js";
4
5
 
5
6
  export async function run() {
6
7
  const args = process.argv.slice(2);
@@ -8,6 +9,9 @@ export async function run() {
8
9
 
9
10
  const ctx: CommandContext = { debug: flags.debug };
10
11
 
12
+ // Check for updates (non-blocking)
13
+ checkForUpdates();
14
+
11
15
  // Debug mode: log parsed arguments
12
16
  debugLog(ctx, "Parsed arguments:", { command, flags, commandArgs });
13
17
 
@@ -47,7 +51,7 @@ export async function run() {
47
51
  case "devices":
48
52
  {
49
53
  const { listDevices } = await import("./commands/devices.js");
50
- await listDevices(ctx);
54
+ await listDevices(commandArgs, ctx);
51
55
  }
52
56
  break;
53
57
  case "device":
package/src/core.ts CHANGED
@@ -8,6 +8,6 @@ export interface Device {
8
8
  is_online: boolean;
9
9
  }
10
10
 
11
- export type DebugMode = {
12
- enabled: boolean;
11
+ export const DebugMode = {
12
+ enabled: false,
13
13
  };
package/src/utils/ui.ts CHANGED
@@ -71,7 +71,7 @@ export function animateText(text: string, delay: number = 50): Promise<void> {
71
71
  }
72
72
 
73
73
  export function printHeader(): void {
74
- const packagePath = join(__dirname, "../../../../package.json");
74
+ const packagePath = join(__dirname, "../../package.json");
75
75
  const packageJson = JSON.parse(readFileSync(packagePath, "utf-8"));
76
76
  const version = packageJson.version;
77
77
  const header = chalk.cyan.bold(`
@@ -0,0 +1,86 @@
1
+ import chalk from "chalk";
2
+ import { readFileSync } from "fs";
3
+ import { dirname, join } from "path";
4
+ import { fileURLToPath } from "url";
5
+
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = dirname(__filename);
8
+
9
+ /**
10
+ * Check if a newer version of the CLI is available on npm
11
+ */
12
+ export async function checkForUpdates(): Promise<void> {
13
+ try {
14
+ // Get current version from package.json
15
+ const packagePath = join(__dirname, "../../package.json");
16
+ const packageJson = JSON.parse(readFileSync(packagePath, "utf-8"));
17
+ const currentVersion = packageJson.version;
18
+ const packageName = packageJson.name;
19
+
20
+ // Fetch latest version from npm registry
21
+ const response = await fetch(
22
+ `https://registry.npmjs.org/${packageName}/latest`,
23
+ {
24
+ headers: { Accept: "application/json" },
25
+ signal: AbortSignal.timeout(3000), // 3 second timeout
26
+ },
27
+ );
28
+
29
+ if (!response.ok) {
30
+ return; // Silently fail if npm check fails
31
+ }
32
+
33
+ const data = (await response.json()) as { version: string };
34
+ const latestVersion = data.version;
35
+
36
+ // Compare versions
37
+ if (latestVersion && latestVersion !== currentVersion) {
38
+ const isNewer = compareVersions(latestVersion, currentVersion) > 0;
39
+
40
+ if (isNewer) {
41
+ console.log("");
42
+ console.log(
43
+ chalk.yellow.bold("╭─────────────────────────────────────────╮"),
44
+ );
45
+ console.log(
46
+ chalk.yellow.bold("│") +
47
+ chalk.yellow(" Update available! ") +
48
+ chalk.gray(`${currentVersion}`) +
49
+ chalk.yellow(" → ") +
50
+ chalk.green.bold(`${latestVersion}`) +
51
+ chalk.yellow.bold(" │"),
52
+ );
53
+ console.log(
54
+ chalk.yellow.bold("│") +
55
+ chalk.cyan(` Run: npm i -g ${packageName}`) +
56
+ " ".repeat(7) +
57
+ chalk.yellow.bold("│"),
58
+ );
59
+ console.log(
60
+ chalk.yellow.bold("╰─────────────────────────────────────────╯"),
61
+ );
62
+ console.log("");
63
+ }
64
+ }
65
+ } catch {
66
+ // Silently fail - update check is not critical
67
+ }
68
+ }
69
+
70
+ /**
71
+ * Compare two semantic versions
72
+ * Returns: positive if a > b, negative if a < b, 0 if equal
73
+ */
74
+ function compareVersions(a: string, b: string): number {
75
+ const partsA = a.split(".").map(Number);
76
+ const partsB = b.split(".").map(Number);
77
+
78
+ for (let i = 0; i < 3; i++) {
79
+ const partA = partsA[i] || 0;
80
+ const partB = partsB[i] || 0;
81
+ if (partA !== partB) {
82
+ return partA - partB;
83
+ }
84
+ }
85
+ return 0;
86
+ }