Detect communities in the code graph. Uses the Leiden algorithm via igraph if available, otherwise falls back to file-based grouping. Args: store: The GraphStore instance. min_size: Minimum number of nodes for a community to be included. Returns: List of co
(
store: GraphStore, min_size: int = 2
)
| 583 | |
| 584 | |
| 585 | def detect_communities( |
| 586 | store: GraphStore, min_size: int = 2 |
| 587 | ) -> list[dict[str, Any]]: |
| 588 | """Detect communities in the code graph. |
| 589 | |
| 590 | Uses the Leiden algorithm via igraph if available, otherwise falls back to |
| 591 | file-based grouping. |
| 592 | |
| 593 | Args: |
| 594 | store: The GraphStore instance. |
| 595 | min_size: Minimum number of nodes for a community to be included. |
| 596 | |
| 597 | Returns: |
| 598 | List of community dicts with keys: name, level, size, cohesion, |
| 599 | dominant_language, description, members, member_qns. |
| 600 | """ |
| 601 | # Gather all nodes (exclude File nodes to focus on code entities) |
| 602 | all_edges = store.get_all_edges() |
| 603 | unique_nodes = store.get_all_nodes(exclude_files=True) |
| 604 | |
| 605 | # Build adjacency index once for fast cohesion computation |
| 606 | adj = _build_adjacency(all_edges) |
| 607 | |
| 608 | logger.info( |
| 609 | "Loaded %d unique nodes, %d edges", |
| 610 | len(unique_nodes), len(all_edges), |
| 611 | ) |
| 612 | |
| 613 | if IGRAPH_AVAILABLE: |
| 614 | logger.info("Detecting communities with Leiden algorithm (igraph)") |
| 615 | results = _detect_leiden(unique_nodes, all_edges, min_size, adj=adj) |
| 616 | else: |
| 617 | logger.info("igraph not available, using file-based community detection") |
| 618 | results = _detect_file_based(unique_nodes, all_edges, min_size, adj=adj) |
| 619 | |
| 620 | # Split oversized communities |
| 621 | results = _split_oversized( |
| 622 | results, unique_nodes, all_edges, |
| 623 | ) |
| 624 | |
| 625 | # Convert member_qns (internal set) to a list for serialization safety, |
| 626 | # then strip it from the returned dicts to avoid leaking internal state. |
| 627 | for comm in results: |
| 628 | if "member_qns" in comm: |
| 629 | comm["member_qns"] = list(comm["member_qns"]) |
| 630 | del comm["member_qns"] |
| 631 | |
| 632 | return results |
| 633 | |
| 634 | |
| 635 | def incremental_detect_communities( |