Know the health of your dependency tree before it kills your build.
npm audit only catches known vulnerabilities. But the package that takes down your build — or your production — usually has zero CVEs. It's just quietly rotting:
| Risk | Why it matters |
|---|---|
| 🟤 Abandoned | No updates in 2+ years. Nobody's patching the next zero-day. |
| 👤 Bus factor of 1 | One phished account and malicious code ships to millions. |
| 📦 Archived repo | Abandonment is public — but the package still publishes. |
| ⚖️ No license / viral license | A legal time bomb for commercial projects. |
| 📉 Major version drift | 2+ majors behind. Breaking changes pile up silently. |
salubrious catches all of these — and more.
# Global (recommended)
npm install -g salubrious
# Or per-project
npm install -D salubrious# Analyze current project (auto-detects lockfile)
salubrious
# CI-friendly: fail on any warning
salubrious --fail-on=warning
# Machine-readable output
salubrious --json
# GitHub Actions annotations
salubrious --format=github-actionsEvery package starts at 100 and loses points for each risk signal detected.
| Signal | Penalty | Description |
|---|---|---|
deprecated |
−50 | npm deprecated flag set |
risky-license |
−40 | GPL/AGPL/SSPL in production deps |
no-license |
−30 | Missing or unknown SPDX license |
abandoned |
−25 | No publish in 24+ months |
archived |
−20 | GitHub repo archived |
typosquat-risk |
−20 | Name similar to a top-1000 package |
bus-factor |
−15 | Only 1 npm maintainer |
new-maintainer |
−15 | New maintainer in the last 6 months |
major-drift |
−10 | 2+ major versions behind latest |
Grading: ≥80 🟢 healthy · 60–79 🟡 warning · 40–59 🟠 risky · <40 🔴 critical
Create salubrious.config.json in your project root:
{
"failThreshold": 60,
"failOn": "warning",
"includeDev": false,
"ignore": ["@types/*", "eslint-*"],
"signals": {
"abandoned": { "thresholdMonths": 24 },
"bus-factor": { "minMaintainers": 2 }
}
}import { analyze } from 'salubrious';
const result = await analyze({ cwd: './my-app' });
console.log(`Health score: ${result.score}/100 (${result.grade})`);
result.packages.forEach(p => {
if (p.grade !== 'healthy') {
console.log(`${p.name}@${p.version}: ${p.score} — ${p.signals.map(s => s.message).join('; ')}`);
}
});- name: Check dependency health
uses: MHAlikhani/salubrious@v0.1.6
with:
fail-on: warning
format: github-actionsdependency_health:
script: npx salubrious --fail-on=warning --json > salubrious-report.json
artifacts:
reports:
sast: salubrious-report.json- Zero runtime dependencies — Node.js built-ins only
- TypeScript-first — strict mode, full type exports
- Dual CJS/ESM — modern exports map
- Fast — parallel fetching, XDG-compliant caching, <2s on 500-dep trees
- Extensible — plugin API coming in v0.2
All PRs welcome! See CONTRIBUTING.md to get started.
MIT License © 2026 Mohammad Hossein Alikhani
See LICENSE for details.