Describe the Bug
The dead-code, health, and workspace CLI commands rebuild the dependency graph in-memory without wiring up the
TsconfigResolver. As a result, TS/JS path aliases like @/components/Foo don't resolve to their target files
during the rebuild — they become external: nodes, so the real target files get in_degree = 0 and are falsely
flagged as unreachable.
The init pipeline does not have this bug: it runs a dedicated tsconfig phase that calls
graph_builder.set_tsconfig_resolver(...) before build()
(packages/core/src/repowise/core/pipeline/phases/ingestion.py:328-348). The CLI commands don't replicate this
wiring.
Steps to Reproduce
- In a TS project with
@/* → ./src/* path alias in tsconfig.json, have src/routes/layout.tsx import
Sensor from @/components/SensorProvider.
- Index the repo:
repowise init . --no-workspace --index-only
- Run:
repowise dead-code . --no-workspace --kind unreachable_file --format json
Expected Behavior
src/components/SensorProvider.tsx is not listed as unreachable (it's imported by src/routes/layout.tsx).
Actual Behavior
src/components/SensorProvider.tsx is reported as unreachable_file with "reason": "File has no importers (in_degree=0)", confidence: 0.7, safe_to_delete: true.
On a real 800-file TS project, 171 of 347 unreachable_file findings (49%) were false positives — every file
imported via @/ was misclassified.
The persisted graph in wiki.db is correct: graph_edges contains ('src/routes/layout.tsx', 'src/components/SensorProvider.tsx', 'imports'). The bug is only in the in-memory graph rebuild the CLI performs.
Affected files (all in packages/cli/src/repowise/cli/commands/):
dead_code_cmd.py (~line 143–156)
health_cmd.py (~line 189–210)
workspace_cmd.py (~line 681)
Environment
- OS: macOS 15
- Python version: 3.14.6
- Repowise version: 0.25.0
- Installation method: pipx
Additional Context
Root cause: TsconfigResolver is constructed and attached to GraphBuilder only in the init pipeline. The
resolver is read by resolve_ts_js_import
(packages/core/src/repowise/core/ingestion/resolvers/typescript.py:60-64) during build(). Without it attached,
ctx.tsconfig_resolver is None and non-relative imports fall through to add_external_node(module_path).
Suggested fix: mirror the pipeline's wiring in each CLI command before graph_builder.build(), or extract a shared
wire_tsconfig_resolver(graph_builder, repo_path, include_submodules, include_nested_repos) helper in
repowise.core.ingestion and call it from the pipeline and all three CLI commands.
Related: PR #71 introduced tsconfig alias resolution (pipeline-only); PRs #299 and #244 fixed the same class of
resolver-not-wired false-positive bug for CommonJS require() and Python imports respectively.
Describe the Bug
The
dead-code,health, andworkspaceCLI commands rebuild the dependency graph in-memory without wiring up theTsconfigResolver. As a result, TS/JS path aliases like@/components/Foodon't resolve to their target filesduring the rebuild — they become
external:nodes, so the real target files getin_degree = 0and are falselyflagged as unreachable.
The
initpipeline does not have this bug: it runs a dedicatedtsconfigphase that callsgraph_builder.set_tsconfig_resolver(...)beforebuild()(
packages/core/src/repowise/core/pipeline/phases/ingestion.py:328-348). The CLI commands don't replicate thiswiring.
Steps to Reproduce
@/*→./src/*path alias intsconfig.json, havesrc/routes/layout.tsximportSensorfrom@/components/SensorProvider.repowise init . --no-workspace --index-onlyrepowise dead-code . --no-workspace --kind unreachable_file --format jsonExpected Behavior
src/components/SensorProvider.tsxis not listed as unreachable (it's imported bysrc/routes/layout.tsx).Actual Behavior
src/components/SensorProvider.tsxis reported asunreachable_filewith"reason": "File has no importers (in_degree=0)",confidence: 0.7,safe_to_delete: true.On a real 800-file TS project, 171 of 347
unreachable_filefindings (49%) were false positives — every fileimported via
@/was misclassified.The persisted graph in
wiki.dbis correct:graph_edgescontains('src/routes/layout.tsx', 'src/components/SensorProvider.tsx', 'imports'). The bug is only in the in-memory graph rebuild the CLI performs.Affected files (all in
packages/cli/src/repowise/cli/commands/):dead_code_cmd.py(~line 143–156)health_cmd.py(~line 189–210)workspace_cmd.py(~line 681)Environment
Additional Context
Root cause:
TsconfigResolveris constructed and attached toGraphBuilderonly in theinitpipeline. Theresolver is read by
resolve_ts_js_import(
packages/core/src/repowise/core/ingestion/resolvers/typescript.py:60-64) duringbuild(). Without it attached,ctx.tsconfig_resolverisNoneand non-relative imports fall through toadd_external_node(module_path).Suggested fix: mirror the pipeline's wiring in each CLI command before
graph_builder.build(), or extract a sharedwire_tsconfig_resolver(graph_builder, repo_path, include_submodules, include_nested_repos)helper inrepowise.core.ingestionand call it from the pipeline and all three CLI commands.Related: PR #71 introduced tsconfig alias resolution (pipeline-only); PRs #299 and #244 fixed the same class of
resolver-not-wired false-positive bug for CommonJS
require()and Python imports respectively.