code-review-graph-codeblackwell 2.3.6.post1__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.
Files changed (74) hide show
  1. code_review_graph/__init__.py +20 -0
  2. code_review_graph/__main__.py +4 -0
  3. code_review_graph/analysis.py +410 -0
  4. code_review_graph/changes.py +409 -0
  5. code_review_graph/cli.py +1255 -0
  6. code_review_graph/communities.py +874 -0
  7. code_review_graph/constants.py +23 -0
  8. code_review_graph/context_savings.py +317 -0
  9. code_review_graph/custom_languages.py +322 -0
  10. code_review_graph/daemon.py +1009 -0
  11. code_review_graph/daemon_cli.py +320 -0
  12. code_review_graph/docs/LLM-OPTIMIZED-REFERENCE.md +71 -0
  13. code_review_graph/embeddings.py +1006 -0
  14. code_review_graph/enrich.py +303 -0
  15. code_review_graph/eval/__init__.py +33 -0
  16. code_review_graph/eval/benchmarks/__init__.py +1 -0
  17. code_review_graph/eval/benchmarks/agent_baseline.py +193 -0
  18. code_review_graph/eval/benchmarks/build_performance.py +60 -0
  19. code_review_graph/eval/benchmarks/flow_completeness.py +36 -0
  20. code_review_graph/eval/benchmarks/impact_accuracy.py +220 -0
  21. code_review_graph/eval/benchmarks/multi_hop_retrieval.py +125 -0
  22. code_review_graph/eval/benchmarks/search_quality.py +59 -0
  23. code_review_graph/eval/benchmarks/token_efficiency.py +143 -0
  24. code_review_graph/eval/configs/code-review-graph.yaml +50 -0
  25. code_review_graph/eval/configs/express.yaml +45 -0
  26. code_review_graph/eval/configs/fastapi.yaml +48 -0
  27. code_review_graph/eval/configs/flask.yaml +50 -0
  28. code_review_graph/eval/configs/gin.yaml +51 -0
  29. code_review_graph/eval/configs/httpx.yaml +48 -0
  30. code_review_graph/eval/reporter.py +301 -0
  31. code_review_graph/eval/runner.py +211 -0
  32. code_review_graph/eval/scorer.py +85 -0
  33. code_review_graph/eval/token_benchmark.py +182 -0
  34. code_review_graph/exports.py +409 -0
  35. code_review_graph/flows.py +698 -0
  36. code_review_graph/graph.py +1427 -0
  37. code_review_graph/graph_diff.py +122 -0
  38. code_review_graph/hints.py +384 -0
  39. code_review_graph/incremental.py +1245 -0
  40. code_review_graph/jedi_resolver.py +303 -0
  41. code_review_graph/main.py +1079 -0
  42. code_review_graph/memory.py +142 -0
  43. code_review_graph/migrations.py +284 -0
  44. code_review_graph/parser.py +6957 -0
  45. code_review_graph/postprocessing.py +134 -0
  46. code_review_graph/prompts.py +159 -0
  47. code_review_graph/refactor.py +852 -0
  48. code_review_graph/registry.py +319 -0
  49. code_review_graph/rescript_resolver.py +206 -0
  50. code_review_graph/search.py +447 -0
  51. code_review_graph/skills.py +1481 -0
  52. code_review_graph/spring_resolver.py +200 -0
  53. code_review_graph/temporal_resolver.py +199 -0
  54. code_review_graph/token_benchmark.py +125 -0
  55. code_review_graph/tools/__init__.py +156 -0
  56. code_review_graph/tools/_common.py +176 -0
  57. code_review_graph/tools/analysis_tools.py +184 -0
  58. code_review_graph/tools/build.py +541 -0
  59. code_review_graph/tools/community_tools.py +246 -0
  60. code_review_graph/tools/context.py +152 -0
  61. code_review_graph/tools/docs.py +274 -0
  62. code_review_graph/tools/flows_tools.py +176 -0
  63. code_review_graph/tools/query.py +692 -0
  64. code_review_graph/tools/refactor_tools.py +168 -0
  65. code_review_graph/tools/registry_tools.py +125 -0
  66. code_review_graph/tools/review.py +477 -0
  67. code_review_graph/tsconfig_resolver.py +257 -0
  68. code_review_graph/visualization.py +2184 -0
  69. code_review_graph/wiki.py +305 -0
  70. code_review_graph_codeblackwell-2.3.6.post1.dist-info/METADATA +718 -0
  71. code_review_graph_codeblackwell-2.3.6.post1.dist-info/RECORD +74 -0
  72. code_review_graph_codeblackwell-2.3.6.post1.dist-info/WHEEL +4 -0
  73. code_review_graph_codeblackwell-2.3.6.post1.dist-info/entry_points.txt +3 -0
  74. code_review_graph_codeblackwell-2.3.6.post1.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,134 @@
