npm-safe

August 29, 2026 · View on GitHub

npm-safe

Scan before you install.

Version npm Downloads Stars License CI Node

Quick start · Why npm-safe? · Security · Roadmap · 中文版


npm-safe low, medium, and high DSH plugin installation risk states

Three DSH installation verdicts at a glance. The desktop app analyzes and generates a pinned command; it does not install from this screen.

npm-safe is a local-first npm supply-chain scanner for the command line, CI, desktop, and AI coding agents. Its fast default scan checks published metadata and README signals; an opt-in deep scan also verifies and inspects the shipped tarball for dangerous archive structure, executable content, obfuscation, process execution, networking, and sensitive environment access. Every run returns an explainable 0–100 security score.

The desktop app turns that evidence into a red/yellow/green installation risk card for npm package names and public GitHub plugin repositories. It checks DSH bundle declarations, shipped patch files, lifecycle scripts, host-owned core dependencies, dependency sources, and peer compatibility, then produces a version- or commit-pinned command without running it.

Static analysis and caching run locally with no account or hosted backend. Optional LLM analysis is disabled by default and only runs when you configure a provider.

If npm-safe makes one dependency decision safer, please consider starring the repository. It helps other developers discover the project.

Why npm-safe?

npm audit is excellent at finding published vulnerabilities in known dependency versions. npm-safe complements it by looking for suspicious package metadata and supply-chain attack signals before or during installation.

Use caseCommandWhat you get
Check a package before choosing itnpm-safe check <package>Rule findings, explanations, and a security score
Guard a package-manager installnpm-safe install <package>An opt-in confirmation gate below your score threshold
Protect an existing projectnpm-safe ci --lockfileDirect and transitive dependency scanning with CI exit codes
Review DSH plugins visuallyDesktop appInstallation risk card, DSH contract checks, and a pinned command
Give coding agents a safety checknpm-safe skill installA skill for Codex, Claude Code, OpenCode, Gemini CLI, and more

The scanner is transparent by design: the 10 metadata rules and 12 deep-scan rules are documented and configurable, and metadata analysis is extensible with local rule plugins.

Quick Start

Requires Node.js 20.12 or later.

Try it without a global install:

npx @npm-safe/core check lodash
npx @npm-safe/core check lodash --deep  # verify + inspect published contents

Or install the CLI globally:

npm install -g @npm-safe/core
npm-safe check lodash

Install as a library:

npm install @npm-safe/core
import { NpmSafeEngine } from "@npm-safe/core";

const engine = new NpmSafeEngine();
const result = await engine.checkPackage("lodash");
console.log(result.security.overallLevel, result.security.overallScore);
engine.close();

CLI Usage

The npm-safe binary ships with the @npm-safe/core package. Global options:

  • -d, --db <path>: custom SQLite database path (default ~/.npm-safe/npm-safe.db)
  • -p, --proxy <url>: HTTP proxy for registry requests
  • -j, --json: JSON output
  • -v, --version: print version
