@rudderhq/cli 0.3.5-canary.16 → 0.3.5-canary.17
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 +203 -135
- package/dist/index.js.map +3 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -13055,7 +13055,7 @@ init_install2();
|
|
|
13055
13055
|
init_install();
|
|
13056
13056
|
import * as p15 from "@clack/prompts";
|
|
13057
13057
|
import { spawn as spawn2, spawnSync as spawnSync3 } from "node:child_process";
|
|
13058
|
-
import { createHash } from "node:crypto";
|
|
13058
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
13059
13059
|
import { createWriteStream, constants as fsConstants, mkdirSync, readFileSync as readFileSync2 } from "node:fs";
|
|
13060
13060
|
import { access, chmod, copyFile, cp, mkdir as mkdir3, mkdtemp, readdir as readdir3, readFile as readFile6, rm as rm2, stat as stat4, utimes, writeFile as writeFile3 } from "node:fs/promises";
|
|
13061
13061
|
import { homedir, tmpdir } from "node:os";
|
|
@@ -13191,6 +13191,8 @@ var DEFAULT_DESKTOP_ASSET_CACHE_MAX_ENTRIES = 2;
|
|
|
13191
13191
|
var DEFAULT_DESKTOP_ASSET_CACHE_MAX_AGE_MS = 14 * 24 * 60 * 60 * 1e3;
|
|
13192
13192
|
var DEFAULT_DESKTOP_ASSET_CACHE_MAX_BYTES = 768 * 1024 * 1024;
|
|
13193
13193
|
var DEFAULT_DESKTOP_ASSET_CACHE_KEEP_PREVIOUS = 1;
|
|
13194
|
+
var DESKTOP_INSTALL_LOCK_TIMEOUT_MS = 60 * 60 * 1e3;
|
|
13195
|
+
var DESKTOP_INSTALL_LOCK_POLL_MS = 250;
|
|
13194
13196
|
function normalizeProgressTotal(totalBytes) {
|
|
13195
13197
|
return typeof totalBytes === "number" && Number.isFinite(totalBytes) && totalBytes > 0 ? totalBytes : null;
|
|
13196
13198
|
}
|
|
@@ -13834,6 +13836,70 @@ async function pathExists2(targetPath) {
|
|
|
13834
13836
|
return false;
|
|
13835
13837
|
}
|
|
13836
13838
|
}
|
|
13839
|
+
function resolveDesktopInstallLockPath(paths) {
|
|
13840
|
+
const installRootHash = createHash("sha256").update(path21.resolve(paths.installRoot)).digest("hex").slice(0, 16);
|
|
13841
|
+
return path21.join(path21.dirname(paths.appPath), `.rudder-desktop-install-${installRootHash}.lock`);
|
|
13842
|
+
}
|
|
13843
|
+
async function readDesktopInstallLock(lockPath) {
|
|
13844
|
+
try {
|
|
13845
|
+
const parsed = JSON.parse(await readFile6(lockPath, "utf8"));
|
|
13846
|
+
if (typeof parsed.pid !== "number" || !Number.isInteger(parsed.pid) || parsed.pid <= 0 || typeof parsed.lockId !== "string" || typeof parsed.installRoot !== "string" || typeof parsed.createdAt !== "string") {
|
|
13847
|
+
return null;
|
|
13848
|
+
}
|
|
13849
|
+
return {
|
|
13850
|
+
lockId: parsed.lockId,
|
|
13851
|
+
pid: parsed.pid,
|
|
13852
|
+
installRoot: parsed.installRoot,
|
|
13853
|
+
createdAt: parsed.createdAt
|
|
13854
|
+
};
|
|
13855
|
+
} catch {
|
|
13856
|
+
return null;
|
|
13857
|
+
}
|
|
13858
|
+
}
|
|
13859
|
+
async function withDesktopInstallLock(paths, fn, options = {}) {
|
|
13860
|
+
const lockPath = resolveDesktopInstallLockPath(paths);
|
|
13861
|
+
const lockDir = path21.dirname(lockPath);
|
|
13862
|
+
const timeoutMs = options.timeoutMs ?? DESKTOP_INSTALL_LOCK_TIMEOUT_MS;
|
|
13863
|
+
const pollMs = options.pollMs ?? DESKTOP_INSTALL_LOCK_POLL_MS;
|
|
13864
|
+
const startedAt = Date.now();
|
|
13865
|
+
const payload = {
|
|
13866
|
+
lockId: randomUUID(),
|
|
13867
|
+
pid: process.pid,
|
|
13868
|
+
installRoot: path21.resolve(paths.installRoot),
|
|
13869
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
13870
|
+
};
|
|
13871
|
+
await mkdir3(lockDir, { recursive: true });
|
|
13872
|
+
while (true) {
|
|
13873
|
+
try {
|
|
13874
|
+
await writeFile3(lockPath, `${JSON.stringify(payload, null, 2)}
|
|
13875
|
+
`, { encoding: "utf8", flag: "wx" });
|
|
13876
|
+
break;
|
|
13877
|
+
} catch (error) {
|
|
13878
|
+
const err = error;
|
|
13879
|
+
if (err.code !== "EEXIST") throw error;
|
|
13880
|
+
const existing = await readDesktopInstallLock(lockPath);
|
|
13881
|
+
const stale = !existing || !processExists(existing.pid);
|
|
13882
|
+
if (stale) {
|
|
13883
|
+
await rm2(lockPath, { force: true });
|
|
13884
|
+
continue;
|
|
13885
|
+
}
|
|
13886
|
+
if (Date.now() - startedAt >= timeoutMs) {
|
|
13887
|
+
throw new Error(
|
|
13888
|
+
`Timed out waiting for Rudder Desktop install lock for ${paths.appPath}. Held by pid ${existing.pid} for ${existing.installRoot}.`
|
|
13889
|
+
);
|
|
13890
|
+
}
|
|
13891
|
+
await delay2(pollMs);
|
|
13892
|
+
}
|
|
13893
|
+
}
|
|
13894
|
+
try {
|
|
13895
|
+
return await fn();
|
|
13896
|
+
} finally {
|
|
13897
|
+
const existing = await readDesktopInstallLock(lockPath);
|
|
13898
|
+
if (existing?.lockId === payload.lockId) {
|
|
13899
|
+
await rm2(lockPath, { force: true });
|
|
13900
|
+
}
|
|
13901
|
+
}
|
|
13902
|
+
}
|
|
13837
13903
|
function runChecked(command, args, options = {}) {
|
|
13838
13904
|
const result = spawnSync3(command, args, {
|
|
13839
13905
|
encoding: "utf8",
|
|
@@ -14286,152 +14352,154 @@ async function startCommand(opts) {
|
|
|
14286
14352
|
p15.outro(pc15.green("Dry run complete."));
|
|
14287
14353
|
return;
|
|
14288
14354
|
}
|
|
14289
|
-
|
|
14290
|
-
|
|
14291
|
-
|
|
14292
|
-
|
|
14293
|
-
release = await runStartPhase(
|
|
14294
|
-
"Resolving Desktop release...",
|
|
14295
|
-
"Desktop release resolved.",
|
|
14296
|
-
() => fetchGithubRelease(repo, tag),
|
|
14297
|
-
desktopProgressJson ? "resolving_release" : null
|
|
14298
|
-
);
|
|
14299
|
-
} catch (error) {
|
|
14300
|
-
if (!directReleaseVersion) throw error;
|
|
14301
|
-
p15.log.warn(
|
|
14302
|
-
`Desktop release metadata could not be resolved; falling back to deterministic download URLs. ${formatFetchError(error)}`
|
|
14303
|
-
);
|
|
14304
|
-
}
|
|
14305
|
-
const releaseTag = release?.tag_name ?? (directReleaseVersion ? tag : null);
|
|
14306
|
-
if (!releaseTag) {
|
|
14307
|
-
throw new Error(`Unable to resolve Rudder Desktop release tag for ${repo}@${tag}.`);
|
|
14308
|
-
}
|
|
14309
|
-
const assetCandidates = resolveDesktopAssetCandidates({
|
|
14310
|
-
releaseAssets: release?.assets ?? [],
|
|
14311
|
-
target,
|
|
14312
|
-
repo,
|
|
14313
|
-
tag,
|
|
14314
|
-
directReleaseVersion,
|
|
14315
|
-
allowShellAssets: runtimeSupportsShellAssets
|
|
14316
|
-
});
|
|
14317
|
-
if (assetCandidates.length === 0) {
|
|
14318
|
-
throw new Error(`No Rudder Desktop portable asset found for ${target.platform}/${target.arch} in ${repo}@${releaseTag}.`);
|
|
14319
|
-
}
|
|
14320
|
-
const checksumAsset = selectChecksumAsset(release?.assets ?? []) ?? (directReleaseVersion ? buildGithubReleaseAsset(repo, tag, DESKTOP_CHECKSUM_ASSET_NAME) : null);
|
|
14321
|
-
const checksums = await downloadChecksums(checksumAsset, outputDir, progressFactory);
|
|
14322
|
-
let selectedCandidate;
|
|
14323
|
-
try {
|
|
14324
|
-
selectedCandidate = selectChecksummedDesktopAssetCandidate(assetCandidates, checksums);
|
|
14325
|
-
} catch (error) {
|
|
14326
|
-
throw new Error(`No checksummed Rudder Desktop asset found for ${target.platform}/${target.arch} in ${repo}@${releaseTag}.`);
|
|
14327
|
-
}
|
|
14328
|
-
for (const warning of selectedCandidate.warnings) p15.log.warn(warning);
|
|
14329
|
-
let selectedAsset = selectedCandidate.asset;
|
|
14330
|
-
let selectedAssetKind = selectedCandidate.kind;
|
|
14331
|
-
let expectedChecksum = selectedCandidate.expectedChecksum;
|
|
14332
|
-
const metadata = await readInstallMetadata(installPaths.metadataPath);
|
|
14333
|
-
if (isInstalledDesktopCurrent(metadata, releaseTag, selectedAsset.name, expectedChecksum) && await pathExists2(installPaths.executablePath)) {
|
|
14334
|
-
p15.log.success(`Rudder Desktop is already installed at ${pc15.cyan(installPaths.appPath)}.`);
|
|
14335
|
-
await runStartPhase(
|
|
14336
|
-
"Refreshing Desktop launchers...",
|
|
14337
|
-
"Desktop launchers ready.",
|
|
14338
|
-
async () => {
|
|
14339
|
-
await removeMacQuarantine(installPaths, target);
|
|
14340
|
-
await createPlatformLaunchers(installPaths, target);
|
|
14341
|
-
},
|
|
14342
|
-
desktopProgressJson ? "preparing_restart" : null
|
|
14343
|
-
);
|
|
14344
|
-
} else {
|
|
14345
|
-
let cachedAsset;
|
|
14355
|
+
await withDesktopInstallLock(installPaths, async () => {
|
|
14356
|
+
const directReleaseVersion = resolveDesktopReleaseVersion(tag);
|
|
14357
|
+
const progressFactory = desktopProgressJson ? createDesktopProgressFactory() : createByteProgress;
|
|
14358
|
+
let release = null;
|
|
14346
14359
|
try {
|
|
14347
|
-
|
|
14348
|
-
|
|
14349
|
-
|
|
14350
|
-
|
|
14360
|
+
release = await runStartPhase(
|
|
14361
|
+
"Resolving Desktop release...",
|
|
14362
|
+
"Desktop release resolved.",
|
|
14363
|
+
() => fetchGithubRelease(repo, tag),
|
|
14364
|
+
desktopProgressJson ? "resolving_release" : null
|
|
14365
|
+
);
|
|
14351
14366
|
} catch (error) {
|
|
14352
|
-
|
|
14353
|
-
if (selectedAssetKind !== "shell" || !fullCandidate) throw error;
|
|
14367
|
+
if (!directReleaseVersion) throw error;
|
|
14354
14368
|
p15.log.warn(
|
|
14355
|
-
`
|
|
14369
|
+
`Desktop release metadata could not be resolved; falling back to deterministic download URLs. ${formatFetchError(error)}`
|
|
14356
14370
|
);
|
|
14357
|
-
selectedAsset = fullCandidate.asset;
|
|
14358
|
-
selectedAssetKind = fullCandidate.kind;
|
|
14359
|
-
expectedChecksum = resolveAssetChecksum(checksums, selectedAsset.name);
|
|
14360
|
-
cachedAsset = await downloadDesktopAssetWithCache(selectedAsset, expectedChecksum, {
|
|
14361
|
-
outputDir,
|
|
14362
|
-
progressFactory
|
|
14363
|
-
});
|
|
14364
14371
|
}
|
|
14365
|
-
|
|
14366
|
-
|
|
14367
|
-
|
|
14372
|
+
const releaseTag = release?.tag_name ?? (directReleaseVersion ? tag : null);
|
|
14373
|
+
if (!releaseTag) {
|
|
14374
|
+
throw new Error(`Unable to resolve Rudder Desktop release tag for ${repo}@${tag}.`);
|
|
14375
|
+
}
|
|
14376
|
+
const assetCandidates = resolveDesktopAssetCandidates({
|
|
14377
|
+
releaseAssets: release?.assets ?? [],
|
|
14378
|
+
target,
|
|
14379
|
+
repo,
|
|
14380
|
+
tag,
|
|
14381
|
+
directReleaseVersion,
|
|
14382
|
+
allowShellAssets: runtimeSupportsShellAssets
|
|
14383
|
+
});
|
|
14384
|
+
if (assetCandidates.length === 0) {
|
|
14385
|
+
throw new Error(`No Rudder Desktop portable asset found for ${target.platform}/${target.arch} in ${repo}@${releaseTag}.`);
|
|
14386
|
+
}
|
|
14387
|
+
const checksumAsset = selectChecksumAsset(release?.assets ?? []) ?? (directReleaseVersion ? buildGithubReleaseAsset(repo, tag, DESKTOP_CHECKSUM_ASSET_NAME) : null);
|
|
14388
|
+
const checksums = await downloadChecksums(checksumAsset, outputDir, progressFactory);
|
|
14389
|
+
let selectedCandidate;
|
|
14390
|
+
try {
|
|
14391
|
+
selectedCandidate = selectChecksummedDesktopAssetCandidate(assetCandidates, checksums);
|
|
14392
|
+
} catch (error) {
|
|
14393
|
+
throw new Error(`No checksummed Rudder Desktop asset found for ${target.platform}/${target.arch} in ${repo}@${releaseTag}.`);
|
|
14394
|
+
}
|
|
14395
|
+
for (const warning of selectedCandidate.warnings) p15.log.warn(warning);
|
|
14396
|
+
let selectedAsset = selectedCandidate.asset;
|
|
14397
|
+
let selectedAssetKind = selectedCandidate.kind;
|
|
14398
|
+
let expectedChecksum = selectedCandidate.expectedChecksum;
|
|
14399
|
+
const metadata = await readInstallMetadata(installPaths.metadataPath);
|
|
14400
|
+
if (isInstalledDesktopCurrent(metadata, releaseTag, selectedAsset.name, expectedChecksum) && await pathExists2(installPaths.executablePath)) {
|
|
14401
|
+
p15.log.success(`Rudder Desktop is already installed at ${pc15.cyan(installPaths.appPath)}.`);
|
|
14402
|
+
await runStartPhase(
|
|
14403
|
+
"Refreshing Desktop launchers...",
|
|
14404
|
+
"Desktop launchers ready.",
|
|
14405
|
+
async () => {
|
|
14406
|
+
await removeMacQuarantine(installPaths, target);
|
|
14407
|
+
await createPlatformLaunchers(installPaths, target);
|
|
14408
|
+
},
|
|
14409
|
+
desktopProgressJson ? "preparing_restart" : null
|
|
14410
|
+
);
|
|
14411
|
+
} else {
|
|
14412
|
+
let cachedAsset;
|
|
14413
|
+
try {
|
|
14414
|
+
cachedAsset = await downloadDesktopAssetWithCache(selectedAsset, expectedChecksum, {
|
|
14415
|
+
outputDir,
|
|
14416
|
+
progressFactory
|
|
14417
|
+
});
|
|
14418
|
+
} catch (error) {
|
|
14419
|
+
const fullCandidate = assetCandidates.find((candidate) => candidate.kind === "full");
|
|
14420
|
+
if (selectedAssetKind !== "shell" || !fullCandidate) throw error;
|
|
14421
|
+
p15.log.warn(
|
|
14422
|
+
`Layered Desktop shell asset download failed; falling back to the full portable asset. ${formatFetchError(error)}`
|
|
14423
|
+
);
|
|
14424
|
+
selectedAsset = fullCandidate.asset;
|
|
14425
|
+
selectedAssetKind = fullCandidate.kind;
|
|
14426
|
+
expectedChecksum = resolveAssetChecksum(checksums, selectedAsset.name);
|
|
14427
|
+
cachedAsset = await downloadDesktopAssetWithCache(selectedAsset, expectedChecksum, {
|
|
14428
|
+
outputDir,
|
|
14429
|
+
progressFactory
|
|
14430
|
+
});
|
|
14431
|
+
}
|
|
14432
|
+
if (cachedAsset.cacheStatus === "hit") {
|
|
14433
|
+
p15.log.success(`Desktop asset cache hit at ${pc15.cyan(cachedAsset.path)}.`);
|
|
14434
|
+
if (desktopProgressJson) {
|
|
14435
|
+
writeDesktopProgress({
|
|
14436
|
+
phase: "downloading_asset",
|
|
14437
|
+
message: `Desktop asset cache hit for ${selectedAsset.name}.`,
|
|
14438
|
+
percent: 100
|
|
14439
|
+
});
|
|
14440
|
+
}
|
|
14441
|
+
}
|
|
14442
|
+
const checksum = await runStartPhase(
|
|
14443
|
+
"Verifying Desktop checksum...",
|
|
14444
|
+
`Verified ${pc15.cyan(path21.basename(cachedAsset.path))}.`,
|
|
14445
|
+
() => assertChecksumMatch(cachedAsset.path, expectedChecksum),
|
|
14446
|
+
desktopProgressJson ? "verifying_checksum" : null
|
|
14447
|
+
);
|
|
14448
|
+
if (desktopProgressJson && opts.desktopWaitForApply === true) {
|
|
14368
14449
|
writeDesktopProgress({
|
|
14369
|
-
phase: "
|
|
14370
|
-
message:
|
|
14450
|
+
phase: "ready_to_install",
|
|
14451
|
+
message: "Desktop update is downloaded and verified.",
|
|
14371
14452
|
percent: 100
|
|
14372
14453
|
});
|
|
14454
|
+
await waitForDesktopApplySignal();
|
|
14455
|
+
writeDesktopProgress({
|
|
14456
|
+
phase: "preparing_restart",
|
|
14457
|
+
message: "Applying Desktop update..."
|
|
14458
|
+
});
|
|
14373
14459
|
}
|
|
14460
|
+
await runStartPhase(
|
|
14461
|
+
"Replacing existing Rudder Desktop if needed...",
|
|
14462
|
+
"Existing Desktop install is ready for replacement.",
|
|
14463
|
+
() => prepareForDesktopReplace(installPaths, target, { waitForActiveRuns: opts.waitForActiveRuns === true }),
|
|
14464
|
+
desktopProgressJson ? opts.waitForActiveRuns === true ? "waiting_for_active_runs" : "preparing_restart" : null
|
|
14465
|
+
);
|
|
14466
|
+
await runStartPhase(
|
|
14467
|
+
"Installing portable Desktop app...",
|
|
14468
|
+
`Installed Rudder Desktop to ${pc15.cyan(installPaths.appPath)}.`,
|
|
14469
|
+
() => installPortableDesktop(cachedAsset.path, installPaths, target),
|
|
14470
|
+
desktopProgressJson ? "preparing_restart" : null
|
|
14471
|
+
);
|
|
14472
|
+
await runStartPhase(
|
|
14473
|
+
"Preparing Desktop launchers...",
|
|
14474
|
+
"Desktop launchers ready.",
|
|
14475
|
+
async () => {
|
|
14476
|
+
await removeMacQuarantine(installPaths, target);
|
|
14477
|
+
await createPlatformLaunchers(installPaths, target);
|
|
14478
|
+
},
|
|
14479
|
+
desktopProgressJson ? "preparing_restart" : null
|
|
14480
|
+
);
|
|
14481
|
+
await writeInstallMetadata(installPaths, releaseTag, selectedAsset.name, checksum, selectedAssetKind);
|
|
14374
14482
|
}
|
|
14375
|
-
const
|
|
14376
|
-
|
|
14377
|
-
|
|
14378
|
-
|
|
14379
|
-
|
|
14380
|
-
|
|
14381
|
-
|
|
14382
|
-
|
|
14383
|
-
|
|
14384
|
-
|
|
14385
|
-
|
|
14386
|
-
|
|
14387
|
-
await
|
|
14388
|
-
|
|
14389
|
-
|
|
14390
|
-
|
|
14391
|
-
|
|
14392
|
-
}
|
|
14393
|
-
await runStartPhase(
|
|
14394
|
-
"Replacing existing Rudder Desktop if needed...",
|
|
14395
|
-
"Existing Desktop install is ready for replacement.",
|
|
14396
|
-
() => prepareForDesktopReplace(installPaths, target, { waitForActiveRuns: opts.waitForActiveRuns === true }),
|
|
14397
|
-
desktopProgressJson ? opts.waitForActiveRuns === true ? "waiting_for_active_runs" : "preparing_restart" : null
|
|
14398
|
-
);
|
|
14399
|
-
await runStartPhase(
|
|
14400
|
-
"Installing portable Desktop app...",
|
|
14401
|
-
`Installed Rudder Desktop to ${pc15.cyan(installPaths.appPath)}.`,
|
|
14402
|
-
() => installPortableDesktop(cachedAsset.path, installPaths, target),
|
|
14403
|
-
desktopProgressJson ? "preparing_restart" : null
|
|
14404
|
-
);
|
|
14405
|
-
await runStartPhase(
|
|
14406
|
-
"Preparing Desktop launchers...",
|
|
14407
|
-
"Desktop launchers ready.",
|
|
14408
|
-
async () => {
|
|
14409
|
-
await removeMacQuarantine(installPaths, target);
|
|
14410
|
-
await createPlatformLaunchers(installPaths, target);
|
|
14411
|
-
},
|
|
14412
|
-
desktopProgressJson ? "preparing_restart" : null
|
|
14413
|
-
);
|
|
14414
|
-
await writeInstallMetadata(installPaths, releaseTag, selectedAsset.name, checksum, selectedAssetKind);
|
|
14415
|
-
}
|
|
14416
|
-
const desktopAssetPrune = await maybePruneDesktopAssetCache({
|
|
14417
|
-
protectedChecksums: [expectedChecksum]
|
|
14418
|
-
});
|
|
14419
|
-
if (desktopAssetPrune) {
|
|
14420
|
-
if (desktopAssetPrune.deleted.length > 0) {
|
|
14421
|
-
p15.log.success(
|
|
14422
|
-
`Pruned ${desktopAssetPrune.deleted.length} old Desktop asset cache(s), freed ${formatBytes(desktopAssetPrune.freedBytes)}.`
|
|
14483
|
+
const desktopAssetPrune = await maybePruneDesktopAssetCache({
|
|
14484
|
+
protectedChecksums: [expectedChecksum]
|
|
14485
|
+
});
|
|
14486
|
+
if (desktopAssetPrune) {
|
|
14487
|
+
if (desktopAssetPrune.deleted.length > 0) {
|
|
14488
|
+
p15.log.success(
|
|
14489
|
+
`Pruned ${desktopAssetPrune.deleted.length} old Desktop asset cache(s), freed ${formatBytes(desktopAssetPrune.freedBytes)}.`
|
|
14490
|
+
);
|
|
14491
|
+
}
|
|
14492
|
+
for (const warning of desktopAssetPrune.warnings) p15.log.warn(warning);
|
|
14493
|
+
}
|
|
14494
|
+
if (opts.open !== false) {
|
|
14495
|
+
await runStartPhase(
|
|
14496
|
+
"Launching Rudder Desktop...",
|
|
14497
|
+
"Rudder Desktop launched.",
|
|
14498
|
+
() => launchDesktop(installPaths, target),
|
|
14499
|
+
desktopProgressJson ? "closing" : null
|
|
14423
14500
|
);
|
|
14424
14501
|
}
|
|
14425
|
-
|
|
14426
|
-
}
|
|
14427
|
-
if (opts.open !== false) {
|
|
14428
|
-
await runStartPhase(
|
|
14429
|
-
"Launching Rudder Desktop...",
|
|
14430
|
-
"Rudder Desktop launched.",
|
|
14431
|
-
() => launchDesktop(installPaths, target),
|
|
14432
|
-
desktopProgressJson ? "closing" : null
|
|
14433
|
-
);
|
|
14434
|
-
}
|
|
14502
|
+
});
|
|
14435
14503
|
}
|
|
14436
14504
|
p15.outro(pc15.green("Rudder start complete."));
|
|
14437
14505
|
}
|