@@ -926,14 +926,20 @@ func (t *FilesystemTool) handleSearchFiles(_ context.Context, toolCall tools.Too
926926 return nil // Skip disallowed paths
927927 }
928928
929- // Check exclude patterns
929+ // Check exclude patterns against relative path from search root
930+ relPath , err := filepath .Rel (args .Path , path )
931+ if err != nil {
932+ return nil
933+ }
934+
930935 for _ , exclude := range args .ExcludePatterns {
931- if match (exclude , filepath .Base (path )) {
936+ if matchExcludePattern (exclude , relPath ) {
937+ if d .IsDir () {
938+ return fs .SkipDir
939+ }
932940 return nil
933941 }
934942 }
935-
936- // Case-insensitive match
937943 if match (pattern , filepath .Base (path )) {
938944 matches = append (matches , path )
939945 }
@@ -980,21 +986,34 @@ func (t *FilesystemTool) handleSearchFilesContent(_ context.Context, toolCall to
980986 var results []string
981987
982988 err := filepath .WalkDir (args .Path , func (path string , d fs.DirEntry , err error ) error {
983- if err != nil || d . IsDir () {
989+ if err != nil {
984990 return nil
985991 }
986992
987993 if err := t .isPathAllowed (path ); err != nil {
988994 return nil
989995 }
990996
991- // Check exclude patterns
997+ // Check exclude patterns against relative path from search root
998+ relPath , err := filepath .Rel (args .Path , path )
999+ if err != nil {
1000+ return nil
1001+ }
1002+
9921003 for _ , exclude := range args .ExcludePatterns {
993- if match (exclude , filepath .Base (path )) {
994- return nil
1004+ if matchExcludePattern (exclude , relPath ) {
1005+ if d .IsDir () {
1006+ return fs .SkipDir // Skip entire directory
1007+ }
1008+ return nil // Skip this file
9951009 }
9961010 }
9971011
1012+ // Only process files, not directories
1013+ if d .IsDir () {
1014+ return nil
1015+ }
1016+
9981017 content , err := os .ReadFile (path )
9991018 if err != nil {
10001019 return nil
@@ -1077,6 +1096,47 @@ func (t *FilesystemTool) Stop() error {
10771096 return nil
10781097}
10791098
1099+ // matchExcludePattern checks if a path should be excluded based on the exclude pattern
1100+ // It supports glob patterns and directory wildcards like .git/*
1101+ func matchExcludePattern (pattern , relPath string ) bool {
1102+ // Normalize path separators to forward slashes for consistent matching
1103+ normalizedPath := filepath .ToSlash (relPath )
1104+ normalizedPattern := filepath .ToSlash (pattern )
1105+
1106+ // Handle directory patterns ending with /*
1107+ if strings .HasSuffix (normalizedPattern , "/*" ) {
1108+ dirPattern := strings .TrimSuffix (normalizedPattern , "/*" )
1109+ // Check if path starts with the directory pattern
1110+ if strings .HasPrefix (normalizedPath , dirPattern + "/" ) || normalizedPath == dirPattern {
1111+ return true
1112+ }
1113+ }
1114+
1115+ // Try glob pattern matching on the full relative path
1116+ matched , _ := filepath .Match (normalizedPattern , normalizedPath )
1117+ if matched {
1118+ return true
1119+ }
1120+
1121+ // Try glob pattern matching on just the base name for backwards compatibility
1122+ matched , _ = filepath .Match (normalizedPattern , filepath .Base (normalizedPath ))
1123+ if matched {
1124+ return true
1125+ }
1126+
1127+ // Check if pattern matches any parent directory path
1128+ pathParts := strings .Split (normalizedPath , "/" )
1129+ for i := range pathParts {
1130+ subPath := strings .Join (pathParts [:i + 1 ], "/" )
1131+ matched , _ := filepath .Match (normalizedPattern , subPath )
1132+ if matched {
1133+ return true
1134+ }
1135+ }
1136+
1137+ return false
1138+ }
1139+
10801140func match (pattern , name string ) bool {
10811141 matched , _ := filepath .Match (pattern , name )
10821142 if matched {
0 commit comments