npm-safe <package>                 # Shorthand for check
npm-safe check <package>            # Check a package's security posture
npm-safe check <pkg1> <pkg2> ...    # Check multiple packages (batch)
npm-safe check --file deps.txt      # Read package names from a file
npm-safe check -r <package>         # Force re-fetch from registry (ignore cache)
npm-safe check --deep <package>     # Verify and inspect the published tarball
npm-safe search <query>            # Search the npm registry
npm-safe search <query> -s 10      # Limit the number of results
npm-safe watch list                # List watched packages
npm-safe watch add <package>       # Add a package to the watchlist
npm-safe watch remove <package>    # Remove a package from the watchlist
npm-safe refresh [package]         # Refresh one (or all watched) packages
npm-safe settings get <key>        # Read a setting
npm-safe settings set <key> <val>  # Write a setting
npm-safe lang [en|zh]              # Get or set the output language
npm-safe rules list                # List scan rules with effective status
npm-safe rules enable <rule-id>    # Enable a scan rule (persisted)
npm-safe rules disable <rule-id>   # Disable a scan rule (persisted)
npm-safe rules severity <rule-id> <severity>  # Override a rule's severity
npm-safe llm status                # Show LLM provider status
npm-safe llm enable                # Enable LLM scanning
npm-safe llm disable               # Disable LLM scanning
npm-safe llm set-provider <openai|gemini|anthropic>
npm-safe llm set-key <api-key>     # Set the LLM API key
npm-safe llm set-model <model>     # Set the LLM model identifier
npm-safe llm set-base-url <url>    # Set a custom LLM API base URL
npm-safe llm test-connection       # Test the LLM connection
npm-safe ci                        # Scan dependencies, fail the build on severe findings
npm-safe ci --lockfile             # Scan every dependency (incl. transitive) in package-lock.json
npm-safe ci --lockfile --deep      # Also inspect each published tarball; fail closed if incomplete
npm-safe report lodash express     # Export security reports (JSON/CSV)
npm-safe telemetry status          # Show telemetry status (opt-in, local only)
npm-safe gate status               # Show install gate status (opt-in)
npm-safe gate enable               # Enable the gate + auto-install wrappers/shims
npm-safe gate shell                # Install shell wrappers + PATH shims
npm-safe gate shell --machine      # Windows (admin): prepend shims to system PATH
npm-safe install axios             # Install with the security gate (if enabled)
npm-safe doctor                    # Diagnose PATH / gate / shim setup

A few everyday examples:

npm-safe check react                # check a single package
npm-safe search "web framework"     # search the npm registry
npm-safe watch add lodash           # watch a package for changes
npm-safe refresh                    # refresh all watched packages
npm-safe settings set lang zh       # persist a setting

Example output:

npm-safe check lodash
# Package: lodash
# Latest version: 4.18.1
# Security level: safe
# Score: 97/100
# Findings: 1 low-severity informational signal

Windows PATH note: a global install places npm-safe in the npm global bin directory (%APPDATA%\npm), which must be on your PATH for external terminals to find it. The official Node.js MSI adds it automatically; for custom installs (e.g. Node unpacked to a custom folder) add it yourself: setx PATH "%APPDATA%\npm;%PATH%", then reopen the terminal. If anything looks off, run npm-safe doctor for a diagnosis.

The deeper features (proxy details, custom rule plugins, LLM scanning, CI/CD, batch operations, report export, telemetry, the shared check history, the command log, and the install-time security gate) are covered in the Features section below.


Desktop GUI

A Neutralinojs desktop app (Material You dashboard with check, search, watch, rules, LLM, and settings tabs) is distributed as a portable ZIP asset on each GitHub Release, not as an npm package. To download:

  1. Open the Releases page.
  2. Pick the latest release and download the portable ZIP (npm-safe-release.zip).
  3. Unzip and run the npm-safe executable (Windows) or npm-safe binary (macOS/Linux). The app bundles the @npm-safe/core engine and stores data in ~/.npm-safe/.

The app checks for updates automatically on startup: when a newer version is available on the Releases page, it prompts and installs the update in place, then restarts. Only the first installation requires a manual ZIP download; subsequent updates are automatic.

What the GUI offers:

  • Overview dashboard: average security score with a half-circle gauge, recent checks list, 7-day check histogram, total count, and risk breakdown.
  • Check: enter a package name and view the security level, score, and findings.
  • Search: keyword search against the npm registry; click a result to jump straight to Check.
  • Watch: manage the watchlist and refresh individual packages or all watched packages.
  • Rules: list all registered rules, toggle each rule, and override its severity; reload custom rule plugins from ~/.npm-safe/rules/.
  • LLM: configure optional LLM scanning with a test-connection button.
  • Settings: read/write arbitrary engine settings (e.g. proxy, lang), including the install gate.
  • Light/Dark themes and custom window chrome: two independent Material You palettes from the custom title bar, with the theme and last active tab remembered across sessions.

