Repository navigation
v0.3.1 — Kotlin dependency edges, and cycles that only count where they bite
The two gaps the 0.3.0 sweep found and left open.
Fixed - a Kotlin dependency graph was empty and claimed to be fine
okhttp reported 0 edges, 6,869 external imports and 0 unresolved relative imports. By the diagnostic added in 0.2.5, that reads as "this code has no internal imports" - about a library that imports its own packages on nearly every file.
That made it the worst remaining honesty hole in the tool: the mechanism built specifically to stop an empty graph being misread was itself handing out a clean bill of health.
Imports were resolved by treating them as paths, relative or dotted, against the set of parsed files. A Kotlin import is not a path. import okhttp3.internal.platform.Platform names a declaration in a package, and the file holding it can be anywhere in the tree. Nothing mapped a package to a file, so every Kotlin import fell through to "external".
Each file's declared package is now read from its package header and indexed, together with the fully-qualified name of every declaration inside it. Three forms resolve:
app.platform.Platform- a declaration, by fully-qualified nameapp.util.*- the whole package, so an edge to every file in itapp.config.Config.DEFAULT- a member, resolved to the declaration above it
okhttp: 0 edges to 1,632, external imports down from 6,869 to 4,768, and 64 dependency cycles that had been invisible. A mixed Kotlin/JavaScript/Python repository went from 2 edges to 89, its Android code finally connected to its own UI and test files.
android.os.Bundle and kotlin.math.roundToInt stay external, which is correct - they are outside the repository.
The index is consulted only for files that declare a package themselves, so a Python dotted import can never collide with a Kotlin fully-qualified name. There is a test for exactly that.
Go is not covered. A Go import is a module path such as github.com/spf13/cobra/..., which needs the module name from go.mod plus a directory mapping. cobra is a single package and genuinely has no internal imports, so the 190 external imports it reports are honest.
Fixed - a Kotlin cycle cost health points for being idiomatic
Resolving Kotlin edges immediately exposed a second defect. okhttp's 64 newly visible cycles cost it the full 20-point cycle penalty, dropping its health from 66.0 to 46.0 - for writing ordinary Kotlin.
That penalty was written for Python and JavaScript, where an import executes at module load and a cycle can raise at runtime. Kotlin, Java and Go compile a module as a whole, and circular references between files are normal; within a package Kotlin needs no import at all.
Every cycle is still reported by scan_repo, because the information is useful. Only a cycle touching a .py, .js, .jsx, .mjs, .cjs, .ts or .tsx file costs points, so a cycle spanning languages still counts.
okhttp is back to 66.0 with its 64 cycles reported. Flask keeps its 37 Python cycles and its 39.1, which is the right answer for a language where they bite.
Upgrading
uv tool upgrade reforge-mcp --refresh # or: pip install -U reforge-mcp
Full detail in CHANGELOG.md.
🤖 Generated with Claude Code