@rudderhq/agent-runtime-utils 0.2.0-canary.9 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/git-identity.d.ts +32 -0
- package/dist/git-identity.d.ts.map +1 -0
- package/dist/git-identity.js +207 -0
- package/dist/git-identity.js.map +1 -0
- package/dist/git-identity.test.d.ts +2 -0
- package/dist/git-identity.test.d.ts.map +1 -0
- package/dist/git-identity.test.js +327 -0
- package/dist/git-identity.test.js.map +1 -0
- package/dist/server-utils.d.ts +28 -0
- package/dist/server-utils.d.ts.map +1 -1
- package/dist/server-utils.js +362 -21
- package/dist/server-utils.js.map +1 -1
- package/dist/server-utils.test.js +337 -9
- package/dist/server-utils.test.js.map +1 -1
- package/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/server-utils.d.ts
CHANGED
|
@@ -16,6 +16,11 @@ interface RunningProcess {
|
|
|
16
16
|
export declare const runningProcesses: Map<string, RunningProcess>;
|
|
17
17
|
export declare const MAX_CAPTURE_BYTES: number;
|
|
18
18
|
export declare const MAX_EXCERPT_BYTES: number;
|
|
19
|
+
type LocalCliCredentialShimCommand = {
|
|
20
|
+
command: string;
|
|
21
|
+
authCheckArgs?: readonly string[];
|
|
22
|
+
credentialEntries?: readonly string[];
|
|
23
|
+
};
|
|
19
24
|
export interface RudderSkillEntry {
|
|
20
25
|
key: string;
|
|
21
26
|
runtimeName: string;
|
|
@@ -78,6 +83,7 @@ export declare const DEFAULT_AGENT_PROMPT_TEMPLATE = "You are agent {{agent.id}}
|
|
|
78
83
|
export declare const ISSUE_ASSIGN_PROMPT_TEMPLATE = "You are agent {{agent.id}} ({{agent.name}}). You have been assigned to work on an issue.\n\n{{context.rudderWorkspace.orgResourcesPrompt}}\n\n## Task Context\n\n**Issue:** {{issue.title}}\n**ID:** {{issue.id}}\n**Status:** {{issue.status}}\n**Priority:** {{issue.priority}}\n\n**Description:**\n{{issue.description}}\n\n{{context.issueDocumentsPrompt}}\n\nYour task is to review this issue and begin working on it. Use the available tools to explore the codebase, understand the requirements, and implement a solution.";
|
|
79
84
|
export declare const COMMENT_MENTION_PROMPT_TEMPLATE = "You are agent {{agent.id}} ({{agent.name}}). You were mentioned in a comment and your attention is needed.\n\n{{context.rudderWorkspace.orgResourcesPrompt}}\n\n## Context\n\n**Issue:** {{issue.title}}\n**ID:** {{issue.id}}\n\n**Issue Description:**\n{{issue.description}}\n\n{{context.issueDocumentsPrompt}}\n\n**Comment:**\n{{comment.body}}\n\nPlease review the comment above and respond or take action as appropriate.";
|
|
80
85
|
export declare const ISSUE_COMMENTED_PROMPT_TEMPLATE = "You are agent {{agent.id}} ({{agent.name}}). There is a new comment on an issue you own.\n\n{{context.rudderWorkspace.orgResourcesPrompt}}\n\n## Context\n\n**Issue:** {{issue.title}}\n**ID:** {{issue.id}}\n**Status:** {{issue.status}}\n\n**Issue Description:**\n{{issue.description}}\n\n{{context.issueDocumentsPrompt}}\n\n**Latest Comment:**\n{{comment.body}}\n\nReview the new comment and continue the issue from the current state. Respond or take action as needed.";
|
|
86
|
+
export declare const ISSUE_CHANGES_REQUESTED_PROMPT_TEMPLATE = "You are agent {{agent.id}} ({{agent.name}}). A reviewer requested changes on an issue you own.\n\n{{context.rudderWorkspace.orgResourcesPrompt}}\n\n## Context\n\n**Issue:** {{issue.title}}\n**ID:** {{issue.id}}\n**Status:** {{issue.status}}\n\n**Issue Description:**\n{{issue.description}}\n\n{{context.issueDocumentsPrompt}}\n\n**Reviewer Comment:**\n{{comment.body}}\n\nReview the requested changes and continue the issue from the current state. Address the reviewer feedback before handing it back for review.";
|
|
81
87
|
export declare const ISSUE_RECOVERY_PROMPT_TEMPLATE = "You are agent {{agent.id}} ({{agent.name}}). This is a recovery run, not a fresh task.\n\n{{context.rudderWorkspace.orgResourcesPrompt}}\n\n## Recovery Context\n\n- Original Run ID: {{context.recovery.originalRunId}}\n- Failure Kind: {{context.recovery.failureKind}}\n- Failure Summary: {{context.recovery.failureSummary}}\n- Recovery Trigger: {{context.recovery.recoveryTrigger}}\n- Recovery Mode: {{context.recovery.recoveryMode}}\n\n## Current Issue Context\n\n- Issue: {{issue.title}}\n- ID: {{issue.id}}\n- Status: {{issue.status}}\n- Priority: {{issue.priority}}\n\n- Description:\n{{issue.description}}\n\n{{context.issueDocumentsPrompt}}\n\nBefore doing anything else, inspect what the previous run already completed and any side effects it may have caused. Continue the remaining work from the current state. Avoid blindly re-running the whole task.";
|
|
82
88
|
export declare const RECOVERY_PROMPT_TEMPLATE = "You are agent {{agent.id}} ({{agent.name}}). This is a recovery run, not a fresh task.\n\n{{context.rudderWorkspace.orgResourcesPrompt}}\n\n## Recovery Context\n\n- Original Run ID: {{context.recovery.originalRunId}}\n- Failure Kind: {{context.recovery.failureKind}}\n- Failure Summary: {{context.recovery.failureSummary}}\n- Recovery Trigger: {{context.recovery.recoveryTrigger}}\n- Recovery Mode: {{context.recovery.recoveryMode}}\n\nBefore doing anything else, inspect what the previous run already completed and any side effects it may have caused. Continue the remaining work from the current state. Avoid blindly re-running the whole task.";
|
|
83
89
|
export declare const ISSUE_PASSIVE_FOLLOWUP_PROMPT_TEMPLATE = "You are agent {{agent.id}} ({{agent.name}}). This is a passive issue follow-up, not a fresh assignment and not a failure recovery.\n\n{{context.rudderWorkspace.orgResourcesPrompt}}\n\n## Why You Were Woken\n\nThe previous run ended without sufficient issue close-out.\n\n- Origin Run ID: {{context.passiveFollowup.originRunId}}\n- Previous Run ID: {{context.passiveFollowup.previousRunId}}\n- Attempt: {{context.passiveFollowup.attempt}} / {{context.passiveFollowup.maxAttempts}}\nReason: {{context.passiveFollowup.reason}}\n\n## Current Issue Context\n\n- Issue: {{issue.title}}\n- ID: {{issue.id}}\n- Status: {{issue.status}}\n- Priority: {{issue.priority}}\n\n- Description:\n{{issue.description}}\n\n{{context.issueDocumentsPrompt}}\n\nBefore changing the issue, inspect the current issue state and any side effects from the previous run. Then 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.";
|
|
@@ -91,6 +97,9 @@ export declare const ISSUE_PASSIVE_FOLLOWUP_PROMPT_TEMPLATE = "You are agent {{a
|
|
|
91
97
|
* - comment.mention:
|
|
92
98
|
* "You were mentioned in a comment ..."
|
|
93
99
|
* Includes issue summary plus mention comment body so the agent can respond without extra fetches.
|
|
100
|
+
* - issue_changes_requested:
|
|
101
|
+
* "A reviewer requested changes on an issue you own ..."
|
|
102
|
+
* Includes issue summary plus reviewer comment body so the assignee can act on feedback immediately.
|
|
94
103
|
* - issue_commented:
|
|
95
104
|
* "There is a new comment on an issue you own ..."
|
|
96
105
|
* Includes issue summary plus the newest comment body so the assignee can continue immediately.
|
|
@@ -170,6 +179,25 @@ export declare function resolveRudderDesiredSkillNames(config: Record<string, un
|
|
|
170
179
|
runtimeName?: string | null;
|
|
171
180
|
}>): string[];
|
|
172
181
|
export declare function writeRudderSkillSyncPreference(config: Record<string, unknown>, desiredSkills: string[]): Record<string, unknown>;
|
|
182
|
+
export declare function resolveLocalOperatorHome(sourceEnv?: NodeJS.ProcessEnv): string;
|
|
183
|
+
export declare function applyLocalCliHomeEnv(targetEnv: Record<string, string>, sourceEnv?: NodeJS.ProcessEnv): void;
|
|
184
|
+
export declare function syncLocalCliCredentialHomeEntries(input: {
|
|
185
|
+
sourceHome?: string | null;
|
|
186
|
+
targetHome: string;
|
|
187
|
+
entries?: readonly string[];
|
|
188
|
+
onLog?: ((stream: "stdout" | "stderr", chunk: string) => Promise<void>) | null;
|
|
189
|
+
}): Promise<{
|
|
190
|
+
linked: string[];
|
|
191
|
+
skipped: string[];
|
|
192
|
+
}>;
|
|
193
|
+
export declare function ensureLocalCliCredentialShimsInPath(input: {
|
|
194
|
+
operatorHome?: string | null;
|
|
195
|
+
targetHome: string;
|
|
196
|
+
env: NodeJS.ProcessEnv;
|
|
197
|
+
cwd?: string;
|
|
198
|
+
commands?: readonly (string | LocalCliCredentialShimCommand)[];
|
|
199
|
+
onLog?: ((stream: "stdout" | "stderr", chunk: string) => Promise<void>) | null;
|
|
200
|
+
}): Promise<NodeJS.ProcessEnv>;
|
|
173
201
|
export declare function ensureRudderSkillSymlink(source: string, target: string, linkSkill?: (source: string, target: string) => Promise<void>): Promise<"created" | "repaired" | "skipped">;
|
|
174
202
|
export declare function removeMaintainerOnlySkillSymlinks(skillsHome: string, allowedSkillNames: Iterable<string>): Promise<string[]>;
|
|
175
203
|
export declare function ensureCommandResolvable(command: string, cwd: string, env: NodeJS.ProcessEnv): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-utils.d.ts","sourceRoot":"","sources":["../src/server-utils.ts"],"names":[],"mappings":"AACA,OAAO,EAAS,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAI9D,OAAO,KAAK,EAEV,yBAAyB,EAC1B,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,UAAU,cAAc;IACtB,KAAK,EAAE,YAAY,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAeD,eAAO,MAAM,gBAAgB,6BAAoC,CAAC;AAclE,eAAO,MAAM,iBAAiB,QAAkB,CAAC;AACjD,eAAO,MAAM,iBAAiB,QAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"server-utils.d.ts","sourceRoot":"","sources":["../src/server-utils.ts"],"names":[],"mappings":"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"}
|
package/dist/server-utils.js
CHANGED
|
@@ -27,6 +27,38 @@ const RUDDER_SKILL_ROOT_RELATIVE_CANDIDATES = [
|
|
|
27
27
|
"../../skills",
|
|
28
28
|
"../../../../../server/resources/bundled-skills",
|
|
29
29
|
];
|
|
30
|
+
const DEFAULT_LOCAL_CLI_CREDENTIAL_HOME_ENTRIES = [
|
|
31
|
+
".aws",
|
|
32
|
+
".azure",
|
|
33
|
+
".config/gh",
|
|
34
|
+
".config/gcloud",
|
|
35
|
+
".config/op",
|
|
36
|
+
".config/vercel",
|
|
37
|
+
".config/configstore",
|
|
38
|
+
".docker",
|
|
39
|
+
".fly",
|
|
40
|
+
".git-credentials",
|
|
41
|
+
".gnupg",
|
|
42
|
+
".kube",
|
|
43
|
+
".netrc",
|
|
44
|
+
".npmrc",
|
|
45
|
+
".ssh",
|
|
46
|
+
".vercel",
|
|
47
|
+
"Library/Application Support/gh",
|
|
48
|
+
"Library/Application Support/com.heroku.cli",
|
|
49
|
+
];
|
|
50
|
+
const DEFAULT_LOCAL_CLI_OPERATOR_HOME_SHIM_COMMANDS = [
|
|
51
|
+
{
|
|
52
|
+
command: "gh",
|
|
53
|
+
authCheckArgs: ["auth", "status"],
|
|
54
|
+
credentialEntries: [".config/gh", "Library/Application Support/gh"],
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
command: "vercel",
|
|
58
|
+
authCheckArgs: ["whoami"],
|
|
59
|
+
credentialEntries: [".config/vercel", ".vercel", ".config/configstore"],
|
|
60
|
+
},
|
|
61
|
+
];
|
|
30
62
|
function normalizePathSlashes(value) {
|
|
31
63
|
return value.replaceAll("\\", "/");
|
|
32
64
|
}
|
|
@@ -277,6 +309,25 @@ export const ISSUE_COMMENTED_PROMPT_TEMPLATE = `You are agent {{agent.id}} ({{ag
|
|
|
277
309
|
{{comment.body}}
|
|
278
310
|
|
|
279
311
|
Review the new comment and continue the issue from the current state. Respond or take action as needed.`;
|
|
312
|
+
export const ISSUE_CHANGES_REQUESTED_PROMPT_TEMPLATE = `You are agent {{agent.id}} ({{agent.name}}). A reviewer requested changes on an issue you own.
|
|
313
|
+
|
|
314
|
+
{{context.rudderWorkspace.orgResourcesPrompt}}
|
|
315
|
+
|
|
316
|
+
## Context
|
|
317
|
+
|
|
318
|
+
**Issue:** {{issue.title}}
|
|
319
|
+
**ID:** {{issue.id}}
|
|
320
|
+
**Status:** {{issue.status}}
|
|
321
|
+
|
|
322
|
+
**Issue Description:**
|
|
323
|
+
{{issue.description}}
|
|
324
|
+
|
|
325
|
+
{{context.issueDocumentsPrompt}}
|
|
326
|
+
|
|
327
|
+
**Reviewer Comment:**
|
|
328
|
+
{{comment.body}}
|
|
329
|
+
|
|
330
|
+
Review the requested changes and continue the issue from the current state. Address the reviewer feedback before handing it back for review.`;
|
|
280
331
|
export const ISSUE_RECOVERY_PROMPT_TEMPLATE = `You are agent {{agent.id}} ({{agent.name}}). This is a recovery run, not a fresh task.
|
|
281
332
|
|
|
282
333
|
{{context.rudderWorkspace.orgResourcesPrompt}}
|
|
@@ -351,6 +402,9 @@ Before changing the issue, inspect the current issue state and any side effects
|
|
|
351
402
|
* - comment.mention:
|
|
352
403
|
* "You were mentioned in a comment ..."
|
|
353
404
|
* Includes issue summary plus mention comment body so the agent can respond without extra fetches.
|
|
405
|
+
* - issue_changes_requested:
|
|
406
|
+
* "A reviewer requested changes on an issue you own ..."
|
|
407
|
+
* Includes issue summary plus reviewer comment body so the assignee can act on feedback immediately.
|
|
354
408
|
* - issue_commented:
|
|
355
409
|
* "There is a new comment on an issue you own ..."
|
|
356
410
|
* Includes issue summary plus the newest comment body so the assignee can continue immediately.
|
|
@@ -399,6 +453,9 @@ export function selectPromptTemplate(configuredTemplate, context) {
|
|
|
399
453
|
if (wakeReason === "issue_passive_followup") {
|
|
400
454
|
return ISSUE_PASSIVE_FOLLOWUP_PROMPT_TEMPLATE;
|
|
401
455
|
}
|
|
456
|
+
if (wakeReason === "issue_changes_requested") {
|
|
457
|
+
return ISSUE_CHANGES_REQUESTED_PROMPT_TEMPLATE;
|
|
458
|
+
}
|
|
402
459
|
if (wakeSource === "assignment" || wakeReason === "issue_assigned") {
|
|
403
460
|
return ISSUE_ASSIGN_PROMPT_TEMPLATE;
|
|
404
461
|
}
|
|
@@ -430,10 +487,18 @@ export const RUDDER_AGENT_OPERATING_CONTRACT = [
|
|
|
430
487
|
"- Shared organization workspace root lives under `$RUDDER_ORG_WORKSPACE_ROOT`.",
|
|
431
488
|
"- Shared organization skills live under `$RUDDER_ORG_SKILLS_DIR`.",
|
|
432
489
|
"- Shared organization plans live under `$RUDDER_ORG_PLANS_DIR`.",
|
|
490
|
+
"- Shared organization artifacts live under `$RUDDER_ORG_ARTIFACTS_DIR`.",
|
|
491
|
+
"- Durable generated outputs such as screenshots, images, mockups, reports, CSVs, handoff logs, and other user-visible files should be written under `$RUDDER_ORG_ARTIFACTS_DIR` when available.",
|
|
492
|
+
"- Use `/tmp` only for transient scratch files and temporary verification artifacts; do not put durable work product there.",
|
|
493
|
+
"- Local trusted runtimes may expose the host operator home as `$RUDDER_OPERATOR_HOME`; use it only when a local skill or script intentionally needs operator-owned desktop app or CLI state. Do not replace `$HOME` with it.",
|
|
433
494
|
"- Durable shared work output should prefer these managed workspace paths instead of ad-hoc top-level `projects/` folders.",
|
|
434
495
|
"",
|
|
496
|
+
"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.",
|
|
497
|
+
"",
|
|
435
498
|
"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.",
|
|
436
499
|
"",
|
|
500
|
+
"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.",
|
|
501
|
+
"",
|
|
437
502
|
"## Memory and Planning",
|
|
438
503
|
"",
|
|
439
504
|
"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 plans. 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/planning conventions.",
|
|
@@ -447,9 +512,40 @@ export const RUDDER_AGENT_OPERATING_CONTRACT = [
|
|
|
447
512
|
"- Never exfiltrate secrets or private data.",
|
|
448
513
|
"- Do not perform any destructive commands unless explicitly requested by the board.",
|
|
449
514
|
].join("\n");
|
|
515
|
+
function toPromptPath(pathValue) {
|
|
516
|
+
return pathValue.split(path.sep).join("/");
|
|
517
|
+
}
|
|
518
|
+
function isInsidePath(parentPath, childPath) {
|
|
519
|
+
const relativePath = path.relative(parentPath, childPath);
|
|
520
|
+
return relativePath === "" || (!relativePath.startsWith("..") && !path.isAbsolute(relativePath));
|
|
521
|
+
}
|
|
522
|
+
function displayInstructionPath(filePath, instructionsFilePath) {
|
|
523
|
+
const resolvedFilePath = path.resolve(filePath);
|
|
524
|
+
const resolvedInstructionsPath = path.resolve(instructionsFilePath);
|
|
525
|
+
const instructionsDir = path.dirname(resolvedInstructionsPath);
|
|
526
|
+
if (path.basename(instructionsDir) === "instructions") {
|
|
527
|
+
const agentHome = path.dirname(instructionsDir);
|
|
528
|
+
if (isInsidePath(agentHome, resolvedFilePath)) {
|
|
529
|
+
const relativePath = path.relative(agentHome, resolvedFilePath);
|
|
530
|
+
return relativePath ? `$AGENT_HOME/${toPromptPath(relativePath)}` : "$AGENT_HOME";
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
return filePath;
|
|
534
|
+
}
|
|
535
|
+
function displayInstructionDir(filePath, instructionsFilePath) {
|
|
536
|
+
const displayPath = displayInstructionPath(filePath, instructionsFilePath);
|
|
537
|
+
const lastSlash = displayPath.lastIndexOf("/");
|
|
538
|
+
return lastSlash >= 0 ? `${displayPath.slice(0, lastSlash)}/` : "";
|
|
539
|
+
}
|
|
450
540
|
export async function loadAgentInstructionsPrefix(input) {
|
|
451
541
|
const instructionsFilePath = input.instructionsFilePath.trim();
|
|
452
542
|
const instructionsDir = instructionsFilePath ? `${path.dirname(instructionsFilePath)}/` : "";
|
|
543
|
+
const displayInstructionsFilePath = instructionsFilePath
|
|
544
|
+
? displayInstructionPath(instructionsFilePath, instructionsFilePath)
|
|
545
|
+
: "";
|
|
546
|
+
const displayInstructionsDir = instructionsFilePath
|
|
547
|
+
? displayInstructionDir(instructionsFilePath, instructionsFilePath)
|
|
548
|
+
: "";
|
|
453
549
|
const warningStream = input.warningStream ?? "stdout";
|
|
454
550
|
const operatingContractSection = `${RUDDER_AGENT_OPERATING_CONTRACT}\n\n` +
|
|
455
551
|
"The above Rudder agent operating contract was injected by Rudder at runtime.";
|
|
@@ -481,29 +577,31 @@ export async function loadAgentInstructionsPrefix(input) {
|
|
|
481
577
|
loadedPaths.add(path.resolve(instructionsFilePath));
|
|
482
578
|
entrySection =
|
|
483
579
|
`${instructionsContents}\n\n` +
|
|
484
|
-
`The above agent instructions were loaded from ${
|
|
485
|
-
`Resolve any relative file references from ${
|
|
486
|
-
await input.onLog("stdout", `[rudder] Loaded agent instructions file: ${
|
|
580
|
+
`The above agent instructions were loaded from ${displayInstructionsFilePath}. ` +
|
|
581
|
+
`Resolve any relative file references from ${displayInstructionsDir}.`;
|
|
582
|
+
await input.onLog("stdout", `[rudder] Loaded agent instructions file: ${displayInstructionsFilePath}\n`);
|
|
487
583
|
}
|
|
488
584
|
catch (err) {
|
|
489
585
|
const reason = err instanceof Error ? err.message : String(err);
|
|
490
586
|
await input.onLog(warningStream, `[rudder] Warning: could not read agent instructions file "${instructionsFilePath}": ${reason}\n`);
|
|
491
|
-
commandNotes.push(`Configured instructionsFilePath ${
|
|
587
|
+
commandNotes.push(`Configured instructionsFilePath ${displayInstructionsFilePath}, but file could not be read; continuing without injected instructions.`);
|
|
492
588
|
}
|
|
493
589
|
async function loadSiblingInstructionFile(siblingInput) {
|
|
494
590
|
const filePath = path.join(path.dirname(instructionsFilePath), siblingInput.fileName);
|
|
495
591
|
const resolvedPath = path.resolve(filePath);
|
|
592
|
+
const displayFilePath = displayInstructionPath(filePath, instructionsFilePath);
|
|
593
|
+
const displayFileDir = displayInstructionDir(filePath, instructionsFilePath);
|
|
496
594
|
if (loadedPaths.has(resolvedPath))
|
|
497
595
|
return { path: filePath, section: "" };
|
|
498
596
|
try {
|
|
499
597
|
const contents = await fs.readFile(filePath, "utf8");
|
|
500
598
|
loadedPaths.add(resolvedPath);
|
|
501
|
-
await input.onLog("stdout", `[rudder] Loaded ${siblingInput.logLabel}: ${
|
|
599
|
+
await input.onLog("stdout", `[rudder] Loaded ${siblingInput.logLabel}: ${displayFilePath}\n`);
|
|
502
600
|
return {
|
|
503
601
|
path: filePath,
|
|
504
602
|
section: `${contents}\n\n` +
|
|
505
|
-
`The above ${siblingInput.label} were loaded from ${
|
|
506
|
-
`Resolve any relative file references from ${
|
|
603
|
+
`The above ${siblingInput.label} were loaded from ${displayFilePath}. ` +
|
|
604
|
+
`Resolve any relative file references from ${displayFileDir}.`,
|
|
507
605
|
};
|
|
508
606
|
}
|
|
509
607
|
catch (err) {
|
|
@@ -519,26 +617,29 @@ export async function loadAgentInstructionsPrefix(input) {
|
|
|
519
617
|
label: "agent role and persona instructions",
|
|
520
618
|
logLabel: "agent soul instructions file",
|
|
521
619
|
});
|
|
522
|
-
if (soul.section)
|
|
523
|
-
commandNotes.push(`Loaded agent soul instructions from ${soul.path}`);
|
|
620
|
+
if (soul.section && soul.path) {
|
|
621
|
+
commandNotes.push(`Loaded agent soul instructions from ${displayInstructionPath(soul.path, instructionsFilePath)}`);
|
|
622
|
+
}
|
|
524
623
|
const tools = await loadSiblingInstructionFile({
|
|
525
624
|
fileName: "TOOLS.md",
|
|
526
625
|
label: "agent tool notes",
|
|
527
626
|
logLabel: "agent tool notes file",
|
|
528
627
|
});
|
|
529
|
-
if (tools.section)
|
|
530
|
-
commandNotes.push(`Loaded agent tool notes from ${tools.path}`);
|
|
628
|
+
if (tools.section && tools.path) {
|
|
629
|
+
commandNotes.push(`Loaded agent tool notes from ${displayInstructionPath(tools.path, instructionsFilePath)}`);
|
|
630
|
+
}
|
|
531
631
|
const memory = await loadSiblingInstructionFile({
|
|
532
632
|
fileName: "MEMORY.md",
|
|
533
633
|
label: "agent memory instructions",
|
|
534
634
|
logLabel: "agent memory instructions file",
|
|
535
635
|
});
|
|
536
|
-
if (memory.section)
|
|
537
|
-
commandNotes.push(`Loaded agent memory instructions from ${memory.path}`);
|
|
636
|
+
if (memory.section && memory.path) {
|
|
637
|
+
commandNotes.push(`Loaded agent memory instructions from ${displayInstructionPath(memory.path, instructionsFilePath)}`);
|
|
638
|
+
}
|
|
538
639
|
const memoryFilePath = memory.section ? memory.path : null;
|
|
539
640
|
const memorySection = memory.section;
|
|
540
641
|
if (entrySection)
|
|
541
|
-
commandNotes.splice(1, 0, `Loaded agent instructions from ${
|
|
642
|
+
commandNotes.splice(1, 0, `Loaded agent instructions from ${displayInstructionsFilePath}`);
|
|
542
643
|
const prefix = joinPromptSections([operatingContractSection, entrySection, soul.section, tools.section, memorySection]);
|
|
543
644
|
return {
|
|
544
645
|
prefix,
|
|
@@ -603,6 +704,15 @@ async function pathExists(candidate) {
|
|
|
603
704
|
return false;
|
|
604
705
|
}
|
|
605
706
|
}
|
|
707
|
+
async function fileExists(candidate) {
|
|
708
|
+
try {
|
|
709
|
+
await fs.access(candidate, fsConstants.F_OK);
|
|
710
|
+
return true;
|
|
711
|
+
}
|
|
712
|
+
catch {
|
|
713
|
+
return false;
|
|
714
|
+
}
|
|
715
|
+
}
|
|
606
716
|
async function resolveCommandPath(command, cwd, env) {
|
|
607
717
|
const hasPathSeparator = command.includes("/") || command.includes("\\");
|
|
608
718
|
if (hasPathSeparator) {
|
|
@@ -673,7 +783,7 @@ async function findAncestorWithFile(startDir, relativePath, maxDepth = 12) {
|
|
|
673
783
|
let current = path.resolve(startDir);
|
|
674
784
|
for (let depth = 0; depth <= maxDepth; depth += 1) {
|
|
675
785
|
const candidate = path.join(current, relativePath);
|
|
676
|
-
if (await
|
|
786
|
+
if (await fileExists(candidate))
|
|
677
787
|
return candidate;
|
|
678
788
|
const parent = path.dirname(current);
|
|
679
789
|
if (parent === current)
|
|
@@ -699,14 +809,14 @@ async function resolveRudderCliShimTarget(moduleDir) {
|
|
|
699
809
|
const rootDir = path.dirname(path.dirname(path.dirname(repoRoot)));
|
|
700
810
|
const tsxEntry = path.join(rootDir, "cli", "node_modules", "tsx", "dist", "cli.mjs");
|
|
701
811
|
const cliSource = path.join(rootDir, "cli", "src", "index.ts");
|
|
702
|
-
if (await
|
|
812
|
+
if (await fileExists(tsxEntry)) {
|
|
703
813
|
return {
|
|
704
814
|
command: process.execPath,
|
|
705
815
|
args: [tsxEntry, cliSource],
|
|
706
816
|
};
|
|
707
817
|
}
|
|
708
818
|
const builtCliEntry = path.join(rootDir, "cli", "dist", "index.js");
|
|
709
|
-
if (await
|
|
819
|
+
if (await fileExists(builtCliEntry)) {
|
|
710
820
|
return {
|
|
711
821
|
command: process.execPath,
|
|
712
822
|
args: [builtCliEntry],
|
|
@@ -735,10 +845,6 @@ async function materializeRudderCliShim(target) {
|
|
|
735
845
|
}
|
|
736
846
|
export async function ensureRudderCliInPath(moduleDir, env) {
|
|
737
847
|
const normalized = ensurePathInEnv(env);
|
|
738
|
-
const cwd = process.cwd();
|
|
739
|
-
if (await resolveCommandPath("rudder", cwd, normalized)) {
|
|
740
|
-
return normalized;
|
|
741
|
-
}
|
|
742
848
|
const target = await resolveRudderCliShimTarget(moduleDir);
|
|
743
849
|
if (!target) {
|
|
744
850
|
return normalized;
|
|
@@ -1013,6 +1119,230 @@ export function writeRudderSkillSyncPreference(config, desiredSkills) {
|
|
|
1013
1119
|
next.rudderSkillSync = current;
|
|
1014
1120
|
return next;
|
|
1015
1121
|
}
|
|
1122
|
+
function nonEmptyEnvPath(value) {
|
|
1123
|
+
return typeof value === "string" && value.trim().length > 0 ? path.resolve(value.trim()) : null;
|
|
1124
|
+
}
|
|
1125
|
+
export function resolveLocalOperatorHome(sourceEnv = process.env) {
|
|
1126
|
+
return (nonEmptyEnvPath(sourceEnv.RUDDER_OPERATOR_HOME)
|
|
1127
|
+
?? nonEmptyEnvPath(process.env.RUDDER_OPERATOR_HOME)
|
|
1128
|
+
?? nonEmptyEnvPath(process.env.HOME)
|
|
1129
|
+
?? nonEmptyEnvPath(sourceEnv.HOME)
|
|
1130
|
+
?? path.resolve(os.homedir()));
|
|
1131
|
+
}
|
|
1132
|
+
export function applyLocalCliHomeEnv(targetEnv, sourceEnv = process.env) {
|
|
1133
|
+
const home = nonEmptyEnvPath(sourceEnv.HOME) ?? path.resolve(os.homedir());
|
|
1134
|
+
targetEnv.HOME = home;
|
|
1135
|
+
const userProfile = nonEmptyEnvPath(sourceEnv.USERPROFILE);
|
|
1136
|
+
if (userProfile) {
|
|
1137
|
+
targetEnv.USERPROFILE = userProfile;
|
|
1138
|
+
}
|
|
1139
|
+
else if (process.platform === "win32") {
|
|
1140
|
+
targetEnv.USERPROFILE = home;
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
async function localCliPathExists(candidate) {
|
|
1144
|
+
return fs.access(candidate).then(() => true).catch(() => false);
|
|
1145
|
+
}
|
|
1146
|
+
async function directoryIsEmpty(target) {
|
|
1147
|
+
const entries = await fs.readdir(target).catch(() => null);
|
|
1148
|
+
return Array.isArray(entries) && entries.length === 0;
|
|
1149
|
+
}
|
|
1150
|
+
async function ensureSymlinkToSource(target, source) {
|
|
1151
|
+
const existing = await fs.lstat(target).catch(() => null);
|
|
1152
|
+
if (!existing) {
|
|
1153
|
+
await fs.mkdir(path.dirname(target), { recursive: true });
|
|
1154
|
+
await fs.symlink(source, target);
|
|
1155
|
+
return "created";
|
|
1156
|
+
}
|
|
1157
|
+
if (!existing.isSymbolicLink()) {
|
|
1158
|
+
if (existing.isDirectory() && await directoryIsEmpty(target)) {
|
|
1159
|
+
await fs.rmdir(target);
|
|
1160
|
+
await fs.symlink(source, target);
|
|
1161
|
+
return "repaired";
|
|
1162
|
+
}
|
|
1163
|
+
return "skipped";
|
|
1164
|
+
}
|
|
1165
|
+
const linkedPath = await fs.readlink(target).catch(() => null);
|
|
1166
|
+
if (!linkedPath)
|
|
1167
|
+
return "skipped";
|
|
1168
|
+
const resolvedLinkedPath = path.isAbsolute(linkedPath)
|
|
1169
|
+
? linkedPath
|
|
1170
|
+
: path.resolve(path.dirname(target), linkedPath);
|
|
1171
|
+
if (resolvedLinkedPath === source)
|
|
1172
|
+
return "skipped";
|
|
1173
|
+
await fs.unlink(target);
|
|
1174
|
+
await fs.symlink(source, target);
|
|
1175
|
+
return "repaired";
|
|
1176
|
+
}
|
|
1177
|
+
export async function syncLocalCliCredentialHomeEntries(input) {
|
|
1178
|
+
const sourceHome = nonEmptyEnvPath(input.sourceHome ?? undefined) ?? path.resolve(os.homedir());
|
|
1179
|
+
const targetHome = path.resolve(input.targetHome);
|
|
1180
|
+
const linked = [];
|
|
1181
|
+
const skipped = [];
|
|
1182
|
+
if (sourceHome === targetHome)
|
|
1183
|
+
return { linked, skipped };
|
|
1184
|
+
const entries = input.entries ?? DEFAULT_LOCAL_CLI_CREDENTIAL_HOME_ENTRIES;
|
|
1185
|
+
for (const relativeEntry of entries) {
|
|
1186
|
+
const source = path.join(sourceHome, relativeEntry);
|
|
1187
|
+
if (!(await localCliPathExists(source)))
|
|
1188
|
+
continue;
|
|
1189
|
+
const target = path.join(targetHome, relativeEntry);
|
|
1190
|
+
try {
|
|
1191
|
+
const result = await ensureSymlinkToSource(target, source);
|
|
1192
|
+
if (result === "skipped")
|
|
1193
|
+
skipped.push(relativeEntry);
|
|
1194
|
+
else
|
|
1195
|
+
linked.push(relativeEntry);
|
|
1196
|
+
}
|
|
1197
|
+
catch {
|
|
1198
|
+
skipped.push(relativeEntry);
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
if (input.onLog && linked.length > 0) {
|
|
1202
|
+
await input.onLog("stdout", `[rudder] Shared ${linked.length} local CLI credential entr${linked.length === 1 ? "y" : "ies"} into managed HOME ${targetHome}: ${linked.join(", ")}\n`);
|
|
1203
|
+
}
|
|
1204
|
+
return { linked, skipped };
|
|
1205
|
+
}
|
|
1206
|
+
async function writeOperatorHomeShim(input) {
|
|
1207
|
+
await fs.mkdir(input.shimDir, { recursive: true });
|
|
1208
|
+
if (process.platform === "win32") {
|
|
1209
|
+
const shimPath = path.join(input.shimDir, `${input.command}.cmd`);
|
|
1210
|
+
const lines = [
|
|
1211
|
+
"@echo off",
|
|
1212
|
+
`set "HOME=${input.operatorHome}"`,
|
|
1213
|
+
`set "USERPROFILE=${input.operatorHome}"`,
|
|
1214
|
+
`${quoteForCmd(input.targetCommand)} %*`,
|
|
1215
|
+
"",
|
|
1216
|
+
];
|
|
1217
|
+
await fs.writeFile(shimPath, lines.join("\r\n"), "utf8");
|
|
1218
|
+
return shimPath;
|
|
1219
|
+
}
|
|
1220
|
+
const shimPath = path.join(input.shimDir, input.command);
|
|
1221
|
+
await fs.writeFile(shimPath, [
|
|
1222
|
+
"#!/bin/sh",
|
|
1223
|
+
`export HOME=${shellQuote(input.operatorHome)}`,
|
|
1224
|
+
`export USERPROFILE=${shellQuote(input.operatorHome)}`,
|
|
1225
|
+
`exec ${shellQuote(input.targetCommand)} "$@"`,
|
|
1226
|
+
"",
|
|
1227
|
+
].join("\n"), "utf8");
|
|
1228
|
+
await fs.chmod(shimPath, 0o755);
|
|
1229
|
+
return shimPath;
|
|
1230
|
+
}
|
|
1231
|
+
function normalizeShimCommand(input) {
|
|
1232
|
+
return typeof input === "string" ? { command: input } : input;
|
|
1233
|
+
}
|
|
1234
|
+
async function runCredentialShimAuthCheck(input) {
|
|
1235
|
+
const env = {
|
|
1236
|
+
...input.env,
|
|
1237
|
+
HOME: input.home,
|
|
1238
|
+
USERPROFILE: input.home,
|
|
1239
|
+
};
|
|
1240
|
+
return await new Promise((resolve) => {
|
|
1241
|
+
const child = spawn(input.targetCommand, [...input.args], {
|
|
1242
|
+
cwd: input.cwd,
|
|
1243
|
+
env,
|
|
1244
|
+
stdio: ["ignore", "ignore", "ignore"],
|
|
1245
|
+
});
|
|
1246
|
+
const timeout = setTimeout(() => {
|
|
1247
|
+
child.kill("SIGTERM");
|
|
1248
|
+
resolve(false);
|
|
1249
|
+
}, 1000);
|
|
1250
|
+
child.on("error", () => {
|
|
1251
|
+
clearTimeout(timeout);
|
|
1252
|
+
resolve(false);
|
|
1253
|
+
});
|
|
1254
|
+
child.on("close", (code) => {
|
|
1255
|
+
clearTimeout(timeout);
|
|
1256
|
+
resolve(code === 0);
|
|
1257
|
+
});
|
|
1258
|
+
});
|
|
1259
|
+
}
|
|
1260
|
+
async function credentialBridgeSatisfied(input) {
|
|
1261
|
+
for (const entry of input.entries) {
|
|
1262
|
+
const source = path.join(input.operatorHome, entry);
|
|
1263
|
+
const target = path.join(input.targetHome, entry);
|
|
1264
|
+
if (!(await localCliPathExists(source)) || !(await localCliPathExists(target)))
|
|
1265
|
+
continue;
|
|
1266
|
+
const [sourceRealpath, targetRealpath] = await Promise.all([
|
|
1267
|
+
fs.realpath(source).catch(() => null),
|
|
1268
|
+
fs.realpath(target).catch(() => null),
|
|
1269
|
+
]);
|
|
1270
|
+
if (sourceRealpath && targetRealpath && sourceRealpath === targetRealpath)
|
|
1271
|
+
return true;
|
|
1272
|
+
}
|
|
1273
|
+
return false;
|
|
1274
|
+
}
|
|
1275
|
+
async function shouldPrepareOperatorHomeShim(input) {
|
|
1276
|
+
const authCheckArgs = input.command.authCheckArgs;
|
|
1277
|
+
if (!authCheckArgs || authCheckArgs.length === 0)
|
|
1278
|
+
return true;
|
|
1279
|
+
if (input.command.credentialEntries && input.command.credentialEntries.length > 0) {
|
|
1280
|
+
const hasOperatorCredentialEntry = await Promise.all(input.command.credentialEntries.map((entry) => localCliPathExists(path.join(input.operatorHome, entry))));
|
|
1281
|
+
if (!hasOperatorCredentialEntry.some(Boolean))
|
|
1282
|
+
return false;
|
|
1283
|
+
if (await credentialBridgeSatisfied({
|
|
1284
|
+
operatorHome: input.operatorHome,
|
|
1285
|
+
targetHome: input.targetHome,
|
|
1286
|
+
entries: input.command.credentialEntries,
|
|
1287
|
+
})) {
|
|
1288
|
+
return false;
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1291
|
+
const managedHomeWorks = await runCredentialShimAuthCheck({
|
|
1292
|
+
targetCommand: input.targetCommand,
|
|
1293
|
+
args: authCheckArgs,
|
|
1294
|
+
cwd: input.cwd,
|
|
1295
|
+
env: input.env,
|
|
1296
|
+
home: input.targetHome,
|
|
1297
|
+
});
|
|
1298
|
+
if (managedHomeWorks)
|
|
1299
|
+
return false;
|
|
1300
|
+
return await runCredentialShimAuthCheck({
|
|
1301
|
+
targetCommand: input.targetCommand,
|
|
1302
|
+
args: authCheckArgs,
|
|
1303
|
+
cwd: input.cwd,
|
|
1304
|
+
env: input.env,
|
|
1305
|
+
home: input.operatorHome,
|
|
1306
|
+
});
|
|
1307
|
+
}
|
|
1308
|
+
export async function ensureLocalCliCredentialShimsInPath(input) {
|
|
1309
|
+
const operatorHome = nonEmptyEnvPath(input.operatorHome ?? undefined);
|
|
1310
|
+
const targetHome = nonEmptyEnvPath(input.targetHome);
|
|
1311
|
+
if (!operatorHome || !targetHome || operatorHome === targetHome) {
|
|
1312
|
+
return ensurePathInEnv(input.env);
|
|
1313
|
+
}
|
|
1314
|
+
const normalized = ensurePathInEnv(input.env);
|
|
1315
|
+
const cwd = input.cwd ?? process.cwd();
|
|
1316
|
+
const commands = input.commands ?? DEFAULT_LOCAL_CLI_OPERATOR_HOME_SHIM_COMMANDS;
|
|
1317
|
+
const shimDir = path.join(targetHome, ".rudder", "local-cli-shims");
|
|
1318
|
+
const prepared = [];
|
|
1319
|
+
for (const rawCommand of commands) {
|
|
1320
|
+
const command = normalizeShimCommand(rawCommand);
|
|
1321
|
+
const targetCommand = await resolveCommandPath(command.command, cwd, normalized);
|
|
1322
|
+
if (!targetCommand)
|
|
1323
|
+
continue;
|
|
1324
|
+
if (path.dirname(targetCommand) === shimDir)
|
|
1325
|
+
continue;
|
|
1326
|
+
if (!(await shouldPrepareOperatorHomeShim({
|
|
1327
|
+
command,
|
|
1328
|
+
targetCommand,
|
|
1329
|
+
cwd,
|
|
1330
|
+
env: normalized,
|
|
1331
|
+
targetHome,
|
|
1332
|
+
operatorHome,
|
|
1333
|
+
}))) {
|
|
1334
|
+
continue;
|
|
1335
|
+
}
|
|
1336
|
+
await writeOperatorHomeShim({ shimDir, command: command.command, targetCommand, operatorHome });
|
|
1337
|
+
prepared.push(command.command);
|
|
1338
|
+
}
|
|
1339
|
+
if (prepared.length === 0)
|
|
1340
|
+
return normalized;
|
|
1341
|
+
if (input.onLog) {
|
|
1342
|
+
await input.onLog("stdout", `[rudder] Prepared local CLI credential shim${prepared.length === 1 ? "" : "s"} for: ${prepared.join(", ")}\n`);
|
|
1343
|
+
}
|
|
1344
|
+
return prependPathEntry(normalized, shimDir);
|
|
1345
|
+
}
|
|
1016
1346
|
export async function ensureRudderSkillSymlink(source, target, linkSkill = (linkSource, linkTarget) => fs.symlink(linkSource, linkTarget)) {
|
|
1017
1347
|
const existing = await fs.lstat(target).catch(() => null);
|
|
1018
1348
|
if (!existing) {
|
|
@@ -1103,6 +1433,17 @@ export async function runChildProcess(runId, command, args, opts) {
|
|
|
1103
1433
|
for (const key of CLAUDE_CODE_NESTING_VARS) {
|
|
1104
1434
|
delete rawMerged[key];
|
|
1105
1435
|
}
|
|
1436
|
+
const GIT_IDENTITY_ENV_VARS = [
|
|
1437
|
+
"GIT_AUTHOR_NAME",
|
|
1438
|
+
"GIT_AUTHOR_EMAIL",
|
|
1439
|
+
"GIT_COMMITTER_NAME",
|
|
1440
|
+
"GIT_COMMITTER_EMAIL",
|
|
1441
|
+
];
|
|
1442
|
+
for (const key of GIT_IDENTITY_ENV_VARS) {
|
|
1443
|
+
if (rawMerged[key] === "" && !Object.prototype.hasOwnProperty.call(opts.env, key)) {
|
|
1444
|
+
delete rawMerged[key];
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1106
1447
|
// When Rudder isolates HOME for child agents, don't let zsh keep using the
|
|
1107
1448
|
// host user's startup dir via an inherited ZDOTDIR. That mismatch makes
|
|
1108
1449
|
// child `zsh -lc` invocations source the host `.zshenv` with the agent HOME.
|