Check history is persisted by the Node.js extension process to the shared SQLite database (~/.npm-safe/npm-safe.db, check_history table); see Shared check history.

Windows first run: if the WebView2 window fails to load with a loopback error, run once in an administrator PowerShell: CheckNetIsolation.exe LoopbackExempt -a -n="Microsoft.Win32WebViewHost_cw5n1h2txyewy".

Developer instructions for running and building the desktop app live in CONTRIBUTING.md; the app itself is documented in the Desktop README.


AI Skill

The npm-safe-scan agent skill (for AI agents that auto-load ~/.agents/skills/) is bundled with the package but is never installed automatically. Installing @npm-safe/core does not run a postinstall hook or write to any agent configuration directory. Use the explicit commands below when you want to install the skill.

To manage the skill manually:

  • npm-safe skill install — install to the generic ~/.agents/skills/npm-safe-scan/ directory
  • npm-safe skill install --agent <ids> — install into one or more specific AI agents (comma-separated: codex,claude-code,opencode,trae,qoder,zcode,gemini-cli)
  • npm-safe skill status — check whether it is installed (including per-agent status)
  • npm-safe skill uninstall — remove it (supports --agent to remove per agent)
  • npm-safe skill — open the interactive installation-wizard TUI in a terminal

Installation targets per agent:

AgentInstall targetKind
Generic (~/.agents/skills/)~/.agents/skills/npm-safe-scan/SKILL.mdskill
OpenCode~/.config/opencode/AGENTS.mdinstructions
Claude Code~/.claude/skills/npm-safe-scan/SKILL.mdskill
Qoder~/.qoder/skills/npm-safe-scan/SKILL.mdskill
Zcode~/.zcode/skills/npm-safe-scan/SKILL.mdskill
Codex~/.codex/AGENTS.mdinstructions
Gemini CLI~/.gemini/GEMINI.mdinstructions
Trae~/.trae/skills/npm-safe-scan/SKILL.mdskill

The skill lets AI agents invoke npm-safe commands (check, search, watch, refresh, settings, lang, and more) to scan npm packages before installing them, acting as a "check before you install" safety gate.


Features

Bounded package-content scanning

--deep downloads the selected version's tarball from the configured registry, verifies npm SRI/shasum metadata when present, parses the archive entirely in memory, and reports file paths and line numbers for high-confidence findings. It never extracts package files or executes package code.

Safety limits are enforced before and during parsing: 20 MiB compressed, 50 MiB unpacked, 5,000 archive entries, 1 MiB per text file, and 8 MiB total text inspected. Tarball URLs and redirects must remain on the configured registry origin. Reaching a limit produces a visible partial result; ci --deep fails closed when any requested deep scan is partial or unavailable.

npm-safe check lodash --deep
npm-safe ci --lockfile --deep
npm-safe install axios --deep --dry-run

Proxy

On restricted networks the registry may only be reachable through a proxy. Proxy resolution order: --proxy flag > persisted proxy setting > HTTPS_PROXY / HTTP_PROXY / ALL_PROXY environment variables. The NO_PROXY variable (exact match, .suffix match, or *) bypasses the proxy.

# Persist a proxy (recommended)
npm-safe settings set proxy http://127.0.0.1:7897

# Or pass it per invocation
npm-safe --proxy http://127.0.0.1:7897 check react

Rules and plugins

Ten metadata rules and twelve opt-in content rules detect install scripts, obfuscation, typosquatting, secret exposure, unsafe archives, executable content, process/network combinations, and more. Rules can be managed at runtime; configuration is persisted in ~/.npm-safe/rules.json:

npm-safe rules list                          # Show every rule and its status
npm-safe rules disable install-script        # Disable a rule
npm-safe rules enable install-script         # Re-enable it
npm-safe rules severity typosquatting critical  # Override a rule's severity

