-
Notifications
You must be signed in to change notification settings - Fork 0
Add canonical semantic and grep skill flows #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,115 @@ | ||||||||||||||||||||||
| #!/usr/bin/env python3 | ||||||||||||||||||||||
| """ | ||||||||||||||||||||||
| CodeAlive Grep Search - exact text or regex search across indexed repositories. | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| Usage: | ||||||||||||||||||||||
| python grep.py "AuthService" my-repo | ||||||||||||||||||||||
| python grep.py "auth\\(" my-repo --regex --max-results 25 | ||||||||||||||||||||||
| python grep.py "TODO" workspace:backend-team --path src --ext .py | ||||||||||||||||||||||
| """ | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| import sys | ||||||||||||||||||||||
| from pathlib import Path | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| sys.path.insert(0, str(Path(__file__).parent / "lib")) | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| from api_client import CodeAliveClient | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
|
|
||||||||||||||||||||||
| def format_grep_results(results: dict) -> str: | ||||||||||||||||||||||
| items = results.get("results", []) if isinstance(results, dict) else [] | ||||||||||||||||||||||
| if not items: | ||||||||||||||||||||||
| return "No results found." | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| output = [] | ||||||||||||||||||||||
| for idx, result in enumerate(items, 1): | ||||||||||||||||||||||
| location = result.get("location", {}) | ||||||||||||||||||||||
| file_path = location.get("path") or result.get("path") | ||||||||||||||||||||||
| matches = result.get("matches", []) | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| output.append(f"\n--- Result #{idx} [{result.get('kind', 'Artifact')}] ---") | ||||||||||||||||||||||
| if file_path: | ||||||||||||||||||||||
| output.append(f" File: {file_path}") | ||||||||||||||||||||||
| if result.get("identifier"): | ||||||||||||||||||||||
| output.append(f" Identifier: {result['identifier']}") | ||||||||||||||||||||||
| if result.get("matchCount") is not None: | ||||||||||||||||||||||
| output.append(f" Match count: {result['matchCount']}") | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| for match in matches: | ||||||||||||||||||||||
| output.append( | ||||||||||||||||||||||
| " " | ||||||||||||||||||||||
| f"{match.get('lineNumber', '?')}:{match.get('startColumn', '?')}-" | ||||||||||||||||||||||
| f"{match.get('endColumn', '?')} {match.get('lineText', '')}" | ||||||||||||||||||||||
| ) | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| output.append( | ||||||||||||||||||||||
| "\nHint: match previews are search evidence only. Fetch the full source " | ||||||||||||||||||||||
| "with `python fetch.py <identifier>` or read the local file before reasoning about behavior." | ||||||||||||||||||||||
| ) | ||||||||||||||||||||||
| return "\n".join(output) | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
|
|
||||||||||||||||||||||
| def main(): | ||||||||||||||||||||||
| if len(sys.argv) < 3: | ||||||||||||||||||||||
| print("Error: Missing required arguments.", file=sys.stderr) | ||||||||||||||||||||||
| print( | ||||||||||||||||||||||
| "Usage: python grep.py <query> <data_source> [data_source2...] " | ||||||||||||||||||||||
| "[--regex] [--max-results N] [--path PATH] [--ext EXT]", | ||||||||||||||||||||||
| file=sys.stderr, | ||||||||||||||||||||||
| ) | ||||||||||||||||||||||
| sys.exit(1) | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| query = sys.argv[1] | ||||||||||||||||||||||
| data_sources = [] | ||||||||||||||||||||||
| paths = [] | ||||||||||||||||||||||
| extensions = [] | ||||||||||||||||||||||
| max_results = None | ||||||||||||||||||||||
| regex = False | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| i = 2 | ||||||||||||||||||||||
| while i < len(sys.argv): | ||||||||||||||||||||||
| arg = sys.argv[i] | ||||||||||||||||||||||
| if arg == "--regex": | ||||||||||||||||||||||
| regex = True | ||||||||||||||||||||||
| i += 1 | ||||||||||||||||||||||
| elif arg == "--max-results" and i + 1 < len(sys.argv): | ||||||||||||||||||||||
| max_results = int(sys.argv[i + 1]) | ||||||||||||||||||||||
| i += 2 | ||||||||||||||||||||||
|
Comment on lines
+75
to
+77
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The
Suggested change
|
||||||||||||||||||||||
| elif arg == "--path" and i + 1 < len(sys.argv): | ||||||||||||||||||||||
| paths.append(sys.argv[i + 1]) | ||||||||||||||||||||||
| i += 2 | ||||||||||||||||||||||
| elif arg == "--ext" and i + 1 < len(sys.argv): | ||||||||||||||||||||||
| extensions.append(sys.argv[i + 1]) | ||||||||||||||||||||||
| i += 2 | ||||||||||||||||||||||
| elif arg == "--help": | ||||||||||||||||||||||
| print(__doc__) | ||||||||||||||||||||||
| sys.exit(0) | ||||||||||||||||||||||
| else: | ||||||||||||||||||||||
| data_sources.append(arg) | ||||||||||||||||||||||
| i += 1 | ||||||||||||||||||||||
|
Comment on lines
+87
to
+89
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The current argument parsing logic treats any unknown argument as a data source. This can lead to confusing behavior if a user makes a typo in a flag (e.g., elif arg.startswith("--"):
print(f"Error: Unknown option '{arg}'", file=sys.stderr)
sys.exit(1)
else:
data_sources.append(arg)
i += 1 |
||||||||||||||||||||||
|
|
||||||||||||||||||||||
| if not data_sources: | ||||||||||||||||||||||
| print( | ||||||||||||||||||||||
| "Error: At least one data source is required. Run datasources.py to see available sources.", | ||||||||||||||||||||||
| file=sys.stderr, | ||||||||||||||||||||||
| ) | ||||||||||||||||||||||
| sys.exit(1) | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| try: | ||||||||||||||||||||||
| client = CodeAliveClient() | ||||||||||||||||||||||
| results = client.grep_search( | ||||||||||||||||||||||
| query=query, | ||||||||||||||||||||||
| data_sources=data_sources, | ||||||||||||||||||||||
| paths=paths or None, | ||||||||||||||||||||||
| extensions=extensions or None, | ||||||||||||||||||||||
| max_results=max_results, | ||||||||||||||||||||||
| regex=regex, | ||||||||||||||||||||||
| ) | ||||||||||||||||||||||
| print(format_grep_results(results)) | ||||||||||||||||||||||
| except Exception as e: | ||||||||||||||||||||||
| print(f"Error: {e}", file=sys.stderr) | ||||||||||||||||||||||
| sys.exit(1) | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
|
|
||||||||||||||||||||||
| if __name__ == "__main__": | ||||||||||||||||||||||
| main() | ||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The result formatting in
grep.pyis missing logic to check forfilePathand to extract the file path from theidentifierif explicit path fields are missing. This logic is present insearch.pyand should be included here for consistency and to ensure the file path is displayed whenever possible.