npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@repostem/engine

v0.2.0

Published

Architectural drift and blast-radius tracking engine for JavaScript/TypeScript repositories. Models repositories as dependency graphs and tracks how their architecture evolves over time, computing structural risk, blast radius, circular dependencies, and

Downloads

76

Readme

@repostem/engine

Architectural drift and blast-radius tracking engine for JavaScript/TypeScript repositories. Models repositories as dependency graphs and tracks how their architecture evolves over time, computing structural risk, blast radius, circular dependencies, and emerging hotspots.

Features

  • Dependency Graph Analysis: Build in-memory dependency graphs from repository code
  • Structural Metrics: Compute centrality, coupling, churn, and circular dependency detection
  • Risk Scoring: Calculate weighted risk scores to identify fragile files
  • Impact Analysis: Determine which files are affected by changes to a specific file (blast radius)
  • Hotspot Detection: Identify architectural hotspots with high risk and impact
  • Hotspot Trend Analysis: Track hotspot evolution over time across snapshots
  • Architectural Drift Detection: Compare structural metrics across snapshots to identify changes
  • Snapshot Persistence: Store and retrieve repository analysis snapshots (SQLite/PostgreSQL)
  • Branch Filtering: Analyze snapshots by branch for multi-branch workflows
  • Cycle Detection: Identify circular dependencies in your codebase
  • AI-Powered Explanations: Get natural language explanations (risk, impact, trend, drift, hotspot queries)
  • Database Migrations: Manage storage backend schema updates
  • Multi-Language Support: Currently supports JavaScript and TypeScript (extensible architecture)

Installation

npm install @repostem/engine
# or
pnpm add @repostem/engine
# or
yarn add @repostem/engine

Quick Start

import {
  analyzeRepository,
  analyzeFileRisk,
  computeFileImpact,
  calculateHotspots,
  calculateHotspotTrends
} from '@repostem/engine';

// Analyze entire repository
const analysis = await analyzeRepository('/path/to/your/repo');
console.log(`Total files: ${analysis.totalFiles}`);
console.log(`High risk files:`, analysis.topRiskFiles);

// Analyze specific file risk
const risk = await analyzeFileRisk('/path/to/your/repo', 'src/core/service.ts');
console.log(`Risk score: ${risk.riskScore}`);
console.log(`Centrality: ${risk.centrality}`);

// Compute file impact
const impact = await computeFileImpact('/path/to/your/repo', 'src/core/service.ts');
console.log(`Files affected: ${impact.totalImpactCount}`);

// Identify architectural hotspots
const hotspots = await calculateHotspots('/path/to/your/repo');
console.log(`Top hotspots:`, hotspots);

// Track hotspot evolution over time
const trends = await calculateHotspotTrends('/path/to/your/repo');
console.log(`Trending hotspots:`, trends);

API Reference

analyzeRepository(repoPath: string)

Analyzes an entire repository and returns project-level metrics.

const result = await analyzeRepository('/path/to/repo');

// Returns:
{
  totalFiles: number;
  totalDependencies: number;
  cycleCount: number;
  topCentralFiles: RankedFile[];
  highChurnFiles: RankedFile[];
  topRiskFiles: RankedFile[];
}

analyzeFileRisk(repoPath: string, filePath: string)

Analyzes a specific file's structural risk.

const result = await analyzeFileRisk('/path/to/repo', 'src/file.ts');

// Returns:
{
  file: string;
  centrality: number;        // 0-1, how many files depend on this file
  coupling: number;          // 0-1, structural connectivity
  churn: number;             // 0-1, historical volatility
  hasCircularDependency: boolean;
  riskScore: number;         // 0-1, weighted risk score
}

computeFileImpact(repoPath: string, filePath: string)

Computes the impact of changing a specific file.

const result = await computeFileImpact('/path/to/repo', 'src/file.ts');

// Returns:
{
  file: string;
  directDependents: string[];
  transitiveDependents: string[];
  totalImpactCount: number;
  impactRatio: number;       // proportion of files affected
}

detectRepositoryCycles(repoPath: string)

Detects circular dependencies in the repository.

const cycles = await detectRepositoryCycles('/path/to/repo');

// Returns:
{
  files: string[];
}[]

ask(question: string, repoPath: string)

Ask natural language questions about your repository (AI-powered).

const answer = await ask('What is the risk of src/core/service.ts?', '/path/to/repo');
// Returns natural language explanation of the risk

classify(repoPath: string)

Classifies repository structure and patterns.

const classification = await classify('/path/to/repo');

initializeRepo(repositoryRoot: string, options: InitRepoOptions)

Initialize repository for snapshot persistence with SQLite or PostgreSQL.

const result = await initializeRepo('/path/to/repo', {
  storageType: 'sqlite',
  storagePath: '.repostem.db',
  repoId: 'optional-existing-repo-id' // for reconfiguration
});

// Returns:
{
  success: boolean;
  repoId: string;
  config: RepoStemConfig;
  migrationResult: MigrationResult;
  message: string;
}

Note: When reconfiguring storage, provide the existing repoId to preserve repository identity.

isRepoInitialized(repositoryRoot: string)

Check if a repository is initialized for persistence.

const initialized = isRepoInitialized('/path/to/repo');
// Returns: boolean

resetPersistence(repositoryRoot: string)

Reset persistence by deleting all snapshots for a repository while keeping the repo record.

const result = await resetPersistence('/path/to/repo');

// Returns:
{
  success: boolean;
  message: string;
  snapshotsDeleted: number;
}

calculateHotspots(repoPath: string, options?: HotspotServiceOptions)

Identify architectural hotspots - files with high structural risk and impact that warrant attention.

import { calculateHotspots, Hotspot } from '@repostem/engine';

const hotspots = await calculateHotspots('/path/to/repo');

// Returns: Hotspot[]
{
  file: string;
  riskScore: number;
  impactRatio: number;
  churn: number;
  circularDependency: number;
  hotspotScore: number;
}

Options:

  • threshold: Minimum hotspot score to include (default: 0.35)
  • limit: Maximum number of hotspots to return (default: 5)

calculateHotspotTrends(repoPath: string, options?: HotspotTrendServiceOptions, trendThreshold?: number, limit?: number)

Track hotspot evolution over time by comparing two snapshots.

import { calculateHotspotTrends, HotspotTrendItem, HotspotTrendServiceOptions } from '@repostem/engine';

const trends = await calculateHotspotTrends('/path/to/repo', {
  since: 'snapshot-id', // optional: compare with specific snapshot
  branch: 'main',       // optional: filter by branch
  noBranchFilter: false // optional: disable branch filtering
}, 0.05, 5);

// Returns: HotspotTrendItem[]
{
  file: string;
  previousRiskScore: number;
  currentRiskScore: number;
  riskDelta: number;
  previousImpactRatio: number;
  currentImpactRatio: number;
  impactDelta: number;
  trendScore: number;
}

Options:

  • since: Snapshot ID to compare against
  • branch: Filter snapshots by branch
  • noBranchFilter: Disable branch filtering

Parameters:

  • trendThreshold: Minimum trend score to include (default: 0.05)
  • limit: Maximum number of trending hotspots to return (default: 5)

detectDrift(repoPath: string, options?: DriftServiceOptions)

Detect architectural drift between snapshots by comparing structural metrics.

import { detectDrift, DriftServiceOptions } from '@repostem/engine';

const drift = await detectDrift('/path/to/repo', {
  since: 'snapshot-id', // optional: compare with specific snapshot
  branch: 'main',       // optional: filter by branch
  noBranchFilter: false // optional: disable branch filtering
});

Options:

  • since: Snapshot ID to compare against
  • branch: Filter snapshots by branch
  • noBranchFilter: Disable branch filtering

getSnapshotHistory(repoPath: string, options?: HistoryServiceOptions)

View snapshot history for a repository.

import { getSnapshotHistory, HistoryServiceOptions } from '@repostem/engine';

const history = await getSnapshotHistory('/path/to/repo', {
  branch: 'main',       // optional: filter by branch
  noBranchFilter: false // optional: disable branch filtering
});

Options:

  • branch: Filter snapshots by branch
  • noBranchFilter: Disable branch filtering

Metrics Explained

Centrality

Measures how many files depend on a given file. High centrality indicates a file that is widely used throughout the codebase.

  • Range: 0.0 - 1.0
  • Formula: inDegree(F) / (totalFiles - 1)

Coupling

Measures structural connectivity through both incoming and outgoing dependencies.

  • Range: 0.0 - 1.0
  • Formula: (inDegree + outDegree) / (2 * (totalFiles - 1))

Churn

Measures historical volatility based on git commit frequency.

  • Range: 0.0 - 1.0
  • Formula: commitCount(F) / maxCommits

Risk Score

Weighted combination of metrics to identify fragile code.

  • Range: 0.0 - 1.0
  • Formula: 0.4*centrality + 0.3*coupling + 0.2*churn + 0.1*circularPenalty

Interpretation:

  • 0.0 - 0.3: Low structural risk
  • 0.3 - 0.6: Moderate structural risk
  • 0.6 - 1.0: High structural risk

Hotspot Score

Combined metric that identifies files with high risk and high impact that warrant attention.

  • Range: 0.0 - 1.0
  • Formula: (riskScore * 0.5) + (normalizedImpactRatio * 0.3) + (churn * 0.15) + cycleBonus
  • cycleBonus: 0.05 if file is in a cycle, otherwise 0

Interpretation:

  • Files with hotspot score > 0.35 are considered architectural hotspots
  • Higher scores indicate files that are both risky and have high impact

Trend Score

Measures the evolution of a file's hotspot status between two snapshots.

  • Range: 0.0 - 1.0
  • Formula: (riskDelta * 0.6) + (normalizedImpactDelta * 0.4)
  • riskDelta: Change in risk score between snapshots
  • normalizedImpactDelta: Impact delta normalized to 0-1 range

Interpretation:

  • Higher trend scores indicate files becoming more problematic
  • Positive values indicate increasing risk/impact
  • Used to identify emerging hotspots

Configuration

Ignore Patterns

The engine respects .gitignore and additional ignore patterns. You can configure custom ignore patterns through the config loader.

AI Explanation

For AI-powered explanations, you'll need to configure an OpenAI API key:

import { setAIService } from '@repostem/engine';
import { OpenAIProvider } from '@repostem/engine';

setAIService(new OpenAIProvider({
  apiKey: process.env.OPENAI_API_KEY
}));

Language Support

Currently supports:

  • JavaScript (ES6+)
  • TypeScript

The parser architecture is extensible. You can add support for additional languages by implementing the LanguageParser interface.

Architecture

The engine is organized into several layers:

  1. Parser: Tree-sitter-based AST parsing for JS/TS
  2. Dependency Graph: In-memory graph representation of file dependencies
  3. Metrics Engine: Computes centrality, coupling, churn, and circular dependencies
  4. Risk Engine: Calculates weighted risk scores
  5. AI Explanation Layer: Converts metrics to natural language explanations

Contributing

Contributions are welcome! Please see the main RepoStem repository for contribution guidelines.

License

MIT

Related Packages

  • @repostem/cli - CLI tool for using this engine from the command line