Skip to content

Commit 7316603

Browse files
test22345claude
andcommitted
fix(test): bash-syntax test catches unclosed fences and covers nested skills
Fable panel findings (CONFIRMED): (1) an unterminated ```bash fence at EOF — the exact garrytan#1667 typo class the test was built for — was silently dropped by the fence parser; it now throws. (2) discovery only scanned depth-1 dirs, skipping openclaw/skills/*/SKILL.md and browser-skills/*/SKILL.md, the hand-written files most likely to carry a typo. Bounded recursive walk (depth ≤ 3); 60 files covered, all pass. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent ad1b382 commit 7316603

1 file changed

Lines changed: 16 additions & 12 deletions

File tree

test/skill-bash-syntax.test.ts

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,20 +24,21 @@ const ROOT = path.resolve(import.meta.dir, '..');
2424

2525
const SKIP_DIRS = new Set(['node_modules', '.git', 'dist']);
2626

27-
function discoverSkillFiles(root: string): string[] {
28-
const subdirs = fs.readdirSync(root, { withFileTypes: true })
29-
.filter(d => d.isDirectory() && !d.name.startsWith('.') && !SKIP_DIRS.has(d.name))
30-
.map(d => d.name);
31-
27+
function discoverSkillFiles(root: string, relDir = '', depth = 0): string[] {
28+
// Bounded recursive walk (depth ≤ 3) so nested hand-written skills are
29+
// covered too: openclaw/skills/*/SKILL.md (depth 3), browser-skills/*/
30+
// SKILL.md (depth 2) — precisely the non-generated files most likely to
31+
// carry a hand-typed bash error.
32+
const abs = path.join(root, relDir);
3233
const results: string[] = [];
33-
if (fs.existsSync(path.join(root, 'SKILL.md'))) {
34-
results.push('SKILL.md');
34+
const skillRel = relDir ? `${relDir}/SKILL.md` : 'SKILL.md';
35+
if (fs.existsSync(path.join(root, skillRel))) {
36+
results.push(skillRel);
3537
}
36-
for (const dir of subdirs) {
37-
const rel = `${dir}/SKILL.md`;
38-
if (fs.existsSync(path.join(root, rel))) {
39-
results.push(rel);
40-
}
38+
if (depth >= 3) return results;
39+
for (const d of fs.readdirSync(abs, { withFileTypes: true })) {
40+
if (!d.isDirectory() || d.name.startsWith('.') || SKIP_DIRS.has(d.name)) continue;
41+
results.push(...discoverSkillFiles(root, relDir ? `${relDir}/${d.name}` : d.name, depth + 1));
4142
}
4243
return results;
4344
}
@@ -71,6 +72,9 @@ function extractBashBlocks(content: string): BashBlock[] {
7172
blockLines.push(line);
7273
}
7374
}
75+
if (inBash) {
76+
throw new Error(`unclosed \`\`\`bash fence starting near line ${startLine - 1}`);
77+
}
7478
return blocks;
7579
}
7680

0 commit comments

Comments
 (0)