codegraphcontext 0.2.12__py3-none-any.whl → 0.3.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- codegraphcontext/cli/cli_helpers.py +113 -46
- codegraphcontext/cli/main.py +12 -8
- codegraphcontext/core/__init__.py +9 -8
- codegraphcontext/tools/code_finder.py +25 -26
- codegraphcontext/viz/dist/assets/function-calls-BtRHrqa2.png +0 -0
- codegraphcontext/viz/dist/assets/graph-total-D1fBAugo.png +0 -0
- codegraphcontext/viz/dist/assets/hero-graph-2voMJp2a.jpg +0 -0
- codegraphcontext/viz/dist/assets/hierarchy-DGADo0YT.png +0 -0
- codegraphcontext/viz/dist/assets/index-DDAcqlyl.css +1 -0
- codegraphcontext/viz/dist/assets/index-Do_-h1Gi.js +23776 -0
- codegraphcontext/viz/dist/favicon.ico +0 -0
- codegraphcontext/viz/dist/index.html +31 -0
- codegraphcontext/viz/dist/placeholder.svg +1 -0
- codegraphcontext/viz/dist/preview-image.png +0 -0
- codegraphcontext/viz/dist/robots.txt +14 -0
- codegraphcontext/viz/dist/tree-sitter.wasm +0 -0
- codegraphcontext/viz/server.py +178 -0
- {codegraphcontext-0.2.12.dist-info → codegraphcontext-0.3.1.dist-info}/METADATA +15 -2
- {codegraphcontext-0.2.12.dist-info → codegraphcontext-0.3.1.dist-info}/RECORD +23 -10
- {codegraphcontext-0.2.12.dist-info → codegraphcontext-0.3.1.dist-info}/WHEEL +0 -0
- {codegraphcontext-0.2.12.dist-info → codegraphcontext-0.3.1.dist-info}/entry_points.txt +0 -0
- {codegraphcontext-0.2.12.dist-info → codegraphcontext-0.3.1.dist-info}/licenses/LICENSE +0 -0
- {codegraphcontext-0.2.12.dist-info → codegraphcontext-0.3.1.dist-info}/top_level.txt +0 -0
|
@@ -4,8 +4,18 @@ import uuid
|
|
|
4
4
|
import urllib.parse
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
import time
|
|
7
|
+
from typing import Optional
|
|
7
8
|
from rich.console import Console
|
|
8
9
|
from rich.table import Table
|
|
10
|
+
from rich.progress import (
|
|
11
|
+
Progress,
|
|
12
|
+
SpinnerColumn,
|
|
13
|
+
TextColumn,
|
|
14
|
+
BarColumn,
|
|
15
|
+
TaskProgressColumn,
|
|
16
|
+
TimeRemainingColumn,
|
|
17
|
+
MofNCompleteColumn,
|
|
18
|
+
)
|
|
9
19
|
|
|
10
20
|
from ..core import get_database_manager
|
|
11
21
|
from ..core.jobs import JobManager
|
|
@@ -67,6 +77,64 @@ def _initialize_services():
|
|
|
67
77
|
return db_manager, graph_builder, code_finder
|
|
68
78
|
|
|
69
79
|
|
|
80
|
+
async def _run_index_with_progress(graph_builder: GraphBuilder, path_obj: Path, is_dependency: bool = False):
|
|
81
|
+
"""Internal helper to run indexing with a Live progress bar."""
|
|
82
|
+
job_id = graph_builder.job_manager.create_job(str(path_obj), is_dependency=is_dependency)
|
|
83
|
+
|
|
84
|
+
# Create the progress bar
|
|
85
|
+
with Progress(
|
|
86
|
+
SpinnerColumn(),
|
|
87
|
+
TextColumn("[progress.description]{task.description}"),
|
|
88
|
+
BarColumn(),
|
|
89
|
+
TaskProgressColumn(),
|
|
90
|
+
MofNCompleteColumn(),
|
|
91
|
+
TimeRemainingColumn(),
|
|
92
|
+
TextColumn("[dim]{task.fields[filename]}"),
|
|
93
|
+
console=console,
|
|
94
|
+
transient=True,
|
|
95
|
+
) as progress:
|
|
96
|
+
|
|
97
|
+
task_id = progress.add_task(
|
|
98
|
+
"Indexing...",
|
|
99
|
+
total=None, # Will be updated once file discovery is done
|
|
100
|
+
filename=""
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
indexing_task = asyncio.create_task(
|
|
104
|
+
graph_builder.build_graph_from_path_async(path_obj, is_dependency=is_dependency, job_id=job_id)
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
from ..core.jobs import JobStatus
|
|
108
|
+
|
|
109
|
+
# Poll for updates
|
|
110
|
+
while not indexing_task.done():
|
|
111
|
+
job = graph_builder.job_manager.get_job(job_id)
|
|
112
|
+
if job:
|
|
113
|
+
if job.total_files > 0:
|
|
114
|
+
progress.update(task_id, total=job.total_files, completed=job.processed_files)
|
|
115
|
+
|
|
116
|
+
# Update the current filename in the UI
|
|
117
|
+
current_file = job.current_file or ""
|
|
118
|
+
if len(current_file) > 40:
|
|
119
|
+
current_file = "..." + current_file[-37:]
|
|
120
|
+
progress.update(task_id, filename=current_file)
|
|
121
|
+
|
|
122
|
+
if job.status in [JobStatus.COMPLETED, JobStatus.FAILED, JobStatus.CANCELLED]:
|
|
123
|
+
break
|
|
124
|
+
|
|
125
|
+
await asyncio.sleep(0.1)
|
|
126
|
+
|
|
127
|
+
# Wait for actual completion and handle final state
|
|
128
|
+
try:
|
|
129
|
+
await indexing_task
|
|
130
|
+
job = graph_builder.job_manager.get_job(job_id)
|
|
131
|
+
if job and job.status == JobStatus.FAILED:
|
|
132
|
+
error_msg = job.errors[0] if job.errors else "Unknown error"
|
|
133
|
+
raise RuntimeError(error_msg)
|
|
134
|
+
except Exception as e:
|
|
135
|
+
raise e
|
|
136
|
+
|
|
137
|
+
|
|
70
138
|
def index_helper(path: str):
|
|
71
139
|
"""Synchronously indexes a repository."""
|
|
72
140
|
time_start = time.time()
|
|
@@ -107,13 +175,9 @@ def index_helper(path: str):
|
|
|
107
175
|
console.print(f"[yellow]Warning: Could not check file count: {e}. Proceeding with indexing...[/yellow]")
|
|
108
176
|
|
|
109
177
|
console.print(f"Starting indexing for: {path_obj}")
|
|
110
|
-
console.print("[yellow]This may take a few minutes for large repositories...[/yellow]")
|
|
111
|
-
|
|
112
|
-
async def do_index():
|
|
113
|
-
await graph_builder.build_graph_from_path_async(path_obj, is_dependency=False)
|
|
114
178
|
|
|
115
179
|
try:
|
|
116
|
-
asyncio.run(
|
|
180
|
+
asyncio.run(_run_index_with_progress(graph_builder, path_obj, is_dependency=False))
|
|
117
181
|
time_end = time.time()
|
|
118
182
|
elapsed = time_end - time_start
|
|
119
183
|
console.print(f"[green]Successfully finished indexing: {path} in {elapsed:.2f} seconds[/green]")
|
|
@@ -159,13 +223,9 @@ def add_package_helper(package_name: str, language: str):
|
|
|
159
223
|
return
|
|
160
224
|
|
|
161
225
|
console.print(f"Starting indexing for package '{package_name}' at: {package_path}")
|
|
162
|
-
console.print("[yellow]This may take a few minutes...[/yellow]")
|
|
163
|
-
|
|
164
|
-
async def do_index():
|
|
165
|
-
await graph_builder.build_graph_from_path_async(package_path, is_dependency=True)
|
|
166
226
|
|
|
167
227
|
try:
|
|
168
|
-
asyncio.run(
|
|
228
|
+
asyncio.run(_run_index_with_progress(graph_builder, package_path, is_dependency=True))
|
|
169
229
|
console.print(f"[green]Successfully finished indexing package: {package_name}[/green]")
|
|
170
230
|
except Exception as e:
|
|
171
231
|
console.print(f"[bold red]An error occurred during package indexing:[/bold red] {e}")
|
|
@@ -280,44 +340,55 @@ def cypher_helper_visual(query: str):
|
|
|
280
340
|
console.print(f"[bold red]An error occurred while executing query:[/bold red] {e}")
|
|
281
341
|
finally:
|
|
282
342
|
db_manager.close_driver()
|
|
283
|
-
|
|
284
|
-
|
|
285
343
|
import webbrowser
|
|
344
|
+
import urllib.parse
|
|
345
|
+
from ..viz.server import run_server, set_db_manager
|
|
286
346
|
|
|
287
|
-
def visualize_helper(
|
|
288
|
-
""""Generates
|
|
347
|
+
def visualize_helper(repo_path: Optional[str] = None, port: int = 8000):
|
|
348
|
+
""""Generates an interactive visualization using the Playground UI."""
|
|
289
349
|
services = _initialize_services()
|
|
290
350
|
if not all(services):
|
|
291
351
|
return
|
|
292
352
|
|
|
293
353
|
db_manager, _, _ = services
|
|
294
354
|
|
|
295
|
-
#
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
355
|
+
# Set the DB manager for the server
|
|
356
|
+
set_db_manager(db_manager)
|
|
357
|
+
|
|
358
|
+
# Determine the static directory (built React app)
|
|
359
|
+
static_dir = Path(__file__).parent.parent / "viz" / "dist"
|
|
360
|
+
if not static_dir.exists():
|
|
361
|
+
console.print("[yellow]Warning: Visualizer UI assets not found in package. Using fallback static dir.[/yellow]")
|
|
362
|
+
# Fallback for development
|
|
363
|
+
static_dir = Path.cwd() / "website" / "dist"
|
|
364
|
+
|
|
365
|
+
# Construct the URL
|
|
366
|
+
backend_url = f"http://localhost:{port}"
|
|
367
|
+
params = {"backend": backend_url}
|
|
368
|
+
if repo_path:
|
|
369
|
+
params["repo_path"] = str(Path(repo_path).resolve())
|
|
370
|
+
|
|
371
|
+
query_string = urllib.parse.urlencode(params)
|
|
372
|
+
visualization_url = f"{backend_url}/playground?{query_string}"
|
|
373
|
+
|
|
374
|
+
console.print(f"[green]Starting visualizer server on {backend_url}...[/green]")
|
|
375
|
+
console.print(f"[cyan]Opening Playground UI:[/cyan] {visualization_url}")
|
|
376
|
+
|
|
377
|
+
# Open browser in a separate thread/process if possible, or just before starting server
|
|
378
|
+
def open_browser():
|
|
379
|
+
import time
|
|
380
|
+
time.sleep(1.5) # Give the server a moment to start
|
|
381
|
+
webbrowser.open(visualization_url)
|
|
382
|
+
|
|
383
|
+
import threading
|
|
384
|
+
threading.Thread(target=open_browser, daemon=True).start()
|
|
385
|
+
|
|
386
|
+
try:
|
|
387
|
+
run_server(host="127.0.0.1", port=port, static_dir=str(static_dir))
|
|
388
|
+
except Exception as e:
|
|
389
|
+
console.print(f"[bold red]An error occurred while running the server:[/bold red] {e}")
|
|
390
|
+
finally:
|
|
391
|
+
db_manager.close_driver()
|
|
321
392
|
|
|
322
393
|
def _visualize_falkordb(db_manager):
|
|
323
394
|
console.print("[dim]Generating FalkorDB visualization (showing up to 500 relationships)...[/dim]")
|
|
@@ -587,13 +658,9 @@ def reindex_helper(path: str):
|
|
|
587
658
|
return
|
|
588
659
|
|
|
589
660
|
console.print(f"[cyan]Re-indexing: {path_obj}[/cyan]")
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
async def do_index():
|
|
593
|
-
await graph_builder.build_graph_from_path_async(path_obj, is_dependency=False)
|
|
594
|
-
|
|
661
|
+
|
|
595
662
|
try:
|
|
596
|
-
asyncio.run(
|
|
663
|
+
asyncio.run(_run_index_with_progress(graph_builder, path_obj, is_dependency=False))
|
|
597
664
|
time_end = time.time()
|
|
598
665
|
elapsed = time_end - time_start
|
|
599
666
|
console.print(f"[green]Successfully re-indexed: {path} in {elapsed:.2f} seconds[/green]")
|
codegraphcontext/cli/main.py
CHANGED
|
@@ -994,15 +994,15 @@ def delete(
|
|
|
994
994
|
delete_helper(path)
|
|
995
995
|
|
|
996
996
|
@app.command()
|
|
997
|
-
def visualize(
|
|
997
|
+
def visualize(
|
|
998
|
+
repo: Optional[str] = typer.Option(None, "--repo", "-r", help="Path to the repository to visualize."),
|
|
999
|
+
port: int = typer.Option(8000, "--port", "-p", help="Port to run the visualizer server on.")
|
|
1000
|
+
):
|
|
998
1001
|
"""
|
|
999
|
-
|
|
1000
|
-
If no query is provided, a default query will be used.
|
|
1002
|
+
Launches the interactive Playground UI to visualize the code graph.
|
|
1001
1003
|
"""
|
|
1002
|
-
if query is None:
|
|
1003
|
-
query = "MATCH p=()-->() RETURN p"
|
|
1004
1004
|
_load_credentials()
|
|
1005
|
-
visualize_helper(
|
|
1005
|
+
visualize_helper(repo, port)
|
|
1006
1006
|
|
|
1007
1007
|
@app.command("list")
|
|
1008
1008
|
def list_repositories():
|
|
@@ -2145,9 +2145,13 @@ def delete_abbrev(
|
|
|
2145
2145
|
delete(path, all_repos)
|
|
2146
2146
|
|
|
2147
2147
|
@app.command("v", rich_help_panel="Shortcuts")
|
|
2148
|
-
def visualize_abbrev(
|
|
2148
|
+
def visualize_abbrev(
|
|
2149
|
+
repo: Optional[str] = typer.Argument(None, help="Path to the repository to visualize."),
|
|
2150
|
+
port: int = typer.Option(8000, "--port", "-p", help="Port to run the visualizer server on.")
|
|
2151
|
+
):
|
|
2149
2152
|
"""Shortcut for 'cgc visualize'"""
|
|
2150
|
-
|
|
2153
|
+
_load_credentials()
|
|
2154
|
+
visualize_helper(repo, port)
|
|
2151
2155
|
|
|
2152
2156
|
@app.command("w", rich_help_panel="Shortcuts")
|
|
2153
2157
|
def watch_abbrev(path: str = typer.Argument(".", help="Path to watch")):
|
|
@@ -125,7 +125,14 @@ def get_database_manager() -> Union['DatabaseManager', 'FalkorDBManager', 'Falko
|
|
|
125
125
|
else:
|
|
126
126
|
raise ValueError(f"Unknown database type: '{db_type}'. Use 'kuzudb', 'falkordb', 'falkordb-remote', or 'neo4j'.")
|
|
127
127
|
|
|
128
|
-
# 4.
|
|
128
|
+
# 4. Auto-detect: Remote FalkorDB (if FALKORDB_HOST is set)
|
|
129
|
+
# This takes priority over zero-config local backends because it's an explicit signal
|
|
130
|
+
if _is_falkordb_remote_configured():
|
|
131
|
+
from .database_falkordb_remote import FalkorDBRemoteManager
|
|
132
|
+
info_logger("Using remote FalkorDB (auto-detected via FALKORDB_HOST)")
|
|
133
|
+
return FalkorDBRemoteManager()
|
|
134
|
+
|
|
135
|
+
# 5. Implicit Default -> FalkorDB Lite (Unix Zero Config)
|
|
129
136
|
if _is_falkordb_available():
|
|
130
137
|
from .database_falkordb import FalkorDBManager, FalkorDBUnavailableError
|
|
131
138
|
try:
|
|
@@ -139,18 +146,12 @@ def get_database_manager() -> Union['DatabaseManager', 'FalkorDBManager', 'Falko
|
|
|
139
146
|
)
|
|
140
147
|
# fall through to KùzuDB below
|
|
141
148
|
|
|
142
|
-
#
|
|
149
|
+
# 6. Implicit Default -> KùzuDB (Best Zero Config)
|
|
143
150
|
if _is_kuzudb_available():
|
|
144
151
|
from .database_kuzu import KuzuDBManager
|
|
145
152
|
info_logger("Using KùzuDB (default)")
|
|
146
153
|
return KuzuDBManager()
|
|
147
154
|
|
|
148
|
-
# 6. Auto-detect: Remote FalkorDB (if FALKORDB_HOST is set)
|
|
149
|
-
if _is_falkordb_remote_configured():
|
|
150
|
-
from .database_falkordb_remote import FalkorDBRemoteManager
|
|
151
|
-
info_logger("Using remote FalkorDB (auto-detected via FALKORDB_HOST)")
|
|
152
|
-
return FalkorDBRemoteManager()
|
|
153
|
-
|
|
154
155
|
# 7. Fallback if configured
|
|
155
156
|
if _is_neo4j_configured():
|
|
156
157
|
from .database import DatabaseManager
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# src/codegraphcontext/tools/code_finder.py
|
|
2
2
|
import logging
|
|
3
|
-
|
|
3
|
+
|
|
4
4
|
from typing import Any, Dict, List, Literal, Optional
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
|
|
@@ -348,7 +348,6 @@ class CodeFinder:
|
|
|
348
348
|
def what_does_function_call(self, function_name: str, path: Optional[str] = None, repo_path: Optional[str] = None) -> List[Dict]:
|
|
349
349
|
"""Find what functions a specific function calls using CALLS relationships"""
|
|
350
350
|
with self.driver.session() as session:
|
|
351
|
-
repo_filter = "AND called.path STARTS WITH $repo_path" if repo_path else ""
|
|
352
351
|
if path:
|
|
353
352
|
# Convert path to absolute path
|
|
354
353
|
absolute_file_path = str(Path(path).resolve())
|
|
@@ -450,16 +449,16 @@ class CodeFinder:
|
|
|
450
449
|
def find_class_hierarchy(self, class_name: str, path: Optional[str] = None, repo_path: Optional[str] = None) -> Dict[str, Any]:
|
|
451
450
|
"""Find class inheritance relationships using INHERITS relationships"""
|
|
452
451
|
with self.driver.session() as session:
|
|
453
|
-
repo_filter = "
|
|
452
|
+
repo_filter = "AND parent.path STARTS WITH $repo_path" if repo_path else ""
|
|
454
453
|
if path:
|
|
455
454
|
match_clause = "MATCH (child:Class {name: $class_name, path: $path})"
|
|
456
455
|
else:
|
|
457
456
|
match_clause = "MATCH (child:Class {name: $class_name})"
|
|
458
457
|
|
|
459
458
|
parents_query = f"""
|
|
460
|
-
{
|
|
459
|
+
{match_clause}
|
|
461
460
|
MATCH (child)-[:INHERITS]->(parent:Class)
|
|
462
|
-
WHERE 1=1 {
|
|
461
|
+
WHERE 1=1 {repo_filter}
|
|
463
462
|
OPTIONAL MATCH (parent_file:File)-[:CONTAINS]->(parent)
|
|
464
463
|
RETURN DISTINCT
|
|
465
464
|
parent.name as parent_class,
|
|
@@ -471,11 +470,11 @@ class CodeFinder:
|
|
|
471
470
|
"""
|
|
472
471
|
parents_result = session.run(parents_query, class_name=class_name, path=path, repo_path=repo_path)
|
|
473
472
|
|
|
474
|
-
repo_filter_child = "
|
|
473
|
+
repo_filter_child = "AND grandchild.path STARTS WITH $repo_path" if repo_path else ""
|
|
475
474
|
children_query = f"""
|
|
476
|
-
{
|
|
475
|
+
{match_clause}
|
|
477
476
|
MATCH (grandchild:Class)-[:INHERITS]->(child)
|
|
478
|
-
WHERE 1=1 {
|
|
477
|
+
WHERE 1=1 {repo_filter_child}
|
|
479
478
|
OPTIONAL MATCH (child_file:File)-[:CONTAINS]->(grandchild)
|
|
480
479
|
RETURN DISTINCT
|
|
481
480
|
grandchild.name as child_class,
|
|
@@ -513,10 +512,10 @@ class CodeFinder:
|
|
|
513
512
|
def find_function_overrides(self, function_name: str, repo_path: Optional[str] = None) -> List[Dict]:
|
|
514
513
|
"""Find all implementations of a function across different classes"""
|
|
515
514
|
with self.driver.session() as session:
|
|
516
|
-
repo_filter = "
|
|
515
|
+
repo_filter = "AND class.path STARTS WITH $repo_path" if repo_path else ""
|
|
517
516
|
result = session.run(f"""
|
|
518
517
|
MATCH (class:Class)-[:CONTAINS]->(func:Function {{name: $function_name}})
|
|
519
|
-
WHERE 1=1 {
|
|
518
|
+
WHERE 1=1 {repo_filter}
|
|
520
519
|
OPTIONAL MATCH (file:File)-[:CONTAINS]->(class)
|
|
521
520
|
RETURN DISTINCT
|
|
522
521
|
class.name as class_name,
|
|
@@ -821,69 +820,69 @@ class CodeFinder:
|
|
|
821
820
|
"instances": variable_instances.data()
|
|
822
821
|
}
|
|
823
822
|
|
|
824
|
-
def analyze_code_relationships(self, query_type: str, target: str, context: Optional[str] = None) -> Dict[str, Any]:
|
|
823
|
+
def analyze_code_relationships(self, query_type: str, target: str, context: Optional[str] = None, repo_path: Optional[str] = None) -> Dict[str, Any]:
|
|
825
824
|
"""Main method to analyze different types of code relationships with fixed return types"""
|
|
826
825
|
query_type = query_type.lower().strip()
|
|
827
826
|
|
|
828
827
|
try:
|
|
829
828
|
if query_type == "find_callers":
|
|
830
|
-
results = self.who_calls_function(target, context)
|
|
829
|
+
results = self.who_calls_function(target, context, repo_path=repo_path)
|
|
831
830
|
return {
|
|
832
831
|
"query_type": "find_callers", "target": target, "context": context, "results": results,
|
|
833
832
|
"summary": f"Found {len(results)} functions that call '{target}'"
|
|
834
833
|
}
|
|
835
834
|
|
|
836
835
|
elif query_type == "find_callees":
|
|
837
|
-
results = self.what_does_function_call(target, context)
|
|
836
|
+
results = self.what_does_function_call(target, context, repo_path=repo_path)
|
|
838
837
|
return {
|
|
839
838
|
"query_type": "find_callees", "target": target, "context": context, "results": results,
|
|
840
839
|
"summary": f"Function '{target}' calls {len(results)} other functions"
|
|
841
840
|
}
|
|
842
841
|
|
|
843
842
|
elif query_type == "find_importers":
|
|
844
|
-
results = self.who_imports_module(target)
|
|
843
|
+
results = self.who_imports_module(target, repo_path=repo_path)
|
|
845
844
|
return {
|
|
846
845
|
"query_type": "find_importers", "target": target, "results": results,
|
|
847
846
|
"summary": f"Found {len(results)} files that import '{target}'"
|
|
848
847
|
}
|
|
849
848
|
|
|
850
849
|
elif query_type == "find_functions_by_argument":
|
|
851
|
-
results = self.find_functions_by_argument(target, context)
|
|
850
|
+
results = self.find_functions_by_argument(target, context, repo_path=repo_path)
|
|
852
851
|
return {
|
|
853
852
|
"query_type": "find_functions_by_argument", "target": target, "context": context, "results": results,
|
|
854
853
|
"summary": f"Found {len(results)} functions that take '{target}' as an argument"
|
|
855
854
|
}
|
|
856
855
|
|
|
857
856
|
elif query_type == "find_functions_by_decorator":
|
|
858
|
-
results = self.find_functions_by_decorator(target, context)
|
|
857
|
+
results = self.find_functions_by_decorator(target, context, repo_path=repo_path)
|
|
859
858
|
return {
|
|
860
859
|
"query_type": "find_functions_by_decorator", "target": target, "context": context, "results": results,
|
|
861
860
|
"summary": f"Found {len(results)} functions decorated with '{target}'"
|
|
862
861
|
}
|
|
863
862
|
|
|
864
863
|
elif query_type in ["who_modifies", "modifies", "mutations", "changes", "variable_usage"]:
|
|
865
|
-
results = self.who_modifies_variable(target)
|
|
864
|
+
results = self.who_modifies_variable(target, repo_path=repo_path)
|
|
866
865
|
return {
|
|
867
866
|
"query_type": "who_modifies", "target": target, "results": results,
|
|
868
867
|
"summary": f"Found {len(results)} containers that hold variable '{target}'"
|
|
869
868
|
}
|
|
870
869
|
|
|
871
870
|
elif query_type in ["class_hierarchy", "inheritance", "extends"]:
|
|
872
|
-
results = self.find_class_hierarchy(target, context)
|
|
871
|
+
results = self.find_class_hierarchy(target, context, repo_path=repo_path)
|
|
873
872
|
return {
|
|
874
873
|
"query_type": "class_hierarchy", "target": target, "results": results,
|
|
875
874
|
"summary": f"Class '{target}' has {len(results['parent_classes'])} parents, {len(results['child_classes'])} children, and {len(results['methods'])} methods"
|
|
876
875
|
}
|
|
877
876
|
|
|
878
877
|
elif query_type in ["overrides", "implementations", "polymorphism"]:
|
|
879
|
-
results = self.find_function_overrides(target)
|
|
878
|
+
results = self.find_function_overrides(target, repo_path=repo_path)
|
|
880
879
|
return {
|
|
881
880
|
"query_type": "overrides", "target": target, "results": results,
|
|
882
881
|
"summary": f"Found {len(results)} implementations of function '{target}'"
|
|
883
882
|
}
|
|
884
883
|
|
|
885
884
|
elif query_type in ["dead_code", "unused", "unreachable"]:
|
|
886
|
-
results = self.find_dead_code()
|
|
885
|
+
results = self.find_dead_code(repo_path=repo_path)
|
|
887
886
|
return {
|
|
888
887
|
"query_type": "dead_code", "results": results,
|
|
889
888
|
"summary": f"Found {len(results['potentially_unused_functions'])} potentially unused functions"
|
|
@@ -891,21 +890,21 @@ class CodeFinder:
|
|
|
891
890
|
|
|
892
891
|
elif query_type == "find_complexity":
|
|
893
892
|
limit = int(context) if context and context.isdigit() else 10
|
|
894
|
-
results = self.find_most_complex_functions(limit)
|
|
893
|
+
results = self.find_most_complex_functions(limit, repo_path=repo_path)
|
|
895
894
|
return {
|
|
896
895
|
"query_type": "find_complexity", "limit": limit, "results": results,
|
|
897
896
|
"summary": f"Found the top {len(results)} most complex functions"
|
|
898
897
|
}
|
|
899
898
|
|
|
900
899
|
elif query_type == "find_all_callers":
|
|
901
|
-
results = self.find_all_callers(target, context)
|
|
900
|
+
results = self.find_all_callers(target, context, repo_path=repo_path)
|
|
902
901
|
return {
|
|
903
902
|
"query_type": "find_all_callers", "target": target, "context": context, "results": results,
|
|
904
903
|
"summary": f"Found {len(results)} direct and indirect callers of '{target}'"
|
|
905
904
|
}
|
|
906
905
|
|
|
907
906
|
elif query_type == "find_all_callees":
|
|
908
|
-
results = self.find_all_callees(target, context)
|
|
907
|
+
results = self.find_all_callees(target, context, repo_path=repo_path)
|
|
909
908
|
return {
|
|
910
909
|
"query_type": "find_all_callees", "target": target, "context": context, "results": results,
|
|
911
910
|
"summary": f"Found {len(results)} direct and indirect callees of '{target}'"
|
|
@@ -916,7 +915,7 @@ class CodeFinder:
|
|
|
916
915
|
start_func, end_func = target.split('->', 1)
|
|
917
916
|
# max_depth can be passed as context, default to 5 if not provided or invalid
|
|
918
917
|
max_depth = int(context) if context and context.isdigit() else 5
|
|
919
|
-
results = self.find_function_call_chain(start_func.strip(), end_func.strip(), max_depth)
|
|
918
|
+
results = self.find_function_call_chain(start_func.strip(), end_func.strip(), max_depth, repo_path=repo_path)
|
|
920
919
|
return {
|
|
921
920
|
"query_type": "call_chain", "target": target, "results": results,
|
|
922
921
|
"summary": f"Found {len(results)} call chains from '{start_func.strip()}' to '{end_func.strip()}' (max depth: {max_depth})"
|
|
@@ -928,14 +927,14 @@ class CodeFinder:
|
|
|
928
927
|
}
|
|
929
928
|
|
|
930
929
|
elif query_type in ["module_deps", "module_dependencies", "module_usage"]:
|
|
931
|
-
results = self.find_module_dependencies(target)
|
|
930
|
+
results = self.find_module_dependencies(target, repo_path=repo_path)
|
|
932
931
|
return {
|
|
933
932
|
"query_type": "module_dependencies", "target": target, "results": results,
|
|
934
933
|
"summary": f"Module '{target}' is imported by {len(results['imported_by_files'])} files"
|
|
935
934
|
}
|
|
936
935
|
|
|
937
936
|
elif query_type in ["variable_scope", "var_scope", "variable_usage_scope"]:
|
|
938
|
-
results = self.find_variable_usage_scope(target)
|
|
937
|
+
results = self.find_variable_usage_scope(target, repo_path=repo_path)
|
|
939
938
|
return {
|
|
940
939
|
"query_type": "variable_scope", "target": target, "results": results,
|
|
941
940
|
"summary": f"Variable '{target}' has {len(results['instances'])} instances across different scopes"
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|