Trace what a change breaks
Find a file's imports, reverse imports, and connected tests with source-line evidence, so a local edit gets a review as wide as its reach.
A change to one file is rarely contained to one file. Before editing, find out who depends on it and which tests are connected.
Show the imports and tests connected to src/core/analysis/dependencies.ts.
This runs locally. No model call.
A real map
{
"file": "src/core/analysis/dependencies.ts",
"depth": 1,
"dependencies": [
{
"file": "src/core/analysis/ast.ts",
"via": [{ "line": 3, "kind": "import" }]
},
{
"file": "src/core/analysis/modulePaths.ts",
"via": [{ "line": 4, "kind": "import" }]
},
{
"file": "src/core/analysis/moduleResolution.ts",
"via": [{ "line": 5, "kind": "import" }]
},
{
"file": "src/core/sourceFiles.ts",
"via": [{ "line": 6, "kind": "import" }]
}
],
"dependents": [
{ "file": "src/mcp/server.ts", "via": [{ "line": 6, "kind": "import" }] },
{
"file": "src/test/dependencies.test.ts",
"test": true,
"via": [{ "line": 6, "kind": "import" }]
}
],
"totalNeighbors": 6,
"truncated": false
}
Three things to read here:
dependencies- what this file pulls in. Change these and you may change this file’s behavior.dependents- what pulls this file in. These are what your edit can break. Here it is exactly one production file,src/mcp/server.ts, so the blast radius is small.test: true-src/test/dependencies.test.tsis the suite connected to this file. That is the one to run first.
Every relationship carries a line, so you can jump straight to the import
rather than searching for it.
Evidence, not coverage
test: true means that file imports this one and sits at a test path. It does
not mean the test covers the code you are about to change, and the map shows
static imports only - not runtime calls, dynamic import() resolved at runtime,
or dependency injection. A file with no listed dependents can still be reached.
Going wider
Default depth is one hop each way. For a change you expect to ripple:
Map the dependencies of src/core/analysis/dependencies.ts two hops out.
Depth goes up to 3. Raise it deliberately - each hop multiplies the neighbors,
and limit (50 by default, 200 max) will start truncating. Check truncated
in the result before treating a map as complete.
Unresolved imports are reported, not hidden
"unresolved": [
{ "line": 1, "specifier": "fs/promises", "reason": "external, out-of-root or unresolved import" },
{ "line": 2, "specifier": "path", "reason": "external, out-of-root or unresolved import" }
]
These are Node built-ins, so they are correctly outside the map. The field exists so you can tell “nothing depends on this” apart from “the scan could not follow the import” - if a specifier you expected to resolve shows up here, the map is incomplete and you should know that before trusting it.
Pairing it with a review
The useful sequence before touching a shared file:
Show the imports and tests connected to src/core/analysis/dependencies.ts.
then, after your edit,
Check src/core/analysis/dependencies.ts and src/mcp/server.ts for likely
runtime failures.
Reviewing the file you changed together with its dependents is what turns a local edit into a review as wide as the change actually reaches.