Third-party rule plugins can be dropped into ~/.npm-safe/rules/ as ES module files (*.mjs / *.js). Each file may export rule, rules, or default holding one or more rules conforming to the ScanRule interface:

// ~/.npm-safe/rules/my-rule.mjs
export const rule = {
  id: "my-rule",
  name: "My rule",
  description: "Detects something bad",
  severity: "high",
  category: "informational",
  enabled: true,
  match(readme, packageJson) {
    return packageJson?.scripts?.postinstall?.includes("wget")
      ? [{ ruleId: "my-rule", ruleName: "My rule", severity: "high",
           message: "postinstall uses wget", category: "informational" }]
      : [];
  },
};

Plugin files are loaded at engine startup and bad files are skipped. The ScanRule interface and the full engine rule API (registerRule, unregisterRule, listRules, setRuleEnabled, setRuleSeverity) are exported from @npm-safe/core for programmatic use. See SCANNER_RULES.md for the built-in rule reference.

LLM scanning

LLM-based semantic scanning is optional and disabled by default. When no API key is configured, static analysis continues normally. Providers: OpenAI, Gemini, Anthropic. Configuration is persisted in ~/.npm-safe/llm.json and can also be supplied via environment variables (OPENAI_API_KEY, GEMINI_API_KEY, or ANTHROPIC_API_KEY).

npm-safe llm status                 # Show the current provider and status
npm-safe llm enable                 # Turn LLM scanning on
npm-safe llm set-provider openai    # Select provider
npm-safe llm set-key $OPENAI_API_KEY
npm-safe llm set-model gpt-4o-mini
npm-safe llm set-base-url <url>     # Custom API base URL (optional)
npm-safe llm test-connection        # Verify the provider works

CI/CD integration

npm-safe ci scans a project's direct dependencies and fails the build when any dependency reaches a configurable security level:

npm-safe ci --dir ./packages/core          # default fail level: dangerous
npm-safe ci --fail-level suspicious        # stricter gate
npm-safe ci --prod                         # skip devDependencies
npm-safe ci --lockfile                     # scan all lockfile deps (incl. transitive)
npm-safe ci --lockfile --deep              # inspect tarballs; fail if any deep scan is incomplete
npm-safe ci --json                         # machine-readable report
npm-safe ci --rate-limit 50                # registry requests per second

Exit codes: 0 pass, 1 usage/config error, 2 one or more dependencies reached the fail level (or the scan errored). A ready-to-use GitHub Actions workflow lives at .github/workflows/ci.yml; it runs the test suite, type checks, and a dependency security scan on every push/PR.

For another repository, copy the minimal workflow from examples/github-actions/npm-safe.yml.

Batch operations

check accepts any number of package names and reads lists from files, scanning concurrently (default 5) while still respecting the rate limiter:

npm-safe check lodash express axios       # batch check
npm-safe check --file deps.txt --concurrency 10
npm-safe check lodash express --json      # machine-readable batch report
npm-safe check detail 2                   # full report of the 2nd package of the last batch

Programmatic consumers can use NpmSafeEngine.checkPackages(names, options) with a concurrency cap and an onProgress callback. The most recent batch is saved to ~/.npm-safe/last-batch.json; check detail <n> re-renders one package's full report (findings, recommendations, snippets) from it without re-fetching.

Report export

Export security reports for any set of packages as JSON or CSV, to stdout or a file:

npm-safe report lodash express                    # JSON to stdout
npm-safe report --format csv lodash express       # CSV
npm-safe report --file deps.txt --format csv --output report.csv
npm-safe report --batch                           # export the last batch check

JSON output includes the full per-package results (BatchPackageResult[]); CSV rows are name,version,level,score,findingCount.

Telemetry and analytics

Local, opt-in usage telemetry (disabled by default, nothing is sent anywhere):

