@rudderhq/cli 0.2.1-canary.3 → 0.2.1-canary.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/index.js CHANGED
@@ -6178,6 +6178,70 @@ var DESKTOP_APP_NAME = "Rudder";
6178
6178
  var DESKTOP_METADATA_FILE = ".rudder-desktop-install.json";
6179
6179
  var DESKTOP_CHECKSUM_ASSET_NAME = "SHASUMS256.txt";
6180
6180
  var GITHUB_ASSET_DOWNLOAD_ACCEPT = "application/octet-stream";
6181
+ function normalizeProgressTotal(totalBytes) {
6182
+ return typeof totalBytes === "number" && Number.isFinite(totalBytes) && totalBytes > 0 ? totalBytes : null;
6183
+ }
6184
+ function writeDesktopProgress(event) {
6185
+ const payload = {
6186
+ source: "rudder-desktop-update",
6187
+ ...event,
6188
+ at: (/* @__PURE__ */ new Date()).toISOString()
6189
+ };
6190
+ try {
6191
+ process.stdout.write(`${JSON.stringify(payload)}
6192
+ `);
6193
+ } catch (error) {
6194
+ const code = typeof error === "object" && error && "code" in error ? String(error.code) : "";
6195
+ if (code !== "EPIPE") throw error;
6196
+ }
6197
+ }
6198
+ function desktopDownloadPhase(label) {
6199
+ return label.toLowerCase().includes("shasums") ? "downloading_checksums" : "downloading_asset";
6200
+ }
6201
+ function createDesktopProgressFactory() {
6202
+ return (label) => {
6203
+ const phase = desktopDownloadPhase(label);
6204
+ let latestReceivedBytes = 0;
6205
+ let latestTotalBytes = null;
6206
+ function emitByteProgress(message, receivedBytes, totalBytes) {
6207
+ const total = normalizeProgressTotal(totalBytes);
6208
+ writeDesktopProgress({
6209
+ phase,
6210
+ message,
6211
+ transferredBytes: Math.max(0, receivedBytes),
6212
+ ...total === null ? {} : {
6213
+ totalBytes: total,
6214
+ percent: Math.max(0, Math.min(100, Math.floor(Math.max(0, receivedBytes) / total * 100)))
6215
+ }
6216
+ });
6217
+ }
6218
+ return {
6219
+ start(totalBytes) {
6220
+ latestReceivedBytes = 0;
6221
+ latestTotalBytes = totalBytes;
6222
+ emitByteProgress(label, 0, totalBytes);
6223
+ },
6224
+ update(receivedBytes, totalBytes) {
6225
+ latestReceivedBytes = receivedBytes;
6226
+ latestTotalBytes = totalBytes;
6227
+ emitByteProgress(label, receivedBytes, totalBytes);
6228
+ },
6229
+ finish(receivedBytes = latestReceivedBytes, totalBytes = latestTotalBytes) {
6230
+ latestReceivedBytes = receivedBytes;
6231
+ latestTotalBytes = totalBytes;
6232
+ emitByteProgress(`${label} complete`, receivedBytes, totalBytes);
6233
+ },
6234
+ fail() {
6235
+ writeDesktopProgress({
6236
+ phase,
6237
+ message: `${label} failed`,
6238
+ transferredBytes: Math.max(0, latestReceivedBytes),
6239
+ error: `${label} failed`
6240
+ });
6241
+ }
6242
+ };
6243
+ };
6244
+ }
6181
6245
  function resolveCurrentCliVersion(env = process.env) {
6182
6246
  const version = resolveCliVersion(import.meta.url, env);
6183
6247
  return version === "0.0.0" ? "latest" : version;
@@ -6480,9 +6544,25 @@ function runChecked(command, args, options = {}) {
6480
6544
  const output = [result.stdout, result.stderr].filter((value) => typeof value === "string" && value.trim().length > 0).join("\n").trim();
6481
6545
  throw new Error(`${command} ${args.join(" ")} failed${output ? `: ${output}` : ""}`);
6482
6546
  }
6547
+ function formatCommandFailure(command, args, stdout, stderr) {
6548
+ const output = [stdout, stderr].filter((value) => typeof value === "string" && value.trim().length > 0).join("\n").trim();
6549
+ return `${command} ${args.join(" ")} failed${output ? `: ${output}` : ""}`;
6550
+ }
6483
6551
  function powershellQuote(value) {
6484
6552
  return `'${value.replaceAll("'", "''")}'`;
6485
6553
  }
6554
+ function buildWindowsZipExtractCommand(zipPath, outputDir) {
6555
+ return { command: "tar.exe", args: ["-xf", zipPath, "-C", outputDir] };
6556
+ }
6557
+ function buildWindowsRobocopyMirrorCommand(sourcePath, destinationPath) {
6558
+ return {
6559
+ command: "robocopy.exe",
6560
+ args: [sourcePath, destinationPath, "/MIR", "/R:2", "/W:1", "/NFL", "/NDL", "/NJH", "/NJS", "/NP"]
6561
+ };
6562
+ }
6563
+ function isSuccessfulRobocopyExitCode(status) {
6564
+ return typeof status === "number" && status >= 0 && status <= 7;
6565
+ }
6486
6566
  async function extractZip(zipPath, outputDir, target) {
6487
6567
  await rm(outputDir, { recursive: true, force: true });
6488
6568
  await mkdir2(outputDir, { recursive: true });
@@ -6491,13 +6571,8 @@ async function extractZip(zipPath, outputDir, target) {
6491
6571
  return;
6492
6572
  }
6493
6573
  if (target.platform === "windows") {
6494
- runChecked("powershell.exe", [
6495
- "-NoProfile",
6496
- "-ExecutionPolicy",
6497
- "Bypass",
6498
- "-Command",
6499
- `Expand-Archive -LiteralPath ${powershellQuote(zipPath)} -DestinationPath ${powershellQuote(outputDir)} -Force`
6500
- ]);
6574
+ const command = buildWindowsZipExtractCommand(zipPath, outputDir);
6575
+ runChecked(command.command, command.args);
6501
6576
  return;
6502
6577
  }
6503
6578
  throw new Error(`Zip assets are not supported for ${target.platform}.`);
@@ -6643,6 +6718,16 @@ async function installPortableDesktop(installerPath, paths, target) {
6643
6718
  }
6644
6719
  }
6645
6720
  async function copyPortableAppBundle(sourcePath, destinationPath) {
6721
+ if (process.platform === "win32") {
6722
+ await mkdir2(destinationPath, { recursive: true });
6723
+ const command = buildWindowsRobocopyMirrorCommand(sourcePath, destinationPath);
6724
+ const result = spawnSync3(command.command, command.args, {
6725
+ encoding: "utf8",
6726
+ stdio: ["ignore", "pipe", "pipe"]
6727
+ });
6728
+ if (isSuccessfulRobocopyExitCode(result.status)) return;
6729
+ throw new Error(formatCommandFailure(command.command, command.args, result.stdout, result.stderr));
6730
+ }
6646
6731
  await cp(sourcePath, destinationPath, { recursive: true, verbatimSymlinks: true });
6647
6732
  }
6648
6733
  async function removeMacQuarantine(paths, target) {
@@ -6730,15 +6815,28 @@ async function writeInstallMetadata(paths, releaseTag, assetName, assetChecksum)
6730
6815
  await writeFile2(paths.metadataPath, `${JSON.stringify(metadata, null, 2)}
6731
6816
  `, "utf8");
6732
6817
  }
6733
- async function runStartPhase(message, successMessage, task) {
6818
+ async function runStartPhase(message, successMessage, task, progressPhase) {
6819
+ if (progressPhase) {
6820
+ writeDesktopProgress({ phase: progressPhase, message });
6821
+ }
6734
6822
  const spinner3 = p13.spinner();
6735
6823
  spinner3.start(message);
6736
6824
  try {
6737
6825
  const result = await task();
6738
6826
  spinner3.stop(successMessage);
6827
+ if (progressPhase) {
6828
+ writeDesktopProgress({ phase: progressPhase, message: successMessage });
6829
+ }
6739
6830
  return result;
6740
6831
  } catch (error) {
6741
6832
  spinner3.stop(pc8.red(`${message} failed.`));
6833
+ if (progressPhase) {
6834
+ writeDesktopProgress({
6835
+ phase: "failed",
6836
+ message: `${message} failed.`,
6837
+ error: error instanceof Error ? error.message : String(error)
6838
+ });
6839
+ }
6742
6840
  throw error;
6743
6841
  }
6744
6842
  }
@@ -6749,6 +6847,12 @@ async function startCommand(opts) {
6749
6847
  const repo = opts.repo?.trim() || DEFAULT_DESKTOP_RELEASE_REPO;
6750
6848
  const version = opts.targetVersion?.trim() || opts.version?.trim() || resolveCurrentCliVersion();
6751
6849
  const dryRun = opts.dryRun === true;
6850
+ const desktopProgressJson = opts.desktopProgressJson === true;
6851
+ if (desktopProgressJson) {
6852
+ process.stdout.on("error", (error) => {
6853
+ if (error.code !== "EPIPE") throw error;
6854
+ });
6855
+ }
6752
6856
  if (!installCli && !installDesktop && !installRuntime) {
6753
6857
  throw new Error("Nothing to start. Remove --no-cli, --no-runtime, or --no-desktop.");
6754
6858
  }
@@ -6822,13 +6926,14 @@ async function startCommand(opts) {
6822
6926
  return;
6823
6927
  }
6824
6928
  const directReleaseVersion = resolveDesktopReleaseVersion(tag);
6825
- const progressFactory = createByteProgress;
6929
+ const progressFactory = desktopProgressJson ? createDesktopProgressFactory() : createByteProgress;
6826
6930
  let release = null;
6827
6931
  try {
6828
6932
  release = await runStartPhase(
6829
6933
  "Resolving Desktop release...",
6830
6934
  "Desktop release resolved.",
6831
- () => fetchGithubRelease(repo, tag)
6935
+ () => fetchGithubRelease(repo, tag),
6936
+ desktopProgressJson ? "resolving_release" : null
6832
6937
  );
6833
6938
  } catch (error) {
6834
6939
  if (!directReleaseVersion) throw error;
@@ -6856,24 +6961,28 @@ async function startCommand(opts) {
6856
6961
  async () => {
6857
6962
  await removeMacQuarantine(installPaths, target);
6858
6963
  await createPlatformLaunchers(installPaths, target);
6859
- }
6964
+ },
6965
+ desktopProgressJson ? "preparing_restart" : null
6860
6966
  );
6861
6967
  } else {
6862
6968
  const installerPath = await downloadAsset(asset, outputDir, progressFactory);
6863
6969
  const checksum = await runStartPhase(
6864
6970
  "Verifying Desktop checksum...",
6865
6971
  `Verified ${pc8.cyan(path11.basename(installerPath))}.`,
6866
- () => assertChecksumMatch(installerPath, expectedChecksum)
6972
+ () => assertChecksumMatch(installerPath, expectedChecksum),
6973
+ desktopProgressJson ? "verifying_checksum" : null
6867
6974
  );
6868
6975
  await runStartPhase(
6869
6976
  "Replacing existing Rudder Desktop if needed...",
6870
6977
  "Existing Desktop install is ready for replacement.",
6871
- () => prepareForDesktopReplace(installPaths, target, { waitForActiveRuns: opts.waitForActiveRuns === true })
6978
+ () => prepareForDesktopReplace(installPaths, target, { waitForActiveRuns: opts.waitForActiveRuns === true }),
6979
+ desktopProgressJson ? opts.waitForActiveRuns === true ? "waiting_for_active_runs" : "preparing_restart" : null
6872
6980
  );
6873
6981
  await runStartPhase(
6874
6982
  "Installing portable Desktop app...",
6875
6983
  `Installed Rudder Desktop to ${pc8.cyan(installPaths.appPath)}.`,
6876
- () => installPortableDesktop(installerPath, installPaths, target)
6984
+ () => installPortableDesktop(installerPath, installPaths, target),
6985
+ desktopProgressJson ? "preparing_restart" : null
6877
6986
  );
6878
6987
  await runStartPhase(
6879
6988
  "Preparing Desktop launchers...",
@@ -6881,7 +6990,8 @@ async function startCommand(opts) {
6881
6990
  async () => {
6882
6991
  await removeMacQuarantine(installPaths, target);
6883
6992
  await createPlatformLaunchers(installPaths, target);
6884
- }
6993
+ },
6994
+ desktopProgressJson ? "preparing_restart" : null
6885
6995
  );
6886
6996
  await writeInstallMetadata(installPaths, releaseTag, asset.name, checksum);
6887
6997
  }
@@ -6889,7 +6999,8 @@ async function startCommand(opts) {
6889
6999
  await runStartPhase(
6890
7000
  "Launching Rudder Desktop...",
6891
7001
  "Rudder Desktop launched.",
6892
- () => launchDesktop(installPaths, target)
7002
+ () => launchDesktop(installPaths, target),
7003
+ desktopProgressJson ? "closing" : null
6893
7004
  );
6894
7005
  }
6895
7006
  }
@@ -11444,7 +11555,7 @@ function createProgram() {
11444
11555
  });
