Bug Report
Summary
get_module_summary returns files=0, functions=0, classes=0, lines=0 on Windows for any directory. external_deps incorrectly returns all workspace-wide external dependencies instead of module-scoped ones.
Environment
- OS: Windows 10/11
- Package:
@astudioplus/codegraph-mcp 0.18.2–0.18.4
- Graph size: 65,556 nodes, 2,615 CodeFiles
Root Cause
File: crates/codegraph-server/src/domain/module_summary.rs, function path_matches() (line ~217):
fn path_matches(path: &str, prefix: &str) -> bool {
if prefix.is_empty() { return true; }
if path == prefix { return true; }
path.starts_with(prefix) && path[prefix.len()..].starts_with('/') // <-- BUG
}
On Windows, the graph stores paths with backslash separators (via file_path.display().to_string()):
path = "C:\Users\...\agent\prompt_builder.py"
prefix = "C:\Users\...\agent"
path.starts_with(prefix) is true, but path[prefix.len()..] starts with \ not /, so the function returns false. Every CodeFile/Function/Class node is skipped, resulting in all-zero counts.
I verified this with a local Rust reproduction:
path_matches_original("C:\Users\...\agent\prompt_builder.py", "C:\Users\...\agent") => false
path_matches_fixed("C:\Users\...\agent\prompt_builder.py", "C:\Users\...\agent") => true
Proposed Fix
Normalise both sides to forward slashes before comparing:
#[inline]
fn path_matches(path: &str, prefix: &str) -> bool {
if prefix.is_empty() {
return true;
}
let norm_path: String = path.replace('\\', "/");
let norm_prefix: String = prefix.replace('\\', "/");
if norm_path == norm_prefix {
return true;
}
norm_path.starts_with(norm_prefix.as_str())
&& norm_path[norm_prefix.len()..].starts_with('/')
}
With corresponding Windows test cases:
#[test]
fn test_path_matches_windows_backslash() {
assert!(path_matches(
"C:\\Users\\me\\project\\src\\main.rs",
"C:/Users/me/project/src"
));
}
#[test]
fn test_path_matches_windows_backslash_prefix() {
assert!(path_matches(
"C:\\Users\\me\\project\\src\\main.rs",
"C:\\Users\\me\\project\\src"
));
}
#[test]
fn test_path_matches_windows_no_partial_dir() {
assert!(!path_matches(
"C:\\Users\\me\\project\\src_foo\\main.rs",
"C:/Users/me/project/src"
));
}
Additional Issue: trim_end_matches('/') doesn't trim \
Line 64: let prefix = directory.trim_end_matches('/');
This also needs to trim backslash on Windows. Suggested fix:
let prefix = directory.trim_end_matches(|c| c == '/' || c == '\\');
Steps to Reproduce
- Install codegraph-mcp on Windows
- Index a workspace
- Call
get_module_summary with any valid directory path:
get_module_summary(path="C:\\Users\\me\\project\\src")
- Observe:
files=0, total_functions=0, total_classes=0, total_lines=0
Expected Result
Non-zero counts matching the actual files/functions/classes in that directory.
Workaround
None currently available — the bug is in the compiled Rust binary.
Bug Report
Summary
get_module_summaryreturnsfiles=0,functions=0,classes=0,lines=0on Windows for any directory.external_depsincorrectly returns all workspace-wide external dependencies instead of module-scoped ones.Environment
@astudioplus/codegraph-mcp0.18.2–0.18.4Root Cause
File:
crates/codegraph-server/src/domain/module_summary.rs, functionpath_matches()(line ~217):On Windows, the graph stores paths with backslash separators (via
file_path.display().to_string()):path="C:\Users\...\agent\prompt_builder.py"prefix="C:\Users\...\agent"path.starts_with(prefix)istrue, butpath[prefix.len()..]starts with\not/, so the function returnsfalse. Every CodeFile/Function/Class node is skipped, resulting in all-zero counts.I verified this with a local Rust reproduction:
Proposed Fix
Normalise both sides to forward slashes before comparing:
With corresponding Windows test cases:
Additional Issue:
trim_end_matches('/')doesn't trim\Line 64:
let prefix = directory.trim_end_matches('/');This also needs to trim backslash on Windows. Suggested fix:
Steps to Reproduce
get_module_summarywith any valid directory path:files=0,total_functions=0,total_classes=0,total_lines=0Expected Result
Non-zero counts matching the actual files/functions/classes in that directory.
Workaround
None currently available — the bug is in the compiled Rust binary.