code-graph-builder 0.2.0__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.
- code_graph_builder/__init__.py +82 -0
- code_graph_builder/builder.py +366 -0
- code_graph_builder/cgb_cli.py +32 -0
- code_graph_builder/cli.py +564 -0
- code_graph_builder/commands_cli.py +1288 -0
- code_graph_builder/config.py +340 -0
- code_graph_builder/constants.py +708 -0
- code_graph_builder/embeddings/__init__.py +40 -0
- code_graph_builder/embeddings/qwen3_embedder.py +573 -0
- code_graph_builder/embeddings/vector_store.py +584 -0
- code_graph_builder/examples/__init__.py +0 -0
- code_graph_builder/examples/example_configuration.py +276 -0
- code_graph_builder/examples/example_kuzu_usage.py +109 -0
- code_graph_builder/examples/example_semantic_search_full.py +347 -0
- code_graph_builder/examples/generate_wiki.py +915 -0
- code_graph_builder/examples/graph_export_example.py +100 -0
- code_graph_builder/examples/rag_example.py +206 -0
- code_graph_builder/examples/test_cli_demo.py +129 -0
- code_graph_builder/examples/test_embedding_api.py +153 -0
- code_graph_builder/examples/test_kuzu_local.py +190 -0
- code_graph_builder/examples/test_rag_redis.py +390 -0
- code_graph_builder/graph_updater.py +605 -0
- code_graph_builder/guidance/__init__.py +1 -0
- code_graph_builder/guidance/agent.py +123 -0
- code_graph_builder/guidance/prompts.py +74 -0
- code_graph_builder/guidance/toolset.py +264 -0
- code_graph_builder/language_spec.py +536 -0
- code_graph_builder/mcp/__init__.py +21 -0
- code_graph_builder/mcp/api_doc_generator.py +764 -0
- code_graph_builder/mcp/file_editor.py +207 -0
- code_graph_builder/mcp/pipeline.py +777 -0
- code_graph_builder/mcp/server.py +161 -0
- code_graph_builder/mcp/tools.py +1800 -0
- code_graph_builder/models.py +115 -0
- code_graph_builder/parser_loader.py +344 -0
- code_graph_builder/parsers/__init__.py +7 -0
- code_graph_builder/parsers/call_processor.py +306 -0
- code_graph_builder/parsers/call_resolver.py +139 -0
- code_graph_builder/parsers/definition_processor.py +796 -0
- code_graph_builder/parsers/factory.py +119 -0
- code_graph_builder/parsers/import_processor.py +293 -0
- code_graph_builder/parsers/structure_processor.py +145 -0
- code_graph_builder/parsers/type_inference.py +143 -0
- code_graph_builder/parsers/utils.py +134 -0
- code_graph_builder/rag/__init__.py +68 -0
- code_graph_builder/rag/camel_agent.py +429 -0
- code_graph_builder/rag/client.py +298 -0
- code_graph_builder/rag/config.py +239 -0
- code_graph_builder/rag/cypher_generator.py +67 -0
- code_graph_builder/rag/llm_backend.py +210 -0
- code_graph_builder/rag/markdown_generator.py +352 -0
- code_graph_builder/rag/prompt_templates.py +440 -0
- code_graph_builder/rag/rag_engine.py +640 -0
- code_graph_builder/rag/review_report.md +172 -0
- code_graph_builder/rag/tests/__init__.py +3 -0
- code_graph_builder/rag/tests/test_camel_agent.py +313 -0
- code_graph_builder/rag/tests/test_client.py +221 -0
- code_graph_builder/rag/tests/test_config.py +177 -0
- code_graph_builder/rag/tests/test_markdown_generator.py +240 -0
- code_graph_builder/rag/tests/test_prompt_templates.py +160 -0
- code_graph_builder/services/__init__.py +39 -0
- code_graph_builder/services/graph_service.py +465 -0
- code_graph_builder/services/kuzu_service.py +665 -0
- code_graph_builder/services/memory_service.py +171 -0
- code_graph_builder/settings.py +75 -0
- code_graph_builder/tests/ACCEPTANCE_CRITERIA_PHASE2.md +401 -0
- code_graph_builder/tests/__init__.py +1 -0
- code_graph_builder/tests/run_acceptance_check.py +378 -0
- code_graph_builder/tests/test_api_find.py +231 -0
- code_graph_builder/tests/test_api_find_integration.py +226 -0
- code_graph_builder/tests/test_basic.py +78 -0
- code_graph_builder/tests/test_c_api_extraction.py +388 -0
- code_graph_builder/tests/test_call_resolution_scenarios.py +504 -0
- code_graph_builder/tests/test_embedder.py +411 -0
- code_graph_builder/tests/test_integration_semantic.py +434 -0
- code_graph_builder/tests/test_mcp_protocol.py +298 -0
- code_graph_builder/tests/test_mcp_user_flow.py +190 -0
- code_graph_builder/tests/test_rag.py +404 -0
- code_graph_builder/tests/test_settings.py +135 -0
- code_graph_builder/tests/test_step1_graph_build.py +264 -0
- code_graph_builder/tests/test_step2_api_docs.py +323 -0
- code_graph_builder/tests/test_step3_embedding.py +278 -0
- code_graph_builder/tests/test_vector_store.py +552 -0
- code_graph_builder/tools/__init__.py +40 -0
- code_graph_builder/tools/graph_query.py +495 -0
- code_graph_builder/tools/semantic_search.py +387 -0
- code_graph_builder/types.py +333 -0
- code_graph_builder/utils/__init__.py +0 -0
- code_graph_builder/utils/path_utils.py +30 -0
- code_graph_builder-0.2.0.dist-info/METADATA +321 -0
- code_graph_builder-0.2.0.dist-info/RECORD +93 -0
- code_graph_builder-0.2.0.dist-info/WHEEL +4 -0
- code_graph_builder-0.2.0.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,564 @@
|
|
|
1
|
+
"""Command-line interface for Code Graph Builder.
|
|
2
|
+
|
|
3
|
+
Examples:
|
|
4
|
+
# Scan a repository with Kùzu backend
|
|
5
|
+
$ code-graph-builder scan /path/to/repo --backend kuzu --db-path ./graph.db
|
|
6
|
+
|
|
7
|
+
# Scan with specific exclusions
|
|
8
|
+
$ code-graph-builder scan /path/to/repo --exclude tests,docs --exclude-pattern "*.md"
|
|
9
|
+
|
|
10
|
+
# Query the graph
|
|
11
|
+
$ code-graph-builder query "MATCH (f:Function) RETURN f.name LIMIT 5" --db-path ./graph.db
|
|
12
|
+
|
|
13
|
+
# Export to JSON
|
|
14
|
+
$ code-graph-builder export /path/to/repo --output ./output.json
|
|
15
|
+
|
|
16
|
+
# Use configuration file
|
|
17
|
+
$ code-graph-builder scan /path/to/repo --config ./config.yaml
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
import argparse
|
|
23
|
+
import json
|
|
24
|
+
import sys
|
|
25
|
+
from pathlib import Path
|
|
26
|
+
from typing import Any
|
|
27
|
+
|
|
28
|
+
from loguru import logger
|
|
29
|
+
|
|
30
|
+
from . import __version__
|
|
31
|
+
from .builder import CodeGraphBuilder
|
|
32
|
+
from .config import (
|
|
33
|
+
KuzuConfig,
|
|
34
|
+
MemgraphConfig,
|
|
35
|
+
MemoryConfig,
|
|
36
|
+
OutputConfig,
|
|
37
|
+
ScanConfig,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def setup_logging(verbose: bool = False) -> None:
|
|
42
|
+
"""Setup logging configuration."""
|
|
43
|
+
level = "DEBUG" if verbose else "INFO"
|
|
44
|
+
logger.remove()
|
|
45
|
+
logger.add(
|
|
46
|
+
sys.stderr,
|
|
47
|
+
level=level,
|
|
48
|
+
format="<green>{time:YYYY-MM-DD HH:mm:ss}</green> | <level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>",
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def load_config_file(config_path: str | Path) -> dict[str, Any]:
|
|
53
|
+
"""Load configuration from YAML or JSON file."""
|
|
54
|
+
config_path = Path(config_path)
|
|
55
|
+
|
|
56
|
+
if not config_path.exists():
|
|
57
|
+
raise FileNotFoundError(f"Config file not found: {config_path}")
|
|
58
|
+
|
|
59
|
+
if config_path.suffix in (".yaml", ".yml"):
|
|
60
|
+
try:
|
|
61
|
+
import yaml
|
|
62
|
+
|
|
63
|
+
with open(config_path) as f:
|
|
64
|
+
return yaml.safe_load(f)
|
|
65
|
+
except ImportError:
|
|
66
|
+
raise ImportError("PyYAML is required for YAML config files. Install with: pip install pyyaml")
|
|
67
|
+
elif config_path.suffix == ".json":
|
|
68
|
+
with open(config_path) as f:
|
|
69
|
+
return json.load(f)
|
|
70
|
+
else:
|
|
71
|
+
raise ValueError(f"Unsupported config file format: {config_path.suffix}")
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def create_builder_from_args(args: argparse.Namespace) -> CodeGraphBuilder:
|
|
75
|
+
"""Create CodeGraphBuilder from command-line arguments."""
|
|
76
|
+
# Load config file if specified
|
|
77
|
+
config = {}
|
|
78
|
+
if hasattr(args, 'config') and args.config:
|
|
79
|
+
config = load_config_file(args.config)
|
|
80
|
+
|
|
81
|
+
# Determine backend
|
|
82
|
+
backend = getattr(args, 'backend', None) or config.get("backend", "kuzu")
|
|
83
|
+
|
|
84
|
+
# Build backend config
|
|
85
|
+
backend_config = config.get("backend_config", {})
|
|
86
|
+
if backend == "kuzu":
|
|
87
|
+
if getattr(args, 'db_path', None):
|
|
88
|
+
backend_config["db_path"] = args.db_path
|
|
89
|
+
if getattr(args, 'batch_size', None):
|
|
90
|
+
backend_config["batch_size"] = args.batch_size
|
|
91
|
+
elif backend == "memgraph":
|
|
92
|
+
if getattr(args, 'host', None):
|
|
93
|
+
backend_config["host"] = args.host
|
|
94
|
+
if getattr(args, 'port', None):
|
|
95
|
+
backend_config["port"] = args.port
|
|
96
|
+
if getattr(args, 'username', None):
|
|
97
|
+
backend_config["username"] = args.username
|
|
98
|
+
if getattr(args, 'password', None):
|
|
99
|
+
backend_config["password"] = args.password
|
|
100
|
+
if getattr(args, 'batch_size', None):
|
|
101
|
+
backend_config["batch_size"] = args.batch_size
|
|
102
|
+
|
|
103
|
+
# Build scan config
|
|
104
|
+
scan_config = config.get("scan_config", {})
|
|
105
|
+
if getattr(args, 'exclude', None):
|
|
106
|
+
# Parse comma-separated exclusions
|
|
107
|
+
exclude_set = set()
|
|
108
|
+
for item in args.exclude:
|
|
109
|
+
exclude_set.update(item.split(","))
|
|
110
|
+
scan_config["exclude_patterns"] = exclude_set
|
|
111
|
+
if getattr(args, 'exclude_pattern', None):
|
|
112
|
+
scan_config.setdefault("exclude_patterns", set()).update(args.exclude_pattern)
|
|
113
|
+
if getattr(args, 'language', None):
|
|
114
|
+
scan_config["include_languages"] = set(args.language.split(","))
|
|
115
|
+
if getattr(args, 'max_file_size', None):
|
|
116
|
+
scan_config["max_file_size"] = args.max_file_size
|
|
117
|
+
|
|
118
|
+
# Create builder
|
|
119
|
+
return CodeGraphBuilder(
|
|
120
|
+
repo_path=args.repo_path,
|
|
121
|
+
backend=backend,
|
|
122
|
+
backend_config=backend_config,
|
|
123
|
+
scan_config=scan_config,
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def cmd_scan(args: argparse.Namespace) -> int:
|
|
128
|
+
"""Execute the scan command."""
|
|
129
|
+
setup_logging(args.verbose)
|
|
130
|
+
|
|
131
|
+
try:
|
|
132
|
+
logger.info(f"Starting scan of: {args.repo_path}")
|
|
133
|
+
logger.info(f"Backend: {args.backend or 'kuzu'}")
|
|
134
|
+
|
|
135
|
+
builder = create_builder_from_args(args)
|
|
136
|
+
|
|
137
|
+
# Build the graph
|
|
138
|
+
result = builder.build_graph(clean=args.clean)
|
|
139
|
+
|
|
140
|
+
print()
|
|
141
|
+
print("=" * 60)
|
|
142
|
+
print("SCAN COMPLETE")
|
|
143
|
+
print("=" * 60)
|
|
144
|
+
print(f"Repository: {result.project_name}")
|
|
145
|
+
print(f"Nodes created: {result.nodes_created}")
|
|
146
|
+
print(f"Relationships created: {result.relationships_created}")
|
|
147
|
+
print(f"Functions found: {result.functions_found}")
|
|
148
|
+
print(f"Classes found: {result.classes_found}")
|
|
149
|
+
print(f"Files processed: {result.files_processed}")
|
|
150
|
+
|
|
151
|
+
if args.backend == "kuzu" or (not args.backend and args.db_path):
|
|
152
|
+
db_path = args.db_path or f"./{Path(args.repo_path).name}_graph.db"
|
|
153
|
+
print(f"Database saved to: {db_path}")
|
|
154
|
+
|
|
155
|
+
# Export to JSON if requested
|
|
156
|
+
if args.output:
|
|
157
|
+
logger.info(f"Exporting to: {args.output}")
|
|
158
|
+
data = builder.export_graph()
|
|
159
|
+
with open(args.output, "w") as f:
|
|
160
|
+
json.dump(data, f, indent=2, default=str)
|
|
161
|
+
print(f"Exported to: {args.output}")
|
|
162
|
+
|
|
163
|
+
return 0
|
|
164
|
+
|
|
165
|
+
except Exception as e:
|
|
166
|
+
logger.error(f"Scan failed: {e}")
|
|
167
|
+
if args.verbose:
|
|
168
|
+
import traceback
|
|
169
|
+
|
|
170
|
+
traceback.print_exc()
|
|
171
|
+
return 1
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def cmd_query(args: argparse.Namespace) -> int:
|
|
175
|
+
"""Execute the query command."""
|
|
176
|
+
setup_logging(args.verbose)
|
|
177
|
+
|
|
178
|
+
try:
|
|
179
|
+
# Determine backend from args
|
|
180
|
+
backend = args.backend or "kuzu"
|
|
181
|
+
backend_config = {"db_path": args.db_path} if args.db_path else {}
|
|
182
|
+
|
|
183
|
+
builder = CodeGraphBuilder(
|
|
184
|
+
repo_path=args.repo_path or ".",
|
|
185
|
+
backend=backend,
|
|
186
|
+
backend_config=backend_config,
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
logger.info(f"Executing query: {args.cypher_query}")
|
|
190
|
+
results = builder.query(args.cypher_query)
|
|
191
|
+
|
|
192
|
+
print()
|
|
193
|
+
print("=" * 60)
|
|
194
|
+
print("QUERY RESULTS")
|
|
195
|
+
print("=" * 60)
|
|
196
|
+
print(f"Query: {args.cypher_query}")
|
|
197
|
+
print(f"Results: {len(results)}")
|
|
198
|
+
print()
|
|
199
|
+
|
|
200
|
+
if results:
|
|
201
|
+
# Print as table
|
|
202
|
+
if args.format == "table":
|
|
203
|
+
headers = list(results[0].keys())
|
|
204
|
+
# Calculate column widths
|
|
205
|
+
widths = {h: len(h) for h in headers}
|
|
206
|
+
for row in results:
|
|
207
|
+
for h in headers:
|
|
208
|
+
widths[h] = max(widths[h], len(str(row.get(h, ""))))
|
|
209
|
+
|
|
210
|
+
# Print header
|
|
211
|
+
header_line = " | ".join(h.ljust(widths[h]) for h in headers)
|
|
212
|
+
print(header_line)
|
|
213
|
+
print("-" * len(header_line))
|
|
214
|
+
|
|
215
|
+
# Print rows
|
|
216
|
+
for row in results:
|
|
217
|
+
print(" | ".join(str(row.get(h, "")).ljust(widths[h]) for h in headers))
|
|
218
|
+
else:
|
|
219
|
+
# JSON format
|
|
220
|
+
for i, row in enumerate(results, 1):
|
|
221
|
+
print(f"{i}. {json.dumps(row, default=str)}")
|
|
222
|
+
else:
|
|
223
|
+
print("No results found.")
|
|
224
|
+
|
|
225
|
+
return 0
|
|
226
|
+
|
|
227
|
+
except Exception as e:
|
|
228
|
+
logger.error(f"Query failed: {e}")
|
|
229
|
+
if args.verbose:
|
|
230
|
+
import traceback
|
|
231
|
+
|
|
232
|
+
traceback.print_exc()
|
|
233
|
+
return 1
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def cmd_export(args: argparse.Namespace) -> int:
|
|
237
|
+
"""Execute the export command."""
|
|
238
|
+
setup_logging(args.verbose)
|
|
239
|
+
|
|
240
|
+
try:
|
|
241
|
+
builder = create_builder_from_args(args)
|
|
242
|
+
|
|
243
|
+
logger.info(f"Exporting graph from: {args.repo_path}")
|
|
244
|
+
|
|
245
|
+
# Build if not already built
|
|
246
|
+
if args.build:
|
|
247
|
+
logger.info("Building graph first...")
|
|
248
|
+
builder.build_graph(clean=args.clean)
|
|
249
|
+
|
|
250
|
+
data = builder.export_graph()
|
|
251
|
+
|
|
252
|
+
output_path = Path(args.output)
|
|
253
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
254
|
+
|
|
255
|
+
with open(output_path, "w") as f:
|
|
256
|
+
json.dump(data, f, indent=2, default=str)
|
|
257
|
+
|
|
258
|
+
print()
|
|
259
|
+
print("=" * 60)
|
|
260
|
+
print("EXPORT COMPLETE")
|
|
261
|
+
print("=" * 60)
|
|
262
|
+
print(f"Output: {output_path.absolute()}")
|
|
263
|
+
print(f"Nodes: {len(data.get('nodes', []))}")
|
|
264
|
+
print(f"Relationships: {len(data.get('relationships', []))}")
|
|
265
|
+
|
|
266
|
+
return 0
|
|
267
|
+
|
|
268
|
+
except Exception as e:
|
|
269
|
+
logger.error(f"Export failed: {e}")
|
|
270
|
+
if args.verbose:
|
|
271
|
+
import traceback
|
|
272
|
+
|
|
273
|
+
traceback.print_exc()
|
|
274
|
+
return 1
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def cmd_stats(args: argparse.Namespace) -> int:
|
|
278
|
+
"""Execute the stats command."""
|
|
279
|
+
setup_logging(args.verbose)
|
|
280
|
+
|
|
281
|
+
try:
|
|
282
|
+
backend = args.backend or "kuzu"
|
|
283
|
+
backend_config = {"db_path": args.db_path} if args.db_path else {}
|
|
284
|
+
|
|
285
|
+
builder = CodeGraphBuilder(
|
|
286
|
+
repo_path=args.repo_path or ".",
|
|
287
|
+
backend=backend,
|
|
288
|
+
backend_config=backend_config,
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
stats = builder.get_statistics()
|
|
292
|
+
|
|
293
|
+
print()
|
|
294
|
+
print("=" * 60)
|
|
295
|
+
print("GRAPH STATISTICS")
|
|
296
|
+
print("=" * 60)
|
|
297
|
+
print(f"Total nodes: {stats.get('total_nodes', 0)}")
|
|
298
|
+
print(f"Total relationships: {stats.get('total_relationships', 0)}")
|
|
299
|
+
print()
|
|
300
|
+
|
|
301
|
+
node_labels = stats.get("node_labels", {})
|
|
302
|
+
if node_labels:
|
|
303
|
+
print("Node types:")
|
|
304
|
+
for label, count in sorted(node_labels.items(), key=lambda x: -x[1]):
|
|
305
|
+
label_str = str(label)
|
|
306
|
+
print(f" {label_str:20s}: {count:5d}")
|
|
307
|
+
print()
|
|
308
|
+
|
|
309
|
+
rel_types = stats.get("relationship_types", {})
|
|
310
|
+
if rel_types:
|
|
311
|
+
print("Relationship types:")
|
|
312
|
+
for rel_type, count in sorted(rel_types.items(), key=lambda x: -x[1]):
|
|
313
|
+
rel_str = str(rel_type)
|
|
314
|
+
print(f" {rel_str:20s}: {count:5d}")
|
|
315
|
+
|
|
316
|
+
return 0
|
|
317
|
+
|
|
318
|
+
except Exception as e:
|
|
319
|
+
logger.error(f"Stats failed: {e}")
|
|
320
|
+
if args.verbose:
|
|
321
|
+
import traceback
|
|
322
|
+
|
|
323
|
+
traceback.print_exc()
|
|
324
|
+
return 1
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
def main() -> int:
|
|
328
|
+
"""Main entry point for CLI."""
|
|
329
|
+
parser = argparse.ArgumentParser(
|
|
330
|
+
prog="code-graph-builder",
|
|
331
|
+
description="Build and query code knowledge graphs",
|
|
332
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
333
|
+
epilog="""
|
|
334
|
+
Examples:
|
|
335
|
+
# Scan repository with Kùzu backend
|
|
336
|
+
code-graph-builder scan /path/to/repo --db-path ./graph.db
|
|
337
|
+
|
|
338
|
+
# Scan with exclusions
|
|
339
|
+
code-graph-builder scan /path/to/repo --exclude tests,docs --exclude-pattern "*.md"
|
|
340
|
+
|
|
341
|
+
# Query the graph
|
|
342
|
+
code-graph-builder query "MATCH (f:Function) RETURN f.name LIMIT 5" --db-path ./graph.db
|
|
343
|
+
|
|
344
|
+
# Export to JSON
|
|
345
|
+
code-graph-builder export /path/to/repo --output ./graph.json --build
|
|
346
|
+
|
|
347
|
+
# Show statistics
|
|
348
|
+
code-graph-builder stats --db-path ./graph.db
|
|
349
|
+
|
|
350
|
+
For more information, visit: https://github.com/your-repo/code-graph-builder
|
|
351
|
+
""",
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
parser.add_argument(
|
|
355
|
+
"--version",
|
|
356
|
+
action="version",
|
|
357
|
+
version=f"%(prog)s {__version__}",
|
|
358
|
+
)
|
|
359
|
+
parser.add_argument(
|
|
360
|
+
"-v",
|
|
361
|
+
"--verbose",
|
|
362
|
+
action="store_true",
|
|
363
|
+
help="Enable verbose output",
|
|
364
|
+
)
|
|
365
|
+
|
|
366
|
+
subparsers = parser.add_subparsers(dest="command", help="Available commands")
|
|
367
|
+
|
|
368
|
+
# Scan command
|
|
369
|
+
scan_parser = subparsers.add_parser(
|
|
370
|
+
"scan",
|
|
371
|
+
help="Scan a repository and build the knowledge graph",
|
|
372
|
+
description="Scan source code and build a knowledge graph.",
|
|
373
|
+
)
|
|
374
|
+
scan_parser.add_argument(
|
|
375
|
+
"repo_path",
|
|
376
|
+
type=str,
|
|
377
|
+
help="Path to the repository to scan",
|
|
378
|
+
)
|
|
379
|
+
scan_parser.add_argument(
|
|
380
|
+
"--backend",
|
|
381
|
+
choices=["kuzu", "memgraph", "memory"],
|
|
382
|
+
default="kuzu",
|
|
383
|
+
help="Storage backend (default: kuzu)",
|
|
384
|
+
)
|
|
385
|
+
scan_parser.add_argument(
|
|
386
|
+
"--db-path",
|
|
387
|
+
type=str,
|
|
388
|
+
help="Path to store the database (for Kùzu backend)",
|
|
389
|
+
)
|
|
390
|
+
scan_parser.add_argument(
|
|
391
|
+
"--host",
|
|
392
|
+
type=str,
|
|
393
|
+
help="Memgraph host (for Memgraph backend)",
|
|
394
|
+
)
|
|
395
|
+
scan_parser.add_argument(
|
|
396
|
+
"--port",
|
|
397
|
+
type=int,
|
|
398
|
+
help="Memgraph port (for Memgraph backend)",
|
|
399
|
+
)
|
|
400
|
+
scan_parser.add_argument(
|
|
401
|
+
"--username",
|
|
402
|
+
type=str,
|
|
403
|
+
help="Memgraph username",
|
|
404
|
+
)
|
|
405
|
+
scan_parser.add_argument(
|
|
406
|
+
"--password",
|
|
407
|
+
type=str,
|
|
408
|
+
help="Memgraph password",
|
|
409
|
+
)
|
|
410
|
+
scan_parser.add_argument(
|
|
411
|
+
"--batch-size",
|
|
412
|
+
type=int,
|
|
413
|
+
help="Batch size for database writes",
|
|
414
|
+
)
|
|
415
|
+
scan_parser.add_argument(
|
|
416
|
+
"--exclude",
|
|
417
|
+
action="append",
|
|
418
|
+
help="Comma-separated patterns to exclude (can be used multiple times)",
|
|
419
|
+
)
|
|
420
|
+
scan_parser.add_argument(
|
|
421
|
+
"--exclude-pattern",
|
|
422
|
+
action="append",
|
|
423
|
+
help="Additional exclude pattern (can be used multiple times)",
|
|
424
|
+
)
|
|
425
|
+
scan_parser.add_argument(
|
|
426
|
+
"--language",
|
|
427
|
+
type=str,
|
|
428
|
+
help="Comma-separated list of languages to include",
|
|
429
|
+
)
|
|
430
|
+
scan_parser.add_argument(
|
|
431
|
+
"--max-file-size",
|
|
432
|
+
type=int,
|
|
433
|
+
help="Maximum file size in bytes",
|
|
434
|
+
)
|
|
435
|
+
scan_parser.add_argument(
|
|
436
|
+
"--clean",
|
|
437
|
+
action="store_true",
|
|
438
|
+
help="Clean existing database before scanning",
|
|
439
|
+
)
|
|
440
|
+
scan_parser.add_argument(
|
|
441
|
+
"--output",
|
|
442
|
+
"-o",
|
|
443
|
+
type=str,
|
|
444
|
+
help="Export graph to JSON file after scanning",
|
|
445
|
+
)
|
|
446
|
+
scan_parser.add_argument(
|
|
447
|
+
"--config",
|
|
448
|
+
"-c",
|
|
449
|
+
type=str,
|
|
450
|
+
help="Configuration file (YAML or JSON)",
|
|
451
|
+
)
|
|
452
|
+
scan_parser.set_defaults(func=cmd_scan)
|
|
453
|
+
|
|
454
|
+
# Query command
|
|
455
|
+
query_parser = subparsers.add_parser(
|
|
456
|
+
"query",
|
|
457
|
+
help="Execute a Cypher query against the graph",
|
|
458
|
+
description="Query the knowledge graph using Cypher.",
|
|
459
|
+
)
|
|
460
|
+
query_parser.add_argument(
|
|
461
|
+
"cypher_query",
|
|
462
|
+
type=str,
|
|
463
|
+
help="Cypher query to execute",
|
|
464
|
+
)
|
|
465
|
+
query_parser.add_argument(
|
|
466
|
+
"--repo-path",
|
|
467
|
+
type=str,
|
|
468
|
+
help="Path to the repository (for reference)",
|
|
469
|
+
)
|
|
470
|
+
query_parser.add_argument(
|
|
471
|
+
"--backend",
|
|
472
|
+
choices=["kuzu", "memgraph", "memory"],
|
|
473
|
+
default="kuzu",
|
|
474
|
+
help="Storage backend (default: kuzu)",
|
|
475
|
+
)
|
|
476
|
+
query_parser.add_argument(
|
|
477
|
+
"--db-path",
|
|
478
|
+
type=str,
|
|
479
|
+
help="Path to the database (for Kùzu backend)",
|
|
480
|
+
)
|
|
481
|
+
query_parser.add_argument(
|
|
482
|
+
"--format",
|
|
483
|
+
choices=["table", "json"],
|
|
484
|
+
default="table",
|
|
485
|
+
help="Output format (default: table)",
|
|
486
|
+
)
|
|
487
|
+
query_parser.set_defaults(func=cmd_query)
|
|
488
|
+
|
|
489
|
+
# Export command
|
|
490
|
+
export_parser = subparsers.add_parser(
|
|
491
|
+
"export",
|
|
492
|
+
help="Export the graph to JSON",
|
|
493
|
+
description="Export the knowledge graph to a JSON file.",
|
|
494
|
+
)
|
|
495
|
+
export_parser.add_argument(
|
|
496
|
+
"repo_path",
|
|
497
|
+
type=str,
|
|
498
|
+
help="Path to the repository",
|
|
499
|
+
)
|
|
500
|
+
export_parser.add_argument(
|
|
501
|
+
"--output",
|
|
502
|
+
"-o",
|
|
503
|
+
type=str,
|
|
504
|
+
required=True,
|
|
505
|
+
help="Output JSON file path",
|
|
506
|
+
)
|
|
507
|
+
export_parser.add_argument(
|
|
508
|
+
"--backend",
|
|
509
|
+
choices=["kuzu", "memgraph", "memory"],
|
|
510
|
+
default="memory",
|
|
511
|
+
help="Storage backend (default: memory)",
|
|
512
|
+
)
|
|
513
|
+
export_parser.add_argument(
|
|
514
|
+
"--build",
|
|
515
|
+
action="store_true",
|
|
516
|
+
help="Build the graph before exporting",
|
|
517
|
+
)
|
|
518
|
+
export_parser.add_argument(
|
|
519
|
+
"--clean",
|
|
520
|
+
action="store_true",
|
|
521
|
+
help="Clean existing data before building",
|
|
522
|
+
)
|
|
523
|
+
export_parser.add_argument(
|
|
524
|
+
"--exclude",
|
|
525
|
+
action="append",
|
|
526
|
+
help="Patterns to exclude",
|
|
527
|
+
)
|
|
528
|
+
export_parser.set_defaults(func=cmd_export)
|
|
529
|
+
|
|
530
|
+
# Stats command
|
|
531
|
+
stats_parser = subparsers.add_parser(
|
|
532
|
+
"stats",
|
|
533
|
+
help="Show graph statistics",
|
|
534
|
+
description="Display statistics about the knowledge graph.",
|
|
535
|
+
)
|
|
536
|
+
stats_parser.add_argument(
|
|
537
|
+
"--repo-path",
|
|
538
|
+
type=str,
|
|
539
|
+
help="Path to the repository",
|
|
540
|
+
)
|
|
541
|
+
stats_parser.add_argument(
|
|
542
|
+
"--backend",
|
|
543
|
+
choices=["kuzu", "memgraph", "memory"],
|
|
544
|
+
default="kuzu",
|
|
545
|
+
help="Storage backend (default: kuzu)",
|
|
546
|
+
)
|
|
547
|
+
stats_parser.add_argument(
|
|
548
|
+
"--db-path",
|
|
549
|
+
type=str,
|
|
550
|
+
help="Path to the database",
|
|
551
|
+
)
|
|
552
|
+
stats_parser.set_defaults(func=cmd_stats)
|
|
553
|
+
|
|
554
|
+
args = parser.parse_args()
|
|
555
|
+
|
|
556
|
+
if not args.command:
|
|
557
|
+
parser.print_help()
|
|
558
|
+
return 1
|
|
559
|
+
|
|
560
|
+
return args.func(args)
|
|
561
|
+
|
|
562
|
+
|
|
563
|
+
if __name__ == "__main__":
|
|
564
|
+
sys.exit(main())
|