| 257 | // "read back identically" guarantee would break for such projects). |
| 258 | // 3. else projectDir. |
| 259 | function _fsWorkspaceRoot(projectDir) { |
| 260 | if (process.env.OPENCLAW_WORKSPACE) return process.env.OPENCLAW_WORKSPACE; |
| 261 | // Walk up from projectDir looking for a .git entry (file or dir) = repo root. |
| 262 | let repoRoot = null; |
| 263 | let dir = projectDir; |
| 264 | while (dir) { |
| 265 | if (fs.existsSync(path.join(dir, '.git'))) { repoRoot = dir; break; } |
| 266 | const parent = path.dirname(dir); |
| 267 | if (parent === dir) break; |
| 268 | dir = parent; |
| 269 | } |
| 270 | if (!repoRoot) return projectDir; |
| 271 | // Mirror getWorkspaceRoot()'s workspace/ subdir step. |
| 272 | const workspaceDir = path.join(repoRoot, 'workspace'); |
| 273 | if (fs.existsSync(workspaceDir)) return workspaceDir; |
| 274 | return repoRoot; |
| 275 | } |
| 276 | |
| 277 | // FS-only re-implementation of src/gep/paths.js getWorkspaceId() for the case |
| 278 | // where the evolver package is not installed (plugin-only installs). It reads |