diff --git a/.changeset/fix-nested-skill-discovery.md b/.changeset/fix-nested-skill-discovery.md new file mode 100644 index 0000000..92642c6 --- /dev/null +++ b/.changeset/fix-nested-skill-discovery.md @@ -0,0 +1,5 @@ +--- +'@tanstack/intent': patch +--- + +Fix skill discovery so skills nested under intermediate grouping directories (directories without their own SKILL.md) are found by the scanner. diff --git a/packages/intent/src/library-scanner.ts b/packages/intent/src/library-scanner.ts index b50989f..445c446 100644 --- a/packages/intent/src/library-scanner.ts +++ b/packages/intent/src/library-scanner.ts @@ -93,8 +93,10 @@ function discoverSkills(skillsDir: string): Array { framework: typeof fm?.framework === 'string' ? fm.framework : undefined, }) - walk(childDir) } + // Always recurse into subdirectories so skills nested under + // intermediate grouping directories (dirs without SKILL.md) are found. + walk(childDir) } } diff --git a/packages/intent/src/scanner.ts b/packages/intent/src/scanner.ts index 100da63..4ed3623 100644 --- a/packages/intent/src/scanner.ts +++ b/packages/intent/src/scanner.ts @@ -170,9 +170,10 @@ function discoverSkills( framework: typeof fm?.framework === 'string' ? fm.framework : undefined, }) - // Recurse for sub-skills - walk(childDir) } + // Always recurse into subdirectories so skills nested under + // intermediate grouping directories (dirs without SKILL.md) are found. + walk(childDir) } } diff --git a/packages/intent/tests/library-scanner.test.ts b/packages/intent/tests/library-scanner.test.ts index a243dc8..daf7233 100644 --- a/packages/intent/tests/library-scanner.test.ts +++ b/packages/intent/tests/library-scanner.test.ts @@ -310,6 +310,28 @@ describe('scanLibrary', () => { expect(names).toContain('routing/nested-routes') }) + it('discovers skills nested under intermediate dirs without SKILL.md', () => { + const pkgDir = createDir(root, 'node_modules', '@tanstack', 'router') + writeJson(join(pkgDir, 'package.json'), { + name: '@tanstack/router', + version: '1.0.0', + keywords: ['tanstack-intent'], + }) + // intermediate directory has no SKILL.md + const groupDir = createDir(pkgDir, 'skills', 'group') + const nestedDir = createDir(groupDir, 'nested-skill') + writeSkillMd(nestedDir, { + name: 'group/nested-skill', + description: 'A nested skill under a grouping dir', + }) + + const result = scanLibrary(scriptPath(pkgDir), root) + + const skills = result.packages[0]!.skills + expect(skills).toHaveLength(1) + expect(skills[0]!.name).toBe('group/nested-skill') + }) + it('handles missing package name without producing double slashes in paths', () => { const pkgDir = createDir(root, 'node_modules', 'no-name-pkg') writeJson(join(pkgDir, 'package.json'), { diff --git a/packages/intent/tests/scanner.test.ts b/packages/intent/tests/scanner.test.ts index 3722415..11c7362 100644 --- a/packages/intent/tests/scanner.test.ts +++ b/packages/intent/tests/scanner.test.ts @@ -186,6 +186,27 @@ describe('scanForIntents', () => { expect(names).toContain('db-core/live-queries') }) + it('discovers skills nested under intermediate dirs without SKILL.md', () => { + const pkgDir = createDir(root, 'node_modules', '@tanstack', 'db') + writeJson(join(pkgDir, 'package.json'), { + name: '@tanstack/db', + version: '0.5.2', + intent: { version: 1, repo: 'TanStack/db', docs: 'docs/' }, + }) + // intermediate directory has no SKILL.md + const groupDir = createDir(pkgDir, 'skills', 'group') + const nestedDir = createDir(groupDir, 'nested-skill') + writeSkillMd(nestedDir, { + name: 'group/nested-skill', + description: 'A nested skill under a grouping dir', + }) + + const result = scanForIntents(root) + expect(result.packages).toHaveLength(1) + expect(result.packages[0]!.skills).toHaveLength(1) + expect(result.packages[0]!.skills[0]!.name).toBe('group/nested-skill') + }) + it('warns on skills/ dir without valid intent field', () => { const pkgDir = createDir(root, 'node_modules', 'bad-pkg') writeJson(join(pkgDir, 'package.json'), {