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

@kb-labs/review-heuristic

v2.94.0

Published

Heuristic analysis engines for AI Review plugin.

Downloads

849

Readme

@kb-labs/review-heuristic

Heuristic analysis engines for AI Review plugin.

Overview

This package provides adapters for deterministic code analysis tools (linters, compilers, SAST) with unified output format and intelligent deduplication.

Features

  • Engine Registry - Maps tools to engine types (compiler/linter/sast/ast)
  • ESLint Adapter - TypeScript/JavaScript linting with fix templates
  • Fingerprint Deduplication - sha1(ruleId|file|bucket|snippetHash)
  • Engine Type Priority - compiler > linter > sast > ast > llm
  • Unified Output - All engines output ReviewFinding[]

Engine Registry

The engine registry maps specific tools to engine types for priority-based deduplication:

import { ENGINE_REGISTRY, getEngine, getEngineTypePriority } from '@kb-labs/review-heuristic';

// Get engine metadata
const eslint = getEngine('eslint');
console.log(eslint.type); // 'linter'

// Get priority (lower = higher priority)
const priority = getEngineTypePriority('eslint');
console.log(priority); // 2 (linter tier)

Supported Engines

| Engine | Type | Language | Priority | |--------|------|----------|----------| | tsc | compiler | TypeScript | 1 | | eslint | linter | TypeScript/JavaScript | 2 | | ruff | linter | Python | 2 | | golangci | linter | Go | 2 | | clippy | linter | Rust | 2 | | rubocop | linter | Ruby | 2 | | semgrep | sast | Multi-language | 3 | | codeql | sast | Multi-language | 3 | | bandit | sast | Python | 3 | | treesitter | ast | Multi-language | 4 |

ESLint Adapter

Run ESLint analysis and get unified findings:

import { analyzeWithESLint } from '@kb-labs/review-heuristic';

// Quick analysis
const findings = await analyzeWithESLint(
  ['src/**/*.ts', 'src/**/*.tsx'],
  '/path/to/project',
  '/path/to/.eslintrc.json'
);

console.log(findings);
// [
//   {
//     id: 'eslint:/path/to/file.ts:no-unused-vars:10:5',
//     ruleId: 'no-unused-vars',
//     type: 'code-quality',
//     severity: 'medium',
//     confidence: 'certain',
//     file: '/path/to/file.ts',
//     line: 10,
//     message: "'foo' is defined but never used.",
//     engine: 'eslint',
//     source: 'heuristic',
//     fix: [{ type: 'replace', ... }],
//     scope: 'local',
//     automated: true
//   }
// ]

Advanced Usage

import { ESLintAdapter } from '@kb-labs/review-heuristic';

const adapter = new ESLintAdapter({
  patterns: ['src/**/*.ts'],
  cwd: '/path/to/project',
  configFile: '.eslintrc.json',
  fix: false, // Don't apply fixes
});

const findings = await adapter.analyze();

Deduplication

Deduplicate findings from multiple engines using fingerprints and priority:

import { deduplicateFindings } from '@kb-labs/review-heuristic';

// Findings from multiple engines
const eslintFindings = await analyzeWithESLint(...);
const tscFindings = await analyzeWithTSC(...);
const semgrepFindings = await analyzeWithSemgrep(...);

// Combine and deduplicate
const allFindings = [...eslintFindings, ...tscFindings, ...semgrepFindings];
const deduplicated = deduplicateFindings(allFindings);

// Result: Keeps highest priority finding for each collision
// - If tsc and eslint report same issue → keep tsc (compiler > linter)
// - If eslint and semgrep report same issue → keep eslint (linter > sast)

How Deduplication Works

  1. Fingerprint Generation: sha1(ruleId|file|bucket|snippetHash)

    • ruleId: Rule identifier (e.g., "no-unused-vars")
    • file: File path
    • bucket: Line bucket (lines 10-19 → bucket 1)
    • snippetHash: Optional hash of code snippet
  2. Collision Detection: Findings with same fingerprint are collisions

  3. Priority Resolution:

    • Sort by engine type priority (compiler > linter > sast > ast > llm)
    • If same type, sort by severity (blocker > high > medium > low > info)
    • Keep highest priority finding, discard rest

Snippet-Based Deduplication

For more precise deduplication, use snippet hashes:

import { deduplicateFindingsWithSnippets } from '@kb-labs/review-heuristic';
import { readFile } from 'node:fs/promises';

// Function to extract code snippet
async function getSnippet(finding: ReviewFinding): Promise<string> {
  const content = await readFile(finding.file, 'utf-8');
  const lines = content.split('\n');
  const snippet = lines[finding.line - 1] ?? '';
  return snippet;
}

// Deduplicate with snippets
const deduplicated = await deduplicateFindingsWithSnippets(
  allFindings,
  getSnippet
);

Integration

This package is used by @kb-labs/review-core for heuristic analysis:

// In review-core
import { analyzeWithESLint, deduplicateFindings } from '@kb-labs/review-heuristic';

export async function runHeuristicAnalysis(request: ReviewRequest): Promise<ReviewResult> {
  const findings: ReviewFinding[] = [];

  // Run ESLint
  const eslintFindings = await analyzeWithESLint(
    request.files,
    request.cwd,
    request.config?.eslintConfig
  );
  findings.push(...eslintFindings);

  // Run other engines...

  // Deduplicate
  const deduplicated = deduplicateFindings(findings);

  return {
    findings: deduplicated,
    metadata: { ... },
  };
}

Architecture

Engine Type Priority System

Instead of hardcoding priority to specific tools (e.g., "ESLint always wins"), we use engine type priority:

  • compiler (priority 1) - Most authoritative, directly from language compiler
  • linter (priority 2) - Language-specific best practices and patterns
  • sast (priority 3) - Security-focused static analysis
  • ast (priority 4) - Read-only AST pattern matching
  • llm (priority 5) - LLM-based heuristics (least deterministic)

This means:

  • TypeScript compiler (tsc) beats ESLint
  • ESLint beats Semgrep
  • Semgrep beats tree-sitter
  • Any deterministic tool beats LLM

But for different languages:

  • ruff (Python linter, priority 2) beats bandit (Python SAST, priority 3)
  • golangci-lint (Go linter, priority 2) beats semgrep (SAST, priority 3)

Why This Design?

  1. Language-Agnostic - Works with any language's tooling
  2. Predictable - Priority based on engine type, not arbitrary tool ranking
  3. Extensible - Easy to add new tools without changing deduplication logic
  4. Respects Expertise - Compilers know best, then linters, then SAST

Future Extensions

Planned adapters:

  • Ruff - Python linter (fast Rust-based)
  • golangci-lint - Go meta-linter
  • Clippy - Rust linter
  • RuboCop - Ruby linter
  • Semgrep - Multi-language SAST
  • CodeQL - GitHub's SAST engine

All will follow the same pattern:

  1. Implement adapter class
  2. Register in ENGINE_REGISTRY
  3. Convert output to ReviewFinding[]
  4. Deduplication handled automatically