1
+ """Shared post-build processing pipeline.
2
+
3
+ After the core Tree-sitter parse (full_build or incremental_update), four
4
+ post-processing steps must run to populate derived tables:
5
+
6
+ 1. Compute node signatures
7
+ 2. Rebuild FTS5 search index
8
+ 3. Trace execution flows
9
+ 4. Detect code communities
10
+
11
+ This module extracts that pipeline so every entry point — MCP tool, CLI
12
+ commands, and watch mode — produces identical results.
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ import logging
18
+ import sqlite3
19
+ from typing import Any
20
+
21
+ from .graph import GraphStore
22
+
23
+ logger = logging.getLogger(__name__)
24
+
25
+
26
+ def run_post_processing(store: GraphStore) -> dict[str, Any]:
27
+ """Run all post-build steps on a populated graph.
28
+
29
+ Each step is non-fatal: failures are logged and collected as warnings
30
+ so the primary build result is never lost.
31
+
32
+ Args:
33
+ store: An open GraphStore with nodes and edges already populated.
34
+
35
+ Returns:
36
+ Dict with keys for each step's result count and a ``warnings``
37
+ list (only present when at least one step failed).
38
+ """
39
+ result: dict[str, Any] = {}
40
+ warnings: list[str] = []
41
+
42
+ _compute_signatures(store, result, warnings)
43
+ _rebuild_fts_index(store, result, warnings)
44
+ _trace_flows(store, result, warnings)
45
+ _detect_communities(store, result, warnings)
46
+
47
+ if warnings:
48
+ result["warnings"] = warnings
49
+ return result
50
+
51
+
52
+ # -- Individual steps (private) ------------------------------------------
53
+
54
+
55
+ def _compute_signatures(
56
+ store: GraphStore,
57
+ result: dict[str, Any],
58
+ warnings: list[str],
59
+ ) -> None:
60
+ """Compute human-readable signatures for nodes that lack one."""
61
+ try:
62
+ rows = store.get_nodes_without_signature()
63
+ for row in rows:
64
+ node_id, name, kind, params, ret = (
65
+ row[0],
66
+ row[1],
67
+ row[2],
68
+ row[3],
69
+ row[4],
70
+ )
71
+ if kind in ("Function", "Test"):
72
+ sig = f"def {name}({params or ''})"
73
+ if ret:
74
+ sig += f" -> {ret}"
75
+ elif kind == "Class":
76
+ sig = f"class {name}"
77
+ else:
78
+ sig = name
79
+ store.update_node_signature(node_id, sig[:512])
80
+ store.commit()
81
+ result["signatures_computed"] = len(rows)
82
+ except (sqlite3.OperationalError, TypeError, KeyError) as e:
83
+ logger.warning("Signature computation failed: %s", e)
84
+ warnings.append(f"Signature computation failed: {type(e).__name__}: {e}")
85
+
86
+
87
+ def _rebuild_fts_index(
88
+ store: GraphStore,
89
+ result: dict[str, Any],
90
+ warnings: list[str],
91
+ ) -> None:
92
+ """Rebuild the FTS5 full-text search index."""
93
+ try:
94
+ from .search import rebuild_fts_index
95
+
96
+ fts_count = rebuild_fts_index(store)
97
+ result["fts_indexed"] = fts_count
98
+ except (sqlite3.OperationalError, ImportError) as e:
99
+ logger.warning("FTS index rebuild failed: %s", e)
100
+ warnings.append(f"FTS index rebuild failed: {type(e).__name__}: {e}")
101
+
102
+
103
+ def _trace_flows(
104
+ store: GraphStore,
105
+ result: dict[str, Any],
106
+ warnings: list[str],
107
+ ) -> None:
108
+ """Trace execution flows from entry points."""
109
+ try:
110
+ from .flows import store_flows, trace_flows
111
+
112
+ flows = trace_flows(store)
113
+ count = store_flows(store, flows)
114
+ result["flows_detected"] = count
115
+ except (sqlite3.OperationalError, ImportError) as e:
116
+ logger.warning("Flow detection failed: %s", e)
117
+ warnings.append(f"Flow detection failed: {type(e).__name__}: {e}")
118
+
119
+
120
+ def _detect_communities(
121
+ store: GraphStore,
122
+ result: dict[str, Any],
123
+ warnings: list[str],
124
+ ) -> None:
125
+ """Detect code communities via Leiden algorithm or file grouping."""
126
+ try:
127
+ from .communities import detect_communities, store_communities
128
+
129
+ comms = detect_communities(store)
130
+ count = store_communities(store, comms)
131
+ result["communities_detected"] = count
132
+ except (sqlite3.OperationalError, ImportError) as e:
133
+ logger.warning("Community detection failed: %s", e)
134
+ warnings.append(f"Community detection failed: {type(e).__name__}: {e}")
@@ -0,0 +1,159 @@
1
+ """MCP prompt templates for Code Review Graph.
2
+
3
+ Provides 5 pre-built prompt workflows, all enforcing token-efficient
4
+ detail_level="minimal" first patterns with get_minimal_context entry point.
5
+
6
+ 1. review_changes - pre-commit review using detect_changes + affected_flows
7
+ 2. architecture_map - architecture docs using communities, flows, Mermaid
8
+ 3. debug_issue - guided debugging using search, flow tracing
9
+ 4. onboard_developer - new dev orientation using stats, architecture, flows
10
+ 5. pre_merge_check - PR readiness with risk scoring, test gaps, dead code
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ from fastmcp.prompts.prompt import Message
16
+
17
+ _TOKEN_EFFICIENCY_PREAMBLE = ( # nosec B105 — prompt template, not a password
18
+ """\
19
+ ## Rules for Token-Efficient Graph Usage
20
+ 1. ALWAYS call `get_minimal_context` first with a task description.
21
+ 2. Use `detail_level="minimal"` on all tool calls unless the minimal output \
22
+ is insufficient.
23
+ 3. Only escalate to `detail_level="standard"` or `"verbose"` for the specific \
24
+ entities that need deeper inspection.
25
+ 4. Never request more than 3 tool calls per turn unless absolutely necessary.
26
+ 5. Prefer targeted queries (query_graph with a specific symbol) over broad \
27
+ scans (list_communities with full members).
28
+ 6. When reviewing changes: detect_changes(detail_level="minimal") → only \
29
+ expand on high-risk items.
30
+ """
31
+ )
32
+
33
+
34
+ def _user(content: str) -> list[Message]:
35
+ """Wrap content as a single-message user prompt.
36
+
37
+ fastmcp >=3.2 rejects raw dicts in prompt return values; each message
38
+ must be a ``Message`` instance (or a plain ``str``). We standardise on
39
+ ``Message`` so role is explicit and future multi-turn prompts compose
40
+ naturally.
41
+ """
42
+ return [Message(role="user", content=content)]
43
+
44
+
45
+ def review_changes_prompt(base: str = "HEAD~1") -> list[Message]:
46
+ """Pre-commit review workflow.
47
+
48
+ Args:
49
+ base: Git ref to diff against. Default: HEAD~1.
50
+ """
51
+ return _user(
52
+ f"{_TOKEN_EFFICIENCY_PREAMBLE}\n"
53
+ f"## Review Workflow\n"
54
+ f'1. Call `get_minimal_context(task="review changes against '
55
+ f'{base}")` to get risk overview.\n'
56
+ f'2. If risk is "low": call '
57
+ f'`detect_changes(detail_level="minimal")` → report summary '
58
+ f"+ any test gaps.\n"
59
+ f'3. If risk is "medium" or "high":\n'
60
+ f' a. Call `detect_changes(detail_level="standard")` for '
61
+ f"full change list.\n"
62
+ f" b. For each high-risk function, call "
63
+ f'`query_graph(pattern="callers_of", target=<func>, '
64
+ f'detail_level="minimal")`.\n'
65
+ f' c. Call `get_affected_flows(detail_level="minimal")` '
66
+ f"only if >3 changed functions.\n"
67
+ f"4. Summarize: risk level, what changed, test gaps, "
68
+ f"specific improvements needed.\n\n"
69
+ f"Do NOT call get_review_context unless you need source code "
70
+ f"snippets for a specific function."
71
+ )
72
+
73
+
74
+ def architecture_map_prompt() -> list[Message]:
75
+ """Architecture documentation workflow."""
76
+ return _user(
77
+ f"{_TOKEN_EFFICIENCY_PREAMBLE}\n"
78
+ "## Architecture Mapping Workflow\n"
79
+ '1. Call `get_minimal_context(task="map architecture")`.\n'
80
+ '2. Call `get_architecture_overview(detail_level="minimal")` '
81
+ "for community coupling summary.\n"
82
+ '3. Call `list_flows(detail_level="minimal")` for critical '
83
+ "flow names + criticality scores.\n"
84
+ "4. Only call `get_community(name=<X>, "
85
+ 'detail_level="standard")` for the 1-2 communities the user '
86
+ "is most interested in.\n"
87
+ "5. Produce a concise Mermaid diagram showing communities as "
88
+ "boxes and key flows as arrows."
89
+ )
90
+
91
+
92
+ def debug_issue_prompt(description: str = "") -> list[Message]:
93
+ """Guided debugging workflow.
94
+
95
+ Args:
96
+ description: Description of the issue to debug.
97
+ """
98
+ desc_part = description or "<description>"
99
+ return _user(
100
+ f"{_TOKEN_EFFICIENCY_PREAMBLE}\n"
101
+ "## Debug Workflow\n"
102
+ f'1. Call `get_minimal_context(task="debug: '
103
+ f'{desc_part}")`.\n'
104
+ "2. Call `semantic_search_nodes(query=<keywords from "
105
+ 'description>, detail_level="minimal", limit=5)`.\n'
106
+ "3. For the top 1-2 results, call "
107
+ '`query_graph(pattern="callers_of", target=<name>, '
108
+ 'detail_level="minimal")`.\n'
109
+ "4. If the issue involves execution flow: call "
110
+ "`get_flow(name=<relevant flow>)` for the single most "
111
+ "relevant flow.\n"
112
+ "5. Only call `get_review_context` or `get_impact_radius` "
113
+ "if you need to trace the blast radius of a specific change."
114
+ )
115
+
116
+
117
+ def onboard_developer_prompt() -> list[Message]:
118
+ """New developer orientation workflow."""
119
+ return _user(
120
+ f"{_TOKEN_EFFICIENCY_PREAMBLE}\n"
121
+ "## Onboarding Workflow\n"
122
+ '1. Call `get_minimal_context(task="onboard developer")`.\n'
123
+ "2. Call `list_graph_stats()` for technology overview.\n"
124
+ '3. Call `get_architecture_overview(detail_level="minimal")` '
125
+ "for the 30-second mental model.\n"
126
+ '4. Call `list_communities(detail_level="minimal")` — '
127
+ "present as a table of module names + sizes.\n"
128
+ '5. Call `list_flows(detail_level="minimal")` — highlight '
129
+ "the top 3 critical flows.\n"
130
+ "6. Only drill into a specific community or flow if the "
131
+ "developer asks."
132
+ )
133
+
134
+
135
+ def pre_merge_check_prompt(base: str = "HEAD~1") -> list[Message]:
136
+ """PR readiness check workflow.
137
+
138
+ Args:
139
+ base: Git ref to diff against. Default: HEAD~1.
140
+ """
141
+ return _user(
142
+ f"{_TOKEN_EFFICIENCY_PREAMBLE}\n"
143
+ "## Pre-Merge Check Workflow\n"
144
+ '1. Call `get_minimal_context(task="pre-merge check")`.\n'
145
+ '2. Call `detect_changes(detail_level="minimal")` for risk '
146
+ "score and test gaps.\n"
147
+ "3. If risk > 0.4: call "
148
+ '`get_affected_flows(detail_level="minimal")`.\n'
149
+ "4. If test_gap_count > 0: call "
150
+ '`query_graph(pattern="tests_for", '
151
+ 'target=<each untested function>, detail_level="minimal")` '
152
+ "for up to 3 functions.\n"
153
+ '5. Call `refactor(mode="dead_code", '
154
+ 'detail_level="minimal")` to check for newly dead code.\n'
155
+ "6. Only call `find_large_functions` or `get_impact_radius` "
156
+ "if risk > 0.7.\n"
157
+ "7. Output: GO/NO-GO recommendation with 1-sentence "
158
+ "justification + list of required follow-ups."
159
+ )