codegraphcontext 0.4.11__py3-none-any.whl → 0.4.12__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/config_manager.py +7 -0
- codegraphcontext/cli/main.py +132 -72
- codegraphcontext/cli/registry_commands.py +20 -8
- codegraphcontext/core/__init__.py +9 -2
- codegraphcontext/core/bundle_registry.py +7 -5
- codegraphcontext/core/cgc_bundle.py +42 -5
- codegraphcontext/tools/code_finder.py +17 -0
- codegraphcontext/utils/git_utils.py +13 -0
- {codegraphcontext-0.4.11.dist-info → codegraphcontext-0.4.12.dist-info}/METADATA +5 -5
- {codegraphcontext-0.4.11.dist-info → codegraphcontext-0.4.12.dist-info}/RECORD +14 -14
- {codegraphcontext-0.4.11.dist-info → codegraphcontext-0.4.12.dist-info}/WHEEL +0 -0
- {codegraphcontext-0.4.11.dist-info → codegraphcontext-0.4.12.dist-info}/entry_points.txt +0 -0
- {codegraphcontext-0.4.11.dist-info → codegraphcontext-0.4.12.dist-info}/licenses/LICENSE +0 -0
- {codegraphcontext-0.4.11.dist-info → codegraphcontext-0.4.12.dist-info}/top_level.txt +0 -0
|
@@ -62,6 +62,8 @@ DEFAULT_CONFIG = {
|
|
|
62
62
|
"ENABLE_VECTOR_RESOLVE": "false",
|
|
63
63
|
"CGC_EMBEDDING_MODEL": "local",
|
|
64
64
|
"CGC_EMBEDDING_BATCH_SIZE": "256",
|
|
65
|
+
# Default fuzzy matching behavior for `cgc find name` (overridable per-command with --fuzzy/--no-fuzzy)
|
|
66
|
+
"FUZZY_SEARCH": "true",
|
|
65
67
|
}
|
|
66
68
|
|
|
67
69
|
# Configuration key descriptions
|
|
@@ -123,6 +125,10 @@ CONFIG_DESCRIPTIONS = {
|
|
|
123
125
|
"Number of function texts to embed per batch when ENABLE_VECTOR_RESOLVE=true. "
|
|
124
126
|
"Larger values are faster but use more RAM. Default: 256. Reduce to 64 if you hit memory errors."
|
|
125
127
|
),
|
|
128
|
+
"FUZZY_SEARCH": (
|
|
129
|
+
"Enable fuzzy matching by default for `cgc find name` (true|false). "
|
|
130
|
+
"Per-invocation overrides are available via --fuzzy / --no-fuzzy."
|
|
131
|
+
),
|
|
126
132
|
}
|
|
127
133
|
|
|
128
134
|
# Valid values for each config key
|
|
@@ -143,6 +149,7 @@ CONFIG_VALIDATORS = {
|
|
|
143
149
|
"ENABLE_INHERIT_RESOLVE": ["true", "false"],
|
|
144
150
|
"ENABLE_VECTOR_RESOLVE": ["true", "false"],
|
|
145
151
|
"CGC_EMBEDDING_MODEL": ["local", "openai"],
|
|
152
|
+
"FUZZY_SEARCH": ["true", "false"],
|
|
146
153
|
}
|
|
147
154
|
DEFAULT_CGCIGNORE_PATTERNS = """\
|
|
148
155
|
# Default .cgcignore patterns
|
codegraphcontext/cli/main.py
CHANGED
|
@@ -285,7 +285,7 @@ def context_default(
|
|
|
285
285
|
# CREDENTIALS LOADING PRECEDENCE
|
|
286
286
|
# ============================================================================
|
|
287
287
|
|
|
288
|
-
def _load_credentials():
|
|
288
|
+
def _load_credentials(cli_context_flag: Optional[str] = None):
|
|
289
289
|
"""
|
|
290
290
|
Loads configuration and credentials from various sources into environment variables.
|
|
291
291
|
Uses per-variable precedence - each variable is loaded from the highest priority source.
|
|
@@ -336,7 +336,7 @@ def _load_credentials():
|
|
|
336
336
|
mcp_file_path = Path.cwd() / "mcp.json"
|
|
337
337
|
if mcp_file_path.exists():
|
|
338
338
|
try:
|
|
339
|
-
with open(mcp_file_path, "r") as f:
|
|
339
|
+
with open(mcp_file_path, "r", encoding="utf-8", errors="replace") as f:
|
|
340
340
|
mcp_config = json.load(f)
|
|
341
341
|
server_env = mcp_config.get("mcpServers", {}).get("CodeGraphContext", {}).get("env", {})
|
|
342
342
|
if isinstance(server_env, dict):
|
|
@@ -355,7 +355,8 @@ def _load_credentials():
|
|
|
355
355
|
global_env_path = Path.home() / ".codegraphcontext" / ".env"
|
|
356
356
|
if global_env_path.exists():
|
|
357
357
|
try:
|
|
358
|
-
|
|
358
|
+
with open(global_env_path, "r", encoding="utf-8", errors="replace") as f:
|
|
359
|
+
_append_source(str(global_env_path), dotenv_values(stream=f))
|
|
359
360
|
except Exception as e:
|
|
360
361
|
console.print(f"[yellow]Warning: Could not load global .env: {e}[/yellow]")
|
|
361
362
|
|
|
@@ -363,7 +364,8 @@ def _load_credentials():
|
|
|
363
364
|
try:
|
|
364
365
|
dotenv_path = find_dotenv(usecwd=True, raise_error_if_not_found=False)
|
|
365
366
|
if dotenv_path:
|
|
366
|
-
|
|
367
|
+
with open(dotenv_path, "r", encoding="utf-8", errors="replace") as f:
|
|
368
|
+
_append_source(str(dotenv_path), dotenv_values(stream=f))
|
|
367
369
|
except Exception as e:
|
|
368
370
|
console.print(f"[yellow]Warning: Could not load .env from current directory: {e}[/yellow]")
|
|
369
371
|
|
|
@@ -371,8 +373,9 @@ def _load_credentials():
|
|
|
371
373
|
try:
|
|
372
374
|
local_cgc_env = codegraphcontext_dotenv_at_cwd(Path.cwd())
|
|
373
375
|
if local_cgc_env and local_cgc_env.resolve() != global_env_path.resolve():
|
|
374
|
-
|
|
375
|
-
|
|
376
|
+
with open(local_cgc_env, "r", encoding="utf-8", errors="replace") as f:
|
|
377
|
+
vals = dotenv_values(stream=f)
|
|
378
|
+
_append_source(str(local_cgc_env), vals)
|
|
376
379
|
except Exception as e:
|
|
377
380
|
console.print(
|
|
378
381
|
f"[yellow]Warning: Could not load .codegraphcontext/.env at cwd: {e}[/yellow]"
|
|
@@ -418,31 +421,62 @@ def _load_credentials():
|
|
|
418
421
|
)
|
|
419
422
|
|
|
420
423
|
|
|
421
|
-
#
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
424
|
+
# Detect the context to see if it specifies a custom database
|
|
425
|
+
if cli_context_flag is None:
|
|
426
|
+
import sys
|
|
427
|
+
for i, arg in enumerate(sys.argv):
|
|
428
|
+
if arg in ("--context", "-c"):
|
|
429
|
+
if i + 1 < len(sys.argv):
|
|
430
|
+
cli_context_flag = sys.argv[i + 1]
|
|
431
|
+
break
|
|
432
|
+
elif arg.startswith("--context="):
|
|
433
|
+
cli_context_flag = arg.split("=", 1)[1]
|
|
434
|
+
break
|
|
435
|
+
|
|
436
|
+
from codegraphcontext.cli.config_manager import resolve_context
|
|
437
|
+
ctx = None
|
|
438
|
+
try:
|
|
439
|
+
ctx = resolve_context(cli_context_flag)
|
|
440
|
+
except Exception:
|
|
441
|
+
pass
|
|
427
442
|
|
|
428
|
-
|
|
443
|
+
# Determine if there is a runtime database override.
|
|
444
|
+
runtime_db = os.environ.get("CGC_RUNTIME_DB_TYPE")
|
|
445
|
+
has_runtime_override = (
|
|
446
|
+
runtime_db is not None
|
|
447
|
+
or "DATABASE_TYPE" in runtime_env
|
|
448
|
+
or "DEFAULT_DATABASE" in runtime_env
|
|
449
|
+
)
|
|
429
450
|
|
|
451
|
+
# If there is no runtime override, but the context defines a database,
|
|
452
|
+
# set DEFAULT_DATABASE to the context database to ensure that's what gets initialized.
|
|
453
|
+
if not has_runtime_override and ctx and ctx.mode != "global" and ctx.database:
|
|
454
|
+
os.environ["DEFAULT_DATABASE"] = ctx.database
|
|
455
|
+
|
|
456
|
+
# Now select the database based on precedence:
|
|
457
|
+
# 1. CGC_RUNTIME_DB_TYPE
|
|
458
|
+
# 2. DATABASE_TYPE or DEFAULT_DATABASE from runtime environment (shell variables)
|
|
459
|
+
# 3. Context database
|
|
460
|
+
# 4. DATABASE_TYPE or DEFAULT_DATABASE from merged config files (.env files)
|
|
461
|
+
# 5. Auto-detect fallback
|
|
430
462
|
if runtime_db:
|
|
463
|
+
default_db = runtime_db.lower()
|
|
431
464
|
db_source = "runtime-env (CGC_RUNTIME_DB_TYPE)"
|
|
432
465
|
elif "DATABASE_TYPE" in runtime_env:
|
|
466
|
+
default_db = runtime_env["DATABASE_TYPE"].lower()
|
|
433
467
|
db_source = "environment (DATABASE_TYPE)"
|
|
434
468
|
elif "DEFAULT_DATABASE" in runtime_env:
|
|
469
|
+
default_db = runtime_env["DEFAULT_DATABASE"].lower()
|
|
435
470
|
db_source = "environment (DEFAULT_DATABASE)"
|
|
436
|
-
elif
|
|
471
|
+
elif not has_runtime_override and ctx and ctx.mode != "global" and ctx.database:
|
|
472
|
+
default_db = ctx.database.lower()
|
|
473
|
+
db_source = f"context ({ctx.context_name or 'resolved'})"
|
|
474
|
+
elif os.environ.get("DATABASE_TYPE") and "DATABASE_TYPE" in key_source_map:
|
|
475
|
+
default_db = os.environ["DATABASE_TYPE"].lower()
|
|
437
476
|
db_source = key_source_map["DATABASE_TYPE"]
|
|
438
|
-
elif
|
|
477
|
+
elif os.environ.get("DEFAULT_DATABASE") and "DEFAULT_DATABASE" in key_source_map:
|
|
478
|
+
default_db = os.environ["DEFAULT_DATABASE"].lower()
|
|
439
479
|
db_source = key_source_map["DEFAULT_DATABASE"]
|
|
440
|
-
else:
|
|
441
|
-
db_source = "auto-detect"
|
|
442
|
-
explicit_db = runtime_db or os.environ.get("DEFAULT_DATABASE")
|
|
443
|
-
|
|
444
|
-
if explicit_db:
|
|
445
|
-
default_db = explicit_db.lower()
|
|
446
480
|
else:
|
|
447
481
|
# No explicit choice — ask the factory which backend it will use
|
|
448
482
|
try:
|
|
@@ -455,6 +489,7 @@ def _load_credentials():
|
|
|
455
489
|
default_db = "falkordb" if _is_falkordb_available() else "kuzudb"
|
|
456
490
|
db_source = "auto-detect"
|
|
457
491
|
|
|
492
|
+
# Print selection banner
|
|
458
493
|
if default_db == "neo4j":
|
|
459
494
|
has_neo4j_creds = all([
|
|
460
495
|
os.environ.get("NEO4J_URI"),
|
|
@@ -473,20 +508,14 @@ def _load_credentials():
|
|
|
473
508
|
console.print(f"[cyan]Using database: falkordb (source: {db_source})[/cyan]")
|
|
474
509
|
elif default_db == "kuzudb":
|
|
475
510
|
console.print(f"[cyan]Using database: kuzudb (source: {db_source})[/cyan]")
|
|
511
|
+
elif default_db == "ladybugdb":
|
|
512
|
+
console.print(f"[cyan]Using database: ladybugdb (source: {db_source})[/cyan]")
|
|
476
513
|
elif default_db == "falkordb-remote":
|
|
477
514
|
host = os.environ.get("FALKORDB_HOST")
|
|
478
515
|
if host:
|
|
479
516
|
console.print(f"[cyan]Using database: falkordb-remote (source: {db_source}, host: {host})[/cyan]")
|
|
480
517
|
else:
|
|
481
518
|
console.print("[yellow]⚠ DATABASE_TYPE=falkordb-remote but FALKORDB_HOST not set.[/yellow]")
|
|
482
|
-
elif default_db == "falkordb":
|
|
483
|
-
if os.environ.get("FALKORDB_HOST"):
|
|
484
|
-
console.print(f"[cyan]Using database: falkordb-remote (source: {db_source}, host: {os.environ.get('FALKORDB_HOST')})[/cyan]")
|
|
485
|
-
else:
|
|
486
|
-
console.print(f"[cyan]Using database: falkordb (source: {db_source})[/cyan]")
|
|
487
|
-
console.print(
|
|
488
|
-
"[yellow]⚠ DEFAULT_DATABASE=falkordb-remote but FALKORDB_HOST not set.[/yellow]"
|
|
489
|
-
)
|
|
490
519
|
else:
|
|
491
520
|
console.print(f"[cyan]Using database: {default_db} (source: {db_source})[/cyan]")
|
|
492
521
|
|
|
@@ -543,7 +572,7 @@ def config_reset():
|
|
|
543
572
|
console.print("[yellow]Reset cancelled[/yellow]")
|
|
544
573
|
|
|
545
574
|
@config_app.command("db")
|
|
546
|
-
def config_db(backend: str = typer.Argument(..., help="Database backend: 'neo4j', 'falkordb', 'falkordb-remote', or '
|
|
575
|
+
def config_db(backend: str = typer.Argument(..., help="Database backend: 'neo4j', 'falkordb', 'falkordb-remote', 'kuzudb', or 'ladybugdb'")):
|
|
547
576
|
"""
|
|
548
577
|
Quickly switch the default database backend.
|
|
549
578
|
|
|
@@ -1388,17 +1417,22 @@ app.add_typer(find_app, name="find")
|
|
|
1388
1417
|
@find_app.command("name")
|
|
1389
1418
|
def find_by_name(
|
|
1390
1419
|
ctx: typer.Context,
|
|
1391
|
-
name: str = typer.Argument(..., help="
|
|
1420
|
+
name: str = typer.Argument(..., help="Name to search for"),
|
|
1392
1421
|
type: Optional[str] = typer.Option(None, "--type", "-t", help="Filter by type (function, class, file, module)"),
|
|
1422
|
+
fuzzy: Optional[bool] = typer.Option(None, "--fuzzy/--no-fuzzy", help="Enable/disable fuzzy matching for this command. Overrides the FUZZY_SEARCH config value (default: true)."),
|
|
1393
1423
|
visual: bool = typer.Option(False, "--visual", "--viz", "-V", help="Show results as interactive graph visualization"),
|
|
1394
1424
|
context: Optional[str] = typer.Option(None, "--context", "-c", help="Specific context to use"),
|
|
1395
1425
|
):
|
|
1396
1426
|
"""
|
|
1397
|
-
Find code elements by
|
|
1398
|
-
|
|
1427
|
+
Find code elements by name.
|
|
1428
|
+
|
|
1429
|
+
Fuzzy matching is enabled by default (configurable via the FUZZY_SEARCH
|
|
1430
|
+
config key, or per-invocation with --fuzzy / --no-fuzzy).
|
|
1431
|
+
|
|
1399
1432
|
Examples:
|
|
1400
1433
|
cgc find name MyClass
|
|
1401
1434
|
cgc find name calculate --type function
|
|
1435
|
+
cgc find name MyClass --no-fuzzy
|
|
1402
1436
|
cgc find name MyClass --visual
|
|
1403
1437
|
"""
|
|
1404
1438
|
_load_credentials()
|
|
@@ -1406,14 +1440,22 @@ def find_by_name(
|
|
|
1406
1440
|
if not all(services[:3]):
|
|
1407
1441
|
return
|
|
1408
1442
|
db_manager, graph_builder, code_finder = services[:3]
|
|
1409
|
-
|
|
1443
|
+
|
|
1444
|
+
# Resolve effective fuzzy setting: CLI flag wins, else config, else true.
|
|
1445
|
+
if fuzzy is None:
|
|
1446
|
+
from codegraphcontext.cli.config_manager import load_config
|
|
1447
|
+
cfg_value = load_config().get("FUZZY_SEARCH", "true")
|
|
1448
|
+
fuzzy_search = str(cfg_value).strip().lower() == "true"
|
|
1449
|
+
else:
|
|
1450
|
+
fuzzy_search = fuzzy
|
|
1451
|
+
|
|
1410
1452
|
try:
|
|
1411
1453
|
results = []
|
|
1412
|
-
|
|
1454
|
+
|
|
1413
1455
|
# Search based on type filter
|
|
1414
1456
|
if type is None or type.lower() == 'all':
|
|
1415
|
-
funcs = code_finder.find_by_function_name(name, fuzzy_search=
|
|
1416
|
-
classes = code_finder.find_by_class_name(name, fuzzy_search=
|
|
1457
|
+
funcs = code_finder.find_by_function_name(name, fuzzy_search=fuzzy_search)
|
|
1458
|
+
classes = code_finder.find_by_class_name(name, fuzzy_search=fuzzy_search)
|
|
1417
1459
|
variables = code_finder.find_by_variable_name(name)
|
|
1418
1460
|
modules = code_finder.find_by_module_name(name)
|
|
1419
1461
|
imports = code_finder.find_imports(name)
|
|
@@ -1445,11 +1487,11 @@ def find_by_name(
|
|
|
1445
1487
|
results.append(row)
|
|
1446
1488
|
|
|
1447
1489
|
elif type.lower() == 'function':
|
|
1448
|
-
results = code_finder.find_by_function_name(name, fuzzy_search=
|
|
1490
|
+
results = code_finder.find_by_function_name(name, fuzzy_search=fuzzy_search)
|
|
1449
1491
|
for r in results: r['type'] = 'Function'
|
|
1450
|
-
|
|
1492
|
+
|
|
1451
1493
|
elif type.lower() == 'class':
|
|
1452
|
-
results = code_finder.find_by_class_name(name, fuzzy_search=
|
|
1494
|
+
results = code_finder.find_by_class_name(name, fuzzy_search=fuzzy_search)
|
|
1453
1495
|
for r in results: r['type'] = 'Class'
|
|
1454
1496
|
|
|
1455
1497
|
elif type.lower() == 'variable':
|
|
@@ -2226,10 +2268,10 @@ def analyze_inheritance_tree(
|
|
|
2226
2268
|
|
|
2227
2269
|
@analyze_app.command("complexity")
|
|
2228
2270
|
def analyze_complexity(
|
|
2229
|
-
path: Optional[str] = typer.Argument(None, help="
|
|
2271
|
+
path: Optional[str] = typer.Argument(None, help="Function name or file path to analyze"),
|
|
2230
2272
|
threshold: int = typer.Option(10, "--threshold", "-t", help="Complexity threshold for warnings"),
|
|
2231
2273
|
limit: int = typer.Option(20, "--limit", "-l", help="Maximum results to show"),
|
|
2232
|
-
file: Optional[str] = typer.Option(None, "--file", "-f", help="Specific file path
|
|
2274
|
+
file: Optional[str] = typer.Option(None, "--file", "-f", help="Specific file path to scope analysis"),
|
|
2233
2275
|
context: Optional[str] = typer.Option(None, "--context", "-c", help="Specific context to use"),
|
|
2234
2276
|
):
|
|
2235
2277
|
"""
|
|
@@ -2240,16 +2282,55 @@ def analyze_complexity(
|
|
|
2240
2282
|
cgc analyze complexity --threshold 15 # Functions over threshold
|
|
2241
2283
|
cgc analyze complexity my_function # Specific function
|
|
2242
2284
|
cgc analyze complexity my_function -f file.py # Specific function in file
|
|
2285
|
+
cgc analyze complexity src/main.py # Most complex functions in file
|
|
2286
|
+
cgc analyze complexity main.py # Most complex functions in file
|
|
2287
|
+
cgc analyze complexity --file src/main.py # Alternative file syntax
|
|
2243
2288
|
"""
|
|
2244
2289
|
_load_credentials()
|
|
2245
2290
|
services = _initialize_services(context)
|
|
2246
2291
|
if not all(services[:3]):
|
|
2247
2292
|
return
|
|
2248
2293
|
db_manager, graph_builder, code_finder = services[:3]
|
|
2249
|
-
|
|
2294
|
+
|
|
2295
|
+
_FILE_EXTENSIONS = ('.py', '.js', '.ts', '.jsx', '.tsx', '.go', '.rs', '.rb',
|
|
2296
|
+
'.java', '.cpp', '.c', '.cs', '.swift', '.kt', '.scala',
|
|
2297
|
+
'.php', '.lua', '.zig', '.ex', '.exs', '.r', '.m', '.sh')
|
|
2298
|
+
|
|
2299
|
+
def _is_file_path(value: str) -> bool:
|
|
2300
|
+
if '/' in value or '\\' in value:
|
|
2301
|
+
return True
|
|
2302
|
+
return any(value.endswith(ext) for ext in _FILE_EXTENSIONS)
|
|
2303
|
+
|
|
2304
|
+
def _render_complexity_table(results, title):
|
|
2305
|
+
if not results:
|
|
2306
|
+
console.print("[yellow]No complexity data available for this file[/yellow]")
|
|
2307
|
+
return
|
|
2308
|
+
table = Table(show_header=True, header_style="bold magenta", box=box.ROUNDED)
|
|
2309
|
+
table.add_column("Function", style="cyan")
|
|
2310
|
+
table.add_column("Complexity", style="yellow", justify="right")
|
|
2311
|
+
table.add_column("Location", style="dim", overflow="fold")
|
|
2312
|
+
for func in results:
|
|
2313
|
+
complexity = func.get('complexity', 0)
|
|
2314
|
+
color = "red" if complexity > threshold else "yellow" if complexity > threshold/2 else "green"
|
|
2315
|
+
fpath = func.get('path', '')
|
|
2316
|
+
line_str = str(func.get('line_number', ''))
|
|
2317
|
+
location_str = f"{fpath}:{line_str}" if line_str else fpath
|
|
2318
|
+
table.add_row(
|
|
2319
|
+
func.get('function_name', ''),
|
|
2320
|
+
f"[{color}]{complexity}[/{color}]",
|
|
2321
|
+
location_str
|
|
2322
|
+
)
|
|
2323
|
+
console.print(f"\n[bold cyan]{title}[/bold cyan]")
|
|
2324
|
+
console.print(table)
|
|
2325
|
+
console.print(f"\n[dim]{len([f for f in results if f.get('complexity', 0) > threshold])} function(s) exceed threshold[/dim]")
|
|
2326
|
+
|
|
2250
2327
|
try:
|
|
2251
|
-
if path:
|
|
2252
|
-
#
|
|
2328
|
+
if path and _is_file_path(path):
|
|
2329
|
+
# File path provided as positional argument
|
|
2330
|
+
results = code_finder.find_most_complex_functions_in_file(path, limit)
|
|
2331
|
+
_render_complexity_table(results, f"Most Complex Functions in '{path}' (threshold: {threshold}):")
|
|
2332
|
+
elif path:
|
|
2333
|
+
# Specific function name
|
|
2253
2334
|
result = code_finder.get_cyclomatic_complexity(path, file)
|
|
2254
2335
|
if result:
|
|
2255
2336
|
console.print(f"\n[bold cyan]Complexity for '{path}':[/bold cyan]")
|
|
@@ -2258,35 +2339,14 @@ def analyze_complexity(
|
|
|
2258
2339
|
console.print(f" Line: [dim]{result.get('line_number', '')}[/dim]")
|
|
2259
2340
|
else:
|
|
2260
2341
|
console.print(f"[yellow]Function '{path}' not found or has no complexity data[/yellow]")
|
|
2342
|
+
elif file:
|
|
2343
|
+
# --file option without positional arg
|
|
2344
|
+
results = code_finder.find_most_complex_functions_in_file(file, limit)
|
|
2345
|
+
_render_complexity_table(results, f"Most Complex Functions in '{file}' (threshold: {threshold}):")
|
|
2261
2346
|
else:
|
|
2262
|
-
#
|
|
2347
|
+
# Global - most complex functions
|
|
2263
2348
|
results = code_finder.find_most_complex_functions(limit)
|
|
2264
|
-
|
|
2265
|
-
if not results:
|
|
2266
|
-
console.print("[yellow]No complexity data available[/yellow]")
|
|
2267
|
-
return
|
|
2268
|
-
|
|
2269
|
-
table = Table(show_header=True, header_style="bold magenta", box=box.ROUNDED)
|
|
2270
|
-
table.add_column("Function", style="cyan")
|
|
2271
|
-
table.add_column("Complexity", style="yellow", justify="right")
|
|
2272
|
-
table.add_column("Location", style="dim", overflow="fold")
|
|
2273
|
-
|
|
2274
|
-
for func in results:
|
|
2275
|
-
complexity = func.get('complexity', 0)
|
|
2276
|
-
color = "red" if complexity > threshold else "yellow" if complexity > threshold/2 else "green"
|
|
2277
|
-
path = func.get('path', '')
|
|
2278
|
-
line_str = str(func.get('line_number', ''))
|
|
2279
|
-
location_str = f"{path}:{line_str}" if line_str else path
|
|
2280
|
-
|
|
2281
|
-
table.add_row(
|
|
2282
|
-
func.get('function_name', ''),
|
|
2283
|
-
f"[{color}]{complexity}[/{color}]",
|
|
2284
|
-
location_str
|
|
2285
|
-
)
|
|
2286
|
-
|
|
2287
|
-
console.print(f"\n[bold cyan]Most Complex Functions (threshold: {threshold}):[/bold cyan]")
|
|
2288
|
-
console.print(table)
|
|
2289
|
-
console.print(f"\n[dim]{len([f for f in results if f.get('complexity', 0) > threshold])} function(s) exceed threshold[/dim]")
|
|
2349
|
+
_render_complexity_table(results, f"Most Complex Functions (threshold: {threshold}):")
|
|
2290
2350
|
finally:
|
|
2291
2351
|
db_manager.close_driver()
|
|
2292
2352
|
|
|
@@ -238,11 +238,14 @@ def download_bundle(name: str, output_dir: Optional[str] = None, auto_load: bool
|
|
|
238
238
|
|
|
239
239
|
# Determine output path
|
|
240
240
|
bundle_filename = bundle.get('bundle_name', f"{name}.cgc")
|
|
241
|
+
is_base64 = download_url.endswith('.base64') or bundle_filename.endswith('.base64')
|
|
242
|
+
clean_filename = bundle_filename.replace('.base64', '')
|
|
243
|
+
|
|
241
244
|
if output_dir:
|
|
242
|
-
output_path = Path(output_dir) /
|
|
245
|
+
output_path = Path(output_dir) / clean_filename
|
|
243
246
|
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
244
247
|
else:
|
|
245
|
-
output_path = Path.cwd() /
|
|
248
|
+
output_path = Path.cwd() / clean_filename
|
|
246
249
|
|
|
247
250
|
# Check if already exists
|
|
248
251
|
if output_path.exists():
|
|
@@ -257,7 +260,7 @@ def download_bundle(name: str, output_dir: Optional[str] = None, auto_load: bool
|
|
|
257
260
|
|
|
258
261
|
# Download with progress bar
|
|
259
262
|
try:
|
|
260
|
-
console.print(f"[cyan]Downloading {
|
|
263
|
+
console.print(f"[cyan]Downloading {clean_filename}...[/cyan]")
|
|
261
264
|
console.print(f"[dim]From: {download_url}[/dim]")
|
|
262
265
|
|
|
263
266
|
response = requests.get(download_url, stream=True, timeout=30)
|
|
@@ -272,11 +275,20 @@ def download_bundle(name: str, output_dir: Optional[str] = None, auto_load: bool
|
|
|
272
275
|
) as progress:
|
|
273
276
|
task = progress.add_task(f"Downloading {bundle.get('size', 'unknown')}...", total=total_size)
|
|
274
277
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
278
|
+
if is_base64:
|
|
279
|
+
# Read entire base64 response, decode it, and write it
|
|
280
|
+
base64_content = response.content.strip()
|
|
281
|
+
import base64
|
|
282
|
+
decoded_content = base64.b64decode(base64_content)
|
|
283
|
+
with open(output_path, 'wb') as f:
|
|
284
|
+
f.write(decoded_content)
|
|
285
|
+
progress.update(task, completed=total_size)
|
|
286
|
+
else:
|
|
287
|
+
with open(output_path, 'wb') as f:
|
|
288
|
+
for chunk in response.iter_content(chunk_size=8192):
|
|
289
|
+
if chunk:
|
|
290
|
+
f.write(chunk)
|
|
291
|
+
progress.update(task, advance=len(chunk))
|
|
280
292
|
|
|
281
293
|
console.print(f"[bold green]✓ Downloaded successfully: {output_path}[/bold green]")
|
|
282
294
|
|
|
@@ -26,6 +26,13 @@ def _is_kuzudb_available() -> bool:
|
|
|
26
26
|
except ImportError:
|
|
27
27
|
return False
|
|
28
28
|
|
|
29
|
+
def _is_ladybugdb_available() -> bool:
|
|
30
|
+
"""Check if LadybugDB is installed."""
|
|
31
|
+
try:
|
|
32
|
+
return importlib.util.find_spec("ladybug") is not None
|
|
33
|
+
except ImportError:
|
|
34
|
+
return False
|
|
35
|
+
|
|
29
36
|
def _is_falkordb_available() -> bool:
|
|
30
37
|
"""Check if FalkorDB Lite is installed (Unix only)."""
|
|
31
38
|
if platform.system() == "Windows":
|
|
@@ -127,8 +134,8 @@ def get_database_manager(db_path: Optional[str] = None) -> Union['DatabaseManage
|
|
|
127
134
|
info_logger("Using Nornic DB (explicit)")
|
|
128
135
|
return NornicDBManager()
|
|
129
136
|
elif db_type == 'ladybugdb':
|
|
130
|
-
if not
|
|
131
|
-
raise ValueError("Database set to 'ladybugdb' but LadybugDB
|
|
137
|
+
if not _is_ladybugdb_available():
|
|
138
|
+
raise ValueError("Database set to 'ladybugdb' but LadybugDB is not installed.\nRun 'pip install ladybug'")
|
|
132
139
|
from .database_ladybug import LadybugDBManager
|
|
133
140
|
info_logger(f"Using LadybugDB (explicit) at {db_path or 'default path'}")
|
|
134
141
|
return LadybugDBManager(db_path=db_path)
|
|
@@ -16,10 +16,12 @@ def _github_headers() -> dict:
|
|
|
16
16
|
headers["Authorization"] = f"token {token}"
|
|
17
17
|
return headers
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
def _get_manifest_url() -> str:
|
|
20
|
+
import os
|
|
21
|
+
hf_repo = os.environ.get("HF_REGISTRY_REPO") or "codegraphcontext/bundles"
|
|
22
|
+
return f"https://huggingface.co/datasets/{hf_repo}/raw/main/manifest.json"
|
|
23
|
+
|
|
24
|
+
REGISTRY_API_URL = "https://api.github.com/repos/CodeGraphContext/CodeGraphContext/releases"
|
|
23
25
|
|
|
24
26
|
class BundleRegistry:
|
|
25
27
|
"""
|
|
@@ -38,7 +40,7 @@ class BundleRegistry:
|
|
|
38
40
|
|
|
39
41
|
# 1. Fetch on-demand bundles from manifest
|
|
40
42
|
try:
|
|
41
|
-
response = requests.get(
|
|
43
|
+
response = requests.get(_get_manifest_url(), headers=_github_headers(), timeout=10)
|
|
42
44
|
if response.status_code == 200:
|
|
43
45
|
manifest = response.json()
|
|
44
46
|
if manifest.get('bundles'):
|
|
@@ -28,7 +28,7 @@ from datetime import datetime, date
|
|
|
28
28
|
import subprocess
|
|
29
29
|
|
|
30
30
|
from codegraphcontext.utils.debug_log import debug_log, info_logger, error_logger, warning_logger
|
|
31
|
-
from codegraphcontext.utils.git_utils import get_repo_commit_hash
|
|
31
|
+
from codegraphcontext.utils.git_utils import get_repo_commit_hash, get_repo_branch_name
|
|
32
32
|
|
|
33
33
|
|
|
34
34
|
class _BundleEncoder(json.JSONEncoder):
|
|
@@ -106,11 +106,9 @@ class CGCBundle:
|
|
|
106
106
|
with tempfile.TemporaryDirectory() as temp_dir:
|
|
107
107
|
temp_path = Path(temp_dir)
|
|
108
108
|
|
|
109
|
-
# Step 1: Extract metadata
|
|
109
|
+
# Step 1: Extract metadata base
|
|
110
110
|
info_logger("Extracting metadata...")
|
|
111
111
|
metadata = self._extract_metadata(repo_path)
|
|
112
|
-
with open(temp_path / "metadata.json", 'w') as f:
|
|
113
|
-
json.dump(metadata, f, indent=2, cls=_BundleEncoder)
|
|
114
112
|
|
|
115
113
|
# Step 2: Extract schema
|
|
116
114
|
info_logger("Extracting schema...")
|
|
@@ -126,12 +124,48 @@ class CGCBundle:
|
|
|
126
124
|
info_logger("Extracting edges...")
|
|
127
125
|
edge_count = self._extract_edges(temp_path / "edges.jsonl", repo_path)
|
|
128
126
|
|
|
129
|
-
# Step 5: Generate statistics
|
|
127
|
+
# Step 5: Generate statistics and assemble standardized metadata
|
|
130
128
|
if include_stats:
|
|
131
129
|
info_logger("Generating statistics...")
|
|
132
130
|
stats = self._generate_stats(repo_path, node_count, edge_count)
|
|
133
131
|
with open(temp_path / "stats.json", 'w') as f:
|
|
134
132
|
json.dump(stats, f, indent=2, cls=_BundleEncoder)
|
|
133
|
+
else:
|
|
134
|
+
stats = None
|
|
135
|
+
|
|
136
|
+
# Compile dynamic standardized metadata
|
|
137
|
+
try:
|
|
138
|
+
from importlib.metadata import version as get_version
|
|
139
|
+
py_version = get_version("codegraphcontext")
|
|
140
|
+
except Exception:
|
|
141
|
+
py_version = "0.4.12"
|
|
142
|
+
|
|
143
|
+
metadata["format_version"] = "1.0.0"
|
|
144
|
+
metadata["generator"] = f"PYv{py_version}"
|
|
145
|
+
|
|
146
|
+
# Timestamp format: YYYY-MM-DDTHH:MM:SSZ (UTC ISO String format)
|
|
147
|
+
# datetime.utcnow() was deprecated, using timezone-aware or simple UTC strftime
|
|
148
|
+
from datetime import timezone
|
|
149
|
+
metadata["exported_at"] = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
150
|
+
|
|
151
|
+
# Build name
|
|
152
|
+
if metadata.get("repo") and "/" in metadata["repo"]:
|
|
153
|
+
owner, repo_name = metadata["repo"].split("/", 1)
|
|
154
|
+
branch = metadata.get("branch", "main")
|
|
155
|
+
commit = metadata.get("commit", "latest")
|
|
156
|
+
metadata["name"] = f"{owner}__{repo_name}__{branch}__{commit}.cgc"
|
|
157
|
+
else:
|
|
158
|
+
foldername = metadata.get("repo", "unknown")
|
|
159
|
+
metadata["name"] = f"{foldername}.cgc"
|
|
160
|
+
|
|
161
|
+
metadata["graph_metrics"] = {
|
|
162
|
+
"total_nodes": node_count,
|
|
163
|
+
"total_edges": edge_count
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
# Save final metadata.json
|
|
167
|
+
with open(temp_path / "metadata.json", 'w') as f:
|
|
168
|
+
json.dump(metadata, f, indent=2, cls=_BundleEncoder)
|
|
135
169
|
|
|
136
170
|
# Step 6: Create README
|
|
137
171
|
self._create_readme(temp_path / "README.md", metadata, stats if include_stats else None)
|
|
@@ -304,6 +338,9 @@ class CGCBundle:
|
|
|
304
338
|
commit = get_repo_commit_hash(repo_path)
|
|
305
339
|
if commit:
|
|
306
340
|
metadata["commit"] = commit[:8]
|
|
341
|
+
branch = get_repo_branch_name(repo_path)
|
|
342
|
+
if branch:
|
|
343
|
+
metadata["branch"] = branch
|
|
307
344
|
|
|
308
345
|
try:
|
|
309
346
|
result = session.run("""
|
|
@@ -1357,6 +1357,23 @@ class CodeFinder:
|
|
|
1357
1357
|
result = session.run(query, limit=limit, repo_path=repo_path)
|
|
1358
1358
|
return result.data()
|
|
1359
1359
|
|
|
1360
|
+
def find_most_complex_functions_in_file(self, file_path: str, limit: int = 20, repo_path: Optional[str] = None) -> List[Dict]:
|
|
1361
|
+
"""Find the most complex functions in a specific file."""
|
|
1362
|
+
with self.driver.session() as session:
|
|
1363
|
+
repo_filter = "AND f.path STARTS WITH $repo_path" if repo_path else ""
|
|
1364
|
+
query = f"""
|
|
1365
|
+
MATCH (f:Function)
|
|
1366
|
+
WHERE f.cyclomatic_complexity IS NOT NULL
|
|
1367
|
+
AND (f.path ENDS WITH $file_path OR f.path = $file_path)
|
|
1368
|
+
{repo_filter}
|
|
1369
|
+
RETURN f.name as function_name, f.path as path,
|
|
1370
|
+
f.cyclomatic_complexity as complexity, f.line_number as line_number
|
|
1371
|
+
ORDER BY f.cyclomatic_complexity DESC
|
|
1372
|
+
LIMIT $limit
|
|
1373
|
+
"""
|
|
1374
|
+
result = session.run(query, file_path=file_path, limit=limit, repo_path=repo_path)
|
|
1375
|
+
return result.data()
|
|
1376
|
+
|
|
1360
1377
|
def list_indexed_repositories(self) -> List[Dict]:
|
|
1361
1378
|
"""List all indexed repositories."""
|
|
1362
1379
|
with self.driver.session() as session:
|
|
@@ -24,3 +24,16 @@ def get_repo_commit_hash(repo_path: Path) -> Optional[str]:
|
|
|
24
24
|
return sha if sha else None
|
|
25
25
|
except (subprocess.CalledProcessError, FileNotFoundError, OSError):
|
|
26
26
|
return None
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def get_repo_branch_name(repo_path: Path) -> Optional[str]:
|
|
30
|
+
"""Return the active git branch name for *repo_path*, or ``None``."""
|
|
31
|
+
try:
|
|
32
|
+
branch = subprocess.check_output(
|
|
33
|
+
["git", "rev-parse", "--abbrev-ref", "HEAD"],
|
|
34
|
+
cwd=repo_path,
|
|
35
|
+
stderr=subprocess.DEVNULL,
|
|
36
|
+
).decode().strip()
|
|
37
|
+
return branch if branch else None
|
|
38
|
+
except (subprocess.CalledProcessError, FileNotFoundError, OSError):
|
|
39
|
+
return None
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codegraphcontext
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.12
|
|
4
4
|
Summary: An MCP server that indexes local code into a graph database to provide context to AI assistants.
|
|
5
5
|
Author-email: Shashank Shekhar Singh <shashankshekharsingh1205@gmail.com>
|
|
6
6
|
License: MIT License
|
|
@@ -168,7 +168,7 @@ A powerful **MCP server** and **CLI toolkit** that indexes local code into a gra
|
|
|
168
168
|
---
|
|
169
169
|
|
|
170
170
|
## Project Details
|
|
171
|
-
- **Version:** 0.4.
|
|
171
|
+
- **Version:** 0.4.12
|
|
172
172
|
- **Authors:** Shashank Shekhar Singh <shashankshekharsingh1205@gmail.com>
|
|
173
173
|
- **License:** MIT License (See [LICENSE](LICENSE) for details)
|
|
174
174
|
- **Website:** [CodeGraphContext](http://codegraphcontext.vercel.app/)
|
|
@@ -201,7 +201,7 @@ A powerful **MCP server** and **CLI toolkit** that indexes local code into a gra
|
|
|
201
201
|
- **Interactive Setup:** A user-friendly command-line wizard for easy setup.
|
|
202
202
|
- **Dual Mode:** Works as a standalone **CLI toolkit** for developers and as an **MCP server** for AI agents.
|
|
203
203
|
- **Multi-Language Support:** Full support for 20 programming languages.
|
|
204
|
-
- **Flexible Database Backend:**
|
|
204
|
+
- **Flexible Database Backend:** FalkorDB Lite (Default), KuzuDB, LadybugDB, FalkorDB Remote, Nornic DB, or Neo4j (all platforms via Docker/native).
|
|
205
205
|
|
|
206
206
|
|
|
207
207
|
---
|
|
@@ -304,8 +304,8 @@ _If you’re using CodeGraphContext in your project, feel free to open a PR and
|
|
|
304
304
|
|
|
305
305
|
3. **Database Setup (Automatic):**
|
|
306
306
|
CodeGraphContext uses an embedded graph database by default.
|
|
307
|
-
- **
|
|
308
|
-
- **
|
|
307
|
+
- **FalkorDB Lite:** Default backend.
|
|
308
|
+
- **KuzuDB:** Cross-platform embedded backend.
|
|
309
309
|
- **Neo4j:** Run `codegraphcontext neo4j setup` to use an external server.
|
|
310
310
|
|
|
311
311
|
---
|
|
@@ -10,15 +10,15 @@ codegraphcontext/api/router.py,sha256=9LU6_5K7_sZCiYIhq6Pko4T6CZ5q8doM_e6rCgvQWM
|
|
|
10
10
|
codegraphcontext/api/schemas.py,sha256=pGLuKtdn55pf8mS8wv8MwehbT_3-4OZuSYjI5LJxzOc,1034
|
|
11
11
|
codegraphcontext/cli/__init__.py,sha256=2vUlnf7H09M9JbS2gS_LmMUBJWAWcGGHkkl4I2YrdSg,39
|
|
12
12
|
codegraphcontext/cli/cli_helpers.py,sha256=_fksM3sBj9e96gQcHOaDmpmJG6444lWRaO0AM-6Wzu8,38773
|
|
13
|
-
codegraphcontext/cli/config_manager.py,sha256=
|
|
14
|
-
codegraphcontext/cli/main.py,sha256=
|
|
15
|
-
codegraphcontext/cli/registry_commands.py,sha256=
|
|
13
|
+
codegraphcontext/cli/config_manager.py,sha256=Vx94GpLlP3TisW5Kp6yZ5p1mVJIsm-wldn0_3P0mY74,44511
|
|
14
|
+
codegraphcontext/cli/main.py,sha256=COwBzgeAR1va4HmdyGfkCkAT6K4YmpVfYnMCIjF2IRk,116918
|
|
15
|
+
codegraphcontext/cli/registry_commands.py,sha256=kM7KtC8-4q83SPHShWI1-xNsq91LvWuelT6xU0OzUHY,16543
|
|
16
16
|
codegraphcontext/cli/setup_macos.py,sha256=Xjlv_9jk9qv8Gh7stpH1pvlalzC0Fg176y7jc5G1zh0,3575
|
|
17
17
|
codegraphcontext/cli/setup_wizard.py,sha256=ssI_9v7yZXiML2sQ7IR3kwbKiG9riPskl-Qkc16ozVQ,47070
|
|
18
18
|
codegraphcontext/cli/visualizer.py,sha256=md5HehQ9_8lBTejQqq2lxXtMRzDxCjjF9L9h2qu6KR0,1902
|
|
19
|
-
codegraphcontext/core/__init__.py,sha256=
|
|
20
|
-
codegraphcontext/core/bundle_registry.py,sha256=
|
|
21
|
-
codegraphcontext/core/cgc_bundle.py,sha256=
|
|
19
|
+
codegraphcontext/core/__init__.py,sha256=Ob-2LzXhmt9-YdaND3OEGMeX0V6nBnTflOE5QGMCeho,8797
|
|
20
|
+
codegraphcontext/core/bundle_registry.py,sha256=CJ4KasV7y2bbmajvz0W66N9IkZ3mdSkOM_kfQmUH37Y,7952
|
|
21
|
+
codegraphcontext/core/cgc_bundle.py,sha256=mAaqe0Zz80EXZnD7gDEpq46JZes9vX_hU5oAn6PJGWU,38016
|
|
22
22
|
codegraphcontext/core/cgcignore.py,sha256=6q7y11V_bNEhMC1167HiUyr7yxDCNg2OMr0DQAqCzlE,4213
|
|
23
23
|
codegraphcontext/core/database.py,sha256=RWMdKKinoWewyTyTuIXX-fk7EHkba91LO18gZ12wwEg,14648
|
|
24
24
|
codegraphcontext/core/database_falkordb.py,sha256=jpa7iTMSRs0k67adMihrCNzl8QnYlqKKHXDsvwW9880,21426
|
|
@@ -31,7 +31,7 @@ codegraphcontext/core/jobs.py,sha256=d6v_IERdEcDlIsz3CW3p0QMp3N-6dgQICs3FZRPgPgU
|
|
|
31
31
|
codegraphcontext/core/watcher.py,sha256=EFjKYK3wUQG2pQter_A2xSe8yIrkZwfjZ9anITAjftA,18949
|
|
32
32
|
codegraphcontext/tools/__init__.py,sha256=iqQPEkDlGXO7rAaLNQrS_ZAbLSklBSK-OowpARq0mig,41
|
|
33
33
|
codegraphcontext/tools/advanced_language_query_tool.py,sha256=73tkiMc_4ez6dX8aQBD6WzKAWhBn7jbsdMDXwdFCvvk,3731
|
|
34
|
-
codegraphcontext/tools/code_finder.py,sha256=
|
|
34
|
+
codegraphcontext/tools/code_finder.py,sha256=AZV51kDFmwIhHKQmH36zuL9qTlrP_RaP3e-ZEN_wi3k,70514
|
|
35
35
|
codegraphcontext/tools/graph_builder.py,sha256=5t8G8eoSRTsjdqMtrZIxAK01I2_B3zToY3ab_GhdNrQ,54278
|
|
36
36
|
codegraphcontext/tools/package_resolver.py,sha256=KtbdMReTezszjdsqYniL-Xb-QUsrAJWtf1NSiyIPkLI,18704
|
|
37
37
|
codegraphcontext/tools/report_generator.py,sha256=K4AROEMZU--fX217JT6y7P7LfiqRnG8olwrj0vO1kKo,12499
|
|
@@ -107,7 +107,7 @@ codegraphcontext/tools/query_tool_languages/scala_toolkit.py,sha256=rCUKIpKyiWG2
|
|
|
107
107
|
codegraphcontext/tools/query_tool_languages/swift_toolkit.py,sha256=fVhf6w2q6DmhQfQP08wEulMGzopG5B8axL3p59puZrI,274
|
|
108
108
|
codegraphcontext/tools/query_tool_languages/typescript_toolkit.py,sha256=MUB0pVG2Bk6wBK0lXqaEwMxUQIcJugm3eeT_hLXJX3s,283
|
|
109
109
|
codegraphcontext/utils/debug_log.py,sha256=PZfti8__3lYqgyyvdU41wARFW99nppcEX5DkFE9KeFY,2878
|
|
110
|
-
codegraphcontext/utils/git_utils.py,sha256=
|
|
110
|
+
codegraphcontext/utils/git_utils.py,sha256=D7ve2gpZaEHk4y6K4ga-o2ka89DVFX1acafD31YAyJM,1383
|
|
111
111
|
codegraphcontext/utils/path_ignore.py,sha256=xaYCSq6nzUVX_mEdn3yrmwM--v7orJImga2XAQeiGB0,2168
|
|
112
112
|
codegraphcontext/utils/repo_path.py,sha256=BxS3y6RV_WaZhg_WxgJygS4SnQa-Ryth2fsicfnYorY,1121
|
|
113
113
|
codegraphcontext/utils/tool_limits.py,sha256=3d-QnlzxBNocz58VKNhdsta7ZpWThs1AX46_gYXl6pQ,2751
|
|
@@ -152,9 +152,9 @@ codegraphcontext/viz/dist/wasm/tree-sitter-typescript.wasm,sha256=hRVATc7tOOHthq
|
|
|
152
152
|
codegraphcontext/viz/dist/wasm/tree-sitter.wasm,sha256=CCeVuI_hXktkBD-DW01xYPv5XoAYVRIqzJUJI5te-RY,196763
|
|
153
153
|
codegraphcontext/viz/dist/wasm/web-tree-sitter.js,sha256=DIaCNqRylrT_PBVw8g4ImeSnhP9uXNe_ycOlUiVGPko,153666
|
|
154
154
|
codegraphcontext/viz/dist/wasm/web-tree-sitter.wasm,sha256=CCeVuI_hXktkBD-DW01xYPv5XoAYVRIqzJUJI5te-RY,196763
|
|
155
|
-
codegraphcontext-0.4.
|
|
156
|
-
codegraphcontext-0.4.
|
|
157
|
-
codegraphcontext-0.4.
|
|
158
|
-
codegraphcontext-0.4.
|
|
159
|
-
codegraphcontext-0.4.
|
|
160
|
-
codegraphcontext-0.4.
|
|
155
|
+
codegraphcontext-0.4.12.dist-info/licenses/LICENSE,sha256=rh8M-bJpQYJnw2vtRVgt0t7piMZXh5QzaKeNEI0vqqA,1061
|
|
156
|
+
codegraphcontext-0.4.12.dist-info/METADATA,sha256=ADQKPPW2ggEmk2ER9bFCD3MVL_rx3wnx1lAzIOScSsI,22639
|
|
157
|
+
codegraphcontext-0.4.12.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
158
|
+
codegraphcontext-0.4.12.dist-info/entry_points.txt,sha256=LCxWCWMshdvYGoHBPuQZ8C-e4CiNSHCLXofrNSGHkoE,103
|
|
159
|
+
codegraphcontext-0.4.12.dist-info/top_level.txt,sha256=CBgc6LAPZIO5FS0nSYYkylDifHsZTIqw3Gf5UwDxeGI,17
|
|
160
|
+
codegraphcontext-0.4.12.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|