fix(prompting): preserved CLI prompt precedence over SYSTEM.md

Skip the secondary loadSystemPromptFiles capability walk when the caller already controls block 0 via customPrompt/resolvedCustomPrompt, so project/user SYSTEM.md cannot silently augment a CLI --system-prompt override.

Fixes #3014
This commit is contained in:
roboomp
2026-06-19 12:00:46 +00:00
parent 21f3496976
commit b4b11232e5
2 changed files with 36 additions and 3 deletions
+9 -3
View File
@@ -505,9 +505,15 @@ export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}):
return result.value;
}
const systemPromptCustomizationPromise = logger.time("loadSystemPromptFiles", loadSystemPromptFiles, {
cwd: resolvedCwd,
});
// Caller-supplied `customPrompt` / `resolvedCustomPrompt` owns block 0; the
// secondary capability-path `SYSTEM.md` walk-up MUST NOT silently augment it,
// because that would defeat CLI precedence over project/user `SYSTEM.md`.
const callerControlsCustomPrompt =
(typeof providedResolvedCustomPrompt === "string" && providedResolvedCustomPrompt.length > 0) ||
(typeof customPrompt === "string" && customPrompt.length > 0);
const systemPromptCustomizationPromise: Promise<string | null> = callerControlsCustomPrompt
? Promise.resolve(null)
: logger.time("loadSystemPromptFiles", loadSystemPromptFiles, { cwd: resolvedCwd });
const contextFilesPromise = providedContextFiles
? Promise.resolve(providedContextFiles)
: logger.time("loadProjectContextFiles", loadProjectContextFiles, { cwd: resolvedCwd });
@@ -106,6 +106,33 @@ describe("SYSTEM.md prompt assembly", () => {
expect(promptText).not.toContain("File content that must not replace the prompt.");
});
it("suppresses discovered SYSTEM.md when the caller supplies a custom prompt", async () => {
const projectDir = path.join(tempDir, "project");
fs.mkdirSync(path.join(projectDir, ".omp"), { recursive: true });
fs.writeFileSync(path.join(projectDir, ".omp", "SYSTEM.md"), "Discovered project SYSTEM prompt");
const { systemPrompt } = await buildSystemPrompt({
cwd: projectDir,
resolvedCustomPrompt: "CLI custom prompt",
contextFiles: [],
skills: [],
rules: [],
toolNames: ["read"],
tools: READ_TOOL,
workspaceTree: {
rootPath: projectDir,
rendered: "",
truncated: false,
totalLines: 0,
agentsMdFiles: [],
},
});
const promptText = systemPrompt.join("\n\n");
expect(promptText).toContain("CLI custom prompt");
expect(promptText).not.toContain("Discovered project SYSTEM prompt");
});
it("prefers project SYSTEM.md over user SYSTEM.md", async () => {
const projectDir = path.join(tempDir, "project");
fs.mkdirSync(path.join(projectDir, ".omp"), { recursive: true });