codegraphcontext 0.3.5__tar.gz → 0.3.8__tar.gz

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 (87) hide show
  1. {codegraphcontext-0.3.5/src/codegraphcontext.egg-info → codegraphcontext-0.3.8}/PKG-INFO +6 -5
  2. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/README.md +3 -3
  3. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/pyproject.toml +3 -2
  4. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/cli/cli_helpers.py +8 -6
  5. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/cli/setup_wizard.py +6 -0
  6. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/core/database_kuzu.py +20 -10
  7. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/server.py +36 -1
  8. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/code_finder.py +93 -31
  9. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/graph_builder.py +88 -19
  10. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/languages/cpp.py +137 -72
  11. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/languages/go.py +42 -5
  12. codegraphcontext-0.3.8/src/codegraphcontext/utils/path_ignore.py +55 -0
  13. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/utils/tree_sitter_manager.py +8 -9
  14. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8/src/codegraphcontext.egg-info}/PKG-INFO +6 -5
  15. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext.egg-info/SOURCES.txt +1 -0
  16. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext.egg-info/requires.txt +2 -1
  17. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/LICENSE +0 -0
  18. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/MANIFEST.in +0 -0
  19. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/setup.cfg +0 -0
  20. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/__init__.py +0 -0
  21. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/__main__.py +0 -0
  22. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/cli/__init__.py +0 -0
  23. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/cli/config_manager.py +0 -0
  24. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/cli/main.py +0 -0
  25. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/cli/registry_commands.py +0 -0
  26. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/cli/setup_macos.py +0 -0
  27. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/cli/visualizer.py +0 -0
  28. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/core/__init__.py +0 -0
  29. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/core/bundle_registry.py +0 -0
  30. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/core/cgc_bundle.py +0 -0
  31. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/core/database.py +0 -0
  32. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/core/database_falkordb.py +0 -0
  33. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/core/database_falkordb_remote.py +0 -0
  34. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/core/falkor_worker.py +0 -0
  35. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/core/jobs.py +0 -0
  36. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/core/watcher.py +0 -0
  37. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/prompts.py +0 -0
  38. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tool_definitions.py +0 -0
  39. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/__init__.py +0 -0
  40. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/advanced_language_query_tool.py +0 -0
  41. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/handlers/analysis_handlers.py +0 -0
  42. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/handlers/indexing_handlers.py +0 -0
  43. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/handlers/management_handlers.py +0 -0
  44. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/handlers/query_handlers.py +0 -0
  45. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/handlers/watcher_handlers.py +0 -0
  46. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/languages/c.py +0 -0
  47. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/languages/csharp.py +0 -0
  48. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/languages/dart.py +0 -0
  49. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/languages/elixir.py +0 -0
  50. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/languages/haskell.py +0 -0
  51. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/languages/java.py +0 -0
  52. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/languages/javascript.py +0 -0
  53. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/languages/kotlin.py +0 -0
  54. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/languages/perl.py +0 -0
  55. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/languages/php.py +0 -0
  56. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/languages/python.py +0 -0
  57. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/languages/ruby.py +0 -0
  58. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/languages/rust.py +0 -0
  59. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/languages/scala.py +0 -0
  60. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/languages/swift.py +0 -0
  61. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/languages/typescript.py +0 -0
  62. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/languages/typescriptjsx.py +0 -0
  63. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/package_resolver.py +0 -0
  64. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/query_tool_languages/c_toolkit.py +0 -0
  65. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/query_tool_languages/cpp_toolkit.py +0 -0
  66. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/query_tool_languages/csharp_toolkit.py +0 -0
  67. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/query_tool_languages/dart_toolkit.py +0 -0
  68. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/query_tool_languages/go_toolkit.py +0 -0
  69. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/query_tool_languages/haskell_toolkit.py +0 -0
  70. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/query_tool_languages/java_toolkit.py +0 -0
  71. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/query_tool_languages/javascript_toolkit.py +0 -0
  72. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/query_tool_languages/perl_toolkit.py +0 -0
  73. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/query_tool_languages/python_toolkit.py +0 -0
  74. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/query_tool_languages/ruby_toolkit.py +0 -0
  75. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/query_tool_languages/rust_toolkit.py +0 -0
  76. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/query_tool_languages/scala_toolkit.py +0 -0
  77. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/query_tool_languages/swift_toolkit.py +0 -0
  78. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/query_tool_languages/typescript_toolkit.py +0 -0
  79. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/scip_indexer.py +0 -0
  80. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/scip_pb2.py +0 -0
  81. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/tools/system.py +0 -0
  82. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/utils/debug_log.py +0 -0
  83. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/utils/visualize_graph.py +0 -0
  84. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext/viz/server.py +0 -0
  85. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext.egg-info/dependency_links.txt +0 -0
  86. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext.egg-info/entry_points.txt +0 -0
  87. {codegraphcontext-0.3.5 → codegraphcontext-0.3.8}/src/codegraphcontext.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codegraphcontext
