Skip to content

v0.2.0: import graph, parallel discovery, agentic skill generation - #4

Merged
mvoutov merged 5 commits into
mainfrom
feat/scan
Mar 21, 2026
Merged

v0.2.0: import graph, parallel discovery, agentic skill generation#4
mvoutov merged 5 commits into
mainfrom
feat/scan

Conversation

@mvoutov

@mvoutov mvoutov commented Mar 21, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features

    • Import-graph analysis with hubs, coupling, and hotspots; domain and architecture discovery with concurrent processing; new CLI flags (--domains, --verbose)
  • Documentation

    • Expanded README and CONTRIBUTING with graph-driven workflow, parallel discovery flow, and local testing guidance
  • Chores

    • Package version bumped to 0.2.0; added issue and pull-request templates
  • Tests

    • New end-to-end graph-builder and scanner test suites and stability fixes

@coderabbitai

coderabbitai Bot commented Mar 21, 2026

Copy link
Copy Markdown

Walkthrough

Adds a repository import-graph builder and integrates it into scan and doc-init flows, introduces parallelized domain and architecture discovery, updates CLI/options and package metadata, adds contributor and GitHub templates, and includes comprehensive graph and scanner tests.

Changes

Cohort / File(s) Summary
GitHub templates & PR guide
\.github/ISSUE_TEMPLATE/bug_report.yml, \.github/ISSUE_TEMPLATE/feature_request.yml, \.github/ISSUE_TEMPLATE/config.yml, \.github/pull_request_template.md
Add structured issue forms, config linking to Discussions, and a PR template with checklist and testing prompts.
Contribution docs
CONTRIBUTING.md
Restructure and expand contributor guide: setup, local testing (Vitest, npm link, dry-run), code-review conventions, project structure updates, and PR guidance.
Package & CLI
package.json, bin/cli.js
Bump version 0.1.0 → 0.2.0, add es-module-lexer dependency, load version from package.json; add --domains and --verbose CLI options.
Graph builder & scanner
src/lib/graph-builder.js, src/lib/scanner.js
Add buildRepoGraph (JS/TS/Python import parsing, resolution, churn, hubs, clusters, hotspots). Update scanRepo to accept extraDomains, change domain detection to directory-based scanning, export detectEntryPoints, and add repo health checks.
Command integration
src/commands/scan.js, src/commands/doc-init.js
Make scanCommand async and integrate graph building/formatting; docInitCommand uses repo graph, runs parallel domain+architecture discovery, merges findings, batches per-domain generation (PARALLEL_LIMIT=3), and reports elapsed time.
Discovery prompts
src/prompts/discover-domains.md, src/prompts/discover-architecture.md
Add structured prompts requiring <findings> output for domain discovery and architecture analysis.
Tests
tests/graph-builder.test.js, tests/scanner.test.js
Add end-to-end graph-builder tests (parsing, resolution, clustering, edge cases). Update scanner tests to isolated fixtures and robust cleanup; adjust domain-detection expectations.
Docs & changelog
README.md, CHANGELOG.md
Document graph-driven pipeline, parallel discovery/generation, CLI changes, and list notable fixes/removals.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant CLI as "bin/cli.js"
    participant Scan as "src/commands/scan.js"
    participant Scanner as "src/lib/scanner.js"
    participant Graph as "src/lib/graph-builder.js"

    User->>CLI: run scan (with --domains/--verbose)
    CLI->>Scan: scanCommand(path, options)
    Scan->>Scanner: scanRepo(repoPath, { extraDomains })
    Scanner-->>Scan: result (languages, domains, health)
    Scan->>Graph: buildRepoGraph(repoPath, result.languages)
    Graph-->>Scan: repoGraph (hubs, clusters, hotspots)
    Scan-->>CLI: formatted graph + health output
    CLI-->>User: display results
Loading
sequenceDiagram
    actor User
    participant CLI as "bin/cli.js"
    participant DocInit as "src/commands/doc-init.js"
    participant Graph as "src/lib/graph-builder.js"
    participant ClaudeA as "Claude (Domains)"
    participant ClaudeB as "Claude (Architecture)"
    participant DocGen as "Documentation Generator"

    User->>CLI: run doc init
    CLI->>DocInit: docInitCommand(path, options)
    DocInit->>Graph: buildRepoGraph(repoPath, languages)
    Graph-->>DocInit: repoGraph
    DocInit->>ClaudeA: discover-domains prompt (parallel)
    DocInit->>ClaudeB: discover-architecture prompt (parallel)
    ClaudeA-->>DocInit: domain findings
    ClaudeB-->>DocInit: architecture findings
    DocInit->>DocInit: merge findings, select effective domains
    DocInit->>ClaudeA: generateChunked per-domain (batched, limit=3)
    ClaudeA-->>DocInit: per-domain docs
    DocInit->>DocGen: assemble CLAUDE.md
    DocGen-->>CLI: complete
    CLI-->>User: show elapsed time & token summary
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the three major features introduced: import graph building, parallel discovery agents, and agentic skill generation, which align with the substantial changes across graph-builder.js, doc-init.js, and related files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/scan

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
src/lib/graph-builder.js (1)

