import assert from "node:assert/strict"; import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; import { tmpdir } from "node:os"; import { dirname, join, resolve } from "node:path"; import test from "node:test"; import { fileURLToPath } from "node:url"; import { readCoverFile, resolveCoverPath, spliceCover, } from "../extensions/system-prompt-cover-config.ts"; const repositoryRoot = resolve(dirname(fileURLToPath(import.meta.url)), ".."); const bundledCoverPath = join(repositoryRoot, "config", "system-prompt-cover.md"); const DEFAULT_PREAMBLE = "You are an expert coding assistant operating inside pi, a coding agent harness. " + "You help users by reading files, executing commands, editing code, and writing new files."; /** A rendered prompt shaped like Pi's: preamble, then tag-wrapped top-level sections. */ function renderedPrompt(preamble = DEFAULT_PREAMBLE) { return [ preamble, "", "- read: reads files", "", "", "- Be concise", "", "", "", " ", " s", " ", "", "", "", '', "Nested content with a -looking line is not a tag.", "", "", "", "/work", "", ].join("\n"); } function tagsOf(text: string): string[] { return [...text.matchAll(/^<([a-z][a-z0-9_-]*)>$/gm)].map((match) => match[1]); } async function makeTempDir() { return mkdtemp(join(tmpdir(), "my-pi-cover-")); } test("bundled cover holds Pi's default preamble text", async () => { const content = await readFile(bundledCoverPath, "utf8"); assert.equal(content.replace(/\s+$/, ""), DEFAULT_PREAMBLE); }); test("spliceCover replaces only the preamble and preserves the remaining bytes", () => { const rendered = renderedPrompt(); const spliced = spliceCover(rendered, "MY CUSTOM COVER"); assert.ok(spliced.startsWith("MY CUSTOM COVER\n")); // Everything after the preamble's terminating newline is untouched. const originalTail = rendered.slice(rendered.indexOf("\n")); assert.ok(spliced.endsWith(originalTail)); // Section order — including nested tags — is identical to the unmodified prompt. assert.deepEqual(tagsOf(spliced), tagsOf(rendered)); assert.deepEqual(tagsOf(spliced), [ "tools", "rules", "skills", "available_skills", "project_context", "cwd", ]); }); test("spliceCover keeps section order rather than appending recovered sections", () => { const rendered = renderedPrompt("ORIGINAL COVER"); const spliced = spliceCover(rendered, "NEW COVER"); const order = tagsOf(spliced).join(","); assert.equal(order, "tools,rules,skills,available_skills,project_context,cwd"); assert.ok( order.indexOf("tools") < order.indexOf("cwd"), "tools must still precede cwd; a re-appended section list would invert this", ); assert.ok( order.indexOf("project_context") < order.indexOf("cwd"), "project_context must keep its original position", ); }); test("spliceCover tolerates a trailing newline from the editor and a blank cover", () => { const rendered = renderedPrompt(); assert.equal(spliceCover(rendered, "COVER\n\n"), spliceCover(rendered, "COVER")); // A whitespace-only cover leaves an empty preamble but still keeps every section. const blank = spliceCover(rendered, " \n"); assert.equal(blank, rendered.slice(rendered.indexOf("\n"))); assert.deepEqual(tagsOf(blank), tagsOf(rendered)); }); test("spliceCover degenerates to the cover when the prompt has no sections", () => { assert.equal(spliceCover("just a preamble", "NEW"), "NEW"); assert.equal(spliceCover("", "NEW"), "NEW"); }); test("spliceCover keeps an attribute-bearing nested tag inside its parent section", () => { // Pi nests inside the bare tag, so the // boundary must be the first *bare* tag line and the nested markup must survive verbatim. const rendered = [ "ORIGINAL COVER", "", "- read: reads files", "", "", '', "nested instructions", "", "", "", "/work", "", ].join("\n"); const spliced = spliceCover(rendered, "NEW"); assert.equal(tagsOf(spliced).join(","), "tools,project_context,cwd"); assert.ok(spliced.startsWith("NEW\n")); assert.ok( spliced.includes('\nnested instructions\n'), "nested project instructions must be preserved byte-for-byte", ); }); test("resolveCoverPath points at the bundle config file", () => { assert.equal(resolveCoverPath(), bundledCoverPath); }); test("readCoverFile returns undefined when the file is absent or blank", async () => { const dir = await makeTempDir(); try { const coverPath = join(dir, "system-prompt-cover.md"); assert.equal(readCoverFile(coverPath), undefined); await writeFile(coverPath, " \n\n", "utf8"); assert.equal(readCoverFile(coverPath), undefined); await writeFile(coverPath, " REAL COVER \n", "utf8"); assert.equal(readCoverFile(coverPath), " REAL COVER"); } finally { await rm(dir, { recursive: true, force: true }); } });