3
- Version: 0.3.5
3
+ Version: 0.3.8
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
@@ -41,7 +41,7 @@ Requires-Dist: watchdog>=3.0.0
41
41
  Requires-Dist: stdlibs>=2023.11.18
42
42
  Requires-Dist: typer[all]>=0.9.0
43
43
  Requires-Dist: rich>=13.7.0
44
- Requires-Dist: inquirerpy>=0.3.5
44
+ Requires-Dist: inquirerpy>=0.3.4
45
45
  Requires-Dist: python-dotenv>=1.0.0
46
46
  Requires-Dist: tree-sitter>=0.21.0
47
47
  Requires-Dist: tree-sitter-language-pack>=0.6.0
@@ -51,6 +51,7 @@ Requires-Dist: nbformat
51
51
  Requires-Dist: nbconvert>=7.16.6
52
52
  Requires-Dist: pathspec>=0.12.1
53
53
  Requires-Dist: falkordb>=0.1.0
54
+ Requires-Dist: requests>=2.28.0
54
55
  Requires-Dist: falkordblite>=0.1.0; sys_platform != "win32" and python_version >= "3.12"
55
56
  Requires-Dist: fastapi>=0.100.0
56
57
  Requires-Dist: uvicorn>=0.22.0
@@ -162,7 +163,7 @@ A powerful **MCP server** and **CLI toolkit** that indexes local code into a gra
162
163
  ---
163
164
 
164
165
  ## Project Details
165
- - **Version:** 0.3.5
166
+ - **Version:** 0.3.8
166
167
  - **Authors:** Shashank Shekhar Singh <shashankshekharsingh1205@gmail.com>
167
168
  - **License:** MIT License (See [LICENSE](LICENSE) for details)
