* Collect settings file paths and their deduplicated parent directories to watch. * Returns all potential settings file paths for watched directories, not just those * that exist at init time, so that newly-created files are also detected.
()
| 178 | * that exist at init time, so that newly-created files are also detected. |
| 179 | */ |
| 180 | async function getWatchTargets(): Promise<{ |
| 181 | dirs: string[] |
| 182 | settingsFiles: Set<string> |
| 183 | dropInDir: string | null |
| 184 | }> { |
| 185 | // Map from directory to all potential settings files in that directory |
| 186 | const dirToSettingsFiles = new Map<string, Set<string>>() |
| 187 | const dirsWithExistingFiles = new Set<string>() |
| 188 | |
| 189 | for (const source of SETTING_SOURCES) { |
| 190 | // Skip flagSettings - they're provided via CLI and won't change during the session. |
| 191 | // Additionally, they may be temp files in $TMPDIR which can contain special files |
| 192 | // (FIFOs, sockets) that cause the file watcher to hang or error. |
| 193 | // See: https://github.com/anthropics/claude-code/issues/16469 |
| 194 | if (source === 'flagSettings') { |
| 195 | continue |
| 196 | } |
| 197 | const path = getSettingsFilePathForSource(source) |
| 198 | if (!path) { |
| 199 | continue |
| 200 | } |
| 201 | |
| 202 | const dir = platformPath.dirname(path) |
| 203 | |
| 204 | // Track all potential settings files in each directory |
| 205 | if (!dirToSettingsFiles.has(dir)) { |
| 206 | dirToSettingsFiles.set(dir, new Set()) |
| 207 | } |
| 208 | dirToSettingsFiles.get(dir)!.add(path) |
| 209 | |
| 210 | // Check if file exists - only watch directories that have at least one existing file |
| 211 | try { |
| 212 | const stats = await stat(path) |
| 213 | if (stats.isFile()) { |
| 214 | dirsWithExistingFiles.add(dir) |
| 215 | } |
| 216 | } catch { |
| 217 | // File doesn't exist, that's fine |
| 218 | } |
| 219 | } |
| 220 | |
| 221 | // For watched directories, include ALL potential settings file paths |
| 222 | // This ensures files created after init are also detected |
| 223 | const settingsFiles = new Set<string>() |
| 224 | for (const dir of dirsWithExistingFiles) { |
| 225 | const filesInDir = dirToSettingsFiles.get(dir) |
| 226 | if (filesInDir) { |
| 227 | for (const file of filesInDir) { |
| 228 | settingsFiles.add(file) |
| 229 | } |
| 230 | } |
| 231 | } |
| 232 | |
| 233 | // Also watch the managed-settings.d/ drop-in directory for policy fragments. |
| 234 | // We add it as a separate watched directory so chokidar's depth:0 watches |
| 235 | // its immediate children (the .json files). Any .json file inside it maps |
| 236 | // to the 'policySettings' source. |
| 237 | let dropInDir: string | null = null |
no test coverage detected