-
Notifications
You must be signed in to change notification settings - Fork 298
Cross Repository Dependency Tracking
See which of your indexed repos import from each other — and trace blast radius across repo boundaries.
When you have multiple repos indexed (a library, a service that uses it, a shared utilities package), jCodeMunch's import graph previously stopped cold at each repo boundary. Calling find_importers on a file in your auth-lib repo would never surface the three microservices in your workspace that import it. v1.13.0 fixes this: all import graph tools can now traverse repo boundaries by matching unresolved import specifiers to the package names published by other indexed repos.
The feature is opt-in (cross_repo=false by default) and requires zero additional setup — package names are extracted automatically from pyproject.toml, package.json, go.mod, Cargo.toml, and .csproj files at index time.
If you maintain a shared library and several services that depend on it, you can now ask "what breaks across my entire workspace if I change this function?" and get a real answer — not just the files in one repo.
| Dimension | Detail |
|---|---|
| Ecosystems | Python (pyproject.toml, setup.cfg), JS/TS (package.json, scoped @org/pkg), Go (go.mod — full domain/org/repo module path), Rust (Cargo.toml), C#/.NET (*.csproj) |
| Index time |
extract_package_names(source_root) runs during index_folder / index_repo and stores package_names: list[str] in CodeIndex metadata. Old indexes load cleanly with []. |
| Registry |
build_package_registry() builds an in-memory {package_name → [repo_id]} map from all loaded indexes. Cached with mtime-based invalidation. No new SQLite DB. |
| Specifier extraction |
extract_root_package_from_specifier(specifier, language) strips submodules/subpaths to get the installable root: flask.blueprints → flask, @org/package/utils → @org/package, github.com/gin-gonic/gin/router → github.com/gin-gonic/gin. Relative imports return "" and are never cross-repo matched. |
| Tools updated |
find_importers, get_blast_radius, get_dependency_graph, get_changed_symbols — all gain cross_repo: bool = false
|
| New tool |
get_cross_repo_map — package-level dependency overview across all indexed repos |
| Cross-repo results | Each cross-repo result carries "cross_repo": true and "source_repo": "<repo-id>" so callers know it crossed a boundary |
| Config |
JCODEMUNCH_CROSS_REPO_DEFAULT=1 flips the default globally without changing every call |
| Tests | 53 new tests in tests/test_cross_repo.py; all 1,378 existing tests still pass |
Find all importers of a file, including other indexed repos:
{
"tool": "find_importers",
"arguments": {
"repo": "local/auth-lib",
"file": "src/auth/tokens.py",
"cross_repo": true
}
}Blast radius across repo boundaries:
{
"tool": "get_blast_radius",
"arguments": {
"repo": "local/auth-lib",
"file": "src/auth/tokens.py",
"cross_repo": true,
"max_depth": 3
}
}Package-level dependency map across all indexed repos:
{
"tool": "get_cross_repo_map",
"arguments": {}
}Filter to a single repo's view:
{
"tool": "get_cross_repo_map",
"arguments": {
"repo": "local/auth-lib"
}
}Enable cross-repo traversal globally (config.jsonc):
Or via env var: JCODEMUNCH_CROSS_REPO_DEFAULT=1
find_importers with cross_repo: true — local results are unchanged; cross-repo importers appear with extra fields:
{
"importers": [
{
"file": "src/middleware/auth.py",
"repo": "local/auth-lib",
"cross_repo": false
},
{
"file": "src/handlers/login.py",
"repo": "local/user-service",
"cross_repo": true,
"source_repo": "local/user-service"
},
{
"file": "src/gateway/proxy.py",
"repo": "local/api-gateway",
"cross_repo": true,
"source_repo": "local/api-gateway"
}
]
}get_cross_repo_map with no filter:
{
"repos": [
{
"repo": "local/user-service",
"package_names": ["user-service"],
"depends_on": [
{ "repo": "local/auth-lib", "package_name": "auth-lib" }
],
"depended_on_by": []
},
{
"repo": "local/auth-lib",
"package_names": ["auth-lib"],
"depends_on": [],
"depended_on_by": [
{ "repo": "local/user-service", "package_name": "auth-lib" },
{ "repo": "local/api-gateway", "package_name": "auth-lib" }
]
}
],
"cross_repo_edges": [
{ "from_repo": "local/user-service", "to_repo": "local/auth-lib", "package_name": "auth-lib" },
{ "from_repo": "local/api-gateway", "to_repo": "local/auth-lib", "package_name": "auth-lib" }
]
}-
tools/package_registry.py— new module: manifest parsing, registry building, specifier root extraction, cross-repo file resolution -
tools/get_cross_repo_map.py— new MCP tool: package-level cross-repo dependency overview -
storage/sqlite_store.py—package_names: list[str]added toCodeIndexdataclass; backward-compatible load -
tools/index_folder.py— callsextract_package_names()after indexing and stores result in the index -
tools/find_importers.py—cross_repoparam; queries other repos' import graphs after local traversal -
tools/get_blast_radius.py—cross_repoparam; BFS hops can cross repo boundaries, capped at depth+1 per crossing -
tools/get_dependency_graph.py—cross_repoparam; cross-repo edges carrycross_repo: truelabel -
tools/get_changed_symbols.py— threadscross_repothrough to blast radius wheninclude_blast_radius=true -
config.py—cross_repo_defaultkey +JCODEMUNCH_CROSS_REPO_DEFAULTenv var -
server.py—get_cross_repo_mapregistered; tool count updated to 31 enabled / 32 total
Cross-repository traversal extends jMRI's ImportGraphProvider interface to its natural conclusion: a workspace is not a single repo, and retrieval intelligence should reflect that. This lays the groundwork for future jMRI v1.1 workspace-scope queries where context bundles and blast-radius results can span multiple repos in a single call.
jcodemunch-mcp on GitHub · 1300+ stars
{ "cross_repo_default": true }