feat(schema): resolve symlinked schema directories#1299
Conversation
Schema discovery filtered directory entries with `Dirent.isDirectory()`, which reports the raw entry type and returns false for symlinks — even those pointing at a real directory. As a result, symlinked schema dirs in the user/project/package schema locations were silently skipped. Add a shared `isSchemaDir()` helper that accepts real directories and dereferences symlinks (via statSync) to admit symlinked directories while still rejecting symlinks-to-files and broken links. Use it at all six discovery sites in resolver.ts and in `schema validate` in schema.ts.
Add unit tests for isSchemaDir (real dir, symlink-to-dir, symlink-to-file, broken symlink, regular file) plus integration tests confirming listSchemas and listSchemasWithInfo pick up a symlinked user schema dir while ignoring symlinks whose target is a file.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughAdds an exported ChangesSymlink-aware schema directory detection
Estimated code review effort: 2 (Simple) | ~12 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
What it does
Adds a shared
isSchemaDir()helper inresolver.tsand uses it everywhere schema directories are enumerated — the six discovery sites inlistSchemas()/listSchemasWithInfo(), plusschema validateinschema.ts. The helper accepts real directories and symlinks whose target is a directory, while still rejecting symlinks-to-files and broken/dangling symlinks.What it fixes
Schema discovery filtered directory entries with
fs.Dirent.isDirectory(). That method reports the raw entry type fromreaddir, so a symlink returnsfalseeven when it points at a real directory. As a result, a symlinked schema directory placed in the user (~/.local/share/openspec/schemas), project, or package schema location was silently skipped — schemas could only be discovered as regular directories, never via symlink.Before → After
Symlink-to-file and broken symlinks remain excluded in both cases.
Why it's safe to merge
entry.isDirectory()short-circuits); only symlink entries — previously dropped entirely — now get astatSyncfollow-up. No existing input changes behaviour.schema.yamlexistence check still runs, so a symlinked dir without a validschema.yamlis rejected exactly as a real dir would be.statSyncthrowsENOENTon dangling links; the helper catches it and returnsfalserather than propagating.pnpm test); the resolver file is 47/47 including 9 new cases.Notes for review
entry.isDirectory()is insideisSchemaDiritself — intentional, it's the helper's own directory check.isSchemaDiris exported soschema.tsreuses it rather than duplicating thestatSynctry/catch.readdirSynccall sites (view.ts,spec.ts, andcopyDirRecursiveinschema.ts) were left untouched — they enumerate changes/specs or perform recursive copies, not schema discovery.Summary by CodeRabbit