codegraphcontext 0.3.2__py3-none-any.whl → 0.3.4__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.
@@ -340,7 +340,9 @@ def cypher_helper_visual(query: str):
340
340
  console.print(f"[bold red]An error occurred while executing query:[/bold red] {e}")
341
341
  finally:
342
342
  db_manager.close_driver()
343
- import webbrowser
343
+
344
+
345
+ import uvicorn
344
346
  import urllib.parse
345
347
  from ..viz.server import run_server, set_db_manager
346
348
 
@@ -356,12 +358,42 @@ def visualize_helper(repo_path: Optional[str] = None, port: int = 8000):
356
358
  set_db_manager(db_manager)
357
359
 
358
360
  # Determine the static directory (built React app)
359
- static_dir = Path(__file__).parent.parent / "viz" / "dist"
361
+ # This points to src/codegraphcontext/viz/dist where we build the website
362
+ # (relative to src/codegraphcontext/cli/cli_helpers.py)
363
+ # Using .resolve() is more robust for path comparison and existence checks
364
+ this_file = Path(__file__).resolve()
365
+ package_root = this_file.parent.parent
366
+ static_dir = package_root / "viz" / "dist"
367
+
368
+ # Fallback for development if not yet built in viz/dist
360
369
  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
-
370
+ # Look for website/dist in the project root (3 levels up from cli/cli_helpers.py, 4 parents)
371
+ # 1: cli/, 2: codegraphcontext/, 3: src/, 4: project_root/
372
+ project_root = this_file.parent.parent.parent.parent
373
+ dev_static_dir = project_root / "website" / "dist"
374
+
375
+ # Also try one level up from package_root just in case of different layouts
376
+ alt_dev_dir = package_root.parent.parent / "website" / "dist"
377
+
378
+ if dev_static_dir.exists():
379
+ static_dir = dev_static_dir
380
+ elif alt_dev_dir.exists():
381
+ static_dir = alt_dev_dir
382
+ else:
383
+ # Last resort: try current working directory
384
+ cwd_static_dir = Path.cwd() / "website" / "dist"
385
+ if cwd_static_dir.exists():
386
+ static_dir = cwd_static_dir
387
+ else:
388
+ console.print(f"[yellow]Warning: Visualization assets not found.[/yellow]")
389
+ console.print(f"[dim]Checked paths:[/dim]")
390
+ console.print(f" [dim]- {static_dir}[/dim]")
391
+ console.print(f" [dim]- {dev_static_dir}[/dim]")
392
+ console.print(f" [dim]- {alt_dev_dir}[/dim]")
393
+ console.print(f" [dim]- {cwd_static_dir}[/dim]")
394
+ console.print("[dim]Please run 'cd website && npm run build' first.[/dim]")
395
+ # We continue anyway to let the server start (helpful for dev)
396
+
365
397
  # Construct the URL
366
398
  backend_url = f"http://localhost:{port}"
367
399
  params = {"backend": backend_url}
@@ -369,7 +401,7 @@ def visualize_helper(repo_path: Optional[str] = None, port: int = 8000):
369
401
  params["repo_path"] = str(Path(repo_path).resolve())
370
402
 
371
403
  query_string = urllib.parse.urlencode(params)
372
- visualization_url = f"{backend_url}/playground?{query_string}"
404
+ visualization_url = f"{backend_url}/explore?{query_string}"
373
405
 
374
406
  console.print(f"[green]Starting visualizer server on {backend_url}...[/green]")
375
407
  console.print(f"[cyan]Opening Playground UI:[/cyan] {visualization_url}")
@@ -377,6 +409,7 @@ def visualize_helper(repo_path: Optional[str] = None, port: int = 8000):
377
409
  # Open browser in a separate thread/process if possible, or just before starting server
378
410
  def open_browser():
379
411
  import time
412
+ import webbrowser
380
413
  time.sleep(1.5) # Give the server a moment to start
381
414
  webbrowser.open(visualization_url)
382
415
 
@@ -390,243 +423,6 @@ def visualize_helper(repo_path: Optional[str] = None, port: int = 8000):
390
423
  finally:
391
424
  db_manager.close_driver()
392
425
 
