@seedvault/cli 0.1.3 → 0.2.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.
Files changed (3) hide show
  1. package/bin/sv.mjs +2 -7
  2. package/dist/sv.js +385 -82
  3. package/package.json +1 -1
package/bin/sv.mjs CHANGED
@@ -1,10 +1,5 @@
1
- #!/usr/bin/env node
2
- import { execFileSync } from "child_process";
1
+ #!/usr/bin/env bun
3
2
  import { join, dirname } from "path";
4
3
  import { fileURLToPath } from "url";
5
4
  const __dirname = dirname(fileURLToPath(import.meta.url));
6
- try {
7
- execFileSync("bun", [join(__dirname, "..", "dist", "sv.js"), ...process.argv.slice(2)], { stdio: "inherit" });
8
- } catch (e) {
9
- process.exit(e.status || 1);
10
- }
5
+ await import(join(__dirname, "..", "dist", "sv.js"));
package/dist/sv.js CHANGED
@@ -3,7 +3,8 @@
3
3
 
4
4
  // src/commands/init.ts
5
5
  import * as readline from "readline/promises";
6
- import { stdin, stdout } from "process";
6
+ import { stdout } from "process";
7
+ import * as fs from "fs";
7
8
 
8
9
  // src/config.ts
9
10
  import { join, resolve, relative, isAbsolute } from "path";
@@ -12,12 +13,25 @@ import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
12
13
  var CONFIG_DIR = join(homedir(), ".config", "seedvault");
13
14
  var CONFIG_PATH = join(CONFIG_DIR, "config.json");
14
15
  var PID_PATH = join(CONFIG_DIR, "daemon.pid");
15
- function getConfigDir() {
16
- return CONFIG_DIR;
17
- }
16
+ var DAEMON_LOG_PATH = join(CONFIG_DIR, "daemon.log");
17
+ var LAUNCHD_PLIST_PATH = join(homedir(), "Library", "LaunchAgents", "ai.seedvault.daemon.plist");
18
+ var SYSTEMD_UNIT_PATH = join(homedir(), ".config", "systemd", "user", "seedvault.service");
19
+ var SCHTASKS_XML_PATH = join(CONFIG_DIR, "seedvault-task.xml");
18
20
  function getPidPath() {
19
21
  return PID_PATH;
20
22
  }
