|
18 | 18 | FileListingMessage, |
19 | 19 | GrepMatch, |
20 | 20 | GrepResultMessage, |
21 | | - emit_error, |
22 | | - emit_warning, |
23 | 21 | get_message_bus, |
24 | 22 | ) |
25 | | -from code_puppy.tools.common import generate_group_id |
26 | 23 |
|
27 | 24 |
|
28 | 25 | # Pydantic models for tool return types |
@@ -53,6 +50,7 @@ class MatchInfo(BaseModel): |
53 | 50 |
|
54 | 51 | class GrepOutput(BaseModel): |
55 | 52 | matches: List[MatchInfo] |
| 53 | + error: str | None = None |
56 | 54 |
|
57 | 55 |
|
58 | 56 | def is_likely_home_directory(directory): |
@@ -582,9 +580,7 @@ def _grep(context: RunContext, search_string: str, directory: str = ".") -> Grep |
582 | 580 |
|
583 | 581 | directory = os.path.abspath(os.path.expanduser(directory)) |
584 | 582 | matches: List[MatchInfo] = [] |
585 | | - |
586 | | - # Generate group_id for this tool execution |
587 | | - group_id = generate_group_id("grep", f"{directory}_{search_string}") |
| 583 | + error_message: str | None = None |
588 | 584 |
|
589 | 585 | # Create a temporary ignore file with our ignore patterns |
590 | 586 | ignore_file = None |
@@ -616,11 +612,10 @@ def _grep(context: RunContext, search_string: str, directory: str = ".") -> Grep |
616 | 612 | break |
617 | 613 |
|
618 | 614 | if not rg_path: |
619 | | - emit_error( |
620 | | - "ripgrep (rg) not found. Please install ripgrep to use this tool.", |
621 | | - message_group=group_id, |
| 615 | + error_message = ( |
| 616 | + "ripgrep (rg) not found. Please install ripgrep to use this tool." |
622 | 617 | ) |
623 | | - return GrepOutput(matches=[]) |
| 618 | + return GrepOutput(matches=[], error=error_message) |
624 | 619 |
|
625 | 620 | cmd = [ |
626 | 621 | rg_path, |
@@ -688,50 +683,43 @@ def _grep(context: RunContext, search_string: str, directory: str = ".") -> Grep |
688 | 683 | # Skip lines that aren't valid JSON |
689 | 684 | continue |
690 | 685 |
|
691 | | - # Build structured GrepMatch objects for the UI |
692 | | - grep_matches = [ |
693 | | - GrepMatch( |
694 | | - file_path=m.file_path or "", |
695 | | - line_number=m.line_number or 1, |
696 | | - line_content=m.line_content or "", |
697 | | - ) |
698 | | - for m in matches |
699 | | - ] |
700 | | - |
701 | | - # Count unique files searched (approximation based on matches) |
702 | | - unique_files = len(set(m.file_path for m in matches)) if matches else 0 |
703 | | - |
704 | | - # Emit structured message for the UI |
705 | | - grep_result_msg = GrepResultMessage( |
706 | | - search_term=search_string, |
707 | | - directory=directory, |
708 | | - matches=grep_matches, |
709 | | - total_matches=len(matches), |
710 | | - files_searched=unique_files, |
711 | | - ) |
712 | | - get_message_bus().emit(grep_result_msg) |
713 | | - |
714 | | - if not matches: |
715 | | - emit_warning( |
716 | | - f"No matches found for '{search_string}' in {directory}", |
717 | | - message_group=group_id, |
718 | | - ) |
719 | | - |
720 | 686 | except subprocess.TimeoutExpired: |
721 | | - emit_error("Grep command timed out after 30 seconds", message_group=group_id) |
| 687 | + error_message = "Grep command timed out after 30 seconds" |
722 | 688 | except FileNotFoundError: |
723 | | - emit_error( |
724 | | - "ripgrep (rg) not found. Please install ripgrep to use this tool.", |
725 | | - message_group=group_id, |
| 689 | + error_message = ( |
| 690 | + "ripgrep (rg) not found. Please install ripgrep to use this tool." |
726 | 691 | ) |
727 | 692 | except Exception as e: |
728 | | - emit_error(f"Error during grep operation: {e}", message_group=group_id) |
| 693 | + error_message = f"Error during grep operation: {e}" |
729 | 694 | finally: |
730 | 695 | # Clean up the temporary ignore file |
731 | 696 | if ignore_file and os.path.exists(ignore_file): |
732 | 697 | os.unlink(ignore_file) |
733 | 698 |
|
734 | | - return GrepOutput(matches=matches) |
| 699 | + # Build structured GrepMatch objects for the UI |
| 700 | + grep_matches = [ |
| 701 | + GrepMatch( |
| 702 | + file_path=m.file_path or "", |
| 703 | + line_number=m.line_number or 1, |
| 704 | + line_content=m.line_content or "", |
| 705 | + ) |
| 706 | + for m in matches |
| 707 | + ] |
| 708 | + |
| 709 | + # Count unique files searched (approximation based on matches) |
| 710 | + unique_files = len(set(m.file_path for m in matches)) if matches else 0 |
| 711 | + |
| 712 | + # Emit structured message for the UI (only once, at the end) |
| 713 | + grep_result_msg = GrepResultMessage( |
| 714 | + search_term=search_string, |
| 715 | + directory=directory, |
| 716 | + matches=grep_matches, |
| 717 | + total_matches=len(matches), |
| 718 | + files_searched=unique_files, |
| 719 | + ) |
| 720 | + get_message_bus().emit(grep_result_msg) |
| 721 | + |
| 722 | + return GrepOutput(matches=matches, error=error_message) |
735 | 723 |
|
736 | 724 |
|
737 | 725 | def register_list_files(agent): |
|
0 commit comments