@rudderhq/cli 0.7.12 → 0.7.14
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 +912 -481
- package/dist/index.js.map +4 -4
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -474,6 +474,15 @@ var init_rudder_mcp_tool_descriptors_generated = __esm({
|
|
|
474
474
|
"requiresAgentId": false,
|
|
475
475
|
"attachesRunIdWhenAvailable": true
|
|
476
476
|
},
|
|
477
|
+
{
|
|
478
|
+
"capabilityId": "issue.create",
|
|
479
|
+
"name": "rudder_issue_create",
|
|
480
|
+
"description": "Create a new issue or subtask with the generic issue surface; agent-created issues default to the creating agent when no assignee is supplied.",
|
|
481
|
+
"mutating": true,
|
|
482
|
+
"requiresOrgId": true,
|
|
483
|
+
"requiresAgentId": false,
|
|
484
|
+
"attachesRunIdWhenAvailable": true
|
|
485
|
+
},
|
|
477
486
|
{
|
|
478
487
|
"capabilityId": "approval.get",
|
|
479
488
|
"name": "rudder_approval_get",
|
|
@@ -1477,6 +1486,20 @@ function coreMcpInputSchema(id) {
|
|
|
1477
1486
|
riskSummary: string("Known risks, limitations, or remaining gaps."),
|
|
1478
1487
|
idempotencyKey: string("Stable key for safe retry.", { maxLength: 500 })
|
|
1479
1488
|
}, ["goal", "contractRevision", "criteria", "evidenceRefs", "riskSummary", "idempotencyKey"]);
|
|
1489
|
+
case "issue.create":
|
|
1490
|
+
return schema({
|
|
1491
|
+
title: string("Issue title.", { maxLength: 500 }),
|
|
1492
|
+
description: string("Issue description.", { maxLength: 5e5 }),
|
|
1493
|
+
status: string("Issue status.", { maxLength: 100 }),
|
|
1494
|
+
priority: string("Issue priority.", { maxLength: 100 }),
|
|
1495
|
+
assigneeAgentId: string("Assignee agent id or reference.", { maxLength: 200 }),
|
|
1496
|
+
projectId: string("Project id or reference.", { maxLength: 200 }),
|
|
1497
|
+
goalId: string("Goal id or reference.", { maxLength: 200 }),
|
|
1498
|
+
parentId: string("Parent issue id or reference.", { maxLength: 200 }),
|
|
1499
|
+
requestDepth: number("Requested issue depth.", 0, 1e4),
|
|
1500
|
+
billingCode: string("Billing code.", { maxLength: 200 }),
|
|
1501
|
+
labelIds: strings("Issue label ids.", 100)
|
|
1502
|
+
}, ["title"]);
|
|
1480
1503
|
case "issue.list":
|
|
1481
1504
|
return schema({
|
|
1482
1505
|
status: string("Comma-separated issue statuses.", { maxLength: 500 }),
|
|
@@ -2397,6 +2420,7 @@ var init_constants = __esm({
|
|
|
2397
2420
|
"rudder_library_file_ref",
|
|
2398
2421
|
"rudder_library_file_link",
|
|
2399
2422
|
"rudder_library_file_put",
|
|
2423
|
+
"rudder_issue_create",
|
|
2400
2424
|
"rudder_approval_get",
|
|
2401
2425
|
"rudder_approval_issues",
|
|
2402
2426
|
"rudder_approval_comment",
|
|
@@ -7440,6 +7464,7 @@ import { execFile } from "node:child_process";
|
|
|
7440
7464
|
import { existsSync as existsSync3 } from "node:fs";
|
|
7441
7465
|
import fs6 from "node:fs/promises";
|
|
7442
7466
|
import path8 from "node:path";
|
|
7467
|
+
import { performance } from "node:perf_hooks";
|
|
7443
7468
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
7444
7469
|
import { promisify } from "node:util";
|
|
7445
7470
|
function nativeTarget() {
|
|
@@ -7472,14 +7497,14 @@ function parseEnvelope(stdout, capability) {
|
|
|
7472
7497
|
}
|
|
7473
7498
|
return envelope;
|
|
7474
7499
|
}
|
|
7475
|
-
async function runNativePayload(capability, args, commandMayAccept) {
|
|
7500
|
+
async function runNativePayload(capability, args, commandMayAccept, timeoutMs = TIMEOUT_MS) {
|
|
7476
7501
|
let stdout = "";
|
|
7477
7502
|
let stderr = "";
|
|
7478
7503
|
try {
|
|
7479
7504
|
const command = resolveNativeCommand(resolveNativePayloadBinary(), args);
|
|
7480
7505
|
const result = await execFileAsync(command.command, command.args, {
|
|
7481
7506
|
encoding: "utf8",
|
|
7482
|
-
timeout: TIMEOUT_MS,
|
|
7507
|
+
timeout: Math.max(1, Math.min(TIMEOUT_MS, timeoutMs)),
|
|
7483
7508
|
maxBuffer: OUTPUT_LIMIT_BYTES,
|
|
7484
7509
|
windowsHide: true
|
|
7485
7510
|
});
|
|
@@ -7498,6 +7523,9 @@ async function runNativePayload(capability, args, commandMayAccept) {
|
|
|
7498
7523
|
envelope2
|
|
7499
7524
|
);
|
|
7500
7525
|
}
|
|
7526
|
+
if (detail.code === "ETIMEDOUT" || detail.killed === true || detail.signal === "SIGTERM") {
|
|
7527
|
+
throw new NativePayloadError("deadline_exceeded", commandMayAccept, detail.code ?? detail.signal);
|
|
7528
|
+
}
|
|
7501
7529
|
const failedBeforeSpawn = detail.code === "ENOENT" || detail.code === "EACCES";
|
|
7502
7530
|
throw new NativePayloadError("process_failed", commandMayAccept && !failedBeforeSpawn, stderr || detail.code);
|
|
7503
7531
|
}
|
|
@@ -7520,16 +7548,16 @@ function nativePayloadPolicy() {
|
|
|
7520
7548
|
legacyToggleEnvs: ["RUDDER_NATIVE_RUNTIME_PAYLOAD"]
|
|
7521
7549
|
});
|
|
7522
7550
|
}
|
|
7523
|
-
async function verifyNativePayload(archivePath, expectedSha256, maxArchiveBytes) {
|
|
7551
|
+
async function verifyNativePayload(archivePath, expectedSha256, maxArchiveBytes, timeoutMs) {
|
|
7524
7552
|
return runNativePayload("payload.verify", [
|
|
7525
7553
|
"payload",
|
|
7526
7554
|
"verify",
|
|
7527
7555
|
path8.resolve(archivePath),
|
|
7528
7556
|
expectedSha256,
|
|
7529
7557
|
String(maxArchiveBytes)
|
|
7530
|
-
], false);
|
|
7558
|
+
], false, timeoutMs);
|
|
7531
7559
|
}
|
|
7532
|
-
async function extractNativePayload(archivePath, stagingPath, maxArchiveBytes) {
|
|
7560
|
+
async function extractNativePayload(archivePath, stagingPath, maxArchiveBytes, timeoutMs) {
|
|
7533
7561
|
try {
|
|
7534
7562
|
return await runNativePayload("payload.extract", [
|
|
7535
7563
|
"payload",
|
|
@@ -7541,7 +7569,7 @@ async function extractNativePayload(archivePath, stagingPath, maxArchiveBytes) {
|
|
|
7541
7569
|
String(maxArchiveBytes),
|
|
7542
7570
|
String(maxArchiveBytes * 2),
|
|
7543
7571
|
"0"
|
|
7544
|
-
], true);
|
|
7572
|
+
], true, timeoutMs);
|
|
7545
7573
|
} catch (error) {
|
|
7546
7574
|
if (error instanceof NativePayloadError && error.code === "process_failed" && !existsSync3(stagingPath)) {
|
|
7547
7575
|
throw new NativePayloadError("process_failed", false, error.message);
|
|
@@ -7549,24 +7577,53 @@ async function extractNativePayload(archivePath, stagingPath, maxArchiveBytes) {
|
|
|
7549
7577
|
throw error;
|
|
7550
7578
|
}
|
|
7551
7579
|
}
|
|
7552
|
-
async function probeNativePayloadVersion(rootPath, executable) {
|
|
7580
|
+
async function probeNativePayloadVersion(rootPath, executable, timeoutMs) {
|
|
7553
7581
|
return runNativePayload("payload.probeVersion", [
|
|
7554
7582
|
"payload",
|
|
7555
7583
|
"probe-version",
|
|
7556
7584
|
path8.resolve(rootPath),
|
|
7557
7585
|
executable,
|
|
7558
7586
|
"PostgreSQL 18.4"
|
|
7559
|
-
], true);
|
|
7587
|
+
], true, timeoutMs);
|
|
7560
7588
|
}
|
|
7561
|
-
async function publishNativePayload(stagingPath, destinationPath) {
|
|
7589
|
+
async function publishNativePayload(stagingPath, destinationPath, timeoutMs) {
|
|
7562
7590
|
return runNativePayload("payload.publish", [
|
|
7563
7591
|
"payload",
|
|
7564
7592
|
"publish",
|
|
7565
7593
|
path8.resolve(stagingPath),
|
|
7566
7594
|
path8.resolve(destinationPath)
|
|
7567
|
-
], true);
|
|
7595
|
+
], true, timeoutMs);
|
|
7568
7596
|
}
|
|
7569
7597
|
async function tryInstallNativePayload(input) {
|
|
7598
|
+
const now = input.now ?? (() => performance.now());
|
|
7599
|
+
const expiresAt = input.timeoutMs === void 0 ? null : now() + input.timeoutMs;
|
|
7600
|
+
const remainingTimeout = (accepted) => {
|
|
7601
|
+
if (expiresAt === null) return void 0;
|
|
7602
|
+
const remaining = Math.ceil(expiresAt - now());
|
|
7603
|
+
if (remaining <= 0) throw new NativePayloadError("deadline_exceeded", accepted);
|
|
7604
|
+
return remaining;
|
|
7605
|
+
};
|
|
7606
|
+
const runCallbackWithinDeadline = async (accepted, callback) => {
|
|
7607
|
+
const controller = new AbortController();
|
|
7608
|
+
const timeoutMs = remainingTimeout(accepted);
|
|
7609
|
+
let timer;
|
|
7610
|
+
const timeoutPromise = timeoutMs === void 0 ? null : new Promise((_resolve, reject) => {
|
|
7611
|
+
timer = setTimeout(() => {
|
|
7612
|
+
controller.abort();
|
|
7613
|
+
reject(new NativePayloadError("deadline_exceeded", accepted));
|
|
7614
|
+
}, timeoutMs);
|
|
7615
|
+
});
|
|
7616
|
+
const context = {
|
|
7617
|
+
signal: controller.signal,
|
|
7618
|
+
remainingMs: () => remainingTimeout(accepted)
|
|
7619
|
+
};
|
|
7620
|
+
try {
|
|
7621
|
+
const operation = callback(context);
|
|
7622
|
+
return timeoutPromise ? await Promise.race([operation, timeoutPromise]) : await operation;
|
|
7623
|
+
} finally {
|
|
7624
|
+
if (timer) clearTimeout(timer);
|
|
7625
|
+
}
|
|
7626
|
+
};
|
|
7570
7627
|
const policy = nativePayloadPolicy();
|
|
7571
7628
|
if (!policy.enabled) return {
|
|
7572
7629
|
installed: false,
|
|
@@ -7589,9 +7646,9 @@ async function tryInstallNativePayload(input) {
|
|
|
7589
7646
|
}
|
|
7590
7647
|
try {
|
|
7591
7648
|
if (expectedSha256) {
|
|
7592
|
-
await verifyNativePayload(input.archivePath, expectedSha256, input.maxArchiveBytes);
|
|
7649
|
+
await verifyNativePayload(input.archivePath, expectedSha256, input.maxArchiveBytes, remainingTimeout(false));
|
|
7593
7650
|
}
|
|
7594
|
-
await extractNativePayload(input.archivePath, input.extractPath, input.maxArchiveBytes);
|
|
7651
|
+
await extractNativePayload(input.archivePath, input.extractPath, input.maxArchiveBytes, remainingTimeout(false));
|
|
7595
7652
|
} catch (error) {
|
|
7596
7653
|
const fallbackSafe = error instanceof NativePayloadError && error.fallbackSafe;
|
|
7597
7654
|
if (!policy.fallbackAllowed || !fallbackSafe) throw error;
|
|
@@ -7610,10 +7667,16 @@ async function tryInstallNativePayload(input) {
|
|
|
7610
7667
|
};
|
|
7611
7668
|
}
|
|
7612
7669
|
try {
|
|
7613
|
-
const versionExecutable = await
|
|
7614
|
-
|
|
7615
|
-
|
|
7616
|
-
|
|
7670
|
+
const versionExecutable = await runCallbackWithinDeadline(
|
|
7671
|
+
true,
|
|
7672
|
+
(context) => input.preparePublish(input.extractPath, input.publishStagingPath, context)
|
|
7673
|
+
);
|
|
7674
|
+
await probeNativePayloadVersion(input.publishStagingPath, versionExecutable, remainingTimeout(true));
|
|
7675
|
+
const published = await publishNativePayload(input.publishStagingPath, input.destinationPath, remainingTimeout(true));
|
|
7676
|
+
await runCallbackWithinDeadline(
|
|
7677
|
+
true,
|
|
7678
|
+
(context) => input.validatePublished(input.destinationPath, context)
|
|
7679
|
+
);
|
|
7617
7680
|
return {
|
|
7618
7681
|
installed: true,
|
|
7619
7682
|
fallbackCode: null,
|
|
@@ -7627,7 +7690,9 @@ async function tryInstallNativePayload(input) {
|
|
|
7627
7690
|
}
|
|
7628
7691
|
};
|
|
7629
7692
|
} finally {
|
|
7630
|
-
|
|
7693
|
+
const cleanup = input.cleanupPublishStaging ?? ((publishStagingPath) => fs6.rm(publishStagingPath, { recursive: true, force: true }));
|
|
7694
|
+
void cleanup(input.publishStagingPath).catch(() => {
|
|
7695
|
+
});
|
|
7631
7696
|
}
|
|
7632
7697
|
}
|
|
7633
7698
|
var execFileAsync, PROTOCOL_VERSION, OUTPUT_LIMIT_BYTES, TIMEOUT_MS, NativePayloadError;
|
|
@@ -7665,81 +7730,26 @@ var init_native_payload = __esm({
|
|
|
7665
7730
|
}
|
|
7666
7731
|
});
|
|
7667
7732
|
|
|
7668
|
-
// src/runtime/postgres-payload.ts
|
|
7669
|
-
import { cp, mkdir, stat } from "node:fs/promises";
|
|
7670
|
-
import path9 from "node:path";
|
|
7671
|
-
async function copyRuntimePostgresPayload(sourceRuntimeDir, targetRuntimeDir, sourceShareDir = path9.join(sourceRuntimeDir, "share")) {
|
|
7672
|
-
await mkdir(targetRuntimeDir, { recursive: true });
|
|
7673
|
-
for (const directoryName of ["bin", "lib"]) {
|
|
7674
|
-
const sourceDirectory = path9.join(sourceRuntimeDir, directoryName);
|
|
7675
|
-
if (!await stat(sourceDirectory).catch(() => null)) continue;
|
|
7676
|
-
await cp(
|
|
7677
|
-
sourceDirectory,
|
|
7678
|
-
path9.join(targetRuntimeDir, directoryName),
|
|
7679
|
-
{ recursive: true, dereference: true }
|
|
7680
|
-
);
|
|
7681
|
-
}
|
|
7682
|
-
await cp(
|
|
7683
|
-
sourceShareDir,
|
|
7684
|
-
path9.join(targetRuntimeDir, "share"),
|
|
7685
|
-
{ recursive: true, dereference: true }
|
|
7686
|
-
);
|
|
7687
|
-
}
|
|
7688
|
-
var init_postgres_payload = __esm({
|
|
7689
|
-
"src/runtime/postgres-payload.ts"() {
|
|
7690
|
-
"use strict";
|
|
7691
|
-
}
|
|
7692
|
-
});
|
|
7693
|
-
|
|
7694
7733
|
// src/runtime/postgres-runtime-download.ts
|
|
7695
7734
|
import { createHash as createHash2 } from "node:crypto";
|
|
7696
7735
|
import { createReadStream, createWriteStream } from "node:fs";
|
|
7697
|
-
import { copyFile, stat as stat2 } from "node:fs/promises";
|
|
7698
7736
|
import { Readable, Transform } from "node:stream";
|
|
7699
7737
|
import { pipeline } from "node:stream/promises";
|
|
7700
7738
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
7701
|
-
async function downloadRuntimePostgresArchive(url, targetPath, trustedSha256) {
|
|
7739
|
+
async function downloadRuntimePostgresArchive(url, targetPath, trustedSha256, options = {}) {
|
|
7702
7740
|
const expectedSha256 = (trustedSha256 ?? process.env[RUDDER_POSTGRES_RUNTIME_ARCHIVE_SHA256_ENV])?.trim().toLowerCase() || null;
|
|
7703
7741
|
if (expectedSha256 && !/^[a-f0-9]{64}$/.test(expectedSha256)) {
|
|
7704
7742
|
throw new Error(`${RUDDER_POSTGRES_RUNTIME_ARCHIVE_SHA256_ENV} must be a 64-character SHA-256 digest`);
|
|
7705
7743
|
}
|
|
7706
7744
|
const configuredMaxBytes = Number.parseInt(process.env[RUDDER_POSTGRES_RUNTIME_ARCHIVE_MAX_BYTES_ENV] ?? "", 10);
|
|
7707
7745
|
const maxBytes = Number.isSafeInteger(configuredMaxBytes) && configuredMaxBytes > 0 ? configuredMaxBytes : DEFAULT_RUNTIME_POSTGRES_ARCHIVE_MAX_BYTES;
|
|
7708
|
-
async function verifyFile(filePath) {
|
|
7709
|
-
if (!expectedSha256) return;
|
|
7710
|
-
const hash = createHash2("sha256");
|
|
7711
|
-
await new Promise((resolve, reject) => {
|
|
7712
|
-
const stream = createReadStream(filePath);
|
|
7713
|
-
stream.on("data", (chunk) => hash.update(chunk));
|
|
7714
|
-
stream.on("error", reject);
|
|
7715
|
-
stream.on("end", resolve);
|
|
7716
|
-
});
|
|
7717
|
-
const actual = hash.digest("hex");
|
|
7718
|
-
if (actual !== expectedSha256) throw new Error(`PostgreSQL runtime archive SHA-256 mismatch: expected ${expectedSha256}, got ${actual}`);
|
|
7719
|
-
}
|
|
7720
|
-
if (url.startsWith("file://")) {
|
|
7721
|
-
await copyFile(fileURLToPath4(url), targetPath);
|
|
7722
|
-
const archiveStat = await stat2(targetPath);
|
|
7723
|
-
if (archiveStat.size > maxBytes) throw new Error(`PostgreSQL runtime archive exceeds ${maxBytes} bytes`);
|
|
7724
|
-
await verifyFile(targetPath);
|
|
7725
|
-
return;
|
|
7726
|
-
}
|
|
7727
7746
|
const parsedTimeout = Number.parseInt(
|
|
7728
|
-
process.env[RUDDER_POSTGRES_RUNTIME_DOWNLOAD_TIMEOUT_MS_ENV] ?? "600000",
|
|
7747
|
+
String(options.timeoutMs ?? process.env[RUDDER_POSTGRES_RUNTIME_DOWNLOAD_TIMEOUT_MS_ENV] ?? "600000"),
|
|
7729
7748
|
10
|
|
7730
7749
|
);
|
|
7731
7750
|
const controller = new AbortController();
|
|
7732
7751
|
const timeout = Number.isFinite(parsedTimeout) && parsedTimeout > 0 ? setTimeout(() => controller.abort(), parsedTimeout) : null;
|
|
7733
7752
|
try {
|
|
7734
|
-
const response = await fetch(url, { signal: controller.signal });
|
|
7735
|
-
if (!response.ok) {
|
|
7736
|
-
throw new Error(`failed to download ${url}: ${response.status} ${response.statusText}`);
|
|
7737
|
-
}
|
|
7738
|
-
const contentLength = Number.parseInt(response.headers.get("content-length") ?? "", 10);
|
|
7739
|
-
if (Number.isSafeInteger(contentLength) && contentLength > maxBytes) {
|
|
7740
|
-
throw new Error(`PostgreSQL runtime archive exceeds ${maxBytes} bytes`);
|
|
7741
|
-
}
|
|
7742
|
-
if (!response.body) throw new Error("PostgreSQL runtime archive response has no body");
|
|
7743
7753
|
const hash = createHash2("sha256");
|
|
7744
7754
|
let bytes = 0;
|
|
7745
7755
|
const monitor = new Transform({
|
|
@@ -7753,15 +7763,39 @@ async function downloadRuntimePostgresArchive(url, targetPath, trustedSha256) {
|
|
|
7753
7763
|
callback(null, chunk);
|
|
7754
7764
|
}
|
|
7755
7765
|
});
|
|
7766
|
+
if (url.startsWith("file://")) {
|
|
7767
|
+
const readStream = (options.createReadStreamImpl ?? createReadStream)(fileURLToPath4(url));
|
|
7768
|
+
await pipeline(readStream, monitor, createWriteStream(targetPath), { signal: controller.signal });
|
|
7769
|
+
if (expectedSha256) {
|
|
7770
|
+
const actual = hash.digest("hex");
|
|
7771
|
+
if (actual !== expectedSha256) throw new Error(`PostgreSQL runtime archive SHA-256 mismatch: expected ${expectedSha256}, got ${actual}`);
|
|
7772
|
+
}
|
|
7773
|
+
return;
|
|
7774
|
+
}
|
|
7775
|
+
const response = await fetch(url, { signal: controller.signal });
|
|
7776
|
+
if (!response.ok) {
|
|
7777
|
+
throw new Error(`failed to download ${url}: ${response.status} ${response.statusText}`);
|
|
7778
|
+
}
|
|
7779
|
+
const contentLength = Number.parseInt(response.headers.get("content-length") ?? "", 10);
|
|
7780
|
+
if (Number.isSafeInteger(contentLength) && contentLength > maxBytes) {
|
|
7781
|
+
throw new Error(`PostgreSQL runtime archive exceeds ${maxBytes} bytes`);
|
|
7782
|
+
}
|
|
7783
|
+
if (!response.body) throw new Error("PostgreSQL runtime archive response has no body");
|
|
7756
7784
|
await pipeline(
|
|
7757
7785
|
Readable.fromWeb(response.body),
|
|
7758
7786
|
monitor,
|
|
7759
|
-
createWriteStream(targetPath, { flags: "wx" })
|
|
7787
|
+
createWriteStream(targetPath, { flags: "wx" }),
|
|
7788
|
+
{ signal: controller.signal }
|
|
7760
7789
|
);
|
|
7761
7790
|
if (expectedSha256) {
|
|
7762
7791
|
const actual = hash.digest("hex");
|
|
7763
7792
|
if (actual !== expectedSha256) throw new Error(`PostgreSQL runtime archive SHA-256 mismatch: expected ${expectedSha256}, got ${actual}`);
|
|
7764
7793
|
}
|
|
7794
|
+
} catch (error) {
|
|
7795
|
+
if (controller.signal.aborted) {
|
|
7796
|
+
throw new Error(`PostgreSQL runtime archive download timed out after ${parsedTimeout}ms`, { cause: error });
|
|
7797
|
+
}
|
|
7798
|
+
throw error;
|
|
7765
7799
|
} finally {
|
|
7766
7800
|
if (timeout) clearTimeout(timeout);
|
|
7767
7801
|
}
|
|
@@ -7816,10 +7850,45 @@ var init_postgres_runtime_source = __esm({
|
|
|
7816
7850
|
|
|
7817
7851
|
// src/runtime/install.ts
|
|
7818
7852
|
import { execFileSync, spawnSync as spawnSync2 } from "node:child_process";
|
|
7819
|
-
import {
|
|
7853
|
+
import { createReadStream as createReadStream2, createWriteStream as createWriteStream2 } from "node:fs";
|
|
7854
|
+
import { chmod, mkdir, mkdtemp, readFile, readdir, realpath, rename, rm, stat, symlink, writeFile } from "node:fs/promises";
|
|
7820
7855
|
import { createRequire } from "node:module";
|
|
7821
|
-
import
|
|
7856
|
+
import path9 from "node:path";
|
|
7857
|
+
import { performance as performance2 } from "node:perf_hooks";
|
|
7858
|
+
import { pipeline as pipeline2 } from "node:stream/promises";
|
|
7822
7859
|
import { pathToFileURL } from "node:url";
|
|
7860
|
+
function createRuntimeInstallDeadline(options) {
|
|
7861
|
+
if (options.timeoutMs === void 0) return void 0;
|
|
7862
|
+
if (!Number.isFinite(options.timeoutMs) || options.timeoutMs <= 0) {
|
|
7863
|
+
throw new Error("Runtime installation timeout must be a positive number of milliseconds.");
|
|
7864
|
+
}
|
|
7865
|
+
const now = options.now ?? (() => performance2.now());
|
|
7866
|
+
return { expiresAt: now() + options.timeoutMs, now };
|
|
7867
|
+
}
|
|
7868
|
+
function remainingRuntimeInstallMs(deadline, cacheDir, command) {
|
|
7869
|
+
if (!deadline) return void 0;
|
|
7870
|
+
const remaining = Math.ceil(deadline.expiresAt - deadline.now());
|
|
7871
|
+
if (remaining <= 0) {
|
|
7872
|
+
throw new RuntimeInstallError(
|
|
7873
|
+
`Timed out while preparing the Rudder runtime during ${command}`,
|
|
7874
|
+
{ cacheDir, command }
|
|
7875
|
+
);
|
|
7876
|
+
}
|
|
7877
|
+
return remaining;
|
|
7878
|
+
}
|
|
7879
|
+
function runtimeInstallDeadlineError(cacheDir, command) {
|
|
7880
|
+
return new RuntimeInstallError(
|
|
7881
|
+
`Timed out while preparing the Rudder runtime during ${command}`,
|
|
7882
|
+
{ cacheDir, command }
|
|
7883
|
+
);
|
|
7884
|
+
}
|
|
7885
|
+
function isRuntimeInstallDeadlineError(error) {
|
|
7886
|
+
return error instanceof RuntimeInstallError && error.message.startsWith("Timed out while preparing the Rudder runtime during ");
|
|
7887
|
+
}
|
|
7888
|
+
function isChildProcessTimeoutError(error) {
|
|
7889
|
+
const detail = error;
|
|
7890
|
+
return detail?.code === "ETIMEDOUT" || detail?.killed === true || detail?.signal === "SIGTERM";
|
|
7891
|
+
}
|
|
7823
7892
|
function sanitizeRuntimeCacheSegment(value) {
|
|
7824
7893
|
return encodeURIComponent(value.trim() || "latest").replaceAll("%", "_");
|
|
7825
7894
|
}
|
|
@@ -7828,7 +7897,7 @@ function resolveRuntimePackageVersion(version) {
|
|
|
7828
7897
|
return normalized.length > 0 ? normalized : "latest";
|
|
7829
7898
|
}
|
|
7830
7899
|
function resolveRuntimeCacheDir(version, homeDir = resolveRudderHomeDir()) {
|
|
7831
|
-
return
|
|
7900
|
+
return path9.join(homeDir, "runtimes", sanitizeRuntimeCacheSegment(resolveRuntimePackageVersion(version)));
|
|
7832
7901
|
}
|
|
7833
7902
|
function resolveRuntimePackageSpec(version, packageName = RUNTIME_NPM_PACKAGE_NAME) {
|
|
7834
7903
|
const packageVersion = resolveRuntimePackageVersion(version);
|
|
@@ -7836,7 +7905,7 @@ function resolveRuntimePackageSpec(version, packageName = RUNTIME_NPM_PACKAGE_NA
|
|
|
7836
7905
|
}
|
|
7837
7906
|
async function readRuntimeInstallMetadata(cacheDir) {
|
|
7838
7907
|
try {
|
|
7839
|
-
const raw = await readFile(
|
|
7908
|
+
const raw = await readFile(path9.join(cacheDir, RUNTIME_METADATA_FILE), "utf8");
|
|
7840
7909
|
const parsed = JSON.parse(raw);
|
|
7841
7910
|
if (parsed.version !== 1) return null;
|
|
7842
7911
|
if (typeof parsed.packageName !== "string" || typeof parsed.packageVersion !== "string") return null;
|
|
@@ -7851,7 +7920,7 @@ async function readRuntimeInstallMetadata(cacheDir) {
|
|
|
7851
7920
|
}
|
|
7852
7921
|
}
|
|
7853
7922
|
async function writeRuntimeInstallMetadata(cacheDir, metadata) {
|
|
7854
|
-
await writeFile(
|
|
7923
|
+
await writeFile(path9.join(cacheDir, RUNTIME_METADATA_FILE), `${JSON.stringify(metadata, null, 2)}
|
|
7855
7924
|
`, "utf8");
|
|
7856
7925
|
}
|
|
7857
7926
|
async function touchRuntimeInstallMetadata(cacheDir, postgresRuntime) {
|
|
@@ -7879,27 +7948,28 @@ function resolveEmbeddedPostgresPlatformPackage(platform = process.platform, arc
|
|
|
7879
7948
|
}
|
|
7880
7949
|
async function canResolveRuntimePackage(cacheDir, packageName) {
|
|
7881
7950
|
try {
|
|
7882
|
-
await readFile(
|
|
7951
|
+
await readFile(path9.join(cacheDir, "node_modules", ...packageName.split("/"), "package.json"), "utf8");
|
|
7883
7952
|
return true;
|
|
7884
7953
|
} catch {
|
|
7885
7954
|
return false;
|
|
7886
7955
|
}
|
|
7887
7956
|
}
|
|
7888
|
-
async function hasRequiredRuntimePlatformDependencies(cacheDir, metadata, postgresVersionProbe) {
|
|
7957
|
+
async function hasRequiredRuntimePlatformDependencies(cacheDir, metadata, postgresVersionProbe, deadline) {
|
|
7889
7958
|
if (!await canResolveRuntimePackage(cacheDir, EMBEDDED_POSTGRES_PACKAGE_NAME)) return true;
|
|
7890
7959
|
const platformPackage = resolveEmbeddedPostgresPlatformPackage();
|
|
7891
7960
|
if (!platformPackage) return true;
|
|
7892
7961
|
if (await canResolveRuntimePackage(cacheDir, platformPackage)) return true;
|
|
7893
7962
|
const expectedSharedBinDir = resolveSharedRuntimePostgresPayloadBinDir(
|
|
7894
|
-
|
|
7963
|
+
path9.dirname(path9.dirname(cacheDir))
|
|
7895
7964
|
);
|
|
7896
|
-
return metadata.postgresRuntime?.scope === "shared" && metadata.postgresRuntime.platform === process.platform && metadata.postgresRuntime.arch === process.arch &&
|
|
7965
|
+
return metadata.postgresRuntime?.scope === "shared" && metadata.postgresRuntime.platform === process.platform && metadata.postgresRuntime.arch === process.arch && path9.resolve(metadata.postgresRuntime.binDir) === path9.resolve(expectedSharedBinDir) && await isRuntimePostgresPayloadUsable(
|
|
7897
7966
|
cacheDir,
|
|
7898
7967
|
metadata.postgresRuntime.binDir,
|
|
7899
|
-
postgresVersionProbe
|
|
7968
|
+
postgresVersionProbe,
|
|
7969
|
+
deadline
|
|
7900
7970
|
);
|
|
7901
7971
|
}
|
|
7902
|
-
async function
|
|
7972
|
+
async function isRuntimeCacheHitWithinDeadline(options, deadline) {
|
|
7903
7973
|
const packageName = options.packageName ?? RUNTIME_NPM_PACKAGE_NAME;
|
|
7904
7974
|
const packageVersion = resolveRuntimePackageVersion(options.version);
|
|
7905
7975
|
const metadata = await readRuntimeInstallMetadata(options.cacheDir);
|
|
@@ -7907,15 +7977,17 @@ async function isRuntimeCacheHit(options) {
|
|
|
7907
7977
|
return false;
|
|
7908
7978
|
}
|
|
7909
7979
|
try {
|
|
7910
|
-
const packageJsonPath =
|
|
7980
|
+
const packageJsonPath = path9.join(options.cacheDir, "node_modules", ...packageName.split("/"), "package.json");
|
|
7911
7981
|
const packageJson = JSON.parse(await readFile(packageJsonPath, "utf8"));
|
|
7912
7982
|
const packageVersionMatches = packageVersion === "latest" || packageJson.version === packageVersion;
|
|
7913
7983
|
return packageVersionMatches && await hasRequiredRuntimePlatformDependencies(
|
|
7914
7984
|
options.cacheDir,
|
|
7915
7985
|
metadata,
|
|
7916
|
-
options.postgresVersionProbe ?? readPostgresVersion
|
|
7986
|
+
options.postgresVersionProbe ?? readPostgresVersion,
|
|
7987
|
+
deadline
|
|
7917
7988
|
);
|
|
7918
|
-
} catch {
|
|
7989
|
+
} catch (error) {
|
|
7990
|
+
if (isRuntimeInstallDeadlineError(error)) throw error;
|
|
7919
7991
|
return false;
|
|
7920
7992
|
}
|
|
7921
7993
|
}
|
|
@@ -7923,15 +7995,45 @@ async function ensureRuntimeInstalled(options) {
|
|
|
7923
7995
|
const packageVersion = resolveRuntimePackageVersion(options.version);
|
|
7924
7996
|
const homeDir = options.homeDir ?? resolveRudderHomeDir();
|
|
7925
7997
|
const cacheDir = resolveRuntimeCacheDir(packageVersion, homeDir);
|
|
7998
|
+
const deadline = createRuntimeInstallDeadline(options);
|
|
7926
7999
|
return withRuntimeFilesystemLock(
|
|
7927
|
-
|
|
8000
|
+
path9.join(homeDir, "runtime-payloads", ".postgres-runtime.lifecycle.lock"),
|
|
7928
8001
|
async () => withRuntimeFilesystemLock(
|
|
7929
8002
|
`${cacheDir}.install.lock`,
|
|
7930
|
-
async () =>
|
|
7931
|
-
|
|
8003
|
+
async () => {
|
|
8004
|
+
try {
|
|
8005
|
+
return await ensureRuntimeInstalledUnlocked(options, deadline);
|
|
8006
|
+
} catch (error) {
|
|
8007
|
+
if (options.cleanupIncompleteOnFailure === true) {
|
|
8008
|
+
scheduleIncompleteRuntimeCacheCleanup({
|
|
8009
|
+
cacheDir,
|
|
8010
|
+
packageVersion,
|
|
8011
|
+
remove: options.removeIncompleteCache
|
|
8012
|
+
});
|
|
8013
|
+
}
|
|
8014
|
+
throw error;
|
|
8015
|
+
}
|
|
8016
|
+
},
|
|
8017
|
+
{ deadline, cacheDir, command: "acquire target runtime install lock" }
|
|
8018
|
+
),
|
|
8019
|
+
{ deadline, cacheDir, command: "acquire PostgreSQL runtime lifecycle lock" }
|
|
7932
8020
|
);
|
|
7933
8021
|
}
|
|
7934
|
-
|
|
8022
|
+
function scheduleIncompleteRuntimeCacheCleanup(options) {
|
|
8023
|
+
const remove = options.remove ?? ((cacheDir) => rm(cacheDir, { recursive: true, force: true }));
|
|
8024
|
+
void withRuntimeFilesystemLock(
|
|
8025
|
+
`${options.cacheDir}.install.lock`,
|
|
8026
|
+
async () => {
|
|
8027
|
+
const metadata = await readRuntimeInstallMetadata(options.cacheDir);
|
|
8028
|
+
if (!metadata || metadata.packageVersion !== options.packageVersion) {
|
|
8029
|
+
await remove(options.cacheDir);
|
|
8030
|
+
}
|
|
8031
|
+
},
|
|
8032
|
+
{ cacheDir: options.cacheDir, command: "cleanup incomplete target runtime cache" }
|
|
8033
|
+
).catch(() => {
|
|
8034
|
+
});
|
|
8035
|
+
}
|
|
8036
|
+
async function ensureRuntimeInstalledUnlocked(options, deadline) {
|
|
7935
8037
|
const packageName = options.packageName ?? RUNTIME_NPM_PACKAGE_NAME;
|
|
7936
8038
|
const packageVersion = resolveRuntimePackageVersion(options.version);
|
|
7937
8039
|
const homeDir = options.homeDir ?? resolveRudderHomeDir();
|
|
@@ -7939,14 +8041,32 @@ async function ensureRuntimeInstalledUnlocked(options) {
|
|
|
7939
8041
|
const packageSpec = resolveRuntimePackageSpec(packageVersion, packageName);
|
|
7940
8042
|
const command = formatRuntimeInstallCommand(cacheDir, packageSpec);
|
|
7941
8043
|
const preparePostgresPayload = options.preparePostgresPayload === true;
|
|
7942
|
-
const postgresVersionProbe = options.postgresVersionProbe ??
|
|
7943
|
-
|
|
8044
|
+
const postgresVersionProbe = options.postgresVersionProbe ?? ((binaryPath) => {
|
|
8045
|
+
const probeCommand = `${binaryPath} --version`;
|
|
8046
|
+
try {
|
|
8047
|
+
return readPostgresVersion(
|
|
8048
|
+
binaryPath,
|
|
8049
|
+
remainingRuntimeInstallMs(deadline, cacheDir, probeCommand)
|
|
8050
|
+
);
|
|
8051
|
+
} catch (error) {
|
|
8052
|
+
if (isChildProcessTimeoutError(error)) {
|
|
8053
|
+
throw runtimeInstallDeadlineError(cacheDir, probeCommand);
|
|
8054
|
+
}
|
|
8055
|
+
throw error;
|
|
8056
|
+
}
|
|
8057
|
+
});
|
|
8058
|
+
if (await isRuntimeCacheHitWithinDeadline(
|
|
8059
|
+
{ cacheDir, version: packageVersion, packageName, postgresVersionProbe },
|
|
8060
|
+
deadline
|
|
8061
|
+
)) {
|
|
7944
8062
|
const postgresPayload2 = await stageRuntimePostgresPayload(
|
|
7945
8063
|
cacheDir,
|
|
7946
8064
|
homeDir,
|
|
7947
8065
|
packageVersion,
|
|
7948
8066
|
preparePostgresPayload,
|
|
7949
|
-
postgresVersionProbe
|
|
8067
|
+
postgresVersionProbe,
|
|
8068
|
+
deadline,
|
|
8069
|
+
options.cleanupPostgresDownloadWorkDir
|
|
7950
8070
|
);
|
|
7951
8071
|
await touchRuntimeInstallMetadata(cacheDir, postgresPayload2.metadata);
|
|
7952
8072
|
const prune2 = await maybePruneRuntimeCache({
|
|
@@ -7965,7 +8085,8 @@ async function ensureRuntimeInstalledUnlocked(options) {
|
|
|
7965
8085
|
spawnSyncImpl,
|
|
7966
8086
|
cacheDir,
|
|
7967
8087
|
packageName,
|
|
7968
|
-
packageVersion
|
|
8088
|
+
packageVersion,
|
|
8089
|
+
deadline
|
|
7969
8090
|
});
|
|
7970
8091
|
if (existingRuntimeOutput !== null) {
|
|
7971
8092
|
const postgresPayload2 = await stageRuntimePostgresPayload(
|
|
@@ -7973,7 +8094,9 @@ async function ensureRuntimeInstalledUnlocked(options) {
|
|
|
7973
8094
|
homeDir,
|
|
7974
8095
|
packageVersion,
|
|
7975
8096
|
preparePostgresPayload,
|
|
7976
|
-
postgresVersionProbe
|
|
8097
|
+
postgresVersionProbe,
|
|
8098
|
+
deadline,
|
|
8099
|
+
options.cleanupPostgresDownloadWorkDir
|
|
7977
8100
|
);
|
|
7978
8101
|
const metadata2 = {
|
|
7979
8102
|
version: 1,
|
|
@@ -7996,30 +8119,32 @@ async function ensureRuntimeInstalledUnlocked(options) {
|
|
|
7996
8119
|
);
|
|
7997
8120
|
}
|
|
7998
8121
|
await rm(cacheDir, { recursive: true, force: true });
|
|
7999
|
-
await
|
|
8000
|
-
await writeFile(
|
|
8122
|
+
await mkdir(cacheDir, { recursive: true });
|
|
8123
|
+
await writeFile(path9.join(cacheDir, "package.json"), `${JSON.stringify(RUNTIME_CACHE_PACKAGE_JSON, null, 2)}
|
|
8001
8124
|
`, "utf8");
|
|
8002
|
-
const result = runNpmRuntimeInstall(spawnSyncImpl, cacheDir, packageSpec);
|
|
8125
|
+
const result = runNpmRuntimeInstall(spawnSyncImpl, cacheDir, packageSpec, deadline);
|
|
8003
8126
|
let output = collectSpawnOutput(result);
|
|
8004
|
-
if (result.status !== 0 && packageVersion !== "latest" && isVersionNotFoundError(output)) {
|
|
8127
|
+
if (result.status !== 0 && packageVersion !== "latest" && options.allowLatestFallback !== false && isVersionNotFoundError(output)) {
|
|
8005
8128
|
const fallbackVersion = "latest";
|
|
8006
8129
|
const fallbackCacheDir = resolveRuntimeCacheDir(fallbackVersion, options.homeDir);
|
|
8007
8130
|
const fallbackSpec = resolveRuntimePackageSpec(fallbackVersion, packageName);
|
|
8008
8131
|
const fallbackInstallResult = await withRuntimeFilesystemLock(
|
|
8009
8132
|
`${fallbackCacheDir}.install.lock`,
|
|
8010
8133
|
async () => {
|
|
8011
|
-
if (await
|
|
8134
|
+
if (await isRuntimeCacheHitWithinDeadline({
|
|
8012
8135
|
cacheDir: fallbackCacheDir,
|
|
8013
8136
|
version: fallbackVersion,
|
|
8014
8137
|
packageName,
|
|
8015
8138
|
postgresVersionProbe
|
|
8016
|
-
})) {
|
|
8139
|
+
}, deadline)) {
|
|
8017
8140
|
const fallbackPostgresPayload = await stageRuntimePostgresPayload(
|
|
8018
8141
|
fallbackCacheDir,
|
|
8019
8142
|
homeDir,
|
|
8020
8143
|
fallbackVersion,
|
|
8021
8144
|
preparePostgresPayload,
|
|
8022
|
-
postgresVersionProbe
|
|
8145
|
+
postgresVersionProbe,
|
|
8146
|
+
deadline,
|
|
8147
|
+
options.cleanupPostgresDownloadWorkDir
|
|
8023
8148
|
);
|
|
8024
8149
|
await touchRuntimeInstallMetadata(fallbackCacheDir, fallbackPostgresPayload.metadata);
|
|
8025
8150
|
return withPostgresPayload(
|
|
@@ -8034,22 +8159,24 @@ async function ensureRuntimeInstalledUnlocked(options) {
|
|
|
8034
8159
|
);
|
|
8035
8160
|
}
|
|
8036
8161
|
await rm(fallbackCacheDir, { recursive: true, force: true });
|
|
8037
|
-
await
|
|
8038
|
-
await writeFile(
|
|
8162
|
+
await mkdir(fallbackCacheDir, { recursive: true });
|
|
8163
|
+
await writeFile(path9.join(fallbackCacheDir, "package.json"), `${JSON.stringify(RUNTIME_CACHE_PACKAGE_JSON, null, 2)}
|
|
8039
8164
|
`, "utf8");
|
|
8040
|
-
const fallbackResult = runNpmRuntimeInstall(spawnSyncImpl, fallbackCacheDir, fallbackSpec);
|
|
8165
|
+
const fallbackResult = runNpmRuntimeInstall(spawnSyncImpl, fallbackCacheDir, fallbackSpec, deadline);
|
|
8041
8166
|
let fallbackOutput = collectSpawnOutput(fallbackResult);
|
|
8042
8167
|
if (fallbackResult.status !== 0) return null;
|
|
8043
8168
|
fallbackOutput = collectOutputParts(
|
|
8044
8169
|
fallbackOutput,
|
|
8045
|
-
await ensureRequiredEmbeddedPostgresPlatformPackage(spawnSyncImpl, fallbackCacheDir)
|
|
8170
|
+
await ensureRequiredEmbeddedPostgresPlatformPackage(spawnSyncImpl, fallbackCacheDir, deadline)
|
|
8046
8171
|
);
|
|
8047
8172
|
const postgresPayload2 = await stageRuntimePostgresPayload(
|
|
8048
8173
|
fallbackCacheDir,
|
|
8049
8174
|
homeDir,
|
|
8050
8175
|
fallbackVersion,
|
|
8051
8176
|
preparePostgresPayload,
|
|
8052
|
-
postgresVersionProbe
|
|
8177
|
+
postgresVersionProbe,
|
|
8178
|
+
deadline,
|
|
8179
|
+
options.cleanupPostgresDownloadWorkDir
|
|
8053
8180
|
);
|
|
8054
8181
|
const fallbackMetadata = {
|
|
8055
8182
|
version: 1,
|
|
@@ -8070,7 +8197,8 @@ async function ensureRuntimeInstalledUnlocked(options) {
|
|
|
8070
8197
|
},
|
|
8071
8198
|
postgresPayload2
|
|
8072
8199
|
);
|
|
8073
|
-
}
|
|
8200
|
+
},
|
|
8201
|
+
{ deadline, cacheDir: fallbackCacheDir, command: "acquire fallback runtime install lock" }
|
|
8074
8202
|
);
|
|
8075
8203
|
if (fallbackInstallResult) return fallbackInstallResult;
|
|
8076
8204
|
}
|
|
@@ -8082,14 +8210,16 @@ async function ensureRuntimeInstalledUnlocked(options) {
|
|
|
8082
8210
|
}
|
|
8083
8211
|
output = collectOutputParts(
|
|
8084
8212
|
output,
|
|
8085
|
-
await ensureRequiredEmbeddedPostgresPlatformPackage(spawnSyncImpl, cacheDir)
|
|
8213
|
+
await ensureRequiredEmbeddedPostgresPlatformPackage(spawnSyncImpl, cacheDir, deadline)
|
|
8086
8214
|
);
|
|
8087
8215
|
const postgresPayload = await stageRuntimePostgresPayload(
|
|
8088
8216
|
cacheDir,
|
|
8089
8217
|
homeDir,
|
|
8090
8218
|
packageVersion,
|
|
8091
8219
|
preparePostgresPayload,
|
|
8092
|
-
postgresVersionProbe
|
|
8220
|
+
postgresVersionProbe,
|
|
8221
|
+
deadline,
|
|
8222
|
+
options.cleanupPostgresDownloadWorkDir
|
|
8093
8223
|
);
|
|
8094
8224
|
const metadata = {
|
|
8095
8225
|
version: 1,
|
|
@@ -8112,10 +8242,10 @@ async function ensureRuntimeInstalledUnlocked(options) {
|
|
|
8112
8242
|
);
|
|
8113
8243
|
}
|
|
8114
8244
|
function resolveRuntimePostgresPayloadBinDir(cacheDir, platform = process.platform, arch = process.arch) {
|
|
8115
|
-
return
|
|
8245
|
+
return path9.join(cacheDir, RUNTIME_POSTGRES_PAYLOAD_DIR, runtimePostgresPlatformSegment(platform, arch), "bin");
|
|
8116
8246
|
}
|
|
8117
8247
|
function resolveSharedRuntimePostgresPayloadBinDir(homeDir = resolveRudderHomeDir(), platform = process.platform, arch = process.arch) {
|
|
8118
|
-
return
|
|
8248
|
+
return path9.join(
|
|
8119
8249
|
homeDir,
|
|
8120
8250
|
"runtime-payloads",
|
|
8121
8251
|
RUNTIME_POSTGRES_PAYLOAD_DIR,
|
|
@@ -8124,19 +8254,21 @@ function resolveSharedRuntimePostgresPayloadBinDir(homeDir = resolveRudderHomeDi
|
|
|
8124
8254
|
);
|
|
8125
8255
|
}
|
|
8126
8256
|
function resolveRuntimeServerEntrypoint(cacheDir, packageName = RUNTIME_NPM_PACKAGE_NAME) {
|
|
8127
|
-
return createRequire(
|
|
8257
|
+
return createRequire(path9.join(cacheDir, "package.json")).resolve(packageName);
|
|
8128
8258
|
}
|
|
8129
8259
|
async function importRuntimeServerModule(cacheDir, packageName = RUNTIME_NPM_PACKAGE_NAME) {
|
|
8130
8260
|
const entrypoint = resolveRuntimeServerEntrypoint(cacheDir, packageName);
|
|
8131
8261
|
return await import(pathToFileURL(entrypoint).href);
|
|
8132
8262
|
}
|
|
8133
|
-
function runNpmRuntimeInstall(spawnSyncImpl, cacheDir, packageSpec) {
|
|
8263
|
+
function runNpmRuntimeInstall(spawnSyncImpl, cacheDir, packageSpec, deadline) {
|
|
8264
|
+
const timeout = remainingRuntimeInstallMs(deadline, cacheDir, `npm install ${packageSpec}`);
|
|
8134
8265
|
return spawnSyncImpl(
|
|
8135
8266
|
process.platform === "win32" ? "npm.cmd" : "npm",
|
|
8136
8267
|
["install", "--prefix", cacheDir, ...RUNTIME_NPM_INSTALL_FLAGS, packageSpec],
|
|
8137
8268
|
{
|
|
8138
8269
|
encoding: "utf8",
|
|
8139
8270
|
stdio: ["ignore", "pipe", "pipe"],
|
|
8271
|
+
...timeout === void 0 ? {} : { timeout },
|
|
8140
8272
|
...process.platform === "win32" ? { shell: true, windowsHide: true } : {}
|
|
8141
8273
|
}
|
|
8142
8274
|
);
|
|
@@ -8145,7 +8277,7 @@ function formatRuntimeInstallCommand(cacheDir, packageSpec) {
|
|
|
8145
8277
|
return `npm install --prefix ${cacheDir} ${RUNTIME_NPM_INSTALL_FLAGS.join(" ")} ${packageSpec}`;
|
|
8146
8278
|
}
|
|
8147
8279
|
function formatRuntimePlatformRepairCommand(cacheDir, packageSpec) {
|
|
8148
|
-
return `npm pack ${packageSpec} --registry=${NPM_PUBLIC_REGISTRY_URL} --silent, then extract it into ${
|
|
8280
|
+
return `npm pack ${packageSpec} --registry=${NPM_PUBLIC_REGISTRY_URL} --silent, then extract it into ${path9.join(cacheDir, "node_modules")}`;
|
|
8149
8281
|
}
|
|
8150
8282
|
function collectSpawnOutput(result) {
|
|
8151
8283
|
return [result.stdout, result.stderr, result.error instanceof Error ? result.error.message : null].filter((value) => typeof value === "string" && value.trim().length > 0).join("\n").trim();
|
|
@@ -8162,7 +8294,7 @@ function withPostgresPayload(result, postgresPayload) {
|
|
|
8162
8294
|
};
|
|
8163
8295
|
}
|
|
8164
8296
|
function runtimePackageJsonPath(cacheDir, packageName) {
|
|
8165
|
-
return
|
|
8297
|
+
return path9.join(cacheDir, "node_modules", ...packageName.split("/"), "package.json");
|
|
8166
8298
|
}
|
|
8167
8299
|
async function readRuntimePackageJson(cacheDir, packageName) {
|
|
8168
8300
|
try {
|
|
@@ -8175,7 +8307,11 @@ async function tryRepairExistingRuntimePackage(options) {
|
|
|
8175
8307
|
const runtimePackage = await readRuntimePackageJson(options.cacheDir, options.packageName);
|
|
8176
8308
|
if (!runtimePackage) return null;
|
|
8177
8309
|
if (options.packageVersion !== "latest" && runtimePackage.version !== options.packageVersion) return null;
|
|
8178
|
-
const output = await ensureRequiredEmbeddedPostgresPlatformPackage(
|
|
8310
|
+
const output = await ensureRequiredEmbeddedPostgresPlatformPackage(
|
|
8311
|
+
options.spawnSyncImpl,
|
|
8312
|
+
options.cacheDir,
|
|
8313
|
+
options.deadline
|
|
8314
|
+
);
|
|
8179
8315
|
if (!await canResolveRuntimePackage(options.cacheDir, EMBEDDED_POSTGRES_PACKAGE_NAME)) return output;
|
|
8180
8316
|
const platformPackage = resolveEmbeddedPostgresPlatformPackage();
|
|
8181
8317
|
return !platformPackage || await canResolveRuntimePackage(options.cacheDir, platformPackage) ? output : null;
|
|
@@ -8189,13 +8325,19 @@ async function resolveEmbeddedPostgresPlatformPackageSpec(cacheDir) {
|
|
|
8189
8325
|
const packageVersion = normalizeOptionalDependencyVersion(versionRange);
|
|
8190
8326
|
return packageVersion ? `${packageName}@${packageVersion}` : packageName;
|
|
8191
8327
|
}
|
|
8192
|
-
async function ensureRequiredEmbeddedPostgresPlatformPackage(spawnSyncImpl, cacheDir) {
|
|
8328
|
+
async function ensureRequiredEmbeddedPostgresPlatformPackage(spawnSyncImpl, cacheDir, deadline) {
|
|
8193
8329
|
const packageSpec = await resolveEmbeddedPostgresPlatformPackageSpec(cacheDir);
|
|
8194
8330
|
if (!packageSpec) return "";
|
|
8195
8331
|
const packageName = packageNameFromSpec(packageSpec);
|
|
8196
8332
|
if (packageName && await canResolveRuntimePackage(cacheDir, packageName)) return "";
|
|
8197
8333
|
await removeRuntimeInstallLocks(cacheDir);
|
|
8198
|
-
const result = await installRuntimePackageInStaging(
|
|
8334
|
+
const result = await installRuntimePackageInStaging(
|
|
8335
|
+
spawnSyncImpl,
|
|
8336
|
+
cacheDir,
|
|
8337
|
+
packageSpec,
|
|
8338
|
+
packageName,
|
|
8339
|
+
deadline
|
|
8340
|
+
);
|
|
8199
8341
|
const output = collectSpawnOutput(result);
|
|
8200
8342
|
if (result.status === 0 && packageName && await canResolveRuntimePackage(cacheDir, packageName)) {
|
|
8201
8343
|
return output;
|
|
@@ -8206,28 +8348,29 @@ async function ensureRequiredEmbeddedPostgresPlatformPackage(spawnSyncImpl, cach
|
|
|
8206
8348
|
{ cacheDir, command, output }
|
|
8207
8349
|
);
|
|
8208
8350
|
}
|
|
8209
|
-
async function installRuntimePackageInStaging(spawnSyncImpl, cacheDir, packageSpec, packageName) {
|
|
8210
|
-
const stagingDir =
|
|
8211
|
-
await
|
|
8351
|
+
async function installRuntimePackageInStaging(spawnSyncImpl, cacheDir, packageSpec, packageName, deadline) {
|
|
8352
|
+
const stagingDir = path9.join(cacheDir, `.platform-repair-${process.pid}-${Date.now()}`);
|
|
8353
|
+
await mkdir(stagingDir, { recursive: true });
|
|
8212
8354
|
try {
|
|
8213
|
-
const packResult = runNpmPack(spawnSyncImpl, packageSpec, stagingDir);
|
|
8355
|
+
const packResult = runNpmPack(spawnSyncImpl, packageSpec, stagingDir, cacheDir, deadline);
|
|
8214
8356
|
if (packResult.status !== 0) return packResult;
|
|
8215
8357
|
const packFilename = parseNpmPackFilename(packResult.stdout);
|
|
8216
8358
|
if (!packFilename) {
|
|
8217
8359
|
return createSyntheticSpawnResult(1, "", `Unable to parse npm pack output for ${packageSpec}.`);
|
|
8218
8360
|
}
|
|
8219
|
-
const archivePath =
|
|
8220
|
-
const targetDir =
|
|
8221
|
-
await
|
|
8361
|
+
const archivePath = path9.join(stagingDir, packFilename);
|
|
8362
|
+
const targetDir = path9.dirname(runtimePackageJsonPath(cacheDir, packageName));
|
|
8363
|
+
await mkdir(path9.dirname(targetDir), { recursive: true });
|
|
8222
8364
|
await rm(targetDir, { recursive: true, force: true });
|
|
8223
|
-
await
|
|
8224
|
-
const extractResult = runTarExtract(spawnSyncImpl, archivePath, targetDir);
|
|
8365
|
+
await mkdir(targetDir, { recursive: true });
|
|
8366
|
+
const extractResult = runTarExtract(spawnSyncImpl, archivePath, targetDir, cacheDir, deadline);
|
|
8225
8367
|
return combineSpawnResults(packResult, extractResult);
|
|
8226
8368
|
} finally {
|
|
8227
8369
|
await rm(stagingDir, { recursive: true, force: true });
|
|
8228
8370
|
}
|
|
8229
8371
|
}
|
|
8230
|
-
function runNpmPack(spawnSyncImpl, packageSpec, destinationDir) {
|
|
8372
|
+
function runNpmPack(spawnSyncImpl, packageSpec, destinationDir, cacheDir, deadline) {
|
|
8373
|
+
const timeout = remainingRuntimeInstallMs(deadline, cacheDir, `npm pack ${packageSpec}`);
|
|
8231
8374
|
return spawnSyncImpl(
|
|
8232
8375
|
process.platform === "win32" ? "npm.cmd" : "npm",
|
|
8233
8376
|
["pack", packageSpec, "--pack-destination", destinationDir, ...RUNTIME_NPM_PACK_FLAGS],
|
|
@@ -8235,17 +8378,20 @@ function runNpmPack(spawnSyncImpl, packageSpec, destinationDir) {
|
|
|
8235
8378
|
encoding: "utf8",
|
|
8236
8379
|
stdio: ["ignore", "pipe", "pipe"],
|
|
8237
8380
|
env: { ...process.env, ...NPM_PLATFORM_REPAIR_ENV },
|
|
8381
|
+
...timeout === void 0 ? {} : { timeout },
|
|
8238
8382
|
...process.platform === "win32" ? { shell: true, windowsHide: true } : {}
|
|
8239
8383
|
}
|
|
8240
8384
|
);
|
|
8241
8385
|
}
|
|
8242
|
-
function runTarExtract(spawnSyncImpl, archivePath, targetDir) {
|
|
8386
|
+
function runTarExtract(spawnSyncImpl, archivePath, targetDir, cacheDir, deadline) {
|
|
8387
|
+
const timeout = remainingRuntimeInstallMs(deadline, cacheDir, "extract runtime platform package");
|
|
8243
8388
|
return spawnSyncImpl(
|
|
8244
8389
|
"tar",
|
|
8245
8390
|
["-xzf", archivePath, "-C", targetDir, "--strip-components", "1"],
|
|
8246
8391
|
{
|
|
8247
8392
|
encoding: "utf8",
|
|
8248
8393
|
stdio: ["ignore", "pipe", "pipe"],
|
|
8394
|
+
...timeout === void 0 ? {} : { timeout },
|
|
8249
8395
|
...process.platform === "win32" ? { windowsHide: true } : {}
|
|
8250
8396
|
}
|
|
8251
8397
|
);
|
|
@@ -8269,8 +8415,8 @@ function combineSpawnResults(...results) {
|
|
|
8269
8415
|
}
|
|
8270
8416
|
async function removeRuntimeInstallLocks(cacheDir) {
|
|
8271
8417
|
await Promise.all([
|
|
8272
|
-
rm(
|
|
8273
|
-
rm(
|
|
8418
|
+
rm(path9.join(cacheDir, "package-lock.json"), { force: true }),
|
|
8419
|
+
rm(path9.join(cacheDir, "node_modules", ".package-lock.json"), { force: true })
|
|
8274
8420
|
]);
|
|
8275
8421
|
}
|
|
8276
8422
|
function packageNameFromSpec(packageSpec) {
|
|
@@ -8294,77 +8440,95 @@ function runtimePostgresExecutableName(baseName) {
|
|
|
8294
8440
|
return process.platform === "win32" ? `${baseName}.exe` : baseName;
|
|
8295
8441
|
}
|
|
8296
8442
|
function debianSharedirCandidate(binDir) {
|
|
8297
|
-
const normalized =
|
|
8298
|
-
const parts = normalized.split(
|
|
8443
|
+
const normalized = path9.resolve(binDir);
|
|
8444
|
+
const parts = normalized.split(path9.sep);
|
|
8299
8445
|
const libIndex = parts.lastIndexOf("lib");
|
|
8300
8446
|
if (libIndex < 0) return null;
|
|
8301
8447
|
if (parts[libIndex + 1] !== "postgresql") return null;
|
|
8302
8448
|
const version = parts[libIndex + 2];
|
|
8303
8449
|
if (!version || parts[libIndex + 3] !== "bin") return null;
|
|
8304
|
-
const prefix = parts.slice(0, libIndex).join(
|
|
8305
|
-
return
|
|
8450
|
+
const prefix = parts.slice(0, libIndex).join(path9.sep) || path9.sep;
|
|
8451
|
+
return path9.join(prefix, "share", "postgresql", version);
|
|
8306
8452
|
}
|
|
8307
|
-
async function resolveRuntimePostgresTemplateDir(binDir) {
|
|
8453
|
+
async function resolveRuntimePostgresTemplateDir(binDir, cacheDir = binDir, deadline) {
|
|
8308
8454
|
for (const candidatePath of [
|
|
8309
|
-
|
|
8310
|
-
|
|
8455
|
+
path9.join(binDir, "..", "share", "postgresql", "postgres.bki"),
|
|
8456
|
+
path9.join(binDir, "..", "share", "postgres.bki")
|
|
8311
8457
|
]) {
|
|
8458
|
+
remainingRuntimeInstallMs(deadline, cacheDir, "discover PostgreSQL runtime templates");
|
|
8312
8459
|
try {
|
|
8313
|
-
await
|
|
8314
|
-
return
|
|
8460
|
+
await stat(candidatePath);
|
|
8461
|
+
return path9.dirname(candidatePath);
|
|
8315
8462
|
} catch {
|
|
8316
8463
|
}
|
|
8317
8464
|
}
|
|
8318
8465
|
const debianSharedir = debianSharedirCandidate(binDir);
|
|
8319
8466
|
if (debianSharedir) {
|
|
8467
|
+
remainingRuntimeInstallMs(deadline, cacheDir, "discover PostgreSQL runtime templates");
|
|
8320
8468
|
try {
|
|
8321
|
-
await
|
|
8469
|
+
await stat(path9.join(debianSharedir, "postgres.bki"));
|
|
8322
8470
|
return debianSharedir;
|
|
8323
8471
|
} catch {
|
|
8324
8472
|
}
|
|
8325
8473
|
}
|
|
8326
|
-
const pgConfigPath =
|
|
8474
|
+
const pgConfigPath = path9.join(binDir, process.platform === "win32" ? "pg_config.exe" : "pg_config");
|
|
8327
8475
|
try {
|
|
8328
|
-
|
|
8329
|
-
|
|
8476
|
+
remainingRuntimeInstallMs(deadline, cacheDir, "discover PostgreSQL runtime templates");
|
|
8477
|
+
await stat(pgConfigPath);
|
|
8478
|
+
const timeout = remainingRuntimeInstallMs(deadline, cacheDir, `${pgConfigPath} --sharedir`);
|
|
8479
|
+
let sharedir;
|
|
8480
|
+
try {
|
|
8481
|
+
sharedir = execFileSync(pgConfigPath, ["--sharedir"], {
|
|
8482
|
+
encoding: "utf8",
|
|
8483
|
+
...timeout === void 0 ? {} : { timeout }
|
|
8484
|
+
}).trim();
|
|
8485
|
+
} catch (error) {
|
|
8486
|
+
if (isChildProcessTimeoutError(error)) {
|
|
8487
|
+
throw runtimeInstallDeadlineError(cacheDir, `${pgConfigPath} --sharedir`);
|
|
8488
|
+
}
|
|
8489
|
+
throw error;
|
|
8490
|
+
}
|
|
8330
8491
|
if (!sharedir) return null;
|
|
8331
|
-
|
|
8332
|
-
|
|
8492
|
+
remainingRuntimeInstallMs(deadline, cacheDir, "validate PostgreSQL runtime templates");
|
|
8493
|
+
const candidatePath = path9.join(sharedir, "postgres.bki");
|
|
8494
|
+
await stat(candidatePath);
|
|
8333
8495
|
return sharedir;
|
|
8334
|
-
} catch {
|
|
8496
|
+
} catch (error) {
|
|
8497
|
+
if (isRuntimeInstallDeadlineError(error)) throw error;
|
|
8335
8498
|
return null;
|
|
8336
8499
|
}
|
|
8337
8500
|
}
|
|
8338
8501
|
function resolveRuntimePostgresShareDir(binDir, templateDir) {
|
|
8339
|
-
const adjacentShareDir =
|
|
8502
|
+
const adjacentShareDir = path9.resolve(binDir, "..", "share");
|
|
8340
8503
|
return pathIsInside(templateDir, adjacentShareDir) ? adjacentShareDir : templateDir;
|
|
8341
8504
|
}
|
|
8342
|
-
async function assertRuntimePostgresBinDirComplete(cacheDir, binDir) {
|
|
8505
|
+
async function assertRuntimePostgresBinDirComplete(cacheDir, binDir, deadline) {
|
|
8343
8506
|
const requiredBinaries = ["initdb", "pg_ctl", "postgres"];
|
|
8344
8507
|
const missing = [];
|
|
8345
8508
|
for (const binary of requiredBinaries) {
|
|
8346
|
-
|
|
8509
|
+
remainingRuntimeInstallMs(deadline, cacheDir, "validate PostgreSQL runtime binaries");
|
|
8510
|
+
const binaryPath = path9.join(binDir, runtimePostgresExecutableName(binary));
|
|
8347
8511
|
try {
|
|
8348
|
-
await
|
|
8512
|
+
await stat(binaryPath);
|
|
8349
8513
|
} catch {
|
|
8350
8514
|
missing.push(binaryPath);
|
|
8351
8515
|
}
|
|
8352
8516
|
}
|
|
8353
|
-
const templateDir = await resolveRuntimePostgresTemplateDir(binDir);
|
|
8517
|
+
const templateDir = await resolveRuntimePostgresTemplateDir(binDir, cacheDir, deadline);
|
|
8354
8518
|
if (!templateDir) {
|
|
8355
|
-
missing.push(
|
|
8519
|
+
missing.push(path9.join(binDir, "..", "share", "postgresql", "postgres.bki"));
|
|
8356
8520
|
} else {
|
|
8357
8521
|
try {
|
|
8358
|
-
await
|
|
8522
|
+
await stat(path9.join(templateDir, "postgresql.conf.sample"));
|
|
8359
8523
|
} catch {
|
|
8360
|
-
missing.push(
|
|
8524
|
+
missing.push(path9.join(templateDir, "postgresql.conf.sample"));
|
|
8361
8525
|
}
|
|
8362
8526
|
const shareDir = resolveRuntimePostgresShareDir(binDir, templateDir);
|
|
8363
8527
|
const hasTimezoneDir = (await Promise.all([
|
|
8364
|
-
|
|
8365
|
-
|
|
8366
|
-
].map((candidate) =>
|
|
8367
|
-
if (!hasTimezoneDir) missing.push(
|
|
8528
|
+
path9.join(templateDir, "timezone"),
|
|
8529
|
+
path9.join(shareDir, "timezone")
|
|
8530
|
+
].map((candidate) => stat(candidate).catch(() => null)))).some((candidate) => candidate?.isDirectory());
|
|
8531
|
+
if (!hasTimezoneDir) missing.push(path9.join(shareDir, "timezone"));
|
|
8368
8532
|
}
|
|
8369
8533
|
if (missing.length > 0) {
|
|
8370
8534
|
throw new RuntimeInstallError(
|
|
@@ -8373,31 +8537,124 @@ async function assertRuntimePostgresBinDirComplete(cacheDir, binDir) {
|
|
|
8373
8537
|
);
|
|
8374
8538
|
}
|
|
8375
8539
|
}
|
|
8376
|
-
function readPostgresVersion(postgresBinary) {
|
|
8377
|
-
return execFileSync(postgresBinary, ["--version"], {
|
|
8540
|
+
function readPostgresVersion(postgresBinary, timeout) {
|
|
8541
|
+
return execFileSync(postgresBinary, ["--version"], {
|
|
8542
|
+
encoding: "utf8",
|
|
8543
|
+
...timeout === void 0 ? {} : { timeout }
|
|
8544
|
+
});
|
|
8378
8545
|
}
|
|
8379
|
-
async function isRuntimePostgresPayloadUsable(cacheDir, binDir, postgresVersionProbe) {
|
|
8546
|
+
async function isRuntimePostgresPayloadUsable(cacheDir, binDir, postgresVersionProbe, deadline) {
|
|
8380
8547
|
try {
|
|
8381
|
-
await validateRuntimePostgresVersion(cacheDir, binDir, postgresVersionProbe);
|
|
8548
|
+
await validateRuntimePostgresVersion(cacheDir, binDir, postgresVersionProbe, deadline);
|
|
8382
8549
|
return true;
|
|
8383
|
-
} catch {
|
|
8550
|
+
} catch (error) {
|
|
8551
|
+
if (isRuntimeInstallDeadlineError(error)) throw error;
|
|
8384
8552
|
return false;
|
|
8385
8553
|
}
|
|
8386
8554
|
}
|
|
8387
8555
|
function pathIsInside(candidatePath, rootPath) {
|
|
8388
|
-
const relative =
|
|
8389
|
-
return relative === "" || relative !== ".." && !relative.startsWith(`..${
|
|
8556
|
+
const relative = path9.relative(path9.resolve(rootPath), path9.resolve(candidatePath));
|
|
8557
|
+
return relative === "" || relative !== ".." && !relative.startsWith(`..${path9.sep}`) && !path9.isAbsolute(relative);
|
|
8558
|
+
}
|
|
8559
|
+
async function copyRuntimePayloadEntry(sourcePath, targetPath, cacheDir, deadline, signal, command) {
|
|
8560
|
+
if (signal.aborted) throw runtimeInstallDeadlineError(cacheDir, command);
|
|
8561
|
+
remainingRuntimeInstallMs(deadline, cacheDir, command);
|
|
8562
|
+
const sourceStats = await stat(sourcePath);
|
|
8563
|
+
if (signal.aborted) throw runtimeInstallDeadlineError(cacheDir, command);
|
|
8564
|
+
remainingRuntimeInstallMs(deadline, cacheDir, command);
|
|
8565
|
+
if (sourceStats.isDirectory()) {
|
|
8566
|
+
await mkdir(targetPath, { recursive: true });
|
|
8567
|
+
const entries = await readdir(sourcePath);
|
|
8568
|
+
for (const entry of entries) {
|
|
8569
|
+
await copyRuntimePayloadEntry(
|
|
8570
|
+
path9.join(sourcePath, entry),
|
|
8571
|
+
path9.join(targetPath, entry),
|
|
8572
|
+
cacheDir,
|
|
8573
|
+
deadline,
|
|
8574
|
+
signal,
|
|
8575
|
+
command
|
|
8576
|
+
);
|
|
8577
|
+
}
|
|
8578
|
+
return;
|
|
8579
|
+
}
|
|
8580
|
+
if (!sourceStats.isFile()) return;
|
|
8581
|
+
await mkdir(path9.dirname(targetPath), { recursive: true });
|
|
8582
|
+
try {
|
|
8583
|
+
await pipeline2(
|
|
8584
|
+
createReadStream2(sourcePath),
|
|
8585
|
+
createWriteStream2(targetPath, { flags: "w", mode: sourceStats.mode }),
|
|
8586
|
+
{ signal }
|
|
8587
|
+
);
|
|
8588
|
+
await chmod(targetPath, sourceStats.mode);
|
|
8589
|
+
remainingRuntimeInstallMs(deadline, cacheDir, command);
|
|
8590
|
+
} catch (error) {
|
|
8591
|
+
await rm(targetPath, { force: true });
|
|
8592
|
+
if (signal.aborted || isRuntimeInstallDeadlineError(error)) {
|
|
8593
|
+
throw runtimeInstallDeadlineError(cacheDir, command);
|
|
8594
|
+
}
|
|
8595
|
+
throw error;
|
|
8596
|
+
}
|
|
8597
|
+
}
|
|
8598
|
+
async function copyRuntimePostgresPayloadWithinDeadline(sourceRuntimeDir, targetRuntimeDir, sourceShareDir, cacheDir, deadline, externalSignal) {
|
|
8599
|
+
const command = "copy PostgreSQL runtime payload";
|
|
8600
|
+
const timeoutMs = remainingRuntimeInstallMs(deadline, cacheDir, command);
|
|
8601
|
+
const controller = new AbortController();
|
|
8602
|
+
const abortFromExternal = () => controller.abort(externalSignal?.reason);
|
|
8603
|
+
if (externalSignal?.aborted) abortFromExternal();
|
|
8604
|
+
else externalSignal?.addEventListener("abort", abortFromExternal, { once: true });
|
|
8605
|
+
let timer;
|
|
8606
|
+
const timeoutPromise = timeoutMs === void 0 ? null : new Promise((_resolve, reject) => {
|
|
8607
|
+
timer = setTimeout(() => {
|
|
8608
|
+
controller.abort();
|
|
8609
|
+
reject(runtimeInstallDeadlineError(cacheDir, command));
|
|
8610
|
+
}, timeoutMs);
|
|
8611
|
+
});
|
|
8612
|
+
const copyPromise = (async () => {
|
|
8613
|
+
await mkdir(targetRuntimeDir, { recursive: true });
|
|
8614
|
+
for (const directoryName of ["bin", "lib"]) {
|
|
8615
|
+
const sourceDirectory = path9.join(sourceRuntimeDir, directoryName);
|
|
8616
|
+
if (!await stat(sourceDirectory).catch(() => null)) continue;
|
|
8617
|
+
await copyRuntimePayloadEntry(
|
|
8618
|
+
sourceDirectory,
|
|
8619
|
+
path9.join(targetRuntimeDir, directoryName),
|
|
8620
|
+
cacheDir,
|
|
8621
|
+
deadline,
|
|
8622
|
+
controller.signal,
|
|
8623
|
+
command
|
|
8624
|
+
);
|
|
8625
|
+
}
|
|
8626
|
+
await copyRuntimePayloadEntry(
|
|
8627
|
+
sourceShareDir,
|
|
8628
|
+
path9.join(targetRuntimeDir, "share"),
|
|
8629
|
+
cacheDir,
|
|
8630
|
+
deadline,
|
|
8631
|
+
controller.signal,
|
|
8632
|
+
command
|
|
8633
|
+
);
|
|
8634
|
+
})();
|
|
8635
|
+
try {
|
|
8636
|
+
if (timeoutPromise) await Promise.race([copyPromise, timeoutPromise]);
|
|
8637
|
+
else await copyPromise;
|
|
8638
|
+
} finally {
|
|
8639
|
+
if (timer) clearTimeout(timer);
|
|
8640
|
+
externalSignal?.removeEventListener("abort", abortFromExternal);
|
|
8641
|
+
}
|
|
8390
8642
|
}
|
|
8391
8643
|
async function withRuntimeFilesystemLock(lockPath, task, options = {}) {
|
|
8392
|
-
const
|
|
8644
|
+
const deadlineTimeout = remainingRuntimeInstallMs(
|
|
8645
|
+
options.deadline,
|
|
8646
|
+
options.cacheDir ?? path9.dirname(lockPath),
|
|
8647
|
+
options.command ?? `wait for runtime lock ${lockPath}`
|
|
8648
|
+
);
|
|
8649
|
+
const timeoutMs = Math.min(options.timeoutMs ?? 3e4, deadlineTimeout ?? Number.POSITIVE_INFINITY);
|
|
8393
8650
|
const pollMs = options.pollMs ?? 50;
|
|
8394
8651
|
const startedAt = Date.now();
|
|
8395
8652
|
const lockId = `${process.pid}-${startedAt}-${Math.random().toString(16).slice(2)}`;
|
|
8396
|
-
const ownerPath =
|
|
8397
|
-
await
|
|
8653
|
+
const ownerPath = path9.join(lockPath, "owner.json");
|
|
8654
|
+
await mkdir(path9.dirname(lockPath), { recursive: true });
|
|
8398
8655
|
while (true) {
|
|
8399
8656
|
try {
|
|
8400
|
-
await
|
|
8657
|
+
await mkdir(lockPath);
|
|
8401
8658
|
await writeFile(
|
|
8402
8659
|
ownerPath,
|
|
8403
8660
|
`${JSON.stringify({ pid: process.pid, lockId, createdAt: (/* @__PURE__ */ new Date()).toISOString() })}
|
|
@@ -8414,7 +8671,7 @@ async function withRuntimeFilesystemLock(lockPath, task, options = {}) {
|
|
|
8414
8671
|
continue;
|
|
8415
8672
|
}
|
|
8416
8673
|
} catch {
|
|
8417
|
-
const lockStats = await
|
|
8674
|
+
const lockStats = await stat(lockPath).catch(() => null);
|
|
8418
8675
|
if (lockStats && Date.now() - lockStats.mtimeMs > 5e3) {
|
|
8419
8676
|
await rm(lockPath, { recursive: true, force: true });
|
|
8420
8677
|
continue;
|
|
@@ -8423,9 +8680,14 @@ async function withRuntimeFilesystemLock(lockPath, task, options = {}) {
|
|
|
8423
8680
|
if (Date.now() - startedAt >= timeoutMs) {
|
|
8424
8681
|
throw new RuntimeInstallError(
|
|
8425
8682
|
`Timed out waiting for PostgreSQL runtime install lock ${lockPath}`,
|
|
8426
|
-
{ cacheDir:
|
|
8683
|
+
{ cacheDir: path9.dirname(lockPath), command: "prepare shared PostgreSQL runtime", output: "" }
|
|
8427
8684
|
);
|
|
8428
8685
|
}
|
|
8686
|
+
remainingRuntimeInstallMs(
|
|
8687
|
+
options.deadline,
|
|
8688
|
+
options.cacheDir ?? path9.dirname(lockPath),
|
|
8689
|
+
options.command ?? `wait for runtime lock ${lockPath}`
|
|
8690
|
+
);
|
|
8429
8691
|
await new Promise((resolve) => setTimeout(resolve, pollMs));
|
|
8430
8692
|
}
|
|
8431
8693
|
}
|
|
@@ -8443,44 +8705,45 @@ async function withRuntimeFilesystemLock(lockPath, task, options = {}) {
|
|
|
8443
8705
|
}
|
|
8444
8706
|
function isManagedRuntimePostgresBinDir(binDir, homeDir) {
|
|
8445
8707
|
const managedBinDir = process.env[RUDDER_DESKTOP_MANAGED_POSTGRES_BIN_DIR_ENV]?.trim();
|
|
8446
|
-
if (managedBinDir &&
|
|
8447
|
-
const runtimesRelative =
|
|
8448
|
-
|
|
8449
|
-
|
|
8708
|
+
if (managedBinDir && path9.resolve(managedBinDir) === path9.resolve(binDir)) return true;
|
|
8709
|
+
const runtimesRelative = path9.relative(
|
|
8710
|
+
path9.join(homeDir, "runtimes"),
|
|
8711
|
+
path9.resolve(binDir)
|
|
8450
8712
|
);
|
|
8451
|
-
const runtimeSegments = runtimesRelative.split(
|
|
8452
|
-
if (runtimesRelative !== "" && runtimesRelative !== ".." && !runtimesRelative.startsWith(`..${
|
|
8713
|
+
const runtimeSegments = runtimesRelative.split(path9.sep);
|
|
8714
|
+
if (runtimesRelative !== "" && runtimesRelative !== ".." && !runtimesRelative.startsWith(`..${path9.sep}`) && !path9.isAbsolute(runtimesRelative) && runtimeSegments.length === 4 && runtimeSegments[0]?.length > 0 && runtimeSegments[1] === RUNTIME_POSTGRES_PAYLOAD_DIR && runtimeSegments[2] === `${process.platform}-${process.arch}` && runtimeSegments[3] === "bin") {
|
|
8453
8715
|
return true;
|
|
8454
8716
|
}
|
|
8455
|
-
const payloadsRelative =
|
|
8456
|
-
|
|
8457
|
-
|
|
8717
|
+
const payloadsRelative = path9.relative(
|
|
8718
|
+
path9.join(homeDir, "runtime-payloads"),
|
|
8719
|
+
path9.resolve(binDir)
|
|
8458
8720
|
);
|
|
8459
|
-
const payloadSegments = payloadsRelative.split(
|
|
8460
|
-
return payloadsRelative !== "" && payloadsRelative !== ".." && !payloadsRelative.startsWith(`..${
|
|
8721
|
+
const payloadSegments = payloadsRelative.split(path9.sep);
|
|
8722
|
+
return payloadsRelative !== "" && payloadsRelative !== ".." && !payloadsRelative.startsWith(`..${path9.sep}`) && !path9.isAbsolute(payloadsRelative) && payloadSegments.length === 3 && payloadSegments[0] === RUNTIME_POSTGRES_PAYLOAD_DIR && payloadSegments[1] === `${process.platform}-${process.arch}` && payloadSegments[2] === "bin";
|
|
8461
8723
|
}
|
|
8462
|
-
async function findLegacyRuntimePostgresBinDir(cacheDir, homeDir, postgresVersionProbe) {
|
|
8463
|
-
const runtimesRoot =
|
|
8724
|
+
async function findLegacyRuntimePostgresBinDir(cacheDir, homeDir, postgresVersionProbe, deadline) {
|
|
8725
|
+
const runtimesRoot = path9.join(homeDir, "runtimes");
|
|
8464
8726
|
const entries = await readdir(runtimesRoot, { withFileTypes: true }).catch(() => []);
|
|
8465
8727
|
for (const entry of entries) {
|
|
8466
8728
|
if (!entry.isDirectory() && !entry.isSymbolicLink()) continue;
|
|
8467
|
-
const candidateCacheDir =
|
|
8468
|
-
if (
|
|
8729
|
+
const candidateCacheDir = path9.join(runtimesRoot, entry.name);
|
|
8730
|
+
if (path9.resolve(candidateCacheDir) === path9.resolve(cacheDir)) continue;
|
|
8469
8731
|
const candidateBinDir = resolveRuntimePostgresPayloadBinDir(candidateCacheDir);
|
|
8470
|
-
|
|
8732
|
+
remainingRuntimeInstallMs(deadline, cacheDir, "find cached PostgreSQL runtime payload");
|
|
8733
|
+
if (await isRuntimePostgresPayloadUsable(cacheDir, candidateBinDir, postgresVersionProbe, deadline)) {
|
|
8471
8734
|
return candidateBinDir;
|
|
8472
8735
|
}
|
|
8473
8736
|
}
|
|
8474
8737
|
return null;
|
|
8475
8738
|
}
|
|
8476
8739
|
async function readLiveRuntimeDescriptors(homeDir) {
|
|
8477
|
-
const instancesRoot =
|
|
8740
|
+
const instancesRoot = path9.join(homeDir, "instances");
|
|
8478
8741
|
const entries = await readdir(instancesRoot, { withFileTypes: true }).catch(() => []);
|
|
8479
8742
|
const descriptors = [];
|
|
8480
8743
|
for (const entry of entries) {
|
|
8481
8744
|
if (!entry.isDirectory()) continue;
|
|
8482
8745
|
try {
|
|
8483
|
-
const raw = JSON.parse(await readFile(
|
|
8746
|
+
const raw = JSON.parse(await readFile(path9.join(instancesRoot, entry.name, "runtime", "server.json"), "utf8"));
|
|
8484
8747
|
if (typeof raw.pid !== "number" || !Number.isInteger(raw.pid) || !isPidRunning(raw.pid) || typeof raw.version !== "string") {
|
|
8485
8748
|
continue;
|
|
8486
8749
|
}
|
|
@@ -8498,13 +8761,13 @@ async function assertSharedPostgresPayloadNotLive(cacheDir, homeDir, sharedBinDi
|
|
|
8498
8761
|
const sharedPhysicalBinDir = await realpath(sharedBinDir).catch(() => null);
|
|
8499
8762
|
const mayReferenceSharedPayload = await Promise.all(liveDescriptors.map(async (descriptor) => {
|
|
8500
8763
|
if (descriptor.postgresBinDir === void 0) return true;
|
|
8501
|
-
if (
|
|
8764
|
+
if (path9.resolve(descriptor.postgresBinDir) === path9.resolve(sharedBinDir)) return true;
|
|
8502
8765
|
const descriptorPhysicalBinDir = await realpath(descriptor.postgresBinDir).catch(() => null);
|
|
8503
|
-
if (descriptorPhysicalBinDir && sharedPhysicalBinDir &&
|
|
8766
|
+
if (descriptorPhysicalBinDir && sharedPhysicalBinDir && path9.resolve(descriptorPhysicalBinDir) === path9.resolve(sharedPhysicalBinDir)) {
|
|
8504
8767
|
return true;
|
|
8505
8768
|
}
|
|
8506
8769
|
if (!descriptorPhysicalBinDir) {
|
|
8507
|
-
return pathIsInside(descriptor.postgresBinDir,
|
|
8770
|
+
return pathIsInside(descriptor.postgresBinDir, path9.join(homeDir, "runtimes")) || pathIsInside(descriptor.postgresBinDir, path9.join(homeDir, "runtime-payloads"));
|
|
8508
8771
|
}
|
|
8509
8772
|
return false;
|
|
8510
8773
|
}));
|
|
@@ -8515,10 +8778,11 @@ async function assertSharedPostgresPayloadNotLive(cacheDir, homeDir, sharedBinDi
|
|
|
8515
8778
|
);
|
|
8516
8779
|
}
|
|
8517
8780
|
}
|
|
8518
|
-
async function validateRuntimePostgresVersion(cacheDir, binDir, postgresVersionProbe) {
|
|
8519
|
-
await assertRuntimePostgresBinDirComplete(cacheDir, binDir);
|
|
8781
|
+
async function validateRuntimePostgresVersion(cacheDir, binDir, postgresVersionProbe, deadline) {
|
|
8782
|
+
await assertRuntimePostgresBinDirComplete(cacheDir, binDir, deadline);
|
|
8520
8783
|
for (const binary of ["initdb", "pg_ctl", "postgres"]) {
|
|
8521
|
-
|
|
8784
|
+
remainingRuntimeInstallMs(deadline, cacheDir, "validate PostgreSQL runtime version");
|
|
8785
|
+
const binaryPath = path9.join(binDir, runtimePostgresExecutableName(binary));
|
|
8522
8786
|
const result = postgresVersionProbe(binaryPath);
|
|
8523
8787
|
if (!/\bPostgreSQL\)?\s+18\.4\b/i.test(result)) {
|
|
8524
8788
|
throw new RuntimeInstallError(
|
|
@@ -8528,7 +8792,8 @@ async function validateRuntimePostgresVersion(cacheDir, binDir, postgresVersionP
|
|
|
8528
8792
|
}
|
|
8529
8793
|
}
|
|
8530
8794
|
}
|
|
8531
|
-
function extractRuntimePostgresArchive(archivePath, extractDir) {
|
|
8795
|
+
function extractRuntimePostgresArchive(archivePath, extractDir, cacheDir, deadline) {
|
|
8796
|
+
const timeout = remainingRuntimeInstallMs(deadline, cacheDir, "extract PostgreSQL runtime archive");
|
|
8532
8797
|
const result = process.platform === "win32" ? spawnSync2("powershell.exe", [
|
|
8533
8798
|
"-NoProfile",
|
|
8534
8799
|
"-NonInteractive",
|
|
@@ -8539,46 +8804,54 @@ function extractRuntimePostgresArchive(archivePath, extractDir) {
|
|
|
8539
8804
|
], {
|
|
8540
8805
|
encoding: "utf8",
|
|
8541
8806
|
env: { ...process.env, PG_ARCHIVE_PATH: archivePath, PG_EXTRACT_DIR: extractDir },
|
|
8542
|
-
windowsHide: true
|
|
8543
|
-
|
|
8807
|
+
windowsHide: true,
|
|
8808
|
+
...timeout === void 0 ? {} : { timeout }
|
|
8809
|
+
}) : spawnSync2("tar", ["-xf", archivePath, "-C", extractDir], {
|
|
8810
|
+
encoding: "utf8",
|
|
8811
|
+
...timeout === void 0 ? {} : { timeout }
|
|
8812
|
+
});
|
|
8544
8813
|
if (result.status !== 0) {
|
|
8545
8814
|
throw new Error(`failed to extract PostgreSQL archive: ${result.stderr || result.stdout}`);
|
|
8546
8815
|
}
|
|
8547
8816
|
}
|
|
8548
|
-
async function findRuntimePostgresBinDir(rootDir, cacheDir, postgresVersionProbe) {
|
|
8817
|
+
async function findRuntimePostgresBinDir(rootDir, cacheDir, postgresVersionProbe, deadline) {
|
|
8549
8818
|
const queue = [rootDir];
|
|
8550
8819
|
for (let index = 0; index < queue.length; index += 1) {
|
|
8551
8820
|
const current = queue[index];
|
|
8552
|
-
|
|
8821
|
+
remainingRuntimeInstallMs(deadline, cacheDir, "find PostgreSQL runtime payload");
|
|
8822
|
+
if (await isRuntimePostgresPayloadUsable(cacheDir, current, postgresVersionProbe, deadline)) return current;
|
|
8553
8823
|
const entries = await readdir(current, { withFileTypes: true }).catch(() => []);
|
|
8554
8824
|
for (const entry of entries) {
|
|
8555
|
-
if (entry.isDirectory()) queue.push(
|
|
8825
|
+
if (entry.isDirectory()) queue.push(path9.join(current, entry.name));
|
|
8556
8826
|
}
|
|
8557
8827
|
}
|
|
8558
8828
|
return null;
|
|
8559
8829
|
}
|
|
8560
|
-
async function reconcileSharedPostgresPayloadGenerations(cacheDir, sharedPlatformRoot, postgresVersionProbe, cleanupDownloads = false) {
|
|
8561
|
-
|
|
8562
|
-
const
|
|
8830
|
+
async function reconcileSharedPostgresPayloadGenerations(cacheDir, sharedPlatformRoot, postgresVersionProbe, cleanupDownloads = false, deadline) {
|
|
8831
|
+
remainingRuntimeInstallMs(deadline, cacheDir, "reconcile shared PostgreSQL payload");
|
|
8832
|
+
const parentDir = path9.dirname(sharedPlatformRoot);
|
|
8833
|
+
const baseName = path9.basename(sharedPlatformRoot);
|
|
8563
8834
|
const entries = await readdir(parentDir, { withFileTypes: true }).catch(() => []);
|
|
8564
|
-
const temporaryRoots = entries.filter((entry) => entry.name.startsWith(`${baseName}.tmp-`)).map((entry) =>
|
|
8565
|
-
const previousRoots = entries.filter((entry) => entry.name.startsWith(`${baseName}.previous-`)).map((entry) =>
|
|
8566
|
-
const downloadsRoot =
|
|
8567
|
-
|
|
8835
|
+
const temporaryRoots = entries.filter((entry) => entry.name.startsWith(`${baseName}.tmp-`)).map((entry) => path9.join(parentDir, entry.name));
|
|
8836
|
+
const previousRoots = entries.filter((entry) => entry.name.startsWith(`${baseName}.previous-`)).map((entry) => path9.join(parentDir, entry.name)).sort().reverse();
|
|
8837
|
+
const downloadsRoot = path9.join(
|
|
8838
|
+
path9.dirname(path9.dirname(sharedPlatformRoot)),
|
|
8568
8839
|
".downloads"
|
|
8569
8840
|
);
|
|
8570
|
-
const staleDownloadRoots = cleanupDownloads ? (await readdir(downloadsRoot, { withFileTypes: true }).catch(() => [])).filter((entry) => entry.name.startsWith("postgres-18.4-")).map((entry) =>
|
|
8571
|
-
const canonicalBinDir =
|
|
8841
|
+
const staleDownloadRoots = cleanupDownloads ? (await readdir(downloadsRoot, { withFileTypes: true }).catch(() => [])).filter((entry) => entry.name.startsWith("postgres-18.4-")).map((entry) => path9.join(downloadsRoot, entry.name)) : [];
|
|
8842
|
+
const canonicalBinDir = path9.join(sharedPlatformRoot, "bin");
|
|
8572
8843
|
if (!await isRuntimePostgresPayloadUsable(
|
|
8573
8844
|
cacheDir,
|
|
8574
8845
|
canonicalBinDir,
|
|
8575
|
-
postgresVersionProbe
|
|
8846
|
+
postgresVersionProbe,
|
|
8847
|
+
deadline
|
|
8576
8848
|
)) {
|
|
8577
8849
|
for (const previousRoot of previousRoots) {
|
|
8578
8850
|
if (!await isRuntimePostgresPayloadUsable(
|
|
8579
8851
|
cacheDir,
|
|
8580
|
-
|
|
8581
|
-
postgresVersionProbe
|
|
8852
|
+
path9.join(previousRoot, "bin"),
|
|
8853
|
+
postgresVersionProbe,
|
|
8854
|
+
deadline
|
|
8582
8855
|
)) {
|
|
8583
8856
|
continue;
|
|
8584
8857
|
}
|
|
@@ -8593,12 +8866,12 @@ async function reconcileSharedPostgresPayloadGenerations(cacheDir, sharedPlatfor
|
|
|
8593
8866
|
...staleDownloadRoots.map((candidate) => rm(candidate, { recursive: true, force: true }))
|
|
8594
8867
|
]);
|
|
8595
8868
|
}
|
|
8596
|
-
async function installSharedRuntimePostgresPayload(cacheDir, homeDir, sourceBinDir, postgresVersionProbe) {
|
|
8869
|
+
async function installSharedRuntimePostgresPayload(cacheDir, homeDir, sourceBinDir, postgresVersionProbe, deadline) {
|
|
8597
8870
|
const sharedBinDir = resolveSharedRuntimePostgresPayloadBinDir(homeDir);
|
|
8598
|
-
const sharedRuntimeDir =
|
|
8871
|
+
const sharedRuntimeDir = path9.dirname(sharedBinDir);
|
|
8599
8872
|
const sharedPlatformRoot = sharedRuntimeDir;
|
|
8600
|
-
const sourceRuntimeDir =
|
|
8601
|
-
const sourceTemplateDir = await resolveRuntimePostgresTemplateDir(sourceBinDir);
|
|
8873
|
+
const sourceRuntimeDir = path9.dirname(sourceBinDir);
|
|
8874
|
+
const sourceTemplateDir = await resolveRuntimePostgresTemplateDir(sourceBinDir, cacheDir, deadline);
|
|
8602
8875
|
if (!sourceTemplateDir) {
|
|
8603
8876
|
throw new RuntimeInstallError(
|
|
8604
8877
|
`${RUDDER_POSTGRES_BIN_DIR_ENV} must contain PostgreSQL 18.4 initdb template files`,
|
|
@@ -8610,13 +8883,15 @@ async function installSharedRuntimePostgresPayload(cacheDir, homeDir, sourceBinD
|
|
|
8610
8883
|
await reconcileSharedPostgresPayloadGenerations(
|
|
8611
8884
|
cacheDir,
|
|
8612
8885
|
sharedPlatformRoot,
|
|
8613
|
-
postgresVersionProbe
|
|
8886
|
+
postgresVersionProbe,
|
|
8887
|
+
false,
|
|
8888
|
+
deadline
|
|
8614
8889
|
);
|
|
8615
|
-
if (await isRuntimePostgresPayloadUsable(cacheDir, sharedBinDir, postgresVersionProbe)) {
|
|
8890
|
+
if (await isRuntimePostgresPayloadUsable(cacheDir, sharedBinDir, postgresVersionProbe, deadline)) {
|
|
8616
8891
|
return sharedBinDir;
|
|
8617
8892
|
}
|
|
8618
8893
|
await assertSharedPostgresPayloadNotLive(cacheDir, homeDir, sharedBinDir);
|
|
8619
|
-
await
|
|
8894
|
+
await mkdir(path9.dirname(sharedPlatformRoot), { recursive: true });
|
|
8620
8895
|
const temporaryPlatformRoot = `${sharedPlatformRoot}.tmp-${process.pid}-${Date.now()}`;
|
|
8621
8896
|
const previousPlatformRoot = `${sharedPlatformRoot}.previous-${process.pid}-${Date.now()}`;
|
|
8622
8897
|
let previousMoved = false;
|
|
@@ -8626,13 +8901,15 @@ async function installSharedRuntimePostgresPayload(cacheDir, homeDir, sourceBinD
|
|
|
8626
8901
|
try {
|
|
8627
8902
|
const temporaryRuntimeDir = temporaryPlatformRoot;
|
|
8628
8903
|
const sourceShareDir = resolveRuntimePostgresShareDir(sourceBinDir, sourceTemplateDir);
|
|
8629
|
-
await
|
|
8904
|
+
await copyRuntimePostgresPayloadWithinDeadline(
|
|
8630
8905
|
sourceRuntimeDir,
|
|
8631
8906
|
temporaryRuntimeDir,
|
|
8632
|
-
sourceShareDir
|
|
8907
|
+
sourceShareDir,
|
|
8908
|
+
cacheDir,
|
|
8909
|
+
deadline
|
|
8633
8910
|
);
|
|
8634
|
-
const temporaryBinDir =
|
|
8635
|
-
await validateRuntimePostgresVersion(cacheDir, temporaryBinDir, postgresVersionProbe);
|
|
8911
|
+
const temporaryBinDir = path9.join(temporaryRuntimeDir, "bin");
|
|
8912
|
+
await validateRuntimePostgresVersion(cacheDir, temporaryBinDir, postgresVersionProbe, deadline);
|
|
8636
8913
|
try {
|
|
8637
8914
|
await rename(sharedPlatformRoot, previousPlatformRoot);
|
|
8638
8915
|
previousMoved = true;
|
|
@@ -8660,30 +8937,35 @@ async function installSharedRuntimePostgresPayload(cacheDir, homeDir, sourceBinD
|
|
|
8660
8937
|
}
|
|
8661
8938
|
}
|
|
8662
8939
|
return sharedBinDir;
|
|
8663
|
-
});
|
|
8940
|
+
}, { deadline, cacheDir, command: "acquire shared PostgreSQL install lock" });
|
|
8664
8941
|
}
|
|
8665
|
-
async function downloadSharedRuntimePostgresPayload(cacheDir, homeDir, postgresVersionProbe) {
|
|
8942
|
+
async function downloadSharedRuntimePostgresPayload(cacheDir, homeDir, postgresVersionProbe, deadline, cleanupWorkDir) {
|
|
8666
8943
|
const archiveSource = resolvePostgresRuntimeArchiveSource();
|
|
8667
8944
|
const archiveUrl = archiveSource?.url ?? null;
|
|
8668
8945
|
if (!archiveUrl) return null;
|
|
8669
8946
|
const sharedBinDir = resolveSharedRuntimePostgresPayloadBinDir(homeDir);
|
|
8670
|
-
const sharedPlatformRoot =
|
|
8947
|
+
const sharedPlatformRoot = path9.dirname(sharedBinDir);
|
|
8671
8948
|
const downloadLockPath = `${sharedPlatformRoot}.download.lock`;
|
|
8672
8949
|
return withRuntimeFilesystemLock(downloadLockPath, async () => {
|
|
8673
|
-
if (await isRuntimePostgresPayloadUsable(cacheDir, sharedBinDir, postgresVersionProbe)) {
|
|
8950
|
+
if (await isRuntimePostgresPayloadUsable(cacheDir, sharedBinDir, postgresVersionProbe, deadline)) {
|
|
8674
8951
|
return sharedBinDir;
|
|
8675
8952
|
}
|
|
8676
|
-
const workRoot =
|
|
8677
|
-
await
|
|
8678
|
-
const workDir = await mkdtemp(
|
|
8679
|
-
const archivePath =
|
|
8680
|
-
const extractDir =
|
|
8953
|
+
const workRoot = path9.join(homeDir, "runtime-payloads", ".downloads");
|
|
8954
|
+
await mkdir(workRoot, { recursive: true });
|
|
8955
|
+
const workDir = await mkdtemp(path9.join(workRoot, "postgres-18.4-"));
|
|
8956
|
+
const archivePath = path9.join(workDir, "postgresql-18.4.zip");
|
|
8957
|
+
const extractDir = path9.join(workDir, "extract");
|
|
8681
8958
|
try {
|
|
8682
|
-
await downloadRuntimePostgresArchive(
|
|
8959
|
+
await downloadRuntimePostgresArchive(
|
|
8960
|
+
archiveUrl,
|
|
8961
|
+
archivePath,
|
|
8962
|
+
archiveSource?.expectedSha256,
|
|
8963
|
+
{ timeoutMs: remainingRuntimeInstallMs(deadline, cacheDir, "download PostgreSQL runtime archive") }
|
|
8964
|
+
);
|
|
8683
8965
|
const configuredMaxBytes = Number.parseInt(process.env[RUDDER_POSTGRES_RUNTIME_ARCHIVE_MAX_BYTES_ENV2] ?? "", 10);
|
|
8684
8966
|
const maxArchiveBytes = Number.isSafeInteger(configuredMaxBytes) && configuredMaxBytes > 0 ? configuredMaxBytes : DEFAULT_RUNTIME_POSTGRES_ARCHIVE_MAX_BYTES2;
|
|
8685
8967
|
const nativePublishStaging = `${sharedPlatformRoot}.tmp-native-${process.pid}-${Date.now()}`;
|
|
8686
|
-
await
|
|
8968
|
+
await mkdir(path9.dirname(sharedPlatformRoot), { recursive: true });
|
|
8687
8969
|
const nativeInstall = await tryInstallNativePayload({
|
|
8688
8970
|
archivePath,
|
|
8689
8971
|
extractPath: extractDir,
|
|
@@ -8691,11 +8973,14 @@ async function downloadSharedRuntimePostgresPayload(cacheDir, homeDir, postgresV
|
|
|
8691
8973
|
destinationPath: sharedPlatformRoot,
|
|
8692
8974
|
maxArchiveBytes,
|
|
8693
8975
|
expectedSha256: archiveSource?.expectedSha256,
|
|
8694
|
-
|
|
8976
|
+
timeoutMs: remainingRuntimeInstallMs(deadline, cacheDir, "prepare native PostgreSQL runtime payload"),
|
|
8977
|
+
now: deadline?.now,
|
|
8978
|
+
preparePublish: async (nativeExtractPath, publishStagingPath, context) => {
|
|
8695
8979
|
const extractedBinDir2 = await findRuntimePostgresBinDir(
|
|
8696
8980
|
nativeExtractPath,
|
|
8697
8981
|
cacheDir,
|
|
8698
|
-
postgresVersionProbe
|
|
8982
|
+
postgresVersionProbe,
|
|
8983
|
+
deadline
|
|
8699
8984
|
);
|
|
8700
8985
|
if (!extractedBinDir2) {
|
|
8701
8986
|
throw new RuntimeInstallError(
|
|
@@ -8703,41 +8988,46 @@ async function downloadSharedRuntimePostgresPayload(cacheDir, homeDir, postgresV
|
|
|
8703
8988
|
{ cacheDir, command: "prepare native PostgreSQL runtime payload", output: "" }
|
|
8704
8989
|
);
|
|
8705
8990
|
}
|
|
8706
|
-
await validateRuntimePostgresVersion(cacheDir, extractedBinDir2, postgresVersionProbe);
|
|
8707
|
-
const templateDir = await resolveRuntimePostgresTemplateDir(extractedBinDir2);
|
|
8991
|
+
await validateRuntimePostgresVersion(cacheDir, extractedBinDir2, postgresVersionProbe, deadline);
|
|
8992
|
+
const templateDir = await resolveRuntimePostgresTemplateDir(extractedBinDir2, cacheDir, deadline);
|
|
8708
8993
|
if (!templateDir) {
|
|
8709
8994
|
throw new RuntimeInstallError(
|
|
8710
8995
|
"PostgreSQL 18.4 archive did not contain initdb template files",
|
|
8711
8996
|
{ cacheDir, command: "prepare native PostgreSQL runtime payload", output: "" }
|
|
8712
8997
|
);
|
|
8713
8998
|
}
|
|
8714
|
-
await
|
|
8715
|
-
|
|
8999
|
+
await copyRuntimePostgresPayloadWithinDeadline(
|
|
9000
|
+
path9.dirname(extractedBinDir2),
|
|
8716
9001
|
publishStagingPath,
|
|
8717
|
-
resolveRuntimePostgresShareDir(extractedBinDir2, templateDir)
|
|
9002
|
+
resolveRuntimePostgresShareDir(extractedBinDir2, templateDir),
|
|
9003
|
+
cacheDir,
|
|
9004
|
+
deadline,
|
|
9005
|
+
context.signal
|
|
8718
9006
|
);
|
|
8719
|
-
return
|
|
9007
|
+
return path9.relative(
|
|
8720
9008
|
publishStagingPath,
|
|
8721
|
-
|
|
9009
|
+
path9.join(publishStagingPath, "bin", runtimePostgresExecutableName("postgres"))
|
|
8722
9010
|
);
|
|
8723
9011
|
},
|
|
8724
9012
|
validatePublished: async (destinationPath) => {
|
|
8725
9013
|
await validateRuntimePostgresVersion(
|
|
8726
9014
|
cacheDir,
|
|
8727
|
-
|
|
8728
|
-
postgresVersionProbe
|
|
9015
|
+
path9.join(destinationPath, "bin"),
|
|
9016
|
+
postgresVersionProbe,
|
|
9017
|
+
deadline
|
|
8729
9018
|
);
|
|
8730
9019
|
}
|
|
8731
9020
|
});
|
|
8732
9021
|
if (nativeInstall.installed) {
|
|
8733
9022
|
return sharedBinDir;
|
|
8734
9023
|
}
|
|
8735
|
-
await
|
|
8736
|
-
extractRuntimePostgresArchive(archivePath, extractDir);
|
|
9024
|
+
await mkdir(extractDir, { recursive: true });
|
|
9025
|
+
extractRuntimePostgresArchive(archivePath, extractDir, cacheDir, deadline);
|
|
8737
9026
|
const extractedBinDir = await findRuntimePostgresBinDir(
|
|
8738
9027
|
extractDir,
|
|
8739
9028
|
cacheDir,
|
|
8740
|
-
postgresVersionProbe
|
|
9029
|
+
postgresVersionProbe,
|
|
9030
|
+
deadline
|
|
8741
9031
|
);
|
|
8742
9032
|
if (!extractedBinDir) {
|
|
8743
9033
|
throw new RuntimeInstallError(
|
|
@@ -8749,28 +9039,31 @@ async function downloadSharedRuntimePostgresPayload(cacheDir, homeDir, postgresV
|
|
|
8749
9039
|
cacheDir,
|
|
8750
9040
|
homeDir,
|
|
8751
9041
|
extractedBinDir,
|
|
8752
|
-
postgresVersionProbe
|
|
9042
|
+
postgresVersionProbe,
|
|
9043
|
+
deadline
|
|
8753
9044
|
);
|
|
8754
9045
|
} finally {
|
|
8755
|
-
|
|
9046
|
+
const cleanup = cleanupWorkDir ?? ((candidate) => rm(candidate, { recursive: true, force: true }));
|
|
9047
|
+
void cleanup(workDir).catch(() => {
|
|
9048
|
+
});
|
|
8756
9049
|
}
|
|
8757
|
-
});
|
|
9050
|
+
}, { deadline, cacheDir, command: "acquire shared PostgreSQL download lock" });
|
|
8758
9051
|
}
|
|
8759
9052
|
async function ensureRuntimePostgresCompatibilityLink(cacheDir, homeDir, packageVersion) {
|
|
8760
|
-
const compatibilityRoot =
|
|
8761
|
-
const sharedPayloadRoot =
|
|
9053
|
+
const compatibilityRoot = path9.join(cacheDir, RUNTIME_POSTGRES_PAYLOAD_DIR);
|
|
9054
|
+
const sharedPayloadRoot = path9.join(homeDir, "runtime-payloads", RUNTIME_POSTGRES_PAYLOAD_DIR);
|
|
8762
9055
|
const runtimeMetadata = await readRuntimeInstallMetadata(cacheDir);
|
|
8763
9056
|
const liveDescriptors = await readLiveRuntimeDescriptors(homeDir);
|
|
8764
9057
|
const compatibilityBinDir = resolveRuntimePostgresPayloadBinDir(cacheDir);
|
|
8765
9058
|
const isProtected = liveDescriptors.some((descriptor) => descriptor.postgresBinDir && pathIsInside(descriptor.postgresBinDir, compatibilityRoot) || !descriptor.postgresBinDir && descriptor.version === (runtimeMetadata?.packageVersion ?? packageVersion));
|
|
8766
9059
|
if (isProtected) return;
|
|
8767
|
-
await
|
|
9060
|
+
await mkdir(path9.dirname(compatibilityRoot), { recursive: true });
|
|
8768
9061
|
const temporaryRoot = `${compatibilityRoot}.next-${process.pid}-${Date.now()}`;
|
|
8769
9062
|
const previousRoot = `${compatibilityRoot}.previous-${process.pid}-${Date.now()}`;
|
|
8770
9063
|
await rm(temporaryRoot, { recursive: true, force: true });
|
|
8771
9064
|
await rm(previousRoot, { recursive: true, force: true });
|
|
8772
9065
|
await symlink(
|
|
8773
|
-
process.platform === "win32" ? sharedPayloadRoot :
|
|
9066
|
+
process.platform === "win32" ? sharedPayloadRoot : path9.relative(path9.dirname(compatibilityRoot), sharedPayloadRoot),
|
|
8774
9067
|
temporaryRoot,
|
|
8775
9068
|
process.platform === "win32" ? "junction" : "dir"
|
|
8776
9069
|
);
|
|
@@ -8800,15 +9093,16 @@ async function ensureRuntimePostgresCompatibilityLink(cacheDir, homeDir, package
|
|
|
8800
9093
|
if (!previousMoved) await rm(previousRoot, { recursive: true, force: true });
|
|
8801
9094
|
}
|
|
8802
9095
|
}
|
|
8803
|
-
async function stageRuntimePostgresPayload(cacheDir, homeDir, packageVersion, enabled, postgresVersionProbe) {
|
|
9096
|
+
async function stageRuntimePostgresPayload(cacheDir, homeDir, packageVersion, enabled, postgresVersionProbe, deadline, cleanupDownloadWorkDir) {
|
|
8804
9097
|
if (!enabled) return { output: "" };
|
|
8805
9098
|
const explicitSourceBinDir = process.env[RUDDER_POSTGRES_BIN_DIR_ENV]?.trim();
|
|
8806
|
-
const resolvedExplicitSourceBinDir = explicitSourceBinDir ?
|
|
9099
|
+
const resolvedExplicitSourceBinDir = explicitSourceBinDir ? path9.resolve(explicitSourceBinDir) : null;
|
|
8807
9100
|
if (resolvedExplicitSourceBinDir && !isManagedRuntimePostgresBinDir(resolvedExplicitSourceBinDir, homeDir)) {
|
|
8808
9101
|
await validateRuntimePostgresVersion(
|
|
8809
9102
|
cacheDir,
|
|
8810
9103
|
resolvedExplicitSourceBinDir,
|
|
8811
|
-
postgresVersionProbe
|
|
9104
|
+
postgresVersionProbe,
|
|
9105
|
+
deadline
|
|
8812
9106
|
);
|
|
8813
9107
|
return {
|
|
8814
9108
|
output: "",
|
|
@@ -8823,35 +9117,41 @@ async function stageRuntimePostgresPayload(cacheDir, homeDir, packageVersion, en
|
|
|
8823
9117
|
};
|
|
8824
9118
|
}
|
|
8825
9119
|
const sharedBinDir = resolveSharedRuntimePostgresPayloadBinDir(homeDir);
|
|
8826
|
-
const sharedPlatformRoot =
|
|
9120
|
+
const sharedPlatformRoot = path9.dirname(sharedBinDir);
|
|
8827
9121
|
await withRuntimeFilesystemLock(
|
|
8828
9122
|
`${sharedPlatformRoot}.install.lock`,
|
|
8829
9123
|
async () => reconcileSharedPostgresPayloadGenerations(
|
|
8830
9124
|
cacheDir,
|
|
8831
9125
|
sharedPlatformRoot,
|
|
8832
9126
|
postgresVersionProbe,
|
|
8833
|
-
true
|
|
8834
|
-
|
|
9127
|
+
true,
|
|
9128
|
+
deadline
|
|
9129
|
+
),
|
|
9130
|
+
{ deadline, cacheDir, command: "reconcile shared PostgreSQL payload" }
|
|
8835
9131
|
);
|
|
8836
9132
|
let output = "";
|
|
8837
|
-
if (!await isRuntimePostgresPayloadUsable(cacheDir, sharedBinDir, postgresVersionProbe)) {
|
|
8838
|
-
const sourceBinDir = resolvedExplicitSourceBinDir ?? await findLegacyRuntimePostgresBinDir(cacheDir, homeDir, postgresVersionProbe);
|
|
9133
|
+
if (!await isRuntimePostgresPayloadUsable(cacheDir, sharedBinDir, postgresVersionProbe, deadline)) {
|
|
9134
|
+
const sourceBinDir = resolvedExplicitSourceBinDir ?? await findLegacyRuntimePostgresBinDir(cacheDir, homeDir, postgresVersionProbe, deadline);
|
|
8839
9135
|
if (sourceBinDir) {
|
|
8840
9136
|
await validateRuntimePostgresVersion(
|
|
8841
9137
|
cacheDir,
|
|
8842
9138
|
sourceBinDir,
|
|
8843
|
-
postgresVersionProbe
|
|
9139
|
+
postgresVersionProbe,
|
|
9140
|
+
deadline
|
|
8844
9141
|
);
|
|
8845
9142
|
await installSharedRuntimePostgresPayload(
|
|
8846
9143
|
cacheDir,
|
|
8847
9144
|
homeDir,
|
|
8848
9145
|
sourceBinDir,
|
|
8849
|
-
postgresVersionProbe
|
|
9146
|
+
postgresVersionProbe,
|
|
9147
|
+
deadline
|
|
8850
9148
|
);
|
|
8851
9149
|
} else if (!await downloadSharedRuntimePostgresPayload(
|
|
8852
9150
|
cacheDir,
|
|
8853
9151
|
homeDir,
|
|
8854
|
-
postgresVersionProbe
|
|
9152
|
+
postgresVersionProbe,
|
|
9153
|
+
deadline,
|
|
9154
|
+
cleanupDownloadWorkDir
|
|
8855
9155
|
)) {
|
|
8856
9156
|
return { output: "" };
|
|
8857
9157
|
}
|
|
@@ -8929,13 +9229,13 @@ async function pruneRuntimeCache(options = {}) {
|
|
|
8929
9229
|
};
|
|
8930
9230
|
}
|
|
8931
9231
|
async function scanRuntimeCacheEntries(homeDir) {
|
|
8932
|
-
const runtimesDir =
|
|
9232
|
+
const runtimesDir = path9.join(homeDir, "runtimes");
|
|
8933
9233
|
const dirents = await readdir(runtimesDir, { withFileTypes: true }).catch(() => null);
|
|
8934
9234
|
if (!dirents) return [];
|
|
8935
9235
|
const entries = [];
|
|
8936
9236
|
for (const dirent of dirents) {
|
|
8937
9237
|
if (!dirent.isDirectory()) continue;
|
|
8938
|
-
const cacheDir =
|
|
9238
|
+
const cacheDir = path9.join(runtimesDir, dirent.name);
|
|
8939
9239
|
const metadata = await readRuntimeInstallMetadata(cacheDir);
|
|
8940
9240
|
if (!metadata) continue;
|
|
8941
9241
|
const fallbackStat = await safeStat(cacheDir);
|
|
@@ -8958,7 +9258,7 @@ function parseTimestampMs(value) {
|
|
|
8958
9258
|
}
|
|
8959
9259
|
async function safeStat(targetPath) {
|
|
8960
9260
|
try {
|
|
8961
|
-
return await
|
|
9261
|
+
return await stat(targetPath);
|
|
8962
9262
|
} catch {
|
|
8963
9263
|
return null;
|
|
8964
9264
|
}
|
|
@@ -8968,7 +9268,7 @@ async function directorySizeBytes(targetPath) {
|
|
|
8968
9268
|
if (!dirents) return 0;
|
|
8969
9269
|
let total = 0;
|
|
8970
9270
|
for (const dirent of dirents) {
|
|
8971
|
-
const entryPath =
|
|
9271
|
+
const entryPath = path9.join(targetPath, dirent.name);
|
|
8972
9272
|
if (dirent.isSymbolicLink()) continue;
|
|
8973
9273
|
if (dirent.isDirectory()) {
|
|
8974
9274
|
total += await directorySizeBytes(entryPath);
|
|
@@ -8980,14 +9280,14 @@ async function directorySizeBytes(targetPath) {
|
|
|
8980
9280
|
return total;
|
|
8981
9281
|
}
|
|
8982
9282
|
async function readActiveRuntimeVersions(homeDir) {
|
|
8983
|
-
const instancesDir =
|
|
9283
|
+
const instancesDir = path9.join(homeDir, "instances");
|
|
8984
9284
|
const dirents = await readdir(instancesDir, { withFileTypes: true }).catch(() => null);
|
|
8985
9285
|
if (!dirents) return [];
|
|
8986
9286
|
const versions = /* @__PURE__ */ new Set();
|
|
8987
9287
|
for (const dirent of dirents) {
|
|
8988
9288
|
if (!dirent.isDirectory()) continue;
|
|
8989
9289
|
try {
|
|
8990
|
-
const descriptorPath =
|
|
9290
|
+
const descriptorPath = path9.join(instancesDir, dirent.name, "runtime", "server.json");
|
|
8991
9291
|
const parsed = JSON.parse(await readFile(descriptorPath, "utf8"));
|
|
8992
9292
|
if (typeof parsed.version !== "string") continue;
|
|
8993
9293
|
if (typeof parsed.pid === "number" && Number.isInteger(parsed.pid) && parsed.pid > 0 && isPidRunning(parsed.pid)) {
|
|
@@ -9102,7 +9402,6 @@ var init_install = __esm({
|
|
|
9102
9402
|
"use strict";
|
|
9103
9403
|
init_home();
|
|
9104
9404
|
init_native_payload();
|
|
9105
|
-
init_postgres_payload();
|
|
9106
9405
|
init_postgres_runtime_download();
|
|
9107
9406
|
init_postgres_runtime_source();
|
|
9108
9407
|
RUNTIME_NPM_PACKAGE_NAME = "@rudderhq/server";
|
|
@@ -9148,7 +9447,7 @@ var init_install = __esm({
|
|
|
9148
9447
|
|
|
9149
9448
|
// src/runtime/server-entry.ts
|
|
9150
9449
|
import fs7 from "node:fs";
|
|
9151
|
-
import
|
|
9450
|
+
import path10 from "node:path";
|
|
9152
9451
|
import { fileURLToPath as fileURLToPath5, pathToFileURL as pathToFileURL2 } from "node:url";
|
|
9153
9452
|
function formatError(err) {
|
|
9154
9453
|
if (err instanceof Error) {
|
|
@@ -9170,8 +9469,8 @@ function maybeEnableUiDevMiddleware(entrypoint) {
|
|
|
9170
9469
|
}
|
|
9171
9470
|
}
|
|
9172
9471
|
function resolveDevServerEntry() {
|
|
9173
|
-
const projectRoot =
|
|
9174
|
-
return
|
|
9472
|
+
const projectRoot = path10.resolve(path10.dirname(fileURLToPath5(import.meta.url)), "../../..");
|
|
9473
|
+
return path10.resolve(projectRoot, "server/src/index.ts");
|
|
9175
9474
|
}
|
|
9176
9475
|
async function loadServerRuntimeModule(options) {
|
|
9177
9476
|
const devEntry = resolveDevServerEntry();
|
|
@@ -9311,21 +9610,21 @@ var init_auth_bootstrap_ceo = __esm({
|
|
|
9311
9610
|
|
|
9312
9611
|
// src/utils/path-resolver.ts
|
|
9313
9612
|
import fs10 from "node:fs";
|
|
9314
|
-
import
|
|
9613
|
+
import path18 from "node:path";
|
|
9315
9614
|
function unique(items) {
|
|
9316
9615
|
return Array.from(new Set(items));
|
|
9317
9616
|
}
|
|
9318
9617
|
function resolveRuntimeLikePath(value, configPath) {
|
|
9319
9618
|
const expanded = expandHomePrefix(value);
|
|
9320
|
-
if (
|
|
9619
|
+
if (path18.isAbsolute(expanded)) return path18.resolve(expanded);
|
|
9321
9620
|
const cwd = process.cwd();
|
|
9322
|
-
const configDir = configPath ?
|
|
9323
|
-
const workspaceRoot = configDir ?
|
|
9621
|
+
const configDir = configPath ? path18.dirname(configPath) : null;
|
|
9622
|
+
const workspaceRoot = configDir ? path18.resolve(configDir, "..") : cwd;
|
|
9324
9623
|
const candidates = unique([
|
|
9325
|
-
...configDir ? [
|
|
9326
|
-
|
|
9327
|
-
|
|
9328
|
-
|
|
9624
|
+
...configDir ? [path18.resolve(configDir, expanded)] : [],
|
|
9625
|
+
path18.resolve(workspaceRoot, "server", expanded),
|
|
9626
|
+
path18.resolve(workspaceRoot, expanded),
|
|
9627
|
+
path18.resolve(cwd, expanded)
|
|
9329
9628
|
]);
|
|
9330
9629
|
return candidates.find((candidate) => fs10.existsSync(candidate)) ?? candidates[0];
|
|
9331
9630
|
}
|
|
@@ -9339,7 +9638,7 @@ var init_path_resolver = __esm({
|
|
|
9339
9638
|
// src/config/secrets-key.ts
|
|
9340
9639
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
9341
9640
|
import fs11 from "node:fs";
|
|
9342
|
-
import
|
|
9641
|
+
import path19 from "node:path";
|
|
9343
9642
|
function ensureLocalSecretsKeyFile(config, configPath) {
|
|
9344
9643
|
if (config.secrets.provider !== "local_encrypted") {
|
|
9345
9644
|
return { status: "skipped_provider", path: null };
|
|
@@ -9354,7 +9653,7 @@ function ensureLocalSecretsKeyFile(config, configPath) {
|
|
|
9354
9653
|
if (fs11.existsSync(keyFilePath)) {
|
|
9355
9654
|
return { status: "existing", path: keyFilePath };
|
|
9356
9655
|
}
|
|
9357
|
-
fs11.mkdirSync(
|
|
9656
|
+
fs11.mkdirSync(path19.dirname(keyFilePath), { recursive: true });
|
|
9358
9657
|
fs11.writeFileSync(keyFilePath, randomBytes2(32).toString("base64"), {
|
|
9359
9658
|
encoding: "utf8",
|
|
9360
9659
|
mode: 384
|
|
@@ -10440,7 +10739,7 @@ var init_port_check = __esm({
|
|
|
10440
10739
|
// src/checks/secrets-check.ts
|
|
10441
10740
|
import { randomBytes as randomBytes3 } from "node:crypto";
|
|
10442
10741
|
import fs14 from "node:fs";
|
|
10443
|
-
import
|
|
10742
|
+
import path20 from "node:path";
|
|
10444
10743
|
function decodeMasterKey(raw) {
|
|
10445
10744
|
const trimmed = raw.trim();
|
|
10446
10745
|
if (!trimmed) return null;
|
|
@@ -10510,7 +10809,7 @@ function secretsCheck(config, configPath) {
|
|
|
10510
10809
|
message: `Secrets key file does not exist yet: ${keyFilePath}`,
|
|
10511
10810
|
canRepair: true,
|
|
10512
10811
|
repair: () => {
|
|
10513
|
-
fs14.mkdirSync(
|
|
10812
|
+
fs14.mkdirSync(path20.dirname(keyFilePath), { recursive: true });
|
|
10514
10813
|
fs14.writeFileSync(keyFilePath, randomBytes3(32).toString("base64"), {
|
|
10515
10814
|
encoding: "utf8",
|
|
10516
10815
|
mode: 384
|
|
@@ -11083,7 +11382,7 @@ var init_run = __esm({
|
|
|
11083
11382
|
|
|
11084
11383
|
// src/commands/onboard.ts
|
|
11085
11384
|
import * as p14 from "@clack/prompts";
|
|
11086
|
-
import
|
|
11385
|
+
import path21 from "node:path";
|
|
11087
11386
|
import pc13 from "picocolors";
|
|
11088
11387
|
function parseBooleanFromEnv(rawValue) {
|
|
11089
11388
|
if (rawValue === void 0) return null;
|
|
@@ -11116,7 +11415,7 @@ function parseEnumFromEnv(rawValue, allowedValues) {
|
|
|
11116
11415
|
}
|
|
11117
11416
|
function resolvePathFromEnv(rawValue) {
|
|
11118
11417
|
if (!rawValue || rawValue.trim().length === 0) return null;
|
|
11119
|
-
return
|
|
11418
|
+
return path21.resolve(expandHomePrefix(rawValue.trim()));
|
|
11120
11419
|
}
|
|
11121
11420
|
function quickstartDefaultsFromEnv() {
|
|
11122
11421
|
const instanceId = resolveRudderInstanceId();
|
|
@@ -11548,7 +11847,7 @@ var init_onboard = __esm({
|
|
|
11548
11847
|
});
|
|
11549
11848
|
|
|
11550
11849
|
// src/program.ts
|
|
11551
|
-
import { Command, CommanderError } from "commander";
|
|
11850
|
+
import { Command, CommanderError, Option } from "commander";
|
|
11552
11851
|
|
|
11553
11852
|
// src/agent-v1-mcp-server.ts
|
|
11554
11853
|
init_dist();
|
|
@@ -12133,7 +12432,7 @@ var AGENT_CLI_CAPABILITIES = [
|
|
|
12133
12432
|
category: "issue",
|
|
12134
12433
|
description: "Create a new issue or subtask with the generic issue surface; agent-created issues default to the creating agent when no assignee is supplied.",
|
|
12135
12434
|
mutating: true,
|
|
12136
|
-
contract: "
|
|
12435
|
+
contract: "agent-v1",
|
|
12137
12436
|
requiresOrgId: true,
|
|
12138
12437
|
requiresAgentId: false,
|
|
12139
12438
|
requiresRunId: false,
|
|
@@ -13081,41 +13380,41 @@ var RudderApiClient = class {
|
|
|
13081
13380
|
this.signal = opts.signal;
|
|
13082
13381
|
this.recoverAuth = opts.recoverAuth;
|
|
13083
13382
|
}
|
|
13084
|
-
get(
|
|
13085
|
-
return this.request(
|
|
13383
|
+
get(path25, opts) {
|
|
13384
|
+
return this.request(path25, { method: "GET" }, opts);
|
|
13086
13385
|
}
|
|
13087
|
-
post(
|
|
13088
|
-
return this.request(
|
|
13386
|
+
post(path25, body, opts) {
|
|
13387
|
+
return this.request(path25, {
|
|
13089
13388
|
method: "POST",
|
|
13090
13389
|
body: body === void 0 ? void 0 : JSON.stringify(body)
|
|
13091
13390
|
}, opts);
|
|
13092
13391
|
}
|
|
13093
|
-
postForm(
|
|
13094
|
-
return this.request(
|
|
13392
|
+
postForm(path25, form, opts) {
|
|
13393
|
+
return this.request(path25, {
|
|
13095
13394
|
method: "POST",
|
|
13096
13395
|
body: form
|
|
13097
13396
|
}, opts);
|
|
13098
13397
|
}
|
|
13099
|
-
patch(
|
|
13100
|
-
return this.request(
|
|
13398
|
+
patch(path25, body, opts) {
|
|
13399
|
+
return this.request(path25, {
|
|
13101
13400
|
method: "PATCH",
|
|
13102
13401
|
body: body === void 0 ? void 0 : JSON.stringify(body)
|
|
13103
13402
|
}, opts);
|
|
13104
13403
|
}
|
|
13105
|
-
put(
|
|
13106
|
-
return this.request(
|
|
13404
|
+
put(path25, body, opts) {
|
|
13405
|
+
return this.request(path25, {
|
|
13107
13406
|
method: "PUT",
|
|
13108
13407
|
body: body === void 0 ? void 0 : JSON.stringify(body)
|
|
13109
13408
|
}, opts);
|
|
13110
13409
|
}
|
|
13111
|
-
delete(
|
|
13112
|
-
return this.request(
|
|
13410
|
+
delete(path25, opts) {
|
|
13411
|
+
return this.request(path25, { method: "DELETE" }, opts);
|
|
13113
13412
|
}
|
|
13114
13413
|
setApiKey(apiKey) {
|
|
13115
13414
|
this.apiKey = apiKey?.trim() || void 0;
|
|
13116
13415
|
}
|
|
13117
|
-
async request(
|
|
13118
|
-
const url = buildUrl(this.apiBase,
|
|
13416
|
+
async request(path25, init, opts, hasRetriedAuth = false) {
|
|
13417
|
+
const url = buildUrl(this.apiBase, path25);
|
|
13119
13418
|
const headers = {
|
|
13120
13419
|
accept: "application/json",
|
|
13121
13420
|
...toStringRecord(init.headers)
|
|
@@ -13146,13 +13445,13 @@ var RudderApiClient = class {
|
|
|
13146
13445
|
const apiError = await toApiError(response);
|
|
13147
13446
|
if (!hasRetriedAuth && this.recoverAuth) {
|
|
13148
13447
|
const recoveredToken = await this.recoverAuth({
|
|
13149
|
-
path:
|
|
13448
|
+
path: path25,
|
|
13150
13449
|
method: String(init.method ?? "GET").toUpperCase(),
|
|
13151
13450
|
error: apiError
|
|
13152
13451
|
});
|
|
13153
13452
|
if (recoveredToken) {
|
|
13154
13453
|
this.setApiKey(recoveredToken);
|
|
13155
|
-
return this.request(
|
|
13454
|
+
return this.request(path25, init, opts, true);
|
|
13156
13455
|
}
|
|
13157
13456
|
}
|
|
13158
13457
|
throw apiError;
|
|
@@ -13171,8 +13470,8 @@ function shouldAttachAgentContext(method) {
|
|
|
13171
13470
|
const normalized = String(method ?? "GET").toUpperCase();
|
|
13172
13471
|
return normalized !== "GET" && normalized !== "HEAD";
|
|
13173
13472
|
}
|
|
13174
|
-
function buildUrl(apiBase,
|
|
13175
|
-
const normalizedPath =
|
|
13473
|
+
function buildUrl(apiBase, path25) {
|
|
13474
|
+
const normalizedPath = path25.startsWith("/") ? path25 : `/${path25}`;
|
|
13176
13475
|
const [pathname, query] = normalizedPath.split("?");
|
|
13177
13476
|
const url = new URL2(apiBase);
|
|
13178
13477
|
url.pathname = `${url.pathname.replace(/\/+$/, "")}${pathname}`;
|
|
@@ -14335,7 +14634,7 @@ async function callToolDirectlyIfSupported(toolName, rawArgs, env, signal) {
|
|
|
14335
14634
|
if (hasLocalImageInputs(input.images)) return null;
|
|
14336
14635
|
const api = mcpApiClient(env, signal);
|
|
14337
14636
|
const success = (data) => mcpSuccess(
|
|
14338
|
-
toCliShortIdOutput(data),
|
|
14637
|
+
capabilityId.startsWith("browser.") ? data : toCliShortIdOutput(data),
|
|
14339
14638
|
capabilityId.startsWith("browser.") ? RUDDER_BROWSER_MCP_MAX_TOOL_RESULT_BYTES : RUDDER_MCP_MAX_TOOL_RESULT_BYTES
|
|
14340
14639
|
);
|
|
14341
14640
|
switch (capabilityId) {
|
|
@@ -14425,6 +14724,26 @@ async function callToolDirectlyIfSupported(toolName, rawArgs, env, signal) {
|
|
|
14425
14724
|
payload
|
|
14426
14725
|
));
|
|
14427
14726
|
}
|
|
14727
|
+
case "issue.create": {
|
|
14728
|
+
const orgId = requiredRuntimeString(env, "RUDDER_ORG_ID");
|
|
14729
|
+
const payload = createIssueSchema.parse({
|
|
14730
|
+
title: requiredString(input, "title"),
|
|
14731
|
+
description: input.description,
|
|
14732
|
+
status: input.status,
|
|
14733
|
+
priority: input.priority,
|
|
14734
|
+
assigneeAgentId: input.assigneeAgentId,
|
|
14735
|
+
projectId: input.projectId,
|
|
14736
|
+
goalId: input.goalId,
|
|
14737
|
+
parentId: input.parentId,
|
|
14738
|
+
requestDepth: input.requestDepth,
|
|
14739
|
+
billingCode: input.billingCode,
|
|
14740
|
+
labelIds: input.labelIds
|
|
14741
|
+
});
|
|
14742
|
+
return success(await api.post(
|
|
14743
|
+
`/api/orgs/${encodeURIComponent(orgId)}/issues`,
|
|
14744
|
+
payload
|
|
14745
|
+
));
|
|
14746
|
+
}
|
|
14428
14747
|
case "issue.get":
|
|
14429
14748
|
return success(await api.get(`/api/issues/${encodeURIComponent(requiredAnyString(input, ["issue", "issueId"]))}`));
|
|
14430
14749
|
case "issue.context": {
|
|
@@ -14864,6 +15183,22 @@ function cliArgsForCapability(capabilityId, input, tempFiles, env) {
|
|
|
14864
15183
|
if (input.resultPayload !== void 0) args.push("--result-payload", JSON.stringify(input.resultPayload));
|
|
14865
15184
|
return args;
|
|
14866
15185
|
}
|
|
15186
|
+
case "issue.create": {
|
|
15187
|
+
const args = ["issue", "create", "--title", requiredString(input, "title")];
|
|
15188
|
+
pushOptional(args, "--description", input.description);
|
|
15189
|
+
pushOptional(args, "--status", input.status);
|
|
15190
|
+
pushOptional(args, "--priority", input.priority);
|
|
15191
|
+
pushOptional(args, "--assignee-agent-id", input.assigneeAgentId);
|
|
15192
|
+
pushOptional(args, "--project-id", input.projectId);
|
|
15193
|
+
pushOptional(args, "--goal-id", input.goalId);
|
|
15194
|
+
pushOptional(args, "--parent-id", input.parentId);
|
|
15195
|
+
pushOptional(args, "--request-depth", input.requestDepth);
|
|
15196
|
+
pushOptional(args, "--billing-code", input.billingCode);
|
|
15197
|
+
if (Array.isArray(input.labelIds)) {
|
|
15198
|
+
for (const labelId of input.labelIds) args.push("--label-id", String(labelId));
|
|
15199
|
+
}
|
|
15200
|
+
return args;
|
|
15201
|
+
}
|
|
14867
15202
|
case "issue.get":
|
|
14868
15203
|
return ["issue", "get", requiredAnyString(input, ["issue", "issueId"])];
|
|
14869
15204
|
case "issue.list": {
|
|
@@ -15726,8 +16061,8 @@ function registerActivityCommands(program) {
|
|
|
15726
16061
|
if (opts.entityType) params.set("entityType", opts.entityType);
|
|
15727
16062
|
if (opts.entityId) params.set("entityId", opts.entityId);
|
|
15728
16063
|
const query = params.toString();
|
|
15729
|
-
const
|
|
15730
|
-
const rows = await ctx.api.get(
|
|
16064
|
+
const path25 = `/api/orgs/${ctx.orgId}/activity${query ? `?${query}` : ""}`;
|
|
16065
|
+
const rows = await ctx.api.get(path25) ?? [];
|
|
15731
16066
|
if (ctx.json) {
|
|
15732
16067
|
printOutput(rows, { json: true });
|
|
15733
16068
|
return;
|
|
@@ -15759,7 +16094,7 @@ function registerActivityCommands(program) {
|
|
|
15759
16094
|
|
|
15760
16095
|
// ../packages/agent-runtime-utils/dist/server-utils.cli.js
|
|
15761
16096
|
import { promises as fs8 } from "node:fs";
|
|
15762
|
-
import
|
|
16097
|
+
import path11 from "node:path";
|
|
15763
16098
|
|
|
15764
16099
|
// ../packages/agent-runtime-utils/dist/native-process-runner.js
|
|
15765
16100
|
init_dist2();
|
|
@@ -16033,12 +16368,11 @@ The prior Run has already persisted the checkpoint named above. Reconstruct the
|
|
|
16033
16368
|
|
|
16034
16369
|
If the checkpoint instead records a wait or human decision, this wake is unexpected: do not invent authorization or execute the waiting action. Refresh managed Goal context, report the mismatch, and leave the Goal waiting for its named actor or external trigger. If a ready Result Proposal exists, stop and wait for human Acceptance.`;
|
|
16035
16370
|
var ISSUE_ASSIGNEE_EXECUTION_RAIL = "Before doing issue-scoped execution as the assignee, check out the assigned issue. If checkout returns `409`, do not retry; stop and report the ownership conflict.";
|
|
16036
|
-
var ISSUE_ASSIGN_PROMPT_TEMPLATE =
|
|
16371
|
+
var ISSUE_ASSIGN_PROMPT_TEMPLATE = `<wake_context>
|
|
16372
|
+
You are agent {{agent.id}} ({{agent.name}}). You have been assigned to work on an issue.
|
|
16037
16373
|
|
|
16038
16374
|
{{context.rudderWorkspace.orgResourcesPrompt}}
|
|
16039
16375
|
|
|
16040
|
-
## Task Context
|
|
16041
|
-
|
|
16042
16376
|
**Issue:** {{issue.title}}
|
|
16043
16377
|
**ID:** {{issue.id}}
|
|
16044
16378
|
**Status:** {{issue.status}}
|
|
@@ -16047,21 +16381,23 @@ var ISSUE_ASSIGN_PROMPT_TEMPLATE = `You are agent {{agent.id}} ({{agent.name}}).
|
|
|
16047
16381
|
**Reviewer:** {{issue.reviewerLabel}}
|
|
16048
16382
|
**Created At:** {{issue.createdAt}}
|
|
16049
16383
|
**Updated At:** {{issue.updatedAt}}
|
|
16384
|
+
</wake_context>
|
|
16050
16385
|
|
|
16386
|
+
<quoted_issue_context>
|
|
16051
16387
|
**Description:**
|
|
16052
16388
|
{{issue.description}}
|
|
16389
|
+
</quoted_issue_context>
|
|
16053
16390
|
|
|
16054
16391
|
|
|
16055
16392
|
Your task is to review this issue, understand what kind of work it asks for, and take the appropriate next action.
|
|
16056
16393
|
|
|
16057
16394
|
Do not assume every issue is a codebase task. If the issue is a question, screenshot check, review, planning request, coordination task, or another non-code request, answer or handle that request directly. Inspect the codebase and implement a change only when the issue actually asks for engineering work or when the relevant project resources make code changes necessary.
|
|
16058
16395
|
${ISSUE_ASSIGNEE_EXECUTION_RAIL}`;
|
|
16059
|
-
var ISSUE_COMMENTED_PROMPT_TEMPLATE =
|
|
16396
|
+
var ISSUE_COMMENTED_PROMPT_TEMPLATE = `<wake_context>
|
|
16397
|
+
You are agent {{agent.id}} ({{agent.name}}). There is a new comment on an issue you own.
|
|
16060
16398
|
|
|
16061
16399
|
{{context.rudderWorkspace.orgResourcesPrompt}}
|
|
16062
16400
|
|
|
16063
|
-
## Context
|
|
16064
|
-
|
|
16065
16401
|
**Issue:** {{issue.title}}
|
|
16066
16402
|
**ID:** {{issue.id}}
|
|
16067
16403
|
**Status:** {{issue.status}}
|
|
@@ -16069,7 +16405,9 @@ var ISSUE_COMMENTED_PROMPT_TEMPLATE = `You are agent {{agent.id}} ({{agent.name}
|
|
|
16069
16405
|
**Reviewer:** {{issue.reviewerLabel}}
|
|
16070
16406
|
**Created At:** {{issue.createdAt}}
|
|
16071
16407
|
**Updated At:** {{issue.updatedAt}}
|
|
16408
|
+
</wake_context>
|
|
16072
16409
|
|
|
16410
|
+
<quoted_issue_context>
|
|
16073
16411
|
**Issue Description:**
|
|
16074
16412
|
{{issue.description}}
|
|
16075
16413
|
|
|
@@ -16078,15 +16416,15 @@ var ISSUE_COMMENTED_PROMPT_TEMPLATE = `You are agent {{agent.id}} ({{agent.name}
|
|
|
16078
16416
|
From: {{comment.authorLabel}} ({{comment.authorKind}})
|
|
16079
16417
|
|
|
16080
16418
|
{{comment.body}}
|
|
16419
|
+
</quoted_issue_context>
|
|
16081
16420
|
|
|
16082
16421
|
Review the new comment and continue the issue from the current state. Respond or take action as needed.
|
|
16083
16422
|
${ISSUE_ASSIGNEE_EXECUTION_RAIL}`;
|
|
16084
|
-
var ISSUE_CHANGES_REQUESTED_PROMPT_TEMPLATE =
|
|
16423
|
+
var ISSUE_CHANGES_REQUESTED_PROMPT_TEMPLATE = `<wake_context>
|
|
16424
|
+
You are agent {{agent.id}} ({{agent.name}}). A reviewer requested changes on an issue you own.
|
|
16085
16425
|
|
|
16086
16426
|
{{context.rudderWorkspace.orgResourcesPrompt}}
|
|
16087
16427
|
|
|
16088
|
-
## Context
|
|
16089
|
-
|
|
16090
16428
|
**Issue:** {{issue.title}}
|
|
16091
16429
|
**ID:** {{issue.id}}
|
|
16092
16430
|
**Status:** {{issue.status}}
|
|
@@ -16094,7 +16432,9 @@ var ISSUE_CHANGES_REQUESTED_PROMPT_TEMPLATE = `You are agent {{agent.id}} ({{age
|
|
|
16094
16432
|
**Reviewer:** {{issue.reviewerLabel}}
|
|
16095
16433
|
**Created At:** {{issue.createdAt}}
|
|
16096
16434
|
**Updated At:** {{issue.updatedAt}}
|
|
16435
|
+
</wake_context>
|
|
16097
16436
|
|
|
16437
|
+
<quoted_issue_context>
|
|
16098
16438
|
**Issue Description:**
|
|
16099
16439
|
{{issue.description}}
|
|
16100
16440
|
|
|
@@ -16103,10 +16443,12 @@ var ISSUE_CHANGES_REQUESTED_PROMPT_TEMPLATE = `You are agent {{agent.id}} ({{age
|
|
|
16103
16443
|
From: {{comment.authorLabel}} ({{comment.authorKind}})
|
|
16104
16444
|
|
|
16105
16445
|
{{comment.body}}
|
|
16446
|
+
</quoted_issue_context>
|
|
16106
16447
|
|
|
16107
16448
|
Review the requested changes and continue the issue from the current state. Address the reviewer feedback before handing it back for review.
|
|
16108
16449
|
${ISSUE_ASSIGNEE_EXECUTION_RAIL}`;
|
|
16109
|
-
var ISSUE_RECOVERY_PROMPT_TEMPLATE =
|
|
16450
|
+
var ISSUE_RECOVERY_PROMPT_TEMPLATE = `<wake_context>
|
|
16451
|
+
You are agent {{agent.id}} ({{agent.name}}). This is a recovery run, not a fresh task.
|
|
16110
16452
|
|
|
16111
16453
|
{{context.rudderWorkspace.orgResourcesPrompt}}
|
|
16112
16454
|
|
|
@@ -16128,20 +16470,24 @@ var ISSUE_RECOVERY_PROMPT_TEMPLATE = `You are agent {{agent.id}} ({{agent.name}}
|
|
|
16128
16470
|
- Reviewer: {{issue.reviewerLabel}}
|
|
16129
16471
|
- Created At: {{issue.createdAt}}
|
|
16130
16472
|
- Updated At: {{issue.updatedAt}}
|
|
16473
|
+
</wake_context>
|
|
16131
16474
|
|
|
16475
|
+
<quoted_issue_context>
|
|
16132
16476
|
- Description:
|
|
16133
16477
|
{{issue.description}}
|
|
16478
|
+
</quoted_issue_context>
|
|
16134
16479
|
|
|
16135
16480
|
|
|
16136
16481
|
Before doing anything else, inspect what the previous run already completed and any side effects it may have caused. Continue the remaining work from the current state. Avoid blindly re-running the whole task.
|
|
16137
16482
|
${ISSUE_ASSIGNEE_EXECUTION_RAIL}`;
|
|
16138
|
-
var ISSUE_PASSIVE_FOLLOWUP_PROMPT_TEMPLATE =
|
|
16483
|
+
var ISSUE_PASSIVE_FOLLOWUP_PROMPT_TEMPLATE = `<wake_context>
|
|
16484
|
+
You are agent {{agent.id}} ({{agent.name}}). This is a passive issue follow-up, not a fresh assignment and not a failure recovery.
|
|
16139
16485
|
|
|
16140
16486
|
{{context.rudderWorkspace.orgResourcesPrompt}}
|
|
16141
16487
|
|
|
16142
16488
|
## Why You Were Woken
|
|
16143
16489
|
|
|
16144
|
-
The previous run ended without sufficient issue close-out.
|
|
16490
|
+
The previous run ended without sufficient issue close-out. Continue to progress the current issue.
|
|
16145
16491
|
|
|
16146
16492
|
- Origin Run ID: {{context.passiveFollowup.originRunId}}
|
|
16147
16493
|
- Previous Run ID: {{context.passiveFollowup.previousRunId}}
|
|
@@ -16158,16 +16504,17 @@ Reason: {{context.passiveFollowup.reason}}
|
|
|
16158
16504
|
- Reviewer: {{issue.reviewerLabel}}
|
|
16159
16505
|
- Created At: {{issue.createdAt}}
|
|
16160
16506
|
- Updated At: {{issue.updatedAt}}
|
|
16507
|
+
</wake_context>
|
|
16161
16508
|
|
|
16509
|
+
<quoted_issue_context>
|
|
16162
16510
|
- Description:
|
|
16163
16511
|
{{issue.description}}
|
|
16512
|
+
</quoted_issue_context>
|
|
16164
16513
|
|
|
16165
16514
|
|
|
16166
|
-
Before changing the issue, inspect the current issue state and any side effects from the previous run.
|
|
16515
|
+
Before changing the issue, continue to progress the current issue, then inspect the current issue state and any side effects from the previous run. Finally, do exactly one close-out action: add a progress comment, mark the issue done, block it with a reason, or hand it off explicitly with explanation.
|
|
16167
16516
|
${ISSUE_ASSIGNEE_EXECUTION_RAIL}`;
|
|
16168
16517
|
var RUDDER_AGENT_OPERATING_CONTRACT = [
|
|
16169
|
-
"# Rudder Agent Operating Contract",
|
|
16170
|
-
"",
|
|
16171
16518
|
"You are a helpful assistant running inside Rudder. Your home directory is `$AGENT_HOME`. Everything personal to you -- life, memory, knowledge -- lives there. Other agents may have their own folders and you may update them when necessary.",
|
|
16172
16519
|
"",
|
|
16173
16520
|
"Read Rudder mcp tools to firstly.",
|
|
@@ -16228,8 +16575,6 @@ var RUDDER_AGENT_OPERATING_CONTRACT = [
|
|
|
16228
16575
|
"- When the user explicitly mentions previously handled issue, tasks or conversations, you need to retrieve the relevant tasks first before proceeding with the next action."
|
|
16229
16576
|
].join("\n");
|
|
16230
16577
|
var RUDDER_AGENT_HEARTBEAT_INSTRUCTION = [
|
|
16231
|
-
"# Rudder Heartbeat Instruction",
|
|
16232
|
-
"",
|
|
16233
16578
|
"This section is injected by Rudder only for heartbeat scene runs. It is the platform-owned heartbeat/self-check pipeline.",
|
|
16234
16579
|
"",
|
|
16235
16580
|
"## Heartbeat Pipeline",
|
|
@@ -16255,8 +16600,8 @@ var RUDDER_AGENT_HEARTBEAT_INSTRUCTION = [
|
|
|
16255
16600
|
// ../packages/agent-runtime-utils/dist/server-utils.cli.js
|
|
16256
16601
|
async function resolveRudderSkillsDir(moduleDir, additionalCandidates = []) {
|
|
16257
16602
|
const candidates = [
|
|
16258
|
-
...RUDDER_SKILL_ROOT_RELATIVE_CANDIDATES.map((relativePath) =>
|
|
16259
|
-
...additionalCandidates.map((candidate) =>
|
|
16603
|
+
...RUDDER_SKILL_ROOT_RELATIVE_CANDIDATES.map((relativePath) => path11.resolve(moduleDir, relativePath)),
|
|
16604
|
+
...additionalCandidates.map((candidate) => path11.resolve(candidate))
|
|
16260
16605
|
];
|
|
16261
16606
|
const seenRoots = /* @__PURE__ */ new Set();
|
|
16262
16607
|
for (const root of candidates) {
|
|
@@ -16273,26 +16618,26 @@ async function removeMaintainerOnlySkillSymlinks(skillsHome, allowedSkillNames)
|
|
|
16273
16618
|
return removeUnselectedRudderSkillSymlinks(skillsHome, allowedSkillNames);
|
|
16274
16619
|
}
|
|
16275
16620
|
async function readRudderMaterializedSkillSource(target) {
|
|
16276
|
-
const manifestPath =
|
|
16621
|
+
const manifestPath = path11.join(target, ".rudder", "materialized-skill.json");
|
|
16277
16622
|
const raw = await fs8.readFile(manifestPath, "utf8").catch(() => null);
|
|
16278
16623
|
if (!raw)
|
|
16279
16624
|
return null;
|
|
16280
16625
|
try {
|
|
16281
16626
|
const parsed = parseObject(JSON.parse(raw));
|
|
16282
16627
|
const sourcePath = asString(parsed.sourcePath, "").trim();
|
|
16283
|
-
return sourcePath.length > 0 ?
|
|
16628
|
+
return sourcePath.length > 0 ? path11.resolve(sourcePath) : null;
|
|
16284
16629
|
} catch {
|
|
16285
16630
|
return null;
|
|
16286
16631
|
}
|
|
16287
16632
|
}
|
|
16288
16633
|
async function removeUnselectedRudderSkillSymlinks(skillsHome, allowedSkillNames, knownSkillSources = []) {
|
|
16289
16634
|
const allowed = new Set(Array.from(allowedSkillNames));
|
|
16290
|
-
const knownSources = new Set(Array.from(knownSkillSources).map((value) => value.trim()).filter(Boolean).map((value) =>
|
|
16635
|
+
const knownSources = new Set(Array.from(knownSkillSources).map((value) => value.trim()).filter(Boolean).map((value) => path11.resolve(value)));
|
|
16291
16636
|
try {
|
|
16292
16637
|
const entries = await fs8.readdir(skillsHome, { withFileTypes: true });
|
|
16293
16638
|
const removed = [];
|
|
16294
16639
|
for (const entry of entries) {
|
|
16295
|
-
const target =
|
|
16640
|
+
const target = path11.join(skillsHome, entry.name);
|
|
16296
16641
|
const existing = await fs8.lstat(target).catch(() => null);
|
|
16297
16642
|
if (!existing)
|
|
16298
16643
|
continue;
|
|
@@ -16301,8 +16646,8 @@ async function removeUnselectedRudderSkillSymlinks(skillsHome, allowedSkillNames
|
|
|
16301
16646
|
const linkedPath = await fs8.readlink(target).catch(() => null);
|
|
16302
16647
|
if (!linkedPath)
|
|
16303
16648
|
continue;
|
|
16304
|
-
const resolvedLinkedPath =
|
|
16305
|
-
isRudderManagedSkill = knownSources.has(
|
|
16649
|
+
const resolvedLinkedPath = path11.isAbsolute(linkedPath) ? linkedPath : path11.resolve(path11.dirname(target), linkedPath);
|
|
16650
|
+
isRudderManagedSkill = knownSources.has(path11.resolve(resolvedLinkedPath)) || isMaintainerOnlySkillTarget(linkedPath) || isMaintainerOnlySkillTarget(resolvedLinkedPath);
|
|
16306
16651
|
} else if (existing.isDirectory()) {
|
|
16307
16652
|
const materializedSource = await readRudderMaterializedSkillSource(target);
|
|
16308
16653
|
isRudderManagedSkill = materializedSource !== null && knownSources.has(materializedSource);
|
|
@@ -16324,7 +16669,7 @@ async function removeUnselectedRudderSkillSymlinks(skillsHome, allowedSkillNames
|
|
|
16324
16669
|
init_dist2();
|
|
16325
16670
|
import fs9 from "node:fs/promises";
|
|
16326
16671
|
import os3 from "node:os";
|
|
16327
|
-
import
|
|
16672
|
+
import path12 from "node:path";
|
|
16328
16673
|
import { fileURLToPath as fileURLToPath6 } from "node:url";
|
|
16329
16674
|
|
|
16330
16675
|
// src/commands/client/help.ts
|
|
@@ -16348,16 +16693,16 @@ function formatHelpExample(example) {
|
|
|
16348
16693
|
}
|
|
16349
16694
|
|
|
16350
16695
|
// src/commands/client/agent.ts
|
|
16351
|
-
var __moduleDir =
|
|
16696
|
+
var __moduleDir = path12.dirname(fileURLToPath6(import.meta.url));
|
|
16352
16697
|
function codexSkillsHome() {
|
|
16353
16698
|
const fromEnv = process.env.CODEX_HOME?.trim();
|
|
16354
|
-
const base = fromEnv && fromEnv.length > 0 ? fromEnv :
|
|
16355
|
-
return
|
|
16699
|
+
const base = fromEnv && fromEnv.length > 0 ? fromEnv : path12.join(os3.homedir(), ".codex");
|
|
16700
|
+
return path12.join(base, "skills");
|
|
16356
16701
|
}
|
|
16357
16702
|
function claudeSkillsHome() {
|
|
16358
16703
|
const fromEnv = process.env.CLAUDE_HOME?.trim();
|
|
16359
|
-
const base = fromEnv && fromEnv.length > 0 ? fromEnv :
|
|
16360
|
-
return
|
|
16704
|
+
const base = fromEnv && fromEnv.length > 0 ? fromEnv : path12.join(os3.homedir(), ".claude");
|
|
16705
|
+
return path12.join(base, "skills");
|
|
16361
16706
|
}
|
|
16362
16707
|
async function installSkillsForTarget(sourceSkillsDir, targetSkillsDir, tool2) {
|
|
16363
16708
|
const summary = {
|
|
@@ -16376,8 +16721,8 @@ async function installSkillsForTarget(sourceSkillsDir, targetSkillsDir, tool2) {
|
|
|
16376
16721
|
);
|
|
16377
16722
|
for (const entry of entries) {
|
|
16378
16723
|
if (!entry.isDirectory()) continue;
|
|
16379
|
-
const source =
|
|
16380
|
-
const target =
|
|
16724
|
+
const source = path12.join(sourceSkillsDir, entry.name);
|
|
16725
|
+
const target = path12.join(targetSkillsDir, entry.name);
|
|
16381
16726
|
const existing = await fs9.lstat(target).catch(() => null);
|
|
16382
16727
|
if (existing) {
|
|
16383
16728
|
if (existing.isSymbolicLink()) {
|
|
@@ -16398,7 +16743,7 @@ async function installSkillsForTarget(sourceSkillsDir, targetSkillsDir, tool2) {
|
|
|
16398
16743
|
continue;
|
|
16399
16744
|
}
|
|
16400
16745
|
}
|
|
16401
|
-
const resolvedLinkedPath =
|
|
16746
|
+
const resolvedLinkedPath = path12.isAbsolute(linkedPath) ? linkedPath : path12.resolve(path12.dirname(target), linkedPath);
|
|
16402
16747
|
const linkedTargetExists = await fs9.stat(resolvedLinkedPath).then(() => true).catch(() => false);
|
|
16403
16748
|
if (!linkedTargetExists) {
|
|
16404
16749
|
await fs9.unlink(target);
|
|
@@ -16623,7 +16968,7 @@ function registerAgentCommands(program) {
|
|
|
16623
16968
|
if (opts.markdown && opts.markdownFile) {
|
|
16624
16969
|
throw new Error("Pass only one of --markdown or --markdown-file.");
|
|
16625
16970
|
}
|
|
16626
|
-
const markdown = opts.markdownFile ? await fs9.readFile(
|
|
16971
|
+
const markdown = opts.markdownFile ? await fs9.readFile(path12.resolve(opts.markdownFile), "utf8") : opts.markdown;
|
|
16627
16972
|
const payload = organizationSkillCreateSchema.parse({
|
|
16628
16973
|
name: opts.name,
|
|
16629
16974
|
slug: opts.slug?.trim() || null,
|
|
@@ -16802,7 +17147,7 @@ function registerAgentCommands(program) {
|
|
|
16802
17147
|
}
|
|
16803
17148
|
const installSummaries = [];
|
|
16804
17149
|
if (opts.installSkills !== false) {
|
|
16805
|
-
const skillsDir = await resolveRudderSkillsDir(__moduleDir, [
|
|
17150
|
+
const skillsDir = await resolveRudderSkillsDir(__moduleDir, [path12.resolve(process.cwd(), "skills")]);
|
|
16806
17151
|
if (!skillsDir) {
|
|
16807
17152
|
throw new Error(
|
|
16808
17153
|
"Could not locate local Rudder skills directory. Expected ./skills in the repo checkout."
|
|
@@ -16890,10 +17235,10 @@ async function buildAgentUpdatePatch(opts) {
|
|
|
16890
17235
|
if (opts.capabilities !== void 0) rawPatch.capabilities = opts.capabilities;
|
|
16891
17236
|
if (opts.description !== void 0) rawPatch.capabilities = opts.description;
|
|
16892
17237
|
if (opts.capabilitiesFile !== void 0) {
|
|
16893
|
-
rawPatch.capabilities = await fs9.readFile(
|
|
17238
|
+
rawPatch.capabilities = await fs9.readFile(path12.resolve(opts.capabilitiesFile), "utf8");
|
|
16894
17239
|
}
|
|
16895
17240
|
if (opts.descriptionFile !== void 0) {
|
|
16896
|
-
rawPatch.capabilities = await fs9.readFile(
|
|
17241
|
+
rawPatch.capabilities = await fs9.readFile(path12.resolve(opts.descriptionFile), "utf8");
|
|
16897
17242
|
}
|
|
16898
17243
|
if (clearCapabilities) rawPatch.capabilities = null;
|
|
16899
17244
|
return updateAgentSchema.parse(rawPatch);
|
|
@@ -16917,7 +17262,7 @@ function parseJsonObject(value, name) {
|
|
|
16917
17262
|
// src/commands/client/approval.ts
|
|
16918
17263
|
init_dist2();
|
|
16919
17264
|
import { readFile as readFile2 } from "node:fs/promises";
|
|
16920
|
-
import
|
|
17265
|
+
import path13 from "node:path";
|
|
16921
17266
|
function registerApprovalCommands(program) {
|
|
16922
17267
|
const approval = program.command("approval").description("Approval operations");
|
|
16923
17268
|
addCommonClientOptions(
|
|
@@ -17108,7 +17453,7 @@ async function readTextInputFile(inputPath, optionName) {
|
|
|
17108
17453
|
if (inputPath === "-") {
|
|
17109
17454
|
return readStdinText();
|
|
17110
17455
|
}
|
|
17111
|
-
const resolvedPath =
|
|
17456
|
+
const resolvedPath = path13.resolve(process.cwd(), inputPath);
|
|
17112
17457
|
return readFile2(resolvedPath, "utf8").catch((err) => {
|
|
17113
17458
|
throw new Error(`Unable to read ${optionName} ${inputPath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
17114
17459
|
});
|
|
@@ -17945,12 +18290,12 @@ async function readStdin() {
|
|
|
17945
18290
|
|
|
17946
18291
|
// src/commands/client/company.ts
|
|
17947
18292
|
import * as p3 from "@clack/prompts";
|
|
17948
|
-
import { mkdir as
|
|
17949
|
-
import
|
|
18293
|
+
import { mkdir as mkdir2, readdir as readdir2, readFile as readFile3, stat as stat2, writeFile as writeFile2 } from "node:fs/promises";
|
|
18294
|
+
import path15 from "node:path";
|
|
17950
18295
|
import pc5 from "picocolors";
|
|
17951
18296
|
|
|
17952
18297
|
// src/commands/client/zip.ts
|
|
17953
|
-
import
|
|
18298
|
+
import path14 from "node:path";
|
|
17954
18299
|
import { inflateRawSync } from "node:zlib";
|
|
17955
18300
|
var textDecoder = new TextDecoder();
|
|
17956
18301
|
var binaryContentTypeByExtension = {
|
|
@@ -17978,7 +18323,7 @@ function sharedArchiveRoot(paths) {
|
|
|
17978
18323
|
return firstSegments.every((parts) => parts.length > 1 && parts[0] === candidate) ? candidate : null;
|
|
17979
18324
|
}
|
|
17980
18325
|
function bytesToPortableFileEntry(pathValue, bytes) {
|
|
17981
|
-
const contentType = binaryContentTypeByExtension[
|
|
18326
|
+
const contentType = binaryContentTypeByExtension[path14.extname(pathValue).toLowerCase()];
|
|
17982
18327
|
if (!contentType) return textDecoder.decode(bytes);
|
|
17983
18328
|
return {
|
|
17984
18329
|
encoding: "base64",
|
|
@@ -18066,7 +18411,7 @@ var IMPORT_INCLUDE_OPTIONS = [
|
|
|
18066
18411
|
];
|
|
18067
18412
|
var IMPORT_PREVIEW_SAMPLE_LIMIT = 6;
|
|
18068
18413
|
function readPortableFileEntry(filePath, contents) {
|
|
18069
|
-
const contentType = binaryContentTypeByExtension[
|
|
18414
|
+
const contentType = binaryContentTypeByExtension[path15.extname(filePath).toLowerCase()];
|
|
18070
18415
|
if (!contentType) return contents.toString("utf8");
|
|
18071
18416
|
return {
|
|
18072
18417
|
encoding: "base64",
|
|
@@ -18121,10 +18466,10 @@ function normalizePortablePath(filePath) {
|
|
|
18121
18466
|
return filePath.replace(/\\/g, "/");
|
|
18122
18467
|
}
|
|
18123
18468
|
function shouldIncludePortableFile(filePath) {
|
|
18124
|
-
const baseName =
|
|
18469
|
+
const baseName = path15.basename(filePath);
|
|
18125
18470
|
const isMarkdown = baseName.endsWith(".md");
|
|
18126
18471
|
const isPaperclipYaml = baseName === ".rudder.yaml" || baseName === ".rudder.yml";
|
|
18127
|
-
const contentType = binaryContentTypeByExtension[
|
|
18472
|
+
const contentType = binaryContentTypeByExtension[path15.extname(baseName).toLowerCase()];
|
|
18128
18473
|
return isMarkdown || isPaperclipYaml || Boolean(contentType);
|
|
18129
18474
|
}
|
|
18130
18475
|
function findPortableExtensionPath(files) {
|
|
@@ -18679,7 +19024,7 @@ function normalizeGithubImportSource(input, refOverride) {
|
|
|
18679
19024
|
}
|
|
18680
19025
|
async function pathExists(inputPath) {
|
|
18681
19026
|
try {
|
|
18682
|
-
await
|
|
19027
|
+
await stat2(path15.resolve(inputPath));
|
|
18683
19028
|
return true;
|
|
18684
19029
|
} catch {
|
|
18685
19030
|
return false;
|
|
@@ -18689,45 +19034,45 @@ async function collectPackageFiles(root, current, files) {
|
|
|
18689
19034
|
const entries = await readdir2(current, { withFileTypes: true });
|
|
18690
19035
|
for (const entry of entries) {
|
|
18691
19036
|
if (entry.name.startsWith(".git")) continue;
|
|
18692
|
-
const absolutePath =
|
|
19037
|
+
const absolutePath = path15.join(current, entry.name);
|
|
18693
19038
|
if (entry.isDirectory()) {
|
|
18694
19039
|
await collectPackageFiles(root, absolutePath, files);
|
|
18695
19040
|
continue;
|
|
18696
19041
|
}
|
|
18697
19042
|
if (!entry.isFile()) continue;
|
|
18698
|
-
const relativePath =
|
|
19043
|
+
const relativePath = path15.relative(root, absolutePath).replace(/\\/g, "/");
|
|
18699
19044
|
if (!shouldIncludePortableFile(relativePath)) continue;
|
|
18700
19045
|
files[relativePath] = readPortableFileEntry(relativePath, await readFile3(absolutePath));
|
|
18701
19046
|
}
|
|
18702
19047
|
}
|
|
18703
19048
|
async function resolveInlineSourceFromPath(inputPath) {
|
|
18704
|
-
const resolved =
|
|
18705
|
-
const resolvedStat = await
|
|
18706
|
-
if (resolvedStat.isFile() &&
|
|
19049
|
+
const resolved = path15.resolve(inputPath);
|
|
19050
|
+
const resolvedStat = await stat2(resolved);
|
|
19051
|
+
if (resolvedStat.isFile() && path15.extname(resolved).toLowerCase() === ".zip") {
|
|
18707
19052
|
const archive = await readZipArchive(await readFile3(resolved));
|
|
18708
19053
|
const filteredFiles = Object.fromEntries(
|
|
18709
19054
|
Object.entries(archive.files).filter(([relativePath]) => shouldIncludePortableFile(relativePath))
|
|
18710
19055
|
);
|
|
18711
19056
|
return {
|
|
18712
|
-
rootPath: archive.rootPath ??
|
|
19057
|
+
rootPath: archive.rootPath ?? path15.basename(resolved, ".zip"),
|
|
18713
19058
|
files: filteredFiles
|
|
18714
19059
|
};
|
|
18715
19060
|
}
|
|
18716
|
-
const rootDir = resolvedStat.isDirectory() ? resolved :
|
|
19061
|
+
const rootDir = resolvedStat.isDirectory() ? resolved : path15.dirname(resolved);
|
|
18717
19062
|
const files = {};
|
|
18718
19063
|
await collectPackageFiles(rootDir, rootDir, files);
|
|
18719
19064
|
return {
|
|
18720
|
-
rootPath:
|
|
19065
|
+
rootPath: path15.basename(rootDir),
|
|
18721
19066
|
files
|
|
18722
19067
|
};
|
|
18723
19068
|
}
|
|
18724
19069
|
async function writeExportToFolder(outDir, exported) {
|
|
18725
|
-
const root =
|
|
18726
|
-
await
|
|
19070
|
+
const root = path15.resolve(outDir);
|
|
19071
|
+
await mkdir2(root, { recursive: true });
|
|
18727
19072
|
for (const [relativePath, content] of Object.entries(exported.files)) {
|
|
18728
19073
|
const normalized = relativePath.replace(/\\/g, "/");
|
|
18729
|
-
const filePath =
|
|
18730
|
-
await
|
|
19074
|
+
const filePath = path15.join(root, normalized);
|
|
19075
|
+
await mkdir2(path15.dirname(filePath), { recursive: true });
|
|
18731
19076
|
const writeValue = portableFileEntryToWriteValue(content);
|
|
18732
19077
|
if (typeof writeValue === "string") {
|
|
18733
19078
|
await writeFile2(filePath, writeValue, "utf8");
|
|
@@ -18737,8 +19082,8 @@ async function writeExportToFolder(outDir, exported) {
|
|
|
18737
19082
|
}
|
|
18738
19083
|
}
|
|
18739
19084
|
async function confirmOverwriteExportDirectory(outDir) {
|
|
18740
|
-
const root =
|
|
18741
|
-
const stats = await
|
|
19085
|
+
const root = path15.resolve(outDir);
|
|
19086
|
+
const stats = await stat2(root).catch(() => null);
|
|
18742
19087
|
if (!stats) return;
|
|
18743
19088
|
if (!stats.isDirectory()) {
|
|
18744
19089
|
throw new Error(`Export output path ${root} exists and is not a directory.`);
|
|
@@ -18919,7 +19264,7 @@ function registerCompanyCommands(program) {
|
|
|
18919
19264
|
printOutput(
|
|
18920
19265
|
{
|
|
18921
19266
|
ok: true,
|
|
18922
|
-
out:
|
|
19267
|
+
out: path15.resolve(opts.out),
|
|
18923
19268
|
rootPath: exported.rootPath,
|
|
18924
19269
|
filesWritten: Object.keys(exported.files).length,
|
|
18925
19270
|
rudderExtensionPath: exported.rudderExtensionPath,
|
|
@@ -19417,8 +19762,8 @@ function parseResultValue(value) {
|
|
|
19417
19762
|
|
|
19418
19763
|
// src/commands/client/issue.ts
|
|
19419
19764
|
init_dist2();
|
|
19420
|
-
import { readFile as readFile4, stat as
|
|
19421
|
-
import
|
|
19765
|
+
import { readFile as readFile4, stat as stat3 } from "node:fs/promises";
|
|
19766
|
+
import path16 from "node:path";
|
|
19422
19767
|
function registerIssueCommands(program) {
|
|
19423
19768
|
const issue = program.command("issue").description("Issue operations");
|
|
19424
19769
|
addCommonClientOptions(
|
|
@@ -19782,7 +20127,7 @@ async function readTextInputFile2(inputPath, optionName) {
|
|
|
19782
20127
|
if (inputPath === "-") {
|
|
19783
20128
|
return readStdinText2();
|
|
19784
20129
|
}
|
|
19785
|
-
const resolvedPath =
|
|
20130
|
+
const resolvedPath = path16.resolve(process.cwd(), inputPath);
|
|
19786
20131
|
return readFile4(resolvedPath, "utf8").catch((err) => {
|
|
19787
20132
|
throw new Error(`Unable to read ${optionName} ${inputPath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
19788
20133
|
});
|
|
@@ -19839,14 +20184,14 @@ async function appendUploadedIssueImages(ctx, issueId, body, imagePaths) {
|
|
|
19839
20184
|
${imageBlock}` : imageBlock;
|
|
19840
20185
|
}
|
|
19841
20186
|
async function uploadIssueCommentImage(ctx, issue, imagePath) {
|
|
19842
|
-
const resolvedPath =
|
|
19843
|
-
const stats = await
|
|
20187
|
+
const resolvedPath = path16.resolve(process.cwd(), imagePath);
|
|
20188
|
+
const stats = await stat3(resolvedPath).catch((err) => {
|
|
19844
20189
|
throw new Error(`Unable to read image ${imagePath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
19845
20190
|
});
|
|
19846
20191
|
if (!stats.isFile()) {
|
|
19847
20192
|
throw new Error(`Image path must be a file: ${imagePath}`);
|
|
19848
20193
|
}
|
|
19849
|
-
const filename =
|
|
20194
|
+
const filename = path16.basename(resolvedPath);
|
|
19850
20195
|
const contentType = inferCommentImageContentType(filename);
|
|
19851
20196
|
const buffer = await readFile4(resolvedPath);
|
|
19852
20197
|
if (buffer.length <= 0) {
|
|
@@ -19865,7 +20210,7 @@ async function uploadIssueCommentImage(ctx, issue, imagePath) {
|
|
|
19865
20210
|
return attachment;
|
|
19866
20211
|
}
|
|
19867
20212
|
function inferCommentImageContentType(filename) {
|
|
19868
|
-
const ext =
|
|
20213
|
+
const ext = path16.extname(filename).toLowerCase();
|
|
19869
20214
|
switch (ext) {
|
|
19870
20215
|
case ".png":
|
|
19871
20216
|
return "image/png";
|
|
@@ -19969,7 +20314,7 @@ function formatIssueSearchMatch(match) {
|
|
|
19969
20314
|
|
|
19970
20315
|
// src/commands/client/library.ts
|
|
19971
20316
|
import { readFile as readFile5 } from "node:fs/promises";
|
|
19972
|
-
import
|
|
20317
|
+
import path17 from "node:path";
|
|
19973
20318
|
function toLibraryFileLinkResult(detail) {
|
|
19974
20319
|
return {
|
|
19975
20320
|
filePath: detail.filePath,
|
|
@@ -20114,7 +20459,7 @@ async function resolveBodyFileInput(inputPath) {
|
|
|
20114
20459
|
if (inputPath === "-") {
|
|
20115
20460
|
return readStdinText3();
|
|
20116
20461
|
}
|
|
20117
|
-
const resolvedPath =
|
|
20462
|
+
const resolvedPath = path17.resolve(process.cwd(), inputPath);
|
|
20118
20463
|
return readFile5(resolvedPath, "utf8").catch((err) => {
|
|
20119
20464
|
throw new Error(`Unable to read --body-file ${inputPath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
20120
20465
|
});
|
|
@@ -20873,8 +21218,8 @@ function registerUserCommands(program) {
|
|
|
20873
21218
|
appendParam(params, "limit", opts.limit);
|
|
20874
21219
|
appendParam(params, "cursor", opts.cursor);
|
|
20875
21220
|
const query = params.toString();
|
|
20876
|
-
const
|
|
20877
|
-
const result = await ctx.api.get(
|
|
21221
|
+
const path25 = `/api/orgs/${ctx.orgId}/users/${encodeURIComponent(userId)}/activity-ledger${query ? `?${query}` : ""}`;
|
|
21222
|
+
const result = await ctx.api.get(path25);
|
|
20878
21223
|
if (ctx.json) {
|
|
20879
21224
|
printOutput(result, { json: true });
|
|
20880
21225
|
return;
|
|
@@ -21691,9 +22036,9 @@ import * as p15 from "@clack/prompts";
|
|
|
21691
22036
|
import { spawn as spawn3, spawnSync as spawnSync4 } from "node:child_process";
|
|
21692
22037
|
import { createHash as createHash4, randomUUID } from "node:crypto";
|
|
21693
22038
|
import { constants as fsConstants, mkdirSync as mkdirSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
21694
|
-
import { access, chmod
|
|
22039
|
+
import { access, chmod as chmod2, copyFile, cp, lstat, mkdir as mkdir3, mkdtemp as mkdtemp2, readdir as readdir3, readFile as readFile6, rm as rm3, stat as stat4, utimes, writeFile as writeFile3 } from "node:fs/promises";
|
|
21695
22040
|
import { homedir, tmpdir } from "node:os";
|
|
21696
|
-
import
|
|
22041
|
+
import path23 from "node:path";
|
|
21697
22042
|
import { clearTimeout as clearTimeout3, setTimeout as setTimeout3 } from "node:timers";
|
|
21698
22043
|
import { setTimeout as delay2 } from "node:timers/promises";
|
|
21699
22044
|
import pc14 from "picocolors";
|
|
@@ -21722,11 +22067,11 @@ init_home();
|
|
|
21722
22067
|
|
|
21723
22068
|
// src/desktop-download.ts
|
|
21724
22069
|
import { createHash as createHash3 } from "node:crypto";
|
|
21725
|
-
import { createWriteStream as
|
|
22070
|
+
import { createWriteStream as createWriteStream3, mkdirSync } from "node:fs";
|
|
21726
22071
|
import { rm as rm2 } from "node:fs/promises";
|
|
21727
|
-
import
|
|
22072
|
+
import path22 from "node:path";
|
|
21728
22073
|
import { Readable as Readable2, Transform as Transform2 } from "node:stream";
|
|
21729
|
-
import { pipeline as
|
|
22074
|
+
import { pipeline as pipeline3 } from "node:stream/promises";
|
|
21730
22075
|
import { clearTimeout as clearTimeout2, setTimeout as setTimeout2 } from "node:timers";
|
|
21731
22076
|
|
|
21732
22077
|
// src/utils/progress.ts
|
|
@@ -21964,7 +22309,7 @@ async function resolveDesktopDownloadOrigins(options) {
|
|
|
21964
22309
|
}
|
|
21965
22310
|
async function downloadAsset(asset, outputDir, progressFactory = createByteProgress, expectedChecksum, timeouts = {}) {
|
|
21966
22311
|
mkdirSync(outputDir, { recursive: true });
|
|
21967
|
-
const outputPath =
|
|
22312
|
+
const outputPath = path22.join(outputDir, path22.basename(asset.name));
|
|
21968
22313
|
const idleTimeoutMs = timeouts.idleMs ?? DESKTOP_ASSET_IDLE_TIMEOUT_MS;
|
|
21969
22314
|
const responseTimeoutMs = timeouts.responseMs ?? DESKTOP_ASSET_RESPONSE_TIMEOUT_MS;
|
|
21970
22315
|
const failures = [];
|
|
@@ -22004,7 +22349,7 @@ async function downloadAsset(asset, outputDir, progressFactory = createByteProgr
|
|
|
22004
22349
|
});
|
|
22005
22350
|
progress.start(totalBytes);
|
|
22006
22351
|
armIdleTimeout();
|
|
22007
|
-
await
|
|
22352
|
+
await pipeline3(Readable2.fromWeb(response.body), monitor, createWriteStream3(outputPath));
|
|
22008
22353
|
if (idleTimeout) clearTimeout2(idleTimeout);
|
|
22009
22354
|
idleTimeout = null;
|
|
22010
22355
|
const actualChecksum = hash.digest("hex");
|
|
@@ -22068,6 +22413,15 @@ var DEFAULT_DESKTOP_ASSET_CACHE_MAX_BYTES = 768 * 1024 * 1024;
|
|
|
22068
22413
|
var DEFAULT_DESKTOP_ASSET_CACHE_KEEP_PREVIOUS = 1;
|
|
22069
22414
|
var DESKTOP_INSTALL_LOCK_TIMEOUT_MS = 60 * 60 * 1e3;
|
|
22070
22415
|
var DESKTOP_INSTALL_LOCK_POLL_MS = 250;
|
|
22416
|
+
var DESKTOP_RUNTIME_PREPARE_TIMEOUT_MS = 9e4;
|
|
22417
|
+
async function waitForDesktopRuntimeSmokeEvidence(envName) {
|
|
22418
|
+
if (process.env.RUDDER_DESKTOP_SMOKE_AUTO_UPDATE_PUBLIC !== "1") return;
|
|
22419
|
+
const value = Number(process.env[envName]);
|
|
22420
|
+
if (!Number.isFinite(value) || value <= 0) return;
|
|
22421
|
+
await delay2(Math.min(value, 1e4));
|
|
22422
|
+
}
|
|
22423
|
+
var DEFAULT_GITHUB_API_BASE_URL = "https://api.github.com";
|
|
22424
|
+
var DEFAULT_GITHUB_DOWNLOAD_BASE_URL = "https://github.com";
|
|
22071
22425
|
function normalizeProgressTotal(totalBytes) {
|
|
22072
22426
|
return typeof totalBytes === "number" && Number.isFinite(totalBytes) && totalBytes > 0 ? totalBytes : null;
|
|
22073
22427
|
}
|
|
@@ -22291,38 +22645,38 @@ function resolveDesktopAssetTarget(platform = process.platform, arch = process.a
|
|
|
22291
22645
|
throw new Error(`Rudder Desktop does not publish portable assets for ${platform}.`);
|
|
22292
22646
|
}
|
|
22293
22647
|
function resolveDefaultDesktopInstallRoot(target, env = process.env, homeDir = homedir()) {
|
|
22294
|
-
if (target.platform === "macos") return
|
|
22648
|
+
if (target.platform === "macos") return path23.join(homeDir, "Applications");
|
|
22295
22649
|
if (target.platform === "windows") {
|
|
22296
|
-
const localAppData = env.LOCALAPPDATA?.trim() ||
|
|
22297
|
-
return
|
|
22650
|
+
const localAppData = env.LOCALAPPDATA?.trim() || path23.join(homeDir, "AppData", "Local");
|
|
22651
|
+
return path23.join(localAppData, "Programs", DESKTOP_APP_NAME);
|
|
22298
22652
|
}
|
|
22299
|
-
return
|
|
22653
|
+
return path23.join(homeDir, ".local", "share", "rudder");
|
|
22300
22654
|
}
|
|
22301
22655
|
function resolveDesktopInstallPaths(target, installRoot) {
|
|
22302
|
-
const root =
|
|
22656
|
+
const root = path23.resolve(installRoot);
|
|
22303
22657
|
if (target.platform === "macos") {
|
|
22304
|
-
const appPath2 =
|
|
22658
|
+
const appPath2 = path23.join(root, `${DESKTOP_APP_NAME}.app`);
|
|
22305
22659
|
return {
|
|
22306
22660
|
installRoot: root,
|
|
22307
22661
|
appPath: appPath2,
|
|
22308
|
-
executablePath:
|
|
22309
|
-
metadataPath:
|
|
22662
|
+
executablePath: path23.join(appPath2, "Contents", "MacOS", DESKTOP_APP_NAME),
|
|
22663
|
+
metadataPath: path23.join(root, DESKTOP_METADATA_FILE)
|
|
22310
22664
|
};
|
|
22311
22665
|
}
|
|
22312
22666
|
if (target.platform === "windows") {
|
|
22313
22667
|
return {
|
|
22314
22668
|
installRoot: root,
|
|
22315
22669
|
appPath: root,
|
|
22316
|
-
executablePath:
|
|
22317
|
-
metadataPath:
|
|
22670
|
+
executablePath: path23.join(root, `${DESKTOP_APP_NAME}.exe`),
|
|
22671
|
+
metadataPath: path23.join(root, DESKTOP_METADATA_FILE)
|
|
22318
22672
|
};
|
|
22319
22673
|
}
|
|
22320
|
-
const appPath =
|
|
22674
|
+
const appPath = path23.join(root, `${DESKTOP_APP_NAME}.AppImage`);
|
|
22321
22675
|
return {
|
|
22322
22676
|
installRoot: root,
|
|
22323
22677
|
appPath,
|
|
22324
22678
|
executablePath: appPath,
|
|
22325
|
-
metadataPath:
|
|
22679
|
+
metadataPath: path23.join(root, DESKTOP_METADATA_FILE)
|
|
22326
22680
|
};
|
|
22327
22681
|
}
|
|
22328
22682
|
function normalizeAssetName(name) {
|
|
@@ -22381,10 +22735,20 @@ function resolveDesktopAssetCandidates(options) {
|
|
|
22381
22735
|
const candidates = [];
|
|
22382
22736
|
const deterministicShellName = options.directReleaseVersion ? resolveDesktopShellAssetName(options.directReleaseVersion, options.target) : null;
|
|
22383
22737
|
if (options.allowShellAssets !== false) {
|
|
22384
|
-
const shellAsset = selectDesktopShellAsset(options.releaseAssets, options.target) ?? (options.releaseAssets.length === 0 && deterministicShellName ? buildGithubReleaseAsset(
|
|
22738
|
+
const shellAsset = selectDesktopShellAsset(options.releaseAssets, options.target) ?? (options.releaseAssets.length === 0 && deterministicShellName ? buildGithubReleaseAsset(
|
|
22739
|
+
options.repo,
|
|
22740
|
+
options.tag,
|
|
22741
|
+
deterministicShellName,
|
|
22742
|
+
options.downloadBaseUrl
|
|
22743
|
+
) : null);
|
|
22385
22744
|
if (shellAsset) candidates.push({ asset: shellAsset, kind: "shell" });
|
|
22386
22745
|
}
|
|
22387
|
-
const fullAsset = selectDesktopAsset(options.releaseAssets, options.target) ?? (options.directReleaseVersion ? buildGithubReleaseAsset(
|
|
22746
|
+
const fullAsset = selectDesktopAsset(options.releaseAssets, options.target) ?? (options.directReleaseVersion ? buildGithubReleaseAsset(
|
|
22747
|
+
options.repo,
|
|
22748
|
+
options.tag,
|
|
22749
|
+
resolveDesktopAssetName(options.directReleaseVersion, options.target),
|
|
22750
|
+
options.downloadBaseUrl
|
|
22751
|
+
) : null);
|
|
22388
22752
|
if (fullAsset) candidates.push({ asset: fullAsset, kind: "full" });
|
|
22389
22753
|
return candidates;
|
|
22390
22754
|
}
|
|
@@ -22428,8 +22792,35 @@ function githubApiHeaders() {
|
|
|
22428
22792
|
};
|
|
22429
22793
|
}
|
|
22430
22794
|
var GITHUB_API_TIMEOUT_MS = 15e3;
|
|
22431
|
-
|
|
22432
|
-
|
|
22795
|
+
function resolveDesktopSmokeReleaseBaseUrls(env = process.env) {
|
|
22796
|
+
if (env.RUDDER_DESKTOP_SMOKE_AUTO_UPDATE_PUBLIC !== "1") {
|
|
22797
|
+
return {
|
|
22798
|
+
apiBaseUrl: DEFAULT_GITHUB_API_BASE_URL,
|
|
22799
|
+
downloadBaseUrl: DEFAULT_GITHUB_DOWNLOAD_BASE_URL
|
|
22800
|
+
};
|
|
22801
|
+
}
|
|
22802
|
+
const normalizeBaseUrl = (value, fallback) => {
|
|
22803
|
+
const configured = value?.trim();
|
|
22804
|
+
if (!configured) return fallback;
|
|
22805
|
+
const parsed = new URL(configured);
|
|
22806
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
22807
|
+
throw new Error(`Desktop smoke release base URL must use HTTP or HTTPS: ${configured}`);
|
|
22808
|
+
}
|
|
22809
|
+
return configured.replace(/\/+$/u, "");
|
|
22810
|
+
};
|
|
22811
|
+
return {
|
|
22812
|
+
apiBaseUrl: normalizeBaseUrl(
|
|
22813
|
+
env.RUDDER_DESKTOP_SMOKE_RELEASE_API_BASE_URL,
|
|
22814
|
+
DEFAULT_GITHUB_API_BASE_URL
|
|
22815
|
+
),
|
|
22816
|
+
downloadBaseUrl: normalizeBaseUrl(
|
|
22817
|
+
env.RUDDER_DESKTOP_SMOKE_RELEASE_DOWNLOAD_BASE_URL,
|
|
22818
|
+
DEFAULT_GITHUB_DOWNLOAD_BASE_URL
|
|
22819
|
+
)
|
|
22820
|
+
};
|
|
22821
|
+
}
|
|
22822
|
+
async function fetchGithubRelease(repo, tag, apiBaseUrl = DEFAULT_GITHUB_API_BASE_URL) {
|
|
22823
|
+
const endpoint = tag === "latest" ? `${apiBaseUrl}/repos/${repo}/releases/latest` : `${apiBaseUrl}/repos/${repo}/releases/tags/${encodeURIComponent(tag)}`;
|
|
22433
22824
|
const response = await fetchWithTimeout2(endpoint, { headers: githubApiHeaders() }, GITHUB_API_TIMEOUT_MS);
|
|
22434
22825
|
if (!response.ok) {
|
|
22435
22826
|
throw new Error(`GitHub Release ${tag} was not found in ${repo} (${response.status}).`);
|
|
@@ -22457,14 +22848,14 @@ function resolveDesktopShellAssetName(version, target) {
|
|
|
22457
22848
|
function encodeReleaseTagForDownloadUrl2(tag) {
|
|
22458
22849
|
return tag.split("/").map((segment) => encodeURIComponent(segment)).join("/");
|
|
22459
22850
|
}
|
|
22460
|
-
function buildGithubReleaseAssetDownloadUrl(repo, tag, assetName) {
|
|
22851
|
+
function buildGithubReleaseAssetDownloadUrl(repo, tag, assetName, downloadBaseUrl = DEFAULT_GITHUB_DOWNLOAD_BASE_URL) {
|
|
22461
22852
|
const encodedTag = encodeReleaseTagForDownloadUrl2(tag);
|
|
22462
|
-
return
|
|
22853
|
+
return `${downloadBaseUrl}/${repo}/releases/download/${encodedTag}/${encodeURIComponent(assetName)}`;
|
|
22463
22854
|
}
|
|
22464
|
-
function buildGithubReleaseAsset(repo, tag, assetName) {
|
|
22855
|
+
function buildGithubReleaseAsset(repo, tag, assetName, downloadBaseUrl) {
|
|
22465
22856
|
return {
|
|
22466
22857
|
name: assetName,
|
|
22467
|
-
browser_download_url: buildGithubReleaseAssetDownloadUrl(repo, tag, assetName)
|
|
22858
|
+
browser_download_url: buildGithubReleaseAssetDownloadUrl(repo, tag, assetName, downloadBaseUrl)
|
|
22468
22859
|
};
|
|
22469
22860
|
}
|
|
22470
22861
|
function checksumForFile(filePath) {
|
|
@@ -22473,16 +22864,16 @@ function checksumForFile(filePath) {
|
|
|
22473
22864
|
return hash.digest("hex");
|
|
22474
22865
|
}
|
|
22475
22866
|
function resolveAssetChecksum(checksums, assetName) {
|
|
22476
|
-
const expected = checksums.get(
|
|
22867
|
+
const expected = checksums.get(path23.basename(assetName));
|
|
22477
22868
|
if (!expected) {
|
|
22478
|
-
throw new Error(`Desktop release checksums do not include ${
|
|
22869
|
+
throw new Error(`Desktop release checksums do not include ${path23.basename(assetName)}.`);
|
|
22479
22870
|
}
|
|
22480
22871
|
return expected;
|
|
22481
22872
|
}
|
|
22482
22873
|
function assertChecksumMatch(filePath, expected) {
|
|
22483
22874
|
const actual = checksumForFile(filePath);
|
|
22484
22875
|
if (actual !== expected.toLowerCase()) {
|
|
22485
|
-
throw new Error(`Checksum mismatch for ${
|
|
22876
|
+
throw new Error(`Checksum mismatch for ${path23.basename(filePath)}.`);
|
|
22486
22877
|
}
|
|
22487
22878
|
return actual;
|
|
22488
22879
|
}
|
|
@@ -22501,10 +22892,10 @@ function normalizeDesktopAssetChecksum(checksum) {
|
|
|
22501
22892
|
return normalized;
|
|
22502
22893
|
}
|
|
22503
22894
|
function resolveDesktopAssetCacheDir(assetChecksum, homeDir = resolveRudderHomeDir()) {
|
|
22504
|
-
return
|
|
22895
|
+
return path23.join(homeDir, DESKTOP_ASSET_CACHE_DIR, normalizeDesktopAssetChecksum(assetChecksum));
|
|
22505
22896
|
}
|
|
22506
22897
|
function resolveDesktopCachedAssetPath(assetName, assetChecksum, homeDir = resolveRudderHomeDir()) {
|
|
22507
|
-
return
|
|
22898
|
+
return path23.join(resolveDesktopAssetCacheDir(assetChecksum, homeDir), path23.basename(assetName));
|
|
22508
22899
|
}
|
|
22509
22900
|
async function pruneDesktopAssetCache(options = {}) {
|
|
22510
22901
|
const homeDir = options.homeDir ?? resolveRudderHomeDir();
|
|
@@ -22550,7 +22941,7 @@ async function maybePruneDesktopAssetCache(options) {
|
|
|
22550
22941
|
return result.deleted.length > 0 || result.warnings.length > 0 ? result : null;
|
|
22551
22942
|
}
|
|
22552
22943
|
async function scanDesktopAssetCacheEntries(homeDir) {
|
|
22553
|
-
const cacheRoot =
|
|
22944
|
+
const cacheRoot = path23.join(homeDir, DESKTOP_ASSET_CACHE_DIR);
|
|
22554
22945
|
const dirents = await readdir3(cacheRoot, { withFileTypes: true }).catch(() => null);
|
|
22555
22946
|
if (!dirents) return [];
|
|
22556
22947
|
const entries = [];
|
|
@@ -22562,7 +22953,7 @@ async function scanDesktopAssetCacheEntries(homeDir) {
|
|
|
22562
22953
|
} catch {
|
|
22563
22954
|
continue;
|
|
22564
22955
|
}
|
|
22565
|
-
const cacheDir =
|
|
22956
|
+
const cacheDir = path23.join(cacheRoot, dirent.name);
|
|
22566
22957
|
const stats = await desktopCacheDirectoryStats(cacheDir);
|
|
22567
22958
|
entries.push({
|
|
22568
22959
|
cacheDir,
|
|
@@ -22574,7 +22965,7 @@ async function scanDesktopAssetCacheEntries(homeDir) {
|
|
|
22574
22965
|
return entries;
|
|
22575
22966
|
}
|
|
22576
22967
|
async function desktopCacheDirectoryStats(targetPath) {
|
|
22577
|
-
const fallbackStat = await
|
|
22968
|
+
const fallbackStat = await stat4(targetPath).catch(() => null);
|
|
22578
22969
|
const dirents = await readdir3(targetPath, { withFileTypes: true }).catch(() => null);
|
|
22579
22970
|
if (!dirents) {
|
|
22580
22971
|
return {
|
|
@@ -22586,8 +22977,8 @@ async function desktopCacheDirectoryStats(targetPath) {
|
|
|
22586
22977
|
let lastUsedAtMs = Number(fallbackStat?.mtimeMs ?? 0);
|
|
22587
22978
|
for (const dirent of dirents) {
|
|
22588
22979
|
if (dirent.isSymbolicLink()) continue;
|
|
22589
|
-
const entryPath =
|
|
22590
|
-
const entryStat = await
|
|
22980
|
+
const entryPath = path23.join(targetPath, dirent.name);
|
|
22981
|
+
const entryStat = await stat4(entryPath).catch(() => null);
|
|
22591
22982
|
if (!entryStat) continue;
|
|
22592
22983
|
lastUsedAtMs = Math.max(lastUsedAtMs, Number(entryStat.mtimeMs ?? 0));
|
|
22593
22984
|
if (dirent.isDirectory()) {
|
|
@@ -22663,14 +23054,14 @@ async function downloadDesktopAssetWithCache(asset, expectedChecksum, options =
|
|
|
22663
23054
|
await rm3(cachePath, { force: true });
|
|
22664
23055
|
}
|
|
22665
23056
|
}
|
|
22666
|
-
const outputDir = options.outputDir ?? await mkdtemp2(
|
|
23057
|
+
const outputDir = options.outputDir ?? await mkdtemp2(path23.join(tmpdir(), "rudder-desktop-installer."));
|
|
22667
23058
|
const removeOutputDir = options.outputDir ? false : true;
|
|
22668
23059
|
try {
|
|
22669
23060
|
const downloadedPath = await downloadAsset(asset, outputDir, options.progressFactory, normalizedChecksum);
|
|
22670
23061
|
const checksum = assertChecksumMatch(downloadedPath, normalizedChecksum);
|
|
22671
|
-
await
|
|
22672
|
-
if (
|
|
22673
|
-
await
|
|
23062
|
+
await mkdir3(path23.dirname(cachePath), { recursive: true });
|
|
23063
|
+
if (path23.resolve(downloadedPath) !== path23.resolve(cachePath)) {
|
|
23064
|
+
await copyFile(downloadedPath, cachePath);
|
|
22674
23065
|
}
|
|
22675
23066
|
return { path: cachePath, checksum, cacheStatus: "miss" };
|
|
22676
23067
|
} finally {
|
|
@@ -22686,8 +23077,8 @@ async function pathExists2(targetPath) {
|
|
|
22686
23077
|
}
|
|
22687
23078
|
}
|
|
22688
23079
|
function resolveDesktopInstallLockPath(paths) {
|
|
22689
|
-
const installRootHash = createHash4("sha256").update(
|
|
22690
|
-
return
|
|
23080
|
+
const installRootHash = createHash4("sha256").update(path23.resolve(paths.installRoot)).digest("hex").slice(0, 16);
|
|
23081
|
+
return path23.join(path23.dirname(paths.appPath), `.rudder-desktop-install-${installRootHash}.lock`);
|
|
22691
23082
|
}
|
|
22692
23083
|
async function readDesktopInstallLock(lockPath) {
|
|
22693
23084
|
try {
|
|
@@ -22707,17 +23098,17 @@ async function readDesktopInstallLock(lockPath) {
|
|
|
22707
23098
|
}
|
|
22708
23099
|
async function withDesktopInstallLock(paths, fn, options = {}) {
|
|
22709
23100
|
const lockPath = resolveDesktopInstallLockPath(paths);
|
|
22710
|
-
const lockDir =
|
|
23101
|
+
const lockDir = path23.dirname(lockPath);
|
|
22711
23102
|
const timeoutMs = options.timeoutMs ?? DESKTOP_INSTALL_LOCK_TIMEOUT_MS;
|
|
22712
23103
|
const pollMs = options.pollMs ?? DESKTOP_INSTALL_LOCK_POLL_MS;
|
|
22713
23104
|
const startedAt = Date.now();
|
|
22714
23105
|
const payload = {
|
|
22715
23106
|
lockId: randomUUID(),
|
|
22716
23107
|
pid: process.pid,
|
|
22717
|
-
installRoot:
|
|
23108
|
+
installRoot: path23.resolve(paths.installRoot),
|
|
22718
23109
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
22719
23110
|
};
|
|
22720
|
-
await
|
|
23111
|
+
await mkdir3(lockDir, { recursive: true });
|
|
22721
23112
|
while (true) {
|
|
22722
23113
|
try {
|
|
22723
23114
|
await writeFile3(lockPath, `${JSON.stringify(payload, null, 2)}
|
|
@@ -22774,7 +23165,7 @@ function isSuccessfulRobocopyExitCode(status) {
|
|
|
22774
23165
|
}
|
|
22775
23166
|
async function extractZip(zipPath, outputDir, target) {
|
|
22776
23167
|
await rm3(outputDir, { recursive: true, force: true });
|
|
22777
|
-
await
|
|
23168
|
+
await mkdir3(outputDir, { recursive: true });
|
|
22778
23169
|
if (target.platform === "macos") {
|
|
22779
23170
|
runChecked("ditto", ["-x", "-k", zipPath, outputDir]);
|
|
22780
23171
|
return;
|
|
@@ -22790,7 +23181,7 @@ async function findPath(root, predicate, maxDepth = 5) {
|
|
|
22790
23181
|
async function visit(dir, depth) {
|
|
22791
23182
|
const entries = await readdir3(dir, { withFileTypes: true });
|
|
22792
23183
|
for (const entry of entries) {
|
|
22793
|
-
const fullPath =
|
|
23184
|
+
const fullPath = path23.join(dir, entry.name);
|
|
22794
23185
|
if (predicate(fullPath, entry.isDirectory())) return fullPath;
|
|
22795
23186
|
if (entry.isDirectory() && depth < maxDepth) {
|
|
22796
23187
|
const nested = await visit(fullPath, depth + 1);
|
|
@@ -22802,18 +23193,18 @@ async function findPath(root, predicate, maxDepth = 5) {
|
|
|
22802
23193
|
return await visit(root, 0);
|
|
22803
23194
|
}
|
|
22804
23195
|
async function findMacApp(extractDir) {
|
|
22805
|
-
const direct =
|
|
23196
|
+
const direct = path23.join(extractDir, `${DESKTOP_APP_NAME}.app`);
|
|
22806
23197
|
if (await pathExists2(direct)) return direct;
|
|
22807
|
-
const found = await findPath(extractDir, (filePath, isDirectory) => isDirectory &&
|
|
23198
|
+
const found = await findPath(extractDir, (filePath, isDirectory) => isDirectory && path23.basename(filePath) === `${DESKTOP_APP_NAME}.app`);
|
|
22808
23199
|
if (!found) throw new Error(`Portable macOS archive did not contain ${DESKTOP_APP_NAME}.app.`);
|
|
22809
23200
|
return found;
|
|
22810
23201
|
}
|
|
22811
23202
|
async function findWindowsAppDir(extractDir) {
|
|
22812
|
-
const direct =
|
|
23203
|
+
const direct = path23.join(extractDir, `${DESKTOP_APP_NAME}.exe`);
|
|
22813
23204
|
if (await pathExists2(direct)) return extractDir;
|
|
22814
|
-
const executable = await findPath(extractDir, (filePath, isDirectory) => !isDirectory &&
|
|
23205
|
+
const executable = await findPath(extractDir, (filePath, isDirectory) => !isDirectory && path23.basename(filePath).toLowerCase() === `${DESKTOP_APP_NAME.toLowerCase()}.exe`);
|
|
22815
23206
|
if (!executable) throw new Error(`Portable Windows archive did not contain ${DESKTOP_APP_NAME}.exe.`);
|
|
22816
|
-
return
|
|
23207
|
+
return path23.dirname(executable);
|
|
22817
23208
|
}
|
|
22818
23209
|
async function readInstallMetadata(metadataPath) {
|
|
22819
23210
|
try {
|
|
@@ -22881,7 +23272,7 @@ async function waitForUpdateQuitResponse(responsePath, timeoutMs = 8e3) {
|
|
|
22881
23272
|
}
|
|
22882
23273
|
async function requestDesktopQuit(executablePath, target, options = {}) {
|
|
22883
23274
|
if (!await pathExists2(executablePath)) return { ok: true, status: "not_running" };
|
|
22884
|
-
const responsePath =
|
|
23275
|
+
const responsePath = path23.join(tmpdir(), `rudder-update-quit-${process.pid}-${Date.now()}.json`);
|
|
22885
23276
|
const result = spawnSync4(executablePath, [
|
|
22886
23277
|
`${DESKTOP_UPDATE_QUIT_ARG}=${responsePath}`,
|
|
22887
23278
|
...options.forceUpdate ? [DESKTOP_UPDATE_FORCE_ARG] : []
|
|
@@ -23039,13 +23430,13 @@ async function prepareForDesktopReplace(paths, target, options = {}) {
|
|
|
23039
23430
|
throw new Error(`Failed to replace existing Rudder Desktop at ${replacePath}. Close Rudder and rerun start.`);
|
|
23040
23431
|
}
|
|
23041
23432
|
async function installPortableDesktop(installerPath, paths, target) {
|
|
23042
|
-
await
|
|
23433
|
+
await mkdir3(paths.installRoot, { recursive: true });
|
|
23043
23434
|
if (target.platform === "linux") {
|
|
23044
|
-
await
|
|
23045
|
-
await
|
|
23435
|
+
await copyFile(installerPath, paths.appPath);
|
|
23436
|
+
await chmod2(paths.appPath, 493);
|
|
23046
23437
|
return;
|
|
23047
23438
|
}
|
|
23048
|
-
const extractDir = await mkdtemp2(
|
|
23439
|
+
const extractDir = await mkdtemp2(path23.join(tmpdir(), "rudder-desktop-extract."));
|
|
23049
23440
|
try {
|
|
23050
23441
|
await extractZip(installerPath, extractDir, target);
|
|
23051
23442
|
if (target.platform === "macos") {
|
|
@@ -23054,7 +23445,7 @@ async function installPortableDesktop(installerPath, paths, target) {
|
|
|
23054
23445
|
return;
|
|
23055
23446
|
}
|
|
23056
23447
|
const appSource = await findWindowsAppDir(extractDir);
|
|
23057
|
-
await
|
|
23448
|
+
await mkdir3(path23.dirname(paths.installRoot), { recursive: true });
|
|
23058
23449
|
await copyPortableAppBundle(appSource, paths.installRoot);
|
|
23059
23450
|
} finally {
|
|
23060
23451
|
await rm3(extractDir, { recursive: true, force: true });
|
|
@@ -23062,7 +23453,7 @@ async function installPortableDesktop(installerPath, paths, target) {
|
|
|
23062
23453
|
}
|
|
23063
23454
|
async function copyPortableAppBundle(sourcePath, destinationPath) {
|
|
23064
23455
|
if (process.platform === "win32") {
|
|
23065
|
-
await
|
|
23456
|
+
await mkdir3(destinationPath, { recursive: true });
|
|
23066
23457
|
const command = buildWindowsRobocopyMirrorCommand(sourcePath, destinationPath);
|
|
23067
23458
|
const result = spawnSync4(command.command, command.args, {
|
|
23068
23459
|
encoding: "utf8",
|
|
@@ -23071,7 +23462,7 @@ async function copyPortableAppBundle(sourcePath, destinationPath) {
|
|
|
23071
23462
|
if (isSuccessfulRobocopyExitCode(result.status)) return;
|
|
23072
23463
|
throw new Error(formatCommandFailure(command.command, command.args, result.stdout, result.stderr));
|
|
23073
23464
|
}
|
|
23074
|
-
await
|
|
23465
|
+
await cp(sourcePath, destinationPath, { recursive: true, verbatimSymlinks: true });
|
|
23075
23466
|
}
|
|
23076
23467
|
async function removeMacQuarantine(paths, target) {
|
|
23077
23468
|
if (target.platform !== "macos") return;
|
|
@@ -23095,26 +23486,26 @@ function buildLinuxDesktopEntry(executablePath) {
|
|
|
23095
23486
|
].join("\n");
|
|
23096
23487
|
}
|
|
23097
23488
|
async function writeLinuxLaunchers(paths) {
|
|
23098
|
-
const desktopDir =
|
|
23099
|
-
await
|
|
23100
|
-
await writeFile3(
|
|
23101
|
-
const binDir =
|
|
23102
|
-
await
|
|
23103
|
-
const wrapperPath =
|
|
23489
|
+
const desktopDir = path23.join(homedir(), ".local", "share", "applications");
|
|
23490
|
+
await mkdir3(desktopDir, { recursive: true });
|
|
23491
|
+
await writeFile3(path23.join(desktopDir, "rudder.desktop"), buildLinuxDesktopEntry(paths.executablePath), "utf8");
|
|
23492
|
+
const binDir = path23.join(homedir(), ".local", "bin");
|
|
23493
|
+
await mkdir3(binDir, { recursive: true });
|
|
23494
|
+
const wrapperPath = path23.join(binDir, "rudder-desktop");
|
|
23104
23495
|
const escaped = paths.executablePath.replaceAll("'", `'"'"'`);
|
|
23105
23496
|
await writeFile3(wrapperPath, `#!/bin/sh
|
|
23106
23497
|
exec '${escaped}' "$@"
|
|
23107
23498
|
`, "utf8");
|
|
23108
|
-
await
|
|
23499
|
+
await chmod2(wrapperPath, 493);
|
|
23109
23500
|
}
|
|
23110
23501
|
function buildWindowsShortcutScript(executablePath) {
|
|
23111
|
-
const appData = process.env.APPDATA?.trim() ||
|
|
23112
|
-
const shortcutPath =
|
|
23502
|
+
const appData = process.env.APPDATA?.trim() || path23.join(homedir(), "AppData", "Roaming");
|
|
23503
|
+
const shortcutPath = path23.join(appData, "Microsoft", "Windows", "Start Menu", "Programs", "Rudder.lnk");
|
|
23113
23504
|
return [
|
|
23114
23505
|
"$shell = New-Object -ComObject WScript.Shell",
|
|
23115
23506
|
`$shortcut = $shell.CreateShortcut(${powershellQuote(shortcutPath)})`,
|
|
23116
23507
|
`$shortcut.TargetPath = ${powershellQuote(executablePath)}`,
|
|
23117
|
-
`$shortcut.WorkingDirectory = ${powershellQuote(
|
|
23508
|
+
`$shortcut.WorkingDirectory = ${powershellQuote(path23.dirname(executablePath))}`,
|
|
23118
23509
|
"$shortcut.Save()"
|
|
23119
23510
|
].join("; ");
|
|
23120
23511
|
}
|
|
@@ -23146,7 +23537,7 @@ function launchDesktop(paths, target) {
|
|
|
23146
23537
|
spawn3(paths.executablePath, [], { detached: true, stdio: "ignore" }).unref();
|
|
23147
23538
|
}
|
|
23148
23539
|
async function writeInstallMetadata(paths, releaseTag, assetName, assetChecksum, assetKind = "full") {
|
|
23149
|
-
mkdirSync2(
|
|
23540
|
+
mkdirSync2(path23.dirname(paths.metadataPath), { recursive: true });
|
|
23150
23541
|
const metadata = {
|
|
23151
23542
|
version: 1,
|
|
23152
23543
|
releaseTag,
|
|
@@ -23193,6 +23584,7 @@ async function startCommand(opts) {
|
|
|
23193
23584
|
const version = opts.targetVersion?.trim() || opts.version?.trim() || resolveCurrentCliVersion();
|
|
23194
23585
|
const dryRun = opts.dryRun === true;
|
|
23195
23586
|
const desktopProgressJson = opts.desktopProgressJson === true;
|
|
23587
|
+
const desktopRuntimeBestEffort = opts.desktopRuntimeBestEffort === true && installDesktop;
|
|
23196
23588
|
const exactDesktopAssetPath = opts.desktopAssetPath?.trim() || null;
|
|
23197
23589
|
const exactDesktopAssetChecksum = opts.desktopAssetChecksum?.trim() || null;
|
|
23198
23590
|
const exactDesktopAssetName = opts.desktopAssetName?.trim() || null;
|
|
@@ -23201,7 +23593,7 @@ async function startCommand(opts) {
|
|
|
23201
23593
|
if (!exactDesktopAssetPath || !exactDesktopAssetChecksum || !exactDesktopAssetName || !exactDesktopReleaseDigest) {
|
|
23202
23594
|
throw new Error("Exact Desktop asset mode requires path, checksum, asset name, and release digest.");
|
|
23203
23595
|
}
|
|
23204
|
-
if (!
|
|
23596
|
+
if (!path23.isAbsolute(exactDesktopAssetPath) || exactDesktopAssetName.includes("/") || !/^[a-f0-9]{64}$/iu.test(exactDesktopAssetChecksum) || !/^[a-f0-9]{64}$/iu.test(exactDesktopReleaseDigest)) {
|
|
23205
23597
|
throw new Error("Exact Desktop asset mode received invalid candidate identity.");
|
|
23206
23598
|
}
|
|
23207
23599
|
if (opts.desktopAssetKind && opts.desktopAssetKind !== "full" && opts.desktopAssetKind !== "shell") {
|
|
@@ -23224,13 +23616,29 @@ async function startCommand(opts) {
|
|
|
23224
23616
|
}
|
|
23225
23617
|
if (installRuntime) {
|
|
23226
23618
|
p15.log.step("Preparing Rudder runtime");
|
|
23619
|
+
if (desktopProgressJson && desktopRuntimeBestEffort) {
|
|
23620
|
+
writeDesktopProgress({
|
|
23621
|
+
phase: "preparing_runtime",
|
|
23622
|
+
message: "Preparing the lightweight Desktop update runtime; the full package will be used if this takes too long."
|
|
23623
|
+
});
|
|
23624
|
+
await waitForDesktopRuntimeSmokeEvidence("RUDDER_DESKTOP_SMOKE_RUNTIME_PREPARING_DELAY_MS");
|
|
23625
|
+
}
|
|
23227
23626
|
if (dryRun) {
|
|
23228
23627
|
p15.log.message(`[dry-run] Would install or reuse ${pc14.cyan(`@rudderhq/server@${version}`)} in the Rudder runtime cache.`);
|
|
23229
23628
|
} else {
|
|
23230
23629
|
const spinner3 = p15.spinner();
|
|
23231
23630
|
spinner3.start("Installing or reusing Rudder runtime...");
|
|
23232
23631
|
try {
|
|
23233
|
-
const runtime = await ensureRuntimeInstalled({
|
|
23632
|
+
const runtime = await ensureRuntimeInstalled({
|
|
23633
|
+
version,
|
|
23634
|
+
preparePostgresPayload: true,
|
|
23635
|
+
...desktopRuntimeBestEffort ? {
|
|
23636
|
+
timeoutMs: DESKTOP_RUNTIME_PREPARE_TIMEOUT_MS,
|
|
23637
|
+
cleanupIncompleteOnFailure: true,
|
|
23638
|
+
pruneRuntimeCache: false,
|
|
23639
|
+
allowLatestFallback: false
|
|
23640
|
+
} : {}
|
|
23641
|
+
});
|
|
23234
23642
|
runtimeSupportsShellAssets = runtimeSupportsDesktopShellAssets(version, runtime);
|
|
23235
23643
|
spinner3.stop(
|
|
23236
23644
|
runtime.status === "hit" ? `Rudder runtime cache hit at ${pc14.cyan(runtime.cacheDir)}.` : `Rudder runtime installed at ${pc14.cyan(runtime.cacheDir)}.`
|
|
@@ -23241,12 +23649,27 @@ async function startCommand(opts) {
|
|
|
23241
23649
|
if (!runtimeSupportsShellAssets && installDesktop) {
|
|
23242
23650
|
p15.log.warn("Rudder runtime did not resolve to the exact Desktop version; the full portable Desktop asset will be used.");
|
|
23243
23651
|
}
|
|
23652
|
+
if (desktopProgressJson && desktopRuntimeBestEffort) {
|
|
23653
|
+
writeDesktopProgress({
|
|
23654
|
+
phase: "preparing_runtime",
|
|
23655
|
+
message: runtimeSupportsShellAssets ? "Lightweight Desktop update runtime is ready." : "Lightweight runtime is unavailable; continuing with the full Desktop package."
|
|
23656
|
+
});
|
|
23657
|
+
}
|
|
23244
23658
|
} catch (error) {
|
|
23245
23659
|
spinner3.stop(pc14.red("Rudder runtime installation failed."));
|
|
23246
23660
|
if (error instanceof RuntimeInstallError && error.output) {
|
|
23247
23661
|
p15.log.message(pc14.dim(error.output));
|
|
23248
23662
|
}
|
|
23249
|
-
throw error;
|
|
23663
|
+
if (!desktopRuntimeBestEffort) throw error;
|
|
23664
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
23665
|
+
p15.log.warn(`Lightweight Desktop update runtime preparation failed; continuing with the full portable asset. ${detail}`);
|
|
23666
|
+
if (desktopProgressJson) {
|
|
23667
|
+
writeDesktopProgress({
|
|
23668
|
+
phase: "preparing_runtime",
|
|
23669
|
+
message: "Lightweight runtime preparation did not finish; continuing with the full Desktop package."
|
|
23670
|
+
});
|
|
23671
|
+
await waitForDesktopRuntimeSmokeEvidence("RUDDER_DESKTOP_SMOKE_RUNTIME_FALLBACK_DELAY_MS");
|
|
23672
|
+
}
|
|
23250
23673
|
}
|
|
23251
23674
|
}
|
|
23252
23675
|
}
|
|
@@ -23281,11 +23704,12 @@ async function startCommand(opts) {
|
|
|
23281
23704
|
if (installDesktop) {
|
|
23282
23705
|
const downloadSource = resolveDesktopDownloadSource(opts.downloadSource);
|
|
23283
23706
|
const mirrorBaseUrl = resolveDesktopReleaseMirrorBaseUrl(repo);
|
|
23707
|
+
const smokeReleaseBaseUrls = resolveDesktopSmokeReleaseBaseUrls();
|
|
23284
23708
|
const target = resolveDesktopAssetTarget();
|
|
23285
23709
|
const tag = resolveDesktopReleaseTag(version);
|
|
23286
|
-
const installRoot = opts.desktopInstallDir ?
|
|
23710
|
+
const installRoot = opts.desktopInstallDir ? path23.resolve(opts.desktopInstallDir) : resolveDefaultDesktopInstallRoot(target);
|
|
23287
23711
|
const installPaths = resolveDesktopInstallPaths(target, installRoot);
|
|
23288
|
-
const outputDir = opts.outputDir ?
|
|
23712
|
+
const outputDir = opts.outputDir ? path23.resolve(opts.outputDir) : await mkdtemp2(path23.join(tmpdir(), "rudder-desktop-installer."));
|
|
23289
23713
|
p15.log.step("Installing desktop app");
|
|
23290
23714
|
p15.log.message(`Release: ${pc14.cyan(`${repo}@${tag}`)}`);
|
|
23291
23715
|
p15.log.message(`Target: ${pc14.cyan(`${target.platform}/${target.arch}`)}`);
|
|
@@ -23325,13 +23749,13 @@ async function startCommand(opts) {
|
|
|
23325
23749
|
if (computedReleaseDigest !== exactDesktopReleaseDigest.toLowerCase()) {
|
|
23326
23750
|
throw new Error("Exact Desktop asset release digest does not match the candidate identity.");
|
|
23327
23751
|
}
|
|
23328
|
-
const descriptor = await
|
|
23752
|
+
const descriptor = await stat4(exactDesktopAssetPath);
|
|
23329
23753
|
if (!descriptor.isFile()) throw new Error("Exact Desktop asset must be a regular file.");
|
|
23330
23754
|
const linkDescriptor = await lstat(exactDesktopAssetPath);
|
|
23331
23755
|
if (linkDescriptor.isSymbolicLink()) throw new Error("Exact Desktop asset must not be a symbolic link.");
|
|
23332
23756
|
const checksum = await runStartPhase(
|
|
23333
23757
|
"Verifying staged Desktop checksum...",
|
|
23334
|
-
`Verified ${pc14.cyan(
|
|
23758
|
+
`Verified ${pc14.cyan(path23.basename(exactDesktopAssetPath))}.`,
|
|
23335
23759
|
() => assertChecksumMatch(exactDesktopAssetPath, expectedChecksum),
|
|
23336
23760
|
desktopProgressJson ? "verifying_checksum" : null
|
|
23337
23761
|
);
|
|
@@ -23343,7 +23767,7 @@ async function startCommand(opts) {
|
|
|
23343
23767
|
release = await runStartPhase(
|
|
23344
23768
|
"Resolving Desktop release...",
|
|
23345
23769
|
"Desktop release resolved.",
|
|
23346
|
-
() => fetchGithubRelease(repo, tag),
|
|
23770
|
+
() => fetchGithubRelease(repo, tag, smokeReleaseBaseUrls.apiBaseUrl),
|
|
23347
23771
|
desktopProgressJson ? "resolving_release" : null
|
|
23348
23772
|
);
|
|
23349
23773
|
} catch (error) {
|
|
@@ -23360,12 +23784,18 @@ async function startCommand(opts) {
|
|
|
23360
23784
|
repo,
|
|
23361
23785
|
tag,
|
|
23362
23786
|
directReleaseVersion,
|
|
23363
|
-
allowShellAssets: runtimeSupportsShellAssets
|
|
23787
|
+
allowShellAssets: runtimeSupportsShellAssets,
|
|
23788
|
+
downloadBaseUrl: smokeReleaseBaseUrls.downloadBaseUrl
|
|
23364
23789
|
});
|
|
23365
23790
|
if (assetCandidates.length === 0) {
|
|
23366
23791
|
throw new Error(`No Rudder Desktop portable asset found for ${target.platform}/${target.arch} in ${repo}@${releaseTag}.`);
|
|
23367
23792
|
}
|
|
23368
|
-
const checksumAsset = selectChecksumAsset(release?.assets ?? []) ?? (directReleaseVersion ? buildGithubReleaseAsset(
|
|
23793
|
+
const checksumAsset = selectChecksumAsset(release?.assets ?? []) ?? (directReleaseVersion ? buildGithubReleaseAsset(
|
|
23794
|
+
repo,
|
|
23795
|
+
tag,
|
|
23796
|
+
DESKTOP_CHECKSUM_ASSET_NAME,
|
|
23797
|
+
smokeReleaseBaseUrls.downloadBaseUrl
|
|
23798
|
+
) : null);
|
|
23369
23799
|
if (!checksumAsset) {
|
|
23370
23800
|
throw new Error("Desktop release is missing SHASUMS256.txt.");
|
|
23371
23801
|
}
|
|
@@ -23444,7 +23874,7 @@ async function startCommand(opts) {
|
|
|
23444
23874
|
}
|
|
23445
23875
|
const checksum = await runStartPhase(
|
|
23446
23876
|
"Verifying Desktop checksum...",
|
|
23447
|
-
`Verified ${pc14.cyan(
|
|
23877
|
+
`Verified ${pc14.cyan(path23.basename(verifiedAsset.path))}.`,
|
|
23448
23878
|
() => assertChecksumMatch(verifiedAsset.path, expectedChecksum),
|
|
23449
23879
|
desktopProgressJson ? "verifying_checksum" : null
|
|
23450
23880
|
);
|
|
@@ -23455,7 +23885,8 @@ async function startCommand(opts) {
|
|
|
23455
23885
|
percent: 100,
|
|
23456
23886
|
assetName: selectedAsset.name,
|
|
23457
23887
|
assetChecksum: checksum,
|
|
23458
|
-
|
|
23888
|
+
assetKind: selectedAssetKind,
|
|
23889
|
+
stagedArtifactPath: path23.resolve(verifiedAsset.path),
|
|
23459
23890
|
stagedArtifactDigest: checksum,
|
|
23460
23891
|
releaseDigest: createHash4("sha256").update(JSON.stringify({
|
|
23461
23892
|
releaseTag,
|
|
@@ -23548,11 +23979,11 @@ async function startCommand(opts) {
|
|
|
23548
23979
|
|
|
23549
23980
|
// src/config/data-dir.ts
|
|
23550
23981
|
init_home();
|
|
23551
|
-
import
|
|
23982
|
+
import path24 from "node:path";
|
|
23552
23983
|
function applyDataDirOverride(options, support = {}) {
|
|
23553
23984
|
const rawDataDir = options.dataDir?.trim();
|
|
23554
23985
|
if (!rawDataDir) return null;
|
|
23555
|
-
const resolvedDataDir =
|
|
23986
|
+
const resolvedDataDir = path24.resolve(expandHomePrefix(rawDataDir));
|
|
23556
23987
|
process.env.RUDDER_HOME = resolvedDataDir;
|
|
23557
23988
|
if (support.hasConfigOption) {
|
|
23558
23989
|
const hasConfigOverride = Boolean(options.config?.trim()) || Boolean(process.env.RUDDER_CONFIG?.trim());
|
|
@@ -23612,7 +24043,7 @@ function createProgram() {
|
|
|
23612
24043
|
});
|
|
23613
24044
|
loadRudderEnvFile(options.config);
|
|
23614
24045
|
});
|
|
23615
|
-
program.command("start").description("Start Rudder Desktop and prepare the matching persistent CLI").option("--server-only", "Prepare the Rudder server runtime and persistent CLI without installing Desktop").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("--download-source <source>", "Desktop download source: auto, cn, or global").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("--desktop-wait-for-apply", "Wait for an apply signal after downloading and verifying the Desktop update", false).option("--desktop-prepare-only", "Download and verify the Desktop update without installing or launching it", false).option("--desktop-asset-path <path>", "Use one previously staged, exact Desktop asset path").option("--desktop-asset-checksum <sha256>", "SHA-256 for the exact staged Desktop asset").option("--desktop-asset-name <name>", "Asset name bound to the exact staged Desktop candidate").option("--desktop-asset-kind <kind>", "Asset kind bound to the exact staged Desktop candidate (full or shell)").option("--desktop-release-digest <sha256>", "Release digest bound to the exact staged Desktop candidate").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);
|
|
24046
|
+
program.command("start").description("Start Rudder Desktop and prepare the matching persistent CLI").option("--server-only", "Prepare the Rudder server runtime and persistent CLI without installing Desktop").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("--download-source <source>", "Desktop download source: auto, cn, or global").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("--desktop-wait-for-apply", "Wait for an apply signal after downloading and verifying the Desktop update", false).option("--desktop-prepare-only", "Download and verify the Desktop update without installing or launching it", false).option("--desktop-asset-path <path>", "Use one previously staged, exact Desktop asset path").option("--desktop-asset-checksum <sha256>", "SHA-256 for the exact staged Desktop asset").option("--desktop-asset-name <name>", "Asset name bound to the exact staged Desktop candidate").option("--desktop-asset-kind <kind>", "Asset kind bound to the exact staged Desktop candidate (full or shell)").option("--desktop-release-digest <sha256>", "Release digest bound to the exact staged Desktop candidate").addOption(new Option("--desktop-runtime-best-effort").hideHelp()).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);
|
|
23616
24047
|
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);
|
|
23617
24048
|
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) => {
|
|
23618
24049
|
await doctor(opts);
|