import { realpath } from 'node:fs/promises'; import { isAbsolute, resolve, sep } from 'node:path'; export class PathScopeError extends Error { constructor(message: string) { super(message); this.name = 'PathScopeError'; } } export async function resolveProjectRoot(projectPath: string): Promise { try { return await realpath(projectPath); } catch { throw new PathScopeError(`project path does not exist: ${projectPath}`); } } export async function pathGuard( projectRoot: string, requested: string ): Promise { if (typeof requested !== 'string' || requested.length === 0) { throw new PathScopeError('path is required'); } const candidate = isAbsolute(requested) ? requested : resolve(projectRoot, requested); let real: string; try { real = await realpath(candidate); } catch { throw new PathScopeError(`path does not exist: ${requested}`); } if (real !== projectRoot && !real.startsWith(projectRoot + sep)) { throw new PathScopeError( `path escapes project root: ${requested} -> ${real}` ); } return real; }