← Back to PRs

#23620: fix(memory): follow symlinks in memory indexer, reader, and watcher

by Diaspar4u open 2026-02-22 14:05 View on GitHub →
cli size: S
Closes #23619 ## Summary - Memory indexer, reader, and file watcher use `lstat` + `isSymbolicLink()` to explicitly reject symlinked files and directories. This silently breaks use cases where workspace memory files are symlinked to an external location (e.g., an Obsidian vault). - Changed `lstat` → `stat` and removed `isSymbolicLink()` rejection logic in 4 files so symlinks are followed transparently. - `walkDir` now resolves symlink targets via `fs.stat()` to determine if they're files or directories before recursing/collecting. ## Safety - Circular symlinks: `fs.stat()` throws `ELOOP`, caught by existing `try/catch` blocks - Duplicate indexing: already handled by `realpath()`-based deduplication in `listMemoryFiles()` ## Test plan - [ ] Create a symlinked `.md` file in `memory/` → verify it appears in `memory_search` results - [ ] Create a symlinked `memory/` directory → verify files inside are indexed - [ ] Symlinked `MEMORY.md` at workspace root → verify it loads at bootstrap and is indexed - [ ] Symlinked `extraPaths` entry → verify it is indexed and watched - [ ] `memory_get` on a symlinked file → verify it returns content instead of throwing - [ ] Circular symlink in `memory/` → verify no crash (silently skipped) <!-- greptile_comment --> <h3>Greptile Summary</h3> Changed memory system from rejecting symlinks (`lstat` + `isSymbolicLink()` checks) to following them transparently (`stat`), enabling workspace memory files stored in external locations like Obsidian vaults. **Key changes:** - Replaced `fs.lstat()` with `fs.stat()` in 4 files to dereference symlinks - Removed explicit `isSymbolicLink()` rejection logic - `walkDir` now recursively follows symlinked directories and collects symlinked `.md` files - Circular symlinks protected by existing error handling (`fs.stat()` throws `ELOOP`, caught silently) - Duplicate indexing handled by existing `realpath()`-based deduplication **Issues found:** - `walkDir` checks `entry.name.endsWith(".md")` for symlinks instead of checking the resolved target path <h3>Confidence Score: 4/5</h3> - Safe to merge with minor fix - symlink following logic is sound with good safety measures - The PR successfully enables symlink following with proper circular symlink protection and deduplication. One logical bug in `walkDir` affects edge cases where symlink names don't match target filenames. Existing error handling and deduplication provide good safety. The changes are well-isolated to memory file operations. - src/memory/internal.ts needs the filename check fix for symlinks <sub>Last reviewed commit: 7d16ab2</sub> <!-- greptile_other_comments_section --> <!-- /greptile_comment -->

Most Similar PRs