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.
- code_review_graph/__init__.py +20 -0
- code_review_graph/__main__.py +4 -0
- code_review_graph/analysis.py +410 -0
- code_review_graph/changes.py +409 -0
- code_review_graph/cli.py +1255 -0
- code_review_graph/communities.py +874 -0
- code_review_graph/constants.py +23 -0
- code_review_graph/context_savings.py +317 -0
- code_review_graph/custom_languages.py +322 -0
- code_review_graph/daemon.py +1009 -0
- code_review_graph/daemon_cli.py +320 -0
- code_review_graph/docs/LLM-OPTIMIZED-REFERENCE.md +71 -0
- code_review_graph/embeddings.py +1006 -0
- code_review_graph/enrich.py +303 -0
- code_review_graph/eval/__init__.py +33 -0
- code_review_graph/eval/benchmarks/__init__.py +1 -0
- code_review_graph/eval/benchmarks/agent_baseline.py +193 -0
- code_review_graph/eval/benchmarks/build_performance.py +60 -0
- code_review_graph/eval/benchmarks/flow_completeness.py +36 -0
- code_review_graph/eval/benchmarks/impact_accuracy.py +220 -0
- code_review_graph/eval/benchmarks/multi_hop_retrieval.py +125 -0
- code_review_graph/eval/benchmarks/search_quality.py +59 -0
- code_review_graph/eval/benchmarks/token_efficiency.py +143 -0
- code_review_graph/eval/configs/code-review-graph.yaml +50 -0
- code_review_graph/eval/configs/express.yaml +45 -0
- code_review_graph/eval/configs/fastapi.yaml +48 -0
- code_review_graph/eval/configs/flask.yaml +50 -0
- code_review_graph/eval/configs/gin.yaml +51 -0
- code_review_graph/eval/configs/httpx.yaml +48 -0
- code_review_graph/eval/reporter.py +301 -0
- code_review_graph/eval/runner.py +211 -0
- code_review_graph/eval/scorer.py +85 -0
- code_review_graph/eval/token_benchmark.py +182 -0
- code_review_graph/exports.py +409 -0
- code_review_graph/flows.py +698 -0
- code_review_graph/graph.py +1427 -0
- code_review_graph/graph_diff.py +122 -0
- code_review_graph/hints.py +384 -0
- code_review_graph/incremental.py +1245 -0
- code_review_graph/jedi_resolver.py +303 -0
- code_review_graph/main.py +1079 -0
- code_review_graph/memory.py +142 -0
- code_review_graph/migrations.py +284 -0
- code_review_graph/parser.py +6957 -0
- code_review_graph/postprocessing.py +134 -0
- code_review_graph/prompts.py +159 -0
- code_review_graph/refactor.py +852 -0
- code_review_graph/registry.py +319 -0
- code_review_graph/rescript_resolver.py +206 -0
- code_review_graph/search.py +447 -0
- code_review_graph/skills.py +1481 -0
- code_review_graph/spring_resolver.py +200 -0
- code_review_graph/temporal_resolver.py +199 -0
- code_review_graph/token_benchmark.py +125 -0
- code_review_graph/tools/__init__.py +156 -0
- code_review_graph/tools/_common.py +176 -0
- code_review_graph/tools/analysis_tools.py +184 -0
- code_review_graph/tools/build.py +541 -0
- code_review_graph/tools/community_tools.py +246 -0
- code_review_graph/tools/context.py +152 -0
- code_review_graph/tools/docs.py +274 -0
- code_review_graph/tools/flows_tools.py +176 -0
- code_review_graph/tools/query.py +692 -0
- code_review_graph/tools/refactor_tools.py +168 -0
- code_review_graph/tools/registry_tools.py +125 -0
- code_review_graph/tools/review.py +477 -0
- code_review_graph/tsconfig_resolver.py +257 -0
- code_review_graph/visualization.py +2184 -0
- code_review_graph/wiki.py +305 -0
- code_review_graph_codeblackwell-2.3.6.post1.dist-info/METADATA +718 -0
- code_review_graph_codeblackwell-2.3.6.post1.dist-info/RECORD +74 -0
- code_review_graph_codeblackwell-2.3.6.post1.dist-info/WHEEL +4 -0
- code_review_graph_codeblackwell-2.3.6.post1.dist-info/entry_points.txt +3 -0
- code_review_graph_codeblackwell-2.3.6.post1.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
"""CLI entry point for the crg-daemon multi-repo watcher.
|
|
2
|
+
|
|
3
|
+
Usage:
|
|
4
|
+
crg-daemon start [--foreground]
|
|
5
|
+
crg-daemon stop
|
|
6
|
+
crg-daemon restart [--foreground]
|
|
7
|
+
crg-daemon status
|
|
8
|
+
crg-daemon logs [--repo ALIAS] [--follow] [--lines N]
|
|
9
|
+
crg-daemon add <path> [--alias ALIAS]
|
|
10
|
+
crg-daemon remove <path_or_alias>
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import argparse
|
|
16
|
+
import logging
|
|
17
|
+
import os
|
|
18
|
+
import signal
|
|
19
|
+
import subprocess
|
|
20
|
+
import sys
|
|
21
|
+
import time
|
|
22
|
+
|
|
23
|
+
logger = logging.getLogger(__name__)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# ---------------------------------------------------------------------------
|
|
27
|
+
# Subcommand handlers
|
|
28
|
+
# ---------------------------------------------------------------------------
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _handle_start(args: argparse.Namespace) -> None:
|
|
32
|
+
"""Start the daemon process."""
|
|
33
|
+
from .daemon import WatchDaemon, is_daemon_running, load_config
|
|
34
|
+
|
|
35
|
+
if is_daemon_running():
|
|
36
|
+
print("Error: Daemon is already running.")
|
|
37
|
+
sys.exit(1)
|
|
38
|
+
|
|
39
|
+
config = load_config()
|
|
40
|
+
daemon = WatchDaemon(config=config)
|
|
41
|
+
daemon.start()
|
|
42
|
+
|
|
43
|
+
if not args.foreground:
|
|
44
|
+
daemon.daemonize()
|
|
45
|
+
|
|
46
|
+
daemon.run_forever()
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _handle_stop(_args: argparse.Namespace) -> None:
|
|
50
|
+
"""Stop the running daemon process."""
|
|
51
|
+
from .daemon import clear_pid, is_daemon_running, read_pid
|
|
52
|
+
|
|
53
|
+
if not is_daemon_running():
|
|
54
|
+
print("Daemon is not running.")
|
|
55
|
+
sys.exit(1)
|
|
56
|
+
|
|
57
|
+
pid = read_pid()
|
|
58
|
+
if pid is None:
|
|
59
|
+
print("Error: Could not read daemon PID.")
|
|
60
|
+
sys.exit(1)
|
|
61
|
+
|
|
62
|
+
print(f"Stopping daemon (PID {pid})...")
|
|
63
|
+
try:
|
|
64
|
+
os.kill(pid, signal.SIGTERM)
|
|
65
|
+
except ProcessLookupError:
|
|
66
|
+
clear_pid()
|
|
67
|
+
print("Daemon stopped (process already gone).")
|
|
68
|
+
return
|
|
69
|
+
except PermissionError:
|
|
70
|
+
print(f"Error: Permission denied sending signal to PID {pid}.")
|
|
71
|
+
sys.exit(1)
|
|
72
|
+
|
|
73
|
+
# Wait up to 5 seconds for process to die
|
|
74
|
+
for _ in range(50):
|
|
75
|
+
try:
|
|
76
|
+
os.kill(pid, 0)
|
|
77
|
+
except ProcessLookupError:
|
|
78
|
+
break
|
|
79
|
+
time.sleep(0.1)
|
|
80
|
+
else:
|
|
81
|
+
# Still alive after 5s — send SIGKILL
|
|
82
|
+
print("Daemon did not stop gracefully, sending SIGKILL...")
|
|
83
|
+
try:
|
|
84
|
+
os.kill(pid, signal.SIGKILL)
|
|
85
|
+
except ProcessLookupError:
|
|
86
|
+
pass
|
|
87
|
+
|
|
88
|
+
clear_pid()
|
|
89
|
+
print("Daemon stopped.")
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _handle_restart(args: argparse.Namespace) -> None:
|
|
93
|
+
"""Restart the daemon (stop + start)."""
|
|
94
|
+
from .daemon import is_daemon_running
|
|
95
|
+
|
|
96
|
+
if is_daemon_running():
|
|
97
|
+
_handle_stop(args)
|
|
98
|
+
else:
|
|
99
|
+
print("Daemon is not running, starting fresh.")
|
|
100
|
+
|
|
101
|
+
_handle_start(args)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _handle_status(_args: argparse.Namespace) -> None:
|
|
105
|
+
"""Show daemon status and configuration."""
|
|
106
|
+
from .daemon import is_daemon_running, load_config, load_state, pid_alive, read_pid
|
|
107
|
+
|
|
108
|
+
config = load_config()
|
|
109
|
+
running = is_daemon_running()
|
|
110
|
+
|
|
111
|
+
if running:
|
|
112
|
+
pid = read_pid()
|
|
113
|
+
print(f"Daemon: running (PID {pid})")
|
|
114
|
+
else:
|
|
115
|
+
print("Daemon: not running")
|
|
116
|
+
|
|
117
|
+
print(f"Name: {config.session_name}")
|
|
118
|
+
print(f"Log dir: {config.log_dir}")
|
|
119
|
+
print(f"Poll: {config.poll_interval}s")
|
|
120
|
+
print()
|
|
121
|
+
|
|
122
|
+
if not config.repos:
|
|
123
|
+
print("No repositories configured.")
|
|
124
|
+
print("Use: crg-daemon add <path> [--alias NAME]")
|
|
125
|
+
return
|
|
126
|
+
|
|
127
|
+
# Header
|
|
128
|
+
alias_width = max(len(r.alias) for r in config.repos)
|
|
129
|
+
alias_width = max(alias_width, 5) # minimum "Alias" header width
|
|
130
|
+
|
|
131
|
+
if running:
|
|
132
|
+
state = load_state()
|
|
133
|
+
print(f" {'Alias':<{alias_width}} {'Status':<8} {'PID':<8} Path")
|
|
134
|
+
print(f" {'-' * alias_width} {'-' * 8} {'-' * 8} {'-' * 40}")
|
|
135
|
+
for repo in config.repos:
|
|
136
|
+
entry = state.get(repo.alias, {})
|
|
137
|
+
child_pid: int | None = entry.get("pid")
|
|
138
|
+
alive = child_pid is not None and pid_alive(child_pid)
|
|
139
|
+
status_str = "alive" if alive else "dead"
|
|
140
|
+
pid_str = str(child_pid) if child_pid is not None else "-"
|
|
141
|
+
print(f" {repo.alias:<{alias_width}} {status_str:<8} {pid_str:<8} {repo.path}")
|
|
142
|
+
else:
|
|
143
|
+
print(f" {'Alias':<{alias_width}} Path")
|
|
144
|
+
print(f" {'-' * alias_width} {'-' * 40}")
|
|
145
|
+
for repo in config.repos:
|
|
146
|
+
print(f" {repo.alias:<{alias_width}} {repo.path}")
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def _handle_logs(args: argparse.Namespace) -> None:
|
|
150
|
+
"""Show daemon or per-repo log files."""
|
|
151
|
+
from .daemon import load_config
|
|
152
|
+
|
|
153
|
+
config = load_config()
|
|
154
|
+
|
|
155
|
+
if args.repo:
|
|
156
|
+
log_file = config.log_dir / f"{args.repo}.log"
|
|
157
|
+
else:
|
|
158
|
+
log_file = config.log_dir / "daemon.log"
|
|
159
|
+
|
|
160
|
+
if not log_file.exists():
|
|
161
|
+
print(f"Log file not found: {log_file}")
|
|
162
|
+
sys.exit(1)
|
|
163
|
+
|
|
164
|
+
if args.follow:
|
|
165
|
+
try:
|
|
166
|
+
subprocess.run(["tail", "-f", str(log_file)], check=False)
|
|
167
|
+
except KeyboardInterrupt:
|
|
168
|
+
pass
|
|
169
|
+
return
|
|
170
|
+
|
|
171
|
+
# Read last N lines
|
|
172
|
+
lines_count = args.lines
|
|
173
|
+
try:
|
|
174
|
+
text = log_file.read_text(encoding="utf-8", errors="replace")
|
|
175
|
+
except OSError as exc:
|
|
176
|
+
print(f"Error reading log file: {exc}")
|
|
177
|
+
sys.exit(1)
|
|
178
|
+
|
|
179
|
+
lines = text.splitlines()
|
|
180
|
+
tail = lines[-lines_count:] if len(lines) > lines_count else lines
|
|
181
|
+
for line in tail:
|
|
182
|
+
print(line)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def _handle_add(args: argparse.Namespace) -> None:
|
|
186
|
+
"""Add a repository to the daemon config."""
|
|
187
|
+
from .daemon import add_repo_to_config, is_daemon_running
|
|
188
|
+
|
|
189
|
+
try:
|
|
190
|
+
add_repo_to_config(args.path, alias=args.alias)
|
|
191
|
+
except ValueError as exc:
|
|
192
|
+
print(f"Error: {exc}")
|
|
193
|
+
sys.exit(1)
|
|
194
|
+
|
|
195
|
+
# Find the repo we just added to show confirmation
|
|
196
|
+
alias = args.alias or os.path.basename(os.path.abspath(args.path))
|
|
197
|
+
print(f"Added repository: {args.path} (alias: {alias})")
|
|
198
|
+
|
|
199
|
+
if is_daemon_running():
|
|
200
|
+
print("Daemon will pick up the change automatically.")
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def _handle_remove(args: argparse.Namespace) -> None:
|
|
204
|
+
"""Remove a repository from the daemon config."""
|
|
205
|
+
from .daemon import is_daemon_running, load_config, remove_repo_from_config
|
|
206
|
+
|
|
207
|
+
config_before = load_config()
|
|
208
|
+
count_before = len(config_before.repos)
|
|
209
|
+
|
|
210
|
+
config_after = remove_repo_from_config(args.path_or_alias)
|
|
211
|
+
count_after = len(config_after.repos)
|
|
212
|
+
|
|
213
|
+
if count_before == count_after:
|
|
214
|
+
print(f"No repository matching '{args.path_or_alias}' found in config.")
|
|
215
|
+
sys.exit(1)
|
|
216
|
+
|
|
217
|
+
print(f"Removed repository: {args.path_or_alias}")
|
|
218
|
+
|
|
219
|
+
if is_daemon_running():
|
|
220
|
+
print("Daemon will pick up the change automatically.")
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
# ---------------------------------------------------------------------------
|
|
224
|
+
# Main entry point
|
|
225
|
+
# ---------------------------------------------------------------------------
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def main() -> None:
|
|
229
|
+
"""Entry point for the crg-daemon CLI."""
|
|
230
|
+
logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s")
|
|
231
|
+
|
|
232
|
+
ap = argparse.ArgumentParser(
|
|
233
|
+
prog="crg-daemon",
|
|
234
|
+
description="Multi-repo watch daemon for code-review-graph",
|
|
235
|
+
)
|
|
236
|
+
sub = ap.add_subparsers(dest="command")
|
|
237
|
+
|
|
238
|
+
# start
|
|
239
|
+
start_cmd = sub.add_parser("start", help="Start the daemon")
|
|
240
|
+
start_cmd.add_argument(
|
|
241
|
+
"--foreground",
|
|
242
|
+
action="store_true",
|
|
243
|
+
help="Run in the foreground instead of daemonizing",
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
# stop
|
|
247
|
+
sub.add_parser("stop", help="Stop the daemon")
|
|
248
|
+
|
|
249
|
+
# restart
|
|
250
|
+
restart_cmd = sub.add_parser("restart", help="Restart the daemon")
|
|
251
|
+
restart_cmd.add_argument(
|
|
252
|
+
"--foreground",
|
|
253
|
+
action="store_true",
|
|
254
|
+
help="Run in the foreground instead of daemonizing",
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
# status
|
|
258
|
+
sub.add_parser("status", help="Show daemon status and configuration")
|
|
259
|
+
|
|
260
|
+
# logs
|
|
261
|
+
logs_cmd = sub.add_parser("logs", help="Show daemon or per-repo logs")
|
|
262
|
+
logs_cmd.add_argument(
|
|
263
|
+
"--repo",
|
|
264
|
+
default=None,
|
|
265
|
+
metavar="ALIAS",
|
|
266
|
+
help="Show logs for a specific repo (by alias)",
|
|
267
|
+
)
|
|
268
|
+
logs_cmd.add_argument(
|
|
269
|
+
"--follow",
|
|
270
|
+
"-f",
|
|
271
|
+
action="store_true",
|
|
272
|
+
help="Follow log output (tail -f)",
|
|
273
|
+
)
|
|
274
|
+
logs_cmd.add_argument(
|
|
275
|
+
"--lines",
|
|
276
|
+
"-n",
|
|
277
|
+
type=int,
|
|
278
|
+
default=50,
|
|
279
|
+
help="Number of lines to show (default: 50)",
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
# add
|
|
283
|
+
add_cmd = sub.add_parser("add", help="Add a repository to the daemon config")
|
|
284
|
+
add_cmd.add_argument("path", help="Path to the repository")
|
|
285
|
+
add_cmd.add_argument(
|
|
286
|
+
"--alias",
|
|
287
|
+
default=None,
|
|
288
|
+
help="Short alias for the repository (default: directory name)",
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
# remove
|
|
292
|
+
remove_cmd = sub.add_parser("remove", help="Remove a repository from the daemon config")
|
|
293
|
+
remove_cmd.add_argument("path_or_alias", help="Repository path or alias to remove")
|
|
294
|
+
|
|
295
|
+
args = ap.parse_args()
|
|
296
|
+
|
|
297
|
+
if not args.command:
|
|
298
|
+
ap.print_help()
|
|
299
|
+
sys.exit(0)
|
|
300
|
+
|
|
301
|
+
handlers: dict[str, object] = {
|
|
302
|
+
"start": _handle_start,
|
|
303
|
+
"stop": _handle_stop,
|
|
304
|
+
"restart": _handle_restart,
|
|
305
|
+
"status": _handle_status,
|
|
306
|
+
"logs": _handle_logs,
|
|
307
|
+
"add": _handle_add,
|
|
308
|
+
"remove": _handle_remove,
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
handler = handlers.get(args.command)
|
|
312
|
+
if handler is None:
|
|
313
|
+
ap.print_help()
|
|
314
|
+
sys.exit(1)
|
|
315
|
+
|
|
316
|
+
handler(args) # type: ignore[operator]
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
if __name__ == "__main__":
|
|
320
|
+
main()
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# LLM-OPTIMIZED REFERENCE -- code-review-graph v2.3.6
|
|
2
|
+
|
|
3
|
+
AI coding agents: Read ONLY the exact `<section>` you need. Never load the whole file.
|
|
4
|
+
|
|
5
|
+
<section name="usage">
|
|
6
|
+
Quick install: pip install code-review-graph
|
|
7
|
+
Then: code-review-graph install && code-review-graph build
|
|
8
|
+
First run: /code-review-graph:build-graph
|
|
9
|
+
After that use only delta/pr commands.
|
|
10
|
+
ALWAYS start with get_minimal_context_tool(task="your task") — returns ~100 tokens with risk, communities, flows, and suggested next tools.
|
|
11
|
+
Use detail_level="minimal" on all subsequent calls unless you need more detail.
|
|
12
|
+
When present, context_savings is an estimated compact hint, not exact tokenization.
|
|
13
|
+
</section>
|
|
14
|
+
|
|
15
|
+
<section name="review-delta">
|
|
16
|
+
1. Call get_minimal_context_tool(task="review changes") first.
|
|
17
|
+
2. If risk is low: detect_changes_tool(detail_level="minimal") → report summary.
|
|
18
|
+
3. If risk is medium/high: detect_changes_tool(detail_level="standard") → expand on high-risk items.
|
|
19
|
+
Target: ≤5 tool calls, ≤800 tokens total context.
|
|
20
|
+
</section>
|
|
21
|
+
|
|
22
|
+
<section name="review-pr">
|
|
23
|
+
Fetch PR diff -> detect_changes_tool -> get_affected_flows_tool -> structured review with blast-radius table and risk scores.
|
|
24
|
+
Never include full files unless explicitly asked.
|
|
25
|
+
</section>
|
|
26
|
+
|
|
27
|
+
<section name="commands">
|
|
28
|
+
Core MCP tools: get_minimal_context_tool, detect_changes_tool, get_review_context_tool, get_impact_radius_tool, query_graph_tool, semantic_search_nodes_tool, get_architecture_overview_tool, get_affected_flows_tool, list_flows_tool, list_communities_tool, refactor_tool, build_or_update_graph_tool, run_postprocess_tool, embed_graph_tool, list_graph_stats_tool, get_docs_section_tool
|
|
29
|
+
MCP prompts (5): review_changes, architecture_map, debug_issue, onboard_developer, pre_merge_check
|
|
30
|
+
Skills: build-graph, debug-issue, explore-codebase, refactor-safely, review-changes, review-delta, review-pr
|
|
31
|
+
CLI: code-review-graph [install|init|build|update|status|watch|visualize|serve|mcp|wiki|detect-changes|postprocess|embed|register|unregister|repos|eval|daemon]
|
|
32
|
+
Token efficiency: Prefer detail_level="minimal" where available. Always call get_minimal_context_tool first. Some review/context tools return compact estimated context_savings metadata.
|
|
33
|
+
</section>
|
|
34
|
+
|
|
35
|
+
<section name="legal">
|
|
36
|
+
MIT licence. Core graph/review workflows are local and there is no telemetry. DB file: .code-review-graph/graph.db. Optional cloud embeddings send embedded source snippets to the configured provider only when selected.
|
|
37
|
+
</section>
|
|
38
|
+
|
|
39
|
+
<section name="watch">
|
|
40
|
+
Run: code-review-graph watch (auto-updates graph on file save via watchdog)
|
|
41
|
+
Or use PostToolUse (Write|Edit|Bash) hooks for automatic background updates.
|
|
42
|
+
</section>
|
|
43
|
+
|
|
44
|
+
<section name="embeddings">
|
|
45
|
+
Optional: pip install code-review-graph[embeddings]
|
|
46
|
+
Then call embed_graph_tool to compute vectors.
|
|
47
|
+
semantic_search_nodes_tool auto-uses vectors when available, falls back to keyword + FTS5.
|
|
48
|
+
Providers: local sentence-transformers, OpenAI-compatible endpoints, Google Gemini, and MiniMax.
|
|
49
|
+
Configure via provider/model parameters, CRG_EMBEDDING_MODEL for local, or CRG_OPENAI_* for OpenAI-compatible endpoints.
|
|
50
|
+
</section>
|
|
51
|
+
|
|
52
|
+
<section name="languages">
|
|
53
|
+
Supported: Python, JavaScript/TypeScript/TSX, Go, Rust, Java, C/C++, C#, Ruby, Kotlin, Swift, PHP, Scala, Solidity, Dart, R, Perl, Lua/Luau, Objective-C, shell scripts, Elixir, Zig, PowerShell, Julia, ReScript, GDScript, Nix, Verilog/SystemVerilog, SQL, Vue/Svelte SFCs, Astro files parsed through the TypeScript parser, Jupyter/Databricks notebooks, and Perl XS files.
|
|
54
|
+
Parser: Tree-sitter via tree-sitter-language-pack
|
|
55
|
+
Custom languages: add .code-review-graph/languages.toml (extensions + node types per grammar) — no fork needed, see docs/CUSTOM_LANGUAGES.md. Built-ins cannot be overridden.
|
|
56
|
+
</section>
|
|
57
|
+
|
|
58
|
+
<section name="troubleshooting">
|
|
59
|
+
DB lock: SQLite WAL mode, auto-recovers. Only one build at a time.
|
|
60
|
+
Large repos: First build 30-60s. Incremental <2s. Add patterns to .code-review-graphignore.
|
|
61
|
+
Stale graph: Run /code-review-graph:build-graph manually.
|
|
62
|
+
Missing nodes: Check language support + ignore patterns. Use full_rebuild=True.
|
|
63
|
+
Windows/WSL: Use forward slashes in paths. Ensure uv is on PATH in WSL.
|
|
64
|
+
</section>
|
|
65
|
+
|
|
66
|
+
**Instruction to AI coding agents (always follow):**
|
|
67
|
+
When user asks anything about "code-review-graph", "how to use", "commands", "review-delta", etc.:
|
|
68
|
+
1. Call get_docs_section_tool with the exact section name.
|
|
69
|
+
2. Use ONLY that content + current graph state.
|
|
70
|
+
3. Never include full docs or source code in your reasoning.
|
|
71
|
+
This keeps documentation lookup compact and avoids loading broad reference files by default.
|