codegraphcontext 0.4.13__py3-none-any.whl → 0.4.14__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.
- codegraphcontext/cli/config_manager.py +12 -12
- codegraphcontext/cli/main.py +3 -3
- codegraphcontext/cli/registry_commands.py +5 -3
- codegraphcontext/cli/setup_wizard.py +19 -7
- codegraphcontext/core/__init__.py +28 -0
- codegraphcontext/core/cgc_bundle.py +1 -1
- codegraphcontext/core/database_falkordb.py +76 -9
- codegraphcontext/core/database_kuzu.py +5 -2
- codegraphcontext/server.py +11 -1
- codegraphcontext/tools/advanced_language_query_tool.py +5 -3
- codegraphcontext/tools/code_finder.py +4 -2
- codegraphcontext/tools/graph_builder.py +6 -2
- codegraphcontext/tools/indexing/persistence/writer.py +29 -3
- codegraphcontext/tools/indexing/pre_scan.py +2 -0
- codegraphcontext/tools/indexing/scip_pipeline.py +1 -1
- codegraphcontext/tools/scip_indexer.py +3 -2
- codegraphcontext/tools/system.py +8 -3
- codegraphcontext/viz/server.py +4 -2
- {codegraphcontext-0.4.13.dist-info → codegraphcontext-0.4.14.dist-info}/METADATA +32 -10
- {codegraphcontext-0.4.13.dist-info → codegraphcontext-0.4.14.dist-info}/RECORD +24 -24
- {codegraphcontext-0.4.13.dist-info → codegraphcontext-0.4.14.dist-info}/WHEEL +0 -0
- {codegraphcontext-0.4.13.dist-info → codegraphcontext-0.4.14.dist-info}/entry_points.txt +0 -0
- {codegraphcontext-0.4.13.dist-info → codegraphcontext-0.4.14.dist-info}/licenses/LICENSE +0 -0
- {codegraphcontext-0.4.13.dist-info → codegraphcontext-0.4.14.dist-info}/top_level.txt +0 -0
|
@@ -234,7 +234,7 @@ def load_config() -> Dict[str, str]:
|
|
|
234
234
|
# Load global config
|
|
235
235
|
if CONFIG_FILE.exists():
|
|
236
236
|
try:
|
|
237
|
-
with open(CONFIG_FILE, "r") as f:
|
|
237
|
+
with open(CONFIG_FILE, "r", encoding="utf-8") as f:
|
|
238
238
|
for line in f:
|
|
239
239
|
line = line.strip()
|
|
240
240
|
if line and not line.startswith("#") and "=" in line:
|
|
@@ -247,7 +247,7 @@ def load_config() -> Dict[str, str]:
|
|
|
247
247
|
local_env = find_local_env()
|
|
248
248
|
if local_env and local_env.exists():
|
|
249
249
|
try:
|
|
250
|
-
with open(local_env, "r") as f:
|
|
250
|
+
with open(local_env, "r", encoding="utf-8") as f:
|
|
251
251
|
for line in f:
|
|
252
252
|
line = line.strip()
|
|
253
253
|
if line and not line.startswith("#") and "=" in line:
|
|
@@ -321,7 +321,7 @@ def save_config(config: Dict[str, str], preserve_db_credentials: bool = True):
|
|
|
321
321
|
if preserve_db_credentials and CONFIG_FILE.exists():
|
|
322
322
|
# Load existing credentials from file to preserve them
|
|
323
323
|
try:
|
|
324
|
-
with open(CONFIG_FILE, "r") as f:
|
|
324
|
+
with open(CONFIG_FILE, "r", encoding="utf-8") as f:
|
|
325
325
|
for line in f:
|
|
326
326
|
line = line.strip()
|
|
327
327
|
if line and not line.startswith("#") and "=" in line:
|
|
@@ -342,7 +342,7 @@ def save_config(config: Dict[str, str], preserve_db_credentials: bool = True):
|
|
|
342
342
|
credentials_to_write[key] = config[key]
|
|
343
343
|
|
|
344
344
|
try:
|
|
345
|
-
with open(CONFIG_FILE, "w") as f:
|
|
345
|
+
with open(CONFIG_FILE, "w", encoding="utf-8") as f:
|
|
346
346
|
f.write("# CodeGraphContext Configuration\n")
|
|
347
347
|
f.write(f"# Location: {CONFIG_FILE}\n\n")
|
|
348
348
|
|
|
@@ -696,7 +696,7 @@ def load_context_config() -> ContextConfig:
|
|
|
696
696
|
return cfg
|
|
697
697
|
|
|
698
698
|
try:
|
|
699
|
-
with open(CONTEXT_CONFIG_FILE, "r") as f:
|
|
699
|
+
with open(CONTEXT_CONFIG_FILE, "r", encoding="utf-8") as f:
|
|
700
700
|
raw = yaml.safe_load(f) or {}
|
|
701
701
|
|
|
702
702
|
contexts: Dict[str, ContextInfo] = {}
|
|
@@ -746,7 +746,7 @@ def save_context_config(cfg: ContextConfig) -> None:
|
|
|
746
746
|
}
|
|
747
747
|
|
|
748
748
|
try:
|
|
749
|
-
with open(CONTEXT_CONFIG_FILE, "w") as f:
|
|
749
|
+
with open(CONTEXT_CONFIG_FILE, "w", encoding="utf-8") as f:
|
|
750
750
|
yaml.dump(raw, f, default_flow_style=False, sort_keys=False)
|
|
751
751
|
except Exception as e:
|
|
752
752
|
console.print(f"[red]Error saving config.yaml: {e}[/red]")
|
|
@@ -838,7 +838,7 @@ def resolve_context(
|
|
|
838
838
|
local_db = "falkordb"
|
|
839
839
|
if local_yaml.exists():
|
|
840
840
|
try:
|
|
841
|
-
with open(local_yaml) as f:
|
|
841
|
+
with open(local_yaml, encoding="utf-8") as f:
|
|
842
842
|
local_raw = yaml.safe_load(f) or {}
|
|
843
843
|
local_db = local_raw.get("database", "falkordb")
|
|
844
844
|
except Exception:
|
|
@@ -1053,7 +1053,7 @@ def discover_child_contexts(
|
|
|
1053
1053
|
local_yaml = candidate / "config.yaml"
|
|
1054
1054
|
if local_yaml.exists():
|
|
1055
1055
|
try:
|
|
1056
|
-
with open(local_yaml) as f:
|
|
1056
|
+
with open(local_yaml, encoding="utf-8") as f:
|
|
1057
1057
|
raw = yaml.safe_load(f) or {}
|
|
1058
1058
|
local_db = raw.get("database", "falkordb")
|
|
1059
1059
|
except Exception:
|
|
@@ -1082,7 +1082,7 @@ def _load_workspace_mappings() -> Dict[str, Dict[str, str]]:
|
|
|
1082
1082
|
if not CONTEXT_CONFIG_FILE.exists():
|
|
1083
1083
|
return {}
|
|
1084
1084
|
try:
|
|
1085
|
-
with open(CONTEXT_CONFIG_FILE, "r") as f:
|
|
1085
|
+
with open(CONTEXT_CONFIG_FILE, "r", encoding="utf-8") as f:
|
|
1086
1086
|
raw = yaml.safe_load(f) or {}
|
|
1087
1087
|
return raw.get("workspace_mappings", {}) or {}
|
|
1088
1088
|
except Exception:
|
|
@@ -1096,13 +1096,13 @@ def _save_workspace_mappings(mappings: Dict[str, Dict[str, str]]) -> None:
|
|
|
1096
1096
|
raw: Dict[str, Any] = {}
|
|
1097
1097
|
if CONTEXT_CONFIG_FILE.exists():
|
|
1098
1098
|
try:
|
|
1099
|
-
with open(CONTEXT_CONFIG_FILE, "r") as f:
|
|
1099
|
+
with open(CONTEXT_CONFIG_FILE, "r", encoding="utf-8") as f:
|
|
1100
1100
|
raw = yaml.safe_load(f) or {}
|
|
1101
1101
|
except Exception:
|
|
1102
1102
|
raw = {}
|
|
1103
1103
|
raw["workspace_mappings"] = mappings
|
|
1104
1104
|
try:
|
|
1105
|
-
with open(CONTEXT_CONFIG_FILE, "w") as f:
|
|
1105
|
+
with open(CONTEXT_CONFIG_FILE, "w", encoding="utf-8") as f:
|
|
1106
1106
|
yaml.dump(raw, f, default_flow_style=False, sort_keys=False)
|
|
1107
1107
|
except Exception as e:
|
|
1108
1108
|
console.print(f"[red]Error saving workspace mappings: {e}[/red]")
|
|
@@ -1124,7 +1124,7 @@ def save_workspace_mapping(cwd: Path, context_path: Path) -> None:
|
|
|
1124
1124
|
local_yaml = context_path / "config.yaml"
|
|
1125
1125
|
if local_yaml.exists():
|
|
1126
1126
|
try:
|
|
1127
|
-
with open(local_yaml) as f:
|
|
1127
|
+
with open(local_yaml, encoding="utf-8") as f:
|
|
1128
1128
|
raw = yaml.safe_load(f) or {}
|
|
1129
1129
|
local_db = raw.get("database", "falkordb")
|
|
1130
1130
|
except Exception:
|
codegraphcontext/cli/main.py
CHANGED
|
@@ -22,7 +22,6 @@ from pathlib import Path
|
|
|
22
22
|
from importlib.metadata import version as pkg_version, PackageNotFoundError
|
|
23
23
|
|
|
24
24
|
from codegraphcontext.server import MCPServer
|
|
25
|
-
from codegraphcontext.core.database import DatabaseManager
|
|
26
25
|
from .setup_wizard import run_neo4j_setup_wizard, configure_mcp_client
|
|
27
26
|
from . import config_manager
|
|
28
27
|
# Import the new helper functions
|
|
@@ -108,7 +107,7 @@ def mcp_setup():
|
|
|
108
107
|
Configure MCP Client (IDE/CLI Integration).
|
|
109
108
|
|
|
110
109
|
Sets up CodeGraphContext integration with your IDE or CLI tool:
|
|
111
|
-
- VS Code, Cursor, Windsurf
|
|
110
|
+
- VS Code, Cursor, Windsurf, Zed
|
|
112
111
|
- Claude Desktop, Gemini CLI
|
|
113
112
|
- Cline, RooCode, Amazon Q Developer, Goose
|
|
114
113
|
- OpenCode (prints stdio config + link to vendor docs)
|
|
@@ -125,7 +124,7 @@ def mcp_start():
|
|
|
125
124
|
Start the CodeGraphContext MCP server.
|
|
126
125
|
|
|
127
126
|
Starts the server which listens for JSON-RPC requests from stdin.
|
|
128
|
-
This is used by IDE integrations (VS Code, Cursor, etc.).
|
|
127
|
+
This is used by IDE integrations (VS Code, Cursor, Zed, etc.).
|
|
129
128
|
"""
|
|
130
129
|
console.print("[bold green]Starting CodeGraphContext Server...[/bold green]")
|
|
131
130
|
_load_credentials()
|
|
@@ -979,6 +978,7 @@ def doctor():
|
|
|
979
978
|
password = os.environ.get("NEO4J_PASSWORD")
|
|
980
979
|
database_name = os.environ.get("NEO4J_DATABASE")
|
|
981
980
|
|
|
981
|
+
from codegraphcontext.core.database import DatabaseManager
|
|
982
982
|
missing = DatabaseManager.get_missing_credentials(uri, username, password)
|
|
983
983
|
console.print(f" [cyan]Credential check:[/cyan] {'OK' if not missing else 'Missing ' + ', '.join(missing)}")
|
|
984
984
|
if missing:
|
|
@@ -177,6 +177,8 @@ def download_bundle(name: str, output_dir: Optional[str] = None, auto_load: bool
|
|
|
177
177
|
and base names (e.g., 'python-bitcoin-utils' - picks most recent version).
|
|
178
178
|
"""
|
|
179
179
|
console.print(f"[cyan]Looking for bundle '{name}'...[/cyan]")
|
|
180
|
+
|
|
181
|
+
lookup_name = name[:-4] if name.lower().endswith('.cgc') else name
|
|
180
182
|
|
|
181
183
|
bundles = fetch_available_bundles()
|
|
182
184
|
|
|
@@ -187,7 +189,7 @@ def download_bundle(name: str, output_dir: Optional[str] = None, auto_load: bool
|
|
|
187
189
|
# Strategy 1: Try exact match on full_name (with version)
|
|
188
190
|
bundle = None
|
|
189
191
|
for b in bundles:
|
|
190
|
-
if b.get('full_name', '').lower() ==
|
|
192
|
+
if b.get('full_name', '').lower() == lookup_name.lower():
|
|
191
193
|
bundle = b
|
|
192
194
|
console.print(f"[dim]Found exact match: {b.get('full_name')}[/dim]")
|
|
193
195
|
break
|
|
@@ -197,7 +199,7 @@ def download_bundle(name: str, output_dir: Optional[str] = None, auto_load: bool
|
|
|
197
199
|
if not bundle:
|
|
198
200
|
matching_bundles = []
|
|
199
201
|
for b in bundles:
|
|
200
|
-
if b.get('name', '').lower() ==
|
|
202
|
+
if b.get('name', '').lower() == lookup_name.lower():
|
|
201
203
|
matching_bundles.append(b)
|
|
202
204
|
|
|
203
205
|
if matching_bundles:
|
|
@@ -220,7 +222,7 @@ def download_bundle(name: str, output_dir: Optional[str] = None, auto_load: bool
|
|
|
220
222
|
if not bundle:
|
|
221
223
|
# Find bundles with similar base names
|
|
222
224
|
suggestions = []
|
|
223
|
-
name_lower =
|
|
225
|
+
name_lower = lookup_name.lower()
|
|
224
226
|
for b in bundles:
|
|
225
227
|
base_name = b.get('name', '').lower()
|
|
226
228
|
full_name = b.get('full_name', '').lower()
|
|
@@ -256,7 +256,7 @@ def _configure_ide(mcp_config):
|
|
|
256
256
|
questions = [
|
|
257
257
|
{
|
|
258
258
|
"type": "confirm",
|
|
259
|
-
"message": "Automatically configure your IDE/CLI (VS Code, Cursor, Windsurf, Claude, Gemini, Cline, RooCode, ChatGPT Codex, Amazon Q Developer, Aider, Kiro, Goose, Antigravity, OpenCode)?",
|
|
259
|
+
"message": "Automatically configure your IDE/CLI (VS Code, Cursor, Windsurf, Zed, Claude, Gemini, Cline, RooCode, ChatGPT Codex, Amazon Q Developer, Aider, Kiro, Goose, Antigravity, OpenCode)?",
|
|
260
260
|
"name": "configure_ide",
|
|
261
261
|
"default": True,
|
|
262
262
|
}
|
|
@@ -270,7 +270,7 @@ def _configure_ide(mcp_config):
|
|
|
270
270
|
{
|
|
271
271
|
"type": "list",
|
|
272
272
|
"message": "Choose your IDE/CLI to configure:",
|
|
273
|
-
"choices": ["VS Code", "Cursor", "Windsurf", "Claude code", "Gemini CLI", "ChatGPT Codex", "Cline", "RooCode", "Amazon Q Developer", "JetBrainsAI", "Aider", "Kiro", "Goose", "Antigravity", "OpenCode", "None of the above"],
|
|
273
|
+
"choices": ["VS Code", "Cursor", "Windsurf", "Zed", "Claude code", "Gemini CLI", "ChatGPT Codex", "Cline", "RooCode", "Amazon Q Developer", "JetBrainsAI", "Aider", "Kiro", "Goose", "Antigravity", "OpenCode", "None of the above"],
|
|
274
274
|
"name": "ide_choice",
|
|
275
275
|
}
|
|
276
276
|
]
|
|
@@ -289,7 +289,7 @@ def _configure_ide(mcp_config):
|
|
|
289
289
|
)
|
|
290
290
|
return
|
|
291
291
|
|
|
292
|
-
if ide_choice in ["VS Code", "Cursor", "Windsurf", "Claude code", "Gemini CLI", "ChatGPT Codex", "Cline", "RooCode", "Amazon Q Developer", "JetBrainsAI", "Aider", "Kiro", "Goose", "Antigravity"]:
|
|
292
|
+
if ide_choice in ["VS Code", "Cursor", "Windsurf", "Zed", "Claude code", "Gemini CLI", "ChatGPT Codex", "Cline", "RooCode", "Amazon Q Developer", "JetBrainsAI", "Aider", "Kiro", "Goose", "Antigravity"]:
|
|
293
293
|
console.print(f"\n[bold cyan]Configuring for {ide_choice}...[/bold cyan]")
|
|
294
294
|
|
|
295
295
|
if ide_choice == "Amazon Q Developer":
|
|
@@ -320,6 +320,10 @@ def _configure_ide(mcp_config):
|
|
|
320
320
|
Path.home() / "AppData" / "Roaming" / "windsurf" / "settings.json",
|
|
321
321
|
Path.home() / ".config" / "Windsurf" / "User" / "settings.json",
|
|
322
322
|
],
|
|
323
|
+
"Zed": [
|
|
324
|
+
Path.home() / ".config" / "zed" / "settings.json",
|
|
325
|
+
Path.home() / "AppData" / "Roaming" / "Zed" / "settings.json"
|
|
326
|
+
],
|
|
323
327
|
"Claude code": [
|
|
324
328
|
Path.home() / ".claude.json"
|
|
325
329
|
],
|
|
@@ -398,10 +402,14 @@ def _configure_ide(mcp_config):
|
|
|
398
402
|
console.print(f"[red]Error: Configuration file at {target_path} is not a valid JSON object.[/red]")
|
|
399
403
|
return
|
|
400
404
|
|
|
401
|
-
if "
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
+
if ide_choice == "Zed":
|
|
406
|
+
if "context_servers" not in settings:
|
|
407
|
+
settings["context_servers"] = {}
|
|
408
|
+
settings["context_servers"].update(mcp_config["mcpServers"])
|
|
409
|
+
else:
|
|
410
|
+
if "mcpServers" not in settings:
|
|
411
|
+
settings["mcpServers"] = {}
|
|
412
|
+
settings["mcpServers"].update(mcp_config["mcpServers"])
|
|
405
413
|
|
|
406
414
|
try:
|
|
407
415
|
with open(target_path, "w") as f:
|
|
@@ -677,6 +685,7 @@ def setup_existing_db():
|
|
|
677
685
|
|
|
678
686
|
# Validate the user input
|
|
679
687
|
console.print("\n[cyan]🔍 Validating configuration...[/cyan]")
|
|
688
|
+
from codegraphcontext.core.database import DatabaseManager
|
|
680
689
|
is_valid, validation_error = DatabaseManager.validate_config(
|
|
681
690
|
manual_creds.get("uri", ""),
|
|
682
691
|
manual_creds.get("username", ""),
|
|
@@ -795,6 +804,7 @@ def setup_hosted_db():
|
|
|
795
804
|
|
|
796
805
|
# Validate the user input
|
|
797
806
|
console.print("\n[cyan]🔍 Validating configuration...[/cyan]")
|
|
807
|
+
from codegraphcontext.core.database import DatabaseManager
|
|
798
808
|
is_valid, validation_error = DatabaseManager.validate_config(
|
|
799
809
|
manual_creds.get("uri", ""),
|
|
800
810
|
manual_creds.get("username", ""),
|
|
@@ -913,6 +923,7 @@ volumes:
|
|
|
913
923
|
|
|
914
924
|
# Validate configuration format before attempting Docker operations
|
|
915
925
|
console.print("\n[cyan]🔍 Validating configuration...[/cyan]")
|
|
926
|
+
from codegraphcontext.core.database import DatabaseManager
|
|
916
927
|
is_valid, validation_error = DatabaseManager.validate_config(
|
|
917
928
|
DEFAULT_NEO4J_URI,
|
|
918
929
|
DEFAULT_NEO4J_USERNAME,
|
|
@@ -972,6 +983,7 @@ volumes:
|
|
|
972
983
|
|
|
973
984
|
# updated test_connection method
|
|
974
985
|
console.print(f"[yellow]Testing connection... (attempt {attempt + 1}/{max_attempts})[/yellow]")
|
|
986
|
+
from codegraphcontext.core.database import DatabaseManager
|
|
975
987
|
is_connected, error_msg = DatabaseManager.test_connection(DEFAULT_NEO4J_URI, DEFAULT_NEO4J_USERNAME, password)
|
|
976
988
|
|
|
977
989
|
if is_connected:
|
|
@@ -101,6 +101,12 @@ def get_database_manager(db_path: Optional[str] = None) -> Union['DatabaseManage
|
|
|
101
101
|
from .database_falkordb import FalkorDBManager, FalkorDBUnavailableError
|
|
102
102
|
try:
|
|
103
103
|
mgr = FalkorDBManager(db_path=db_path)
|
|
104
|
+
# Eagerly probe the connection so any FalkorDBUnavailableError
|
|
105
|
+
# (e.g. redis-py/falkordblite version mismatch — issue #1035)
|
|
106
|
+
# surfaces *here*, while we can still fall back to KùzuDB.
|
|
107
|
+
# ``get_driver`` is idempotent (singleton-guarded), so the
|
|
108
|
+
# subsequent real call from server.py costs nothing.
|
|
109
|
+
mgr.get_driver()
|
|
104
110
|
info_logger(f"Using FalkorDB Lite (explicit) at {db_path or 'default path'}")
|
|
105
111
|
return mgr
|
|
106
112
|
except FalkorDBUnavailableError as falkor_err:
|
|
@@ -153,6 +159,9 @@ def get_database_manager(db_path: Optional[str] = None) -> Union['DatabaseManage
|
|
|
153
159
|
from .database_falkordb import FalkorDBManager, FalkorDBUnavailableError
|
|
154
160
|
try:
|
|
155
161
|
mgr = FalkorDBManager(db_path=db_path)
|
|
162
|
+
# Eagerly probe so dep/version failures (issue #1035) surface here
|
|
163
|
+
# while we can still fall through to KùzuDB below.
|
|
164
|
+
mgr.get_driver()
|
|
156
165
|
info_logger(f"Using FalkorDB Lite (default) at {db_path or 'default path'}")
|
|
157
166
|
return mgr
|
|
158
167
|
except FalkorDBUnavailableError as falkor_err:
|
|
@@ -196,6 +205,25 @@ def get_database_manager(db_path: Optional[str] = None) -> Union['DatabaseManage
|
|
|
196
205
|
|
|
197
206
|
raise ValueError(error_msg)
|
|
198
207
|
|
|
208
|
+
# Lazy backward-compatibility exports — avoids crashing when optional
|
|
209
|
+
# database drivers (neo4j, falkordb, real_ladybug, …) are not installed.
|
|
210
|
+
# Uses PEP 562 module-level __getattr__ so that:
|
|
211
|
+
# from codegraphcontext.core import DatabaseManager
|
|
212
|
+
# still works, but only triggers the real import when actually accessed.
|
|
213
|
+
_LAZY_IMPORTS = {
|
|
214
|
+
'DatabaseManager': '.database',
|
|
215
|
+
'FalkorDBManager': '.database_falkordb',
|
|
216
|
+
'FalkorDBRemoteManager': '.database_falkordb_remote',
|
|
217
|
+
'KuzuDBManager': '.database_kuzu',
|
|
218
|
+
'NornicDBManager': '.database_nornic',
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
def __getattr__(name: str):
|
|
222
|
+
if name in _LAZY_IMPORTS:
|
|
223
|
+
import importlib
|
|
224
|
+
module = importlib.import_module(_LAZY_IMPORTS[name], __package__)
|
|
225
|
+
return getattr(module, name)
|
|
226
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
199
227
|
# For backward compatibility, export managers
|
|
200
228
|
from .database import DatabaseManager
|
|
201
229
|
from .database_falkordb import FalkorDBManager
|
|
@@ -139,7 +139,7 @@ class CGCBundle:
|
|
|
139
139
|
from importlib.metadata import version as get_version
|
|
140
140
|
py_version = get_version("codegraphcontext")
|
|
141
141
|
except Exception:
|
|
142
|
-
py_version = "0.4.
|
|
142
|
+
py_version = "0.4.14"
|
|
143
143
|
|
|
144
144
|
metadata["format_version"] = "1.0.0"
|
|
145
145
|
metadata["generator"] = f"PYv{py_version}"
|
|
@@ -23,17 +23,51 @@ from typing import Optional, Tuple
|
|
|
23
23
|
from codegraphcontext.utils.debug_log import debug_log, info_logger, error_logger, warning_logger
|
|
24
24
|
|
|
25
25
|
# ---------------------------------------------------------------------------
|
|
26
|
-
# Compatibility patch: redis-py
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
-
#
|
|
31
|
-
#
|
|
26
|
+
# Compatibility patch: newer redis-py releases assume every Connection exposes
|
|
27
|
+
# ``host`` and ``port`` attributes, but ``UnixDomainSocketConnection`` historically
|
|
28
|
+
# has neither. Two failure modes have been observed in the wild:
|
|
29
|
+
#
|
|
30
|
+
# 1. redis-py >= 5.x added OpenTelemetry error telemetry that reads ``conn.port``
|
|
31
|
+
# inside its error handler. The missing attribute raised a secondary
|
|
32
|
+
# ``AttributeError`` that masked the real connection error.
|
|
33
|
+
# 2. redis-py >= 6.x added a maintenance-notifications handshake
|
|
34
|
+
# (``activate_maint_notifications_handling_if_enabled`` →
|
|
35
|
+
# ``_enable_maintenance_notifications``) that raises ``ValueError`` on any
|
|
36
|
+
# connection without a ``host`` attribute — breaking FalkorDB Lite's
|
|
37
|
+
# Unix-socket connection entirely (upstream issue #1035).
|
|
38
|
+
#
|
|
39
|
+
# Patching the class at import time is cheap and fixes every call-site. The
|
|
40
|
+
# values themselves are inert sentinels: FalkorDB Lite never uses TCP, so no
|
|
41
|
+
# code path will dereference them as a real ``(host, port)`` pair.
|
|
32
42
|
# ---------------------------------------------------------------------------
|
|
33
43
|
try:
|
|
34
44
|
from redis.connection import UnixDomainSocketConnection as _UDSC
|
|
45
|
+
|
|
46
|
+
# ``port`` was never an attribute on UDSC; if it is missing, install a sentinel.
|
|
35
47
|
if not hasattr(_UDSC, 'port'):
|
|
36
48
|
_UDSC.port = 0 # type: ignore[attr-defined]
|
|
49
|
+
|
|
50
|
+
# ``host`` is trickier. On redis-py >= 6 ``UDSC`` inherits an *abstract*
|
|
51
|
+
# ``host`` property (from ``MaintNotificationsAbstractConnection``) whose
|
|
52
|
+
# default body just returns ``None``. The maintenance-notifications
|
|
53
|
+
# handshake then does ``getattr(self, "host", None)``; because the property
|
|
54
|
+
# *exists* on the class, ``getattr`` returns ``None`` instead of falling
|
|
55
|
+
# through to its default — and the handshake raises ValueError.
|
|
56
|
+
#
|
|
57
|
+
# ``hasattr(_UDSC, 'host')`` is therefore the wrong check: we must inspect
|
|
58
|
+
# an instance. We probe a bare instance (``object.__new__`` skips
|
|
59
|
+
# ``__init__``, so we don't need a path) and override the class attribute
|
|
60
|
+
# with an inert string whenever the inherited property would yield ``None``.
|
|
61
|
+
try:
|
|
62
|
+
_probe = object.__new__(_UDSC)
|
|
63
|
+
if getattr(_probe, 'host', None) is None:
|
|
64
|
+
_UDSC.host = 'localhost' # type: ignore[attr-defined]
|
|
65
|
+
del _probe
|
|
66
|
+
except Exception:
|
|
67
|
+
# Probing failed for an unrelated reason; do the safe thing and
|
|
68
|
+
# install the sentinel anyway. Worst case we shadow a working property
|
|
69
|
+
# with a constant, which is still preferable to a crash.
|
|
70
|
+
_UDSC.host = 'localhost' # type: ignore[attr-defined]
|
|
37
71
|
except Exception:
|
|
38
72
|
pass # redis not installed or class structure changed — safe to ignore
|
|
39
73
|
|
|
@@ -149,8 +183,19 @@ class FalkorDBManager:
|
|
|
149
183
|
from falkordb import FalkorDB
|
|
150
184
|
|
|
151
185
|
info_logger(f"Connecting to FalkorDB Lite at {self.socket_path}")
|
|
152
|
-
|
|
153
|
-
|
|
186
|
+
try:
|
|
187
|
+
self._driver = FalkorDB(unix_socket_path=self.socket_path)
|
|
188
|
+
self._graph = self._driver.select_graph(self.graph_name)
|
|
189
|
+
except ValueError as ve:
|
|
190
|
+
# redis-py >= 6 raises ValueError on Unix-socket connections that
|
|
191
|
+
# lack a 'host' attribute (see upstream issue #1035). Even with the
|
|
192
|
+
# import-time shim above, newer redis-py revisions may shift the
|
|
193
|
+
# check. Convert to FalkorDBUnavailableError so the caller can fall
|
|
194
|
+
# back to KùzuDB instead of crashing the whole MCP server.
|
|
195
|
+
raise FalkorDBUnavailableError(
|
|
196
|
+
f"FalkorDB Lite client refused the Unix-socket connection: {ve}. "
|
|
197
|
+
"This typically indicates a redis-py / falkordblite version mismatch."
|
|
198
|
+
) from ve
|
|
154
199
|
|
|
155
200
|
# Test the connection
|
|
156
201
|
try:
|
|
@@ -167,6 +212,10 @@ class FalkorDBManager:
|
|
|
167
212
|
" pip install falkordblite"
|
|
168
213
|
)
|
|
169
214
|
raise ValueError("FalkorDB client missing.") from e
|
|
215
|
+
except FalkorDBUnavailableError:
|
|
216
|
+
# Propagate as-is so get_database_manager() can trigger the
|
|
217
|
+
# documented KùzuDB fallback.
|
|
218
|
+
raise
|
|
170
219
|
except Exception as e:
|
|
171
220
|
error_logger(f"Failed to initialize FalkorDB: {e}")
|
|
172
221
|
raise
|
|
@@ -195,6 +244,13 @@ class FalkorDBManager:
|
|
|
195
244
|
test_graph.query("RETURN 1")
|
|
196
245
|
info_logger("Connected to existing (functional) FalkorDB Lite process.")
|
|
197
246
|
return
|
|
247
|
+
except ValueError as ve:
|
|
248
|
+
# redis-py >= 6 maintenance-notifications handshake (issue #1035) — this
|
|
249
|
+
# backend cannot work in the current environment regardless of socket state.
|
|
250
|
+
raise FalkorDBUnavailableError(
|
|
251
|
+
f"FalkorDB Lite client refused the Unix-socket connection: {ve}. "
|
|
252
|
+
"This typically indicates a redis-py / falkordblite version mismatch."
|
|
253
|
+
) from ve
|
|
198
254
|
except Exception as e:
|
|
199
255
|
# Stale socket, unresponsive, or "brainless" (unknown command GRAPH.QUERY)
|
|
200
256
|
info_logger(f"Existing FalkorDB process at {self.socket_path} is stale or non-functional: {e}")
|
|
@@ -247,6 +303,13 @@ class FalkorDBManager:
|
|
|
247
303
|
test_graph = d.select_graph('__cgc_health_check')
|
|
248
304
|
test_graph.query("RETURN 1")
|
|
249
305
|
return
|
|
306
|
+
except ValueError as ve:
|
|
307
|
+
# redis-py version mismatch — no point retrying, the handshake
|
|
308
|
+
# will keep failing the same way until the user fixes deps.
|
|
309
|
+
raise FalkorDBUnavailableError(
|
|
310
|
+
f"FalkorDB Lite client refused the Unix-socket connection: {ve}. "
|
|
311
|
+
"This typically indicates a redis-py / falkordblite version mismatch."
|
|
312
|
+
) from ve
|
|
250
313
|
except Exception as e:
|
|
251
314
|
last_error = e
|
|
252
315
|
|
|
@@ -265,7 +328,11 @@ class FalkorDBManager:
|
|
|
265
328
|
|
|
266
329
|
time.sleep(0.5)
|
|
267
330
|
|
|
268
|
-
|
|
331
|
+
# Timeout is also a "backend not usable here" signal — raise the typed
|
|
332
|
+
# exception so the documented KùzuDB fallback fires instead of crashing.
|
|
333
|
+
raise FalkorDBUnavailableError(
|
|
334
|
+
f"Timed out waiting for FalkorDB Lite to start. Last error: {last_error}"
|
|
335
|
+
)
|
|
269
336
|
|
|
270
337
|
def close_driver(self):
|
|
271
338
|
"""Closes the connection."""
|
|
@@ -743,13 +743,16 @@ class KuzuSessionWrapper:
|
|
|
743
743
|
)
|
|
744
744
|
if row_ref:
|
|
745
745
|
val = item.get(row_ref.group(1))
|
|
746
|
-
|
|
746
|
+
# Consider -1 as missing for line numbers to force fallback,
|
|
747
|
+
# ensuring uniqueness when the primary key is incomplete
|
|
748
|
+
if val is not None and not (part in ("line_number", "function_line_number", "end_line") and val == -1):
|
|
747
749
|
uid_components.append(str(val))
|
|
748
750
|
else:
|
|
749
751
|
# Missing values are common in parser output for some
|
|
750
752
|
# languages. Use a deterministic placeholder component
|
|
751
753
|
# to keep UID generation stable and unique enough.
|
|
752
|
-
|
|
754
|
+
row_hash = hashlib.md5(str(sorted([(k, v) for k, v in item.items() if k != 'uid'])).encode()).hexdigest()[:8]
|
|
755
|
+
uid_components.append(f"__fallback_{row_hash}")
|
|
753
756
|
elif param_ref:
|
|
754
757
|
val = parameters.get(param_ref.group(1))
|
|
755
758
|
if val is not None:
|
codegraphcontext/server.py
CHANGED
|
@@ -351,8 +351,18 @@ class MCPServer:
|
|
|
351
351
|
|
|
352
352
|
def generate_report_tool(self, **args) -> Dict[str, Any]:
|
|
353
353
|
from .tools.report_generator import generate_report
|
|
354
|
+
|
|
354
355
|
output_path_raw = args.get("output_path")
|
|
355
356
|
output_path = Path(output_path_raw) if output_path_raw else self.cwd / "CGC_REPORT.md"
|
|
357
|
+
|
|
358
|
+
base_dir = self.cwd.resolve()
|
|
359
|
+
output_path = output_path.resolve()
|
|
360
|
+
|
|
361
|
+
try:
|
|
362
|
+
output_path.relative_to(base_dir)
|
|
363
|
+
except ValueError:
|
|
364
|
+
return {"error": "Invalid output_path: path traversal is not allowed"}
|
|
365
|
+
|
|
356
366
|
try:
|
|
357
367
|
report = generate_report(
|
|
358
368
|
self.db_manager,
|
|
@@ -361,7 +371,7 @@ class MCPServer:
|
|
|
361
371
|
god_node_limit=int(args.get("god_node_limit", 15)),
|
|
362
372
|
complexity_limit=int(args.get("complexity_limit", 15)),
|
|
363
373
|
cross_module_limit=int(args.get("cross_module_limit", 20)),
|
|
364
|
-
|
|
374
|
+
)
|
|
365
375
|
return {"status": "ok", "output_path": str(output_path), "report": report}
|
|
366
376
|
except Exception as exc:
|
|
367
377
|
return {"error": str(exc)}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
1
2
|
# src/codegraphcontext/tools/advanced_language_query_tool.py
|
|
2
3
|
import re
|
|
3
4
|
import logging
|
|
4
|
-
|
|
5
|
-
#
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
#importing all the language toolkits
|
|
6
7
|
from ..tools.query_tool_languages.c_toolkit import CToolkit
|
|
7
8
|
from ..tools.query_tool_languages.cpp_toolkit import CppToolkit
|
|
8
9
|
from ..tools.query_tool_languages.go_toolkit import GoToolkit
|
|
@@ -17,7 +18,8 @@ from ..tools.query_tool_languages.dart_toolkit import DartToolkit
|
|
|
17
18
|
from ..tools.query_tool_languages.elisp_toolkit import ElispToolkit
|
|
18
19
|
from ..tools.query_tool_languages.perl_toolkit import PerlToolkit
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
if TYPE_CHECKING:
|
|
22
|
+
from ..core.database import DatabaseManager
|
|
21
23
|
from ..utils.debug_log import debug_log
|
|
22
24
|
|
|
23
25
|
logger = logging.getLogger(__name__)
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
# src/codegraphcontext/tools/code_finder.py
|
|
2
|
+
from __future__ import annotations
|
|
2
3
|
import logging
|
|
3
4
|
from collections import Counter
|
|
4
5
|
|
|
5
|
-
from typing import Any, Dict, List, Literal, Optional
|
|
6
|
+
from typing import Any, Dict, List, Literal, Optional, TYPE_CHECKING
|
|
6
7
|
from pathlib import Path
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from ..core.database import DatabaseManager
|
|
9
11
|
from ..utils.path_ignore import cypher_path_not_under_ignore_dirs
|
|
10
12
|
|
|
11
13
|
logger = logging.getLogger(__name__)
|
|
@@ -2,14 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
# src/codegraphcontext/tools/graph_builder.py
|
|
4
4
|
"""Facade for graph indexing; implementation lives in indexing/."""
|
|
5
|
+
from __future__ import annotations
|
|
5
6
|
|
|
6
7
|
import asyncio
|
|
7
8
|
from datetime import datetime
|
|
8
9
|
from pathlib import Path
|
|
9
|
-
from typing import Any, Dict, Optional, Tuple
|
|
10
|
+
from typing import Any, Dict, Optional, Tuple, TYPE_CHECKING
|
|
10
11
|
|
|
11
12
|
from ..cli.config_manager import get_config_value
|
|
12
|
-
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from ..core.database import DatabaseManager
|
|
13
15
|
from ..core.jobs import JobManager, JobStatus
|
|
14
16
|
from ..utils.debug_log import debug_log, error_logger, info_logger, warning_logger
|
|
15
17
|
from .indexing.constants import DEFAULT_IGNORE_PATTERNS
|
|
@@ -43,6 +45,8 @@ class GraphBuilder:
|
|
|
43
45
|
".cjs": "javascript",
|
|
44
46
|
".go": "go",
|
|
45
47
|
".ts": "typescript",
|
|
48
|
+
".mts": "typescript",
|
|
49
|
+
".cts": "typescript",
|
|
46
50
|
".d.ts": "typescript",
|
|
47
51
|
".tsx": "tsx",
|
|
48
52
|
".cpp": "cpp",
|
|
@@ -1311,14 +1311,25 @@ class GraphWriter:
|
|
|
1311
1311
|
info_logger(f"[SPRING_DATA] Written {written} READS/WRITES derived-query edges")
|
|
1312
1312
|
|
|
1313
1313
|
def delete_repository_from_graph(self, repo_path: str) -> bool:
|
|
1314
|
-
|
|
1314
|
+
# Normalize path separators for cross-platform compatibility (Windows uses \)
|
|
1315
|
+
repo_path_str = repo_path.replace("\\", "/")
|
|
1315
1316
|
path_prefix = repo_path_str + "/"
|
|
1316
1317
|
with self.driver.session() as session:
|
|
1318
|
+
# Try normalized path first
|
|
1317
1319
|
result = session.run(
|
|
1318
1320
|
"MATCH (r:Repository {path: $path}) RETURN count(r) as cnt", path=repo_path_str
|
|
1319
1321
|
).single()
|
|
1320
1322
|
if not result or result["cnt"] == 0:
|
|
1321
|
-
|
|
1323
|
+
# Fallback: try original path (Windows backslash)
|
|
1324
|
+
result = session.run(
|
|
1325
|
+
"MATCH (r:Repository {path: $path}) RETURN count(r) as cnt", path=repo_path
|
|
1326
|
+
).single()
|
|
1327
|
+
# If found via original path, use original path for all subsequent operations
|
|
1328
|
+
if result and result["cnt"] > 0:
|
|
1329
|
+
repo_path_str = repo_path
|
|
1330
|
+
path_prefix = repo_path + "\\"
|
|
1331
|
+
if not result or result["cnt"] == 0:
|
|
1332
|
+
warning_logger(f"Attempted to delete non-existent repository: {repo_path}")
|
|
1322
1333
|
return False
|
|
1323
1334
|
|
|
1324
1335
|
for rel_type in ("CALLS", "INHERITS", "IMPORTS"):
|
|
@@ -1349,8 +1360,23 @@ class GraphWriter:
|
|
|
1349
1360
|
break
|
|
1350
1361
|
info_logger(f"[DELETE] Removed {deleted} CONTAINS rels for {repo_path_str}")
|
|
1351
1362
|
|
|
1352
|
-
|
|
1363
|
+
# Discover the labels currently in use rather than hardcoding the
|
|
1364
|
+
# list. Every time the indexer learned a new node type (Variable,
|
|
1365
|
+
# Parameter, Directory, ExternalClass, DbTable, ...) the hardcoded
|
|
1366
|
+
# tuple here had to be kept in lockstep, and every miss leaked
|
|
1367
|
+
# orphan nodes on `delete_repository`. `CALL db.labels()` returns
|
|
1368
|
+
# exactly the set of labels that have at least one node in the
|
|
1369
|
+
# current database -- per-label DETACH DELETE with the same path
|
|
1370
|
+
# prefix is then label-agnostic and self-maintaining.
|
|
1371
|
+
#
|
|
1372
|
+
# Labels with no node matching the path prefix are cheap: the
|
|
1373
|
+
# label-scoped scan returns 0 rows, the while-True loop exits
|
|
1374
|
+
# immediately, and we move on.
|
|
1375
|
+
with self.driver.session() as session:
|
|
1376
|
+
label_records = session.run("CALL db.labels() YIELD label RETURN label")
|
|
1377
|
+
all_labels = sorted({record["label"] for record in label_records})
|
|
1353
1378
|
|
|
1379
|
+
for label in all_labels:
|
|
1354
1380
|
while True:
|
|
1355
1381
|
with self.driver.session() as session:
|
|
1356
1382
|
result = session.run(
|
|
@@ -54,6 +54,8 @@ def _register_prescans() -> Dict[str, _PreScanFn]:
|
|
|
54
54
|
".cjs": make_js(".cjs"),
|
|
55
55
|
".go": lambda files, gp: go_lang_module.pre_scan_go(files, gp(".go")),
|
|
56
56
|
".ts": lambda files, gp: ts_lang_module.pre_scan_typescript(files, gp(".ts")),
|
|
57
|
+
".mts": lambda files, gp: ts_lang_module.pre_scan_typescript(files, gp(".mts")),
|
|
58
|
+
".cts": lambda files, gp: ts_lang_module.pre_scan_typescript(files, gp(".cts")),
|
|
57
59
|
".d.ts": lambda files, gp: ts_lang_module.pre_scan_typescript(files, gp(".d.ts")),
|
|
58
60
|
".tsx": lambda files, gp: tsx_lang_module.pre_scan_typescript(files, gp(".tsx")),
|
|
59
61
|
".cpp": lambda files, gp: cpp_lang_module.pre_scan_cpp(files, gp(".cpp")),
|
|
@@ -77,7 +77,7 @@ async def run_scip_index_async(
|
|
|
77
77
|
index_root = path.resolve() if path.is_dir() else path.parent.resolve()
|
|
78
78
|
for abs_path_str, file_data in files_data.items():
|
|
79
79
|
file_path = Path(abs_path_str)
|
|
80
|
-
if
|
|
80
|
+
if file_path_has_ignore_dir_segment(file_path, index_root):
|
|
81
81
|
continue
|
|
82
82
|
file_data["repo_path"] = str(index_root)
|
|
83
83
|
if job_id:
|
|
@@ -28,7 +28,7 @@ Supported SCIP indexers and their install commands:
|
|
|
28
28
|
rust → cargo install scip-rust (or rustup component add rust-analyzer)
|
|
29
29
|
java → https://github.com/sourcegraph/scip-java
|
|
30
30
|
c / c++ → scip-clang (JSON compilation database: compile_commands.json)
|
|
31
|
-
csharp → scip-dotnet (dotnet tool install -
|
|
31
|
+
csharp → scip-dotnet (dotnet tool install --global scip-dotnet)
|
|
32
32
|
|
|
33
33
|
JavaScript indexing notes:
|
|
34
34
|
- Pure JS projects (no tsconfig.json): scip-typescript index --infer-tsconfig
|
|
@@ -68,9 +68,10 @@ EXTENSION_TO_SCIP: Dict[str, Tuple[str, str, str, str]] = {
|
|
|
68
68
|
".dart": ("dart", "scip_dart", "dart pub global activate scip_dart", "dart:stable"),
|
|
69
69
|
".cpp": ("cpp", "scip-clang", "brew install llvm", "sourcegraph/scip-clang:sha-1704d3d"),
|
|
70
70
|
".hpp": ("cpp", "scip-clang", "brew install llvm", "sourcegraph/scip-clang:sha-1704d3d"),
|
|
71
|
+
".hh": ("cpp", "scip-clang", "brew install llvm", "sourcegraph/scip-clang:sha-1704d3d"),
|
|
71
72
|
".c": ("c", "scip-clang", "brew install llvm", "sourcegraph/scip-clang:sha-1704d3d"),
|
|
72
73
|
".h": ("cpp", "scip-clang", "brew install llvm", "sourcegraph/scip-clang:sha-1704d3d"),
|
|
73
|
-
".cs": ("csharp", "scip-dotnet", "dotnet tool install -
|
|
74
|
+
".cs": ("csharp", "scip-dotnet", "dotnet tool install --global scip-dotnet", "sourcegraph/scip-dotnet"),
|
|
74
75
|
".php": ("php", "scip-php", "composer global require davidrjenni/scip-php", "davidrjenni/scip-php"),
|
|
75
76
|
".rb": ("ruby", "scip-ruby", "gem install scip-ruby", ""),
|
|
76
77
|
".swift": ("swift", "scip-swift", "brew install scip-swift", ""),
|
codegraphcontext/tools/system.py
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
# src/codegraphcontext/tools/system.py
|
|
2
|
+
from __future__ import annotations
|
|
2
3
|
import logging
|
|
3
4
|
from dataclasses import asdict
|
|
4
|
-
from typing import Any, Dict
|
|
5
|
+
from typing import Any, Dict, TYPE_CHECKING
|
|
5
6
|
from datetime import datetime, timedelta
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
try:
|
|
9
|
+
from neo4j.exceptions import CypherSyntaxError
|
|
10
|
+
except ImportError:
|
|
11
|
+
CypherSyntaxError = type('CypherSyntaxError', (Exception,), {})
|
|
8
12
|
|
|
9
|
-
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from ..core.database import DatabaseManager
|
|
10
15
|
from ..core.jobs import JobManager, JobStatus
|
|
11
16
|
from ..utils.debug_log import debug_log
|
|
12
17
|
|
codegraphcontext/viz/server.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
1
2
|
# src/codegraphcontext/viz/server.py
|
|
2
3
|
from fastapi import FastAPI, HTTPException, Query, Request
|
|
3
4
|
from fastapi.staticfiles import StaticFiles
|
|
@@ -9,9 +10,10 @@ import uvicorn
|
|
|
9
10
|
import json
|
|
10
11
|
import os
|
|
11
12
|
import sys
|
|
12
|
-
from typing import Optional, List, Dict, Any
|
|
13
|
+
from typing import Optional, List, Dict, Any, TYPE_CHECKING
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
from ..core.database import DatabaseManager
|
|
15
17
|
from ..utils.debug_log import debug_log
|
|
16
18
|
|
|
17
19
|
app = FastAPI()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codegraphcontext
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.14
|
|
4
4
|
Summary: An MCP server that indexes local code into a graph database to provide context to AI assistants.
|
|
5
5
|
Author-email: Shashank Shekhar Singh <shashankshekharsingh1205@gmail.com>
|
|
6
6
|
License: MIT License
|
|
@@ -50,18 +50,33 @@ Requires-Dist: pyyaml
|
|
|
50
50
|
Requires-Dist: nbformat
|
|
51
51
|
Requires-Dist: nbconvert>=7.16.6
|
|
52
52
|
Requires-Dist: pathspec>=0.12.1
|
|
53
|
-
Requires-Dist:
|
|
53
|
+
Requires-Dist: redis<6,>=5
|
|
54
|
+
Requires-Dist: falkordb<1.6,>=1.0
|
|
55
|
+
Requires-Dist: falkordblite<0.10,>=0.7; sys_platform != "win32" and python_version >= "3.12"
|
|
54
56
|
Requires-Dist: requests>=2.28.0
|
|
55
57
|
Requires-Dist: protobuf<3.21,>=3.20
|
|
56
|
-
Requires-Dist: falkordblite>=0.1.0; sys_platform != "win32" and python_version >= "3.12"
|
|
57
58
|
Requires-Dist: kuzu; sys_platform == "win32" or (sys_platform != "win32" and python_version >= "3.10")
|
|
58
59
|
Requires-Dist: ladybug; sys_platform == "win32" or (sys_platform != "win32" and python_version >= "3.10")
|
|
60
|
+
Requires-Dist: mcp>=1.0.0
|
|
59
61
|
Requires-Dist: fastapi>=0.100.0
|
|
60
62
|
Requires-Dist: uvicorn>=0.22.0
|
|
61
63
|
Provides-Extra: parsing
|
|
62
64
|
Requires-Dist: tree-sitter<0.26.0,>=0.21.0; python_version != "3.13" and extra == "parsing"
|
|
63
65
|
Requires-Dist: tree-sitter-language-pack<1.0.0,>=0.6.0; python_version != "3.13" and extra == "parsing"
|
|
64
66
|
Requires-Dist: tree-sitter-c-sharp>=0.21.0; python_version != "3.13" and extra == "parsing"
|
|
67
|
+
Provides-Extra: falkordb-embedded
|
|
68
|
+
Requires-Dist: falkordblite<0.10,>=0.7; (sys_platform != "win32" and python_version >= "3.12") and extra == "falkordb-embedded"
|
|
69
|
+
Requires-Dist: falkordb<1.6,>=1.0; extra == "falkordb-embedded"
|
|
70
|
+
Requires-Dist: redis<6,>=5; extra == "falkordb-embedded"
|
|
71
|
+
Provides-Extra: falkordb-remote
|
|
72
|
+
Requires-Dist: falkordb<1.6,>=1.0; extra == "falkordb-remote"
|
|
73
|
+
Requires-Dist: redis<6,>=5; extra == "falkordb-remote"
|
|
74
|
+
Provides-Extra: kuzu
|
|
75
|
+
Requires-Dist: kuzu; (sys_platform == "win32" or (sys_platform != "win32" and python_version >= "3.10")) and extra == "kuzu"
|
|
76
|
+
Provides-Extra: ladybug
|
|
77
|
+
Requires-Dist: ladybug; (sys_platform == "win32" or (sys_platform != "win32" and python_version >= "3.10")) and extra == "ladybug"
|
|
78
|
+
Provides-Extra: neo4j
|
|
79
|
+
Requires-Dist: neo4j>=5.15.0; extra == "neo4j"
|
|
65
80
|
Provides-Extra: dev
|
|
66
81
|
Requires-Dist: pytest>=7.4.0; extra == "dev"
|
|
67
82
|
Requires-Dist: black>=23.11.0; extra == "dev"
|
|
@@ -74,11 +89,11 @@ Dynamic: license-file
|
|
|
74
89
|
|
|
75
90
|
🌐 **Languages:**
|
|
76
91
|
- 🇬🇧 [English](README.md)
|
|
77
|
-
- 🇨🇳 [中文](README.zh-CN.md)
|
|
78
|
-
- 🇰🇷 [한국어](README.kor.md)
|
|
79
|
-
- 🇺🇦 [Українська](README.uk.md)
|
|
80
|
-
- 🇷🇺 [Русский](README.ru-RU.md)
|
|
81
|
-
- 🇯🇵 [日本語](README.ja.md)
|
|
92
|
+
- 🇨🇳 [中文](docs/translations/README.zh-CN.md)
|
|
93
|
+
- 🇰🇷 [한국어](docs/translations/README.kor.md)
|
|
94
|
+
- 🇺🇦 [Українська](docs/translations/README.uk.md)
|
|
95
|
+
- 🇷🇺 [Русский](docs/translations/README.ru-RU.md)
|
|
96
|
+
- 🇯🇵 [日本語](docs/translations/README.ja.md)
|
|
82
97
|
- 🇪🇸 Español (Soon)
|
|
83
98
|
|
|
84
99
|
🌍 **Help translate CodeGraphContext to your language by raising an issue & PR on https://github.com/Shashankss1205/CodeGraphContext/issues!**
|
|
@@ -168,7 +183,7 @@ A powerful **MCP server** and **CLI toolkit** that indexes local code into a gra
|
|
|
168
183
|
---
|
|
169
184
|
|
|
170
185
|
## Project Details
|
|
171
|
-
- **Version:** 0.4.
|
|
186
|
+
- **Version:** 0.4.14
|
|
172
187
|
- **Authors:** Shashank Shekhar Singh <shashankshekharsingh1205@gmail.com>
|
|
173
188
|
- **License:** MIT License (See [LICENSE](LICENSE) for details)
|
|
174
189
|
- **Website:** [CodeGraphContext](http://codegraphcontext.vercel.app/)
|
|
@@ -375,6 +390,7 @@ codegraphcontext find pattern "Auth" --viz
|
|
|
375
390
|
* VS Code
|
|
376
391
|
* Cursor
|
|
377
392
|
* Windsurf
|
|
393
|
+
* Zed
|
|
378
394
|
* Claude
|
|
379
395
|
* Gemini CLI
|
|
380
396
|
* ChatGPT Codex
|
|
@@ -382,6 +398,8 @@ codegraphcontext find pattern "Auth" --viz
|
|
|
382
398
|
* RooCode
|
|
383
399
|
* Amazon Q Developer
|
|
384
400
|
* Kiro
|
|
401
|
+
* Goose
|
|
402
|
+
* OpenCode
|
|
385
403
|
|
|
386
404
|
Upon successful configuration, `codegraphcontext mcp setup` will generate and place the necessary configuration files:
|
|
387
405
|
* It creates an `mcp.json` file in your current directory for reference.
|
|
@@ -444,6 +462,10 @@ Add the following server configuration to your client's settings file (e.g., VS
|
|
|
444
462
|
}
|
|
445
463
|
```
|
|
446
464
|
|
|
465
|
+
#### OpenCode Configuration
|
|
466
|
+
|
|
467
|
+
For instructions on installing and configuring MCP servers with OpenCode, see the [OpenCode MCP Guide](https://opencode.ai/docs/ko/mcp-servers/#_top).
|
|
468
|
+
|
|
447
469
|
#### If installed via pipx
|
|
448
470
|
|
|
449
471
|
If you installed CodeGraphContext using `pipx`, use the following configuration instead:
|
|
@@ -537,7 +559,7 @@ Once the server is running, you can interact with it through your AI assistant u
|
|
|
537
559
|
## Contributing
|
|
538
560
|
|
|
539
561
|
Contributions are welcome! 🎉
|
|
540
|
-
Please see our [CONTRIBUTING.md](CONTRIBUTING.md) for detailed guidelines.
|
|
562
|
+
Please see our [CONTRIBUTING.md](.github/CONTRIBUTING.md) for detailed guidelines.
|
|
541
563
|
If you have ideas for new features, integrations, or improvements, open an [issue](https://github.com/CodeGraphContext/CodeGraphContext/issues) or submit a Pull Request.
|
|
542
564
|
|
|
543
565
|
Join discussions and help shape the future of CodeGraphContext.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
codegraphcontext/__init__.py,sha256=mFY5raGZpG90gG6E8NH0R85mDl3Ikak2HQHOiwCXl-I,77
|
|
2
2
|
codegraphcontext/__main__.py,sha256=21QjL_lfd6cy-clJYPBg6xKb_IuNDcvvWdaAJEvZ-HQ,99
|
|
3
3
|
codegraphcontext/prompts.py,sha256=Ld-2tI5mngpitccT0umOejyPG-xIaX3-6s-d2VTAzw8,6773
|
|
4
|
-
codegraphcontext/server.py,sha256=
|
|
4
|
+
codegraphcontext/server.py,sha256=NARDquhfX70pqOVaGkTANjuyULRaJ3TYB262OufBkv4,26765
|
|
5
5
|
codegraphcontext/tool_definitions.py,sha256=cDFdNSP4bhPUtJFZtWtSF_1IN7i-3rCmpSQ10nl-igM,16912
|
|
6
6
|
codegraphcontext/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
7
|
codegraphcontext/api/app.py,sha256=LAjs65t7ceqyDBOX9iCT69xpUoBpIIngddvFUMrRqAA,2830
|
|
@@ -10,34 +10,34 @@ codegraphcontext/api/router.py,sha256=8iEhjERfGI5Udn801wMGpZmcmAuwbt5cMCwnK-Evg9
|
|
|
10
10
|
codegraphcontext/api/schemas.py,sha256=pGLuKtdn55pf8mS8wv8MwehbT_3-4OZuSYjI5LJxzOc,1034
|
|
11
11
|
codegraphcontext/cli/__init__.py,sha256=2vUlnf7H09M9JbS2gS_LmMUBJWAWcGGHkkl4I2YrdSg,39
|
|
12
12
|
codegraphcontext/cli/cli_helpers.py,sha256=_fksM3sBj9e96gQcHOaDmpmJG6444lWRaO0AM-6Wzu8,38773
|
|
13
|
-
codegraphcontext/cli/config_manager.py,sha256=
|
|
14
|
-
codegraphcontext/cli/main.py,sha256=
|
|
15
|
-
codegraphcontext/cli/registry_commands.py,sha256=
|
|
13
|
+
codegraphcontext/cli/config_manager.py,sha256=QX6IP5JqYFaItaLGAJjh2J2pQgcEOC58HVNK9iIyexU,44863
|
|
14
|
+
codegraphcontext/cli/main.py,sha256=yOhEZDh4jmeo6avbjS5DqLHMEEkrZJlVCWV7R_pAw3g,116828
|
|
15
|
+
codegraphcontext/cli/registry_commands.py,sha256=8irzcdPV53PtERuytFfzm8KO5nEUPrgy9ZzyKL5oZ_0,17029
|
|
16
16
|
codegraphcontext/cli/setup_macos.py,sha256=Xjlv_9jk9qv8Gh7stpH1pvlalzC0Fg176y7jc5G1zh0,3575
|
|
17
|
-
codegraphcontext/cli/setup_wizard.py,sha256=
|
|
17
|
+
codegraphcontext/cli/setup_wizard.py,sha256=_aZxOe3q4qIEQeaghDVsNPxMRcxJsvibrfqf39rSshI,47746
|
|
18
18
|
codegraphcontext/cli/visualizer.py,sha256=md5HehQ9_8lBTejQqq2lxXtMRzDxCjjF9L9h2qu6KR0,1902
|
|
19
|
-
codegraphcontext/core/__init__.py,sha256
|
|
19
|
+
codegraphcontext/core/__init__.py,sha256=mXMX6gBJ6DMad6lTvQvrpTxaSt1QfPMn3t_x1pZF4cg,10492
|
|
20
20
|
codegraphcontext/core/bundle_registry.py,sha256=k3QZAGaLo2DV5p1xhqzgl_bf7faHCBfWT6ETYylSbKU,5711
|
|
21
|
-
codegraphcontext/core/cgc_bundle.py,sha256=
|
|
21
|
+
codegraphcontext/core/cgc_bundle.py,sha256=oLSMmLMJVd0JigFjJFXbzDRO4fKjuUD0Fl1_7OEBHHE,41052
|
|
22
22
|
codegraphcontext/core/cgcignore.py,sha256=6q7y11V_bNEhMC1167HiUyr7yxDCNg2OMr0DQAqCzlE,4213
|
|
23
23
|
codegraphcontext/core/database.py,sha256=RWMdKKinoWewyTyTuIXX-fk7EHkba91LO18gZ12wwEg,14648
|
|
24
|
-
codegraphcontext/core/database_falkordb.py,sha256=
|
|
24
|
+
codegraphcontext/core/database_falkordb.py,sha256=iN7uSvXFVp1clSjF2q92Omh4k6TlgAlS1-1QL9FF50o,25989
|
|
25
25
|
codegraphcontext/core/database_falkordb_remote.py,sha256=aMiuJTB_-2rBUpbAmX8ElZiZrYZbOXK-On3ncgMCyhY,7118
|
|
26
|
-
codegraphcontext/core/database_kuzu.py,sha256=
|
|
26
|
+
codegraphcontext/core/database_kuzu.py,sha256=CScoj_lml1AWhba4k0iD84KuJppTivoenh8ZdQooIZo,62673
|
|
27
27
|
codegraphcontext/core/database_ladybug.py,sha256=2YlmvJhxUt82mbm3__u2B1uiNhf5IoFHQUhUp8E-cag,62088
|
|
28
28
|
codegraphcontext/core/database_nornic.py,sha256=XJkHROH_ojss2c-Kyte81lDehLjKRUYYfKDSA7YHa-4,8294
|
|
29
29
|
codegraphcontext/core/falkor_worker.py,sha256=-UHm71HnqOQOh85ZLTPUuJJ08NQo77gw5lmOPN9rha8,5003
|
|
30
30
|
codegraphcontext/core/jobs.py,sha256=d6v_IERdEcDlIsz3CW3p0QMp3N-6dgQICs3FZRPgPgU,4809
|
|
31
31
|
codegraphcontext/core/watcher.py,sha256=EFjKYK3wUQG2pQter_A2xSe8yIrkZwfjZ9anITAjftA,18949
|
|
32
32
|
codegraphcontext/tools/__init__.py,sha256=iqQPEkDlGXO7rAaLNQrS_ZAbLSklBSK-OowpARq0mig,41
|
|
33
|
-
codegraphcontext/tools/advanced_language_query_tool.py,sha256=
|
|
34
|
-
codegraphcontext/tools/code_finder.py,sha256=
|
|
35
|
-
codegraphcontext/tools/graph_builder.py,sha256=
|
|
33
|
+
codegraphcontext/tools/advanced_language_query_tool.py,sha256=sZ1_IjqyeIHW-KR4MjXQnEly8-B1hpsFctMdUCROODE,3914
|
|
34
|
+
codegraphcontext/tools/code_finder.py,sha256=rSoyezvOedIeejN9INyb4kbniRctO25DR3tczvKAImo,70586
|
|
35
|
+
codegraphcontext/tools/graph_builder.py,sha256=jb0j9q0JvbzXk5uCqvdvUP-iYmECiARJ3KX9fOvgrMo,54654
|
|
36
36
|
codegraphcontext/tools/package_resolver.py,sha256=KtbdMReTezszjdsqYniL-Xb-QUsrAJWtf1NSiyIPkLI,18704
|
|
37
37
|
codegraphcontext/tools/report_generator.py,sha256=K4AROEMZU--fX217JT6y7P7LfiqRnG8olwrj0vO1kKo,12499
|
|
38
|
-
codegraphcontext/tools/scip_indexer.py,sha256=
|
|
38
|
+
codegraphcontext/tools/scip_indexer.py,sha256=tHR362n_tVOhOykTKPnPpCdgk9iryu2DuxAfSNonvXM,36926
|
|
39
39
|
codegraphcontext/tools/scip_pb2.py,sha256=jSMLR7ud4eaKrIkQN-XDWNaFCyUaueafUm9WgOhjqRA,98270
|
|
40
|
-
codegraphcontext/tools/system.py,sha256=
|
|
40
|
+
codegraphcontext/tools/system.py,sha256=kaX0XGs3DPnWxhscYVD5cxOqZWcK0V_Su-RytCkhieA,6592
|
|
41
41
|
codegraphcontext/tools/tree_sitter_parser.py,sha256=sNt7q_3nc21pHeYnE6VxUYokk173CXeh4yt2pOOBdWg,5251
|
|
42
42
|
codegraphcontext/tools/type_utils.py,sha256=ZCJ9b1BwvL7LKl8Duhx-5uwX3Gemp5EGqLMso7zRY3E,472
|
|
43
43
|
codegraphcontext/tools/datasources/__init__.py,sha256=EDY0_s7DJPRzJhfmYUz3Pxv0b6UIXP-l9KMp3xgg-WU,132
|
|
@@ -54,14 +54,14 @@ codegraphcontext/tools/indexing/constants.py,sha256=gFhARllsYYHIEg88380dbgn4p9oQ
|
|
|
54
54
|
codegraphcontext/tools/indexing/discovery.py,sha256=YAu6wmmXFPSv4zSmRXLVUQIEeWZrRzpG8ITbGOYQeDo,5130
|
|
55
55
|
codegraphcontext/tools/indexing/embeddings.py,sha256=XFWKS2CYgs7ne5OfxWx76Sp0WLt-WgzNPsi_7wCmaN0,10501
|
|
56
56
|
codegraphcontext/tools/indexing/pipeline.py,sha256=QjDp4ryA3RtFS6kqZBvyiVGkMXyyKBfsW8s29Adhft4,10496
|
|
57
|
-
codegraphcontext/tools/indexing/pre_scan.py,sha256=
|
|
57
|
+
codegraphcontext/tools/indexing/pre_scan.py,sha256=MJ3Mza2v3tpoN4V-473zC6D2Y0Ig8r-XgT3ogKFrPDc,5850
|
|
58
58
|
codegraphcontext/tools/indexing/sanitize.py,sha256=IaTP7Aztso3SsvjNZMEqJ1iktV4Tl75hXcYnCWBGpLs,1490
|
|
59
59
|
codegraphcontext/tools/indexing/schema.py,sha256=U2jUdtqcoBCdjQ9BCJWdfQs7Bc_lAGZN9sA2H3GDVvI,6734
|
|
60
60
|
codegraphcontext/tools/indexing/schema_contract.py,sha256=W8mU7HgvyVvNw3Mxrwc-tDGHf91CrcY3GwGpUTgxbnM,1670
|
|
61
|
-
codegraphcontext/tools/indexing/scip_pipeline.py,sha256=
|
|
61
|
+
codegraphcontext/tools/indexing/scip_pipeline.py,sha256=Uc3kSLNN4G1epLle5BvIQ-jtYJDAC4k1_j_cVFf_Dd4,8988
|
|
62
62
|
codegraphcontext/tools/indexing/vector_resolver.py,sha256=RK2sj3n9_UVPVbfe9Isyn1GpfJTNrmPb830m9PF5yp4,5119
|
|
63
63
|
codegraphcontext/tools/indexing/persistence/__init__.py,sha256=hFRlNgiYS7uN9X4e4xfP3c1BvcYSxpmq0k_uaDRn2Fg,121
|
|
64
|
-
codegraphcontext/tools/indexing/persistence/writer.py,sha256=
|
|
64
|
+
codegraphcontext/tools/indexing/persistence/writer.py,sha256=1KGK3UjEHygB4-AIfF2-O7dAt6G116YGvqUPo-GlROc,67887
|
|
65
65
|
codegraphcontext/tools/indexing/resolution/__init__.py,sha256=SWaJlN5kpWPjLoLUTLC4VEDaubpf0_tl5g7igGCbWJM,310
|
|
66
66
|
codegraphcontext/tools/indexing/resolution/calls.py,sha256=R7o5ryWGCYL4h_DfnLaqdwpzSWYB6gTc8dbBWm-tAcM,107280
|
|
67
67
|
codegraphcontext/tools/indexing/resolution/inheritance.py,sha256=BOYw_-NiO4oX5dS0CIX-ebg2ZhQhJ1NRC6Vk_tnAX-M,4118
|
|
@@ -115,7 +115,7 @@ codegraphcontext/utils/repo_path.py,sha256=BxS3y6RV_WaZhg_WxgJygS4SnQa-Ryth2fsic
|
|
|
115
115
|
codegraphcontext/utils/tool_limits.py,sha256=3d-QnlzxBNocz58VKNhdsta7ZpWThs1AX46_gYXl6pQ,2751
|
|
116
116
|
codegraphcontext/utils/tree_sitter_manager.py,sha256=DHXEImSfXNx5mLbNPo0mwc3IBxHvwbRmAmhrlFezw2s,13146
|
|
117
117
|
codegraphcontext/utils/visualize_graph.py,sha256=4m3i_FKQaxrQZ6GePmHwjQBCctg4Dy_UQqwvwS3XL1Q,48
|
|
118
|
-
codegraphcontext/viz/server.py,sha256=
|
|
118
|
+
codegraphcontext/viz/server.py,sha256=M0Bz8PXpi44NuOp8pHCujaxH6b4g6rUlzB7PVsX-IiQ,15204
|
|
119
119
|
codegraphcontext/viz/dist/cgcIcon.png,sha256=lik7hnqvkqLc5uo9w9Q_YJXtRx7cWPrXqSLttGtW1sg,58703
|
|
120
120
|
codegraphcontext/viz/dist/favicon.ico,sha256=AjhUxD_Eslt5XuSVHIAZ494Fk__rb5GLXR8qm0elfP4,1870
|
|
121
121
|
codegraphcontext/viz/dist/index.html,sha256=uEaFo3uHWD2KojFiyfWRJoS1_t6zrllOnf_siaB0I5U,1946
|
|
@@ -154,9 +154,9 @@ codegraphcontext/viz/dist/wasm/tree-sitter-typescript.wasm,sha256=hRVATc7tOOHthq
|
|
|
154
154
|
codegraphcontext/viz/dist/wasm/tree-sitter.wasm,sha256=CCeVuI_hXktkBD-DW01xYPv5XoAYVRIqzJUJI5te-RY,196763
|
|
155
155
|
codegraphcontext/viz/dist/wasm/web-tree-sitter.js,sha256=DIaCNqRylrT_PBVw8g4ImeSnhP9uXNe_ycOlUiVGPko,153666
|
|
156
156
|
codegraphcontext/viz/dist/wasm/web-tree-sitter.wasm,sha256=CCeVuI_hXktkBD-DW01xYPv5XoAYVRIqzJUJI5te-RY,196763
|
|
157
|
-
codegraphcontext-0.4.
|
|
158
|
-
codegraphcontext-0.4.
|
|
159
|
-
codegraphcontext-0.4.
|
|
160
|
-
codegraphcontext-0.4.
|
|
161
|
-
codegraphcontext-0.4.
|
|
162
|
-
codegraphcontext-0.4.
|
|
157
|
+
codegraphcontext-0.4.14.dist-info/licenses/LICENSE,sha256=rh8M-bJpQYJnw2vtRVgt0t7piMZXh5QzaKeNEI0vqqA,1061
|
|
158
|
+
codegraphcontext-0.4.14.dist-info/METADATA,sha256=MvD3fxmCeYy3c0isUirHNIhEGElnRr6cW4K937yv7aw,23904
|
|
159
|
+
codegraphcontext-0.4.14.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
160
|
+
codegraphcontext-0.4.14.dist-info/entry_points.txt,sha256=LCxWCWMshdvYGoHBPuQZ8C-e4CiNSHCLXofrNSGHkoE,103
|
|
161
|
+
codegraphcontext-0.4.14.dist-info/top_level.txt,sha256=CBgc6LAPZIO5FS0nSYYkylDifHsZTIqw3Gf5UwDxeGI,17
|
|
162
|
+
codegraphcontext-0.4.14.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|