Skip to content

feat(js): dependency-cruiser integration with stash+checkout diff#8

Merged
Schr0d merged 15 commits into
mainfrom
feature/v0.7-jsplugin-v2
Apr 15, 2026
Merged

feat(js): dependency-cruiser integration with stash+checkout diff#8
Schr0d merged 15 commits into
mainfrom
feature/v0.7-jsplugin-v2

Conversation

@Schr0d

@Schr0d Schr0d commented Apr 15, 2026

Copy link
Copy Markdown
Owner

Summary

Core feature: archon diff now produces accurate JS/TS dependency changes by temporarily checking out the base commit and running dependency-cruiser against the real file tree.

12 commits across 5 themes:

JS/TS Parser Rewrite

  • Replace regex-based JS/TS parser with dependency-cruiser subprocess (f4a8122)
  • Fix async stderr read, stdin close, and path normalization (9a4646b)

Agent Output & DX

  • Add AgentOutputFormatter, --format agent flag, DiffCommand zero-arg mode (07df8f0)
  • Fix agent format check ordering, suppress ANSI in piped mode (f286501, 5cca7a4)
  • Short name handling for JS path IDs, DX improvements for analyze (b0cbd13, 04bd63f)

Stash+Checkout Diff Pipeline

  • Add stash/checkout/branch methods to GitAdapter (7dbe3d1)
  • Add supportsBatchParse() SPI method, override in JsPlugin (d149ac8)
  • Implement stash+checkout batch-parse path for base graph (7abbb87)
  • Add tests for git stash/checkout batch-parse feature (eaacae9)

Review Fixes

  • Fix printStep ANSI leak, lock file location, stash conflict handling, UTF-8 charset, pin dependency-cruiser to 17.3.10 (d089bdd)

Regex Fallback

  • Regex fallback for diff base graph content parsing + review fixes (0ee21ac)

Pre-Landing Review

6 findings (0 critical, 6 informational), all fixed:

  • printStep ANSI codes leak in agent mode → auto-fixed
  • Temp file read without UTF-8 charset → auto-fixed
  • Lock file in working tree → moved to .git/
  • stashPop failure silently deletes lock file → preserves lock file
  • Lock file written before stash → single write after stash
  • dependency-cruiser @latest unpinned → pinned to 17.3.10

Plan Completion

Plan file: ~/.claude/plans/abstract-moseying-lemon.md
All 6 implementation steps completed + review fixes applied.

Documentation

