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 |
alfred-openspec
left a comment
There was a problem hiding this comment.
The shared helper consistently admits real directories and symlinks to directories while rejecting file and dangling targets across list, info, and validate paths. The focused resolver suite passed 47/47 at this exact head, and the full Linux, macOS, and Windows matrix is green.
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