npm package that analyzes TypeScript codebases — parses source, builds dependency graphs, computes architectural metrics, and exposes everything via MCP stdio for LLM-assisted code understanding.
src/
types/index.ts <- All TypeScript interfaces (single source of truth)
parser/index.ts <- TS Compiler API parser (files, functions, imports)
graph/index.ts <- graphology graph builder + circular dep detection
analyzer/index.ts <- Metrics engine (PageRank, betweenness, cohesion, tension, churn, complexity, blast radius, dead exports)
mcp/index.ts <- MCP stdio server (15 tools, 2 prompts, 3 resources)
mcp/hints.ts <- Next-step hints for MCP tool responses
server/graph-store.ts <- Global graph state (shared by CLI + MCP)
impact/index.ts <- Symbol-level impact analysis + rename planning
search/index.ts <- BM25 search engine
process/index.ts <- Entry point detection + call chain tracing
community/index.ts <- Louvain clustering
persistence/index.ts <- Graph export/import to .code-visualizer/
cli.ts <- CLI entry point (commander)
docs/
architecture.md <- Pipeline, module map, data flow, design decisions
data-model.md <- All TypeScript interfaces with field descriptions
metrics.md <- Per-file + module metrics, force analysis, complexity scoring
mcp-tools.md <- 15 MCP tools: inputs, outputs, use cases, selection guide
specs/
active/ <- Current spec
CLI args -> Parser (TS AST) -> Graph Builder (graphology) -> Analyzer (metrics) -> MCP stdio
- ESM modules (
"type": "module") - Bundler module resolution
- Strict mode enabled
- All internal imports use
.jsextension (ESM convention) - Types defined in
src/types/index.ts— import from there, never duplicate import typefor type-only imports (enforced by ESLint)
- graphology — graph data structure. Import as
import Graph from "graphology". Use as both constructor and type. - graphology-metrics — PageRank, betweenness. Default imports from subpaths.
- @modelcontextprotocol/sdk — MCP server. Uses
McpServerclass withserver.tool()registration. - typescript — used as a library (Compiler API), not just a dev tool.
- zod — MCP tool input validation.
- commander — CLI argument parsing.
npm run lint # ESLint (strict typescript-eslint)
npm run typecheck # tsc --noEmit
npm run build # tsc
npm run test # vitestAll four must pass before shipping. Run in order: lint -> typecheck -> build -> test.
| Change Type | Bump | Example |
|---|---|---|
| New MCP tools, new metrics | minor | 1.0.1 → 1.1.0 |
| Bug fixes, description changes, doc sync | patch | 1.1.0 → 1.1.1 |
| Breaking: removed tool, changed tool params | major | 1.1.0 → 2.0.0 |
1. All quality gates pass (lint → typecheck → build → test)
2. Bump version in package.json
3. Commit: "chore(release): bump to vX.Y.Z"
4. Tag: git tag vX.Y.Z
5. Push: git push origin main --tags
6. Publish: pnpm publish:npm
# Bump version (edit package.json, then:)
git add package.json && git commit -m "chore(release): bump to vX.Y.Z"
git tag vX.Y.Z
git push origin main --tags
# Publish to npm (runs lint → typecheck → build → test → publish)
pnpm publish:npmnpm logincompleted on your machine- npm account/package permissions set
- if npm 2FA is enabled, provide OTP during publish
- lint
- typecheck
- build
- test
npm publish --access public
- Strict type-checked config (
strictTypeChecked) - No
any— useunknown+ type guards - No unused vars (except
_prefix) - Consistent type imports enforced
- Explicit return types on non-expression functions
- MCP handlers exempt from
require-awaitandno-deprecated(SDK constraints)
- Validate and clamp all MCP tool input parameters
- No filesystem access beyond the parsed graph data
- New analysis metrics go in
src/analyzer/index.ts - New MCP tools go in
src/mcp/index.ts(register withserver.tool()) - Types always in
src/types/index.ts
- graphology's
getNodeAttribute()returnsunknown— always cast withas Type | undefined path.sepdiffers on Windows vs Linux — normalize to forward slashes for cross-platform- Parser's
walkDirtracks visited dirs to prevent symlink loops - Circular dep detection uses iterative DFS (not recursive) to avoid stack overflow
- MCP tool handlers must be async (SDK requirement) even if they don't await
LLM knowledge base for building this tool. Single source of truth per topic:
| Doc | Covers | Update When |
|---|---|---|
docs/architecture.md |
Pipeline, module map, data flow, design decisions | New module or pipeline change |
docs/data-model.md |
All TypeScript interfaces (mirrors src/types/index.ts) |
Type changes |
docs/metrics.md |
Per-file + module metrics, force analysis, complexity scoring | New metric added |
docs/mcp-tools.md |
15 MCP tools with inputs/outputs/use cases | New tool or param change |
- Test runner: vitest
- Test files:
src/**/*.test.ts,tests/**/*.test.ts - Run:
npm testornpx vitest run
- Every new function, endpoint, or behavior MUST have tests
- Every bug fix MUST include a regression test
- Target: maximum coverage — if code exists, it should be tested
- No feature or fix ships without corresponding tests
- NEVER mock internal modules — use real parser, real graph, real analyzer
- NEVER mock graphology — build real graphs with real data
- NEVER mock filesystem for parser tests — use real fixture directories with real
.tsfiles - Only mock external third-party APIs that require network/auth (none currently)
- Integration tests > unit tests. Test the pipeline, not isolated functions.
| Layer | Test Approach |
|---|---|
| Parser | Real .ts fixture files on disk, assert parsed output |
| Graph | Real parsed files -> real graph builder, assert nodes/edges |
| Analyzer | Real graph -> real metrics, assert values |
| MCP | Real MCP server instance, assert tool responses |
| CLI | Real process execution where feasible |
- NEVER use
jest.mock()orvi.mock()for internal modules - NEVER create fake/stub graph objects — build them through the real pipeline
- NEVER skip tests because "it's just config"
- NEVER write tests that pass regardless of implementation (test behavior, not existence)