4 files updated to match v0.7.0.0 changes:

  • README.md: JS parser "Closure Compiler" → "dependency-cruiser", CLI commands updated with --format agent and zero-arg diff, roadmap v0.6 checked
  • README-zh.md: Parallel Chinese updates for parser name, CLI syntax, and roadmap
  • skill.md: Updated /archon diff and /archon analyze descriptions for zero-arg mode and --format agent
  • TODOS.md: Deleted stale swc4j items (fix: multi-language support for archon impact command #3, feat(viz): DOM+SVG rewrite — replace canvas renderer #4), updated DiffCommand --json status to "PARTIALLY ADDRESSED" (P2), renumbered remaining items

Test plan

  • All Gradle tests pass (BUILD SUCCESSFUL)
  • CliGitAdapterTest: 10 new tests for stash/checkout/branch
  • DiffCommandTest: partition, lock file lifecycle, agent format tests
  • JsPluginTest: dependency-cruiser JSON parsing, batch parse support

🤖 Generated with Claude Code

Schr0d and others added 15 commits April 14, 2026 23:44
…rocess

Replace the closure-compiler/regex-based JsPlugin with a lazy batch
subprocess pattern that spawns dependency-cruiser once for the entire
source root, caches the JSON results, and serves subsequent file
lookups from cache.

This increases edge detection from 38 edges (0.078 ratio) to 627 edges
(1.646 ratio) on real Vue projects, a 16x improvement.

Key changes:
- JsPlugin now uses dependency-cruiser via npx subprocess
- Lazy batch: subprocess runs once on first parseFromContent() call
- Filters node_modules, core modules (via coreModule flag), and builtins
- Reports unresolved modules as blind spots
- Protected runDependencyCruiser() for testability via subclass override
- Node.js detection with actionable error message

Deleted files (regex-based parser):
- JsAstVisitor.java, VueFileExtractor.java, ModulePathResolver.java
- ClosureCompilerValidationTest.java, ModulePathResolverTest.java

Build changes:
- Removed closure-compiler dependency
- Added gson:2.10.1 for JSON parsing

28 tests passing, full build clean.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Code review fixes:
- Read stderr in separate thread to avoid blocking the 120s timeout
- Close subprocess stdin immediately to prevent potential hangs
- Add thread safety documentation to JsPlugin class
- Add assertions to Windows path normalization test

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…and zero-arg mode

- AgentOutputFormatter: compressed structured text output for AI agents,
  producing <=200 lines for a 500-node project with hotspots, cycles,
  domain coupling, and blind spots sections
- --format agent flag on both AnalyzeCommand and DiffCommand with
  auto-detect when stdout is not a TTY (System.console() == null)
- DiffCommand migrated to optional parameters (0-3 args): zero args
  compares working tree vs HEAD, one arg compares named ref vs working
  tree, two/three args retain existing behavior
- CliGitAdapter.getWorkingTreeChanges() for staged + unstaged file listing
- 12 new AgentOutputFormatter tests, 3 new CliGitAdapter tests

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Prevent colored ANSI output from leaking into agent-format stream by
computing all analysis data first, then checking format before printing
any text output. Previously, cycles/hotspots/blindspots sections were
printed in color before the agent format check.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Suppress printStep() ANSI codes when console is null (agent/piped mode)
- Remove CliGitAdapter cast, use interface method directly
- Add --format field tests to AnalyzeCommandTest

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Update command description to remove "Java" (it's multi-language)
- Improve --json flag description for clarity
- Add --languages flag to filter plugins by language (escape hatch)
- Add file count breakdown by language before parsing
- Add edge/node ratio warning for potentially incomplete analysis
- Wrap plugin parsing in generic catch to preserve partial results
  when one plugin crashes
- Add extensionLabel helper for human-readable language names
- Add tests for languages flag, extensionLabel, partial result
  preservation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…nore

- DiffCommand.shortName() now handles JS/Vue path-style node IDs
  (src/components/Header.vue → Header.vue) not just Java FQCNs
- Document that JsPlugin intentionally ignores content parameter
  since dependency-cruiser reads files from disk

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
JsPlugin's lazy batch cache caused `archon diff` to produce zero diff
for JS/TS files (base graph returned working-tree data from cache).

Fix: when content is provided AND cache is populated (diff base graph
via git show), parse the content directly with regex instead of using
the dependency-cruiser cache. Includes Vue <script> section extraction.

Also fixes from /review:
- Empty cycle list guards in AgentOutputFormatter and DiffCommand
- Stale step numbering removed from AnalyzeCommand

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ase workflow

Add stashPush, stashPop, checkout, getCurrentBranch, and getHeadSha
to enable stash+checkout approach for accurate JS/TS diff base graphs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…Plugin

Non-breaking SPI addition. Default returns false; JsPlugin overrides to
true because dependency-cruiser must analyze an entire source root at once.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Refactor buildBaseGraph() to partition changed files by plugin type:
- Batch-parse plugins (JS/TS) use stash+checkout to get accurate base
  commit data via dependency-cruiser against the actual base working tree
- Per-file plugins (Java/Python) continue using git show + parseFromContent
- Fresh plugin instances are created for base parse to avoid stale cache
- Crash recovery via .archon-restore.json lock file at startup
- Fallback to per-file regex parsing if stash/checkout fails

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add comprehensive tests covering the new diff infrastructure:
- CliGitAdapter: getCurrentBranch, getHeadSha, stashPush, stashPop,
  checkout (8 new tests with real git repos using @tempdir)
- DiffCommand: partitionChangedFiles logic, extractJsonString helper,
  lock file lifecycle (13 new tests via package-private visibility)
- JsPlugin: supportsBatchParse returns true (1 new test)

Make DiffCommand helper methods package-private for testability:
partitionChangedFiles, extractJsonString, writeRestoreLockFile,
deleteRestoreLockFile.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix printStep ANSI codes leaking in agent/piped mode
- Move crash recovery lock file into .git/ (invisible to git status)
- Write lock file once after stash (not before) for accurate stashRef
- Preserve lock file on stashPop failure so user can recover manually
- Specify UTF-8 charset when reading dependency-cruiser temp output
- Pin dependency-cruiser to 17.3.10 for reproducible builds
- Update lock file tests for new .git/ location

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@Schr0d Schr0d merged commit 3a33771 into main Apr 15, 2026
1 check passed
@Schr0d Schr0d deleted the feature/v0.7-jsplugin-v2 branch April 15, 2026 06:39
Schr0d added a commit that referenced this pull request Apr 15, 2026
- Update AnalyzeCommand description to mention impact assessment
- README/README-zh: remove view/impact/check/ecp references, update
  CLI to analyze+diff only, remove archon-viz from architecture, add
  v0.7 to roadmap, update blind spots (Spring DI now detected)
- CHANGELOG: add v0.7.1.0 entry for SpringDIPostProcessor + command slash
- skill.md/SKILL.md: replace view --format json with analyze --format
  agent, remove Spring DI from blind spots lists
- TODOS: mark #4/#6/#8 DONE, mark #5/#7 OBSOLETE, update remaining
  items to reflect current state

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Schr0d added a commit that referenced this pull request Apr 16, 2026
* feat(core): add SPRING_DI edge type to both EdgeType enums

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(spi): add postProcess() hook to LanguagePlugin for post-parse edge discovery

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(core): integrate postProcess hook into ParseOrchestrator with graph rebuild

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(java): add ArchUnit dependency and ClassDirectoryFinder for Maven/Gradle auto-detection

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(java): SpringDIPostProcessor with ArchUnit bytecode scanning for Spring DI

Uses ArchUnit ClassFileImporter to scan compiled .class files for Spring DI
patterns: @Autowired fields, @resource fields, and constructor injection.
Resolves interface types to concrete @Component/@Service/@repository
implementations and reports ambiguous injections as blind spots.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(java): wire SpringDIPostProcessor into JavaPlugin.postProcess()

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* legal: add THIRD-PARTY-NOTICES for ArchUnit Apache 2.0

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(java): support javax.annotation.Resource + add @Autowired constructor test

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: bump version to 0.7.1.0 for SpringDIPostProcessor

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor(cli): slash to analyze + diff only, merge impact into analyze --target

Remove check, ecp, view commands. Impact analysis now via analyze --target.
EcpGenerator stub removed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: sync all docs for v0.7.1.0 command consolidation + Spring DI

- Update AnalyzeCommand description to mention impact assessment
- README/README-zh: remove view/impact/check/ecp references, update
  CLI to analyze+diff only, remove archon-viz from architecture, add
  v0.7 to roadmap, update blind spots (Spring DI now detected)
- CHANGELOG: add v0.7.1.0 entry for SpringDIPostProcessor + command slash
- skill.md/SKILL.md: replace view --format json with analyze --format
  agent, remove Spring DI from blind spots lists
- TODOS: mark #4/#6/#8 DONE, mark #5/#7 OBSOLETE, update remaining
  items to reflect current state

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(cli): pipe buffer deadlock, ArchUnit log spam, and test coverage

- Fix CliGitAdapter pipe buffer deadlock: drain output stream
  concurrently with waitFor() to prevent 60s hangs on large git show
- Add logback.xml to suppress ArchUnit/Javaparser DEBUG logging
- Cap unbounded module listing in analyze --target (max 20 shown)
- Add 5 tests for resolveTarget/stripNamespacePrefix (replaced
  deleted ImpactCommandTest coverage)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: update CHANGELOG with bug fixes for v0.7.1.0

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor(viz): remove dead ViewCommand and visualization classes

ViewCommand was removed from ArchonCli in the CLI consolidation but the
class and its dependency tree were left behind. Removed:
- ViewCommand, ViewCommandTest (dead CLI entry point)
- TerminalRenderer, TerminalRendererTest (only used by ViewCommand)
- PerspectiveBuilder, PerspectiveBuilderTest (unused visualization)
- NodeGroup, NodeView, EdgeView, PerspectiveView (internal to above)

Kept: JsonSerializer, DiffSerializer, ViewServer (used by analyze/diff)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(cli): --json output no longer mixed with text summary

Moved --json output handling before agent format auto-detection so JSON
output short-circuits cleanly instead of printing after the human-readable
summary.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant