@rudderhq/cli 0.7.15 → 0.7.18
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 +950 -451
- package/dist/index.js.map +4 -4
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1700,7 +1700,9 @@ var init_rudder_agent_contract_generated = __esm({
|
|
|
1700
1700
|
},
|
|
1701
1701
|
{
|
|
1702
1702
|
"api": {
|
|
1703
|
-
"
|
|
1703
|
+
"method": "GET",
|
|
1704
|
+
"pathTemplate": "/api/issues/{issue}/comments",
|
|
1705
|
+
"transport": "direct"
|
|
1704
1706
|
},
|
|
1705
1707
|
"cli": {
|
|
1706
1708
|
"attachesRunIdWhenAvailable": false,
|
|
@@ -1760,7 +1762,9 @@ var init_rudder_agent_contract_generated = __esm({
|
|
|
1760
1762
|
},
|
|
1761
1763
|
{
|
|
1762
1764
|
"api": {
|
|
1763
|
-
"
|
|
1765
|
+
"method": "GET",
|
|
1766
|
+
"pathTemplate": "/api/issues/{issue}/comments/{comment}",
|
|
1767
|
+
"transport": "direct"
|
|
1764
1768
|
},
|
|
1765
1769
|
"cli": {
|
|
1766
1770
|
"attachesRunIdWhenAvailable": false,
|
|
@@ -8582,6 +8586,65 @@ var init_rudder_agent_contract_generated = __esm({
|
|
|
8582
8586
|
},
|
|
8583
8587
|
"name": "rudder_runs_retry"
|
|
8584
8588
|
}
|
|
8589
|
+
},
|
|
8590
|
+
{
|
|
8591
|
+
"api": {
|
|
8592
|
+
"method": "POST",
|
|
8593
|
+
"pathTemplate": "/api/agent-runs/delegation",
|
|
8594
|
+
"transport": "direct"
|
|
8595
|
+
},
|
|
8596
|
+
"cli": {
|
|
8597
|
+
"attachesRunIdWhenAvailable": true,
|
|
8598
|
+
"category": "runs",
|
|
8599
|
+
"command": "rudder runs create --task <text> --idempotency-key <key> [--target-agent-id <id>]",
|
|
8600
|
+
"contract": "agent-v1",
|
|
8601
|
+
"description": "Create an independently governed Delegation Run for the current or another same-organization Agent.",
|
|
8602
|
+
"id": "runs.create",
|
|
8603
|
+
"mutating": true,
|
|
8604
|
+
"requiresAgentId": true,
|
|
8605
|
+
"requiresOrgId": false,
|
|
8606
|
+
"requiresRunId": true
|
|
8607
|
+
},
|
|
8608
|
+
"id": "runs.create",
|
|
8609
|
+
"mcp": {
|
|
8610
|
+
"annotations": {
|
|
8611
|
+
"destructiveHint": false,
|
|
8612
|
+
"idempotentHint": true,
|
|
8613
|
+
"readOnlyHint": false,
|
|
8614
|
+
"title": "Create an independently governed Delegation Run"
|
|
8615
|
+
},
|
|
8616
|
+
"capabilityId": "runs.create",
|
|
8617
|
+
"description": "Create an independently governed Delegation Run for the current or another same-organization Agent. Mutating: yes. Runtime identity and authorization are injected by the Rudder-managed MCP server and are not accepted as tool input. Org context: not required by this tool. Agent context: required from runtime env. Run attribution: attached from runtime env when available.",
|
|
8618
|
+
"inputSchema": {
|
|
8619
|
+
"additionalProperties": false,
|
|
8620
|
+
"properties": {
|
|
8621
|
+
"idempotencyKey": {
|
|
8622
|
+
"description": "Required stable key for safe replay.",
|
|
8623
|
+
"maxLength": 500,
|
|
8624
|
+
"minLength": 1,
|
|
8625
|
+
"type": "string"
|
|
8626
|
+
},
|
|
8627
|
+
"targetAgentId": {
|
|
8628
|
+
"description": "Optional same-organization target Agent id.",
|
|
8629
|
+
"maxLength": 200,
|
|
8630
|
+
"minLength": 1,
|
|
8631
|
+
"type": "string"
|
|
8632
|
+
},
|
|
8633
|
+
"task": {
|
|
8634
|
+
"description": "Delegation task to run independently.",
|
|
8635
|
+
"maxLength": 2e4,
|
|
8636
|
+
"minLength": 1,
|
|
8637
|
+
"type": "string"
|
|
8638
|
+
}
|
|
8639
|
+
},
|
|
8640
|
+
"required": [
|
|
8641
|
+
"task",
|
|
8642
|
+
"idempotencyKey"
|
|
8643
|
+
],
|
|
8644
|
+
"type": "object"
|
|
8645
|
+
},
|
|
8646
|
+
"name": "rudder_runs_create"
|
|
8647
|
+
}
|
|
8585
8648
|
}
|
|
8586
8649
|
],
|
|
8587
8650
|
"contractVersion": "rudder.agent-contract/v1",
|
|
@@ -16296,6 +16359,50 @@ var init_rudder_mcp_tool_descriptors_generated = __esm({
|
|
|
16296
16359
|
],
|
|
16297
16360
|
"type": "object"
|
|
16298
16361
|
}
|
|
16362
|
+
},
|
|
16363
|
+
{
|
|
16364
|
+
"capabilityId": "runs.create",
|
|
16365
|
+
"name": "rudder_runs_create",
|
|
16366
|
+
"description": "Create an independently governed Delegation Run for the current or another same-organization Agent.",
|
|
16367
|
+
"semanticDescription": "Create an independently governed Delegation Run for the current or another same-organization Agent. Mutating: yes. Runtime identity and authorization are injected by the Rudder-managed MCP server and are not accepted as tool input. Org context: not required by this tool. Agent context: required from runtime env. Run attribution: attached from runtime env when available.",
|
|
16368
|
+
"annotations": {
|
|
16369
|
+
"destructiveHint": false,
|
|
16370
|
+
"idempotentHint": true,
|
|
16371
|
+
"readOnlyHint": false,
|
|
16372
|
+
"title": "Create an independently governed Delegation Run"
|
|
16373
|
+
},
|
|
16374
|
+
"mutating": true,
|
|
16375
|
+
"requiresOrgId": false,
|
|
16376
|
+
"requiresAgentId": true,
|
|
16377
|
+
"attachesRunIdWhenAvailable": true,
|
|
16378
|
+
"inputSchema": {
|
|
16379
|
+
"additionalProperties": false,
|
|
16380
|
+
"properties": {
|
|
16381
|
+
"idempotencyKey": {
|
|
16382
|
+
"description": "Required stable key for safe replay.",
|
|
16383
|
+
"maxLength": 500,
|
|
16384
|
+
"minLength": 1,
|
|
16385
|
+
"type": "string"
|
|
16386
|
+
},
|
|
16387
|
+
"targetAgentId": {
|
|
16388
|
+
"description": "Optional same-organization target Agent id.",
|
|
16389
|
+
"maxLength": 200,
|
|
16390
|
+
"minLength": 1,
|
|
16391
|
+
"type": "string"
|
|
16392
|
+
},
|
|
16393
|
+
"task": {
|
|
16394
|
+
"description": "Delegation task to run independently.",
|
|
16395
|
+
"maxLength": 2e4,
|
|
16396
|
+
"minLength": 1,
|
|
16397
|
+
"type": "string"
|
|
16398
|
+
}
|
|
16399
|
+
},
|
|
16400
|
+
"required": [
|
|
16401
|
+
"task",
|
|
16402
|
+
"idempotencyKey"
|
|
16403
|
+
],
|
|
16404
|
+
"type": "object"
|
|
16405
|
+
}
|
|
16299
16406
|
}
|
|
16300
16407
|
];
|
|
16301
16408
|
}
|
|
@@ -16895,7 +17002,8 @@ var init_constants = __esm({
|
|
|
16895
17002
|
"rudder_runs_transcript",
|
|
16896
17003
|
"rudder_runs_errors",
|
|
16897
17004
|
"rudder_runs_cancel",
|
|
16898
|
-
"rudder_runs_retry"
|
|
17005
|
+
"rudder_runs_retry",
|
|
17006
|
+
"rudder_runs_create"
|
|
16899
17007
|
];
|
|
16900
17008
|
RUDDER_BROWSER_MCP_TOOL_NAMES2 = RUDDER_AGENT_V1_MCP_TOOL_NAMES.filter((name) => name.startsWith("rudder_browser_"));
|
|
16901
17009
|
RUDDER_CORE_MCP_TOOL_NAMES2 = RUDDER_AGENT_V1_MCP_TOOL_NAMES.filter((name) => !name.startsWith("rudder_browser_"));
|
|
@@ -18532,6 +18640,7 @@ var init_chat = __esm({
|
|
|
18532
18640
|
}).strict();
|
|
18533
18641
|
addChatMessageSchema = z5.object({
|
|
18534
18642
|
body: z5.string().trim().max(2e4).default(""),
|
|
18643
|
+
clientMutationId: z5.string().trim().min(1).max(120).optional(),
|
|
18535
18644
|
inlineAnnotations: chatInlineAnnotationsInputSchema.optional(),
|
|
18536
18645
|
editUserMessageId: z5.string().uuid().optional().nullable(),
|
|
18537
18646
|
queuedMessageId: z5.string().uuid().optional().nullable(),
|
|
@@ -19975,7 +20084,7 @@ var init_resource = __esm({
|
|
|
19975
20084
|
|
|
19976
20085
|
// ../packages/shared/dist/validators/agent.js
|
|
19977
20086
|
import { z as z20 } from "zod";
|
|
19978
|
-
var agentPermissionsSchema, agentInstructionsBundleModeSchema, updateAgentInstructionsBundleSchema, upsertAgentInstructionsFileSchema, agentRuntimeConfigSchema, optionalAgentNameSchema, uploadedAgentIconSchema, diceBearNotionistsAgentIconSchema, oreoAgentIconSchema, agentIconSchema, createAgentSchema, createAgentHireSchema, updateAgentSchema, updateAgentInstructionsPathSchema, createAgentKeySchema, wakeAgentSchema, resetAgentSessionSchema, testAgentRuntimeEnvironmentSchema, updateAgentPermissionsSchema;
|
|
20087
|
+
var agentPermissionsSchema, agentInstructionsBundleModeSchema, updateAgentInstructionsBundleSchema, upsertAgentInstructionsFileSchema, agentRuntimeConfigSchema, optionalAgentNameSchema, uploadedAgentIconSchema, diceBearNotionistsAgentIconSchema, oreoAgentIconSchema, agentIconSchema, createAgentSchema, createAgentHireSchema, updateAgentSchema, updateAgentInstructionsPathSchema, createAgentKeySchema, wakeAgentSchema, delegationTaskSchema, createDelegationRunSchema, resetAgentSessionSchema, testAgentRuntimeEnvironmentSchema, updateAgentPermissionsSchema;
|
|
19979
20088
|
var init_agent = __esm({
|
|
19980
20089
|
"../packages/shared/dist/validators/agent.js"() {
|
|
19981
20090
|
"use strict";
|
|
@@ -20072,6 +20181,12 @@ var init_agent = __esm({
|
|
|
20072
20181
|
idempotencyKey: z20.string().optional().nullable(),
|
|
20073
20182
|
forceFreshSession: z20.preprocess((value) => value === null ? void 0 : value, z20.boolean().optional().default(false))
|
|
20074
20183
|
});
|
|
20184
|
+
delegationTaskSchema = z20.string().trim().min(1).refine((value) => Array.from(value).length <= 2e4, "task must be no more than 20,000 Unicode characters");
|
|
20185
|
+
createDelegationRunSchema = z20.object({
|
|
20186
|
+
task: delegationTaskSchema,
|
|
20187
|
+
targetAgentId: z20.string().trim().min(1).max(200).optional(),
|
|
20188
|
+
idempotencyKey: z20.string().trim().min(1).max(500)
|
|
20189
|
+
});
|
|
20075
20190
|
resetAgentSessionSchema = z20.object({
|
|
20076
20191
|
taskKey: z20.string().min(1).optional().nullable()
|
|
20077
20192
|
});
|
|
@@ -20284,7 +20399,7 @@ var init_project = __esm({
|
|
|
20284
20399
|
|
|
20285
20400
|
// ../packages/shared/dist/validators/issue.js
|
|
20286
20401
|
import { z as z23 } from "zod";
|
|
20287
|
-
var runWorkspaceStrategySchema, issueRunWorkspaceSettingsSchema, issueAssigneeAdapterOverridesSchema, createIssueSchema, createIssueLabelSchema, updateIssueLabelSchema, updateIssueSchema, reorderIssueSchema, checkoutIssueSchema, addIssueCommentSchema, updateIssueCommentSchema, reportIssueCommitSchema, linkIssueApprovalSchema, createIssueAttachmentMetadataSchema, createIssueWorkspaceAttachmentSchema, ISSUE_DOCUMENT_FORMATS, issueDocumentFormatSchema, createLibraryDocumentSchema, updateLibraryDocumentSchema, restoreLibraryDocumentRevisionSchema;
|
|
20402
|
+
var runWorkspaceStrategySchema, issueRunWorkspaceSettingsSchema, issueAssigneeAdapterOverridesSchema, createIssueSchema, createRunDebugIssueSchema, createIssueLabelSchema, updateIssueLabelSchema, updateIssueSchema, reorderIssueSchema, checkoutIssueSchema, addIssueCommentSchema, updateIssueCommentSchema, reportIssueCommitSchema, linkIssueApprovalSchema, createIssueAttachmentMetadataSchema, createIssueWorkspaceAttachmentSchema, ISSUE_DOCUMENT_FORMATS, issueDocumentFormatSchema, createLibraryDocumentSchema, updateLibraryDocumentSchema, restoreLibraryDocumentRevisionSchema;
|
|
20288
20403
|
var init_issue = __esm({
|
|
20289
20404
|
"../packages/shared/dist/validators/issue.js"() {
|
|
20290
20405
|
"use strict";
|
|
@@ -20347,6 +20462,9 @@ var init_issue = __esm({
|
|
|
20347
20462
|
executionWorkspaceSettings: issueRunWorkspaceSettingsSchema.optional().nullable(),
|
|
20348
20463
|
labelIds: z23.array(z23.string().uuid()).optional()
|
|
20349
20464
|
});
|
|
20465
|
+
createRunDebugIssueSchema = z23.object({
|
|
20466
|
+
diagnostics: z23.string().trim().min(1).max(32e3)
|
|
20467
|
+
});
|
|
20350
20468
|
createIssueLabelSchema = z23.object({
|
|
20351
20469
|
name: z23.string().trim().min(1).max(48),
|
|
20352
20470
|
color: z23.string().regex(/^#(?:[0-9a-fA-F]{6})$/, "Color must be a 6-digit hex value")
|
|
@@ -21530,12 +21648,12 @@ var init_dist2 = __esm({
|
|
|
21530
21648
|
});
|
|
21531
21649
|
|
|
21532
21650
|
// src/config/home.ts
|
|
21533
|
-
import
|
|
21534
|
-
import
|
|
21651
|
+
import os2 from "node:os";
|
|
21652
|
+
import path2 from "node:path";
|
|
21535
21653
|
function resolveRudderHomeDir() {
|
|
21536
21654
|
const envHome = process.env.RUDDER_HOME?.trim();
|
|
21537
|
-
if (envHome) return
|
|
21538
|
-
return
|
|
21655
|
+
if (envHome) return path2.resolve(expandHomePrefix(envHome));
|
|
21656
|
+
return path2.resolve(os2.homedir(), ".rudder");
|
|
21539
21657
|
}
|
|
21540
21658
|
function resolveRudderInstanceId(override) {
|
|
21541
21659
|
const raw = override?.trim() || process.env.RUDDER_INSTANCE_ID?.trim() || DEFAULT_INSTANCE_ID;
|
|
@@ -21548,35 +21666,35 @@ function resolveRudderInstanceId(override) {
|
|
|
21548
21666
|
}
|
|
21549
21667
|
function resolveRudderInstanceRoot(instanceId) {
|
|
21550
21668
|
const id = resolveRudderInstanceId(instanceId);
|
|
21551
|
-
return
|
|
21669
|
+
return path2.resolve(resolveRudderHomeDir(), "instances", id);
|
|
21552
21670
|
}
|
|
21553
21671
|
function resolveDefaultConfigPath(instanceId) {
|
|
21554
|
-
return
|
|
21672
|
+
return path2.resolve(resolveRudderInstanceRoot(instanceId), "config.json");
|
|
21555
21673
|
}
|
|
21556
21674
|
function resolveDefaultContextPath() {
|
|
21557
|
-
return
|
|
21675
|
+
return path2.resolve(resolveRudderHomeDir(), "context.json");
|
|
21558
21676
|
}
|
|
21559
21677
|
function resolveDefaultCliAuthPath() {
|
|
21560
|
-
return
|
|
21678
|
+
return path2.resolve(resolveRudderHomeDir(), "auth.json");
|
|
21561
21679
|
}
|
|
21562
21680
|
function resolveDefaultEmbeddedPostgresDir(instanceId) {
|
|
21563
|
-
return
|
|
21681
|
+
return path2.resolve(resolveRudderInstanceRoot(instanceId), "db");
|
|
21564
21682
|
}
|
|
21565
21683
|
function resolveDefaultLogsDir(instanceId) {
|
|
21566
|
-
return
|
|
21684
|
+
return path2.resolve(resolveRudderInstanceRoot(instanceId), "logs");
|
|
21567
21685
|
}
|
|
21568
21686
|
function resolveDefaultSecretsKeyFilePath(instanceId) {
|
|
21569
|
-
return
|
|
21687
|
+
return path2.resolve(resolveRudderInstanceRoot(instanceId), "secrets", "master.key");
|
|
21570
21688
|
}
|
|
21571
21689
|
function resolveDefaultStorageDir(instanceId) {
|
|
21572
|
-
return
|
|
21690
|
+
return path2.resolve(resolveRudderInstanceRoot(instanceId), "data", "storage");
|
|
21573
21691
|
}
|
|
21574
21692
|
function resolveDefaultBackupDir(instanceId) {
|
|
21575
|
-
return
|
|
21693
|
+
return path2.resolve(resolveRudderInstanceRoot(instanceId), "data", "backups");
|
|
21576
21694
|
}
|
|
21577
21695
|
function expandHomePrefix(value) {
|
|
21578
|
-
if (value === "~") return
|
|
21579
|
-
if (value.startsWith("~/")) return
|
|
21696
|
+
if (value === "~") return os2.homedir();
|
|
21697
|
+
if (value.startsWith("~/")) return path2.resolve(os2.homedir(), value.slice(2));
|
|
21580
21698
|
return value;
|
|
21581
21699
|
}
|
|
21582
21700
|
function describeLocalInstancePaths(instanceId) {
|
|
@@ -21612,30 +21730,30 @@ var init_schema = __esm({
|
|
|
21612
21730
|
});
|
|
21613
21731
|
|
|
21614
21732
|
// src/config/store.ts
|
|
21615
|
-
import
|
|
21616
|
-
import
|
|
21733
|
+
import fs4 from "node:fs";
|
|
21734
|
+
import path5 from "node:path";
|
|
21617
21735
|
function findConfigFileFromAncestors(startDir) {
|
|
21618
|
-
const absoluteStartDir =
|
|
21736
|
+
const absoluteStartDir = path5.resolve(startDir);
|
|
21619
21737
|
let currentDir = absoluteStartDir;
|
|
21620
21738
|
while (true) {
|
|
21621
|
-
const candidate =
|
|
21622
|
-
if (
|
|
21739
|
+
const candidate = path5.resolve(currentDir, ".rudder", DEFAULT_CONFIG_BASENAME);
|
|
21740
|
+
if (fs4.existsSync(candidate)) {
|
|
21623
21741
|
return candidate;
|
|
21624
21742
|
}
|
|
21625
|
-
const nextDir =
|
|
21743
|
+
const nextDir = path5.resolve(currentDir, "..");
|
|
21626
21744
|
if (nextDir === currentDir) break;
|
|
21627
21745
|
currentDir = nextDir;
|
|
21628
21746
|
}
|
|
21629
21747
|
return null;
|
|
21630
21748
|
}
|
|
21631
21749
|
function resolveConfigPath(overridePath) {
|
|
21632
|
-
if (overridePath) return
|
|
21633
|
-
if (process.env.RUDDER_CONFIG) return
|
|
21750
|
+
if (overridePath) return path5.resolve(overridePath);
|
|
21751
|
+
if (process.env.RUDDER_CONFIG) return path5.resolve(process.env.RUDDER_CONFIG);
|
|
21634
21752
|
return findConfigFileFromAncestors(process.cwd()) ?? resolveDefaultConfigPath(resolveRudderInstanceId());
|
|
21635
21753
|
}
|
|
21636
21754
|
function parseJson2(filePath) {
|
|
21637
21755
|
try {
|
|
21638
|
-
return JSON.parse(
|
|
21756
|
+
return JSON.parse(fs4.readFileSync(filePath, "utf-8"));
|
|
21639
21757
|
} catch (err) {
|
|
21640
21758
|
throw new Error(`Failed to parse JSON at ${filePath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
21641
21759
|
}
|
|
@@ -21674,7 +21792,7 @@ function formatValidationError(err) {
|
|
|
21674
21792
|
}
|
|
21675
21793
|
function readConfig(configPath) {
|
|
21676
21794
|
const filePath = resolveConfigPath(configPath);
|
|
21677
|
-
if (!
|
|
21795
|
+
if (!fs4.existsSync(filePath)) return null;
|
|
21678
21796
|
const raw = parseJson2(filePath);
|
|
21679
21797
|
const migrated = migrateLegacyConfig(raw);
|
|
21680
21798
|
const parsed = rudderConfigSchema.safeParse(migrated);
|
|
@@ -21685,19 +21803,19 @@ function readConfig(configPath) {
|
|
|
21685
21803
|
}
|
|
21686
21804
|
function writeConfig(config, configPath) {
|
|
21687
21805
|
const filePath = resolveConfigPath(configPath);
|
|
21688
|
-
const dir =
|
|
21689
|
-
|
|
21690
|
-
if (
|
|
21806
|
+
const dir = path5.dirname(filePath);
|
|
21807
|
+
fs4.mkdirSync(dir, { recursive: true });
|
|
21808
|
+
if (fs4.existsSync(filePath)) {
|
|
21691
21809
|
const backupPath = filePath + ".backup";
|
|
21692
|
-
|
|
21693
|
-
|
|
21810
|
+
fs4.copyFileSync(filePath, backupPath);
|
|
21811
|
+
fs4.chmodSync(backupPath, 384);
|
|
21694
21812
|
}
|
|
21695
|
-
|
|
21813
|
+
fs4.writeFileSync(filePath, JSON.stringify(config, null, 2) + "\n", {
|
|
21696
21814
|
mode: 384
|
|
21697
21815
|
});
|
|
21698
21816
|
}
|
|
21699
21817
|
function configExists(configPath) {
|
|
21700
|
-
return
|
|
21818
|
+
return fs4.existsSync(resolveConfigPath(configPath));
|
|
21701
21819
|
}
|
|
21702
21820
|
var DEFAULT_CONFIG_BASENAME;
|
|
21703
21821
|
var init_store = __esm({
|
|
@@ -21711,7 +21829,7 @@ var init_store = __esm({
|
|
|
21711
21829
|
|
|
21712
21830
|
// src/version.ts
|
|
21713
21831
|
import { existsSync, readFileSync } from "node:fs";
|
|
21714
|
-
import
|
|
21832
|
+
import path6 from "node:path";
|
|
21715
21833
|
import { fileURLToPath } from "node:url";
|
|
21716
21834
|
function readPackageVersion(packagePath, expectedName) {
|
|
21717
21835
|
if (!existsSync(packagePath)) return null;
|
|
@@ -21727,12 +21845,12 @@ function resolveCliVersion(moduleUrl = import.meta.url, env = process.env) {
|
|
|
21727
21845
|
if (env.npm_package_name === CLI_PACKAGE_NAME && env.npm_package_version) {
|
|
21728
21846
|
return env.npm_package_version;
|
|
21729
21847
|
}
|
|
21730
|
-
const moduleDir =
|
|
21848
|
+
const moduleDir = path6.dirname(fileURLToPath(moduleUrl));
|
|
21731
21849
|
const candidates = [
|
|
21732
|
-
|
|
21733
|
-
|
|
21734
|
-
|
|
21735
|
-
|
|
21850
|
+
path6.resolve(moduleDir, CLI_VERSION_MANIFEST),
|
|
21851
|
+
path6.resolve(moduleDir, "package.json"),
|
|
21852
|
+
path6.resolve(moduleDir, "../package.json"),
|
|
21853
|
+
path6.resolve(moduleDir, "../../package.json")
|
|
21736
21854
|
];
|
|
21737
21855
|
for (const candidate of candidates) {
|
|
21738
21856
|
const version = readPackageVersion(candidate, CLI_PACKAGE_NAME);
|
|
@@ -21782,10 +21900,10 @@ var init_hostnames = __esm({
|
|
|
21782
21900
|
// src/config/env.ts
|
|
21783
21901
|
import { config as loadDotenv, parse as parseEnvFileContents } from "dotenv";
|
|
21784
21902
|
import { randomBytes } from "node:crypto";
|
|
21785
|
-
import
|
|
21786
|
-
import
|
|
21903
|
+
import fs6 from "node:fs";
|
|
21904
|
+
import path8 from "node:path";
|
|
21787
21905
|
function resolveEnvFilePath(configPath) {
|
|
21788
|
-
return
|
|
21906
|
+
return path8.resolve(path8.dirname(resolveConfigPath(configPath)), ".env");
|
|
21789
21907
|
}
|
|
21790
21908
|
function isNonEmpty(value) {
|
|
21791
21909
|
return typeof value === "string" && value.trim().length > 0;
|
|
@@ -21820,7 +21938,7 @@ function loadRudderEnvFile(configPath) {
|
|
|
21820
21938
|
}
|
|
21821
21939
|
function loadAgentJwtEnvFile(filePath = resolveEnvFilePath()) {
|
|
21822
21940
|
if (loadedEnvFiles.has(filePath)) return;
|
|
21823
|
-
if (!
|
|
21941
|
+
if (!fs6.existsSync(filePath)) return;
|
|
21824
21942
|
loadedEnvFiles.add(filePath);
|
|
21825
21943
|
loadDotenv({ path: filePath, override: false, quiet: true });
|
|
21826
21944
|
}
|
|
@@ -21830,8 +21948,8 @@ function readAgentJwtSecretFromEnv(configPath) {
|
|
|
21830
21948
|
return isNonEmpty(raw) ? raw.trim() : null;
|
|
21831
21949
|
}
|
|
21832
21950
|
function readAgentJwtSecretFromEnvFile(filePath = resolveEnvFilePath()) {
|
|
21833
|
-
if (!
|
|
21834
|
-
const raw =
|
|
21951
|
+
if (!fs6.existsSync(filePath)) return null;
|
|
21952
|
+
const raw = fs6.readFileSync(filePath, "utf-8");
|
|
21835
21953
|
const values = parseEnvFile(raw);
|
|
21836
21954
|
const value = values[JWT_SECRET_ENV_KEY];
|
|
21837
21955
|
return isNonEmpty(value) ? value.trim() : null;
|
|
@@ -21854,13 +21972,13 @@ function writeAgentJwtEnv(secret, filePath = resolveEnvFilePath()) {
|
|
|
21854
21972
|
mergePaperclipEnvEntries({ [JWT_SECRET_ENV_KEY]: secret }, filePath);
|
|
21855
21973
|
}
|
|
21856
21974
|
function readPaperclipEnvEntries(filePath = resolveEnvFilePath()) {
|
|
21857
|
-
if (!
|
|
21858
|
-
return parseEnvFile(
|
|
21975
|
+
if (!fs6.existsSync(filePath)) return {};
|
|
21976
|
+
return parseEnvFile(fs6.readFileSync(filePath, "utf-8"));
|
|
21859
21977
|
}
|
|
21860
21978
|
function writePaperclipEnvEntries(entries, filePath = resolveEnvFilePath()) {
|
|
21861
|
-
const dir =
|
|
21862
|
-
|
|
21863
|
-
|
|
21979
|
+
const dir = path8.dirname(filePath);
|
|
21980
|
+
fs6.mkdirSync(dir, { recursive: true });
|
|
21981
|
+
fs6.writeFileSync(filePath, renderEnvFile(entries), {
|
|
21864
21982
|
mode: 384
|
|
21865
21983
|
});
|
|
21866
21984
|
}
|
|
@@ -21904,8 +22022,8 @@ var init_npm_command = __esm({
|
|
|
21904
22022
|
// src/runtime/native-payload.ts
|
|
21905
22023
|
import { execFile } from "node:child_process";
|
|
21906
22024
|
import { existsSync as existsSync3 } from "node:fs";
|
|
21907
|
-
import
|
|
21908
|
-
import
|
|
22025
|
+
import fs7 from "node:fs/promises";
|
|
22026
|
+
import path9 from "node:path";
|
|
21909
22027
|
import { performance } from "node:perf_hooks";
|
|
21910
22028
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
21911
22029
|
import { promisify } from "node:util";
|
|
@@ -21914,14 +22032,14 @@ function nativeTarget() {
|
|
|
21914
22032
|
}
|
|
21915
22033
|
function resolveNativePayloadBinary() {
|
|
21916
22034
|
const configured = process.env.RUDDER_NATIVE_PAYLOAD_PATH?.trim() || process.env.RUDDER_NATIVE_PATH?.trim();
|
|
21917
|
-
if (configured) return
|
|
22035
|
+
if (configured) return path9.resolve(configured);
|
|
21918
22036
|
const binaryName = process.platform === "win32" ? "rudder-native.exe" : "rudder-native";
|
|
21919
|
-
const moduleDir =
|
|
22037
|
+
const moduleDir = path9.dirname(fileURLToPath3(import.meta.url));
|
|
21920
22038
|
const target = nativeTarget();
|
|
21921
22039
|
const candidates = [
|
|
21922
|
-
|
|
21923
|
-
|
|
21924
|
-
|
|
22040
|
+
path9.resolve(moduleDir, "../../../native/target/debug", binaryName),
|
|
22041
|
+
path9.resolve(moduleDir, "../../../../native/target/debug", binaryName),
|
|
22042
|
+
path9.resolve(moduleDir, "../../../native", target ?? "unsupported", binaryName)
|
|
21925
22043
|
];
|
|
21926
22044
|
return candidates.find((candidate) => existsSync3(candidate)) ?? candidates[0];
|
|
21927
22045
|
}
|
|
@@ -21994,7 +22112,7 @@ async function verifyNativePayload(archivePath, expectedSha256, maxArchiveBytes,
|
|
|
21994
22112
|
return runNativePayload("payload.verify", [
|
|
21995
22113
|
"payload",
|
|
21996
22114
|
"verify",
|
|
21997
|
-
|
|
22115
|
+
path9.resolve(archivePath),
|
|
21998
22116
|
expectedSha256,
|
|
21999
22117
|
String(maxArchiveBytes)
|
|
22000
22118
|
], false, timeoutMs);
|
|
@@ -22004,9 +22122,9 @@ async function extractNativePayload(archivePath, stagingPath, maxArchiveBytes, t
|
|
|
22004
22122
|
return await runNativePayload("payload.extract", [
|
|
22005
22123
|
"payload",
|
|
22006
22124
|
"extract",
|
|
22007
|
-
|
|
22125
|
+
path9.resolve(archivePath),
|
|
22008
22126
|
"auto",
|
|
22009
|
-
|
|
22127
|
+
path9.resolve(stagingPath),
|
|
22010
22128
|
String(maxArchiveBytes),
|
|
22011
22129
|
String(maxArchiveBytes),
|
|
22012
22130
|
String(maxArchiveBytes * 2),
|
|
@@ -22023,7 +22141,7 @@ async function probeNativePayloadVersion(rootPath, executable, timeoutMs) {
|
|
|
22023
22141
|
return runNativePayload("payload.probeVersion", [
|
|
22024
22142
|
"payload",
|
|
22025
22143
|
"probe-version",
|
|
22026
|
-
|
|
22144
|
+
path9.resolve(rootPath),
|
|
22027
22145
|
executable,
|
|
22028
22146
|
"PostgreSQL 18.4"
|
|
22029
22147
|
], true, timeoutMs);
|
|
@@ -22032,8 +22150,8 @@ async function publishNativePayload(stagingPath, destinationPath, timeoutMs) {
|
|
|
22032
22150
|
return runNativePayload("payload.publish", [
|
|
22033
22151
|
"payload",
|
|
22034
22152
|
"publish",
|
|
22035
|
-
|
|
22036
|
-
|
|
22153
|
+
path9.resolve(stagingPath),
|
|
22154
|
+
path9.resolve(destinationPath)
|
|
22037
22155
|
], true, timeoutMs);
|
|
22038
22156
|
}
|
|
22039
22157
|
async function tryInstallNativePayload(input) {
|
|
@@ -22132,7 +22250,7 @@ async function tryInstallNativePayload(input) {
|
|
|
22132
22250
|
}
|
|
22133
22251
|
};
|
|
22134
22252
|
} finally {
|
|
22135
|
-
const cleanup = input.cleanupPublishStaging ?? ((publishStagingPath) =>
|
|
22253
|
+
const cleanup = input.cleanupPublishStaging ?? ((publishStagingPath) => fs7.rm(publishStagingPath, { recursive: true, force: true }));
|
|
22136
22254
|
void cleanup(input.publishStagingPath).catch(() => {
|
|
22137
22255
|
});
|
|
22138
22256
|
}
|
|
@@ -22173,7 +22291,7 @@ var init_native_payload = __esm({
|
|
|
22173
22291
|
});
|
|
22174
22292
|
|
|
22175
22293
|
// src/runtime/postgres-runtime-download.ts
|
|
22176
|
-
import { createHash as
|
|
22294
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
22177
22295
|
import { createReadStream, createWriteStream } from "node:fs";
|
|
22178
22296
|
import { Readable, Transform } from "node:stream";
|
|
22179
22297
|
import { pipeline } from "node:stream/promises";
|
|
@@ -22192,7 +22310,7 @@ async function downloadRuntimePostgresArchive(url, targetPath, trustedSha256, op
|
|
|
22192
22310
|
const controller = new AbortController();
|
|
22193
22311
|
const timeout = Number.isFinite(parsedTimeout) && parsedTimeout > 0 ? setTimeout(() => controller.abort(), parsedTimeout) : null;
|
|
22194
22312
|
try {
|
|
22195
|
-
const hash =
|
|
22313
|
+
const hash = createHash3("sha256");
|
|
22196
22314
|
let bytes = 0;
|
|
22197
22315
|
const monitor = new Transform({
|
|
22198
22316
|
transform(chunk, _encoding, callback) {
|
|
@@ -22295,7 +22413,7 @@ import { execFileSync, spawnSync as spawnSync2 } from "node:child_process";
|
|
|
22295
22413
|
import { createReadStream as createReadStream2, createWriteStream as createWriteStream2 } from "node:fs";
|
|
22296
22414
|
import { chmod, mkdir, mkdtemp, readFile, readdir, realpath, rename, rm, stat, symlink, writeFile } from "node:fs/promises";
|
|
22297
22415
|
import { createRequire } from "node:module";
|
|
22298
|
-
import
|
|
22416
|
+
import path10 from "node:path";
|
|
22299
22417
|
import { performance as performance2 } from "node:perf_hooks";
|
|
22300
22418
|
import { pipeline as pipeline2 } from "node:stream/promises";
|
|
22301
22419
|
import { pathToFileURL } from "node:url";
|
|
@@ -22339,7 +22457,7 @@ function resolveRuntimePackageVersion(version) {
|
|
|
22339
22457
|
return normalized.length > 0 ? normalized : "latest";
|
|
22340
22458
|
}
|
|
22341
22459
|
function resolveRuntimeCacheDir(version, homeDir = resolveRudderHomeDir()) {
|
|
22342
|
-
return
|
|
22460
|
+
return path10.join(homeDir, "runtimes", sanitizeRuntimeCacheSegment(resolveRuntimePackageVersion(version)));
|
|
22343
22461
|
}
|
|
22344
22462
|
function resolveRuntimePackageSpec(version, packageName = RUNTIME_NPM_PACKAGE_NAME) {
|
|
22345
22463
|
const packageVersion = resolveRuntimePackageVersion(version);
|
|
@@ -22347,7 +22465,7 @@ function resolveRuntimePackageSpec(version, packageName = RUNTIME_NPM_PACKAGE_NA
|
|
|
22347
22465
|
}
|
|
22348
22466
|
async function readRuntimeInstallMetadata(cacheDir) {
|
|
22349
22467
|
try {
|
|
22350
|
-
const raw = await readFile(
|
|
22468
|
+
const raw = await readFile(path10.join(cacheDir, RUNTIME_METADATA_FILE), "utf8");
|
|
22351
22469
|
const parsed = JSON.parse(raw);
|
|
22352
22470
|
if (parsed.version !== 1) return null;
|
|
22353
22471
|
if (typeof parsed.packageName !== "string" || typeof parsed.packageVersion !== "string") return null;
|
|
@@ -22362,7 +22480,7 @@ async function readRuntimeInstallMetadata(cacheDir) {
|
|
|
22362
22480
|
}
|
|
22363
22481
|
}
|
|
22364
22482
|
async function writeRuntimeInstallMetadata(cacheDir, metadata) {
|
|
22365
|
-
await writeFile(
|
|
22483
|
+
await writeFile(path10.join(cacheDir, RUNTIME_METADATA_FILE), `${JSON.stringify(metadata, null, 2)}
|
|
22366
22484
|
`, "utf8");
|
|
22367
22485
|
}
|
|
22368
22486
|
async function touchRuntimeInstallMetadata(cacheDir, postgresRuntime) {
|
|
@@ -22390,7 +22508,7 @@ function resolveEmbeddedPostgresPlatformPackage(platform = process.platform, arc
|
|
|
22390
22508
|
}
|
|
22391
22509
|
async function canResolveRuntimePackage(cacheDir, packageName) {
|
|
22392
22510
|
try {
|
|
22393
|
-
await readFile(
|
|
22511
|
+
await readFile(path10.join(cacheDir, "node_modules", ...packageName.split("/"), "package.json"), "utf8");
|
|
22394
22512
|
return true;
|
|
22395
22513
|
} catch {
|
|
22396
22514
|
return false;
|
|
@@ -22402,9 +22520,9 @@ async function hasRequiredRuntimePlatformDependencies(cacheDir, metadata, postgr
|
|
|
22402
22520
|
if (!platformPackage) return true;
|
|
22403
22521
|
if (await canResolveRuntimePackage(cacheDir, platformPackage)) return true;
|
|
22404
22522
|
const expectedSharedBinDir = resolveSharedRuntimePostgresPayloadBinDir(
|
|
22405
|
-
|
|
22523
|
+
path10.dirname(path10.dirname(cacheDir))
|
|
22406
22524
|
);
|
|
22407
|
-
return metadata.postgresRuntime?.scope === "shared" && metadata.postgresRuntime.platform === process.platform && metadata.postgresRuntime.arch === process.arch &&
|
|
22525
|
+
return metadata.postgresRuntime?.scope === "shared" && metadata.postgresRuntime.platform === process.platform && metadata.postgresRuntime.arch === process.arch && path10.resolve(metadata.postgresRuntime.binDir) === path10.resolve(expectedSharedBinDir) && await isRuntimePostgresPayloadUsable(
|
|
22408
22526
|
cacheDir,
|
|
22409
22527
|
metadata.postgresRuntime.binDir,
|
|
22410
22528
|
postgresVersionProbe,
|
|
@@ -22419,7 +22537,7 @@ async function isRuntimeCacheHitWithinDeadline(options, deadline) {
|
|
|
22419
22537
|
return false;
|
|
22420
22538
|
}
|
|
22421
22539
|
try {
|
|
22422
|
-
const packageJsonPath =
|
|
22540
|
+
const packageJsonPath = path10.join(options.cacheDir, "node_modules", ...packageName.split("/"), "package.json");
|
|
22423
22541
|
const packageJson = JSON.parse(await readFile(packageJsonPath, "utf8"));
|
|
22424
22542
|
const packageVersionMatches = packageVersion === "latest" || packageJson.version === packageVersion;
|
|
22425
22543
|
return packageVersionMatches && await hasRequiredRuntimePlatformDependencies(
|
|
@@ -22439,7 +22557,7 @@ async function ensureRuntimeInstalled(options) {
|
|
|
22439
22557
|
const cacheDir = resolveRuntimeCacheDir(packageVersion, homeDir);
|
|
22440
22558
|
const deadline = createRuntimeInstallDeadline(options);
|
|
22441
22559
|
return withRuntimeFilesystemLock(
|
|
22442
|
-
|
|
22560
|
+
path10.join(homeDir, "runtime-payloads", ".postgres-runtime.lifecycle.lock"),
|
|
22443
22561
|
async () => withRuntimeFilesystemLock(
|
|
22444
22562
|
`${cacheDir}.install.lock`,
|
|
22445
22563
|
async () => {
|
|
@@ -22562,7 +22680,7 @@ async function ensureRuntimeInstalledUnlocked(options, deadline) {
|
|
|
22562
22680
|
}
|
|
22563
22681
|
await rm(cacheDir, { recursive: true, force: true });
|
|
22564
22682
|
await mkdir(cacheDir, { recursive: true });
|
|
22565
|
-
await writeFile(
|
|
22683
|
+
await writeFile(path10.join(cacheDir, "package.json"), `${JSON.stringify(RUNTIME_CACHE_PACKAGE_JSON, null, 2)}
|
|
22566
22684
|
`, "utf8");
|
|
22567
22685
|
const result = runNpmRuntimeInstall(spawnSyncImpl, cacheDir, packageSpec, deadline);
|
|
22568
22686
|
let output = collectSpawnOutput(result);
|
|
@@ -22602,7 +22720,7 @@ async function ensureRuntimeInstalledUnlocked(options, deadline) {
|
|
|
22602
22720
|
}
|
|
22603
22721
|
await rm(fallbackCacheDir, { recursive: true, force: true });
|
|
22604
22722
|
await mkdir(fallbackCacheDir, { recursive: true });
|
|
22605
|
-
await writeFile(
|
|
22723
|
+
await writeFile(path10.join(fallbackCacheDir, "package.json"), `${JSON.stringify(RUNTIME_CACHE_PACKAGE_JSON, null, 2)}
|
|
22606
22724
|
`, "utf8");
|
|
22607
22725
|
const fallbackResult = runNpmRuntimeInstall(spawnSyncImpl, fallbackCacheDir, fallbackSpec, deadline);
|
|
22608
22726
|
let fallbackOutput = collectSpawnOutput(fallbackResult);
|
|
@@ -22684,10 +22802,10 @@ async function ensureRuntimeInstalledUnlocked(options, deadline) {
|
|
|
22684
22802
|
);
|
|
22685
22803
|
}
|
|
22686
22804
|
function resolveRuntimePostgresPayloadBinDir(cacheDir, platform = process.platform, arch = process.arch) {
|
|
22687
|
-
return
|
|
22805
|
+
return path10.join(cacheDir, RUNTIME_POSTGRES_PAYLOAD_DIR, runtimePostgresPlatformSegment(platform, arch), "bin");
|
|
22688
22806
|
}
|
|
22689
22807
|
function resolveSharedRuntimePostgresPayloadBinDir(homeDir = resolveRudderHomeDir(), platform = process.platform, arch = process.arch) {
|
|
22690
|
-
return
|
|
22808
|
+
return path10.join(
|
|
22691
22809
|
homeDir,
|
|
22692
22810
|
"runtime-payloads",
|
|
22693
22811
|
RUNTIME_POSTGRES_PAYLOAD_DIR,
|
|
@@ -22696,7 +22814,7 @@ function resolveSharedRuntimePostgresPayloadBinDir(homeDir = resolveRudderHomeDi
|
|
|
22696
22814
|
);
|
|
22697
22815
|
}
|
|
22698
22816
|
function resolveRuntimeServerEntrypoint(cacheDir, packageName = RUNTIME_NPM_PACKAGE_NAME) {
|
|
22699
|
-
return createRequire(
|
|
22817
|
+
return createRequire(path10.join(cacheDir, "package.json")).resolve(packageName);
|
|
22700
22818
|
}
|
|
22701
22819
|
async function importRuntimeServerModule(cacheDir, packageName = RUNTIME_NPM_PACKAGE_NAME) {
|
|
22702
22820
|
const entrypoint = resolveRuntimeServerEntrypoint(cacheDir, packageName);
|
|
@@ -22720,7 +22838,7 @@ function formatRuntimeInstallCommand(cacheDir, packageSpec) {
|
|
|
22720
22838
|
return `npm install --prefix ${cacheDir} ${RUNTIME_NPM_INSTALL_FLAGS.join(" ")} ${packageSpec}`;
|
|
22721
22839
|
}
|
|
22722
22840
|
function formatRuntimePlatformRepairCommand(cacheDir, packageSpec) {
|
|
22723
|
-
return `npm pack ${packageSpec} --registry=${NPM_PUBLIC_REGISTRY_URL} --silent, then extract it into ${
|
|
22841
|
+
return `npm pack ${packageSpec} --registry=${NPM_PUBLIC_REGISTRY_URL} --silent, then extract it into ${path10.join(cacheDir, "node_modules")}`;
|
|
22724
22842
|
}
|
|
22725
22843
|
function collectSpawnOutput(result) {
|
|
22726
22844
|
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();
|
|
@@ -22737,7 +22855,7 @@ function withPostgresPayload(result, postgresPayload) {
|
|
|
22737
22855
|
};
|
|
22738
22856
|
}
|
|
22739
22857
|
function runtimePackageJsonPath(cacheDir, packageName) {
|
|
22740
|
-
return
|
|
22858
|
+
return path10.join(cacheDir, "node_modules", ...packageName.split("/"), "package.json");
|
|
22741
22859
|
}
|
|
22742
22860
|
async function readRuntimePackageJson(cacheDir, packageName) {
|
|
22743
22861
|
try {
|
|
@@ -22792,7 +22910,7 @@ async function ensureRequiredEmbeddedPostgresPlatformPackage(spawnSyncImpl, cach
|
|
|
22792
22910
|
);
|
|
22793
22911
|
}
|
|
22794
22912
|
async function installRuntimePackageInStaging(spawnSyncImpl, cacheDir, packageSpec, packageName, deadline) {
|
|
22795
|
-
const stagingDir =
|
|
22913
|
+
const stagingDir = path10.join(cacheDir, `.platform-repair-${process.pid}-${Date.now()}`);
|
|
22796
22914
|
await mkdir(stagingDir, { recursive: true });
|
|
22797
22915
|
try {
|
|
22798
22916
|
const packResult = runNpmPack(spawnSyncImpl, packageSpec, stagingDir, cacheDir, deadline);
|
|
@@ -22801,9 +22919,9 @@ async function installRuntimePackageInStaging(spawnSyncImpl, cacheDir, packageSp
|
|
|
22801
22919
|
if (!packFilename) {
|
|
22802
22920
|
return createSyntheticSpawnResult(1, "", `Unable to parse npm pack output for ${packageSpec}.`);
|
|
22803
22921
|
}
|
|
22804
|
-
const archivePath =
|
|
22805
|
-
const targetDir =
|
|
22806
|
-
await mkdir(
|
|
22922
|
+
const archivePath = path10.join(stagingDir, packFilename);
|
|
22923
|
+
const targetDir = path10.dirname(runtimePackageJsonPath(cacheDir, packageName));
|
|
22924
|
+
await mkdir(path10.dirname(targetDir), { recursive: true });
|
|
22807
22925
|
await rm(targetDir, { recursive: true, force: true });
|
|
22808
22926
|
await mkdir(targetDir, { recursive: true });
|
|
22809
22927
|
const extractResult = runTarExtract(spawnSyncImpl, archivePath, targetDir, cacheDir, deadline);
|
|
@@ -22859,8 +22977,8 @@ function combineSpawnResults(...results) {
|
|
|
22859
22977
|
}
|
|
22860
22978
|
async function removeRuntimeInstallLocks(cacheDir) {
|
|
22861
22979
|
await Promise.all([
|
|
22862
|
-
rm(
|
|
22863
|
-
rm(
|
|
22980
|
+
rm(path10.join(cacheDir, "package-lock.json"), { force: true }),
|
|
22981
|
+
rm(path10.join(cacheDir, "node_modules", ".package-lock.json"), { force: true })
|
|
22864
22982
|
]);
|
|
22865
22983
|
}
|
|
22866
22984
|
function packageNameFromSpec(packageSpec) {
|
|
@@ -22884,25 +23002,25 @@ function runtimePostgresExecutableName(baseName) {
|
|
|
22884
23002
|
return process.platform === "win32" ? `${baseName}.exe` : baseName;
|
|
22885
23003
|
}
|
|
22886
23004
|
function debianSharedirCandidate(binDir) {
|
|
22887
|
-
const normalized =
|
|
22888
|
-
const parts = normalized.split(
|
|
23005
|
+
const normalized = path10.resolve(binDir);
|
|
23006
|
+
const parts = normalized.split(path10.sep);
|
|
22889
23007
|
const libIndex = parts.lastIndexOf("lib");
|
|
22890
23008
|
if (libIndex < 0) return null;
|
|
22891
23009
|
if (parts[libIndex + 1] !== "postgresql") return null;
|
|
22892
23010
|
const version = parts[libIndex + 2];
|
|
22893
23011
|
if (!version || parts[libIndex + 3] !== "bin") return null;
|
|
22894
|
-
const prefix = parts.slice(0, libIndex).join(
|
|
22895
|
-
return
|
|
23012
|
+
const prefix = parts.slice(0, libIndex).join(path10.sep) || path10.sep;
|
|
23013
|
+
return path10.join(prefix, "share", "postgresql", version);
|
|
22896
23014
|
}
|
|
22897
23015
|
async function resolveRuntimePostgresTemplateDir(binDir, cacheDir = binDir, deadline) {
|
|
22898
23016
|
for (const candidatePath of [
|
|
22899
|
-
|
|
22900
|
-
|
|
23017
|
+
path10.join(binDir, "..", "share", "postgresql", "postgres.bki"),
|
|
23018
|
+
path10.join(binDir, "..", "share", "postgres.bki")
|
|
22901
23019
|
]) {
|
|
22902
23020
|
remainingRuntimeInstallMs(deadline, cacheDir, "discover PostgreSQL runtime templates");
|
|
22903
23021
|
try {
|
|
22904
23022
|
await stat(candidatePath);
|
|
22905
|
-
return
|
|
23023
|
+
return path10.dirname(candidatePath);
|
|
22906
23024
|
} catch {
|
|
22907
23025
|
}
|
|
22908
23026
|
}
|
|
@@ -22910,12 +23028,12 @@ async function resolveRuntimePostgresTemplateDir(binDir, cacheDir = binDir, dead
|
|
|
22910
23028
|
if (debianSharedir) {
|
|
22911
23029
|
remainingRuntimeInstallMs(deadline, cacheDir, "discover PostgreSQL runtime templates");
|
|
22912
23030
|
try {
|
|
22913
|
-
await stat(
|
|
23031
|
+
await stat(path10.join(debianSharedir, "postgres.bki"));
|
|
22914
23032
|
return debianSharedir;
|
|
22915
23033
|
} catch {
|
|
22916
23034
|
}
|
|
22917
23035
|
}
|
|
22918
|
-
const pgConfigPath =
|
|
23036
|
+
const pgConfigPath = path10.join(binDir, process.platform === "win32" ? "pg_config.exe" : "pg_config");
|
|
22919
23037
|
try {
|
|
22920
23038
|
remainingRuntimeInstallMs(deadline, cacheDir, "discover PostgreSQL runtime templates");
|
|
22921
23039
|
await stat(pgConfigPath);
|
|
@@ -22934,7 +23052,7 @@ async function resolveRuntimePostgresTemplateDir(binDir, cacheDir = binDir, dead
|
|
|
22934
23052
|
}
|
|
22935
23053
|
if (!sharedir) return null;
|
|
22936
23054
|
remainingRuntimeInstallMs(deadline, cacheDir, "validate PostgreSQL runtime templates");
|
|
22937
|
-
const candidatePath =
|
|
23055
|
+
const candidatePath = path10.join(sharedir, "postgres.bki");
|
|
22938
23056
|
await stat(candidatePath);
|
|
22939
23057
|
return sharedir;
|
|
22940
23058
|
} catch (error) {
|
|
@@ -22943,7 +23061,7 @@ async function resolveRuntimePostgresTemplateDir(binDir, cacheDir = binDir, dead
|
|
|
22943
23061
|
}
|
|
22944
23062
|
}
|
|
22945
23063
|
function resolveRuntimePostgresShareDir(binDir, templateDir) {
|
|
22946
|
-
const adjacentShareDir =
|
|
23064
|
+
const adjacentShareDir = path10.resolve(binDir, "..", "share");
|
|
22947
23065
|
return pathIsInside(templateDir, adjacentShareDir) ? adjacentShareDir : templateDir;
|
|
22948
23066
|
}
|
|
22949
23067
|
async function assertRuntimePostgresBinDirComplete(cacheDir, binDir, deadline) {
|
|
@@ -22951,7 +23069,7 @@ async function assertRuntimePostgresBinDirComplete(cacheDir, binDir, deadline) {
|
|
|
22951
23069
|
const missing = [];
|
|
22952
23070
|
for (const binary of requiredBinaries) {
|
|
22953
23071
|
remainingRuntimeInstallMs(deadline, cacheDir, "validate PostgreSQL runtime binaries");
|
|
22954
|
-
const binaryPath =
|
|
23072
|
+
const binaryPath = path10.join(binDir, runtimePostgresExecutableName(binary));
|
|
22955
23073
|
try {
|
|
22956
23074
|
await stat(binaryPath);
|
|
22957
23075
|
} catch {
|
|
@@ -22960,19 +23078,19 @@ async function assertRuntimePostgresBinDirComplete(cacheDir, binDir, deadline) {
|
|
|
22960
23078
|
}
|
|
22961
23079
|
const templateDir = await resolveRuntimePostgresTemplateDir(binDir, cacheDir, deadline);
|
|
22962
23080
|
if (!templateDir) {
|
|
22963
|
-
missing.push(
|
|
23081
|
+
missing.push(path10.join(binDir, "..", "share", "postgresql", "postgres.bki"));
|
|
22964
23082
|
} else {
|
|
22965
23083
|
try {
|
|
22966
|
-
await stat(
|
|
23084
|
+
await stat(path10.join(templateDir, "postgresql.conf.sample"));
|
|
22967
23085
|
} catch {
|
|
22968
|
-
missing.push(
|
|
23086
|
+
missing.push(path10.join(templateDir, "postgresql.conf.sample"));
|
|
22969
23087
|
}
|
|
22970
23088
|
const shareDir = resolveRuntimePostgresShareDir(binDir, templateDir);
|
|
22971
23089
|
const hasTimezoneDir = (await Promise.all([
|
|
22972
|
-
|
|
22973
|
-
|
|
23090
|
+
path10.join(templateDir, "timezone"),
|
|
23091
|
+
path10.join(shareDir, "timezone")
|
|
22974
23092
|
].map((candidate) => stat(candidate).catch(() => null)))).some((candidate) => candidate?.isDirectory());
|
|
22975
|
-
if (!hasTimezoneDir) missing.push(
|
|
23093
|
+
if (!hasTimezoneDir) missing.push(path10.join(shareDir, "timezone"));
|
|
22976
23094
|
}
|
|
22977
23095
|
if (missing.length > 0) {
|
|
22978
23096
|
throw new RuntimeInstallError(
|
|
@@ -22997,8 +23115,8 @@ async function isRuntimePostgresPayloadUsable(cacheDir, binDir, postgresVersionP
|
|
|
22997
23115
|
}
|
|
22998
23116
|
}
|
|
22999
23117
|
function pathIsInside(candidatePath, rootPath) {
|
|
23000
|
-
const relative =
|
|
23001
|
-
return relative === "" || relative !== ".." && !relative.startsWith(`..${
|
|
23118
|
+
const relative = path10.relative(path10.resolve(rootPath), path10.resolve(candidatePath));
|
|
23119
|
+
return relative === "" || relative !== ".." && !relative.startsWith(`..${path10.sep}`) && !path10.isAbsolute(relative);
|
|
23002
23120
|
}
|
|
23003
23121
|
async function copyRuntimePayloadEntry(sourcePath, targetPath, cacheDir, deadline, signal, command) {
|
|
23004
23122
|
if (signal.aborted) throw runtimeInstallDeadlineError(cacheDir, command);
|
|
@@ -23011,8 +23129,8 @@ async function copyRuntimePayloadEntry(sourcePath, targetPath, cacheDir, deadlin
|
|
|
23011
23129
|
const entries = await readdir(sourcePath);
|
|
23012
23130
|
for (const entry of entries) {
|
|
23013
23131
|
await copyRuntimePayloadEntry(
|
|
23014
|
-
|
|
23015
|
-
|
|
23132
|
+
path10.join(sourcePath, entry),
|
|
23133
|
+
path10.join(targetPath, entry),
|
|
23016
23134
|
cacheDir,
|
|
23017
23135
|
deadline,
|
|
23018
23136
|
signal,
|
|
@@ -23022,7 +23140,7 @@ async function copyRuntimePayloadEntry(sourcePath, targetPath, cacheDir, deadlin
|
|
|
23022
23140
|
return;
|
|
23023
23141
|
}
|
|
23024
23142
|
if (!sourceStats.isFile()) return;
|
|
23025
|
-
await mkdir(
|
|
23143
|
+
await mkdir(path10.dirname(targetPath), { recursive: true });
|
|
23026
23144
|
try {
|
|
23027
23145
|
await pipeline2(
|
|
23028
23146
|
createReadStream2(sourcePath),
|
|
@@ -23056,11 +23174,11 @@ async function copyRuntimePostgresPayloadWithinDeadline(sourceRuntimeDir, target
|
|
|
23056
23174
|
const copyPromise = (async () => {
|
|
23057
23175
|
await mkdir(targetRuntimeDir, { recursive: true });
|
|
23058
23176
|
for (const directoryName of ["bin", "lib"]) {
|
|
23059
|
-
const sourceDirectory =
|
|
23177
|
+
const sourceDirectory = path10.join(sourceRuntimeDir, directoryName);
|
|
23060
23178
|
if (!await stat(sourceDirectory).catch(() => null)) continue;
|
|
23061
23179
|
await copyRuntimePayloadEntry(
|
|
23062
23180
|
sourceDirectory,
|
|
23063
|
-
|
|
23181
|
+
path10.join(targetRuntimeDir, directoryName),
|
|
23064
23182
|
cacheDir,
|
|
23065
23183
|
deadline,
|
|
23066
23184
|
controller.signal,
|
|
@@ -23069,7 +23187,7 @@ async function copyRuntimePostgresPayloadWithinDeadline(sourceRuntimeDir, target
|
|
|
23069
23187
|
}
|
|
23070
23188
|
await copyRuntimePayloadEntry(
|
|
23071
23189
|
sourceShareDir,
|
|
23072
|
-
|
|
23190
|
+
path10.join(targetRuntimeDir, "share"),
|
|
23073
23191
|
cacheDir,
|
|
23074
23192
|
deadline,
|
|
23075
23193
|
controller.signal,
|
|
@@ -23087,15 +23205,15 @@ async function copyRuntimePostgresPayloadWithinDeadline(sourceRuntimeDir, target
|
|
|
23087
23205
|
async function withRuntimeFilesystemLock(lockPath, task, options = {}) {
|
|
23088
23206
|
const deadlineTimeout = remainingRuntimeInstallMs(
|
|
23089
23207
|
options.deadline,
|
|
23090
|
-
options.cacheDir ??
|
|
23208
|
+
options.cacheDir ?? path10.dirname(lockPath),
|
|
23091
23209
|
options.command ?? `wait for runtime lock ${lockPath}`
|
|
23092
23210
|
);
|
|
23093
23211
|
const timeoutMs = Math.min(options.timeoutMs ?? 3e4, deadlineTimeout ?? Number.POSITIVE_INFINITY);
|
|
23094
23212
|
const pollMs = options.pollMs ?? 50;
|
|
23095
23213
|
const startedAt = Date.now();
|
|
23096
23214
|
const lockId = `${process.pid}-${startedAt}-${Math.random().toString(16).slice(2)}`;
|
|
23097
|
-
const ownerPath =
|
|
23098
|
-
await mkdir(
|
|
23215
|
+
const ownerPath = path10.join(lockPath, "owner.json");
|
|
23216
|
+
await mkdir(path10.dirname(lockPath), { recursive: true });
|
|
23099
23217
|
while (true) {
|
|
23100
23218
|
try {
|
|
23101
23219
|
await mkdir(lockPath);
|
|
@@ -23124,12 +23242,12 @@ async function withRuntimeFilesystemLock(lockPath, task, options = {}) {
|
|
|
23124
23242
|
if (Date.now() - startedAt >= timeoutMs) {
|
|
23125
23243
|
throw new RuntimeInstallError(
|
|
23126
23244
|
`Timed out waiting for PostgreSQL runtime install lock ${lockPath}`,
|
|
23127
|
-
{ cacheDir:
|
|
23245
|
+
{ cacheDir: path10.dirname(lockPath), command: "prepare shared PostgreSQL runtime", output: "" }
|
|
23128
23246
|
);
|
|
23129
23247
|
}
|
|
23130
23248
|
remainingRuntimeInstallMs(
|
|
23131
23249
|
options.deadline,
|
|
23132
|
-
options.cacheDir ??
|
|
23250
|
+
options.cacheDir ?? path10.dirname(lockPath),
|
|
23133
23251
|
options.command ?? `wait for runtime lock ${lockPath}`
|
|
23134
23252
|
);
|
|
23135
23253
|
await new Promise((resolve) => setTimeout(resolve, pollMs));
|
|
@@ -23149,29 +23267,29 @@ async function withRuntimeFilesystemLock(lockPath, task, options = {}) {
|
|
|
23149
23267
|
}
|
|
23150
23268
|
function isManagedRuntimePostgresBinDir(binDir, homeDir) {
|
|
23151
23269
|
const managedBinDir = process.env[RUDDER_DESKTOP_MANAGED_POSTGRES_BIN_DIR_ENV]?.trim();
|
|
23152
|
-
if (managedBinDir &&
|
|
23153
|
-
const runtimesRelative =
|
|
23154
|
-
|
|
23155
|
-
|
|
23270
|
+
if (managedBinDir && path10.resolve(managedBinDir) === path10.resolve(binDir)) return true;
|
|
23271
|
+
const runtimesRelative = path10.relative(
|
|
23272
|
+
path10.join(homeDir, "runtimes"),
|
|
23273
|
+
path10.resolve(binDir)
|
|
23156
23274
|
);
|
|
23157
|
-
const runtimeSegments = runtimesRelative.split(
|
|
23158
|
-
if (runtimesRelative !== "" && runtimesRelative !== ".." && !runtimesRelative.startsWith(`..${
|
|
23275
|
+
const runtimeSegments = runtimesRelative.split(path10.sep);
|
|
23276
|
+
if (runtimesRelative !== "" && runtimesRelative !== ".." && !runtimesRelative.startsWith(`..${path10.sep}`) && !path10.isAbsolute(runtimesRelative) && runtimeSegments.length === 4 && runtimeSegments[0]?.length > 0 && runtimeSegments[1] === RUNTIME_POSTGRES_PAYLOAD_DIR && runtimeSegments[2] === `${process.platform}-${process.arch}` && runtimeSegments[3] === "bin") {
|
|
23159
23277
|
return true;
|
|
23160
23278
|
}
|
|
23161
|
-
const payloadsRelative =
|
|
23162
|
-
|
|
23163
|
-
|
|
23279
|
+
const payloadsRelative = path10.relative(
|
|
23280
|
+
path10.join(homeDir, "runtime-payloads"),
|
|
23281
|
+
path10.resolve(binDir)
|
|
23164
23282
|
);
|
|
23165
|
-
const payloadSegments = payloadsRelative.split(
|
|
23166
|
-
return payloadsRelative !== "" && payloadsRelative !== ".." && !payloadsRelative.startsWith(`..${
|
|
23283
|
+
const payloadSegments = payloadsRelative.split(path10.sep);
|
|
23284
|
+
return payloadsRelative !== "" && payloadsRelative !== ".." && !payloadsRelative.startsWith(`..${path10.sep}`) && !path10.isAbsolute(payloadsRelative) && payloadSegments.length === 3 && payloadSegments[0] === RUNTIME_POSTGRES_PAYLOAD_DIR && payloadSegments[1] === `${process.platform}-${process.arch}` && payloadSegments[2] === "bin";
|
|
23167
23285
|
}
|
|
23168
23286
|
async function findLegacyRuntimePostgresBinDir(cacheDir, homeDir, postgresVersionProbe, deadline) {
|
|
23169
|
-
const runtimesRoot =
|
|
23287
|
+
const runtimesRoot = path10.join(homeDir, "runtimes");
|
|
23170
23288
|
const entries = await readdir(runtimesRoot, { withFileTypes: true }).catch(() => []);
|
|
23171
23289
|
for (const entry of entries) {
|
|
23172
23290
|
if (!entry.isDirectory() && !entry.isSymbolicLink()) continue;
|
|
23173
|
-
const candidateCacheDir =
|
|
23174
|
-
if (
|
|
23291
|
+
const candidateCacheDir = path10.join(runtimesRoot, entry.name);
|
|
23292
|
+
if (path10.resolve(candidateCacheDir) === path10.resolve(cacheDir)) continue;
|
|
23175
23293
|
const candidateBinDir = resolveRuntimePostgresPayloadBinDir(candidateCacheDir);
|
|
23176
23294
|
remainingRuntimeInstallMs(deadline, cacheDir, "find cached PostgreSQL runtime payload");
|
|
23177
23295
|
if (await isRuntimePostgresPayloadUsable(cacheDir, candidateBinDir, postgresVersionProbe, deadline)) {
|
|
@@ -23181,13 +23299,13 @@ async function findLegacyRuntimePostgresBinDir(cacheDir, homeDir, postgresVersio
|
|
|
23181
23299
|
return null;
|
|
23182
23300
|
}
|
|
23183
23301
|
async function readLiveRuntimeDescriptors(homeDir) {
|
|
23184
|
-
const instancesRoot =
|
|
23302
|
+
const instancesRoot = path10.join(homeDir, "instances");
|
|
23185
23303
|
const entries = await readdir(instancesRoot, { withFileTypes: true }).catch(() => []);
|
|
23186
23304
|
const descriptors = [];
|
|
23187
23305
|
for (const entry of entries) {
|
|
23188
23306
|
if (!entry.isDirectory()) continue;
|
|
23189
23307
|
try {
|
|
23190
|
-
const raw = JSON.parse(await readFile(
|
|
23308
|
+
const raw = JSON.parse(await readFile(path10.join(instancesRoot, entry.name, "runtime", "server.json"), "utf8"));
|
|
23191
23309
|
if (typeof raw.pid !== "number" || !Number.isInteger(raw.pid) || !isPidRunning(raw.pid) || typeof raw.version !== "string") {
|
|
23192
23310
|
continue;
|
|
23193
23311
|
}
|
|
@@ -23205,13 +23323,13 @@ async function assertSharedPostgresPayloadNotLive(cacheDir, homeDir, sharedBinDi
|
|
|
23205
23323
|
const sharedPhysicalBinDir = await realpath(sharedBinDir).catch(() => null);
|
|
23206
23324
|
const mayReferenceSharedPayload = await Promise.all(liveDescriptors.map(async (descriptor) => {
|
|
23207
23325
|
if (descriptor.postgresBinDir === void 0) return true;
|
|
23208
|
-
if (
|
|
23326
|
+
if (path10.resolve(descriptor.postgresBinDir) === path10.resolve(sharedBinDir)) return true;
|
|
23209
23327
|
const descriptorPhysicalBinDir = await realpath(descriptor.postgresBinDir).catch(() => null);
|
|
23210
|
-
if (descriptorPhysicalBinDir && sharedPhysicalBinDir &&
|
|
23328
|
+
if (descriptorPhysicalBinDir && sharedPhysicalBinDir && path10.resolve(descriptorPhysicalBinDir) === path10.resolve(sharedPhysicalBinDir)) {
|
|
23211
23329
|
return true;
|
|
23212
23330
|
}
|
|
23213
23331
|
if (!descriptorPhysicalBinDir) {
|
|
23214
|
-
return pathIsInside(descriptor.postgresBinDir,
|
|
23332
|
+
return pathIsInside(descriptor.postgresBinDir, path10.join(homeDir, "runtimes")) || pathIsInside(descriptor.postgresBinDir, path10.join(homeDir, "runtime-payloads"));
|
|
23215
23333
|
}
|
|
23216
23334
|
return false;
|
|
23217
23335
|
}));
|
|
@@ -23226,7 +23344,7 @@ async function validateRuntimePostgresVersion(cacheDir, binDir, postgresVersionP
|
|
|
23226
23344
|
await assertRuntimePostgresBinDirComplete(cacheDir, binDir, deadline);
|
|
23227
23345
|
for (const binary of ["initdb", "pg_ctl", "postgres"]) {
|
|
23228
23346
|
remainingRuntimeInstallMs(deadline, cacheDir, "validate PostgreSQL runtime version");
|
|
23229
|
-
const binaryPath =
|
|
23347
|
+
const binaryPath = path10.join(binDir, runtimePostgresExecutableName(binary));
|
|
23230
23348
|
const result = postgresVersionProbe(binaryPath);
|
|
23231
23349
|
if (!/\bPostgreSQL\)?\s+18\.4\b/i.test(result)) {
|
|
23232
23350
|
throw new RuntimeInstallError(
|
|
@@ -23266,24 +23384,24 @@ async function findRuntimePostgresBinDir(rootDir, cacheDir, postgresVersionProbe
|
|
|
23266
23384
|
if (await isRuntimePostgresPayloadUsable(cacheDir, current, postgresVersionProbe, deadline)) return current;
|
|
23267
23385
|
const entries = await readdir(current, { withFileTypes: true }).catch(() => []);
|
|
23268
23386
|
for (const entry of entries) {
|
|
23269
|
-
if (entry.isDirectory()) queue.push(
|
|
23387
|
+
if (entry.isDirectory()) queue.push(path10.join(current, entry.name));
|
|
23270
23388
|
}
|
|
23271
23389
|
}
|
|
23272
23390
|
return null;
|
|
23273
23391
|
}
|
|
23274
23392
|
async function reconcileSharedPostgresPayloadGenerations(cacheDir, sharedPlatformRoot, postgresVersionProbe, cleanupDownloads = false, deadline) {
|
|
23275
23393
|
remainingRuntimeInstallMs(deadline, cacheDir, "reconcile shared PostgreSQL payload");
|
|
23276
|
-
const parentDir =
|
|
23277
|
-
const baseName =
|
|
23394
|
+
const parentDir = path10.dirname(sharedPlatformRoot);
|
|
23395
|
+
const baseName = path10.basename(sharedPlatformRoot);
|
|
23278
23396
|
const entries = await readdir(parentDir, { withFileTypes: true }).catch(() => []);
|
|
23279
|
-
const temporaryRoots = entries.filter((entry) => entry.name.startsWith(`${baseName}.tmp-`)).map((entry) =>
|
|
23280
|
-
const previousRoots = entries.filter((entry) => entry.name.startsWith(`${baseName}.previous-`)).map((entry) =>
|
|
23281
|
-
const downloadsRoot =
|
|
23282
|
-
|
|
23397
|
+
const temporaryRoots = entries.filter((entry) => entry.name.startsWith(`${baseName}.tmp-`)).map((entry) => path10.join(parentDir, entry.name));
|
|
23398
|
+
const previousRoots = entries.filter((entry) => entry.name.startsWith(`${baseName}.previous-`)).map((entry) => path10.join(parentDir, entry.name)).sort().reverse();
|
|
23399
|
+
const downloadsRoot = path10.join(
|
|
23400
|
+
path10.dirname(path10.dirname(sharedPlatformRoot)),
|
|
23283
23401
|
".downloads"
|
|
23284
23402
|
);
|
|
23285
|
-
const staleDownloadRoots = cleanupDownloads ? (await readdir(downloadsRoot, { withFileTypes: true }).catch(() => [])).filter((entry) => entry.name.startsWith("postgres-18.4-")).map((entry) =>
|
|
23286
|
-
const canonicalBinDir =
|
|
23403
|
+
const staleDownloadRoots = cleanupDownloads ? (await readdir(downloadsRoot, { withFileTypes: true }).catch(() => [])).filter((entry) => entry.name.startsWith("postgres-18.4-")).map((entry) => path10.join(downloadsRoot, entry.name)) : [];
|
|
23404
|
+
const canonicalBinDir = path10.join(sharedPlatformRoot, "bin");
|
|
23287
23405
|
if (!await isRuntimePostgresPayloadUsable(
|
|
23288
23406
|
cacheDir,
|
|
23289
23407
|
canonicalBinDir,
|
|
@@ -23293,7 +23411,7 @@ async function reconcileSharedPostgresPayloadGenerations(cacheDir, sharedPlatfor
|
|
|
23293
23411
|
for (const previousRoot of previousRoots) {
|
|
23294
23412
|
if (!await isRuntimePostgresPayloadUsable(
|
|
23295
23413
|
cacheDir,
|
|
23296
|
-
|
|
23414
|
+
path10.join(previousRoot, "bin"),
|
|
23297
23415
|
postgresVersionProbe,
|
|
23298
23416
|
deadline
|
|
23299
23417
|
)) {
|
|
@@ -23312,9 +23430,9 @@ async function reconcileSharedPostgresPayloadGenerations(cacheDir, sharedPlatfor
|
|
|
23312
23430
|
}
|
|
23313
23431
|
async function installSharedRuntimePostgresPayload(cacheDir, homeDir, sourceBinDir, postgresVersionProbe, deadline) {
|
|
23314
23432
|
const sharedBinDir = resolveSharedRuntimePostgresPayloadBinDir(homeDir);
|
|
23315
|
-
const sharedRuntimeDir =
|
|
23433
|
+
const sharedRuntimeDir = path10.dirname(sharedBinDir);
|
|
23316
23434
|
const sharedPlatformRoot = sharedRuntimeDir;
|
|
23317
|
-
const sourceRuntimeDir =
|
|
23435
|
+
const sourceRuntimeDir = path10.dirname(sourceBinDir);
|
|
23318
23436
|
const sourceTemplateDir = await resolveRuntimePostgresTemplateDir(sourceBinDir, cacheDir, deadline);
|
|
23319
23437
|
if (!sourceTemplateDir) {
|
|
23320
23438
|
throw new RuntimeInstallError(
|
|
@@ -23335,7 +23453,7 @@ async function installSharedRuntimePostgresPayload(cacheDir, homeDir, sourceBinD
|
|
|
23335
23453
|
return sharedBinDir;
|
|
23336
23454
|
}
|
|
23337
23455
|
await assertSharedPostgresPayloadNotLive(cacheDir, homeDir, sharedBinDir);
|
|
23338
|
-
await mkdir(
|
|
23456
|
+
await mkdir(path10.dirname(sharedPlatformRoot), { recursive: true });
|
|
23339
23457
|
const temporaryPlatformRoot = `${sharedPlatformRoot}.tmp-${process.pid}-${Date.now()}`;
|
|
23340
23458
|
const previousPlatformRoot = `${sharedPlatformRoot}.previous-${process.pid}-${Date.now()}`;
|
|
23341
23459
|
let previousMoved = false;
|
|
@@ -23352,7 +23470,7 @@ async function installSharedRuntimePostgresPayload(cacheDir, homeDir, sourceBinD
|
|
|
23352
23470
|
cacheDir,
|
|
23353
23471
|
deadline
|
|
23354
23472
|
);
|
|
23355
|
-
const temporaryBinDir =
|
|
23473
|
+
const temporaryBinDir = path10.join(temporaryRuntimeDir, "bin");
|
|
23356
23474
|
await validateRuntimePostgresVersion(cacheDir, temporaryBinDir, postgresVersionProbe, deadline);
|
|
23357
23475
|
try {
|
|
23358
23476
|
await rename(sharedPlatformRoot, previousPlatformRoot);
|
|
@@ -23388,17 +23506,17 @@ async function downloadSharedRuntimePostgresPayload(cacheDir, homeDir, postgresV
|
|
|
23388
23506
|
const archiveUrl = archiveSource?.url ?? null;
|
|
23389
23507
|
if (!archiveUrl) return null;
|
|
23390
23508
|
const sharedBinDir = resolveSharedRuntimePostgresPayloadBinDir(homeDir);
|
|
23391
|
-
const sharedPlatformRoot =
|
|
23509
|
+
const sharedPlatformRoot = path10.dirname(sharedBinDir);
|
|
23392
23510
|
const downloadLockPath = `${sharedPlatformRoot}.download.lock`;
|
|
23393
23511
|
return withRuntimeFilesystemLock(downloadLockPath, async () => {
|
|
23394
23512
|
if (await isRuntimePostgresPayloadUsable(cacheDir, sharedBinDir, postgresVersionProbe, deadline)) {
|
|
23395
23513
|
return sharedBinDir;
|
|
23396
23514
|
}
|
|
23397
|
-
const workRoot =
|
|
23515
|
+
const workRoot = path10.join(homeDir, "runtime-payloads", ".downloads");
|
|
23398
23516
|
await mkdir(workRoot, { recursive: true });
|
|
23399
|
-
const workDir = await mkdtemp(
|
|
23400
|
-
const archivePath =
|
|
23401
|
-
const extractDir =
|
|
23517
|
+
const workDir = await mkdtemp(path10.join(workRoot, "postgres-18.4-"));
|
|
23518
|
+
const archivePath = path10.join(workDir, "postgresql-18.4.zip");
|
|
23519
|
+
const extractDir = path10.join(workDir, "extract");
|
|
23402
23520
|
try {
|
|
23403
23521
|
await downloadRuntimePostgresArchive(
|
|
23404
23522
|
archiveUrl,
|
|
@@ -23409,7 +23527,7 @@ async function downloadSharedRuntimePostgresPayload(cacheDir, homeDir, postgresV
|
|
|
23409
23527
|
const configuredMaxBytes = Number.parseInt(process.env[RUDDER_POSTGRES_RUNTIME_ARCHIVE_MAX_BYTES_ENV2] ?? "", 10);
|
|
23410
23528
|
const maxArchiveBytes = Number.isSafeInteger(configuredMaxBytes) && configuredMaxBytes > 0 ? configuredMaxBytes : DEFAULT_RUNTIME_POSTGRES_ARCHIVE_MAX_BYTES2;
|
|
23411
23529
|
const nativePublishStaging = `${sharedPlatformRoot}.tmp-native-${process.pid}-${Date.now()}`;
|
|
23412
|
-
await mkdir(
|
|
23530
|
+
await mkdir(path10.dirname(sharedPlatformRoot), { recursive: true });
|
|
23413
23531
|
const nativeInstall = await tryInstallNativePayload({
|
|
23414
23532
|
archivePath,
|
|
23415
23533
|
extractPath: extractDir,
|
|
@@ -23441,22 +23559,22 @@ async function downloadSharedRuntimePostgresPayload(cacheDir, homeDir, postgresV
|
|
|
23441
23559
|
);
|
|
23442
23560
|
}
|
|
23443
23561
|
await copyRuntimePostgresPayloadWithinDeadline(
|
|
23444
|
-
|
|
23562
|
+
path10.dirname(extractedBinDir2),
|
|
23445
23563
|
publishStagingPath,
|
|
23446
23564
|
resolveRuntimePostgresShareDir(extractedBinDir2, templateDir),
|
|
23447
23565
|
cacheDir,
|
|
23448
23566
|
deadline,
|
|
23449
23567
|
context.signal
|
|
23450
23568
|
);
|
|
23451
|
-
return
|
|
23569
|
+
return path10.relative(
|
|
23452
23570
|
publishStagingPath,
|
|
23453
|
-
|
|
23571
|
+
path10.join(publishStagingPath, "bin", runtimePostgresExecutableName("postgres"))
|
|
23454
23572
|
);
|
|
23455
23573
|
},
|
|
23456
23574
|
validatePublished: async (destinationPath) => {
|
|
23457
23575
|
await validateRuntimePostgresVersion(
|
|
23458
23576
|
cacheDir,
|
|
23459
|
-
|
|
23577
|
+
path10.join(destinationPath, "bin"),
|
|
23460
23578
|
postgresVersionProbe,
|
|
23461
23579
|
deadline
|
|
23462
23580
|
);
|
|
@@ -23494,20 +23612,20 @@ async function downloadSharedRuntimePostgresPayload(cacheDir, homeDir, postgresV
|
|
|
23494
23612
|
}, { deadline, cacheDir, command: "acquire shared PostgreSQL download lock" });
|
|
23495
23613
|
}
|
|
23496
23614
|
async function ensureRuntimePostgresCompatibilityLink(cacheDir, homeDir, packageVersion) {
|
|
23497
|
-
const compatibilityRoot =
|
|
23498
|
-
const sharedPayloadRoot =
|
|
23615
|
+
const compatibilityRoot = path10.join(cacheDir, RUNTIME_POSTGRES_PAYLOAD_DIR);
|
|
23616
|
+
const sharedPayloadRoot = path10.join(homeDir, "runtime-payloads", RUNTIME_POSTGRES_PAYLOAD_DIR);
|
|
23499
23617
|
const runtimeMetadata = await readRuntimeInstallMetadata(cacheDir);
|
|
23500
23618
|
const liveDescriptors = await readLiveRuntimeDescriptors(homeDir);
|
|
23501
23619
|
const compatibilityBinDir = resolveRuntimePostgresPayloadBinDir(cacheDir);
|
|
23502
23620
|
const isProtected = liveDescriptors.some((descriptor) => descriptor.postgresBinDir && pathIsInside(descriptor.postgresBinDir, compatibilityRoot) || !descriptor.postgresBinDir && descriptor.version === (runtimeMetadata?.packageVersion ?? packageVersion));
|
|
23503
23621
|
if (isProtected) return;
|
|
23504
|
-
await mkdir(
|
|
23622
|
+
await mkdir(path10.dirname(compatibilityRoot), { recursive: true });
|
|
23505
23623
|
const temporaryRoot = `${compatibilityRoot}.next-${process.pid}-${Date.now()}`;
|
|
23506
23624
|
const previousRoot = `${compatibilityRoot}.previous-${process.pid}-${Date.now()}`;
|
|
23507
23625
|
await rm(temporaryRoot, { recursive: true, force: true });
|
|
23508
23626
|
await rm(previousRoot, { recursive: true, force: true });
|
|
23509
23627
|
await symlink(
|
|
23510
|
-
process.platform === "win32" ? sharedPayloadRoot :
|
|
23628
|
+
process.platform === "win32" ? sharedPayloadRoot : path10.relative(path10.dirname(compatibilityRoot), sharedPayloadRoot),
|
|
23511
23629
|
temporaryRoot,
|
|
23512
23630
|
process.platform === "win32" ? "junction" : "dir"
|
|
23513
23631
|
);
|
|
@@ -23540,7 +23658,7 @@ async function ensureRuntimePostgresCompatibilityLink(cacheDir, homeDir, package
|
|
|
23540
23658
|
async function stageRuntimePostgresPayload(cacheDir, homeDir, packageVersion, enabled, postgresVersionProbe, deadline, cleanupDownloadWorkDir) {
|
|
23541
23659
|
if (!enabled) return { output: "" };
|
|
23542
23660
|
const explicitSourceBinDir = process.env[RUDDER_POSTGRES_BIN_DIR_ENV]?.trim();
|
|
23543
|
-
const resolvedExplicitSourceBinDir = explicitSourceBinDir ?
|
|
23661
|
+
const resolvedExplicitSourceBinDir = explicitSourceBinDir ? path10.resolve(explicitSourceBinDir) : null;
|
|
23544
23662
|
if (resolvedExplicitSourceBinDir && !isManagedRuntimePostgresBinDir(resolvedExplicitSourceBinDir, homeDir)) {
|
|
23545
23663
|
await validateRuntimePostgresVersion(
|
|
23546
23664
|
cacheDir,
|
|
@@ -23561,7 +23679,7 @@ async function stageRuntimePostgresPayload(cacheDir, homeDir, packageVersion, en
|
|
|
23561
23679
|
};
|
|
23562
23680
|
}
|
|
23563
23681
|
const sharedBinDir = resolveSharedRuntimePostgresPayloadBinDir(homeDir);
|
|
23564
|
-
const sharedPlatformRoot =
|
|
23682
|
+
const sharedPlatformRoot = path10.dirname(sharedBinDir);
|
|
23565
23683
|
await withRuntimeFilesystemLock(
|
|
23566
23684
|
`${sharedPlatformRoot}.install.lock`,
|
|
23567
23685
|
async () => reconcileSharedPostgresPayloadGenerations(
|
|
@@ -23673,13 +23791,13 @@ async function pruneRuntimeCache(options = {}) {
|
|
|
23673
23791
|
};
|
|
23674
23792
|
}
|
|
23675
23793
|
async function scanRuntimeCacheEntries(homeDir) {
|
|
23676
|
-
const runtimesDir =
|
|
23794
|
+
const runtimesDir = path10.join(homeDir, "runtimes");
|
|
23677
23795
|
const dirents = await readdir(runtimesDir, { withFileTypes: true }).catch(() => null);
|
|
23678
23796
|
if (!dirents) return [];
|
|
23679
23797
|
const entries = [];
|
|
23680
23798
|
for (const dirent of dirents) {
|
|
23681
23799
|
if (!dirent.isDirectory()) continue;
|
|
23682
|
-
const cacheDir =
|
|
23800
|
+
const cacheDir = path10.join(runtimesDir, dirent.name);
|
|
23683
23801
|
const metadata = await readRuntimeInstallMetadata(cacheDir);
|
|
23684
23802
|
if (!metadata) continue;
|
|
23685
23803
|
const fallbackStat = await safeStat(cacheDir);
|
|
@@ -23712,7 +23830,7 @@ async function directorySizeBytes(targetPath) {
|
|
|
23712
23830
|
if (!dirents) return 0;
|
|
23713
23831
|
let total = 0;
|
|
23714
23832
|
for (const dirent of dirents) {
|
|
23715
|
-
const entryPath =
|
|
23833
|
+
const entryPath = path10.join(targetPath, dirent.name);
|
|
23716
23834
|
if (dirent.isSymbolicLink()) continue;
|
|
23717
23835
|
if (dirent.isDirectory()) {
|
|
23718
23836
|
total += await directorySizeBytes(entryPath);
|
|
@@ -23724,14 +23842,14 @@ async function directorySizeBytes(targetPath) {
|
|
|
23724
23842
|
return total;
|
|
23725
23843
|
}
|
|
23726
23844
|
async function readActiveRuntimeVersions(homeDir) {
|
|
23727
|
-
const instancesDir =
|
|
23845
|
+
const instancesDir = path10.join(homeDir, "instances");
|
|
23728
23846
|
const dirents = await readdir(instancesDir, { withFileTypes: true }).catch(() => null);
|
|
23729
23847
|
if (!dirents) return [];
|
|
23730
23848
|
const versions = /* @__PURE__ */ new Set();
|
|
23731
23849
|
for (const dirent of dirents) {
|
|
23732
23850
|
if (!dirent.isDirectory()) continue;
|
|
23733
23851
|
try {
|
|
23734
|
-
const descriptorPath =
|
|
23852
|
+
const descriptorPath = path10.join(instancesDir, dirent.name, "runtime", "server.json");
|
|
23735
23853
|
const parsed = JSON.parse(await readFile(descriptorPath, "utf8"));
|
|
23736
23854
|
if (typeof parsed.version !== "string") continue;
|
|
23737
23855
|
if (typeof parsed.pid === "number" && Number.isInteger(parsed.pid) && parsed.pid > 0 && isPidRunning(parsed.pid)) {
|
|
@@ -23891,8 +24009,8 @@ var init_install = __esm({
|
|
|
23891
24009
|
});
|
|
23892
24010
|
|
|
23893
24011
|
// src/runtime/server-entry.ts
|
|
23894
|
-
import
|
|
23895
|
-
import
|
|
24012
|
+
import fs8 from "node:fs";
|
|
24013
|
+
import path11 from "node:path";
|
|
23896
24014
|
import { fileURLToPath as fileURLToPath5, pathToFileURL as pathToFileURL2 } from "node:url";
|
|
23897
24015
|
function formatError(err) {
|
|
23898
24016
|
if (err instanceof Error) {
|
|
@@ -23914,12 +24032,12 @@ function maybeEnableUiDevMiddleware(entrypoint) {
|
|
|
23914
24032
|
}
|
|
23915
24033
|
}
|
|
23916
24034
|
function resolveDevServerEntry() {
|
|
23917
|
-
const projectRoot =
|
|
23918
|
-
return
|
|
24035
|
+
const projectRoot = path11.resolve(path11.dirname(fileURLToPath5(import.meta.url)), "../../..");
|
|
24036
|
+
return path11.resolve(projectRoot, "server/src/index.ts");
|
|
23919
24037
|
}
|
|
23920
24038
|
async function loadServerRuntimeModule(options) {
|
|
23921
24039
|
const devEntry = resolveDevServerEntry();
|
|
23922
|
-
if (
|
|
24040
|
+
if (fs8.existsSync(devEntry)) {
|
|
23923
24041
|
maybeEnableUiDevMiddleware(devEntry);
|
|
23924
24042
|
return await import(pathToFileURL2(devEntry).href);
|
|
23925
24043
|
}
|
|
@@ -23930,7 +24048,7 @@ async function loadServerRuntimeModule(options) {
|
|
|
23930
24048
|
};
|
|
23931
24049
|
const runtime = await ensureRuntimeInstalled(installOptions);
|
|
23932
24050
|
if (!process.env[RUDDER_POSTGRES_BIN_DIR_ENV2]?.trim()) {
|
|
23933
|
-
if (runtime.postgresPayloadBinDir &&
|
|
24051
|
+
if (runtime.postgresPayloadBinDir && fs8.existsSync(runtime.postgresPayloadBinDir)) {
|
|
23934
24052
|
process.env[RUDDER_POSTGRES_BIN_DIR_ENV2] = runtime.postgresPayloadBinDir;
|
|
23935
24053
|
}
|
|
23936
24054
|
}
|
|
@@ -24054,24 +24172,24 @@ var init_auth_bootstrap_ceo = __esm({
|
|
|
24054
24172
|
});
|
|
24055
24173
|
|
|
24056
24174
|
// src/utils/path-resolver.ts
|
|
24057
|
-
import
|
|
24058
|
-
import
|
|
24175
|
+
import fs11 from "node:fs";
|
|
24176
|
+
import path19 from "node:path";
|
|
24059
24177
|
function unique(items) {
|
|
24060
24178
|
return Array.from(new Set(items));
|
|
24061
24179
|
}
|
|
24062
24180
|
function resolveRuntimeLikePath(value, configPath) {
|
|
24063
24181
|
const expanded = expandHomePrefix(value);
|
|
24064
|
-
if (
|
|
24182
|
+
if (path19.isAbsolute(expanded)) return path19.resolve(expanded);
|
|
24065
24183
|
const cwd = process.cwd();
|
|
24066
|
-
const configDir = configPath ?
|
|
24067
|
-
const workspaceRoot = configDir ?
|
|
24184
|
+
const configDir = configPath ? path19.dirname(configPath) : null;
|
|
24185
|
+
const workspaceRoot = configDir ? path19.resolve(configDir, "..") : cwd;
|
|
24068
24186
|
const candidates = unique([
|
|
24069
|
-
...configDir ? [
|
|
24070
|
-
|
|
24071
|
-
|
|
24072
|
-
|
|
24187
|
+
...configDir ? [path19.resolve(configDir, expanded)] : [],
|
|
24188
|
+
path19.resolve(workspaceRoot, "server", expanded),
|
|
24189
|
+
path19.resolve(workspaceRoot, expanded),
|
|
24190
|
+
path19.resolve(cwd, expanded)
|
|
24073
24191
|
]);
|
|
24074
|
-
return candidates.find((candidate) =>
|
|
24192
|
+
return candidates.find((candidate) => fs11.existsSync(candidate)) ?? candidates[0];
|
|
24075
24193
|
}
|
|
24076
24194
|
var init_path_resolver = __esm({
|
|
24077
24195
|
"src/utils/path-resolver.ts"() {
|
|
@@ -24082,8 +24200,8 @@ var init_path_resolver = __esm({
|
|
|
24082
24200
|
|
|
24083
24201
|
// src/config/secrets-key.ts
|
|
24084
24202
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
24085
|
-
import
|
|
24086
|
-
import
|
|
24203
|
+
import fs12 from "node:fs";
|
|
24204
|
+
import path20 from "node:path";
|
|
24087
24205
|
function ensureLocalSecretsKeyFile(config, configPath) {
|
|
24088
24206
|
if (config.secrets.provider !== "local_encrypted") {
|
|
24089
24207
|
return { status: "skipped_provider", path: null };
|
|
@@ -24095,16 +24213,16 @@ function ensureLocalSecretsKeyFile(config, configPath) {
|
|
|
24095
24213
|
const keyFileOverride = process.env.RUDDER_SECRETS_MASTER_KEY_FILE;
|
|
24096
24214
|
const configuredPath = keyFileOverride && keyFileOverride.trim().length > 0 ? keyFileOverride.trim() : config.secrets.localEncrypted.keyFilePath;
|
|
24097
24215
|
const keyFilePath = resolveRuntimeLikePath(configuredPath, configPath);
|
|
24098
|
-
if (
|
|
24216
|
+
if (fs12.existsSync(keyFilePath)) {
|
|
24099
24217
|
return { status: "existing", path: keyFilePath };
|
|
24100
24218
|
}
|
|
24101
|
-
|
|
24102
|
-
|
|
24219
|
+
fs12.mkdirSync(path20.dirname(keyFilePath), { recursive: true });
|
|
24220
|
+
fs12.writeFileSync(keyFilePath, randomBytes2(32).toString("base64"), {
|
|
24103
24221
|
encoding: "utf8",
|
|
24104
24222
|
mode: 384
|
|
24105
24223
|
});
|
|
24106
24224
|
try {
|
|
24107
|
-
|
|
24225
|
+
fs12.chmodSync(keyFilePath, 384);
|
|
24108
24226
|
} catch {
|
|
24109
24227
|
}
|
|
24110
24228
|
return { status: "created", path: keyFilePath };
|
|
@@ -24871,7 +24989,7 @@ var init_path_resolver2 = __esm({
|
|
|
24871
24989
|
});
|
|
24872
24990
|
|
|
24873
24991
|
// src/checks/database-check.ts
|
|
24874
|
-
import
|
|
24992
|
+
import fs13 from "node:fs";
|
|
24875
24993
|
async function databaseCheck(config, configPath) {
|
|
24876
24994
|
if (config.database.mode === "postgres") {
|
|
24877
24995
|
if (!config.database.connectionString) {
|
|
@@ -24903,8 +25021,8 @@ async function databaseCheck(config, configPath) {
|
|
|
24903
25021
|
if (config.database.mode === "embedded-postgres") {
|
|
24904
25022
|
const dataDir = resolveRuntimeLikePath(config.database.embeddedPostgresDataDir, configPath);
|
|
24905
25023
|
const reportedPath = dataDir;
|
|
24906
|
-
if (!
|
|
24907
|
-
|
|
25024
|
+
if (!fs13.existsSync(dataDir)) {
|
|
25025
|
+
fs13.mkdirSync(reportedPath, { recursive: true });
|
|
24908
25026
|
}
|
|
24909
25027
|
return {
|
|
24910
25028
|
name: "Database",
|
|
@@ -25100,15 +25218,15 @@ var init_llm_check = __esm({
|
|
|
25100
25218
|
});
|
|
25101
25219
|
|
|
25102
25220
|
// src/checks/log-check.ts
|
|
25103
|
-
import
|
|
25221
|
+
import fs14 from "node:fs";
|
|
25104
25222
|
function logCheck(config, configPath) {
|
|
25105
25223
|
const logDir = resolveRuntimeLikePath(config.logging.logDir, configPath);
|
|
25106
25224
|
const reportedDir = logDir;
|
|
25107
|
-
if (!
|
|
25108
|
-
|
|
25225
|
+
if (!fs14.existsSync(logDir)) {
|
|
25226
|
+
fs14.mkdirSync(reportedDir, { recursive: true });
|
|
25109
25227
|
}
|
|
25110
25228
|
try {
|
|
25111
|
-
|
|
25229
|
+
fs14.accessSync(reportedDir, fs14.constants.W_OK);
|
|
25112
25230
|
return {
|
|
25113
25231
|
name: "Log directory",
|
|
25114
25232
|
status: "pass",
|
|
@@ -25183,8 +25301,8 @@ var init_port_check = __esm({
|
|
|
25183
25301
|
|
|
25184
25302
|
// src/checks/secrets-check.ts
|
|
25185
25303
|
import { randomBytes as randomBytes3 } from "node:crypto";
|
|
25186
|
-
import
|
|
25187
|
-
import
|
|
25304
|
+
import fs15 from "node:fs";
|
|
25305
|
+
import path21 from "node:path";
|
|
25188
25306
|
function decodeMasterKey(raw) {
|
|
25189
25307
|
const trimmed = raw.trim();
|
|
25190
25308
|
if (!trimmed) return null;
|
|
@@ -25246,7 +25364,7 @@ function secretsCheck(config, configPath) {
|
|
|
25246
25364
|
const keyFileOverride = process.env.RUDDER_SECRETS_MASTER_KEY_FILE;
|
|
25247
25365
|
const configuredPath = keyFileOverride && keyFileOverride.trim().length > 0 ? keyFileOverride.trim() : config.secrets.localEncrypted.keyFilePath;
|
|
25248
25366
|
const keyFilePath = resolveRuntimeLikePath(configuredPath, configPath);
|
|
25249
|
-
if (!
|
|
25367
|
+
if (!fs15.existsSync(keyFilePath)) {
|
|
25250
25368
|
return withStrictModeNote(
|
|
25251
25369
|
{
|
|
25252
25370
|
name: "Secrets adapter",
|
|
@@ -25254,13 +25372,13 @@ function secretsCheck(config, configPath) {
|
|
|
25254
25372
|
message: `Secrets key file does not exist yet: ${keyFilePath}`,
|
|
25255
25373
|
canRepair: true,
|
|
25256
25374
|
repair: () => {
|
|
25257
|
-
|
|
25258
|
-
|
|
25375
|
+
fs15.mkdirSync(path21.dirname(keyFilePath), { recursive: true });
|
|
25376
|
+
fs15.writeFileSync(keyFilePath, randomBytes3(32).toString("base64"), {
|
|
25259
25377
|
encoding: "utf8",
|
|
25260
25378
|
mode: 384
|
|
25261
25379
|
});
|
|
25262
25380
|
try {
|
|
25263
|
-
|
|
25381
|
+
fs15.chmodSync(keyFilePath, 384);
|
|
25264
25382
|
} catch {
|
|
25265
25383
|
}
|
|
25266
25384
|
},
|
|
@@ -25271,7 +25389,7 @@ function secretsCheck(config, configPath) {
|
|
|
25271
25389
|
}
|
|
25272
25390
|
let raw;
|
|
25273
25391
|
try {
|
|
25274
|
-
raw =
|
|
25392
|
+
raw = fs15.readFileSync(keyFilePath, "utf8");
|
|
25275
25393
|
} catch (err) {
|
|
25276
25394
|
return {
|
|
25277
25395
|
name: "Secrets adapter",
|
|
@@ -25307,15 +25425,15 @@ var init_secrets_check = __esm({
|
|
|
25307
25425
|
});
|
|
25308
25426
|
|
|
25309
25427
|
// src/checks/storage-check.ts
|
|
25310
|
-
import
|
|
25428
|
+
import fs16 from "node:fs";
|
|
25311
25429
|
function storageCheck(config, configPath) {
|
|
25312
25430
|
if (config.storage.provider === "local_disk") {
|
|
25313
25431
|
const baseDir = resolveRuntimeLikePath(config.storage.localDisk.baseDir, configPath);
|
|
25314
|
-
if (!
|
|
25315
|
-
|
|
25432
|
+
if (!fs16.existsSync(baseDir)) {
|
|
25433
|
+
fs16.mkdirSync(baseDir, { recursive: true });
|
|
25316
25434
|
}
|
|
25317
25435
|
try {
|
|
25318
|
-
|
|
25436
|
+
fs16.accessSync(baseDir, fs16.constants.W_OK);
|
|
25319
25437
|
return {
|
|
25320
25438
|
name: "Storage",
|
|
25321
25439
|
status: "pass",
|
|
@@ -25721,7 +25839,7 @@ __export(run_exports, {
|
|
|
25721
25839
|
runCommand: () => runCommand
|
|
25722
25840
|
});
|
|
25723
25841
|
import * as p13 from "@clack/prompts";
|
|
25724
|
-
import
|
|
25842
|
+
import fs17 from "node:fs";
|
|
25725
25843
|
import pc12 from "picocolors";
|
|
25726
25844
|
async function runCommand(opts) {
|
|
25727
25845
|
let localEnvProfile = resolveActiveLocalEnvProfile();
|
|
@@ -25731,9 +25849,9 @@ async function runCommand(opts) {
|
|
|
25731
25849
|
const instanceId = resolveRudderInstanceId(opts.instance);
|
|
25732
25850
|
process.env.RUDDER_INSTANCE_ID = instanceId;
|
|
25733
25851
|
const homeDir = resolveRudderHomeDir();
|
|
25734
|
-
|
|
25852
|
+
fs17.mkdirSync(homeDir, { recursive: true });
|
|
25735
25853
|
const paths = describeLocalInstancePaths(instanceId);
|
|
25736
|
-
|
|
25854
|
+
fs17.mkdirSync(paths.instanceRoot, { recursive: true });
|
|
25737
25855
|
const configPath = resolveConfigPath(opts.config);
|
|
25738
25856
|
process.env.RUDDER_CONFIG = configPath;
|
|
25739
25857
|
loadRudderEnvFile(configPath);
|
|
@@ -25830,7 +25948,7 @@ var init_run = __esm({
|
|
|
25830
25948
|
|
|
25831
25949
|
// src/commands/onboard.ts
|
|
25832
25950
|
import * as p14 from "@clack/prompts";
|
|
25833
|
-
import
|
|
25951
|
+
import path22 from "node:path";
|
|
25834
25952
|
import pc13 from "picocolors";
|
|
25835
25953
|
function parseBooleanFromEnv(rawValue) {
|
|
25836
25954
|
if (rawValue === void 0) return null;
|
|
@@ -25863,7 +25981,7 @@ function parseEnumFromEnv(rawValue, allowedValues) {
|
|
|
25863
25981
|
}
|
|
25864
25982
|
function resolvePathFromEnv(rawValue) {
|
|
25865
25983
|
if (!rawValue || rawValue.trim().length === 0) return null;
|
|
25866
|
-
return
|
|
25984
|
+
return path22.resolve(expandHomePrefix(rawValue.trim()));
|
|
25867
25985
|
}
|
|
25868
25986
|
function quickstartDefaultsFromEnv() {
|
|
25869
25987
|
const instanceId = resolveRudderInstanceId();
|
|
@@ -26324,9 +26442,9 @@ function fingerprintRudderMcpToolManifest(tools) {
|
|
|
26324
26442
|
init_dist2();
|
|
26325
26443
|
import { spawn as spawn2, spawnSync } from "node:child_process";
|
|
26326
26444
|
import { existsSync as existsSync2 } from "node:fs";
|
|
26327
|
-
import
|
|
26328
|
-
import
|
|
26329
|
-
import
|
|
26445
|
+
import fs5 from "node:fs/promises";
|
|
26446
|
+
import os3 from "node:os";
|
|
26447
|
+
import path7 from "node:path";
|
|
26330
26448
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
26331
26449
|
|
|
26332
26450
|
// src/agent-v1-registry.ts
|
|
@@ -27737,6 +27855,18 @@ var AGENT_CLI_CAPABILITIES = [
|
|
|
27737
27855
|
"requiresAgentId": false,
|
|
27738
27856
|
"requiresOrgId": false,
|
|
27739
27857
|
"requiresRunId": false
|
|
27858
|
+
},
|
|
27859
|
+
{
|
|
27860
|
+
"attachesRunIdWhenAvailable": true,
|
|
27861
|
+
"category": "runs",
|
|
27862
|
+
"command": "rudder runs create --task <text> --idempotency-key <key> [--target-agent-id <id>]",
|
|
27863
|
+
"contract": "agent-v1",
|
|
27864
|
+
"description": "Create an independently governed Delegation Run for the current or another same-organization Agent.",
|
|
27865
|
+
"id": "runs.create",
|
|
27866
|
+
"mutating": true,
|
|
27867
|
+
"requiresAgentId": true,
|
|
27868
|
+
"requiresOrgId": false,
|
|
27869
|
+
"requiresRunId": true
|
|
27740
27870
|
}
|
|
27741
27871
|
];
|
|
27742
27872
|
|
|
@@ -27839,6 +27969,8 @@ function formatAgentCliCapabilitiesHumanReadable(capabilities = getAgentCliCapab
|
|
|
27839
27969
|
|
|
27840
27970
|
// src/client/http.ts
|
|
27841
27971
|
import { URL as URL2 } from "node:url";
|
|
27972
|
+
|
|
27973
|
+
// src/client/api-request-error.ts
|
|
27842
27974
|
var ApiRequestError = class extends Error {
|
|
27843
27975
|
status;
|
|
27844
27976
|
code;
|
|
@@ -27852,6 +27984,294 @@ var ApiRequestError = class extends Error {
|
|
|
27852
27984
|
this.body = body;
|
|
27853
27985
|
}
|
|
27854
27986
|
};
|
|
27987
|
+
|
|
27988
|
+
// src/client/issue-transport-budget.ts
|
|
27989
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
27990
|
+
import fs from "node:fs/promises";
|
|
27991
|
+
import os from "node:os";
|
|
27992
|
+
import path from "node:path";
|
|
27993
|
+
var DEFAULT_BACKOFF_MS = 6e4;
|
|
27994
|
+
var LOCK_RETRY_MS = 5;
|
|
27995
|
+
var LOCK_TIMEOUT_MS = 250;
|
|
27996
|
+
var IssueTransportBudget = class {
|
|
27997
|
+
runId;
|
|
27998
|
+
surface;
|
|
27999
|
+
stateDir;
|
|
28000
|
+
backoffMs;
|
|
28001
|
+
now;
|
|
28002
|
+
constructor(options) {
|
|
28003
|
+
this.runId = options.runId?.trim() || void 0;
|
|
28004
|
+
this.surface = options.surface ?? transportSurfaceFromEnv();
|
|
28005
|
+
this.stateDir = options.stateDir ?? process.env.RUDDER_RUNTIME_TMPDIR?.trim() ?? path.join(os.tmpdir(), "rudder-issue-transport");
|
|
28006
|
+
this.backoffMs = options.backoffMs ?? DEFAULT_BACKOFF_MS;
|
|
28007
|
+
this.now = options.now ?? Date.now;
|
|
28008
|
+
}
|
|
28009
|
+
async reserve(method, requestPath) {
|
|
28010
|
+
if (!this.runId) return null;
|
|
28011
|
+
const scope = issueTransportScope(method, requestPath);
|
|
28012
|
+
if (!scope) return null;
|
|
28013
|
+
const filePath = this.stateFilePath(scope);
|
|
28014
|
+
try {
|
|
28015
|
+
return await this.withLock(filePath, async () => {
|
|
28016
|
+
const now = this.now();
|
|
28017
|
+
let state = await readState(filePath);
|
|
28018
|
+
if (state && state.expiresAt <= now) {
|
|
28019
|
+
await fs.rm(filePath, { force: true });
|
|
28020
|
+
state = null;
|
|
28021
|
+
}
|
|
28022
|
+
if (!state) {
|
|
28023
|
+
return { filePath, scope, surface: this.surface, attempt: "initial" };
|
|
28024
|
+
}
|
|
28025
|
+
if (state.phase === "fallback_available" && state.initialSurface !== this.surface) {
|
|
28026
|
+
await writeState(filePath, {
|
|
28027
|
+
...state,
|
|
28028
|
+
phase: "fallback_in_flight",
|
|
28029
|
+
fallbackSurface: this.surface
|
|
28030
|
+
});
|
|
28031
|
+
return { filePath, scope, surface: this.surface, attempt: "fallback" };
|
|
28032
|
+
}
|
|
28033
|
+
throw issueTransportUnavailable(state, now, scope);
|
|
28034
|
+
});
|
|
28035
|
+
} catch (error) {
|
|
28036
|
+
if (error instanceof ApiRequestError) throw error;
|
|
28037
|
+
return null;
|
|
28038
|
+
}
|
|
28039
|
+
}
|
|
28040
|
+
async succeed(reservation) {
|
|
28041
|
+
if (!reservation) return;
|
|
28042
|
+
await this.tryWithLock(reservation.filePath, async () => {
|
|
28043
|
+
await fs.rm(reservation.filePath, { force: true });
|
|
28044
|
+
});
|
|
28045
|
+
}
|
|
28046
|
+
async fail(reservation, error) {
|
|
28047
|
+
if (!reservation) return;
|
|
28048
|
+
if (error.status < 500 || error.status > 599) {
|
|
28049
|
+
await this.succeed(reservation);
|
|
28050
|
+
return;
|
|
28051
|
+
}
|
|
28052
|
+
const failure = buildFingerprint(reservation.scope, error);
|
|
28053
|
+
const now = this.now();
|
|
28054
|
+
await this.tryWithLock(reservation.filePath, async () => {
|
|
28055
|
+
const current = await readState(reservation.filePath);
|
|
28056
|
+
const concurrentMatchingFailure = reservation.attempt === "initial" && current?.failure?.fingerprint === failure.fingerprint;
|
|
28057
|
+
const budgetExhausted = reservation.attempt === "fallback" || concurrentMatchingFailure;
|
|
28058
|
+
const state = {
|
|
28059
|
+
...reservation.scope,
|
|
28060
|
+
phase: budgetExhausted ? "blocked" : "fallback_available",
|
|
28061
|
+
initialSurface: current?.initialSurface ?? reservation.surface,
|
|
28062
|
+
fallbackSurface: reservation.attempt === "fallback" ? reservation.surface : void 0,
|
|
28063
|
+
fallbackMatchedFingerprint: budgetExhausted ? current?.failure?.fingerprint === failure.fingerprint : void 0,
|
|
28064
|
+
failure,
|
|
28065
|
+
observedAt: now,
|
|
28066
|
+
expiresAt: now + this.backoffMs
|
|
28067
|
+
};
|
|
28068
|
+
await writeState(reservation.filePath, state);
|
|
28069
|
+
attachTransportDiagnostic(error, state, now, reservation.scope);
|
|
28070
|
+
appendFallbackGuidance(error, state, reservation.scope);
|
|
28071
|
+
if (budgetExhausted) {
|
|
28072
|
+
error.code = "issue_transport_unavailable";
|
|
28073
|
+
error.message = "Issue transport unavailable";
|
|
28074
|
+
}
|
|
28075
|
+
});
|
|
28076
|
+
}
|
|
28077
|
+
stateFilePath(scope) {
|
|
28078
|
+
const key = [this.runId, scope.operation, scope.issueId].join("\n");
|
|
28079
|
+
const digest = createHash2("sha256").update(key).digest("hex");
|
|
28080
|
+
return path.join(this.stateDir, "issue-transport-budget", `${digest}.json`);
|
|
28081
|
+
}
|
|
28082
|
+
async tryWithLock(filePath, action) {
|
|
28083
|
+
try {
|
|
28084
|
+
return await this.withLock(filePath, action);
|
|
28085
|
+
} catch {
|
|
28086
|
+
return void 0;
|
|
28087
|
+
}
|
|
28088
|
+
}
|
|
28089
|
+
async withLock(filePath, action) {
|
|
28090
|
+
await fs.mkdir(path.dirname(filePath), { recursive: true, mode: 448 });
|
|
28091
|
+
const lockPath = `${filePath}.lock`;
|
|
28092
|
+
const deadline = Date.now() + LOCK_TIMEOUT_MS;
|
|
28093
|
+
let lock = null;
|
|
28094
|
+
while (!lock) {
|
|
28095
|
+
try {
|
|
28096
|
+
lock = await fs.open(lockPath, "wx", 384);
|
|
28097
|
+
} catch (error) {
|
|
28098
|
+
if (!isAlreadyExists(error) || Date.now() >= deadline) throw error;
|
|
28099
|
+
await new Promise((resolve) => setTimeout(resolve, LOCK_RETRY_MS));
|
|
28100
|
+
}
|
|
28101
|
+
}
|
|
28102
|
+
try {
|
|
28103
|
+
return await action();
|
|
28104
|
+
} finally {
|
|
28105
|
+
await lock.close();
|
|
28106
|
+
await fs.rm(lockPath, { force: true });
|
|
28107
|
+
}
|
|
28108
|
+
}
|
|
28109
|
+
};
|
|
28110
|
+
function issueTransportScope(method, requestPath) {
|
|
28111
|
+
const normalizedMethod = String(method ?? "GET").toUpperCase();
|
|
28112
|
+
const [pathname, queryString] = requestPath.split("?", 2);
|
|
28113
|
+
const match = /^\/api\/issues\/([^/]+)(?:\/(heartbeat-context|comments)(?:\/([^/]+))?)?$/.exec(pathname);
|
|
28114
|
+
if (!match) return null;
|
|
28115
|
+
const issueId = decodeURIComponent(match[1] ?? "");
|
|
28116
|
+
const resource = match[2];
|
|
28117
|
+
const commentId = match[3];
|
|
28118
|
+
let operation = null;
|
|
28119
|
+
if (normalizedMethod === "GET" && !resource) operation = "issue.get";
|
|
28120
|
+
if (normalizedMethod === "GET" && resource === "heartbeat-context") operation = "issue.context";
|
|
28121
|
+
if (normalizedMethod === "GET" && resource === "comments" && !commentId) operation = "issue.comments.list";
|
|
28122
|
+
if (normalizedMethod === "GET" && resource === "comments" && commentId) operation = "issue.comments.get";
|
|
28123
|
+
if (normalizedMethod === "POST" && resource === "comments" && !commentId) operation = "issue.comment";
|
|
28124
|
+
if (!operation) return null;
|
|
28125
|
+
const query = new URLSearchParams(queryString ?? "");
|
|
28126
|
+
return {
|
|
28127
|
+
operation,
|
|
28128
|
+
issueId,
|
|
28129
|
+
fallbackCommand: buildCliFallbackCommand(operation, issueId, commentId, query)
|
|
28130
|
+
};
|
|
28131
|
+
}
|
|
28132
|
+
function buildFingerprint(scope, error) {
|
|
28133
|
+
const normalizedMessage = error.message.trim().replace(/\s+/g, " ").toLowerCase().slice(0, 256);
|
|
28134
|
+
const code = error.code?.trim() || "api_request_error";
|
|
28135
|
+
const value = [scope.operation, scope.issueId, error.status, code, normalizedMessage].join("\n");
|
|
28136
|
+
return {
|
|
28137
|
+
fingerprint: createHash2("sha256").update(value).digest("hex"),
|
|
28138
|
+
status: error.status,
|
|
28139
|
+
code,
|
|
28140
|
+
normalizedMessage
|
|
28141
|
+
};
|
|
28142
|
+
}
|
|
28143
|
+
function issueTransportUnavailable(state, now, requestScope = state) {
|
|
28144
|
+
const details = { issueTransport: transportDiagnostic(state, now, requestScope) };
|
|
28145
|
+
return new ApiRequestError(
|
|
28146
|
+
503,
|
|
28147
|
+
issueTransportErrorMessage(state, requestScope),
|
|
28148
|
+
details,
|
|
28149
|
+
{ error: "Issue transport unavailable", code: "issue_transport_unavailable", details },
|
|
28150
|
+
"issue_transport_unavailable"
|
|
28151
|
+
);
|
|
28152
|
+
}
|
|
28153
|
+
function attachTransportDiagnostic(error, state, now, requestScope = state) {
|
|
28154
|
+
const upstreamDetails = error.details;
|
|
28155
|
+
error.details = {
|
|
28156
|
+
...isRecord2(upstreamDetails) ? upstreamDetails : upstreamDetails === void 0 ? {} : { upstreamDetails },
|
|
28157
|
+
issueTransport: transportDiagnostic(state, now, requestScope)
|
|
28158
|
+
};
|
|
28159
|
+
}
|
|
28160
|
+
function appendFallbackGuidance(error, state, requestScope) {
|
|
28161
|
+
const fallback = issueTransportFallbackAction(state, requestScope);
|
|
28162
|
+
if (!fallback) return;
|
|
28163
|
+
error.message = `${error.message}; use the equivalent ${fallbackSurfaceLabel(fallback.surface)} fallback once: ${fallbackTarget(fallback)}`;
|
|
28164
|
+
}
|
|
28165
|
+
function issueTransportErrorMessage(state, requestScope = state) {
|
|
28166
|
+
const base = state.phase === "fallback_in_flight" ? "Issue transport probe already in flight" : "Issue transport unavailable";
|
|
28167
|
+
const fallback = issueTransportFallbackAction(state, requestScope);
|
|
28168
|
+
return fallback ? `${base}; use the equivalent ${fallbackSurfaceLabel(fallback.surface)} fallback once: ${fallbackTarget(fallback)}` : base;
|
|
28169
|
+
}
|
|
28170
|
+
function transportDiagnostic(state, now, requestScope = state) {
|
|
28171
|
+
return {
|
|
28172
|
+
state: state.phase,
|
|
28173
|
+
fingerprint: state.failure?.fingerprint ?? null,
|
|
28174
|
+
operation: state.operation,
|
|
28175
|
+
issueId: state.issueId,
|
|
28176
|
+
upstreamStatus: state.failure?.status ?? null,
|
|
28177
|
+
upstreamCode: state.failure?.code ?? null,
|
|
28178
|
+
normalizedServerMessage: state.failure?.normalizedMessage ?? null,
|
|
28179
|
+
initialSurface: state.initialSurface,
|
|
28180
|
+
fallbackSurface: state.fallbackSurface ?? null,
|
|
28181
|
+
fallbackMatchedFingerprint: state.fallbackMatchedFingerprint ?? null,
|
|
28182
|
+
fallbackBudgetRemaining: state.phase === "fallback_available" ? 1 : 0,
|
|
28183
|
+
fallbackAction: issueTransportFallbackAction(state, requestScope),
|
|
28184
|
+
retryAfterMs: Math.max(0, state.expiresAt - now),
|
|
28185
|
+
checkpoint: "Issue transport unavailable"
|
|
28186
|
+
};
|
|
28187
|
+
}
|
|
28188
|
+
function issueTransportFallbackAction(state, requestScope = state) {
|
|
28189
|
+
if (state.phase !== "fallback_available") return null;
|
|
28190
|
+
if (state.initialSurface === "mcp") {
|
|
28191
|
+
return {
|
|
28192
|
+
surface: "cli",
|
|
28193
|
+
command: requestScope.fallbackCommand ?? state.fallbackCommand ?? buildCliFallbackCommand(state.operation, state.issueId, void 0, new URLSearchParams())
|
|
28194
|
+
};
|
|
28195
|
+
}
|
|
28196
|
+
return {
|
|
28197
|
+
surface: "mcp",
|
|
28198
|
+
tool: mcpToolNameForOperation(state.operation)
|
|
28199
|
+
};
|
|
28200
|
+
}
|
|
28201
|
+
function fallbackSurfaceLabel(surface) {
|
|
28202
|
+
return surface === "cli" ? "Rudder CLI" : "Rudder MCP";
|
|
28203
|
+
}
|
|
28204
|
+
function fallbackTarget(fallback) {
|
|
28205
|
+
return fallback.command ?? fallback.tool ?? "the alternate Rudder transport";
|
|
28206
|
+
}
|
|
28207
|
+
function mcpToolNameForOperation(operation) {
|
|
28208
|
+
return `rudder_${operation.replace(/\./g, "_")}`;
|
|
28209
|
+
}
|
|
28210
|
+
function buildCliFallbackCommand(operation, issueId, commentId, query) {
|
|
28211
|
+
const issue = shellQuote(issueId);
|
|
28212
|
+
switch (operation) {
|
|
28213
|
+
case "issue.get":
|
|
28214
|
+
return `rudder issue get ${issue} --json`;
|
|
28215
|
+
case "issue.context": {
|
|
28216
|
+
const command = [`rudder issue context ${issue}`];
|
|
28217
|
+
appendCliOption(command, "--wake-comment-id", query.get("wakeCommentId"));
|
|
28218
|
+
return `${command.join(" ")} --json`;
|
|
28219
|
+
}
|
|
28220
|
+
case "issue.comments.list": {
|
|
28221
|
+
const command = [`rudder issue comments list ${issue}`];
|
|
28222
|
+
appendCliOption(command, "--after", query.get("after"));
|
|
28223
|
+
appendCliOption(command, "--order", query.get("order"));
|
|
28224
|
+
return `${command.join(" ")} --json`;
|
|
28225
|
+
}
|
|
28226
|
+
case "issue.comments.get":
|
|
28227
|
+
return `rudder issue comments get ${issue} ${shellQuote(commentId ?? "<comment-id>")} --json`;
|
|
28228
|
+
case "issue.comment":
|
|
28229
|
+
return `rudder issue comment ${issue} --body-file ./issue-comment.md --json`;
|
|
28230
|
+
default:
|
|
28231
|
+
return `rudder issue ${shellQuote(operation)} ${issue} --json`;
|
|
28232
|
+
}
|
|
28233
|
+
}
|
|
28234
|
+
function appendCliOption(command, option, value) {
|
|
28235
|
+
if (value === null || value.trim().length === 0) return;
|
|
28236
|
+
command.push(option, shellQuote(value));
|
|
28237
|
+
}
|
|
28238
|
+
function shellQuote(value) {
|
|
28239
|
+
if (/^[A-Za-z0-9_./:-]+$/.test(value)) return value;
|
|
28240
|
+
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
28241
|
+
}
|
|
28242
|
+
async function readState(filePath) {
|
|
28243
|
+
try {
|
|
28244
|
+
const parsed = JSON.parse(await fs.readFile(filePath, "utf8"));
|
|
28245
|
+
return isIssueTransportState(parsed) ? parsed : null;
|
|
28246
|
+
} catch (error) {
|
|
28247
|
+
if (isNotFound(error) || error instanceof SyntaxError) return null;
|
|
28248
|
+
throw error;
|
|
28249
|
+
}
|
|
28250
|
+
}
|
|
28251
|
+
async function writeState(filePath, state) {
|
|
28252
|
+
const tempPath = `${filePath}.${process.pid}.${Math.random().toString(16).slice(2)}.tmp`;
|
|
28253
|
+
await fs.writeFile(tempPath, `${JSON.stringify(state)}
|
|
28254
|
+
`, { encoding: "utf8", mode: 384 });
|
|
28255
|
+
await fs.rename(tempPath, filePath);
|
|
28256
|
+
}
|
|
28257
|
+
function isIssueTransportState(value) {
|
|
28258
|
+
if (!isRecord2(value)) return false;
|
|
28259
|
+
return typeof value.operation === "string" && typeof value.issueId === "string" && ["fallback_available", "fallback_in_flight", "blocked"].includes(String(value.phase)) && (value.initialSurface === "cli" || value.initialSurface === "mcp") && typeof value.observedAt === "number" && typeof value.expiresAt === "number";
|
|
28260
|
+
}
|
|
28261
|
+
function transportSurfaceFromEnv() {
|
|
28262
|
+
return process.env.RUDDER_TOOL_TRANSPORT_SURFACE === "mcp" ? "mcp" : "cli";
|
|
28263
|
+
}
|
|
28264
|
+
function isRecord2(value) {
|
|
28265
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
28266
|
+
}
|
|
28267
|
+
function isAlreadyExists(error) {
|
|
28268
|
+
return isRecord2(error) && error.code === "EEXIST";
|
|
28269
|
+
}
|
|
28270
|
+
function isNotFound(error) {
|
|
28271
|
+
return isRecord2(error) && error.code === "ENOENT";
|
|
28272
|
+
}
|
|
28273
|
+
|
|
28274
|
+
// src/client/http.ts
|
|
27855
28275
|
var RudderApiClient = class {
|
|
27856
28276
|
apiBase;
|
|
27857
28277
|
apiKey;
|
|
@@ -27859,6 +28279,7 @@ var RudderApiClient = class {
|
|
|
27859
28279
|
runId;
|
|
27860
28280
|
signal;
|
|
27861
28281
|
recoverAuth;
|
|
28282
|
+
issueTransportBudget;
|
|
27862
28283
|
constructor(opts) {
|
|
27863
28284
|
this.apiBase = opts.apiBase.replace(/\/+$/, "");
|
|
27864
28285
|
this.apiKey = opts.apiKey?.trim() || void 0;
|
|
@@ -27866,42 +28287,50 @@ var RudderApiClient = class {
|
|
|
27866
28287
|
this.runId = opts.runId?.trim() || void 0;
|
|
27867
28288
|
this.signal = opts.signal;
|
|
27868
28289
|
this.recoverAuth = opts.recoverAuth;
|
|
28290
|
+
this.issueTransportBudget = new IssueTransportBudget({
|
|
28291
|
+
runId: this.runId,
|
|
28292
|
+
surface: opts.transportSurface,
|
|
28293
|
+
stateDir: opts.transportStateDir,
|
|
28294
|
+
backoffMs: opts.transportBackoffMs,
|
|
28295
|
+
now: opts.now
|
|
28296
|
+
});
|
|
27869
28297
|
}
|
|
27870
|
-
get(
|
|
27871
|
-
return this.request(
|
|
28298
|
+
get(path26, opts) {
|
|
28299
|
+
return this.request(path26, { method: "GET" }, opts);
|
|
27872
28300
|
}
|
|
27873
|
-
post(
|
|
27874
|
-
return this.request(
|
|
28301
|
+
post(path26, body, opts) {
|
|
28302
|
+
return this.request(path26, {
|
|
27875
28303
|
method: "POST",
|
|
27876
28304
|
body: body === void 0 ? void 0 : JSON.stringify(body)
|
|
27877
28305
|
}, opts);
|
|
27878
28306
|
}
|
|
27879
|
-
postForm(
|
|
27880
|
-
return this.request(
|
|
28307
|
+
postForm(path26, form, opts) {
|
|
28308
|
+
return this.request(path26, {
|
|
27881
28309
|
method: "POST",
|
|
27882
28310
|
body: form
|
|
27883
28311
|
}, opts);
|
|
27884
28312
|
}
|
|
27885
|
-
patch(
|
|
27886
|
-
return this.request(
|
|
28313
|
+
patch(path26, body, opts) {
|
|
28314
|
+
return this.request(path26, {
|
|
27887
28315
|
method: "PATCH",
|
|
27888
28316
|
body: body === void 0 ? void 0 : JSON.stringify(body)
|
|
27889
28317
|
}, opts);
|
|
27890
28318
|
}
|
|
27891
|
-
put(
|
|
27892
|
-
return this.request(
|
|
28319
|
+
put(path26, body, opts) {
|
|
28320
|
+
return this.request(path26, {
|
|
27893
28321
|
method: "PUT",
|
|
27894
28322
|
body: body === void 0 ? void 0 : JSON.stringify(body)
|
|
27895
28323
|
}, opts);
|
|
27896
28324
|
}
|
|
27897
|
-
delete(
|
|
27898
|
-
return this.request(
|
|
28325
|
+
delete(path26, opts) {
|
|
28326
|
+
return this.request(path26, { method: "DELETE" }, opts);
|
|
27899
28327
|
}
|
|
27900
28328
|
setApiKey(apiKey) {
|
|
27901
28329
|
this.apiKey = apiKey?.trim() || void 0;
|
|
27902
28330
|
}
|
|
27903
|
-
async request(
|
|
27904
|
-
const url = buildUrl(this.apiBase,
|
|
28331
|
+
async request(path26, init, opts, hasRetriedAuth = false) {
|
|
28332
|
+
const url = buildUrl(this.apiBase, path26);
|
|
28333
|
+
const reservation = await this.issueTransportBudget.reserve(init.method, path26);
|
|
27905
28334
|
const headers = {
|
|
27906
28335
|
accept: "application/json",
|
|
27907
28336
|
...toStringRecord(init.headers)
|
|
@@ -27920,29 +28349,39 @@ var RudderApiClient = class {
|
|
|
27920
28349
|
headers["x-rudder-run-id"] = this.runId;
|
|
27921
28350
|
}
|
|
27922
28351
|
}
|
|
27923
|
-
|
|
27924
|
-
|
|
27925
|
-
|
|
27926
|
-
|
|
27927
|
-
|
|
28352
|
+
let response;
|
|
28353
|
+
try {
|
|
28354
|
+
response = await fetch(url, {
|
|
28355
|
+
...init,
|
|
28356
|
+
headers,
|
|
28357
|
+
signal: init.signal ?? this.signal
|
|
28358
|
+
});
|
|
28359
|
+
} catch (error) {
|
|
28360
|
+
await this.issueTransportBudget.succeed(reservation);
|
|
28361
|
+
throw error;
|
|
28362
|
+
}
|
|
27928
28363
|
if (opts?.ignoreNotFound && response.status === 404) {
|
|
28364
|
+
await this.issueTransportBudget.succeed(reservation);
|
|
27929
28365
|
return null;
|
|
27930
28366
|
}
|
|
27931
28367
|
if (!response.ok) {
|
|
27932
28368
|
const apiError = await toApiError(response);
|
|
27933
28369
|
if (!hasRetriedAuth && this.recoverAuth) {
|
|
27934
28370
|
const recoveredToken = await this.recoverAuth({
|
|
27935
|
-
path:
|
|
28371
|
+
path: path26,
|
|
27936
28372
|
method: String(init.method ?? "GET").toUpperCase(),
|
|
27937
28373
|
error: apiError
|
|
27938
28374
|
});
|
|
27939
28375
|
if (recoveredToken) {
|
|
28376
|
+
await this.issueTransportBudget.succeed(reservation);
|
|
27940
28377
|
this.setApiKey(recoveredToken);
|
|
27941
|
-
return this.request(
|
|
28378
|
+
return this.request(path26, init, opts, true);
|
|
27942
28379
|
}
|
|
27943
28380
|
}
|
|
28381
|
+
await this.issueTransportBudget.fail(reservation, apiError);
|
|
27944
28382
|
throw apiError;
|
|
27945
28383
|
}
|
|
28384
|
+
await this.issueTransportBudget.succeed(reservation);
|
|
27946
28385
|
if (response.status === 204) {
|
|
27947
28386
|
return null;
|
|
27948
28387
|
}
|
|
@@ -27957,8 +28396,8 @@ function shouldAttachAgentContext(method) {
|
|
|
27957
28396
|
const normalized = String(method ?? "GET").toUpperCase();
|
|
27958
28397
|
return normalized !== "GET" && normalized !== "HEAD";
|
|
27959
28398
|
}
|
|
27960
|
-
function buildUrl(apiBase,
|
|
27961
|
-
const normalizedPath =
|
|
28399
|
+
function buildUrl(apiBase, path26) {
|
|
28400
|
+
const normalizedPath = path26.startsWith("/") ? path26 : `/${path26}`;
|
|
27962
28401
|
const [pathname, query] = normalizedPath.split("?");
|
|
27963
28402
|
const url = new URL2(apiBase);
|
|
27964
28403
|
url.pathname = `${url.pathname.replace(/\/+$/, "")}${pathname}`;
|
|
@@ -28009,8 +28448,8 @@ import pc2 from "picocolors";
|
|
|
28009
28448
|
// src/client/board-auth.ts
|
|
28010
28449
|
init_home();
|
|
28011
28450
|
import { spawn } from "node:child_process";
|
|
28012
|
-
import
|
|
28013
|
-
import
|
|
28451
|
+
import fs2 from "node:fs";
|
|
28452
|
+
import path3 from "node:path";
|
|
28014
28453
|
import pc from "picocolors";
|
|
28015
28454
|
|
|
28016
28455
|
// src/client/command-label.ts
|
|
@@ -28033,14 +28472,14 @@ function normalizeApiBase(apiBase) {
|
|
|
28033
28472
|
return apiBase.trim().replace(/\/+$/, "");
|
|
28034
28473
|
}
|
|
28035
28474
|
function resolveBoardAuthStorePath(overridePath) {
|
|
28036
|
-
if (overridePath?.trim()) return
|
|
28037
|
-
if (process.env.RUDDER_AUTH_STORE?.trim()) return
|
|
28475
|
+
if (overridePath?.trim()) return path3.resolve(overridePath.trim());
|
|
28476
|
+
if (process.env.RUDDER_AUTH_STORE?.trim()) return path3.resolve(process.env.RUDDER_AUTH_STORE.trim());
|
|
28038
28477
|
return resolveDefaultCliAuthPath();
|
|
28039
28478
|
}
|
|
28040
28479
|
function readBoardAuthStore(storePath) {
|
|
28041
28480
|
const filePath = resolveBoardAuthStorePath(storePath);
|
|
28042
|
-
if (!
|
|
28043
|
-
const raw = JSON.parse(
|
|
28481
|
+
if (!fs2.existsSync(filePath)) return defaultBoardAuthStore();
|
|
28482
|
+
const raw = JSON.parse(fs2.readFileSync(filePath, "utf8"));
|
|
28044
28483
|
const credentials = raw?.credentials && typeof raw.credentials === "object" ? raw.credentials : {};
|
|
28045
28484
|
const normalized = {};
|
|
28046
28485
|
for (const [key, value] of Object.entries(credentials)) {
|
|
@@ -28066,8 +28505,8 @@ function readBoardAuthStore(storePath) {
|
|
|
28066
28505
|
}
|
|
28067
28506
|
function writeBoardAuthStore(store, storePath) {
|
|
28068
28507
|
const filePath = resolveBoardAuthStorePath(storePath);
|
|
28069
|
-
|
|
28070
|
-
|
|
28508
|
+
fs2.mkdirSync(path3.dirname(filePath), { recursive: true });
|
|
28509
|
+
fs2.writeFileSync(filePath, `${JSON.stringify(store, null, 2)}
|
|
28071
28510
|
`, { mode: 384 });
|
|
28072
28511
|
}
|
|
28073
28512
|
function getStoredBoardCredential(apiBase, storePath) {
|
|
@@ -28213,27 +28652,27 @@ async function revokeStoredBoardCredential(params) {
|
|
|
28213
28652
|
|
|
28214
28653
|
// src/client/context.ts
|
|
28215
28654
|
init_home();
|
|
28216
|
-
import
|
|
28217
|
-
import
|
|
28655
|
+
import fs3 from "node:fs";
|
|
28656
|
+
import path4 from "node:path";
|
|
28218
28657
|
var DEFAULT_CONTEXT_BASENAME = "context.json";
|
|
28219
28658
|
var DEFAULT_PROFILE = "default";
|
|
28220
28659
|
function findContextFileFromAncestors(startDir) {
|
|
28221
|
-
const absoluteStartDir =
|
|
28660
|
+
const absoluteStartDir = path4.resolve(startDir);
|
|
28222
28661
|
let currentDir = absoluteStartDir;
|
|
28223
28662
|
while (true) {
|
|
28224
|
-
const candidate =
|
|
28225
|
-
if (
|
|
28663
|
+
const candidate = path4.resolve(currentDir, ".rudder", DEFAULT_CONTEXT_BASENAME);
|
|
28664
|
+
if (fs3.existsSync(candidate)) {
|
|
28226
28665
|
return candidate;
|
|
28227
28666
|
}
|
|
28228
|
-
const nextDir =
|
|
28667
|
+
const nextDir = path4.resolve(currentDir, "..");
|
|
28229
28668
|
if (nextDir === currentDir) break;
|
|
28230
28669
|
currentDir = nextDir;
|
|
28231
28670
|
}
|
|
28232
28671
|
return null;
|
|
28233
28672
|
}
|
|
28234
28673
|
function resolveContextPath(overridePath) {
|
|
28235
|
-
if (overridePath) return
|
|
28236
|
-
if (process.env.RUDDER_CONTEXT) return
|
|
28674
|
+
if (overridePath) return path4.resolve(overridePath);
|
|
28675
|
+
if (process.env.RUDDER_CONTEXT) return path4.resolve(process.env.RUDDER_CONTEXT);
|
|
28237
28676
|
return findContextFileFromAncestors(process.cwd()) ?? resolveDefaultContextPath();
|
|
28238
28677
|
}
|
|
28239
28678
|
function defaultClientContext() {
|
|
@@ -28247,7 +28686,7 @@ function defaultClientContext() {
|
|
|
28247
28686
|
}
|
|
28248
28687
|
function parseJson(filePath) {
|
|
28249
28688
|
try {
|
|
28250
|
-
return JSON.parse(
|
|
28689
|
+
return JSON.parse(fs3.readFileSync(filePath, "utf-8"));
|
|
28251
28690
|
} catch (err) {
|
|
28252
28691
|
throw new Error(`Failed to parse JSON at ${filePath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
28253
28692
|
}
|
|
@@ -28293,7 +28732,7 @@ function normalizeContext(raw) {
|
|
|
28293
28732
|
}
|
|
28294
28733
|
function readContext(contextPath) {
|
|
28295
28734
|
const filePath = resolveContextPath(contextPath);
|
|
28296
|
-
if (!
|
|
28735
|
+
if (!fs3.existsSync(filePath)) {
|
|
28297
28736
|
return defaultClientContext();
|
|
28298
28737
|
}
|
|
28299
28738
|
const raw = parseJson(filePath);
|
|
@@ -28301,10 +28740,10 @@ function readContext(contextPath) {
|
|
|
28301
28740
|
}
|
|
28302
28741
|
function writeContext(context, contextPath) {
|
|
28303
28742
|
const filePath = resolveContextPath(contextPath);
|
|
28304
|
-
const dir =
|
|
28305
|
-
|
|
28743
|
+
const dir = path4.dirname(filePath);
|
|
28744
|
+
fs3.mkdirSync(dir, { recursive: true });
|
|
28306
28745
|
const normalized = normalizeContext(context);
|
|
28307
|
-
|
|
28746
|
+
fs3.writeFileSync(filePath, `${JSON.stringify(normalized, null, 2)}
|
|
28308
28747
|
`, { mode: 384 });
|
|
28309
28748
|
}
|
|
28310
28749
|
function upsertProfile(profileName, patch, contextPath) {
|
|
@@ -28750,7 +29189,8 @@ function buildMcpServerEnv(env = process.env) {
|
|
|
28750
29189
|
RUDDER_BROWSER_ENABLED: env.RUDDER_BROWSER_ENABLED,
|
|
28751
29190
|
RUDDER_COMPUTER_ENABLED: env.RUDDER_COMPUTER_ENABLED,
|
|
28752
29191
|
RUDDER_PROJECT_LIBRARY_PATH: env.RUDDER_PROJECT_LIBRARY_PATH,
|
|
28753
|
-
RUDDER_MCP_RUDDER_BIN: env.RUDDER_MCP_RUDDER_BIN
|
|
29192
|
+
RUDDER_MCP_RUDDER_BIN: env.RUDDER_MCP_RUDDER_BIN,
|
|
29193
|
+
RUDDER_TOOL_TRANSPORT_SURFACE: env.RUDDER_TOOL_TRANSPORT_SURFACE
|
|
28754
29194
|
};
|
|
28755
29195
|
}
|
|
28756
29196
|
function buildAgentV1ToolCallPlan(toolName, rawArgs, env = buildMcpServerEnv()) {
|
|
@@ -28758,10 +29198,10 @@ function buildAgentV1ToolCallPlan(toolName, rawArgs, env = buildMcpServerEnv())
|
|
|
28758
29198
|
if (!capabilityId) {
|
|
28759
29199
|
throw new Error(`Unknown Rudder MCP tool: ${toolName}`);
|
|
28760
29200
|
}
|
|
28761
|
-
if (rawArgs !== void 0 && rawArgs !== null && !
|
|
29201
|
+
if (rawArgs !== void 0 && rawArgs !== null && !isRecord3(rawArgs)) {
|
|
28762
29202
|
throwInvalidMcpArgument(toolName, "arguments", "must be object");
|
|
28763
29203
|
}
|
|
28764
|
-
const input = normalizeLegacyToolArguments(capabilityId,
|
|
29204
|
+
const input = normalizeLegacyToolArguments(capabilityId, isRecord3(rawArgs) ? rawArgs : {});
|
|
28765
29205
|
const capability = getAgentCliCapabilityById(capabilityId);
|
|
28766
29206
|
rejectModelProvidedRuntimeIdentity(input);
|
|
28767
29207
|
rejectUnsupportedToolArguments(toolName, input);
|
|
@@ -28784,7 +29224,8 @@ function buildAgentV1ToolCallPlan(toolName, rawArgs, env = buildMcpServerEnv())
|
|
|
28784
29224
|
RUDDER_RUN_ID: env.RUDDER_RUN_ID,
|
|
28785
29225
|
RUDDER_BROWSER_ENABLED: env.RUDDER_BROWSER_ENABLED,
|
|
28786
29226
|
RUDDER_COMPUTER_ENABLED: env.RUDDER_COMPUTER_ENABLED,
|
|
28787
|
-
RUDDER_PROJECT_LIBRARY_PATH: env.RUDDER_PROJECT_LIBRARY_PATH
|
|
29227
|
+
RUDDER_PROJECT_LIBRARY_PATH: env.RUDDER_PROJECT_LIBRARY_PATH,
|
|
29228
|
+
RUDDER_TOOL_TRANSPORT_SURFACE: "mcp"
|
|
28788
29229
|
},
|
|
28789
29230
|
tempFiles
|
|
28790
29231
|
};
|
|
@@ -28870,7 +29311,7 @@ async function runAgentV1McpJsonRpcMessage(message, env = buildMcpServerEnv(), s
|
|
|
28870
29311
|
case "tools/list": {
|
|
28871
29312
|
const tools = surface === "computer" ? computerCapabilityEnabled(env) ? COMPUTER_USE_MCP_TOOLS : [] : surface === "browser" && !browserCapabilityEnabled(env) ? [] : buildAgentV1McpToolsManifest("agent-v1", { surface }).tools.map(toMcpToolListEntry);
|
|
28872
29313
|
if (isModernMcpRequest(message.params)) {
|
|
28873
|
-
const cursor =
|
|
29314
|
+
const cursor = isRecord3(message.params) ? message.params.cursor : void 0;
|
|
28874
29315
|
if (typeof cursor === "string" && parseMcpToolCursor(cursor) === null) {
|
|
28875
29316
|
return rpcError(id, -32602, "Invalid tools/list cursor");
|
|
28876
29317
|
}
|
|
@@ -29024,7 +29465,7 @@ async function callToolSafely(params, env, surface, signal) {
|
|
|
29024
29465
|
const details = errorDetails(err);
|
|
29025
29466
|
const payload = {
|
|
29026
29467
|
status: "error",
|
|
29027
|
-
code:
|
|
29468
|
+
code: isRecord3(details) && typeof details.code === "string" ? details.code : "rudder_mcp_tool_error",
|
|
29028
29469
|
message: errorMessage(err),
|
|
29029
29470
|
details: details ?? null
|
|
29030
29471
|
};
|
|
@@ -29039,7 +29480,7 @@ async function callToolSafely(params, env, surface, signal) {
|
|
|
29039
29480
|
}
|
|
29040
29481
|
}
|
|
29041
29482
|
async function callTool(params, env, surface, signal) {
|
|
29042
|
-
const record =
|
|
29483
|
+
const record = isRecord3(params) ? params : {};
|
|
29043
29484
|
const toolName = typeof record.name === "string" ? record.name : "";
|
|
29044
29485
|
if (surface === "computer") {
|
|
29045
29486
|
if (!computerCapabilityEnabled(env)) {
|
|
@@ -29054,7 +29495,7 @@ async function callTool(params, env, surface, signal) {
|
|
|
29054
29495
|
error.code = "rudder_mcp_tool_not_available";
|
|
29055
29496
|
throw error;
|
|
29056
29497
|
}
|
|
29057
|
-
const rawArgs2 =
|
|
29498
|
+
const rawArgs2 = isRecord3(record.arguments) ? record.arguments : {};
|
|
29058
29499
|
rejectModelProvidedRuntimeIdentity(rawArgs2);
|
|
29059
29500
|
const parsed = computerUseActionSchemas[action].safeParse(rawArgs2);
|
|
29060
29501
|
if (!parsed.success) {
|
|
@@ -29073,17 +29514,17 @@ async function callTool(params, env, surface, signal) {
|
|
|
29073
29514
|
throw err;
|
|
29074
29515
|
}
|
|
29075
29516
|
const rawArgs = record.arguments;
|
|
29076
|
-
const args =
|
|
29517
|
+
const args = isRecord3(rawArgs) ? normalizeLegacyToolArguments(toolNameToCapabilityId(toolName) ?? "", rawArgs) : rawArgs;
|
|
29077
29518
|
const plan = buildAgentV1ToolCallPlan(toolName, args, env);
|
|
29078
29519
|
const directResult = await callToolDirectlyIfSupported(toolName, args, env, signal);
|
|
29079
29520
|
if (directResult) return directResult;
|
|
29080
|
-
const tempDir = plan.tempFiles.length > 0 ? await
|
|
29521
|
+
const tempDir = plan.tempFiles.length > 0 ? await fs5.mkdtemp(path7.join(os3.tmpdir(), "rudder-mcp-")) : null;
|
|
29081
29522
|
const materializedArgs = [...plan.args];
|
|
29082
29523
|
try {
|
|
29083
29524
|
if (tempDir) {
|
|
29084
29525
|
for (const tempFile of plan.tempFiles) {
|
|
29085
|
-
const tempPath =
|
|
29086
|
-
await
|
|
29526
|
+
const tempPath = path7.join(tempDir, `${tempFile.flag.replace(/^-+/, "")}.md`);
|
|
29527
|
+
await fs5.writeFile(tempPath, tempFile.contents, "utf8");
|
|
29087
29528
|
const index = materializedArgs.indexOf(tempFile.flag);
|
|
29088
29529
|
if (index >= 0) materializedArgs[index + 1] = tempPath;
|
|
29089
29530
|
}
|
|
@@ -29111,13 +29552,13 @@ async function callTool(params, env, surface, signal) {
|
|
|
29111
29552
|
isError: true
|
|
29112
29553
|
};
|
|
29113
29554
|
} finally {
|
|
29114
|
-
if (tempDir) await
|
|
29555
|
+
if (tempDir) await fs5.rm(tempDir, { recursive: true, force: true });
|
|
29115
29556
|
}
|
|
29116
29557
|
}
|
|
29117
29558
|
async function callToolDirectlyIfSupported(toolName, rawArgs, env, signal) {
|
|
29118
29559
|
const capabilityId = toolNameToCapabilityId(toolName);
|
|
29119
29560
|
if (!capabilityId) return null;
|
|
29120
|
-
const input =
|
|
29561
|
+
const input = isRecord3(rawArgs) ? rawArgs : {};
|
|
29121
29562
|
if (hasLocalImageInputs(input.images)) return null;
|
|
29122
29563
|
const api = mcpApiClient(env, signal);
|
|
29123
29564
|
const success = (data) => mcpSuccess(
|
|
@@ -29242,6 +29683,18 @@ async function callToolDirectlyIfSupported(toolName, rawArgs, env, signal) {
|
|
|
29242
29683
|
`/api/issues/${encodeURIComponent(requiredAnyString(input, ["issue", "issueId"]))}/heartbeat-context${query ? `?${query}` : ""}`
|
|
29243
29684
|
));
|
|
29244
29685
|
}
|
|
29686
|
+
case "issue.comments.list": {
|
|
29687
|
+
const params = new URLSearchParams();
|
|
29688
|
+
appendOptionalQuery(params, "after", input.after);
|
|
29689
|
+
appendOptionalQuery(params, "order", input.order ?? "desc");
|
|
29690
|
+
return success(await api.get(
|
|
29691
|
+
`/api/issues/${encodeURIComponent(requiredAnyString(input, ["issue", "issueId"]))}/comments?${params}`
|
|
29692
|
+
));
|
|
29693
|
+
}
|
|
29694
|
+
case "issue.comments.get":
|
|
29695
|
+
return success(await api.get(
|
|
29696
|
+
`/api/issues/${encodeURIComponent(requiredAnyString(input, ["issue", "issueId"]))}/comments/${encodeURIComponent(requiredAnyString(input, ["comment", "commentId"]))}`
|
|
29697
|
+
));
|
|
29245
29698
|
case "issue.checkout": {
|
|
29246
29699
|
const expectedStatuses = parseCsvInput(input.expectedStatuses, "todo,backlog,blocked");
|
|
29247
29700
|
const payload = checkoutIssueSchema.parse({
|
|
@@ -29270,6 +29723,12 @@ async function callToolDirectlyIfSupported(toolName, rawArgs, env, signal) {
|
|
|
29270
29723
|
{ status: "done", comment }
|
|
29271
29724
|
));
|
|
29272
29725
|
}
|
|
29726
|
+
case "runs.create":
|
|
29727
|
+
return success(await api.post("/api/agent-runs/delegation", {
|
|
29728
|
+
task: requiredString(input, "task"),
|
|
29729
|
+
...optionalString(input.targetAgentId) ? { targetAgentId: optionalString(input.targetAgentId) } : {},
|
|
29730
|
+
idempotencyKey: requiredString(input, "idempotencyKey")
|
|
29731
|
+
}));
|
|
29273
29732
|
case "runs.list":
|
|
29274
29733
|
return success(await api.get(
|
|
29275
29734
|
`/api/run-intelligence/orgs/${encodeURIComponent(requiredRuntimeString(env, "RUDDER_ORG_ID"))}/runs?${buildDirectRunsListQuery(input)}`
|
|
@@ -29452,11 +29911,12 @@ function mcpApiClient(env, signal) {
|
|
|
29452
29911
|
apiKey: optionalString(env.RUDDER_API_KEY) ?? void 0,
|
|
29453
29912
|
agentId: optionalString(env.RUDDER_AGENT_ID) ?? void 0,
|
|
29454
29913
|
runId: optionalString(env.RUDDER_RUN_ID) ?? void 0,
|
|
29914
|
+
transportSurface: "mcp",
|
|
29455
29915
|
signal
|
|
29456
29916
|
});
|
|
29457
29917
|
}
|
|
29458
29918
|
function mcpSuccess(data, maxResultBytes = RUDDER_MCP_MAX_TOOL_RESULT_BYTES) {
|
|
29459
|
-
if (
|
|
29919
|
+
if (isRecord3(data) && (data.mimeType === "image/png" || data.mimeType === "image/jpeg") && typeof data.base64 === "string" && data.base64.length > 0) {
|
|
29460
29920
|
const { base64, ...metadata } = data;
|
|
29461
29921
|
return {
|
|
29462
29922
|
content: [{ type: "image", data: base64, mimeType: data.mimeType }],
|
|
@@ -29467,9 +29927,9 @@ function mcpSuccess(data, maxResultBytes = RUDDER_MCP_MAX_TOOL_RESULT_BYTES) {
|
|
|
29467
29927
|
return mcpSuccessFromJsonText(JSON.stringify(data ?? {}), maxResultBytes);
|
|
29468
29928
|
}
|
|
29469
29929
|
function mcpSuccessWithImages(data, maxResultBytes) {
|
|
29470
|
-
if (!
|
|
29930
|
+
if (!isRecord3(data) || !Array.isArray(data.images)) return mcpSuccess(data, maxResultBytes);
|
|
29471
29931
|
const images = data.images.filter(
|
|
29472
|
-
(entry) =>
|
|
29932
|
+
(entry) => isRecord3(entry) && (entry.mimeType === "image/png" || entry.mimeType === "image/jpeg") && typeof entry.base64 === "string" && entry.base64.length > 0
|
|
29473
29933
|
);
|
|
29474
29934
|
if (images.length === 0) return mcpSuccess(data, maxResultBytes);
|
|
29475
29935
|
const metadata = { ...data };
|
|
@@ -30073,6 +30533,11 @@ function cliArgsForCapability(capabilityId, input, tempFiles, env) {
|
|
|
30073
30533
|
}
|
|
30074
30534
|
case "chat.archive":
|
|
30075
30535
|
return ["chat", "archive", requiredAnyString(input, ["chat", "chatId"])];
|
|
30536
|
+
case "runs.create": {
|
|
30537
|
+
const args = ["runs", "create", "--task", requiredString(input, "task"), "--idempotency-key", requiredString(input, "idempotencyKey")];
|
|
30538
|
+
pushOptional(args, "--target-agent-id", input.targetAgentId);
|
|
30539
|
+
return args;
|
|
30540
|
+
}
|
|
30076
30541
|
case "runs.list": {
|
|
30077
30542
|
const args = ["runs", "list"];
|
|
30078
30543
|
pushOptional(args, "--updated-after", input.updatedAfter);
|
|
@@ -30162,7 +30627,7 @@ function modernOrLegacyResult(params, result, options) {
|
|
|
30162
30627
|
}
|
|
30163
30628
|
function paginateMcpTools(tools, params) {
|
|
30164
30629
|
if (!isModernMcpRequest(params)) return { tools };
|
|
30165
|
-
const record =
|
|
30630
|
+
const record = isRecord3(params) ? params : {};
|
|
30166
30631
|
const cursor = typeof record.cursor === "string" ? record.cursor : null;
|
|
30167
30632
|
const offset = cursor === null ? 0 : parseMcpToolCursor(cursor) ?? 0;
|
|
30168
30633
|
const page = tools.slice(offset, offset + RUDDER_MCP_TOOL_PAGE_SIZE);
|
|
@@ -30185,7 +30650,7 @@ function parseMcpToolCursor(cursor) {
|
|
|
30185
30650
|
return null;
|
|
30186
30651
|
}
|
|
30187
30652
|
function requestedProtocolVersion(params) {
|
|
30188
|
-
if (!
|
|
30653
|
+
if (!isRecord3(params)) return null;
|
|
30189
30654
|
return typeof params.protocolVersion === "string" && params.protocolVersion.trim().length > 0 ? params.protocolVersion.trim() : null;
|
|
30190
30655
|
}
|
|
30191
30656
|
function toolNameToCapabilityId(toolName) {
|
|
@@ -30230,7 +30695,7 @@ function pushJson(args, flag, value) {
|
|
|
30230
30695
|
args.push(flag, value.trim());
|
|
30231
30696
|
return;
|
|
30232
30697
|
}
|
|
30233
|
-
if (
|
|
30698
|
+
if (isRecord3(value) || Array.isArray(value)) {
|
|
30234
30699
|
args.push(flag, JSON.stringify(value));
|
|
30235
30700
|
}
|
|
30236
30701
|
}
|
|
@@ -30299,20 +30764,20 @@ function validateMcpToolArguments(toolName, input) {
|
|
|
30299
30764
|
}
|
|
30300
30765
|
if (Array.isArray(schema.anyOf)) {
|
|
30301
30766
|
const matches = schema.anyOf.some((candidate) => {
|
|
30302
|
-
if (!
|
|
30767
|
+
if (!isRecord3(candidate) || !Array.isArray(candidate.required)) return false;
|
|
30303
30768
|
return candidate.required.every((key) => {
|
|
30304
30769
|
const value = input[String(key)];
|
|
30305
30770
|
return value !== void 0 && value !== null && !(typeof value === "string" && value.trim().length === 0) && !(Array.isArray(value) && value.length === 0);
|
|
30306
30771
|
});
|
|
30307
30772
|
});
|
|
30308
30773
|
if (!matches) {
|
|
30309
|
-
const alternatives = schema.anyOf.flatMap((candidate) =>
|
|
30774
|
+
const alternatives = schema.anyOf.flatMap((candidate) => isRecord3(candidate) && Array.isArray(candidate.required) ? candidate.required : []).map(String);
|
|
30310
30775
|
throwInvalidMcpArgument(toolName, alternatives.join(" or "), "is required");
|
|
30311
30776
|
}
|
|
30312
30777
|
}
|
|
30313
30778
|
for (const [key, value] of Object.entries(input)) {
|
|
30314
30779
|
const property = schema.properties[key];
|
|
30315
|
-
if (!
|
|
30780
|
+
if (!isRecord3(property) || value === void 0) continue;
|
|
30316
30781
|
const violation = jsonSchemaViolation(value, property);
|
|
30317
30782
|
if (violation) throwInvalidMcpArgument(toolName, key, violation);
|
|
30318
30783
|
}
|
|
@@ -30320,20 +30785,21 @@ function validateMcpToolArguments(toolName, input) {
|
|
|
30320
30785
|
function jsonSchemaViolation(value, schema) {
|
|
30321
30786
|
if (Array.isArray(schema.oneOf)) {
|
|
30322
30787
|
const matches = schema.oneOf.some(
|
|
30323
|
-
(candidate) =>
|
|
30788
|
+
(candidate) => isRecord3(candidate) && jsonSchemaViolation(value, candidate) === null
|
|
30324
30789
|
);
|
|
30325
30790
|
if (!matches) return "does not match any allowed shape";
|
|
30326
30791
|
}
|
|
30327
30792
|
const types = Array.isArray(schema.type) ? schema.type : schema.type === void 0 ? [] : [schema.type];
|
|
30328
30793
|
if (types.length > 0) {
|
|
30329
|
-
const validType = types.some((type) => type === "string" ? typeof value === "string" : type === "number" ? typeof value === "number" && Number.isFinite(value) : type === "boolean" ? typeof value === "boolean" : type === "array" ? Array.isArray(value) : type === "object" ?
|
|
30794
|
+
const validType = types.some((type) => type === "string" ? typeof value === "string" : type === "number" ? typeof value === "number" && Number.isFinite(value) : type === "boolean" ? typeof value === "boolean" : type === "array" ? Array.isArray(value) : type === "object" ? isRecord3(value) : false);
|
|
30330
30795
|
if (!validType) return `must be ${types.join(" or ")}`;
|
|
30331
30796
|
}
|
|
30332
30797
|
if (typeof value === "string") {
|
|
30333
|
-
|
|
30798
|
+
const characterLength = Array.from(value).length;
|
|
30799
|
+
if (typeof schema.minLength === "number" && characterLength < schema.minLength) {
|
|
30334
30800
|
return `must contain at least ${schema.minLength} character(s)`;
|
|
30335
30801
|
}
|
|
30336
|
-
if (typeof schema.maxLength === "number" &&
|
|
30802
|
+
if (typeof schema.maxLength === "number" && characterLength > schema.maxLength) {
|
|
30337
30803
|
return `must contain at most ${schema.maxLength} characters`;
|
|
30338
30804
|
}
|
|
30339
30805
|
if (Array.isArray(schema.enum) && !schema.enum.includes(value)) {
|
|
@@ -30355,15 +30821,15 @@ function jsonSchemaViolation(value, schema) {
|
|
|
30355
30821
|
if (typeof schema.maxItems === "number" && value.length > schema.maxItems) {
|
|
30356
30822
|
return `must contain at most ${schema.maxItems} items`;
|
|
30357
30823
|
}
|
|
30358
|
-
if (
|
|
30824
|
+
if (isRecord3(schema.items)) {
|
|
30359
30825
|
for (const [index, item] of value.entries()) {
|
|
30360
30826
|
const violation = jsonSchemaViolation(item, schema.items);
|
|
30361
30827
|
if (violation) return `item ${index} ${violation}`;
|
|
30362
30828
|
}
|
|
30363
30829
|
}
|
|
30364
30830
|
}
|
|
30365
|
-
if (
|
|
30366
|
-
const properties =
|
|
30831
|
+
if (isRecord3(value) && schema.type === "object") {
|
|
30832
|
+
const properties = isRecord3(schema.properties) ? schema.properties : {};
|
|
30367
30833
|
const required = Array.isArray(schema.required) ? schema.required.map(String) : [];
|
|
30368
30834
|
for (const key of required) {
|
|
30369
30835
|
if (!(key in value)) return `field ${key} is required`;
|
|
@@ -30374,7 +30840,7 @@ function jsonSchemaViolation(value, schema) {
|
|
|
30374
30840
|
}
|
|
30375
30841
|
for (const [key, child] of Object.entries(value)) {
|
|
30376
30842
|
const childSchema = properties[key];
|
|
30377
|
-
if (!
|
|
30843
|
+
if (!isRecord3(childSchema)) continue;
|
|
30378
30844
|
const violation = jsonSchemaViolation(child, childSchema);
|
|
30379
30845
|
if (violation) return `field ${key} ${violation}`;
|
|
30380
30846
|
}
|
|
@@ -30436,7 +30902,7 @@ function assertBrowserCapabilityEnabled(capabilityId, env) {
|
|
|
30436
30902
|
function structuredContentFromJsonText(text6) {
|
|
30437
30903
|
try {
|
|
30438
30904
|
const parsed = JSON.parse(text6);
|
|
30439
|
-
if (
|
|
30905
|
+
if (isRecord3(parsed)) return { structuredContent: parsed };
|
|
30440
30906
|
return { structuredContent: { result: parsed } };
|
|
30441
30907
|
} catch {
|
|
30442
30908
|
return {};
|
|
@@ -30497,10 +30963,18 @@ function errorMessage(err) {
|
|
|
30497
30963
|
}
|
|
30498
30964
|
function errorDetails(err) {
|
|
30499
30965
|
if (!(err instanceof Error)) return void 0;
|
|
30966
|
+
if (err instanceof ApiRequestError) {
|
|
30967
|
+
const details = isRecord3(err.details) ? err.details : err.details === void 0 ? {} : { upstreamDetails: err.details };
|
|
30968
|
+
return {
|
|
30969
|
+
code: err.code ?? "api_request_error",
|
|
30970
|
+
status: err.status,
|
|
30971
|
+
...details
|
|
30972
|
+
};
|
|
30973
|
+
}
|
|
30500
30974
|
const code = err.code;
|
|
30501
30975
|
return code ? { code } : void 0;
|
|
30502
30976
|
}
|
|
30503
|
-
function
|
|
30977
|
+
function isRecord3(value) {
|
|
30504
30978
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
30505
30979
|
}
|
|
30506
30980
|
|
|
@@ -30554,8 +31028,8 @@ function registerActivityCommands(program) {
|
|
|
30554
31028
|
if (opts.entityType) params.set("entityType", opts.entityType);
|
|
30555
31029
|
if (opts.entityId) params.set("entityId", opts.entityId);
|
|
30556
31030
|
const query = params.toString();
|
|
30557
|
-
const
|
|
30558
|
-
const rows = await ctx.api.get(
|
|
31031
|
+
const path26 = `/api/orgs/${ctx.orgId}/activity${query ? `?${query}` : ""}`;
|
|
31032
|
+
const rows = await ctx.api.get(path26) ?? [];
|
|
30559
31033
|
if (ctx.json) {
|
|
30560
31034
|
printOutput(rows, { json: true });
|
|
30561
31035
|
return;
|
|
@@ -30586,8 +31060,8 @@ function registerActivityCommands(program) {
|
|
|
30586
31060
|
}
|
|
30587
31061
|
|
|
30588
31062
|
// ../packages/agent-runtime-utils/dist/server-utils.cli.js
|
|
30589
|
-
import { promises as
|
|
30590
|
-
import
|
|
31063
|
+
import { promises as fs9 } from "node:fs";
|
|
31064
|
+
import path12 from "node:path";
|
|
30591
31065
|
|
|
30592
31066
|
// ../packages/agent-runtime-utils/dist/native-process-runner.js
|
|
30593
31067
|
init_dist2();
|
|
@@ -31008,17 +31482,21 @@ Reason: {{context.passiveFollowup.reason}}
|
|
|
31008
31482
|
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.
|
|
31009
31483
|
${ISSUE_ASSIGNEE_EXECUTION_RAIL}`;
|
|
31010
31484
|
var RUDDER_AGENT_OPERATING_CONTRACT = [
|
|
31011
|
-
"You are a helpful assistant running inside Rudder. Your home directory is `$AGENT_HOME`. Everything personal to you -- life, memory, knowledge -- lives there.
|
|
31485
|
+
"You are a helpful assistant running inside Rudder. Your home directory is `$AGENT_HOME`. Everything personal to you -- life, memory, knowledge -- lives there. Every agent has its own folders and you may update them when necessary.",
|
|
31012
31486
|
"",
|
|
31013
|
-
"
|
|
31014
|
-
"
|
|
31487
|
+
"## Basic Rules",
|
|
31488
|
+
"- If you want to perform any Rudder-related operation such as issue, chat, agent run, automation, or projects, you can use rudder-mcp.",
|
|
31489
|
+
"- When working in an issue, the only scenario for user feedback and communication is via issue comments. Whenever there is progress, changes, or responses, always post an issue comment. Users do not see the entire trajectory of your agent run by default.",
|
|
31490
|
+
"- Another scenario is when you need to request something from the user. In such cases, use a request approval to seek the user's assistance.",
|
|
31491
|
+
"- Before taking action, deeply analyze and research the existing information to ensure you have comprehensive context information before proceeding with the next action. You have your own goal, memory, skills, automation, library, project, org, use these resources to make better decisions.",
|
|
31492
|
+
"- When the user explicitly mentions previously handled issue, tasks or conversations, retrieve the relevant tasks first before proceeding with the next action.",
|
|
31015
31493
|
"",
|
|
31494
|
+
"## Basic Paths",
|
|
31016
31495
|
"- Your personal instructions live under `$AGENT_HOME/instructions`.",
|
|
31017
31496
|
"- Personal memory lives under `$AGENT_HOME/memory`.",
|
|
31018
31497
|
"- Tacit memory instruction lives at `$AGENT_HOME/instructions/MEMORY.md` and is automatically loaded when present.",
|
|
31019
31498
|
"- Personal skills live under `$AGENT_HOME/skills`.",
|
|
31020
|
-
"- Shared organization workspace root lives under `$RUDDER_ORG_WORKSPACE_ROOT`.",
|
|
31021
|
-
"- Shared organization skills live under `$RUDDER_ORG_SKILLS_DIR`.",
|
|
31499
|
+
"- Shared organization workspace root lives under `$RUDDER_ORG_WORKSPACE_ROOT` and shared org's skills live under `$RUDDER_ORG_SKILLS_DIR`.",
|
|
31022
31500
|
"- Project Library root lives under `$RUDDER_PROJECT_LIBRARY_ROOT` when the run has project context.",
|
|
31023
31501
|
"- Project Library locator lives in `$RUDDER_PROJECT_LIBRARY_PATH` when the run has project context, for example `projects/<project-key>`.",
|
|
31024
31502
|
'- Library-backed project resources use `sourceType: "library"`; their `locator` points into `library:projects/<project-key>/`.',
|
|
@@ -31034,11 +31512,8 @@ var RUDDER_AGENT_OPERATING_CONTRACT = [
|
|
|
31034
31512
|
"When you create or copy a skill under `$AGENT_HOME/skills/<slug>/`, check the agent's Skills snapshot before claiming it will load in future runs. If it is installed but not enabled, say exactly that future runs will not load it until enabled, and offer to enable it with `rudder agent skills enable <agent-id> <selection-ref>` when you have permission.",
|
|
31035
31513
|
"If there is an AGENTS.md file in the project you're working on, please read it first and follow the project's development guidelines.",
|
|
31036
31514
|
"",
|
|
31037
|
-
"When you write issue comments or chat replies, match the language of the user's or board's most recent substantive message unless they explicitly ask for a different language.",
|
|
31038
|
-
"When you mention a web page, issue URL, external dashboard, or other user-openable target in an issue comment or chat reply, write it as a clickable Markdown link with a descriptive label, for example `[NameSilo transfer page](https://www.namesilo.com/account_domain_manage_transfer.php)`. Do not put action URLs in backticks or code blocks unless you are showing literal code or a command.",
|
|
31039
31515
|
"",
|
|
31040
31516
|
"## Rudder Renderable Links",
|
|
31041
|
-
"",
|
|
31042
31517
|
"When you mention Rudder entities in any user-visible Markdown output, prefer Rudder's renderable Markdown link syntax over plain IDs, bare URLs, or backticked references so the UI can render chips and navigate correctly.",
|
|
31043
31518
|
"",
|
|
31044
31519
|
"- Issues: use `[](issue://<issue-id>)`; include `?c=<comment-id>` when linking to a specific comment.",
|
|
@@ -31048,6 +31523,7 @@ var RUDDER_AGENT_OPERATING_CONTRACT = [
|
|
|
31048
31523
|
"- Chat threads: use `[](chat://<conversation-id>)` when citing a Rudder chat conversation.",
|
|
31049
31524
|
"- Skills: use `[](skill://<skill-ref>)` when citing a Rudder skill reference. The skill ref may be an org skill, agent skill, bundled Rudder skill, or local-machine skill ref; the UI resolves the display label when metadata is available.",
|
|
31050
31525
|
'- Library files: use the `markdownLink` returned by `rudder library file ref "$RUDDER_PROJECT_LIBRARY_PATH/<relative-file>" --json` with project context, or `rudder library file ref "artifacts/YYYY-MM-DD/<conversation-title>/<relative-file>" --json` without project context; do not hand-write `library-entry://...` links, and treat `library-file://...` as legacy path syntax only.',
|
|
31526
|
+
"- Web page, issue URL, external dashboard, or other user-openable target: write it as a clickable Markdown link with a descriptive label, eg: [NameSilo transfer page](https://www.namesilo.com/account_domain_manage_transfer.php). Do not put action URLs in backticks or code blocks unless you are showing literal code or a command.",
|
|
31051
31527
|
"",
|
|
31052
31528
|
"Write these as normal Markdown links, not inside code spans or code blocks, unless you are literally documenting the syntax.",
|
|
31053
31529
|
"",
|
|
@@ -31055,17 +31531,19 @@ var RUDDER_AGENT_OPERATING_CONTRACT = [
|
|
|
31055
31531
|
"",
|
|
31056
31532
|
"When an issue comment, done comment, or blocker comment cites visual evidence from a local screenshot/image path, attach the image with the Rudder CLI `--image <path>` option instead of leaving only the filesystem path in the text.",
|
|
31057
31533
|
"",
|
|
31534
|
+
"## Rudder Issue Transport Failures",
|
|
31535
|
+
"",
|
|
31536
|
+
"For Issue read/comment operations, treat typed Rudder MCP and the `rudder issue` CLI as one backend failure domain. Build the failure fingerprint from operation, Issue id, HTTP status/code, and normalized server message.",
|
|
31537
|
+
"After the typed MCP surface returns a 5xx failure, make at most one recorded fallback through the CLI. If that fallback returns the same fingerprint or reports `issue_transport_unavailable`, stop all Issue transport probes for the reported backoff: do not switch profiles, repeat either surface, or call the API directly.",
|
|
31538
|
+
"When the Issue transport budget is exhausted but local task work can continue, record the checkpoint `Issue transport unavailable` in the run outcome and keep Issue ownership, reviewer, and lifecycle state unchanged. Retry only after the diagnostic backoff expires or an explicit prerequisite changes.",
|
|
31539
|
+
"",
|
|
31058
31540
|
"## Memory and Shared Work Notes",
|
|
31059
31541
|
"",
|
|
31060
31542
|
"You MUST use the `para-memory-files` skill for all memory operations: storing facts, writing daily notes, creating entities, running weekly synthesis, recalling past context, and managing shared work notes. The skill defines your three-layer memory system (knowledge graph, daily notes, tacit knowledge), the PARA folder structure, atomic fact schemas, memory decay rules, and recall conventions.",
|
|
31061
31543
|
"",
|
|
31062
|
-
"Keep stable preferences and operating lessons in `$AGENT_HOME/instructions/MEMORY.md`. Use `$AGENT_HOME/memory/YYYY-MM-DD.md` for daily notes and `$AGENT_HOME/life/` for structured long-term memory.
|
|
31544
|
+
"Keep stable preferences and operating lessons in `$AGENT_HOME/instructions/MEMORY.md`. Use `$AGENT_HOME/memory/YYYY-MM-DD.md` for daily notes and `$AGENT_HOME/life/` for structured long-term memory. ",
|
|
31063
31545
|
"",
|
|
31064
|
-
"Invoke it whenever you need to remember, retrieve, or organize anything."
|
|
31065
|
-
"",
|
|
31066
|
-
"## Other",
|
|
31067
|
-
"- Before taking action, deeply analyze and research the existing information to ensure you have comprehensive context information before proceeding with the next action. You have your own goal, memory, skills, automation, library, project, org, use these resources to make better decisions.",
|
|
31068
|
-
"- 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."
|
|
31546
|
+
"Invoke it whenever you need to remember, retrieve, or organize anything."
|
|
31069
31547
|
].join("\n");
|
|
31070
31548
|
var RUDDER_AGENT_HEARTBEAT_INSTRUCTION = [
|
|
31071
31549
|
"This section is injected by Rudder only for heartbeat scene runs. It is the platform-owned heartbeat/self-check pipeline.",
|
|
@@ -31093,15 +31571,15 @@ var RUDDER_AGENT_HEARTBEAT_INSTRUCTION = [
|
|
|
31093
31571
|
// ../packages/agent-runtime-utils/dist/server-utils.cli.js
|
|
31094
31572
|
async function resolveRudderSkillsDir(moduleDir, additionalCandidates = []) {
|
|
31095
31573
|
const candidates = [
|
|
31096
|
-
...RUDDER_SKILL_ROOT_RELATIVE_CANDIDATES.map((relativePath) =>
|
|
31097
|
-
...additionalCandidates.map((candidate) =>
|
|
31574
|
+
...RUDDER_SKILL_ROOT_RELATIVE_CANDIDATES.map((relativePath) => path12.resolve(moduleDir, relativePath)),
|
|
31575
|
+
...additionalCandidates.map((candidate) => path12.resolve(candidate))
|
|
31098
31576
|
];
|
|
31099
31577
|
const seenRoots = /* @__PURE__ */ new Set();
|
|
31100
31578
|
for (const root of candidates) {
|
|
31101
31579
|
if (seenRoots.has(root))
|
|
31102
31580
|
continue;
|
|
31103
31581
|
seenRoots.add(root);
|
|
31104
|
-
const isDirectory = await
|
|
31582
|
+
const isDirectory = await fs9.stat(root).then((stats) => stats.isDirectory()).catch(() => false);
|
|
31105
31583
|
if (isDirectory)
|
|
31106
31584
|
return root;
|
|
31107
31585
|
}
|
|
@@ -31111,36 +31589,36 @@ async function removeMaintainerOnlySkillSymlinks(skillsHome, allowedSkillNames)
|
|
|
31111
31589
|
return removeUnselectedRudderSkillSymlinks(skillsHome, allowedSkillNames);
|
|
31112
31590
|
}
|
|
31113
31591
|
async function readRudderMaterializedSkillSource(target) {
|
|
31114
|
-
const manifestPath =
|
|
31115
|
-
const raw = await
|
|
31592
|
+
const manifestPath = path12.join(target, ".rudder", "materialized-skill.json");
|
|
31593
|
+
const raw = await fs9.readFile(manifestPath, "utf8").catch(() => null);
|
|
31116
31594
|
if (!raw)
|
|
31117
31595
|
return null;
|
|
31118
31596
|
try {
|
|
31119
31597
|
const parsed = parseObject(JSON.parse(raw));
|
|
31120
31598
|
const sourcePath = asString(parsed.sourcePath, "").trim();
|
|
31121
|
-
return sourcePath.length > 0 ?
|
|
31599
|
+
return sourcePath.length > 0 ? path12.resolve(sourcePath) : null;
|
|
31122
31600
|
} catch {
|
|
31123
31601
|
return null;
|
|
31124
31602
|
}
|
|
31125
31603
|
}
|
|
31126
31604
|
async function removeUnselectedRudderSkillSymlinks(skillsHome, allowedSkillNames, knownSkillSources = []) {
|
|
31127
31605
|
const allowed = new Set(Array.from(allowedSkillNames));
|
|
31128
|
-
const knownSources = new Set(Array.from(knownSkillSources).map((value) => value.trim()).filter(Boolean).map((value) =>
|
|
31606
|
+
const knownSources = new Set(Array.from(knownSkillSources).map((value) => value.trim()).filter(Boolean).map((value) => path12.resolve(value)));
|
|
31129
31607
|
try {
|
|
31130
|
-
const entries = await
|
|
31608
|
+
const entries = await fs9.readdir(skillsHome, { withFileTypes: true });
|
|
31131
31609
|
const removed = [];
|
|
31132
31610
|
for (const entry of entries) {
|
|
31133
|
-
const target =
|
|
31134
|
-
const existing = await
|
|
31611
|
+
const target = path12.join(skillsHome, entry.name);
|
|
31612
|
+
const existing = await fs9.lstat(target).catch(() => null);
|
|
31135
31613
|
if (!existing)
|
|
31136
31614
|
continue;
|
|
31137
31615
|
let isRudderManagedSkill = false;
|
|
31138
31616
|
if (existing.isSymbolicLink()) {
|
|
31139
|
-
const linkedPath = await
|
|
31617
|
+
const linkedPath = await fs9.readlink(target).catch(() => null);
|
|
31140
31618
|
if (!linkedPath)
|
|
31141
31619
|
continue;
|
|
31142
|
-
const resolvedLinkedPath =
|
|
31143
|
-
isRudderManagedSkill = knownSources.has(
|
|
31620
|
+
const resolvedLinkedPath = path12.isAbsolute(linkedPath) ? linkedPath : path12.resolve(path12.dirname(target), linkedPath);
|
|
31621
|
+
isRudderManagedSkill = knownSources.has(path12.resolve(resolvedLinkedPath)) || isMaintainerOnlySkillTarget(linkedPath) || isMaintainerOnlySkillTarget(resolvedLinkedPath);
|
|
31144
31622
|
} else if (existing.isDirectory()) {
|
|
31145
31623
|
const materializedSource = await readRudderMaterializedSkillSource(target);
|
|
31146
31624
|
isRudderManagedSkill = materializedSource !== null && knownSources.has(materializedSource);
|
|
@@ -31149,7 +31627,7 @@ async function removeUnselectedRudderSkillSymlinks(skillsHome, allowedSkillNames
|
|
|
31149
31627
|
continue;
|
|
31150
31628
|
if (allowed.has(entry.name))
|
|
31151
31629
|
continue;
|
|
31152
|
-
await
|
|
31630
|
+
await fs9.rm(target, { recursive: true, force: true });
|
|
31153
31631
|
removed.push(entry.name);
|
|
31154
31632
|
}
|
|
31155
31633
|
return removed;
|
|
@@ -31160,9 +31638,9 @@ async function removeUnselectedRudderSkillSymlinks(skillsHome, allowedSkillNames
|
|
|
31160
31638
|
|
|
31161
31639
|
// src/commands/client/agent.ts
|
|
31162
31640
|
init_dist2();
|
|
31163
|
-
import
|
|
31164
|
-
import
|
|
31165
|
-
import
|
|
31641
|
+
import fs10 from "node:fs/promises";
|
|
31642
|
+
import os4 from "node:os";
|
|
31643
|
+
import path13 from "node:path";
|
|
31166
31644
|
import { fileURLToPath as fileURLToPath6 } from "node:url";
|
|
31167
31645
|
|
|
31168
31646
|
// src/commands/client/help.ts
|
|
@@ -31186,16 +31664,16 @@ function formatHelpExample(example) {
|
|
|
31186
31664
|
}
|
|
31187
31665
|
|
|
31188
31666
|
// src/commands/client/agent.ts
|
|
31189
|
-
var __moduleDir =
|
|
31667
|
+
var __moduleDir = path13.dirname(fileURLToPath6(import.meta.url));
|
|
31190
31668
|
function codexSkillsHome() {
|
|
31191
31669
|
const fromEnv = process.env.CODEX_HOME?.trim();
|
|
31192
|
-
const base = fromEnv && fromEnv.length > 0 ? fromEnv :
|
|
31193
|
-
return
|
|
31670
|
+
const base = fromEnv && fromEnv.length > 0 ? fromEnv : path13.join(os4.homedir(), ".codex");
|
|
31671
|
+
return path13.join(base, "skills");
|
|
31194
31672
|
}
|
|
31195
31673
|
function claudeSkillsHome() {
|
|
31196
31674
|
const fromEnv = process.env.CLAUDE_HOME?.trim();
|
|
31197
|
-
const base = fromEnv && fromEnv.length > 0 ? fromEnv :
|
|
31198
|
-
return
|
|
31675
|
+
const base = fromEnv && fromEnv.length > 0 ? fromEnv : path13.join(os4.homedir(), ".claude");
|
|
31676
|
+
return path13.join(base, "skills");
|
|
31199
31677
|
}
|
|
31200
31678
|
async function installSkillsForTarget(sourceSkillsDir, targetSkillsDir, tool2) {
|
|
31201
31679
|
const summary = {
|
|
@@ -31206,26 +31684,26 @@ async function installSkillsForTarget(sourceSkillsDir, targetSkillsDir, tool2) {
|
|
|
31206
31684
|
skipped: [],
|
|
31207
31685
|
failed: []
|
|
31208
31686
|
};
|
|
31209
|
-
await
|
|
31210
|
-
const entries = await
|
|
31687
|
+
await fs10.mkdir(targetSkillsDir, { recursive: true });
|
|
31688
|
+
const entries = await fs10.readdir(sourceSkillsDir, { withFileTypes: true });
|
|
31211
31689
|
summary.removed = await removeMaintainerOnlySkillSymlinks(
|
|
31212
31690
|
targetSkillsDir,
|
|
31213
31691
|
entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name)
|
|
31214
31692
|
);
|
|
31215
31693
|
for (const entry of entries) {
|
|
31216
31694
|
if (!entry.isDirectory()) continue;
|
|
31217
|
-
const source =
|
|
31218
|
-
const target =
|
|
31219
|
-
const existing = await
|
|
31695
|
+
const source = path13.join(sourceSkillsDir, entry.name);
|
|
31696
|
+
const target = path13.join(targetSkillsDir, entry.name);
|
|
31697
|
+
const existing = await fs10.lstat(target).catch(() => null);
|
|
31220
31698
|
if (existing) {
|
|
31221
31699
|
if (existing.isSymbolicLink()) {
|
|
31222
31700
|
let linkedPath = null;
|
|
31223
31701
|
try {
|
|
31224
|
-
linkedPath = await
|
|
31702
|
+
linkedPath = await fs10.readlink(target);
|
|
31225
31703
|
} catch (err) {
|
|
31226
|
-
await
|
|
31704
|
+
await fs10.unlink(target);
|
|
31227
31705
|
try {
|
|
31228
|
-
await
|
|
31706
|
+
await fs10.symlink(source, target);
|
|
31229
31707
|
summary.linked.push(entry.name);
|
|
31230
31708
|
continue;
|
|
31231
31709
|
} catch (linkErr) {
|
|
@@ -31236,10 +31714,10 @@ async function installSkillsForTarget(sourceSkillsDir, targetSkillsDir, tool2) {
|
|
|
31236
31714
|
continue;
|
|
31237
31715
|
}
|
|
31238
31716
|
}
|
|
31239
|
-
const resolvedLinkedPath =
|
|
31240
|
-
const linkedTargetExists = await
|
|
31717
|
+
const resolvedLinkedPath = path13.isAbsolute(linkedPath) ? linkedPath : path13.resolve(path13.dirname(target), linkedPath);
|
|
31718
|
+
const linkedTargetExists = await fs10.stat(resolvedLinkedPath).then(() => true).catch(() => false);
|
|
31241
31719
|
if (!linkedTargetExists) {
|
|
31242
|
-
await
|
|
31720
|
+
await fs10.unlink(target);
|
|
31243
31721
|
} else {
|
|
31244
31722
|
summary.skipped.push(entry.name);
|
|
31245
31723
|
continue;
|
|
@@ -31250,7 +31728,7 @@ async function installSkillsForTarget(sourceSkillsDir, targetSkillsDir, tool2) {
|
|
|
31250
31728
|
}
|
|
31251
31729
|
}
|
|
31252
31730
|
try {
|
|
31253
|
-
await
|
|
31731
|
+
await fs10.symlink(source, target);
|
|
31254
31732
|
summary.linked.push(entry.name);
|
|
31255
31733
|
} catch (err) {
|
|
31256
31734
|
summary.failed.push({
|
|
@@ -31461,7 +31939,7 @@ function registerAgentCommands(program) {
|
|
|
31461
31939
|
if (opts.markdown && opts.markdownFile) {
|
|
31462
31940
|
throw new Error("Pass only one of --markdown or --markdown-file.");
|
|
31463
31941
|
}
|
|
31464
|
-
const markdown = opts.markdownFile ? await
|
|
31942
|
+
const markdown = opts.markdownFile ? await fs10.readFile(path13.resolve(opts.markdownFile), "utf8") : opts.markdown;
|
|
31465
31943
|
const payload = organizationSkillCreateSchema.parse({
|
|
31466
31944
|
name: opts.name,
|
|
31467
31945
|
slug: opts.slug?.trim() || null,
|
|
@@ -31640,7 +32118,7 @@ function registerAgentCommands(program) {
|
|
|
31640
32118
|
}
|
|
31641
32119
|
const installSummaries = [];
|
|
31642
32120
|
if (opts.installSkills !== false) {
|
|
31643
|
-
const skillsDir = await resolveRudderSkillsDir(__moduleDir, [
|
|
32121
|
+
const skillsDir = await resolveRudderSkillsDir(__moduleDir, [path13.resolve(process.cwd(), "skills")]);
|
|
31644
32122
|
if (!skillsDir) {
|
|
31645
32123
|
throw new Error(
|
|
31646
32124
|
"Could not locate local Rudder skills directory. Expected ./skills in the repo checkout."
|
|
@@ -31728,10 +32206,10 @@ async function buildAgentUpdatePatch(opts) {
|
|
|
31728
32206
|
if (opts.capabilities !== void 0) rawPatch.capabilities = opts.capabilities;
|
|
31729
32207
|
if (opts.description !== void 0) rawPatch.capabilities = opts.description;
|
|
31730
32208
|
if (opts.capabilitiesFile !== void 0) {
|
|
31731
|
-
rawPatch.capabilities = await
|
|
32209
|
+
rawPatch.capabilities = await fs10.readFile(path13.resolve(opts.capabilitiesFile), "utf8");
|
|
31732
32210
|
}
|
|
31733
32211
|
if (opts.descriptionFile !== void 0) {
|
|
31734
|
-
rawPatch.capabilities = await
|
|
32212
|
+
rawPatch.capabilities = await fs10.readFile(path13.resolve(opts.descriptionFile), "utf8");
|
|
31735
32213
|
}
|
|
31736
32214
|
if (clearCapabilities) rawPatch.capabilities = null;
|
|
31737
32215
|
return updateAgentSchema.parse(rawPatch);
|
|
@@ -31755,7 +32233,7 @@ function parseJsonObject(value, name) {
|
|
|
31755
32233
|
// src/commands/client/approval.ts
|
|
31756
32234
|
init_dist2();
|
|
31757
32235
|
import { readFile as readFile2 } from "node:fs/promises";
|
|
31758
|
-
import
|
|
32236
|
+
import path14 from "node:path";
|
|
31759
32237
|
function registerApprovalCommands(program) {
|
|
31760
32238
|
const approval = program.command("approval").description("Approval operations");
|
|
31761
32239
|
addCommonClientOptions(
|
|
@@ -31946,7 +32424,7 @@ async function readTextInputFile(inputPath, optionName) {
|
|
|
31946
32424
|
if (inputPath === "-") {
|
|
31947
32425
|
return readStdinText();
|
|
31948
32426
|
}
|
|
31949
|
-
const resolvedPath =
|
|
32427
|
+
const resolvedPath = path14.resolve(process.cwd(), inputPath);
|
|
31950
32428
|
return readFile2(resolvedPath, "utf8").catch((err) => {
|
|
31951
32429
|
throw new Error(`Unable to read ${optionName} ${inputPath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
31952
32430
|
});
|
|
@@ -32784,11 +33262,11 @@ async function readStdin() {
|
|
|
32784
33262
|
// src/commands/client/company.ts
|
|
32785
33263
|
import * as p3 from "@clack/prompts";
|
|
32786
33264
|
import { mkdir as mkdir2, readdir as readdir2, readFile as readFile3, stat as stat2, writeFile as writeFile2 } from "node:fs/promises";
|
|
32787
|
-
import
|
|
33265
|
+
import path16 from "node:path";
|
|
32788
33266
|
import pc5 from "picocolors";
|
|
32789
33267
|
|
|
32790
33268
|
// src/commands/client/zip.ts
|
|
32791
|
-
import
|
|
33269
|
+
import path15 from "node:path";
|
|
32792
33270
|
import { inflateRawSync } from "node:zlib";
|
|
32793
33271
|
var textDecoder = new TextDecoder();
|
|
32794
33272
|
var binaryContentTypeByExtension = {
|
|
@@ -32816,7 +33294,7 @@ function sharedArchiveRoot(paths) {
|
|
|
32816
33294
|
return firstSegments.every((parts) => parts.length > 1 && parts[0] === candidate) ? candidate : null;
|
|
32817
33295
|
}
|
|
32818
33296
|
function bytesToPortableFileEntry(pathValue, bytes) {
|
|
32819
|
-
const contentType = binaryContentTypeByExtension[
|
|
33297
|
+
const contentType = binaryContentTypeByExtension[path15.extname(pathValue).toLowerCase()];
|
|
32820
33298
|
if (!contentType) return textDecoder.decode(bytes);
|
|
32821
33299
|
return {
|
|
32822
33300
|
encoding: "base64",
|
|
@@ -32904,7 +33382,7 @@ var IMPORT_INCLUDE_OPTIONS = [
|
|
|
32904
33382
|
];
|
|
32905
33383
|
var IMPORT_PREVIEW_SAMPLE_LIMIT = 6;
|
|
32906
33384
|
function readPortableFileEntry(filePath, contents) {
|
|
32907
|
-
const contentType = binaryContentTypeByExtension[
|
|
33385
|
+
const contentType = binaryContentTypeByExtension[path16.extname(filePath).toLowerCase()];
|
|
32908
33386
|
if (!contentType) return contents.toString("utf8");
|
|
32909
33387
|
return {
|
|
32910
33388
|
encoding: "base64",
|
|
@@ -32959,10 +33437,10 @@ function normalizePortablePath(filePath) {
|
|
|
32959
33437
|
return filePath.replace(/\\/g, "/");
|
|
32960
33438
|
}
|
|
32961
33439
|
function shouldIncludePortableFile(filePath) {
|
|
32962
|
-
const baseName =
|
|
33440
|
+
const baseName = path16.basename(filePath);
|
|
32963
33441
|
const isMarkdown = baseName.endsWith(".md");
|
|
32964
33442
|
const isPaperclipYaml = baseName === ".rudder.yaml" || baseName === ".rudder.yml";
|
|
32965
|
-
const contentType = binaryContentTypeByExtension[
|
|
33443
|
+
const contentType = binaryContentTypeByExtension[path16.extname(baseName).toLowerCase()];
|
|
32966
33444
|
return isMarkdown || isPaperclipYaml || Boolean(contentType);
|
|
32967
33445
|
}
|
|
32968
33446
|
function findPortableExtensionPath(files) {
|
|
@@ -33517,7 +33995,7 @@ function normalizeGithubImportSource(input, refOverride) {
|
|
|
33517
33995
|
}
|
|
33518
33996
|
async function pathExists(inputPath) {
|
|
33519
33997
|
try {
|
|
33520
|
-
await stat2(
|
|
33998
|
+
await stat2(path16.resolve(inputPath));
|
|
33521
33999
|
return true;
|
|
33522
34000
|
} catch {
|
|
33523
34001
|
return false;
|
|
@@ -33527,45 +34005,45 @@ async function collectPackageFiles(root, current, files) {
|
|
|
33527
34005
|
const entries = await readdir2(current, { withFileTypes: true });
|
|
33528
34006
|
for (const entry of entries) {
|
|
33529
34007
|
if (entry.name.startsWith(".git")) continue;
|
|
33530
|
-
const absolutePath =
|
|
34008
|
+
const absolutePath = path16.join(current, entry.name);
|
|
33531
34009
|
if (entry.isDirectory()) {
|
|
33532
34010
|
await collectPackageFiles(root, absolutePath, files);
|
|
33533
34011
|
continue;
|
|
33534
34012
|
}
|
|
33535
34013
|
if (!entry.isFile()) continue;
|
|
33536
|
-
const relativePath =
|
|
34014
|
+
const relativePath = path16.relative(root, absolutePath).replace(/\\/g, "/");
|
|
33537
34015
|
if (!shouldIncludePortableFile(relativePath)) continue;
|
|
33538
34016
|
files[relativePath] = readPortableFileEntry(relativePath, await readFile3(absolutePath));
|
|
33539
34017
|
}
|
|
33540
34018
|
}
|
|
33541
34019
|
async function resolveInlineSourceFromPath(inputPath) {
|
|
33542
|
-
const resolved =
|
|
34020
|
+
const resolved = path16.resolve(inputPath);
|
|
33543
34021
|
const resolvedStat = await stat2(resolved);
|
|
33544
|
-
if (resolvedStat.isFile() &&
|
|
34022
|
+
if (resolvedStat.isFile() && path16.extname(resolved).toLowerCase() === ".zip") {
|
|
33545
34023
|
const archive = await readZipArchive(await readFile3(resolved));
|
|
33546
34024
|
const filteredFiles = Object.fromEntries(
|
|
33547
34025
|
Object.entries(archive.files).filter(([relativePath]) => shouldIncludePortableFile(relativePath))
|
|
33548
34026
|
);
|
|
33549
34027
|
return {
|
|
33550
|
-
rootPath: archive.rootPath ??
|
|
34028
|
+
rootPath: archive.rootPath ?? path16.basename(resolved, ".zip"),
|
|
33551
34029
|
files: filteredFiles
|
|
33552
34030
|
};
|
|
33553
34031
|
}
|
|
33554
|
-
const rootDir = resolvedStat.isDirectory() ? resolved :
|
|
34032
|
+
const rootDir = resolvedStat.isDirectory() ? resolved : path16.dirname(resolved);
|
|
33555
34033
|
const files = {};
|
|
33556
34034
|
await collectPackageFiles(rootDir, rootDir, files);
|
|
33557
34035
|
return {
|
|
33558
|
-
rootPath:
|
|
34036
|
+
rootPath: path16.basename(rootDir),
|
|
33559
34037
|
files
|
|
33560
34038
|
};
|
|
33561
34039
|
}
|
|
33562
34040
|
async function writeExportToFolder(outDir, exported) {
|
|
33563
|
-
const root =
|
|
34041
|
+
const root = path16.resolve(outDir);
|
|
33564
34042
|
await mkdir2(root, { recursive: true });
|
|
33565
34043
|
for (const [relativePath, content] of Object.entries(exported.files)) {
|
|
33566
34044
|
const normalized = relativePath.replace(/\\/g, "/");
|
|
33567
|
-
const filePath =
|
|
33568
|
-
await mkdir2(
|
|
34045
|
+
const filePath = path16.join(root, normalized);
|
|
34046
|
+
await mkdir2(path16.dirname(filePath), { recursive: true });
|
|
33569
34047
|
const writeValue = portableFileEntryToWriteValue(content);
|
|
33570
34048
|
if (typeof writeValue === "string") {
|
|
33571
34049
|
await writeFile2(filePath, writeValue, "utf8");
|
|
@@ -33575,7 +34053,7 @@ async function writeExportToFolder(outDir, exported) {
|
|
|
33575
34053
|
}
|
|
33576
34054
|
}
|
|
33577
34055
|
async function confirmOverwriteExportDirectory(outDir) {
|
|
33578
|
-
const root =
|
|
34056
|
+
const root = path16.resolve(outDir);
|
|
33579
34057
|
const stats = await stat2(root).catch(() => null);
|
|
33580
34058
|
if (!stats) return;
|
|
33581
34059
|
if (!stats.isDirectory()) {
|
|
@@ -33757,7 +34235,7 @@ function registerCompanyCommands(program) {
|
|
|
33757
34235
|
printOutput(
|
|
33758
34236
|
{
|
|
33759
34237
|
ok: true,
|
|
33760
|
-
out:
|
|
34238
|
+
out: path16.resolve(opts.out),
|
|
33761
34239
|
rootPath: exported.rootPath,
|
|
33762
34240
|
filesWritten: Object.keys(exported.files).length,
|
|
33763
34241
|
rudderExtensionPath: exported.rudderExtensionPath,
|
|
@@ -34256,7 +34734,7 @@ function parseResultValue(value) {
|
|
|
34256
34734
|
// src/commands/client/issue.ts
|
|
34257
34735
|
init_dist2();
|
|
34258
34736
|
import { readFile as readFile4, stat as stat3 } from "node:fs/promises";
|
|
34259
|
-
import
|
|
34737
|
+
import path17 from "node:path";
|
|
34260
34738
|
function registerIssueCommands(program) {
|
|
34261
34739
|
const issue = program.command("issue").description("Issue operations");
|
|
34262
34740
|
addCommonClientOptions(
|
|
@@ -34620,7 +35098,7 @@ async function readTextInputFile2(inputPath, optionName) {
|
|
|
34620
35098
|
if (inputPath === "-") {
|
|
34621
35099
|
return readStdinText2();
|
|
34622
35100
|
}
|
|
34623
|
-
const resolvedPath =
|
|
35101
|
+
const resolvedPath = path17.resolve(process.cwd(), inputPath);
|
|
34624
35102
|
return readFile4(resolvedPath, "utf8").catch((err) => {
|
|
34625
35103
|
throw new Error(`Unable to read ${optionName} ${inputPath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
34626
35104
|
});
|
|
@@ -34677,14 +35155,14 @@ async function appendUploadedIssueImages(ctx, issueId, body, imagePaths) {
|
|
|
34677
35155
|
${imageBlock}` : imageBlock;
|
|
34678
35156
|
}
|
|
34679
35157
|
async function uploadIssueCommentImage(ctx, issue, imagePath) {
|
|
34680
|
-
const resolvedPath =
|
|
35158
|
+
const resolvedPath = path17.resolve(process.cwd(), imagePath);
|
|
34681
35159
|
const stats = await stat3(resolvedPath).catch((err) => {
|
|
34682
35160
|
throw new Error(`Unable to read image ${imagePath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
34683
35161
|
});
|
|
34684
35162
|
if (!stats.isFile()) {
|
|
34685
35163
|
throw new Error(`Image path must be a file: ${imagePath}`);
|
|
34686
35164
|
}
|
|
34687
|
-
const filename =
|
|
35165
|
+
const filename = path17.basename(resolvedPath);
|
|
34688
35166
|
const contentType = inferCommentImageContentType(filename);
|
|
34689
35167
|
const buffer = await readFile4(resolvedPath);
|
|
34690
35168
|
if (buffer.length <= 0) {
|
|
@@ -34703,7 +35181,7 @@ async function uploadIssueCommentImage(ctx, issue, imagePath) {
|
|
|
34703
35181
|
return attachment;
|
|
34704
35182
|
}
|
|
34705
35183
|
function inferCommentImageContentType(filename) {
|
|
34706
|
-
const ext =
|
|
35184
|
+
const ext = path17.extname(filename).toLowerCase();
|
|
34707
35185
|
switch (ext) {
|
|
34708
35186
|
case ".png":
|
|
34709
35187
|
return "image/png";
|
|
@@ -34807,7 +35285,7 @@ function formatIssueSearchMatch(match) {
|
|
|
34807
35285
|
|
|
34808
35286
|
// src/commands/client/library.ts
|
|
34809
35287
|
import { readFile as readFile5 } from "node:fs/promises";
|
|
34810
|
-
import
|
|
35288
|
+
import path18 from "node:path";
|
|
34811
35289
|
function toLibraryFileLinkResult(detail) {
|
|
34812
35290
|
return {
|
|
34813
35291
|
filePath: detail.filePath,
|
|
@@ -34952,7 +35430,7 @@ async function resolveBodyFileInput(inputPath) {
|
|
|
34952
35430
|
if (inputPath === "-") {
|
|
34953
35431
|
return readStdinText3();
|
|
34954
35432
|
}
|
|
34955
|
-
const resolvedPath =
|
|
35433
|
+
const resolvedPath = path18.resolve(process.cwd(), inputPath);
|
|
34956
35434
|
return readFile5(resolvedPath, "utf8").catch((err) => {
|
|
34957
35435
|
throw new Error(`Unable to read --body-file ${inputPath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
34958
35436
|
});
|
|
@@ -35154,6 +35632,21 @@ function projectPath(projectRef, orgId) {
|
|
|
35154
35632
|
// src/commands/client/runs.ts
|
|
35155
35633
|
function registerRunsCommands(program) {
|
|
35156
35634
|
const runs = program.command("runs").description("Run debugging operations");
|
|
35635
|
+
addCommonClientOptions(
|
|
35636
|
+
runs.command("create").description(getAgentCliCapabilityById("runs.create").description).requiredOption("--task <text>", "Delegation task text").option("--target-agent-id <id>", "Same-organization target Agent; defaults to the current Agent").requiredOption("--idempotency-key <key>", "Stable key for safe replay").action(async (opts) => {
|
|
35637
|
+
try {
|
|
35638
|
+
const ctx = resolveCommandContext(opts);
|
|
35639
|
+
const row = await ctx.api.post("/api/agent-runs/delegation", {
|
|
35640
|
+
task: opts.task,
|
|
35641
|
+
...opts.targetAgentId ? { targetAgentId: opts.targetAgentId } : {},
|
|
35642
|
+
idempotencyKey: opts.idempotencyKey
|
|
35643
|
+
});
|
|
35644
|
+
printOutput(row, { json: ctx.json });
|
|
35645
|
+
} catch (err) {
|
|
35646
|
+
handleCommandError(err);
|
|
35647
|
+
}
|
|
35648
|
+
})
|
|
35649
|
+
);
|
|
35157
35650
|
addCommonClientOptions(
|
|
35158
35651
|
runs.command("list").description(getAgentCliCapabilityById("runs.list").description).option("-O, --org-id <id>", "Organization ID").option("--updated-after <iso>", "Only runs updated after this timestamp").option("--run-id-prefix <prefix>", "Filter by run ID prefix").option("--agent-id <id>", "Filter by agent ID").option("--status <status>", "Filter by run status").option("--runtime <type>", "Filter by runtime type").option("--issue-id <id>", "Filter by linked issue ID").option("--used-skill <key-or-name>", "Filter by skill actually used during the run").option("--loaded-skill <key-or-name>", "Filter by skill loaded for the run").option("--created-before <iso>", "Only runs created before this timestamp").option("--cursor <cursor>", "Stable summary cursor returned in page.nextCursor").option("--limit <n>", "Maximum rows; defaults to 50 summaries or 200 full rows").option("--full", "Use the legacy full-row list response for compatibility").addHelpText("after", formatExamplesAndCautions({
|
|
35159
35652
|
examples: [
|
|
@@ -35806,8 +36299,8 @@ function registerUserCommands(program) {
|
|
|
35806
36299
|
appendParam(params, "limit", opts.limit);
|
|
35807
36300
|
appendParam(params, "cursor", opts.cursor);
|
|
35808
36301
|
const query = params.toString();
|
|
35809
|
-
const
|
|
35810
|
-
const result = await ctx.api.get(
|
|
36302
|
+
const path26 = `/api/orgs/${ctx.orgId}/users/${encodeURIComponent(userId)}/activity-ledger${query ? `?${query}` : ""}`;
|
|
36303
|
+
const result = await ctx.api.get(path26);
|
|
35811
36304
|
if (ctx.json) {
|
|
35812
36305
|
printOutput(result, { json: true });
|
|
35813
36306
|
return;
|
|
@@ -36622,11 +37115,11 @@ init_run();
|
|
|
36622
37115
|
// src/commands/start.ts
|
|
36623
37116
|
import * as p15 from "@clack/prompts";
|
|
36624
37117
|
import { spawn as spawn3, spawnSync as spawnSync4 } from "node:child_process";
|
|
36625
|
-
import { createHash as
|
|
37118
|
+
import { createHash as createHash5, randomUUID } from "node:crypto";
|
|
36626
37119
|
import { constants as fsConstants, mkdirSync as mkdirSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
36627
37120
|
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";
|
|
36628
37121
|
import { homedir, tmpdir } from "node:os";
|
|
36629
|
-
import
|
|
37122
|
+
import path24 from "node:path";
|
|
36630
37123
|
import { clearTimeout as clearTimeout3, setTimeout as setTimeout3 } from "node:timers";
|
|
36631
37124
|
import { setTimeout as delay2 } from "node:timers/promises";
|
|
36632
37125
|
import pc14 from "picocolors";
|
|
@@ -36654,10 +37147,10 @@ function parseChecksumFile(contents) {
|
|
|
36654
37147
|
init_home();
|
|
36655
37148
|
|
|
36656
37149
|
// src/desktop-download.ts
|
|
36657
|
-
import { createHash as
|
|
37150
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
36658
37151
|
import { createWriteStream as createWriteStream3, mkdirSync } from "node:fs";
|
|
36659
37152
|
import { rm as rm2 } from "node:fs/promises";
|
|
36660
|
-
import
|
|
37153
|
+
import path23 from "node:path";
|
|
36661
37154
|
import { Readable as Readable2, Transform as Transform2 } from "node:stream";
|
|
36662
37155
|
import { pipeline as pipeline3 } from "node:stream/promises";
|
|
36663
37156
|
import { clearTimeout as clearTimeout2, setTimeout as setTimeout2 } from "node:timers";
|
|
@@ -36897,7 +37390,7 @@ async function resolveDesktopDownloadOrigins(options) {
|
|
|
36897
37390
|
}
|
|
36898
37391
|
async function downloadAsset(asset, outputDir, progressFactory = createByteProgress, expectedChecksum, timeouts = {}) {
|
|
36899
37392
|
mkdirSync(outputDir, { recursive: true });
|
|
36900
|
-
const outputPath =
|
|
37393
|
+
const outputPath = path23.join(outputDir, path23.basename(asset.name));
|
|
36901
37394
|
const idleTimeoutMs = timeouts.idleMs ?? DESKTOP_ASSET_IDLE_TIMEOUT_MS;
|
|
36902
37395
|
const responseTimeoutMs = timeouts.responseMs ?? DESKTOP_ASSET_RESPONSE_TIMEOUT_MS;
|
|
36903
37396
|
const failures = [];
|
|
@@ -36917,7 +37410,7 @@ async function downloadAsset(asset, outputDir, progressFactory = createByteProgr
|
|
|
36917
37410
|
const totalBytes = contentLengthFromHeaders(response.headers);
|
|
36918
37411
|
progress = progressFactory(`Downloading ${asset.name}`);
|
|
36919
37412
|
let receivedBytes = 0;
|
|
36920
|
-
const hash =
|
|
37413
|
+
const hash = createHash4("sha256");
|
|
36921
37414
|
let monitor;
|
|
36922
37415
|
const armIdleTimeout = () => {
|
|
36923
37416
|
if (idleTimeout) clearTimeout2(idleTimeout);
|
|
@@ -37233,38 +37726,38 @@ function resolveDesktopAssetTarget(platform = process.platform, arch = process.a
|
|
|
37233
37726
|
throw new Error(`Rudder Desktop does not publish portable assets for ${platform}.`);
|
|
37234
37727
|
}
|
|
37235
37728
|
function resolveDefaultDesktopInstallRoot(target, env = process.env, homeDir = homedir()) {
|
|
37236
|
-
if (target.platform === "macos") return
|
|
37729
|
+
if (target.platform === "macos") return path24.join(homeDir, "Applications");
|
|
37237
37730
|
if (target.platform === "windows") {
|
|
37238
|
-
const localAppData = env.LOCALAPPDATA?.trim() ||
|
|
37239
|
-
return
|
|
37731
|
+
const localAppData = env.LOCALAPPDATA?.trim() || path24.join(homeDir, "AppData", "Local");
|
|
37732
|
+
return path24.join(localAppData, "Programs", DESKTOP_APP_NAME);
|
|
37240
37733
|
}
|
|
37241
|
-
return
|
|
37734
|
+
return path24.join(homeDir, ".local", "share", "rudder");
|
|
37242
37735
|
}
|
|
37243
37736
|
function resolveDesktopInstallPaths(target, installRoot) {
|
|
37244
|
-
const root =
|
|
37737
|
+
const root = path24.resolve(installRoot);
|
|
37245
37738
|
if (target.platform === "macos") {
|
|
37246
|
-
const appPath2 =
|
|
37739
|
+
const appPath2 = path24.join(root, `${DESKTOP_APP_NAME}.app`);
|
|
37247
37740
|
return {
|
|
37248
37741
|
installRoot: root,
|
|
37249
37742
|
appPath: appPath2,
|
|
37250
|
-
executablePath:
|
|
37251
|
-
metadataPath:
|
|
37743
|
+
executablePath: path24.join(appPath2, "Contents", "MacOS", DESKTOP_APP_NAME),
|
|
37744
|
+
metadataPath: path24.join(root, DESKTOP_METADATA_FILE)
|
|
37252
37745
|
};
|
|
37253
37746
|
}
|
|
37254
37747
|
if (target.platform === "windows") {
|
|
37255
37748
|
return {
|
|
37256
37749
|
installRoot: root,
|
|
37257
37750
|
appPath: root,
|
|
37258
|
-
executablePath:
|
|
37259
|
-
metadataPath:
|
|
37751
|
+
executablePath: path24.join(root, `${DESKTOP_APP_NAME}.exe`),
|
|
37752
|
+
metadataPath: path24.join(root, DESKTOP_METADATA_FILE)
|
|
37260
37753
|
};
|
|
37261
37754
|
}
|
|
37262
|
-
const appPath =
|
|
37755
|
+
const appPath = path24.join(root, `${DESKTOP_APP_NAME}.AppImage`);
|
|
37263
37756
|
return {
|
|
37264
37757
|
installRoot: root,
|
|
37265
37758
|
appPath,
|
|
37266
37759
|
executablePath: appPath,
|
|
37267
|
-
metadataPath:
|
|
37760
|
+
metadataPath: path24.join(root, DESKTOP_METADATA_FILE)
|
|
37268
37761
|
};
|
|
37269
37762
|
}
|
|
37270
37763
|
function normalizeAssetName(name) {
|
|
@@ -37447,21 +37940,21 @@ function buildGithubReleaseAsset(repo, tag, assetName, downloadBaseUrl) {
|
|
|
37447
37940
|
};
|
|
37448
37941
|
}
|
|
37449
37942
|
function checksumForFile(filePath) {
|
|
37450
|
-
const hash =
|
|
37943
|
+
const hash = createHash5("sha256");
|
|
37451
37944
|
hash.update(readFileSync2(filePath));
|
|
37452
37945
|
return hash.digest("hex");
|
|
37453
37946
|
}
|
|
37454
37947
|
function resolveAssetChecksum(checksums, assetName) {
|
|
37455
|
-
const expected = checksums.get(
|
|
37948
|
+
const expected = checksums.get(path24.basename(assetName));
|
|
37456
37949
|
if (!expected) {
|
|
37457
|
-
throw new Error(`Desktop release checksums do not include ${
|
|
37950
|
+
throw new Error(`Desktop release checksums do not include ${path24.basename(assetName)}.`);
|
|
37458
37951
|
}
|
|
37459
37952
|
return expected;
|
|
37460
37953
|
}
|
|
37461
37954
|
function assertChecksumMatch(filePath, expected) {
|
|
37462
37955
|
const actual = checksumForFile(filePath);
|
|
37463
37956
|
if (actual !== expected.toLowerCase()) {
|
|
37464
|
-
throw new Error(`Checksum mismatch for ${
|
|
37957
|
+
throw new Error(`Checksum mismatch for ${path24.basename(filePath)}.`);
|
|
37465
37958
|
}
|
|
37466
37959
|
return actual;
|
|
37467
37960
|
}
|
|
@@ -37480,10 +37973,10 @@ function normalizeDesktopAssetChecksum(checksum) {
|
|
|
37480
37973
|
return normalized;
|
|
37481
37974
|
}
|
|
37482
37975
|
function resolveDesktopAssetCacheDir(assetChecksum, homeDir = resolveRudderHomeDir()) {
|
|
37483
|
-
return
|
|
37976
|
+
return path24.join(homeDir, DESKTOP_ASSET_CACHE_DIR, normalizeDesktopAssetChecksum(assetChecksum));
|
|
37484
37977
|
}
|
|
37485
37978
|
function resolveDesktopCachedAssetPath(assetName, assetChecksum, homeDir = resolveRudderHomeDir()) {
|
|
37486
|
-
return
|
|
37979
|
+
return path24.join(resolveDesktopAssetCacheDir(assetChecksum, homeDir), path24.basename(assetName));
|
|
37487
37980
|
}
|
|
37488
37981
|
async function pruneDesktopAssetCache(options = {}) {
|
|
37489
37982
|
const homeDir = options.homeDir ?? resolveRudderHomeDir();
|
|
@@ -37529,7 +38022,7 @@ async function maybePruneDesktopAssetCache(options) {
|
|
|
37529
38022
|
return result.deleted.length > 0 || result.warnings.length > 0 ? result : null;
|
|
37530
38023
|
}
|
|
37531
38024
|
async function scanDesktopAssetCacheEntries(homeDir) {
|
|
37532
|
-
const cacheRoot =
|
|
38025
|
+
const cacheRoot = path24.join(homeDir, DESKTOP_ASSET_CACHE_DIR);
|
|
37533
38026
|
const dirents = await readdir3(cacheRoot, { withFileTypes: true }).catch(() => null);
|
|
37534
38027
|
if (!dirents) return [];
|
|
37535
38028
|
const entries = [];
|
|
@@ -37541,7 +38034,7 @@ async function scanDesktopAssetCacheEntries(homeDir) {
|
|
|
37541
38034
|
} catch {
|
|
37542
38035
|
continue;
|
|
37543
38036
|
}
|
|
37544
|
-
const cacheDir =
|
|
38037
|
+
const cacheDir = path24.join(cacheRoot, dirent.name);
|
|
37545
38038
|
const stats = await desktopCacheDirectoryStats(cacheDir);
|
|
37546
38039
|
entries.push({
|
|
37547
38040
|
cacheDir,
|
|
@@ -37565,7 +38058,7 @@ async function desktopCacheDirectoryStats(targetPath) {
|
|
|
37565
38058
|
let lastUsedAtMs = Number(fallbackStat?.mtimeMs ?? 0);
|
|
37566
38059
|
for (const dirent of dirents) {
|
|
37567
38060
|
if (dirent.isSymbolicLink()) continue;
|
|
37568
|
-
const entryPath =
|
|
38061
|
+
const entryPath = path24.join(targetPath, dirent.name);
|
|
37569
38062
|
const entryStat = await stat4(entryPath).catch(() => null);
|
|
37570
38063
|
if (!entryStat) continue;
|
|
37571
38064
|
lastUsedAtMs = Math.max(lastUsedAtMs, Number(entryStat.mtimeMs ?? 0));
|
|
@@ -37642,13 +38135,13 @@ async function downloadDesktopAssetWithCache(asset, expectedChecksum, options =
|
|
|
37642
38135
|
await rm3(cachePath, { force: true });
|
|
37643
38136
|
}
|
|
37644
38137
|
}
|
|
37645
|
-
const outputDir = options.outputDir ?? await mkdtemp2(
|
|
38138
|
+
const outputDir = options.outputDir ?? await mkdtemp2(path24.join(tmpdir(), "rudder-desktop-installer."));
|
|
37646
38139
|
const removeOutputDir = options.outputDir ? false : true;
|
|
37647
38140
|
try {
|
|
37648
38141
|
const downloadedPath = await downloadAsset(asset, outputDir, options.progressFactory, normalizedChecksum);
|
|
37649
38142
|
const checksum = assertChecksumMatch(downloadedPath, normalizedChecksum);
|
|
37650
|
-
await mkdir3(
|
|
37651
|
-
if (
|
|
38143
|
+
await mkdir3(path24.dirname(cachePath), { recursive: true });
|
|
38144
|
+
if (path24.resolve(downloadedPath) !== path24.resolve(cachePath)) {
|
|
37652
38145
|
await copyFile(downloadedPath, cachePath);
|
|
37653
38146
|
}
|
|
37654
38147
|
return { path: cachePath, checksum, cacheStatus: "miss" };
|
|
@@ -37665,8 +38158,8 @@ async function pathExists2(targetPath) {
|
|
|
37665
38158
|
}
|
|
37666
38159
|
}
|
|
37667
38160
|
function resolveDesktopInstallLockPath(paths) {
|
|
37668
|
-
const installRootHash =
|
|
37669
|
-
return
|
|
38161
|
+
const installRootHash = createHash5("sha256").update(path24.resolve(paths.installRoot)).digest("hex").slice(0, 16);
|
|
38162
|
+
return path24.join(path24.dirname(paths.appPath), `.rudder-desktop-install-${installRootHash}.lock`);
|
|
37670
38163
|
}
|
|
37671
38164
|
async function readDesktopInstallLock(lockPath) {
|
|
37672
38165
|
try {
|
|
@@ -37686,14 +38179,14 @@ async function readDesktopInstallLock(lockPath) {
|
|
|
37686
38179
|
}
|
|
37687
38180
|
async function withDesktopInstallLock(paths, fn, options = {}) {
|
|
37688
38181
|
const lockPath = resolveDesktopInstallLockPath(paths);
|
|
37689
|
-
const lockDir =
|
|
38182
|
+
const lockDir = path24.dirname(lockPath);
|
|
37690
38183
|
const timeoutMs = options.timeoutMs ?? DESKTOP_INSTALL_LOCK_TIMEOUT_MS;
|
|
37691
38184
|
const pollMs = options.pollMs ?? DESKTOP_INSTALL_LOCK_POLL_MS;
|
|
37692
38185
|
const startedAt = Date.now();
|
|
37693
38186
|
const payload = {
|
|
37694
38187
|
lockId: randomUUID(),
|
|
37695
38188
|
pid: process.pid,
|
|
37696
|
-
installRoot:
|
|
38189
|
+
installRoot: path24.resolve(paths.installRoot),
|
|
37697
38190
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
37698
38191
|
};
|
|
37699
38192
|
await mkdir3(lockDir, { recursive: true });
|
|
@@ -37769,7 +38262,7 @@ async function findPath(root, predicate, maxDepth = 5) {
|
|
|
37769
38262
|
async function visit(dir, depth) {
|
|
37770
38263
|
const entries = await readdir3(dir, { withFileTypes: true });
|
|
37771
38264
|
for (const entry of entries) {
|
|
37772
|
-
const fullPath =
|
|
38265
|
+
const fullPath = path24.join(dir, entry.name);
|
|
37773
38266
|
if (predicate(fullPath, entry.isDirectory())) return fullPath;
|
|
37774
38267
|
if (entry.isDirectory() && depth < maxDepth) {
|
|
37775
38268
|
const nested = await visit(fullPath, depth + 1);
|
|
@@ -37781,18 +38274,18 @@ async function findPath(root, predicate, maxDepth = 5) {
|
|
|
37781
38274
|
return await visit(root, 0);
|
|
37782
38275
|
}
|
|
37783
38276
|
async function findMacApp(extractDir) {
|
|
37784
|
-
const direct =
|
|
38277
|
+
const direct = path24.join(extractDir, `${DESKTOP_APP_NAME}.app`);
|
|
37785
38278
|
if (await pathExists2(direct)) return direct;
|
|
37786
|
-
const found = await findPath(extractDir, (filePath, isDirectory) => isDirectory &&
|
|
38279
|
+
const found = await findPath(extractDir, (filePath, isDirectory) => isDirectory && path24.basename(filePath) === `${DESKTOP_APP_NAME}.app`);
|
|
37787
38280
|
if (!found) throw new Error(`Portable macOS archive did not contain ${DESKTOP_APP_NAME}.app.`);
|
|
37788
38281
|
return found;
|
|
37789
38282
|
}
|
|
37790
38283
|
async function findWindowsAppDir(extractDir) {
|
|
37791
|
-
const direct =
|
|
38284
|
+
const direct = path24.join(extractDir, `${DESKTOP_APP_NAME}.exe`);
|
|
37792
38285
|
if (await pathExists2(direct)) return extractDir;
|
|
37793
|
-
const executable = await findPath(extractDir, (filePath, isDirectory) => !isDirectory &&
|
|
38286
|
+
const executable = await findPath(extractDir, (filePath, isDirectory) => !isDirectory && path24.basename(filePath).toLowerCase() === `${DESKTOP_APP_NAME.toLowerCase()}.exe`);
|
|
37794
38287
|
if (!executable) throw new Error(`Portable Windows archive did not contain ${DESKTOP_APP_NAME}.exe.`);
|
|
37795
|
-
return
|
|
38288
|
+
return path24.dirname(executable);
|
|
37796
38289
|
}
|
|
37797
38290
|
async function readInstallMetadata(metadataPath) {
|
|
37798
38291
|
try {
|
|
@@ -37848,6 +38341,11 @@ function findDesktopExecutablePids(executablePath, target) {
|
|
|
37848
38341
|
return matchesExecutable && pid !== process.pid ? [pid] : [];
|
|
37849
38342
|
});
|
|
37850
38343
|
}
|
|
38344
|
+
function desktopApplicationEnvironment() {
|
|
38345
|
+
const env = { ...process.env };
|
|
38346
|
+
delete env.ELECTRON_RUN_AS_NODE;
|
|
38347
|
+
return env;
|
|
38348
|
+
}
|
|
37851
38349
|
async function waitForUpdateQuitResponse(responsePath, timeoutMs = 8e3) {
|
|
37852
38350
|
const startedAt = Date.now();
|
|
37853
38351
|
while (Date.now() - startedAt < timeoutMs) {
|
|
@@ -37860,11 +38358,12 @@ async function waitForUpdateQuitResponse(responsePath, timeoutMs = 8e3) {
|
|
|
37860
38358
|
}
|
|
37861
38359
|
async function requestDesktopQuit(executablePath, target, options = {}) {
|
|
37862
38360
|
if (!await pathExists2(executablePath)) return { ok: true, status: "not_running" };
|
|
37863
|
-
const responsePath =
|
|
38361
|
+
const responsePath = path24.join(tmpdir(), `rudder-update-quit-${process.pid}-${Date.now()}.json`);
|
|
37864
38362
|
const result = spawnSync4(executablePath, [
|
|
37865
38363
|
`${DESKTOP_UPDATE_QUIT_ARG}=${responsePath}`,
|
|
37866
38364
|
...options.forceUpdate ? [DESKTOP_UPDATE_FORCE_ARG] : []
|
|
37867
38365
|
], {
|
|
38366
|
+
env: desktopApplicationEnvironment(),
|
|
37868
38367
|
stdio: "ignore",
|
|
37869
38368
|
timeout: 5e3
|
|
37870
38369
|
});
|
|
@@ -38024,7 +38523,7 @@ async function installPortableDesktop(installerPath, paths, target) {
|
|
|
38024
38523
|
await chmod2(paths.appPath, 493);
|
|
38025
38524
|
return;
|
|
38026
38525
|
}
|
|
38027
|
-
const extractDir = await mkdtemp2(
|
|
38526
|
+
const extractDir = await mkdtemp2(path24.join(tmpdir(), "rudder-desktop-extract."));
|
|
38028
38527
|
try {
|
|
38029
38528
|
await extractZip(installerPath, extractDir, target);
|
|
38030
38529
|
if (target.platform === "macos") {
|
|
@@ -38033,7 +38532,7 @@ async function installPortableDesktop(installerPath, paths, target) {
|
|
|
38033
38532
|
return;
|
|
38034
38533
|
}
|
|
38035
38534
|
const appSource = await findWindowsAppDir(extractDir);
|
|
38036
|
-
await mkdir3(
|
|
38535
|
+
await mkdir3(path24.dirname(paths.installRoot), { recursive: true });
|
|
38037
38536
|
await copyPortableAppBundle(appSource, paths.installRoot);
|
|
38038
38537
|
} finally {
|
|
38039
38538
|
await rm3(extractDir, { recursive: true, force: true });
|
|
@@ -38074,12 +38573,12 @@ function buildLinuxDesktopEntry(executablePath) {
|
|
|
38074
38573
|
].join("\n");
|
|
38075
38574
|
}
|
|
38076
38575
|
async function writeLinuxLaunchers(paths) {
|
|
38077
|
-
const desktopDir =
|
|
38576
|
+
const desktopDir = path24.join(homedir(), ".local", "share", "applications");
|
|
38078
38577
|
await mkdir3(desktopDir, { recursive: true });
|
|
38079
|
-
await writeFile3(
|
|
38080
|
-
const binDir =
|
|
38578
|
+
await writeFile3(path24.join(desktopDir, "rudder.desktop"), buildLinuxDesktopEntry(paths.executablePath), "utf8");
|
|
38579
|
+
const binDir = path24.join(homedir(), ".local", "bin");
|
|
38081
38580
|
await mkdir3(binDir, { recursive: true });
|
|
38082
|
-
const wrapperPath =
|
|
38581
|
+
const wrapperPath = path24.join(binDir, "rudder-desktop");
|
|
38083
38582
|
const escaped = paths.executablePath.replaceAll("'", `'"'"'`);
|
|
38084
38583
|
await writeFile3(wrapperPath, `#!/bin/sh
|
|
38085
38584
|
exec '${escaped}' "$@"
|
|
@@ -38087,13 +38586,13 @@ exec '${escaped}' "$@"
|
|
|
38087
38586
|
await chmod2(wrapperPath, 493);
|
|
38088
38587
|
}
|
|
38089
38588
|
function buildWindowsShortcutScript(executablePath) {
|
|
38090
|
-
const appData = process.env.APPDATA?.trim() ||
|
|
38091
|
-
const shortcutPath =
|
|
38589
|
+
const appData = process.env.APPDATA?.trim() || path24.join(homedir(), "AppData", "Roaming");
|
|
38590
|
+
const shortcutPath = path24.join(appData, "Microsoft", "Windows", "Start Menu", "Programs", "Rudder.lnk");
|
|
38092
38591
|
return [
|
|
38093
38592
|
"$shell = New-Object -ComObject WScript.Shell",
|
|
38094
38593
|
`$shortcut = $shell.CreateShortcut(${powershellQuote(shortcutPath)})`,
|
|
38095
38594
|
`$shortcut.TargetPath = ${powershellQuote(executablePath)}`,
|
|
38096
|
-
`$shortcut.WorkingDirectory = ${powershellQuote(
|
|
38595
|
+
`$shortcut.WorkingDirectory = ${powershellQuote(path24.dirname(executablePath))}`,
|
|
38097
38596
|
"$shortcut.Save()"
|
|
38098
38597
|
].join("; ");
|
|
38099
38598
|
}
|
|
@@ -38125,7 +38624,7 @@ function launchDesktop(paths, target) {
|
|
|
38125
38624
|
spawn3(paths.executablePath, [], { detached: true, stdio: "ignore" }).unref();
|
|
38126
38625
|
}
|
|
38127
38626
|
async function writeInstallMetadata(paths, releaseTag, assetName, assetChecksum, assetKind = "full") {
|
|
38128
|
-
mkdirSync2(
|
|
38627
|
+
mkdirSync2(path24.dirname(paths.metadataPath), { recursive: true });
|
|
38129
38628
|
const metadata = {
|
|
38130
38629
|
version: 1,
|
|
38131
38630
|
releaseTag,
|
|
@@ -38181,7 +38680,7 @@ async function startCommand(opts) {
|
|
|
38181
38680
|
if (!exactDesktopAssetPath || !exactDesktopAssetChecksum || !exactDesktopAssetName || !exactDesktopReleaseDigest) {
|
|
38182
38681
|
throw new Error("Exact Desktop asset mode requires path, checksum, asset name, and release digest.");
|
|
38183
38682
|
}
|
|
38184
|
-
if (!
|
|
38683
|
+
if (!path24.isAbsolute(exactDesktopAssetPath) || exactDesktopAssetName.includes("/") || !/^[a-f0-9]{64}$/iu.test(exactDesktopAssetChecksum) || !/^[a-f0-9]{64}$/iu.test(exactDesktopReleaseDigest)) {
|
|
38185
38684
|
throw new Error("Exact Desktop asset mode received invalid candidate identity.");
|
|
38186
38685
|
}
|
|
38187
38686
|
if (opts.desktopAssetKind && opts.desktopAssetKind !== "full" && opts.desktopAssetKind !== "shell") {
|
|
@@ -38295,9 +38794,9 @@ async function startCommand(opts) {
|
|
|
38295
38794
|
const smokeReleaseBaseUrls = resolveDesktopSmokeReleaseBaseUrls();
|
|
38296
38795
|
const target = resolveDesktopAssetTarget();
|
|
38297
38796
|
const tag = resolveDesktopReleaseTag(version);
|
|
38298
|
-
const installRoot = opts.desktopInstallDir ?
|
|
38797
|
+
const installRoot = opts.desktopInstallDir ? path24.resolve(opts.desktopInstallDir) : resolveDefaultDesktopInstallRoot(target);
|
|
38299
38798
|
const installPaths = resolveDesktopInstallPaths(target, installRoot);
|
|
38300
|
-
const outputDir = opts.outputDir ?
|
|
38799
|
+
const outputDir = opts.outputDir ? path24.resolve(opts.outputDir) : await mkdtemp2(path24.join(tmpdir(), "rudder-desktop-installer."));
|
|
38301
38800
|
p15.log.step("Installing desktop app");
|
|
38302
38801
|
p15.log.message(`Release: ${pc14.cyan(`${repo}@${tag}`)}`);
|
|
38303
38802
|
p15.log.message(`Target: ${pc14.cyan(`${target.platform}/${target.arch}`)}`);
|
|
@@ -38326,7 +38825,7 @@ async function startCommand(opts) {
|
|
|
38326
38825
|
};
|
|
38327
38826
|
selectedAssetKind = opts.desktopAssetKind ?? "full";
|
|
38328
38827
|
expectedChecksum = normalizeDesktopAssetChecksum(exactDesktopAssetChecksum);
|
|
38329
|
-
const computedReleaseDigest =
|
|
38828
|
+
const computedReleaseDigest = createHash5("sha256").update(JSON.stringify({
|
|
38330
38829
|
releaseTag,
|
|
38331
38830
|
assetName: selectedAsset.name,
|
|
38332
38831
|
assetChecksum: expectedChecksum,
|
|
@@ -38343,7 +38842,7 @@ async function startCommand(opts) {
|
|
|
38343
38842
|
if (linkDescriptor.isSymbolicLink()) throw new Error("Exact Desktop asset must not be a symbolic link.");
|
|
38344
38843
|
const checksum = await runStartPhase(
|
|
38345
38844
|
"Verifying staged Desktop checksum...",
|
|
38346
|
-
`Verified ${pc14.cyan(
|
|
38845
|
+
`Verified ${pc14.cyan(path24.basename(exactDesktopAssetPath))}.`,
|
|
38347
38846
|
() => assertChecksumMatch(exactDesktopAssetPath, expectedChecksum),
|
|
38348
38847
|
desktopProgressJson ? "verifying_checksum" : null
|
|
38349
38848
|
);
|
|
@@ -38462,7 +38961,7 @@ async function startCommand(opts) {
|
|
|
38462
38961
|
}
|
|
38463
38962
|
const checksum = await runStartPhase(
|
|
38464
38963
|
"Verifying Desktop checksum...",
|
|
38465
|
-
`Verified ${pc14.cyan(
|
|
38964
|
+
`Verified ${pc14.cyan(path24.basename(verifiedAsset.path))}.`,
|
|
38466
38965
|
() => assertChecksumMatch(verifiedAsset.path, expectedChecksum),
|
|
38467
38966
|
desktopProgressJson ? "verifying_checksum" : null
|
|
38468
38967
|
);
|
|
@@ -38474,9 +38973,9 @@ async function startCommand(opts) {
|
|
|
38474
38973
|
assetName: selectedAsset.name,
|
|
38475
38974
|
assetChecksum: checksum,
|
|
38476
38975
|
assetKind: selectedAssetKind,
|
|
38477
|
-
stagedArtifactPath:
|
|
38976
|
+
stagedArtifactPath: path24.resolve(verifiedAsset.path),
|
|
38478
38977
|
stagedArtifactDigest: checksum,
|
|
38479
|
-
releaseDigest:
|
|
38978
|
+
releaseDigest: createHash5("sha256").update(JSON.stringify({
|
|
38480
38979
|
releaseTag,
|
|
38481
38980
|
assetName: selectedAsset.name,
|
|
38482
38981
|
assetChecksum: checksum,
|
|
@@ -38490,12 +38989,12 @@ async function startCommand(opts) {
|
|
|
38490
38989
|
let applySignal = null;
|
|
38491
38990
|
let applySignalController = null;
|
|
38492
38991
|
if (desktopProgressJson && opts.desktopWaitForApply === true) {
|
|
38992
|
+
applySignalController = createDesktopApplySignalController();
|
|
38493
38993
|
writeDesktopProgress({
|
|
38494
38994
|
phase: "ready_to_install",
|
|
38495
38995
|
message: "Desktop update is downloaded and verified.",
|
|
38496
38996
|
percent: 100
|
|
38497
38997
|
});
|
|
38498
|
-
applySignalController = createDesktopApplySignalController();
|
|
38499
38998
|
applySignal = await applySignalController.waitForInitialSignal();
|
|
38500
38999
|
writeDesktopProgress({
|
|
38501
39000
|
phase: "preparing_restart",
|
|
@@ -38567,11 +39066,11 @@ async function startCommand(opts) {
|
|
|
38567
39066
|
|
|
38568
39067
|
// src/config/data-dir.ts
|
|
38569
39068
|
init_home();
|
|
38570
|
-
import
|
|
39069
|
+
import path25 from "node:path";
|
|
38571
39070
|
function applyDataDirOverride(options, support = {}) {
|
|
38572
39071
|
const rawDataDir = options.dataDir?.trim();
|
|
38573
39072
|
if (!rawDataDir) return null;
|
|
38574
|
-
const resolvedDataDir =
|
|
39073
|
+
const resolvedDataDir = path25.resolve(expandHomePrefix(rawDataDir));
|
|
38575
39074
|
process.env.RUDDER_HOME = resolvedDataDir;
|
|
38576
39075
|
if (support.hasConfigOption) {
|
|
38577
39076
|
const hasConfigOverride = Boolean(options.config?.trim()) || Boolean(process.env.RUDDER_CONFIG?.trim());
|