codegraph-engine 2.1.7__py3-none-any.whl → 2.2.0__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.
- codegraph/__init__.py +1 -1
- codegraph/cli.py +177 -54
- codegraph/cli_output.py +190 -0
- codegraph/context.py +119 -3
- codegraph/database/interrogation.py +30 -7
- codegraph/freshness.py +59 -21
- codegraph/indexing/indexer.py +11 -4
- codegraph/installer.py +72 -22
- codegraph/interrogation.py +19 -0
- codegraph/mcp/server.py +97 -6
- codegraph/mcp_diagnostics.py +5 -2
- codegraph/monorepo.py +1 -1
- codegraph/process_lifecycle.py +1115 -0
- codegraph/runtime/runner.py +204 -0
- {codegraph_engine-2.1.7.dist-info → codegraph_engine-2.2.0.dist-info}/METADATA +48 -23
- {codegraph_engine-2.1.7.dist-info → codegraph_engine-2.2.0.dist-info}/RECORD +20 -17
- {codegraph_engine-2.1.7.dist-info → codegraph_engine-2.2.0.dist-info}/WHEEL +0 -0
- {codegraph_engine-2.1.7.dist-info → codegraph_engine-2.2.0.dist-info}/entry_points.txt +0 -0
- {codegraph_engine-2.1.7.dist-info → codegraph_engine-2.2.0.dist-info}/licenses/LICENSE +0 -0
- {codegraph_engine-2.1.7.dist-info → codegraph_engine-2.2.0.dist-info}/top_level.txt +0 -0
codegraph/mcp/server.py
CHANGED
|
@@ -173,6 +173,8 @@ def create_server(
|
|
|
173
173
|
repository: Path,
|
|
174
174
|
settings: Settings | None = None,
|
|
175
175
|
profile: str = "full",
|
|
176
|
+
host: str = "127.0.0.1",
|
|
177
|
+
port: int = 8765,
|
|
176
178
|
) -> Any:
|
|
177
179
|
"""Build an MCP FastMCP server lazily so normal CLI use needs no MCP dependency."""
|
|
178
180
|
try:
|
|
@@ -184,7 +186,12 @@ def create_server(
|
|
|
184
186
|
|
|
185
187
|
indexer = Indexer(repository, settings)
|
|
186
188
|
memory = MemoryStore(indexer.db_path)
|
|
187
|
-
app = FastMCP(
|
|
189
|
+
app = FastMCP(
|
|
190
|
+
"CodeGraph MCP",
|
|
191
|
+
instructions=render_agent_rules("antigravity"),
|
|
192
|
+
host=host,
|
|
193
|
+
port=port,
|
|
194
|
+
)
|
|
188
195
|
max_read_bytes = indexer.settings.max_read_bytes
|
|
189
196
|
|
|
190
197
|
# -----------------------------------------------------------------------
|
|
@@ -486,25 +493,79 @@ def create_server(
|
|
|
486
493
|
return git_analyze_change_impact(con, indexer.repository, since=since, until=until)
|
|
487
494
|
|
|
488
495
|
def get_repository_status() -> dict[str, object]:
|
|
489
|
-
"""Get repository indexing status, freshness, symbol counts, and health."""
|
|
496
|
+
"""Get repository indexing status, freshness, symbol counts, and health (automatically hot-reloads in-memory caches when `.codegraph.sqlite3` is created or updated by `codegraph init` / `codegraph index`)."""
|
|
497
|
+
from codegraph.resources.cache import get_graph_cache, get_parse_cache
|
|
498
|
+
|
|
499
|
+
get_graph_cache().clear()
|
|
500
|
+
get_parse_cache().clear()
|
|
501
|
+
if not indexer.db_path.exists():
|
|
502
|
+
return {
|
|
503
|
+
"status": "error",
|
|
504
|
+
"repository": str(indexer.repository),
|
|
505
|
+
"generation": 0,
|
|
506
|
+
"freshness": "NOT_INDEXED",
|
|
507
|
+
"freshness_detail": "No CodeGraph index exists for this repository.",
|
|
508
|
+
"files": 0,
|
|
509
|
+
"files_indexed": 0,
|
|
510
|
+
"symbols": 0,
|
|
511
|
+
"symbols_indexed": 0,
|
|
512
|
+
"graph_edges": 0,
|
|
513
|
+
"framework_routes": 0,
|
|
514
|
+
"reloaded": True,
|
|
515
|
+
"error": {
|
|
516
|
+
"code": "INDEX_NOT_FOUND",
|
|
517
|
+
"message": "No CodeGraph index exists for this repository.",
|
|
518
|
+
"next_action": {
|
|
519
|
+
"command": "codegraph init",
|
|
520
|
+
"reason": "Initialize the repository before querying it.",
|
|
521
|
+
},
|
|
522
|
+
},
|
|
523
|
+
}
|
|
490
524
|
with indexer.session() as con:
|
|
491
525
|
report = check_freshness(indexer.repository, con)
|
|
492
|
-
file_count = con.execute("SELECT count(*) FROM files").fetchone()[0]
|
|
493
|
-
symbol_count = con.execute("SELECT count(*) FROM symbols").fetchone()[0]
|
|
494
|
-
edge_count = con.execute("SELECT count(*) FROM graph_edges").fetchone()[0]
|
|
495
|
-
route_count = con.execute("SELECT count(*) FROM framework_routes").fetchone()[0]
|
|
526
|
+
file_count = int(con.execute("SELECT count(*) FROM files").fetchone()[0])
|
|
527
|
+
symbol_count = int(con.execute("SELECT count(*) FROM symbols").fetchone()[0])
|
|
528
|
+
edge_count = int(con.execute("SELECT count(*) FROM graph_edges").fetchone()[0])
|
|
529
|
+
route_count = int(con.execute("SELECT count(*) FROM framework_routes").fetchone()[0])
|
|
530
|
+
if file_count == 0:
|
|
531
|
+
return {
|
|
532
|
+
"status": "error",
|
|
533
|
+
"repository": str(indexer.repository),
|
|
534
|
+
"generation": report.index_generation,
|
|
535
|
+
"freshness": "NOT_INDEXED",
|
|
536
|
+
"freshness_detail": "No files are indexed in this repository.",
|
|
537
|
+
"files": 0,
|
|
538
|
+
"files_indexed": 0,
|
|
539
|
+
"symbols": 0,
|
|
540
|
+
"symbols_indexed": 0,
|
|
541
|
+
"graph_edges": 0,
|
|
542
|
+
"framework_routes": 0,
|
|
543
|
+
"reloaded": True,
|
|
544
|
+
"error": {
|
|
545
|
+
"code": "INDEX_NOT_FOUND",
|
|
546
|
+
"message": "No CodeGraph index exists for this repository.",
|
|
547
|
+
"next_action": {
|
|
548
|
+
"command": "codegraph init",
|
|
549
|
+
"reason": "Initialize the repository before querying it.",
|
|
550
|
+
},
|
|
551
|
+
},
|
|
552
|
+
}
|
|
496
553
|
return {
|
|
554
|
+
"status": "ok",
|
|
497
555
|
"repository": str(indexer.repository),
|
|
498
556
|
"generation": report.index_generation,
|
|
499
557
|
"freshness": report.status.value,
|
|
500
558
|
"freshness_detail": report.detail,
|
|
559
|
+
"files": file_count,
|
|
501
560
|
"files_indexed": file_count,
|
|
561
|
+
"symbols": symbol_count,
|
|
502
562
|
"symbols_indexed": symbol_count,
|
|
503
563
|
"graph_edges": edge_count,
|
|
504
564
|
"framework_routes": route_count,
|
|
505
565
|
"modified_files": report.modified_files,
|
|
506
566
|
"deleted_files": report.deleted_files,
|
|
507
567
|
"parse_failed_files": report.parse_failed_files,
|
|
568
|
+
"reloaded": True,
|
|
508
569
|
}
|
|
509
570
|
|
|
510
571
|
def trace_call(
|
|
@@ -1024,12 +1085,41 @@ def create_server(
|
|
|
1024
1085
|
else:
|
|
1025
1086
|
selected_names = set(all_tools.keys())
|
|
1026
1087
|
|
|
1088
|
+
_last_db_sig: list[tuple[int, int, int, int] | None] = [None]
|
|
1089
|
+
|
|
1090
|
+
def _compute_db_sig() -> tuple[int, int, int, int] | None:
|
|
1091
|
+
db_file = indexer.db_path
|
|
1092
|
+
if not db_file.exists():
|
|
1093
|
+
return None
|
|
1094
|
+
try:
|
|
1095
|
+
st = db_file.stat()
|
|
1096
|
+
wal_file = Path(f"{db_file}-wal")
|
|
1097
|
+
wal_mtime = wal_file.stat().st_mtime_ns if wal_file.exists() else 0
|
|
1098
|
+
return (st.st_ino, st.st_mtime_ns, st.st_size, wal_mtime)
|
|
1099
|
+
except OSError:
|
|
1100
|
+
return None
|
|
1101
|
+
|
|
1102
|
+
_last_db_sig[0] = _compute_db_sig()
|
|
1103
|
+
|
|
1104
|
+
def _ensure_hot_reloaded() -> bool:
|
|
1105
|
+
"""Detect if `.codegraph.sqlite3` was created, replaced, or updated on disk (e.g. via `codegraph init`)."""
|
|
1106
|
+
cur_sig = _compute_db_sig()
|
|
1107
|
+
if cur_sig != _last_db_sig[0]:
|
|
1108
|
+
_last_db_sig[0] = cur_sig
|
|
1109
|
+
from codegraph.resources.cache import get_graph_cache, get_parse_cache
|
|
1110
|
+
|
|
1111
|
+
get_graph_cache().clear()
|
|
1112
|
+
get_parse_cache().clear()
|
|
1113
|
+
return True
|
|
1114
|
+
return False
|
|
1115
|
+
|
|
1027
1116
|
for tool_name in sorted(selected_names):
|
|
1028
1117
|
target_fn: Any = all_tools[tool_name]
|
|
1029
1118
|
|
|
1030
1119
|
def _make_guarded(fn: Any) -> Any:
|
|
1031
1120
|
@functools.wraps(fn)
|
|
1032
1121
|
def _guarded(*args: Any, **kwargs: Any) -> Any:
|
|
1122
|
+
_ensure_hot_reloaded()
|
|
1033
1123
|
with indexer.governor.task_scope(TaskPriority.INTERACTIVE_HIGH):
|
|
1034
1124
|
return fn(*args, **kwargs)
|
|
1035
1125
|
|
|
@@ -1151,4 +1241,5 @@ def create_server(
|
|
|
1151
1241
|
"2. Run `get_context` with intent='REVIEW'."
|
|
1152
1242
|
)
|
|
1153
1243
|
|
|
1244
|
+
app._codegraph_indexer = indexer # type: ignore[attr-defined]
|
|
1154
1245
|
return app
|
codegraph/mcp_diagnostics.py
CHANGED
|
@@ -111,14 +111,17 @@ class MCPDoctorReport:
|
|
|
111
111
|
"discovered_tools": list(self.discovered_tools),
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
def format_human(self) -> str:
|
|
114
|
+
def format_human(self, *, unicode_override: bool | None = None) -> str:
|
|
115
|
+
from codegraph.cli_output import get_cli_symbols
|
|
116
|
+
|
|
117
|
+
sym = get_cli_symbols(unicode_override=unicode_override)
|
|
115
118
|
lines = [
|
|
116
119
|
"CodeGraph MCP Doctor",
|
|
117
120
|
"--------------------",
|
|
118
121
|
"",
|
|
119
122
|
]
|
|
120
123
|
for chk in self.checks:
|
|
121
|
-
mark =
|
|
124
|
+
mark = sym.ok if chk.passed else sym.error
|
|
122
125
|
lines.append(f"{mark} {chk.name}")
|
|
123
126
|
return "\n".join(lines)
|
|
124
127
|
|
codegraph/monorepo.py
CHANGED
|
@@ -29,7 +29,7 @@ from codegraph.indexing.classifier import FileCategory, classify_file
|
|
|
29
29
|
from codegraph.security import is_sensitive, safe_path
|
|
30
30
|
|
|
31
31
|
try:
|
|
32
|
-
import yaml
|
|
32
|
+
import yaml
|
|
33
33
|
_HAS_YAML = True
|
|
34
34
|
except ImportError:
|
|
35
35
|
_HAS_YAML = False
|