Both findInstallSourceRoot and findAgentsSourceRoot now accept an optional
runtimeConfigDir. When provided, they first check <runtimeConfigDir>/.gsd-source:
read the stored path, verify it exists, and return it. Fall through to the
path.dirname walk-up only when the marker is absent or points to a missing path.
The factory functions (commandsKind, agentsKind, skillsKind) now receive configDir
from the switch arms and pass it through to the finders. listSurface in surface.cjs
passes its runtimeConfigDir argument to findInstallSourceRoot so installed-from-source
layouts use the marker rather than the walk-up.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Both findInstallSourceRoot and findAgentsSourceRoot previously returned a
path.join(__dirname, '..', '..', '..', ...) fallback when the walk-up loop
found nothing. Replace with throw per CLAUDE.md "No Relative Path Traversal"
policy: .. chains silently break on CWD changes; a throw with the failing
__dirname in the message is an unambiguous diagnostic.
The walk-up loop already uses path.dirname iteratively (no literal ..); only
the dead-end fallback used the banned pattern.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>