168
169
  - **Website:** [CodeGraphContext](http://codegraphcontext.vercel.app/)
@@ -249,7 +250,7 @@ _If you’re using CodeGraphContext in your project, feel free to open a PR and
249
250
  - `stdlibs>=2023.11.18`
250
251
  - `typer[all]>=0.9.0`
251
252
  - `rich>=13.7.0`
252
- - `inquirerpy>=0.3.5`
253
+ - `inquirerpy>=0.3.7`
253
254
  - `python-dotenv>=1.0.0`
254
255
  - `tree-sitter>=0.21.0`
255
256
  - `tree-sitter-language-pack>=0.6.0`
@@ -271,7 +272,7 @@ pip install codegraphcontext
271
272
 
272
273
  ### If 'cgc' command isn't found, run our one-line fix:
273
274
  ```
274
- curl -sSL [https://raw.githubusercontent.com/CodeGraphContext/CodeGraphContext/main/scripts/post_install_fix.sh](https://raw.githubusercontent.com/CodeGraphContext/CodeGraphContext/main/scripts/post_install_fix.sh) | bash
275
+ curl -sSL https://raw.githubusercontent.com/CodeGraphContext/CodeGraphContext/main/scripts/post_install_fix.sh | bash
275
276
  ```
276
277
 
277
278
  ---
@@ -96,7 +96,7 @@ A powerful **MCP server** and **CLI toolkit** that indexes local code into a gra
96
96
  ---
97
97
 
98
98
  ## Project Details
99
- - **Version:** 0.3.5
99
+ - **Version:** 0.3.8
100
100
  - **Authors:** Shashank Shekhar Singh <shashankshekharsingh1205@gmail.com>
101
101
  - **License:** MIT License (See [LICENSE](LICENSE) for details)
102
102
  - **Website:** [CodeGraphContext](http://codegraphcontext.vercel.app/)
@@ -183,7 +183,7 @@ _If you’re using CodeGraphContext in your project, feel free to open a PR and
183
183
  - `stdlibs>=2023.11.18`
184
184
  - `typer[all]>=0.9.0`
185
185
  - `rich>=13.7.0`
186
- - `inquirerpy>=0.3.5`
186
+ - `inquirerpy>=0.3.7`
187
187
  - `python-dotenv>=1.0.0`
188
188
  - `tree-sitter>=0.21.0`
189
189
  - `tree-sitter-language-pack>=0.6.0`
@@ -205,7 +205,7 @@ pip install codegraphcontext
205
205
 
206
206
  ### If 'cgc' command isn't found, run our one-line fix:
207
207
  ```
208
- curl -sSL [https://raw.githubusercontent.com/CodeGraphContext/CodeGraphContext/main/scripts/post_install_fix.sh](https://raw.githubusercontent.com/CodeGraphContext/CodeGraphContext/main/scripts/post_install_fix.sh) | bash
208
+ curl -sSL https://raw.githubusercontent.com/CodeGraphContext/CodeGraphContext/main/scripts/post_install_fix.sh | bash
209
209
  ```
210
210
 
211
211
  ---
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "codegraphcontext"
3
- version = "0.3.5"
3
+ version = "0.3.8"
4
4
  description = "An MCP server that indexes local code into a graph database to provide context to AI assistants."
5
5
  authors = [{ name = "Shashank Shekhar Singh", email = "shashankshekharsingh1205@gmail.com" }]
6
6
  readme = "README.md"
@@ -20,7 +20,7 @@ dependencies = [
20
20
  "stdlibs>=2023.11.18",
21
21
  "typer[all]>=0.9.0",
22
22
  "rich>=13.7.0",
23
- "inquirerpy>=0.3.5",
23
+ "inquirerpy>=0.3.4",
24
24
  "python-dotenv>=1.0.0",
25
25
  "tree-sitter>=0.21.0",
26
26
  "tree-sitter-language-pack>=0.6.0",
@@ -30,6 +30,7 @@ dependencies = [
30
30
  "nbconvert>=7.16.6",
31
31
  "pathspec>=0.12.1",
32
32
  "falkordb>=0.1.0",
33
+ "requests>=2.28.0",
33
34
  "falkordblite>=0.1.0; sys_platform != 'win32' and python_version >= '3.12'",
34
35
  "fastapi>=0.100.0",
35
36
  "uvicorn>=0.22.0"
@@ -483,9 +483,10 @@ def clean_helper():
483
483
  console.print("[cyan]🧹 Cleaning database (removing orphaned nodes)...[/cyan]")
484
484
 
485
485
  try:
486
- # Determine if we're using FalkorDB or Neo4j for query optimization
486
+ # Determine backend type for query compatibility
487
487
  db_type = db_manager.__class__.__name__
488
488
  is_falkordb = "Falkor" in db_type
489
+ is_kuzu = "Kuzu" in db_type
489
490
 
490
491
  total_deleted = 0
491
492
  batch_size = 1000
@@ -493,14 +494,15 @@ def clean_helper():
493
494
  with db_manager.get_driver().session() as session:
494
495
  # Keep deleting orphaned nodes in batches until none are found
495
496
  while True:
496
- if is_falkordb:
497
- # FalkorDB-compatible query using OPTIONAL MATCH
497
+ if is_falkordb or is_kuzu:
498
+ # FalkorDB / KùzuDB-compatible query using OPTIONAL MATCH
499
+ # (KùzuDB does not support the Neo4j `NOT EXISTS { MATCH ... }` subquery syntax)
498
500
  query = """
499
501
  MATCH (n)
500
502
  WHERE NOT (n:Repository)
501
- OPTIONAL MATCH path = (n)-[*..10]-(r:Repository)
502
- WITH n, path
503
- WHERE path IS NULL
503
+ OPTIONAL MATCH p = (n)-[*..10]-(r:Repository)
504
+ WITH n, p
505
+ WHERE p IS NULL
504
506
  WITH n LIMIT $batch_size
505
507
  DETACH DELETE n
506
508
  RETURN count(n) as deleted
@@ -296,6 +296,12 @@ def run_command(command, console, shell=False, check=True, input_text=None):
296
296
  Returns the completed process object on success, None on failure.
297
297
  """
298
298
  cmd_str = command if isinstance(command, str) else ' '.join(command)
299
+
300
+ # Mask passwords from being printed out
301
+ if "set-initial-password" in cmd_str:
302
+ import re
303
+ cmd_str = re.sub(r'(set-initial-password\s+)(\S+)', r'\g<1>********', cmd_str)
304
+
299
305
  console.print(f"[cyan]$ {cmd_str}[/cyan]")
300
306
  try:
301
307
  process = subprocess.run(
@@ -109,14 +109,21 @@ class KuzuDBManager:
109
109
  ("Parameter", "uid STRING, name STRING, path STRING, function_line_number INT64, PRIMARY KEY (uid)")
110
110
  ]
111
111
 
112
+ # rel_tables: list of (table_name, schema, use_group)
113
+ # use_group=True -> CREATE REL TABLE GROUP (for multi FROM..TO bindings)
114
+ # use_group=False -> CREATE REL TABLE (single binding)
112
115
  rel_tables = [
113
- ("CONTAINS", "FROM File TO Function, FROM File TO Class, FROM File TO Variable, FROM File TO Trait, FROM File TO Interface, FROM `Macro` TO `Macro`, FROM File TO `Macro`, FROM File TO Struct, FROM File TO Enum, FROM File TO `Union`, FROM File TO Annotation, FROM File TO Record, FROM File TO Property, FROM Repository TO Directory, FROM Directory TO Directory, FROM Directory TO File, FROM Repository TO File, FROM Class TO Function, FROM Function TO Function"),
114
- ("CALLS", "FROM Function TO Function, FROM Function TO Class, FROM File TO Function, FROM File TO Class, FROM Class TO Function, FROM Class TO Class, line_number INT64, args STRING[], full_call_name STRING"),
115
- ("IMPORTS", "FROM File TO Module, alias STRING, full_import_name STRING, imported_name STRING, line_number INT64"),
116
- ("INHERITS", "FROM Class TO Class, FROM Record TO Record, FROM Interface TO Interface"),
117
- ("HAS_PARAMETER", "FROM Function TO Parameter"),
118
- ("INCLUDES", "FROM Class TO Module"),
119
- ("IMPLEMENTS", "FROM Class TO Interface, FROM Struct TO Interface, FROM Record TO Interface")
116
+ # Note: in KùzuDB, some labels (e.g. `Macro`, `Property`, `Union`) are treated as reserved
117
+ # keywords in CREATE REL TABLE statements. We must escape them with backticks
118
+ # or the rel table creation will fail silently, leading to runtime
119
+ # "Binder exception: Table CONTAINS does not exist".
120
+ ("CONTAINS", "FROM File TO Function, FROM File TO Class, FROM File TO Variable, FROM File TO Trait, FROM File TO Interface, FROM `Macro` TO `Macro`, FROM File TO `Macro`, FROM File TO Struct, FROM File TO Enum, FROM File TO `Union`, FROM File TO Annotation, FROM File TO Record, FROM File TO `Property`, FROM Repository TO Directory, FROM Directory TO Directory, FROM Directory TO File, FROM Repository TO File, FROM Class TO Function, FROM Function TO Function", True),
121
+ ("CALLS", "FROM Function TO Function, FROM Function TO Class, FROM File TO Function, FROM File TO Class, FROM Class TO Function, FROM Class TO Class, line_number INT64, args STRING[], full_call_name STRING", True),
122
+ ("IMPORTS", "FROM File TO Module, alias STRING, full_import_name STRING, imported_name STRING, line_number INT64", False),
123
+ ("INHERITS", "FROM Class TO Class, FROM Record TO Record, FROM Interface TO Interface", True),
124
+ ("HAS_PARAMETER", "FROM Function TO Parameter", False),
125
+ ("INCLUDES", "FROM Class TO Module", False),
126
+ ("IMPLEMENTS", "FROM Class TO Interface, FROM Struct TO Interface, FROM Record TO Interface", True)
120
127
  ]
121
128
 
122
129
  for table_name, schema in node_tables:
@@ -127,10 +134,13 @@ class KuzuDBManager:
127
134
  warning_logger(f"Kuzu Schema Node Error ({table_name}): {e}")
128
135
  debug_log(f"Kuzu Schema Node Error ({table_name}): {e}")
129
136
 
130
- for table_name, schema in rel_tables:
137
+ for table_name, schema, use_group in rel_tables:
131
138
  try:
132
- # Need to handle backticks in schema as well for keywords
133
- self._conn.execute(f"CREATE REL TABLE `{table_name}`({schema})")
139
+ if use_group:
140
+ # KùzuDB requires CREATE REL TABLE GROUP for multi-binding relationships
141
+ self._conn.execute(f"CREATE REL TABLE GROUP `{table_name}`({schema})")
142
+ else:
143
+ self._conn.execute(f"CREATE REL TABLE `{table_name}`({schema})")
134
144
  except Exception as e:
135
145
  if "already exists" not in str(e).lower():
136
146
  warning_logger(f"Kuzu Schema Rel Error ({table_name}): {e}")
@@ -36,6 +36,40 @@ from .tools.handlers import (
36
36
  DEFAULT_EDIT_DISTANCE = 2
37
37
  DEFAULT_FUZZY_SEARCH = False
38
38
 
39
+ WORKSPACE_PREFIX = "/workspace/"
40
+
41
+
42
+ def _is_path_key(key: str) -> bool:
43
+ """Check if a dict key represents a file path field.
44
+
45
+ Matches keys like 'path', 'clone_path', 'caller_file_path', and also
46
+ Cypher-aliased keys like 'f.path', 'n.caller_file_path'.
47
+ """
48
+ # Strip Cypher alias prefix (e.g. "f.path" -> "path")
49
+ bare = key.rsplit(".", 1)[-1] if "." in key else key
50
+ return bare == "path" or bare.endswith("_path")
51
+
52
+
53
+ def _strip_path_value(value):
54
+ """Strip /workspace/ prefix from a single string value."""
55
+ if isinstance(value, str) and value.startswith(WORKSPACE_PREFIX):
56
+ return value[len(WORKSPACE_PREFIX):]
57
+ return value
58
+
59
+
60
+ def _strip_workspace_prefix(obj):
61
+ """Recursively strip /workspace/ prefix from path values in results."""
62
+ if isinstance(obj, dict):
63
+ return {
64
+ k: _strip_path_value(v) if _is_path_key(k) else _strip_workspace_prefix(v)
65
+ for k, v in obj.items()
66
+ }
67
+ elif isinstance(obj, list):
68
+ return [_strip_workspace_prefix(item) for item in obj]
69
+ return obj
70
+
71
+
72
+
39
73
  class MCPServer:
40
74
  """
41
75
  The main MCP Server class.
@@ -254,7 +288,8 @@ class MCPServer:
254
288
  tool_name = params.get('name')
255
289
  args = params.get('arguments', {})
256
290
  result = await self.handle_tool_call(tool_name, args)
257
-
291
+ result = _strip_workspace_prefix(result)
292
+
258
293
  if "error" in result:
259
294
  response = {
260
295
  "jsonrpc": "2.0", "id": request_id,
@@ -5,6 +5,7 @@ from typing import Any, Dict, List, Literal, Optional
5
5
  from pathlib import Path
6
6
 
7
7
  from ..core.database import DatabaseManager
8
+ from ..utils.path_ignore import cypher_path_not_under_ignore_dirs
8
9
 
9
10
  logger = logging.getLogger(__name__)
10
11
 
@@ -539,9 +540,13 @@ class CodeFinder:
539
540
 
540
541
  with self.driver.session() as session:
541
542
  repo_filter = "AND func.path STARTS WITH $repo_path" if repo_path else ""
542
- result = session.run(f"""
543
+ decorator_filter = "AND ALL(decorator_name IN $exclude_decorated_with WHERE NOT decorator_name IN func.decorators)" if exclude_decorated_with else ""
544
+ func_ignore = cypher_path_not_under_ignore_dirs("func.path")
545
+ caller_ignore = cypher_path_not_under_ignore_dirs("caller.path")
546
+
547
+ query = f"""
543
548
  MATCH (func:Function)
544
- WHERE func.is_dependency = false {repo_filter}
549
+ WHERE func.is_dependency = false {repo_filter} {func_ignore}
545
550
  AND NOT func.name IN ['main', 'setup', 'run']
546
551
  AND NOT (func.name STARTS WITH '__' AND func.name ENDS WITH '__')
547
552
  AND NOT func.name STARTS WITH '_test'
@@ -550,10 +555,10 @@ class CodeFinder:
550
555
  AND NOT toLower(func.name) CONTAINS 'application'
551
556
  AND NOT toLower(func.name) CONTAINS 'entry'
552
557
  AND NOT toLower(func.name) CONTAINS 'entrypoint'
553
- AND ALL(decorator_name IN $exclude_decorated_with WHERE NOT decorator_name IN func.decorators)
558
+ {decorator_filter}
554
559
  WITH func
555
560
  OPTIONAL MATCH (caller:Function)-[:CALLS]->(func)
556
- WHERE caller.is_dependency = false
561
+ WHERE caller.is_dependency = false {caller_ignore}
557
562
  WITH func, count(caller) as caller_count
558
563
  WHERE caller_count = 0
559
564
  OPTIONAL MATCH (file:File)-[:CONTAINS]->(func)
@@ -566,7 +571,15 @@ class CodeFinder:
566
571
  file.name as file_name
567
572
  ORDER BY func.path, func.line_number
568
573
  LIMIT 50
569
- """, exclude_decorated_with=exclude_decorated_with, repo_path=repo_path)
574
+ """
575
+
576
+ params = {}
577
+ if repo_path:
578
+ params["repo_path"] = repo_path
579
+ if exclude_decorated_with:
580
+ params["exclude_decorated_with"] = exclude_decorated_with
581
+
582
+ result = session.run(query, **params)
570
583
 
571
584
  return {
572
585
  "potentially_unused_functions": result.data(),
@@ -581,8 +594,8 @@ class CodeFinder:
581
594
  # KùzuDB-compatible: Use anonymous end node and filter with WHERE
582
595
  query = f"""
583
596
  MATCH p = (f:Function)-[:CALLS*]->()
584
- WITH f, p, nodes(p) as path_nodes
585
- WITH f, path_nodes, list_extract(path_nodes, size(path_nodes)) as target
597
+ WITH f as f, p as p, nodes(p) as path_nodes
598
+ WITH f as f, path_nodes as path_nodes, path_nodes[size(path_nodes)] as target
586
599
  WHERE target.name = $function_name AND target.path = $path {repo_filter}
587
600
  RETURN DISTINCT f.name AS caller_name, f.path AS caller_file_path, f.line_number AS caller_line_number, f.is_dependency AS caller_is_dependency
588
601
  ORDER BY caller_is_dependency ASC, caller_file_path, caller_line_number
@@ -593,8 +606,8 @@ class CodeFinder:
593
606
  # KùzuDB-compatible: Use anonymous end node and filter with WHERE
594
607
  query = f"""
595
608
  MATCH p = (f:Function)-[:CALLS*]->()
596
- WITH f, p, nodes(p) as path_nodes
597
- WITH f, path_nodes, list_extract(path_nodes, size(path_nodes)) as target
609
+ WITH f as f, p as p, nodes(p) as path_nodes
610
+ WITH f as f, path_nodes as path_nodes, path_nodes[size(path_nodes)] as target
598
611
  WHERE target.name = $function_name {repo_filter}
599
612
  RETURN DISTINCT f.name AS caller_name, f.path AS caller_file_path, f.line_number AS caller_line_number, f.is_dependency AS caller_is_dependency
600
613
  ORDER BY caller_is_dependency ASC, caller_file_path, caller_line_number
@@ -612,8 +625,8 @@ class CodeFinder:
612
625
  query = f"""
613
626
  MATCH (caller:Function {{name: $function_name, path: $path}})
614
627
  MATCH p = (caller)-[:CALLS*]->()
615
- WITH p, nodes(p) as path_nodes
616
- WITH list_extract(path_nodes, size(path_nodes)) as f
628
+ WITH p as p, nodes(p) as path_nodes
629
+ WITH path_nodes[size(path_nodes)] as f
617
630
  {repo_filter}
618
631
  RETURN DISTINCT f.name AS callee_name, f.path AS callee_file_path, f.line_number AS callee_line_number, f.is_dependency AS callee_is_dependency
619
632
  ORDER BY callee_is_dependency ASC, callee_file_path, callee_line_number
@@ -625,8 +638,8 @@ class CodeFinder:
625
638
  query = f"""
626
639
  MATCH (caller:Function {{name: $function_name}})
627
640
  MATCH p = (caller)-[:CALLS*]->()
628
- WITH p, nodes(p) as path_nodes
629
- WITH list_extract(path_nodes, size(path_nodes)) as f
641
+ WITH p as p, nodes(p) as path_nodes
642
+ WITH path_nodes[size(path_nodes)] as f
630
643
  {repo_filter}
631
644
  RETURN DISTINCT f.name AS callee_name, f.path AS callee_file_path, f.line_number AS callee_line_number, f.is_dependency AS callee_is_dependency
632
645
  ORDER BY callee_is_dependency ASC, callee_file_path, callee_line_number
@@ -647,24 +660,12 @@ class CodeFinder:
647
660
  query = f"""
648
661
  MATCH (start:Function {start_props}), (end_target:Function {end_props})
649
662
  {repo_filter}
650
- WITH start, end_target
663
+ WITH start as start, end_target as end_target
651
664
  MATCH path = (start)-[:CALLS*1..{max_depth}]->()
652
- WITH path, end_target, nodes(path) as func_nodes, relationships(path) as call_rels
653
- WITH path, func_nodes, call_rels, list_extract(func_nodes, size(func_nodes)) as path_end
665
+ WITH path as path, end_target as end_target, nodes(path) as func_nodes, relationships(path) as call_rels
666
+ WITH path as path, func_nodes as func_nodes, call_rels as call_rels, end_target as end_target, func_nodes[size(func_nodes)] as path_end
654
667
  WHERE path_end.name = end_target.name AND (end_target.path IS NULL OR path_end.path = end_target.path)
655
- RETURN
656
- [node in func_nodes | {{
657
- name: node.name,
658
- path: node.path,
659
- line_number: node.line_number,
660
- is_dependency: node.is_dependency
661
- }}] as function_chain,
662
- [rel in call_rels | {{
663
- call_line: rel.line_number,
664
- args: rel.args,
665
- full_call_name: rel.full_call_name
666
- }}] as call_details,
667
- length(path) as chain_length
668
+ RETURN func_nodes as function_nodes, call_rels as call_nodes, size(call_rels) as chain_length
668
669
  ORDER BY chain_length ASC
669
670
  LIMIT 20
670
671
  """
@@ -679,7 +680,67 @@ class CodeFinder:
679
680
  }
680
681
 
681
682
  result = session.run(query, **params)
682
- return result.data()
683
+
684
+ # Post-process Node/Rel objects into plain dicts so CLI output stays stable
685
+ rows = result.data()
686
+ transformed: List[Dict[str, Any]] = []
687
+ for row in rows:
688
+ func_nodes = row.get("function_nodes") or []
689
+ rel_nodes = row.get("call_nodes") or []
690
+ chain_len = row.get("chain_length", 0)
691
+
692
+ function_chain = []
693
+ for n in func_nodes:
694
+ # Depending on KùzuDB + driver wrapping, list elements can arrive
695
+ # either as Node/Rel objects or already-materialized dicts.
696
+ if isinstance(n, dict):
697
+ props = n
698
+ else:
699
+ props = None
700
+ try:
701
+ props = n.get_properties()
702
+ except Exception:
703
+ props = getattr(n, "properties", None)
704
+ if props is None:
705
+ props = {}
706
+ function_chain.append(
707
+ {
708
+ "name": props.get("name"),
709
+ "path": props.get("path"),
710
+ "line_number": props.get("line_number"),
711
+ "is_dependency": props.get("is_dependency"),
712
+ }
713
+ )
714
+
715
+ call_details = []
716
+ for r in rel_nodes:
717
+ if isinstance(r, dict):
718
+ props = r
719
+ else:
720
+ props = None
721
+ try:
722
+ props = r.get_properties()
723
+ except Exception:
724
+ props = getattr(r, "properties", None)
725
+ if props is None:
726
+ props = {}
727
+ call_details.append(
728
+ {
729
+ "call_line": props.get("line_number"),
730
+ "args": props.get("args"),
731
+ "full_call_name": props.get("full_call_name"),
732
+ }
733
+ )
734
+
735
+ transformed.append(
736
+ {
737
+ "function_chain": function_chain,
738
+ "call_details": call_details,
739
+ "chain_length": chain_len,
740
+ }
741
+ )
742
+
743
+ return transformed
683
744
 
684
745
  def find_by_type(self, element_type: str, limit: int = 50) -> List[Dict]:
685
746
  """Find all elements of a specific type (Function, Class, File, Module)."""
@@ -988,9 +1049,10 @@ class CodeFinder:
988
1049
  """Find the most complex functions based on cyclomatic complexity."""
989
1050
  with self.driver.session() as session:
990
1051
  repo_filter = "AND f.path STARTS WITH $repo_path" if repo_path else ""
1052
+ path_ignore = cypher_path_not_under_ignore_dirs("f.path")
991
1053
  query = f"""
992
1054
  MATCH (f:Function)
993
- WHERE f.cyclomatic_complexity IS NOT NULL AND f.is_dependency = false {repo_filter}
1055
+ WHERE f.cyclomatic_complexity IS NOT NULL AND f.is_dependency = false {repo_filter} {path_ignore}
994
1056
  RETURN f.name as function_name, f.path as path, f.cyclomatic_complexity as complexity, f.line_number as line_number
995
1057
  ORDER BY f.cyclomatic_complexity DESC
996
1058
  LIMIT $limit