@@ -259,18 +259,16 @@ func searchWithRipgrep(ctx context.Context, pattern, path, include string) ([]gr
259259 continue
260260 }
261261
262− // Parse ripgrep output format: file:line:content
263− parts := strings.SplitN(line, ":", 3)
264− if len(parts) < 3 {
262+ // Parse ripgrep output using null separation
263+ filePath, lineNumStr, lineText, ok := parseRipgrepLine(line)
264+ if !ok {
265265 continue
266266 }
267267
268− filePath := parts[0]
269− lineNum, err := strconv.Atoi(parts[1])
268+ lineNum, err := strconv.Atoi(lineNumStr)
270269 if err != nil {
271270 continue
272271 }
273− lineText := parts[2]
274272
275273 fileInfo, err := os.Stat(filePath)
276274 if err != nil {
@@ -288,6 +286,33 @@ func searchWithRipgrep(ctx context.Context, pattern, path, include string) ([]gr
288286 return matches, nil
289287}
290288
289+// parseRipgrepLine parses ripgrep output with null separation to handle Windows paths
290+func parseRipgrepLine(line string) (filePath, lineNum, lineText string, ok bool) {
291+ // Split on null byte first to separate filename from rest
292+ parts := strings.SplitN(line, "\x00", 2)
293+ if len(parts) != 2 {
294+ return "", "", "", false
295+ }
296+
297+ filePath = parts[0]
298+ remainder := parts[1]
299+
300+ // Now split the remainder on first colon: "linenum:content"
301+ colonIndex := strings.Index(remainder, ":")
302+ if colonIndex == -1 {
303+ return "", "", "", false
304+ }
305+
306+ lineNumStr := remainder[:colonIndex]
307+ lineText = remainder[colonIndex+1:]
308+
309+ if _, err := strconv.Atoi(lineNumStr); err != nil {
310+ return "", "", "", false
311+ }
312+
313+ return filePath, lineNumStr, lineText, true
314+}
315+
291316func searchFilesWithRegex(pattern, rootPath, include string) ([]grepMatch, error) {
292317 matches := []grepMatch{}
293318