( pattern: string, source: PermissionRuleSource, )
| 851 | } |
| 852 | |
| 853 | function patternWithRoot( |
| 854 | pattern: string, |
| 855 | source: PermissionRuleSource, |
| 856 | ): { |
| 857 | relativePattern: string |
| 858 | root: string | null |
| 859 | } { |
| 860 | if (pattern.startsWith(`${DIR_SEP}${DIR_SEP}`)) { |
| 861 | // Patterns starting with // resolve relative to / |
| 862 | const patternWithoutDoubleSlash = pattern.slice(1) |
| 863 | |
| 864 | // On Windows, check if this is a POSIX-style drive path like //c/Users/... |
| 865 | // Note: UNC paths (//server/share) will not match this regex and will be treated |
| 866 | // as root-relative patterns, which may need separate handling in the future |
| 867 | if ( |
| 868 | getPlatform() === 'windows' && |
| 869 | patternWithoutDoubleSlash.match(/^\/[a-z]\//i) |
| 870 | ) { |
| 871 | // Convert POSIX path to Windows format |
| 872 | // The pattern is like /c/Users/... so we convert it to C:\Users\... |
| 873 | const driveLetter = patternWithoutDoubleSlash[1]?.toUpperCase() ?? 'C' |
| 874 | // Keep the pattern in POSIX format since relativePath returns POSIX paths |
| 875 | const pathAfterDrive = patternWithoutDoubleSlash.slice(2) |
| 876 | |
| 877 | // Extract the drive root (C:\) and the rest of the pattern |
| 878 | const driveRoot = `${driveLetter}:\\` |
| 879 | const relativeFromDrive = pathAfterDrive.startsWith('/') |
| 880 | ? pathAfterDrive.slice(1) |
| 881 | : pathAfterDrive |
| 882 | |
| 883 | return { |
| 884 | relativePattern: relativeFromDrive, |
| 885 | root: driveRoot, |
| 886 | } |
| 887 | } |
| 888 | |
| 889 | return { |
| 890 | relativePattern: patternWithoutDoubleSlash, |
| 891 | root: DIR_SEP, |
| 892 | } |
| 893 | } else if (pattern.startsWith(`~${DIR_SEP}`)) { |
| 894 | // Patterns starting with ~/ resolve relative to homedir |
| 895 | return { |
| 896 | relativePattern: pattern.slice(1), |
| 897 | root: homedir().normalize('NFC'), |
| 898 | } |
| 899 | } else if (pattern.startsWith(DIR_SEP)) { |
| 900 | // Patterns starting with / resolve relative to the directory where settings are stored (without .claude/) |
| 901 | return { |
| 902 | relativePattern: pattern, |
| 903 | root: rootPathForSource(source), |
| 904 | } |
| 905 | } |
| 906 | // No root specified, put it with all the other patterns |
| 907 | // Normalize patterns that start with "./" to remove the prefix |
| 908 | // This ensures that patterns like "./.env" match files like ".env" |
| 909 | let normalizedPattern = pattern |
| 910 | if (pattern.startsWith(`.${DIR_SEP}`)) { |
no test coverage detected