findProjectRoot was keyed by exact startPath, so sibling files in the
same project repeated the entire upward marker walk. The walk does one
existsSync per marker per ancestor directory, which adds up on every
read/write/edit/multiedit tool call.
Track every directory visited during the walk and seed the cache with
the resolved root for each of them. Subsequent lookups for any
descendant short-circuit to the cached ancestor without re-running
marker probes. Cache invalidation still happens on session.deleted /
session.compacted, so production semantics are unchanged.
Pin the new contract via a sibling-startpath test, and make the
existing finder.test.ts beforeEach explicit about cache state so the
more aggressive cache does not leak between tests.
* feat(rules-injector): add GitHub Copilot instructions format support
- Add .github/instructions/ directory to rule discovery paths
- Add applyTo as alias for globs field in frontmatter parser
- Support .github/copilot-instructions.md single-file format (always-apply)
- Filter .github/instructions/ to only accept *.instructions.md files
- Add comprehensive tests for parser and finder
Closes#397
* fix(rules-injector): use cross-platform path separator in calculateDistance
path.relative() returns OS-native separators (backslashes on Windows),
but the code was splitting by forward slash only, causing incorrect
distance calculations on Windows.
Use regex /[/\]/ to handle both separator types.
---------
Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>