From 41ddc80c3cae55f8aadf76b71997e8db71f8d53b Mon Sep 17 00:00:00 2001 From: Riku Kurosawa Date: Sat, 4 Apr 2026 00:59:01 +0900 Subject: [PATCH 1/2] fix(intent): discover skills under intermediate dirs without SKILL.md The recursive walk in discoverSkills only descended into directories that contained a SKILL.md, so skills nested under grouping directories (dirs without their own SKILL.md) were silently skipped. Move the walk(childDir) call outside the SKILL.md existence check so the traversal always recurses into subdirectories. --- packages/intent/src/library-scanner.ts | 4 +++- packages/intent/src/scanner.ts | 5 +++-- packages/intent/tests/library-scanner.test.ts | 22 +++++++++++++++++++ packages/intent/tests/scanner.test.ts | 21 ++++++++++++++++++ 4 files changed, 49 insertions(+), 3 deletions(-) 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'), { From 3830864c745bed64b5793f27ab6c50829bcb0e0a Mon Sep 17 00:00:00 2001 From: Riku Kurosawa Date: Sat, 4 Apr 2026 01:03:23 +0900 Subject: [PATCH 2/2] chore: add changeset for nested skill discovery fix --- .changeset/fix-nested-skill-discovery.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/fix-nested-skill-discovery.md 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.