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

@comity-dev/validate

v0.5.2

Published

Thin orchestrator over Comity shared validation tooling. Development tooling.

Readme

@comity-dev/validate

Purpose

Thin orchestrator over Comity shared validation tooling. Discovers a repository, invokes the specialized engines (schema, dependency-cruiser, ESLint, Semgrep, adapter-peers, declarations), and returns a normalized result.

This package is intentionally small. It does not implement source-code rules; the in-process declaration engine implements the rules in ADR-035. Its only responsibilities are:

  1. Discover repository configuration (comity.config.json).
  2. Discover packages.
  3. Invoke specialized engines.
  4. Collect and normalize results.
  5. Present a unified summary.

Scope

The engines wrap shared Development-owned tooling:

| Engine | Tool | Concern | | --------------- | --------------------------------------- | ---------------------------------------------------------- | | schema | @comity-dev/schemas (Ajv) | JSON Schema for package metadata and comity.config.json. | | depcruise | dependency-cruiser | Dependency graph layering. | | eslint | ESLint + @comity-dev/eslint-plugin | Source-code lint policy. | | semgrep | semgrep + @comity-dev/semgrep-rules | Structural source patterns. | | adapter-peers | in-process | Adapter peer-dependency contract. | | declarations | in-process + TypeScript | Published declaration dependency contract (ADR-035). | | packed-surface | in-process + pnpm pack + system tar | Packed tarball surface: rules ARCH-PACK-001…006 (ADR-035 stage 2). |

Engines report one of PASS / FAIL / NOT-RUN / TOOL-UNAVAILABLE / CONFIGURATION-ERROR / EXECUTION-ERROR / NOT-APPLICABLE. PASS is only reported when the engine actually executed.

Tool and configuration resolution

The tools the validator runs (dependency-cruiser, eslint) and the modules its generated ESLint configuration imports (@comity-dev/eslint-plugin, @comity-dev/eslint-plugin/recommended, @typescript-eslint/parser) are the validator's own declared dependencies. They are resolved from the validator's installed location with import.meta.resolve, and an executable is the script declared in the dependency's bin field, run with the current Node binary. The result is the same under npm (hoisted) and pnpm (isolated) layouts.

  • Consumers do not need to install these packages directly, and consumer-installed versions are not used: ESLint always lints with the plugin and parser versions this validator declares.
  • node_modules/.bin, the consumer repository's node_modules, and global installs are never consulted.
  • If a dependency cannot be resolved the engine reports TOOL-UNAVAILABLE with the reason; ESLint output that cannot be interpreted (including exit code 0 with malformed output) is EXECUTION-ERROR, never PASS, and the tool's stderr is kept in the finding.
  • Semgrep is an external Python tool and is still discovered through SEMGREP_BIN, PATH, and the standard system locations.

Dependency engine (depcruise)

The engine generates architecture rules with @comity-dev/dependency-rules, runs dependency-cruiser --output-type json from the repository root, and validates the result before trusting it.

  • Result contract. dependency-cruiser's JSON result is { modules, summary }. Violations are in summary.violations; each entry has from and to (module path strings) and rule: { name, severity }. Per-severity totals are summary.error|warn|info|ignore, and summary.ruleSetUsed.forbidden lists the rules applied. The same shape is declared in dependency-cruiser v9 through v17. Supported range: ^16.10.4; tests run against the lockfile-resolved version (16.10.4) with captured real output in src/engines/__tests__/__fixtures__/.
  • Exit code is not a verdict. The JSON reporter always exits 0, even when error violations exist. The verdict comes from the validated violation entries.
  • Type-only imports are included (the generated configuration enables tsPreCompilationDeps), so a forbidden import type fails exactly like a forbidden runtime import.
  • Severities. error violations fail validation. warn and info violations are reported as warnings and do not fail it (the same policy as the ESLint engine). Findings are counted from the entries, never from the summary counters as well.
  • Fail closed. Output that is empty, not JSON, not the schema above, internally inconsistent (counters that disagree with the entries), a non-zero exit that the result does not explain, a crash, a start-up failure, or a kill by signal is reported as EXECUTION-ERROR (rule DEP-CRASH), never PASS.
  • Rules were applied. The engine fails with EXECUTION-ERROR if dependency-cruiser did not apply the number of rules that were generated, or if no cruised module is governed by any generated rule. An individual rule that matches no module is not an error.
  • No layered packages. A repository in which no package declares a comity.layer reports NOT-APPLICABLE instead of PASS.