508-528: Consider adding a timeout error message for verbose mode.

execSync has a 5-second timeout, but failures are silently caught. In very large repos, users might wonder why churn data is missing. However, this is acceptable since churn is supplementary data.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/graph-builder.js` around lines 508 - 528, The analyzeGitChurn
function currently swallows all errors from execSync; update its catch block to
emit a clear timeout/exec error when running in verbose mode so users know why
churn is missing. In the catch for analyzeGitChurn, inspect the caught error
(e.g., check err.code === 'ERR_CHILD_PROCESS_TIMED_OUT' or err.killed/signal)
and, when a verbose flag is set (use process.env.VERBOSE or an existing logger),
log a concise warning that includes repoPath and the error message/stack;
otherwise keep returning the empty churn object.
src/lib/scanner.js (1)

33-67: Minor: sourceFileCount fallback.

Line 55 uses modules.length || undefined, but 0 is a valid count. This won't cause bugs since the domain was matched, but sourceFileCount: modules.length would be more accurate.

Suggested fix
-        sourceFileCount: modules.length || undefined,
+        sourceFileCount: modules.length,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/scanner.js` around lines 33 - 67, In mergeExtraDomains, the matched
domain sets sourceFileCount using "modules.length || undefined" which converts a
valid 0 to undefined; change it to set sourceFileCount to modules.length so zero
is preserved (update the object constructed in mergeExtraDomains where
sourceFileCount is assigned); keep the rest of the structure unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@CONTRIBUTING.md`:
- Around line 103-122: The fenced code block containing the project directory
listing (starts with entries like bin/cli.js, src/, commands/, tests/) lacks a
language tag; change the opening fence from ``` to ```text so the block is
explicitly marked as plain text (e.g., modify the CONTRIBUTING.md fenced block
that lists bin/cli.js, src/, commands/, etc., to begin with ```text).

In `@tests/graph-builder.test.js`:
- Around line 42-117: Tests fail because es-module-lexer isn’t initialized
before parseJsImports is used; update the code so parseJsImports always runs
after init. Either (a) export and call the existing init from graph-builder.js
(the same init used by buildRepoGraph) at the top of the test file before
invoking parseJsImports, or (b) make parseJsImports async and call await init()
inside parseJsImports before calling parse(), ensuring parseJsImports and any
callers (tests) await it; reference parseJsImports, init, and buildRepoGraph
when locating the code to change.

---

Nitpick comments:
In `@src/lib/graph-builder.js`:
- Around line 508-528: The analyzeGitChurn function currently swallows all
errors from execSync; update its catch block to emit a clear timeout/exec error
when running in verbose mode so users know why churn is missing. In the catch
for analyzeGitChurn, inspect the caught error (e.g., check err.code ===
'ERR_CHILD_PROCESS_TIMED_OUT' or err.killed/signal) and, when a verbose flag is
set (use process.env.VERBOSE or an existing logger), log a concise warning that
includes repoPath and the error message/stack; otherwise keep returning the
empty churn object.

In `@src/lib/scanner.js`:
- Around line 33-67: In mergeExtraDomains, the matched domain sets
sourceFileCount using "modules.length || undefined" which converts a valid 0 to
undefined; change it to set sourceFileCount to modules.length so zero is
preserved (update the object constructed in mergeExtraDomains where
sourceFileCount is assigned); keep the rest of the structure unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e13c237a-cd7b-4d39-afbf-0f79a3b1972c

📥 Commits

Reviewing files that changed from the base of the PR and between a6c038e and e9561be.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (15)
  • .github/ISSUE_TEMPLATE/bug_report.yml
  • .github/ISSUE_TEMPLATE/config.yml
  • .github/ISSUE_TEMPLATE/feature_request.yml
  • .github/pull_request_template.md
  • CONTRIBUTING.md
  • bin/cli.js
  • package.json
  • src/commands/doc-init.js
  • src/commands/scan.js
  • src/lib/graph-builder.js
  • src/lib/scanner.js
  • src/prompts/discover-architecture.md
  • src/prompts/discover-domains.md
  • tests/graph-builder.test.js
  • tests/scanner.test.js

Comment thread CONTRIBUTING.md
Comment thread tests/graph-builder.test.js

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
tests/graph-builder.test.js (2)

13-37: Use a unique temp fixture root to avoid parallel-test collisions.

A shared fixed directory can cause flaky cleanup/race behavior across workers/files. Prefer per-run temp dirs.