npm-safe telemetry status         # show whether enabled + aggregated stats
npm-safe telemetry enable         # start collecting (local only)
npm-safe telemetry disable        # stop collecting (keeps existing data)
npm-safe telemetry export         # dump the collected data as JSON
npm-safe telemetry reset          # clear all collected data

When enabled, check and ci runs are recorded to ~/.npm-safe/telemetry.json: per-event counters, total packages scanned, security-level distribution, error counts, and a rolling window of the last 200 events.

Shared check history

Every package checked via the CLI (check / ci), and every check run inside the desktop GUI, is written to the shared SQLite database (~/.npm-safe/npm-safe.db, check_history table, newest-first, capped at 1000). The desktop GUI's overview dashboard loads this history directly, so packages scanned on the command line appear in the app, and vice versa. Legacy ~/.npm-safe/history.json data is migrated into the database once on first launch. Programmatic access: engine.recordCheckHistory(result), engine.getCheckHistory(), engine.clearCheckHistory().

The desktop extension also honours the persisted proxy setting: on startup it reads the settings table and configures the engine, so a proxy configured in the GUI or via npm-safe settings set proxy ... applies to desktop scans too.

Command log

Every CLI invocation appends one JSONL line to ~/.npm-safe/commands.jsonl with { timestamp, command, argv, exitCode, durationMs }, written on process exit. API keys, proxy credentials, auth tokens, and generic setting values are replaced with [REDACTED] before they are persisted. The file is restricted to the current user (0600) where the platform supports it. The location can be redirected with the NPM_SAFE_COMMAND_LOG environment variable.

Install-time security gate (opt-in)

npm-safe install wraps npm install with an optional security gate: every target package is checked first, and any package scoring below the threshold (default 85) requires manual confirmation before the install proceeds. The gate is disabled by default and can be turned on via the CLI or the desktop GUI (Settings → 安装安全检查):

npm-safe gate status               # show enabled state + threshold
npm-safe gate enable               # turn the gate on (auto-installs shell wrappers)
npm-safe gate disable              # turn it off
npm-safe gate set-threshold 90     # raise the bar
npm-safe install axios             # gated install (prompts below threshold)
npm-safe install axios --yes       # auto-confirm
npm-safe install axios --dry-run   # check + prompt without installing

gate enable does everything in one step: it enables the check, installs PATH shims into ~/.npm-safe/bin (npm.cmd / pnpm.cmd / yarn.cmd; they work in every shell), and appends wrapper functions for npm, pnpm, and yarn to your shell config (PowerShell $PROFILE on Windows, ~/.zshrc/~/.bashrc otherwise). How to activate:

Your shellActivation
PowerShell / bash / zshJust restart the shell; the profile wrappers load automatically
Windows cmd (or any shell where the shim dir isn't first in PATH)Run once as administrator: npm-safe gate shell --machine; this prepends the shim directory to the system PATH, so every new terminal (incl. cmd) is intercepted. Reopen terminals afterwards.

On Windows, only the system PATH reliably precedes the Node.js installation directory; user-PATH edits are not enough when a tool puts the machine PATH first. npm-safe doctor verifies that where npm.cmd resolves to the shim first and prints the exact fix.

Pass --shell-file <path> to target a specific config file, --no-shell to skip. After activation, any pnpm add <pkg> or npm install <pkg> first runs npm-safe install ...; the gate checks the package and asks for confirmation below the threshold before the real package manager runs. Remove everything with:

npm-safe gate shell --remove

The gate shares the same settings table as the GUI, so the CLI switch and the GUI toggle stay in sync.


Security Model

npm-safe is an early-warning heuristic, not a safety certification. The default scan inspects registry metadata, the selected manifest, and README. Passing --deep additionally verifies and heuristically inspects the shipped tarball within strict resource limits, without extracting or executing it. A safe result means that no configured signal was detected in the selected inspection boundary; it does not prove runtime safety.

Use it alongside vulnerability databases, lockfiles, code review, and least-privilege build environments. See the full threat model, security policy, and product roadmap.


Architecture

The engine is composed of five layers. Each layer depends only on the layers below it. The index.ts facade composes every dependency and exposes the result as a single NpmSafeEngine class.

                           +-----------------------+
                           |      index.ts          |
                           |  NpmSafeEngine facade  |
                           |  29 public methods     |
                           +-----------+-----------+
                                       |
              +------------------------+------------------------+
              |                        |                        |
     +--------v--------+     +---------v---------+     +--------v--------+
     |   Registry      |     |    Scanner        |     |   Scheduler     |
     |  NpmRegistryClient|   |  StaticAnalyzer   |     | RefreshScheduler|
     |  Validator       |     |  10 rules         |     |  TokenBucket    |
     |  (HTTP fetch)    |     |  (pure analysis)  |     |  (rate-limit)   |
     +--------+---------+     +---------+---------+     +--------+--------+
              |                          |                        |
              |                          |                        |
              +--------------------------+------------------------+
                                         |
                                +--------v--------+
                                |     Store       |
                                | DatabaseManager |
                                |  CacheManager   |
                                |  SQLite (WAL)   |
                                +-----------------+

Layer responsibilities

LayerModule(s)Role
Registryregistry/client.ts, registry/validator.ts, registry/types.tsHTTP communication with the npm registry API. Fetches packuments, validates package names and versions, defines all registry-facing TypeScript types.
Scannerscanner/static-rules.ts, scanner/rule-config.ts, scanner/rule-loader.ts, scanner/types.tsPure static analysis of package metadata and README content. Ten built-in rules detect install scripts, obfuscation, typosquatting, secret exposure, homograph attacks, and more; plus runtime rule registration, per-rule config overrides, and plugin discovery.
Schedulerscheduler/refresh-scheduler.ts, scheduler/rate-limiter.tsManages periodic refresh cycles for watched packages. A token bucket (5 tokens/s, 10 burst) limits registry request frequency.
Storestore/database.ts, store/cache-manager.ts, store/schema.tsPersistent storage via better-sqlite3 with WAL mode. Handles migrations, TTL-based caching of metadata and scan reports, watchlist persistence, and key-value settings.
Facadeindex.tsThe NpmSafeEngine class composes all four layers. Exposes 29 public methods: checkPackage, searchPackages, watchlist CRUD, refresh operations, settings access, lifecycle, rule management, and LLM configuration (startAutoRefresh, stopAutoRefresh, close).

A sixth auxiliary layer, Translator (translator/types.ts, translator/provider.ts), provides a pluggable translation interface for converting findings and summaries into different languages. It is not wired into the core scan pipeline but is fully typed and importable.


Documentation

Detailed documentation is available under packages/core/:

  • SECURITY.md: private vulnerability reporting process and supported-version policy.
  • THREAT_MODEL.md: inspection boundary, trust assumptions, out-of-scope threats, and score interpretation.
  • ROADMAP.md: AST analysis, SARIF, policy, benchmark, and integration priorities.
  • CHANGELOG.md: user-facing changes by release.
  • ARCHITECTURE.md: layer map, module dependency graph, data flow diagrams (hot path and refresh path), database schema (ERD), migration system, error taxonomy, and annotated design decisions.
  • API.md: complete public API reference covering the NpmSafeEngine class (all 29 public methods), exported interfaces, and all type definitions (SecurityLevel, Severity, FindingCategory, CheckResult, ScanFinding, StaticScanReport, etc.).
  • SCANNER_RULES.md: reference for all metadata and deep package-content rules, including categories, severities, limits, and mitigations.
  • CONTRIBUTING.md: developer guide covering development setup, code conventions, testing, the publishing workflow, and the desktop GUI build.
  • README_zh.md: Chinese translation of the project README.

The desktop GUI lives under packages/desktop/ and is documented in the Desktop README.


Directory Structure

npm-safe/
  LICENSE                  # Apache-2.0
  README.md                # project README (English)
  README_zh.md             # project README (Chinese)
  CONTRIBUTING.md          # developer guide (setup, conventions, publishing)
  CHANGELOG.md             # user-facing release history
  SECURITY.md              # private reporting and security support policy
  ROADMAP.md               # product and scanner priorities
  CODE_OF_CONDUCT.md       # project participation standards
  docs/THREAT_MODEL.md     # inspection boundary and trust assumptions
  pnpm-workspace.yaml      # workspace = packages/*
  tsconfig.base.json       # shared TypeScript config (ESNext, strict)
  .github/
    workflows/
      ci.yml               # CI: typecheck + tests + dependency security scan
      publish.yml          # npm publish (SLSA provenance, tag-triggered)
      desktop-release.yml  # desktop ZIP assets on GitHub Releases
  packages/
    core/
      package.json         # @npm-safe/core v1.0.5, ESM, publishConfig (public, provenance)
      .npmignore           # publish exclude rules
      tsconfig.json        # extends ../../tsconfig.base.json
      API.md               # public API reference
      ARCHITECTURE.md      # layer map, data flows, DB schema
      SCANNER_RULES.md     # 10 static rule reference
      skill/
        npm-safe-scan/
          SKILL.md         # AI skill, installed only via an explicit `skill install`
      src/
        index.ts           # NpmSafeEngine facade, unified public API
        cli/               # command implementations, command log, i18n
        llm/               # LLM providers (OpenAI / Gemini / Anthropic)
        registry/          # registry client, validator, types
        scanner/           # StaticAnalyzer, rule config, plugin loader
        scheduler/         # rate limiter + refresh scheduler
        store/             # SQLite database, migrations, cache manager
        translator/        # pluggable translation interface
      test/                # module tests (see CONTRIBUTING.md)
    desktop/               # @npm-safe/desktop (Neutralinojs GUI)
      package.json         # desktop workspace package
      neutralino.config.json  # Neutralino app config (borderless, extensions)
      resources/           # index.html, styles.css, js/, icons/, extensions/core/main.mjs

Key Design Decisions

DecisionRationale
ESM-only ("type": "module")Aligns with the modern Node.js ecosystem. All imports use .js specifiers as required by native ESM.
Strict TypeScript, no anyEvery function and interface is fully typed. The project compiles with --strict and zero implicit any.
250-LOC ceiling per moduleKeeps each file focused and reviewable. The facade (index.ts) is the only module that modestly exceeds this limit due to its composition responsibilities.
SQLite via better-sqlite3Zero-configuration embedded database. WAL mode, busy_timeout=5000, synchronous=NORMAL, and foreign keys are enabled on open.
Pure static analysis (no network)The scanner inspects only metadata and README text already fetched by the registry client. No external API calls during analysis.
TokenBucket rate limiter (5 tokens/s, 10 burst)Prevents registry throttling. Tokens refill at 5 per second; burst allows up to 10 immediate requests.
Cache-first checkPackage with TTL stalenessReturns cached results immediately when the TTL has not expired. Stale cache triggers a background refresh. Default TTL is 1 hour.
String enums for SecurityLevel / SeverityUnlike numeric enums, string enums are safe to log, serialize, and use in switch statements without reverse-mapping surprises.
Score: 100 minus severity weightsCritical = 25, High = 15, Medium = 8, Low = 3. Starting from 100 ensures an unscored package scores 100 (safe).
Level thresholds>=80 Safe, >=50 Suspicious, >=20 Dangerous, else Unknown. These thresholds are shared between StaticAnalyzer and CacheManager for consistency.

Acknowledgements

Weifang Leimingyun Network Technology Co., Ltd. provided the AI automatic promotion tool Bizbot (http://bizbot.zvo.cn) for this project.

Questions and collaboration: 1031402408@qq.com.

License

Apache-2.0. See LICENSE.