PR #883 nested Claude skills 3 levels deep under gsd-ns-*/skills/<stem>/SKILL.md. Claude Code's Skill tool scans only one level under ~/.claude/skills/ — nested concrete skills were never listed and Skill(skill="gsd-plan-phase") calls failed. Revert to flat layout: all ~61 concrete skills at ~/.claude/skills/gsd-<name>/SKILL.md. The 6 other runtimes confirmed as non-recursive scanners (cline, qwen, hermes, augment, trae, antigravity) retain their nested layout — only Claude changes. Tradeoff: ~61 top-level skill dirs return to the flat install, but they are discoverable and invokable. Nested concretes were invisible to the Skill tool entirely. Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -32,7 +32,8 @@ const { COMMANDS_GSD, ROUTER_STEMS, routerChildren } = require('./helpers/nested
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
const NEST = [
|
||||
{ runtime: 'claude', scope: 'global', skillsSub: 'skills', prefix: 'gsd-' },
|
||||
// Claude reverted to flat (#924: nested layout breaks Skill-tool discovery on Claude Code).
|
||||
// Only the 6 runtimes below keep the nested layout.
|
||||
{ runtime: 'cline', scope: 'global', skillsSub: 'skills', prefix: 'gsd-' },
|
||||
{ runtime: 'qwen', scope: 'global', skillsSub: 'skills', prefix: 'gsd-' },
|
||||
{ runtime: 'hermes', scope: 'global', skillsSub: 'skills/gsd', prefix: '' },
|
||||
@@ -42,6 +43,9 @@ const NEST = [
|
||||
];
|
||||
|
||||
const FLAT = [
|
||||
// Claude reverted to flat (#924): Claude Code scans only one level under ~/.claude/skills/
|
||||
// so nested concretes were never discoverable by the Skill tool.
|
||||
{ runtime: 'claude', scope: 'global', skillsSub: 'skills' },
|
||||
{ runtime: 'cursor', scope: 'global', skillsSub: 'skills' },
|
||||
{ runtime: 'codex', scope: 'global', skillsSub: 'skills' },
|
||||
{ runtime: 'copilot', scope: 'global', skillsSub: 'skills' },
|
||||
@@ -200,10 +204,13 @@ for (const { runtime, scope, skillsSub, prefix } of NEST) {
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// claude extra: total top-level gsd- count must equal exactly 6
|
||||
// claude extra: total top-level gsd- count must be >= 60 (FLAT, #924)
|
||||
//
|
||||
// Pre-#924 (nested) this block asserted exactly 6 (only routers).
|
||||
// Post-#924 (flat) Claude has all concrete skills at the top level.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('claude: total top-level gsd- entries == 6', () => {
|
||||
describe('claude: total top-level gsd- entries >= 60 (flat layout, #924)', () => {
|
||||
let tmpDir;
|
||||
|
||||
before(() => {
|
||||
@@ -216,15 +223,15 @@ describe('claude: total top-level gsd- entries == 6', () => {
|
||||
}
|
||||
});
|
||||
|
||||
test('claude: total top-level gsd- skill entries == 6', () => {
|
||||
test('claude: >= 60 gsd-* top-level skill entries (concrete flat layout, not nested)', () => {
|
||||
const skillsDir = path.join(tmpDir, 'skills');
|
||||
assert.ok(fs.existsSync(skillsDir), 'skills/ dir must exist');
|
||||
|
||||
const topLevel = fs.readdirSync(skillsDir).filter((n) => n.startsWith('gsd-'));
|
||||
assert.strictEqual(
|
||||
topLevel.length,
|
||||
6,
|
||||
`Expected exactly 6 gsd-* top-level entries under claude/skills, got ${topLevel.length}: [${topLevel.join(', ')}]`,
|
||||
assert.ok(
|
||||
topLevel.length >= 60,
|
||||
`Expected >= 60 gsd-* top-level entries under claude/skills (flat layout after #924 fix). ` +
|
||||
`Got ${topLevel.length}: [${topLevel.slice(0, 10).join(', ')}${topLevel.length > 10 ? ', …' : ''}]`,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user