MCPcopy Create free account
hub / github.com/EvoMap/evolver / getRepoRoot

Function getRepoRoot

src/gep/paths.js:25–149  ·  view source on GitHub ↗
()

Source from the content-addressed store, hash-verified

23// EVOLVER_USE_PARENT_GIT=true flag is still honored for forward
24// compatibility but is no longer required.
25function getRepoRoot() {
26 // Always check EVOLVER_REPO_ROOT first, even when a cached value exists.
27 // .env is loaded during index.js bootstrap AFTER this function has
28 // already been called at least once (for locating the .env file
29 // itself). Caching the pre-dotenv result would permanently shadow any
30 // EVOLVER_REPO_ROOT later populated from .env. See #526.
31 if (process.env.EVOLVER_REPO_ROOT) {
32 _cachedRepoRoot = process.env.EVOLVER_REPO_ROOT;
33 return _cachedRepoRoot;
34 }
35
36 if (_cachedRepoRoot) return _cachedRepoRoot;
37
38 const ownDir = path.resolve(__dirname, '..', '..');
39
40 const noParent = String(process.env.EVOLVER_NO_PARENT_GIT || '').toLowerCase() === 'true';
41 // Older flag kept for backward compatibility. Setting it to 'false'
42 // explicitly is treated as an opt-out, mirroring EVOLVER_NO_PARENT_GIT.
43 const legacyFlag = process.env.EVOLVER_USE_PARENT_GIT;
44 const legacyOptOut = typeof legacyFlag === 'string' && legacyFlag.toLowerCase() === 'false';
45
46 // Both upward walks below must stop at the parent of the nearest
47 // `node_modules` ancestor — never escape into whatever `.git` happens
48 // to live above it (issue #541). On macOS with Homebrew, the global
49 // install lives at `/opt/homebrew/lib/node_modules/@evomap/evolver`
50 // and `/opt/homebrew` is itself a git repo; an unbounded walk
51 // therefore resolves repoRoot to `/opt/homebrew`, sending
52 // workspaceRoot / memoryDir / evolutionDir to a directory that
53 // doesn't belong to the user and silently producing evolution
54 // proposals for the wrong codebase.
55 //
56 // Boundary semantics: returns the parent of the nearest `node_modules`
57 // ancestor (inclusive — a `.git` at that parent IS still picked up),
58 // or null if `dir` is not inside any `node_modules` (dev clone /
59 // user project root). Callers stop AFTER checking the boundary path
60 // itself.
61 //
62 // For a local install (`<project>/node_modules/@evomap/evolver`), the
63 // parent of node_modules IS the user's project, so the boundary
64 // includes `<project>` and `<project>/.git` is still picked up
65 // correctly. For a dev clone, the boundary is null and the walk is
66 // unbounded as before.
67 function _nodeModulesBoundary(dir) {
68 const segments = dir.split(path.sep);
69 const nmIdx = segments.lastIndexOf('node_modules');
70 if (nmIdx <= 0) return null;
71 return segments.slice(0, nmIdx).join(path.sep) || path.sep;
72 }
73
74 function _walkForGit(start) {
75 const stopAt = _nodeModulesBoundary(start);
76 let dir = start;
77 while (dir !== path.dirname(dir)) {
78 if (fs.existsSync(path.join(dir, '.git'))) {
79 if (!process.env.EVOLVER_QUIET_PARENT_GIT) {
80 // Diagnostic, not data. Goes to stderr so it cannot poison
81 // a child process's stdout-as-JSON contract — the Stop hook
82 // emits JSON on stdout, and any caller invoking the hook via

Callers 15

mainFunction · 0.85
paths.test.jsFile · 0.85
legacyGepAssetsDirFunction · 0.85
getWorkspaceRootFunction · 0.85
runLlmReviewFunction · 0.85
captureNodeIdentityFunction · 0.85
captureEnvConfigFunction · 0.85
captureLocalStatePathsFunction · 0.85
runGhFunction · 0.85
maybeCreatePRFunction · 0.85

Calls 2

_walkForGitFunction · 0.85
_nodeModulesBoundaryFunction · 0.85

Tested by

no test coverage detected