393
- def _visualize_falkordb(db_manager):
394
- console.print("[dim]Generating FalkorDB visualization (showing up to 500 relationships)...[/dim]")
395
- try:
396
- data_nodes = []
397
- data_edges = []
398
-
399
- with db_manager.get_driver().session() as session:
400
- # Fetch nodes and edges
401
- q = "MATCH (n)-[r]->(m) RETURN n, r, m LIMIT 500"
402
- result = session.run(q)
403
-
404
- seen_nodes = set()
405
-
406
- for record in result:
407
- # record values are Node/Relationship objects from falkordb client
408
- n = record['n']
409
- r = record['r']
410
- m = record['m']
411
-
412
- # Process Node helper
413
- def process_node(node):
414
- nid = getattr(node, 'id', -1)
415
- labels = getattr(node, 'labels', [])
416
- lbl = list(labels)[0] if labels else "Node"
417
- props = getattr(node, 'properties', {})
418
- name = props.get('name', str(nid))
419
-
420
- if nid not in seen_nodes:
421
- seen_nodes.add(nid)
422
- color = "#97c2fc" # Default blue
423
- if "Repository" in labels: color = "#ffb3ba" # Red
424
- elif "File" in labels: color = "#baffc9" # Green
425
- elif "Class" in labels: color = "#bae1ff" # Light Blue
426
- elif "Function" in labels: color = "#ffffba" # Yellow
427
- elif "Package" in labels: color = "#ffdfba" # Orange
428
-
429
- data_nodes.append({
430
- "id": nid,
431
- "label": name,
432
- "group": lbl,
433
- "title": str(props),
434
- "color": color
435
- })
436
- return nid
437
-
438
- nid = process_node(n)
439
- mid = process_node(m)
440
-
441
- # Check Edge
442
- e_type = getattr(r, 'relation', '') or getattr(r, 'type', 'REL')
443
- data_edges.append({
444
- "from": nid,
445
- "to": mid,
446
- "label": e_type,
447
- "arrows": "to"
448
- })
449
-
450
- filename = "codegraph_viz.html"
451
- html_content = f"""
452
- <!DOCTYPE html>
453
- <html>
454
- <head>
455
- <title>CodeGraphContext Visualization</title>
456
- <script type="text/javascript" src="https://unpkg.com/vis-network/standalone/umd/vis-network.min.js"></script>
457
- <style type="text/css">
458
- #mynetwork {{
459
- width: 100%;
460
- height: 100vh;
461
- border: 1px solid lightgray;
462
- }}
463
- </style>
464
- </head>
465
- <body>
466
- <div id="mynetwork"></div>
467
- <script type="text/javascript">
468
- var nodes = new vis.DataSet({json.dumps(data_nodes)});
469
- var edges = new vis.DataSet({json.dumps(data_edges)});
470
- var container = document.getElementById('mynetwork');
471
- var data = {{ nodes: nodes, edges: edges }};
472
- var options = {{
473
- nodes: {{ shape: 'dot', size: 16 }},
474
- physics: {{ stabilization: false }},
475
- layout: {{ improvedLayout: false }}
476
- }};
477
- var network = new vis.Network(container, data, options);
478
- </script>
479
- </body>
480
- </html>
481
- """
482
-
483
- out_path = Path(filename).resolve()
484
- with open(out_path, "w") as f:
485
- f.write(html_content)
486
-
487
- console.print(f"[green]Visualization generated at:[/green] {out_path}")
488
- console.print("Opening in default browser...")
489
- webbrowser.open(f"file://{out_path}")
490
-
491
- except Exception as e:
492
- console.print(f"[bold red]Visualization failed:[/bold red] {e}")
493
- import traceback
494
- traceback.print_exc()
495
- finally:
496
- db_manager.close_driver()
497
-
498
-
499
- def _visualize_kuzudb(db_manager):
500
- console.print("[dim]Generating KùzuDB visualization (showing up to 500 relationships)...[/dim]")
501
- try:
502
- data_nodes = []
503
- data_edges = []
504
-
505
- with db_manager.get_driver().session() as session:
506
- # Fetch nodes and edges
507
- # KùzuDB returns dicts for n, r, m in the result
508
- q = "MATCH (n)-[r]->(m) RETURN n, r, m LIMIT 500"
509
- result = session.run(q)
510
-
511
- seen_nodes = set()
512
-
513
- # Helper to extract Node ID and props
514
- def process_node(node):
515
- uid = None
516
- lbl = 'Node'
517
- props = {}
518
-
519
- # Handle Kuzu Node Object (processed by wrapper)
520
- if hasattr(node, 'properties'):
521
- props = node.properties or {}
522
- if hasattr(node, 'labels') and node.labels:
523
- lbl = node.labels[0]
524
- if hasattr(node, 'id'):
525
- uid = str(node.id)
526
- # Handle Dictionary (raw Kuzu result)
527
- elif isinstance(node, dict):
528
- if '_id' in node:
529
- uid = f"{node['_id']['table']}_{node['_id']['offset']}"
530
- lbl = node.get('_label', 'Node')
531
- props = {k: v for k, v in node.items() if not k.startswith('_')}
532
-
533
- if not uid:
534
- uid = str(uuid.uuid4())
535
-
536
- name = props.get('name', str(uid))
537
-
538
- if uid not in seen_nodes:
539
- seen_nodes.add(uid)
540
- color = "#97c2fc" # Default blue
541
- if "Repository" == lbl: color = "#ffb3ba"
542
- elif "File" == lbl: color = "#baffc9"
543
- elif "Class" == lbl: color = "#bae1ff"
544
- elif "Function" == lbl: color = "#ffffba"
545
- elif "Module" == lbl: color = "#ffdfba"
546
-
547
- data_nodes.append({
548
- "id": uid,
549
- "label": name,
550
- "group": lbl,
551
- "title": str(props),
552
- "color": color
553
- })
554
- return uid
555
-
556
- # Iterate results
557
- for record in result:
558
- # record is dict-like access to row items
559
- n = record['n']
560
- r = record['r']
561
- m = record['m']
562
-
563
- nid = process_node(n)
564
- mid = process_node(m)
565
-
566
- # Process Edge
567
- e_type = 'REL'
568
- if hasattr(r, 'type'):
569
- e_type = r.type
570
- elif isinstance(r, dict):
571
- e_type = r.get('_label', 'REL')
572
- elif hasattr(r, 'label'): # Some versions
573
- e_type = r.label
574
-
575
- data_edges.append({
576
- "from": nid,
577
- "to": mid,
578
- "label": e_type,
579
- "arrows": "to"
580
- })
581
-
582
- filename = "codegraph_viz.html"
583
- html_content = f"""
584
- <!DOCTYPE html>
585
- <html>
586
- <head>
587
- <title>CodeGraphContext KùzuDB Visualization</title>
588
- <script type="text/javascript" src="https://unpkg.com/vis-network/standalone/umd/vis-network.min.js"></script>
589
- <style type="text/css">
590
- #mynetwork {{
591
- width: 100%;
592
- height: 100vh;
593
- border: 1px solid lightgray;
594
- }}
595
- </style>
596
- </head>
597
- <body>
598
- <div id="mynetwork"></div>
599
- <script type="text/javascript">
600
- var nodes = new vis.DataSet({json.dumps(data_nodes)});
601
- var edges = new vis.DataSet({json.dumps(data_edges)});
602
- var container = document.getElementById('mynetwork');
603
- var data = {{ nodes: nodes, edges: edges }};
604
- var options = {{
605
- nodes: {{ shape: 'dot', size: 16 }},
606
- physics: {{ stabilization: false }},
607
- layout: {{ improvedLayout: false }}
608
- }};
609
- var network = new vis.Network(container, data, options);
610
- </script>
611
- </body>
612
- </html>
613
- """
614
-
615
- out_path = Path(filename).resolve()
616
- with open(out_path, "w") as f:
617
- f.write(html_content)
618
-
619
- console.print(f"[green]Visualization generated at:[/green] {out_path}")
620
- console.print("Opening in default browser...")
621
- webbrowser.open(f"file://{out_path}")
622
-
623
- except Exception as e:
624
- console.print(f"[bold red]Visualization failed:[/bold red] {e}")
625
- import traceback
626
- traceback.print_exc()
627
- finally:
628
- db_manager.close_driver()
629
-
630
426
 
631
427
  def reindex_helper(path: str):
632
428
  """Force re-index by deleting and rebuilding the repository."""
@@ -999,7 +999,7 @@ def visualize(
999
999
  port: int = typer.Option(8000, "--port", "-p", help="Port to run the visualizer server on.")
1000
1000
  ):
1001
1001
  """
1002
- Launches the interactive Playground UI to visualize the code graph.
1002
+ Launches the interactive UI to visualize the code graph.
1003
1003
  """
1004
1004
  _load_credentials()
1005
1005
  visualize_helper(repo, port)