Ownership

Owned by comity-development. Consumed by Comity repositories via the comity-validate CLI.

Public API

import {
  runValidation,
  discoverRepository,
  formatSummary,
  formatViolations,
  ExitCode,
} from "@comity-dev/validate";

CLI

comity-validate --repo /path/to/repo
comity-validate --only=schema        # one engine only
comity-validate --only=declarations

--only <category> runs a single engine. Policies owned by another engine are not evaluated: --only semgrep does not check ESLint-owned policy, including the required @internal marker rule (@comity-dev/require-internal-marker). Use the default run (no --only) for full policy coverage.

packed-surface (ADR-035 stage 2)

--only=packed-surface packs every publishable package with pnpm pack, reads the resulting tarball (file list, contents and packed package.json) with the system tar, and applies ARCH-PACK-001…006. It never reads the workspace dist, so it observes the effect of the files field, exports and workspace: rewriting — which stage 1 cannot see.

It is deliberately not part of the default run: it packs every package (slower) and it runs in the producer repository after pnpm build and before publication. Both release workflows run it after Build and before the Changesets Release step.

Enforcement is active (2026-11-05). The release-workflow step blocks publication only when the repository variable COMITY_PACKED_SURFACE_ENFORCEMENT is true; that variable is set in both comityjs/development and comityjs/framework, so a stage-2 finding now fails the release job before publication. It was activated only after WP-A1 (Community workspace:* migration), WP-A4 (Development @comity-dev/* migration) and WP-B formal ratification were complete, because pnpm pack rewrites workspace:* to an exact pin and ARCH-PACK-005 reports those pins; both repositories now report 0 findings. Local runs are unaffected: the category still runs only with --only=packed-surface and the default validate categories are unchanged.

Exit codes:

  • 0 — validation passed
  • 1 — validation failed (violations found)
  • 2 — configuration / discovery error (may co-occur with findings)
  • 3 — required tool not installed

Environment

The Semgrep engine shells out to a local Semgrep installation:

| Variable | Purpose | | --------------------------- | ------------------------------------------------------------------------------------------------ | | SEMGREP_BIN | Path to the semgrep executable. Used as-is when it exists; otherwise resolved from PATH. | | SEMGREP_PYTHON | Path to the Python interpreter that ships the semgrep module. The scan is executed with it. | | COMITY_SEMGREP_TIMEOUT_MS | Overall scan timeout in milliseconds. Defaults to 300000 (five minutes). Must be an integer between 1 and 2147483647; invalid or oversized values are reported as CONFIGURATION-ERROR. |

Rules:

  • An explicit SEMGREP_PYTHON always wins and is never silently overridden.
  • A set-but-missing SEMGREP_PYTHON is invalid configuration: the engine reports TOOL-UNAVAILABLE naming the variable instead of falling back to another interpreter.
  • When SEMGREP_PYTHON is unset, the previous resolution applies (/usr/bin/python3, /usr/local/bin/python3, /opt/homebrew/bin/python3, then python3 on PATH).
  • The scan PATH is prefixed with the directories of the resolved SEMGREP_BIN and interpreter so Semgrep finds its sibling pysemgrep.
  • Every scan has an overall liveness bound (COMITY_SEMGREP_TIMEOUT_MS). A timeout is reported as EXECUTION-ERROR, never as PASS. On POSIX the scanner's process group is terminated so Semgrep's Python and semgrep-core descendants do not remain running; on Windows only the immediate child can be signalled, so descendant termination is best-effort.
  • --verbose emits a stderr heartbeat every ten seconds while a scan is running; the final summary remains on stdout.
  • A file Semgrep could not fully parse (PartialParsing) is reported as EXECUTION-ERROR with a SEM-PARTIAL-PARSE finding naming the file, never as PASS: a partially parsed file may have been skipped by AST-based rules, so the scan is incomplete rather than clean.
SEMGREP_BIN=~/.local/bin/semgrep SEMGREP_PYTHON=/opt/homebrew/bin/python3 \
  comity-validate --repo /path/to/repo

Negative fixtures

The src/__fixtures__/third-repo/ directory contains a deliberately invalid repository used by the package's own integration tests. It is not scanned by the canonical validate run (the engine excludes __fixtures__/**); it is asserted against failure by src/__tests__/integration.test.ts.

Development

pnpm build
pnpm test

Relationship to Comity Standards

  • layering-policy.md
  • architecture-validation.md
  • ADR-008, ADR-026
  • adapters.md §13 (adapter-peer engine)