11445
11556
  loadRudderEnvFile(options.config);
11446
11557
  });
11447
- program.command("start").description("Start Rudder Desktop and prepare the matching persistent CLI").option("--no-cli", "Skip persistent CLI installation").option("--no-runtime", "Skip Rudder runtime installation").option("--no-desktop", "Skip desktop app installation").option("--version <version>", "Rudder version to start (default: current CLI version)").option("--target-version <version>", "Rudder version to start; avoids the root CLI version flag").option("--repo <owner/repo>", "GitHub repository that hosts desktop releases").option("--output-dir <path>", "Directory for downloaded desktop release assets").option("--desktop-install-dir <path>", "Directory for the portable Desktop install").option("--no-open", "Install Desktop without launching it").option("--wait-for-active-runs", "Wait for active Rudder runs to finish before replacing Desktop", false).option("--no-version-check", "Skip checking npm for a newer Rudder CLI version").option("--dry-run", "Print the start actions without changing the machine", false).action(startCommand);
11558
+ program.command("start").description("Start Rudder Desktop and prepare the matching persistent CLI").option("--no-cli", "Skip persistent CLI installation").option("--no-runtime", "Skip Rudder runtime installation").option("--no-desktop", "Skip desktop app installation").option("--version <version>", "Rudder version to start (default: current CLI version)").option("--target-version <version>", "Rudder version to start; avoids the root CLI version flag").option("--repo <owner/repo>", "GitHub repository that hosts desktop releases").option("--output-dir <path>", "Directory for downloaded desktop release assets").option("--desktop-install-dir <path>", "Directory for the portable Desktop install").option("--no-open", "Install Desktop without launching it").option("--wait-for-active-runs", "Wait for active Rudder runs to finish before replacing Desktop", false).option("--desktop-progress-json", "Emit newline-delimited Desktop update progress events").option("--no-version-check", "Skip checking npm for a newer Rudder CLI version").option("--dry-run", "Print the start actions without changing the machine", false).action(startCommand);
11448
11559
  program.command("onboard").description("Interactive first-run setup wizard").option("-c, --config <path>", "Path to config file").option("-d, --data-dir <path>", DATA_DIR_OPTION_HELP).option("-y, --yes", "Accept defaults (quickstart + start immediately)", false).option("--run", "Start Rudder immediately after saving config", false).action(onboard);
11449
11560
  program.command("doctor").description("Run diagnostic checks on your Rudder setup").option("-c, --config <path>", "Path to config file").option("-d, --data-dir <path>", DATA_DIR_OPTION_HELP).option("--repair", "Attempt to repair issues automatically").alias("--fix").option("-y, --yes", "Skip repair confirmation prompts").action(async (opts) => {
11450
11561
  await doctor(opts);