Proposed refactor
-import { mkdirSync, writeFileSync, rmSync, existsSync } from 'fs';
+import { mkdirSync, writeFileSync, rmSync, existsSync, mkdtempSync } from 'fs';
 import { join } from 'path';
+import { tmpdir } from 'os';
@@
-const FIXTURES_DIR = join(import.meta.dirname, 'fixtures', 'graph-builder');
+const FIXTURES_DIR = mkdtempSync(join(tmpdir(), 'aspens-graph-builder-'));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/graph-builder.test.js` around lines 13 - 37, Replace the shared
FIXTURES_DIR with a unique per-run temp directory: create a temp root using
os/tmp mkdtemp (or fs.mkdtempSync) at test startup (referencing beforeAll and
init) and use that temp root in createFixture instead of the fixed FIXTURES_DIR
constant; ensure createFixture still creates directories and files under the
temp root, and update afterAll cleanup to rmSync that temp directory (and handle
the existing try/catch) so parallel test workers won't collide with each other's
fixture directories.

111-118: Strengthen the require() test assertion (current check is too weak).

expect(result).toBeDefined() passes even if behavior regresses. Assert the returned shape and rename the case to match the actual contract.

Proposed refactor
-  it('handles require() calls as imports', () => {
+  it('does not crash on require() calls', () => {
     const code = `const foo = require('./bar');`;
     const result = parseJsImports(code, 'src/app.js');
-    // es-module-lexer may or may not pick up require() — it focuses on ESM.
-    // If it does, great; if not, this is expected behavior.
-    // The implementation relies on es-module-lexer which only parses ESM syntax.
-    expect(result).toBeDefined();
+    expect(result).toMatchObject({
+      imports: expect.any(Array),
+      exports: expect.any(Array),
+    });
   });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/graph-builder.test.js` around lines 111 - 118, Rename the test to
something like "handles require() calls (may produce no ESM imports)" and
strengthen assertions around parseJsImports: call parseJsImports(code,
'src/app.js') and assert Array.isArray(result) (or assert the returned object's
imports array if parseJsImports returns an object), then assert that if
result.length > 0 each item has the expected shape (e.g., item.specifier is a
string and item.start/item.end are numbers) so the test fails on regressions;
use parseJsImports and item property names (specifier, start, end) as the unique
identifiers to locate and validate the output.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@tests/graph-builder.test.js`:
- Around line 13-37: Replace the shared FIXTURES_DIR with a unique per-run temp
directory: create a temp root using os/tmp mkdtemp (or fs.mkdtempSync) at test
startup (referencing beforeAll and init) and use that temp root in createFixture
instead of the fixed FIXTURES_DIR constant; ensure createFixture still creates
directories and files under the temp root, and update afterAll cleanup to rmSync
that temp directory (and handle the existing try/catch) so parallel test workers
won't collide with each other's fixture directories.
- Around line 111-118: Rename the test to something like "handles require()
calls (may produce no ESM imports)" and strengthen assertions around
parseJsImports: call parseJsImports(code, 'src/app.js') and assert
Array.isArray(result) (or assert the returned object's imports array if
parseJsImports returns an object), then assert that if result.length > 0 each
item has the expected shape (e.g., item.specifier is a string and
item.start/item.end are numbers) so the test fails on regressions; use
parseJsImports and item property names (specifier, start, end) as the unique
identifiers to locate and validate the output.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7936c293-edbb-4386-a8e1-1149f7fdc49d

📥 Commits

Reviewing files that changed from the base of the PR and between e9561be and aa4fd2f.

📒 Files selected for processing (1)
  • tests/graph-builder.test.js

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@README.md`:
- Around line 83-124: The fenced code block in README.md that begins with ```
and contains the aspens doc init output is missing a language specifier
(triggering MD040); update the opening fence to include a language (for example
change ``` to ```text) so the block is explicitly marked as plain text while
keeping the existing closing ``` unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ca262a3a-50f1-4af9-85b8-709220da29a8

📥 Commits

Reviewing files that changed from the base of the PR and between aa4fd2f and 35628dd.

📒 Files selected for processing (5)
  • CHANGELOG.md
  • README.md
  • bin/cli.js
  • src/lib/graph-builder.js
  • tests/graph-builder.test.js
✅ Files skipped from review due to trivial changes (2)
  • CHANGELOG.md
  • src/lib/graph-builder.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/graph-builder.test.js

Comment thread README.md
@mvoutov
mvoutov merged commit fc9fef7 into main Mar 21, 2026
2 checks passed
@mvoutov
mvoutov deleted the feat/scan branch March 21, 2026 00:45
@coderabbitai coderabbitai Bot mentioned this pull request Mar 28, 2026
6 tasks
@coderabbitai coderabbitai Bot mentioned this pull request Apr 25, 2026
6 tasks
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