fix(context-bill): a root container skips a nested skill reached through a directory link at any depth

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
garrytanandcapy-ai[bot] committed 2026-10-26 03:00:25 +00:00
1 parent c44548413d
commit b67d9f288f
2 files changed
+38 -5

No files matched your search

+12 -5
View File
@@ -284,7 +284,11 @@ export interface WalkedFile {
*
* With `skipNestedSkills`, a top-level subdirectory holding its own SKILL.md is
* not entered, so a container skill keeps the files it shares with a nested
* skill instead of losing them to whichever path sorted first.
* skill instead of losing them to whichever path sorted first. The root
* container also skips a nested skill reached through a directory link at any
* depth: discovery bills that skill on its own, and the plain walk this
* replaced never followed directory links, so counting it here too would bill
* it twice.
*
* Every directory is read through its realpath, so a lookup crosses at most
* one link however deep the lexical path runs: a chain of links never hits
@@ -301,8 +305,9 @@ export function walkMdFiles(dir: string, opts: { billedRoot?: string; skipNested
return out;
}
const seen = new Set<string>([rootReal]);
const container = rootReal === billedReal;
let entryCount = 0;
const walk = (current: string, currentReal: string) => {
const walk = (current: string, currentReal: string, viaLink: boolean) => {
let entries: fs.Dirent[];
try {
entries = fs.readdirSync(currentReal, { withFileTypes: true });
@@ -320,7 +325,9 @@ export function walkMdFiles(dir: string, opts: { billedRoot?: string; skipNested
} else if (
kind !== "dir" ||
fs.existsSync(path.join(viaReal, ".git")) ||
(opts.skipNestedSkills && current === dir && isFile(path.join(viaReal, "SKILL.md")))
(opts.skipNestedSkills &&
(current === dir || (container && (viaLink || e.isSymbolicLink()))) &&
isFile(path.join(viaReal, "SKILL.md")))
) {
continue;
}
@@ -347,10 +354,10 @@ export function walkMdFiles(dir: string, opts: { billedRoot?: string; skipNested
}
if (encloses(real, rootReal) || encloses(real, billedReal)) continue;
seen.add(real);
walk(p, real);
walk(p, real, viaLink || e.isSymbolicLink());
}
};
walk(dir, rootReal);
walk(dir, rootReal, false);
return out;
}
+26
View File
@@ -398,6 +398,32 @@ describe("upstream fix b: installed-tree layout (repo-checkout subdir skip)", ()
fs.rmSync(root, { recursive: true, force: true });
});
it("keeps a root container from billing a nested skill that a deeper directory link reaches", () => {
if (process.platform === "win32") return;
const root = fs.mkdtempSync(path.join(os.tmpdir(), "context-bill-container-deep-"));
fs.writeFileSync(path.join(root, "SKILL.md"), "---\nname: c\ndescription: d\n---\n# c\n");
fs.mkdirSync(path.join(root, "sub"));
fs.writeFileSync(path.join(root, "sub", "SKILL.md"), "---\nname: s\ndescription: d\n---\n# s\n");
fs.writeFileSync(path.join(root, "sub", "big.md"), "b".repeat(10_000));
fs.mkdirSync(path.join(root, "refs"));
fs.writeFileSync(path.join(root, "refs", "note.md"), "n");
fs.symlinkSync(path.join(root, "sub"), path.join(root, "refs", "alias"));
const outside = fs.mkdtempSync(path.join(os.tmpdir(), "context-bill-container-outside-"));
fs.mkdirSync(path.join(outside, "deep"));
fs.writeFileSync(path.join(outside, "deep", "SKILL.md"), "---\nname: o\ndescription: d\n---\n# o\n");
fs.writeFileSync(path.join(outside, "deep", "o.md"), "o".repeat(5_000));
fs.mkdirSync(path.join(root, "linked"));
fs.symlinkSync(outside, path.join(root, "linked", "via"));
const bill = buildBill(root);
const byName = Object.fromEntries(bill.skills.map((s) => [s.name, s]));
fs.rmSync(root, { recursive: true, force: true });
fs.rmSync(outside, { recursive: true, force: true });
expect(Object.keys(byName).sort()).toEqual([path.basename(root), path.join("linked", "via", "deep"), path.join("refs", "alias"), "sub"].sort());
expect(byName[path.basename(root)].totalMdBytes).toBe("---\nname: c\ndescription: d\n---\n# c\n".length + 1);
expect(byName[path.join("refs", "alias")].totalMdBytes).toBe(byName.sub.totalMdBytes);
});
it("walks a chain of links deeper than the kernel's link limit without losing files", () => {
if (process.platform === "win32") return;
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "context-bill-deep-chain-"));