23
+ function getDaemonLogPath() {
24
+ return DAEMON_LOG_PATH;
25
+ }
26
+ function getLaunchdPlistPath() {
27
+ return LAUNCHD_PLIST_PATH;
28
+ }
29
+ function getSystemdUnitPath() {
30
+ return SYSTEMD_UNIT_PATH;
31
+ }
32
+ function getSchtasksXmlPath() {
33
+ return SCHTASKS_XML_PATH;
34
+ }
21
35
  function ensureConfigDir() {
22
36
  if (!existsSync(CONFIG_DIR)) {
23
37
  mkdirSync(CONFIG_DIR, { recursive: true });
@@ -258,7 +272,14 @@ async function init(args) {
258
272
  console.log(` Token: ${result.token}`);
259
273
  return;
260
274
  }
261
- const rl = readline.createInterface({ input: stdin, output: stdout });
275
+ let input;
276
+ try {
277
+ const fd = fs.openSync("/dev/tty", "r");
278
+ input = fs.createReadStream("", { fd });
279
+ } catch {
280
+ input = process.stdin;
281
+ }
282
+ const rl = readline.createInterface({ input, output: stdout });
262
283
  try {
263
284
  console.log(`Seedvault Setup
264
285
  `);
@@ -402,7 +423,7 @@ async function collections() {
402
423
  }
403
424
 
404
425
  // src/commands/start.ts
405
- import { writeFileSync as writeFileSync2, unlinkSync } from "fs";
426
+ import { writeFileSync as writeFileSync2, unlinkSync as unlinkSync2 } from "fs";
406
427
 
407
428
  // ../node_modules/.bun/chokidar@4.0.3/node_modules/chokidar/esm/index.js
408
429
  import { stat as statcb } from "fs";
@@ -2271,13 +2292,350 @@ async function walkDirRecursive(dir, results) {
2271
2292
  }
2272
2293
  }
2273
2294
 
2295
+ // src/daemon/service.ts
2296
+ import { resolve as resolve5, dirname as dirname3 } from "path";
2297
+ import { existsSync as existsSync3, mkdirSync as mkdirSync2, unlinkSync } from "fs";
2298
+ var TASK_NAME = "SeedvaultDaemon";
2299
+ function detectPlatform() {
2300
+ if (process.platform === "darwin")
2301
+ return "macos";
2302
+ if (process.platform === "linux")
2303
+ return "linux";
2304
+ if (process.platform === "win32")
2305
+ return "windows";
2306
+ throw new Error(`Unsupported platform: ${process.platform}. Only macOS, Linux, and Windows are supported.`);
2307
+ }
2308
+ function resolveBunPath() {
2309
+ const which = Bun.which("bun");
2310
+ if (which)
2311
+ return which;
2312
+ if (process.platform === "win32") {
2313
+ const fallback = resolve5(process.env.USERPROFILE || process.env.HOME || "~", ".bun", "bin", "bun.exe");
2314
+ if (existsSync3(fallback))
2315
+ return fallback;
2316
+ } else {
2317
+ const fallback = resolve5(process.env.HOME || "~", ".bun", "bin", "bun");
2318
+ if (existsSync3(fallback))
2319
+ return fallback;
2320
+ }
2321
+ throw new Error("Cannot find bun executable. Ensure bun is in your PATH.");
2322
+ }
2323
+ function resolveSvPath() {
2324
+ return resolve5(process.argv[1]);
2325
+ }
2326
+ async function runCommand(cmd, args) {
2327
+ const proc = Bun.spawn([cmd, ...args], {
2328
+ stdout: "pipe",
2329
+ stderr: "pipe"
2330
+ });
2331
+ const [stdout2, stderr] = await Promise.all([
2332
+ new Response(proc.stdout).text(),
2333
+ new Response(proc.stderr).text()
2334
+ ]);
2335
+ const exitCode = await proc.exited;
2336
+ if (exitCode !== 0) {
2337
+ throw new Error(`Command failed: ${cmd} ${args.join(" ")}
2338
+ ${stderr.trim() || stdout2.trim()}`);
2339
+ }
2340
+ return { stdout: stdout2.trim(), stderr: stderr.trim() };
2341
+ }
2342
+ function generatePlist(bunPath, svPath, logPath) {
2343
+ return `<?xml version="1.0" encoding="UTF-8"?>
2344
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
2345
+ <plist version="1.0">
2346
+ <dict>
2347
+ <key>Label</key>
2348
+ <string>ai.seedvault.daemon</string>
2349
+ <key>ProgramArguments</key>
2350
+ <array>
2351
+ <string>${bunPath}</string>
2352
+ <string>${svPath}</string>
2353
+ <string>start</string>
2354
+ <string>--foreground</string>
2355
+ </array>
2356
+ <key>KeepAlive</key>
2357
+ <dict>
2358
+ <key>SuccessfulExit</key>
2359
+ <false/>
2360
+ </dict>
2361
+ <key>RunAtLoad</key>
2362
+ <true/>
2363
+ <key>ThrottleInterval</key>
2364
+ <integer>5</integer>
2365
+ <key>StandardOutPath</key>
2366
+ <string>${logPath}</string>
2367
+ <key>StandardErrorPath</key>
2368
+ <string>${logPath}</string>
2369
+ </dict>
2370
+ </plist>
2371
+ `;
2372
+ }
2373
+ function generateUnit(bunPath, svPath, logPath) {
2374
+ return `[Unit]
2375
+ Description=Seedvault Sync Daemon
2376
+
2377
+ [Service]
2378
+ ExecStart=${bunPath} ${svPath} start --foreground
2379
+ Restart=on-failure
2380
+ RestartSec=5
2381
+ StandardOutput=append:${logPath}
2382
+ StandardError=append:${logPath}
2383
+
2384
+ [Install]
2385
+ WantedBy=default.target
2386
+ `;
2387
+ }
2388
+ function escapeXml(s) {
2389
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
2390
+ }
2391
+ function generateTaskXml(bunPath, svPath, logPath) {
2392
+ const eBun = escapeXml(bunPath);
2393
+ const eSv = escapeXml(svPath);
2394
+ const eLog = escapeXml(logPath);
2395
+ return `<?xml version="1.0" encoding="UTF-16"?>
2396
+ <Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
2397
+ <RegistrationInfo>
2398
+ <Description>Seedvault Sync Daemon</Description>
2399
+ </RegistrationInfo>
2400
+ <Triggers>
2401
+ <LogonTrigger>
2402
+ <Enabled>true</Enabled>
2403
+ </LogonTrigger>
2404
+ </Triggers>
2405
+ <Settings>
2406
+ <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
2407
+ <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
2408
+ <StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>
2409
+ <ExecutionTimeLimit>PT0S</ExecutionTimeLimit>
2410
+ <RestartOnFailure>
2411
+ <Interval>PT5S</Interval>
2412
+ <Count>999</Count>
2413
+ </RestartOnFailure>
2414
+ </Settings>
2415
+ <Actions>
2416
+ <Exec>
2417
+ <Command>cmd</Command>
2418
+ <Arguments>/c "${eBun}" "${eSv}" start --foreground &gt;&gt; "${eLog}" 2&gt;&amp;1</Arguments>
2419
+ </Exec>
2420
+ </Actions>
2421
+ </Task>
2422
+ `;
2423
+ }
2424
+ async function installService() {
2425
+ const platform = detectPlatform();
2426
+ const bunPath = resolveBunPath();
2427
+ const svPath = resolveSvPath();
2428
+ const logPath = getDaemonLogPath();
2429
+ ensureConfigDir();
2430
+ if (platform === "macos") {
2431
+ await installMacos(bunPath, svPath, logPath);
2432
+ } else if (platform === "linux") {
2433
+ await installLinux(bunPath, svPath, logPath);
2434
+ } else {
2435
+ await installWindows(bunPath, svPath, logPath);
2436
+ }
2437
+ }
2438
+ async function installMacos(bunPath, svPath, logPath) {
2439
+ const plistPath = getLaunchdPlistPath();
2440
+ const plistDir = dirname3(plistPath);
2441
+ if (!existsSync3(plistDir)) {
2442
+ mkdirSync2(plistDir, { recursive: true });
2443
+ }
2444
+ if (existsSync3(plistPath)) {
2445
+ try {
2446
+ await runCommand("launchctl", ["unload", plistPath]);
2447
+ } catch {}
2448
+ }
2449
+ await Bun.write(plistPath, generatePlist(bunPath, svPath, logPath));
2450
+ await runCommand("launchctl", ["load", plistPath]);
2451
+ console.log("Seedvault daemon registered with launchd.");
2452
+ console.log(` Service: ai.seedvault.daemon`);
2453
+ console.log(` Log: ${logPath}`);
2454
+ console.log(` The daemon will auto-restart on crash and start on login.`);
2455
+ console.log(` Run 'sv status' to check, 'sv stop' to unregister.`);
2456
+ }
2457
+ async function installLinux(bunPath, svPath, logPath) {
2458
+ const unitPath = getSystemdUnitPath();
2459
+ const unitDir = dirname3(unitPath);
2460
+ if (!existsSync3(unitDir)) {
2461
+ mkdirSync2(unitDir, { recursive: true });
2462
+ }
2463
+ if (existsSync3(unitPath)) {
2464
+ try {
2465
+ await runCommand("systemctl", ["--user", "disable", "--now", "seedvault.service"]);
2466
+ } catch {}
2467
+ }
2468
+ await Bun.write(unitPath, generateUnit(bunPath, svPath, logPath));
2469
+ await runCommand("systemctl", ["--user", "daemon-reload"]);
2470
+ await runCommand("systemctl", ["--user", "enable", "--now", "seedvault.service"]);
2471
+ console.log("Seedvault daemon registered with systemd.");
2472
+ console.log(` Service: seedvault.service`);
2473
+ console.log(` Log: ${logPath}`);
2474
+ console.log(` The daemon will auto-restart on crash and start on login.`);
2475
+ console.log(` Run 'sv status' to check, 'sv stop' to unregister.`);
2476
+ }
2477
+ async function installWindows(bunPath, svPath, logPath) {
2478
+ const xmlPath = getSchtasksXmlPath();
2479
+ try {
2480
+ await runCommand("schtasks", ["/Delete", "/TN", TASK_NAME, "/F"]);
2481
+ } catch {}
2482
+ await Bun.write(xmlPath, generateTaskXml(bunPath, svPath, logPath));
2483
+ await runCommand("schtasks", ["/Create", "/TN", TASK_NAME, "/XML", xmlPath, "/F"]);
2484
+ await runCommand("schtasks", ["/Run", "/TN", TASK_NAME]);
2485
+ console.log("Seedvault daemon registered with Windows Task Scheduler.");
2486
+ console.log(` Task: ${TASK_NAME}`);
2487
+ console.log(` Log: ${logPath}`);
2488
+ console.log(` The daemon will auto-restart on failure and start on login.`);
2489
+ console.log(` Run 'sv status' to check, 'sv stop' to unregister.`);
2490
+ }
2491
+ async function uninstallService() {
2492
+ const platform = detectPlatform();
2493
+ if (platform === "macos") {
2494
+ await uninstallMacos();
2495
+ } else if (platform === "linux") {
2496
+ await uninstallLinux();
2497
+ } else {
2498
+ await uninstallWindows();
2499
+ }
2500
+ }
2501
+ async function uninstallMacos() {
2502
+ const plistPath = getLaunchdPlistPath();
2503
+ if (!existsSync3(plistPath)) {
2504
+ console.log("No daemon service is registered.");
2505
+ return;
2506
+ }
2507
+ try {
2508
+ await runCommand("launchctl", ["unload", plistPath]);
2509
+ } catch {}
2510
+ unlinkSync(plistPath);
2511
+ cleanupPidFile();
2512
+ console.log("Daemon stopped and service unregistered.");
2513
+ }
2514
+ async function uninstallLinux() {
2515
+ const unitPath = getSystemdUnitPath();
2516
+ if (!existsSync3(unitPath)) {
2517
+ console.log("No daemon service is registered.");
2518
+ return;
2519
+ }
2520
+ try {
2521
+ await runCommand("systemctl", ["--user", "disable", "--now", "seedvault.service"]);
2522
+ } catch {}
2523
+ unlinkSync(unitPath);
2524
+ try {
2525
+ await runCommand("systemctl", ["--user", "daemon-reload"]);
2526
+ } catch {}
2527
+ cleanupPidFile();
2528
+ console.log("Daemon stopped and service unregistered.");
2529
+ }
2530
+ async function uninstallWindows() {
2531
+ let taskExists = false;
2532
+ try {
2533
+ await runCommand("schtasks", ["/Query", "/TN", TASK_NAME]);
2534
+ taskExists = true;
2535
+ } catch {}
2536
+ if (!taskExists) {
2537
+ console.log("No daemon service is registered.");
2538
+ return;
2539
+ }
2540
+ try {
2541
+ await runCommand("schtasks", ["/End", "/TN", TASK_NAME]);
2542
+ } catch {}
2543
+ try {
2544
+ await runCommand("schtasks", ["/Delete", "/TN", TASK_NAME, "/F"]);
2545
+ } catch {}
2546
+ const xmlPath = getSchtasksXmlPath();
2547
+ if (existsSync3(xmlPath)) {
2548
+ try {
2549
+ unlinkSync(xmlPath);
2550
+ } catch {}
2551
+ }
2552
+ cleanupPidFile();
2553
+ console.log("Daemon stopped and service unregistered.");
2554
+ }
2555
+ function cleanupPidFile() {
2556
+ const pidPath = getPidPath();
2557
+ if (existsSync3(pidPath)) {
2558
+ try {
2559
+ unlinkSync(pidPath);
2560
+ } catch {}
2561
+ }
2562
+ }
2563
+ async function getServiceStatus() {
2564
+ const platform = detectPlatform();
2565
+ if (platform === "macos") {
2566
+ return getStatusMacos();
2567
+ } else if (platform === "linux") {
2568
+ return getStatusLinux();
2569
+ } else {
2570
+ return getStatusWindows();
2571
+ }
2572
+ }
2573
+ async function getStatusMacos() {
2574
+ const plistPath = getLaunchdPlistPath();
2575
+ if (!existsSync3(plistPath)) {
2576
+ return { installed: false, running: false, pid: null };
2577
+ }
2578
+ try {
2579
+ const { stdout: stdout2 } = await runCommand("launchctl", ["list", "ai.seedvault.daemon"]);
2580
+ const pidMatch = stdout2.match(/"PID"\s*=\s*(\d+)/);
2581
+ const pid = pidMatch ? parseInt(pidMatch[1], 10) : null;
2582
+ return { installed: true, running: pid !== null, pid };
2583
+ } catch {
2584
+ return { installed: true, running: false, pid: null };
2585
+ }
2586
+ }
2587
+ async function getStatusLinux() {
2588
+ const unitPath = getSystemdUnitPath();
2589
+ if (!existsSync3(unitPath)) {
2590
+ return { installed: false, running: false, pid: null };
2591
+ }
2592
+ let running = false;
2593
+ try {
2594
+ const { stdout: stdout2 } = await runCommand("systemctl", ["--user", "is-active", "seedvault.service"]);
2595
+ running = stdout2 === "active";
2596
+ } catch {}
2597
+ let pid = null;
2598
+ if (running) {
2599
+ try {
2600
+ const { stdout: stdout2 } = await runCommand("systemctl", ["--user", "show", "--property=MainPID", "seedvault.service"]);
2601
+ const match = stdout2.match(/MainPID=(\d+)/);
2602
+ if (match) {
2603
+ const parsed = parseInt(match[1], 10);
2604
+ if (parsed > 0)
2605
+ pid = parsed;
2606
+ }
2607
+ } catch {}
2608
+ }
2609
+ return { installed: true, running, pid };
2610
+ }
2611
+ async function getStatusWindows() {
2612
+ try {
2613
+ const { stdout: stdout2 } = await runCommand("schtasks", ["/Query", "/TN", TASK_NAME, "/FO", "CSV", "/NH"]);
2614
+ const installed = true;
2615
+ const running = stdout2.toLowerCase().includes("running");
2616
+ let pid = null;
2617
+ const pidPath = getPidPath();
2618
+ if (running && existsSync3(pidPath)) {
2619
+ try {
2620
+ const content = await Bun.file(pidPath).text();
2621
+ const parsed = parseInt(content.trim(), 10);
2622
+ if (!isNaN(parsed) && parsed > 0)
2623
+ pid = parsed;
2624
+ } catch {}
2625
+ }
2626
+ return { installed, running, pid };
2627
+ } catch {
2628
+ return { installed: false, running: false, pid: null };
2629
+ }
2630
+ }
2631
+
2274
2632
  // src/commands/start.ts
2275
2633
  async function start(args) {
2276
- const daemonize = args.includes("-d") || args.includes("--daemon");
2277
- if (daemonize) {
2278
- return startBackground();
2634
+ const foreground = args.includes("-f") || args.includes("--foreground");
2635
+ if (foreground) {
2636
+ return startForeground();
2279
2637
  }
2280
- return startForeground();
2638
+ return installService();
2281
2639
  }
2282
2640
  async function startForeground() {
2283
2641
  let config = loadConfig();
@@ -2398,31 +2756,13 @@ async function startForeground() {
2398
2756
  watcher.close();
2399
2757
  syncer.stop();
2400
2758
  try {
2401
- unlinkSync(getPidPath());
2759
+ unlinkSync2(getPidPath());
2402
2760
  } catch {}
2403
2761
  process.exit(0);
2404
2762
  };
2405
2763
  process.on("SIGINT", shutdown);
2406
2764
  process.on("SIGTERM", shutdown);
2407
2765
  }
2408
- async function startBackground() {
2409
- loadConfig();
2410
- const entryPoint = import.meta.dir + "/../index.ts";
2411
- const logPath = getConfigDir() + "/daemon.log";
2412
- const child = Bun.spawn({
2413
- cmd: ["bun", "run", entryPoint, "start"],
2414
- stdin: "ignore",
2415
- stdout: Bun.file(logPath),
2416
- stderr: Bun.file(logPath),
2417
- env: { ...process.env }
2418
- });
2419
- const pid = child.pid;
2420
- writeFileSync2(getPidPath(), String(pid));
2421
- console.log(`Daemon started in background (PID ${pid}).`);
2422
- console.log(` Log: ${logPath}`);
2423
- console.log(` Run 'sv status' to check, 'sv stop' to stop.`);
2424
- child.unref();
2425
- }
2426
2766
  function keyByName(collections2) {
2427
2767
  const map = new Map;
2428
2768
  for (const collection of collections2) {
@@ -2455,46 +2795,11 @@ function reconcileCollections(prev, next) {
2455
2795
  }
2456
2796
 
2457
2797
  // src/commands/stop.ts
2458
- import { readFileSync as readFileSync2, unlinkSync as unlinkSync2, existsSync as existsSync3 } from "fs";
2459
2798
  async function stop() {
2460
- const pidPath = getPidPath();
2461
- if (!existsSync3(pidPath)) {
2462
- console.log("No daemon is running (no PID file found).");
2463
- return;
2464
- }
2465
- const pid = parseInt(readFileSync2(pidPath, "utf-8").trim(), 10);
2466
- if (isNaN(pid)) {
2467
- console.error("Invalid PID file. Removing it.");
2468
- unlinkSync2(pidPath);
2469
- return;
2470
- }
2471
- try {
2472
- process.kill(pid, 0);
2473
- } catch {
2474
- console.log(`Daemon (PID ${pid}) is not running. Cleaning up PID file.`);
2475
- unlinkSync2(pidPath);
2476
- return;
2477
- }
2478
- try {
2479
- process.kill(pid, "SIGTERM");
2480
- console.log(`Sent SIGTERM to daemon (PID ${pid}).`);
2481
- await Bun.sleep(500);
2482
- try {
2483
- process.kill(pid, 0);
2484
- console.log("Daemon still running. Send SIGKILL with: kill -9 " + pid);
2485
- } catch {
2486
- console.log("Daemon stopped.");
2487
- try {
2488
- unlinkSync2(pidPath);
2489
- } catch {}
2490
- }
2491
- } catch (e) {
2492
- console.error(`Failed to stop daemon: ${e.message}`);
2493
- }
2799
+ await uninstallService();
2494
2800
  }
2495
2801
 
2496
2802
  // src/commands/status.ts
2497
- import { readFileSync as readFileSync3, existsSync as existsSync4 } from "fs";
2498
2803
  async function status() {
2499
2804
  if (!configExists()) {
2500
2805
  console.log("Not configured. Run 'sv init' first.");
@@ -2505,21 +2810,19 @@ async function status() {
2505
2810
  `);
2506
2811
  console.log(` Server: ${config.server}`);
2507
2812
  console.log(` Contributor: ${config.contributorId}`);
2508
- const pidPath = getPidPath();
2509
- if (existsSync4(pidPath)) {
2510
- const pid = parseInt(readFileSync3(pidPath, "utf-8").trim(), 10);
2511
- let alive = false;
2512
- try {
2513
- process.kill(pid, 0);
2514
- alive = true;
2515
- } catch {}
2516
- if (alive) {
2517
- console.log(` Daemon: running (PID ${pid})`);
2813
+ try {
2814
+ const platform = detectPlatform();
2815
+ const serviceName = platform === "macos" ? "launchd" : platform === "linux" ? "systemd" : "Task Scheduler";
2816
+ const svc = await getServiceStatus();
2817
+ if (!svc.installed) {
2818
+ console.log(` Daemon: not registered (run 'sv start' to register)`);
2819
+ } else if (svc.running) {
2820
+ console.log(` Daemon: running via ${serviceName}${svc.pid ? ` (PID ${svc.pid})` : ""}`);
2518
2821
  } else {
2519
- console.log(` Daemon: not running (stale PID file)`);
2822
+ console.log(` Daemon: registered via ${serviceName} but not running`);
2520
2823
  }
2521
- } else {
2522
- console.log(" Daemon: not running");
2824
+ } catch {
2825
+ console.log(" Daemon: unsupported platform");
2523
2826
  }
2524
2827
  if (config.collections.length === 0) {
2525
2828
  console.log(" Collections: none configured");
@@ -2644,9 +2947,9 @@ Collections:
2644
2947
  collections List configured collections
2645
2948
 
2646
2949
  Daemon:
2647
- start Start syncing (foreground)
2648
- start -d Start syncing (background)
2649
- stop Stop the daemon
2950
+ start Register OS service and start syncing
2951
+ start -f Start syncing in foreground (debug)
2952
+ stop Stop daemon and unregister service
2650
2953
  status Show sync status
2651
2954
 
2652
2955
  Files:
@@ -2664,7 +2967,7 @@ async function main() {
2664
2967
  return;
2665
2968
  }
2666
2969
  if (cmd === "--version" || cmd === "-v") {
2667
- console.log("0.1.3");
2970
+ console.log("0.2.1");
2668
2971
  return;
2669
2972
  }
2670
2973
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seedvault/cli",
3
- "version": "0.1.3",
3
+ "version": "0.2.1",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "sv": "bin/sv.mjs"