* Finds the first existing parent directory by walking up the directory tree. * @param dirPath Starting directory path * @returns The first existing directory path, or null if root is reached without finding one
(dirPath: string)
| 153 | * @returns The first existing directory path, or null if root is reached without finding one |
| 154 | */ |
| 155 | private static async findFirstExistingDirectory(dirPath: string): Promise<string | null> { |
| 156 | let currentDir = dirPath; |
| 157 | |
| 158 | while (true) { |
| 159 | try { |
| 160 | const stats = await fs.stat(currentDir); |
| 161 | if (stats.isDirectory()) { |
| 162 | return currentDir; |
| 163 | } |
| 164 | // Path component exists but is not a directory (edge case) |
| 165 | console.debug(`Path component ${currentDir} exists but is not a directory`); |
| 166 | return null; |
| 167 | } catch (error: any) { |
| 168 | if (error.code === 'ENOENT') { |
| 169 | // Directory doesn't exist, move up one level |
| 170 | const parentDir = path.dirname(currentDir); |
| 171 | if (parentDir === currentDir) { |
| 172 | // Reached filesystem root without finding existing directory |
| 173 | return null; |
| 174 | } |
| 175 | currentDir = parentDir; |
| 176 | } else { |
| 177 | // Unexpected error (permissions, I/O error, etc.) |
| 178 | console.debug(`Error checking directory ${currentDir}: ${error.message}`); |
| 179 | return null; |
| 180 | } |
| 181 | } |
| 182 | } |
| 183 | } |
| 184 | |
| 185 | static async canWriteFile(filePath: string): Promise<boolean> { |
| 186 | try { |