Compare commits

...
Author SHA1 Message Date
Brent Vatne 9a82ca82ae fix: keep the dot-dir and node_modules skips inside .expo-agents
The walk entered every child of .expo-agents/ without its usual skips, so
.expo-agents/.claude/worktrees/ checkouts and .expo-agents/node_modules/ setup
dirs were swept as scopes. It now walks .expo-agents/ with the same rules and
steps over the code-review/ child it already recorded. The test also runs
checkConfigRefs, so it shows the nested prompts are scanned.
2026-11-06 14:07:27 -07:00
Kudo Chien affb5cf6a9 fix: let ref-check sweep a scope config kept inside .expo-agents 2026-11-05 23:47:54 +08:00
3 changed files with 39 additions and 3 deletions

No files matched your search

+5 -1
View File
@@ -152,7 +152,11 @@ surface — the same reason `ecr verify-config` sweeps on disk instead of trusti
manifest ([LLP 0007][verify]). Inside a setup dir the scan covers prompts and configs
(`.md`, `.json`, `.jsonc`, `.txt`) and skips dot entries, so `.runs/` artifacts are never
scanned. Dot directories elsewhere are skipped too, which keeps `.claude/worktrees/`
checkouts of the same repo from being swept as if they were scopes.
checkouts of the same repo from being swept as if they were scopes. `.expo-agents/` is the
exception: besides its `code-review/` child, the walk enters its other children with the same
skips, so a scope that keeps its config at `.expo-agents/<scope>/.expo-agents/code-review/` is
swept, while `.expo-agents/.claude/` and `.expo-agents/node_modules/` are not
[observed: `discoverSetupDirs`].
## Run Points: Command and Review
+26
View File
@@ -388,6 +388,32 @@ test("scope setup dirs are swept too, and dot dirs (other worktrees) are not", a
);
});
test("a setup dir nested inside .expo-agents, such as a routed scope config, is swept", async () => {
const root = await makeRepo({
".expo-agents/code-review/agents/security.md": "# Security\n",
".expo-agents/autonomous-code-review/.expo-agents/code-review/agents/deep.md": `<!-- ${REF} src/gone.ts -->\n`,
// Dot dirs and node_modules under .expo-agents stay skipped, as at the root.
".expo-agents/.claude/worktrees/other/.expo-agents/code-review/agents/x.md": `<!-- ${REF} src/gone.ts -->\n`,
".expo-agents/node_modules/pkg/.expo-code-review/agents/y.md": `<!-- ${REF} src/gone.ts -->\n`,
});
const dirs = await discoverSetupDirs(root);
expect(dirs.map((d) => path.relative(root, d)).sort()).toEqual([
path.join(".expo-agents", "autonomous-code-review", ".expo-agents", "code-review"),
path.join(".expo-agents", "code-review"),
]);
const report = await checkConfigRefs({ root });
expect(report.problems.map((problem) => problem.file)).toEqual([
path.join(
".expo-agents",
"autonomous-code-review",
".expo-agents",
"code-review",
"agents",
"deep.md",
),
]);
});
test("one ref covers the prose form of the same citation", async () => {
const root = await makeRepo(
setup({
+8 -2
View File
@@ -537,7 +537,7 @@ async function listRepoFiles(root: string): Promise<string[]> {
*/
export async function discoverSetupDirs(root: string): Promise<string[]> {
const found: string[] = [];
async function walk(dir: string): Promise<void> {
async function walk(dir: string, setupInside?: string): Promise<void> {
let entries;
try {
entries = await readdir(dir, { withFileTypes: true });
@@ -549,16 +549,22 @@ export async function discoverSetupDirs(root: string): Promise<string[]> {
continue;
}
const child = path.join(dir, entry.name);
if (child === setupInside) {
continue; // already found, and a setup dir never nests another
}
if (entry.name === LEGACY_CONFIG_DIRNAME) {
found.push(child);
continue; // a setup dir never nests another
}
if (entry.name === ".expo-agents") {
// The shared Expo agent-tools dir: only its code-review/ child is ours.
// The shared Expo agent-tools dir: its code-review/ child is ours.
const setup = path.join(dir, CONFIG_DIRNAME);
if ((await pathKind(setup)) === "dir") {
found.push(setup);
}
// A routing scope may keep its config in another child, such as
// .expo-agents/<scope>/.expo-agents/code-review, so walk the other children too.
await walk(child, setup);
continue;
}
// Other dot dirs are skipped wholesale: `.claude/worktrees/` holds checkouts of