⏳ This skill is pending AI review.
Scores will appear once the review pipeline completes.
new-dependency-evaluation
Help decide what to add as a NEW npm dependency — comparing 2-5 named candidates for the same job, evaluating one named candidate against its real peers, or shortlisting candidates from a described need, before anything is installed. Use for "which should we use for X," "axios vs got vs node-fetch," "is X a good pick for Y," "what should we use to do Z," "should we add X or is there something better." Not for auditing packages already in the project (see dependency-audit), not for a deep single-package compromise/trust investigation (see package-trust-check), and not for a plain factual question with no choice being made ("what does X do").
Choose how to use this skill
You do not need every option. Choose the path your AI client supports. The stable page stays the same; versioned files are immutable.
1. Native installer
This listing has no registered native installer command. Use the complete package or source fallback below, depending on what your client supports.
Do not guess an installer command or replace an existing version without reviewing the diff.
2. Complete package recommended
Download the ZIP when available. It includes SKILL.md plus the references, security notes and version metadata.
No complete ProSkills package is published for this listing yet.3. Prompt-only
Copy the prompt above when the agent can read the stable page or when you want to adopt the workflow without installing a skill.
Need only the instruction file?
Download SKILL.md only if your client requires a single file. The complete ZIP is safer for a full installation because it preserves the references and release context.
No path installs or executes anything by itself. Your agent still needs access to the project files. Before updating, compare the installed version and review the diff.
// RATINGS
Not yet listed on ClawHub or SkillsMP
// README
NPMScan plugin for Claude Code
A Claude Code plugin that gives Claude read-only npm package and vulnerability lookups, backed by npmscan.com's free, unauthenticated MCP server.
NPMScan is also officially listed for both ChatGPT and Claude on npmscan.com's MCP page, so users can verify that this plugin points at the same public service.
Official listings
- Claude (Anthropic's official Claude directory): claude.ai/customize/skills/…/npmscan
- ChatGPT (install npmscan as an app for one-click setup): chatgpt.com/plugins/…/npmscan
- mcpHQ: mcphq.org
- TensorBlock MCP Index: tensorblock.co/mcp
- Awesome Gemini CLI: Piebald-AI/awesome-gemini-cli
- Awesome Gemini CLI Extensions: Piebald-AI/awesome-gemini-cli-extensions
- Awesome Codex Plugins: hashgraph-online/awesome-codex-plugins
- Setup docs for other clients: npmscan.com/mcp
Pending:
- Grok Build (xAI's official plugin marketplace): submitted in xai-org/plugin-marketplace#1506, awaiting xAI review. See Using it with Grok Build.
- GitHub Copilot (Awesome Copilot marketplace): submitted in github/awesome-copilot#5142.
- Gemini CLI (extension gallery): indexed automatically from this repo. See Using it with Gemini CLI.
What it adds
-
MCP server (
npmscan,https://npmscan.com/api/mcp) with twenty-three tools — see Tools below. Every tool result includes annpmscanUrllinking back to the full write-up on npmscan.com. No API key or auth required — same public data as the website. The server is stateless and rate-limited to 30 requests/minute per IP. Every vulnerability finding carriesisMalware, so a confirmed-malicious package is reported as malware to remove, never as an ordinary bug. -
/npmscan:dependency-auditskill — chainsbatch_query_vulnerabilities→get_package/get_package_version→analyze_transitive_dependencies→ the maintainer/provenance/license/remediation/alternative tools into one dependency-audit report, instead of leaving that tool sequencing to Claude each time. Also handles PR-style before/after diffs viadiff_dependencies, rawnpm audit --jsonoutput viaenrich_npm_audit, and a bare GitHub repo URL viaaudit_github_repository. Triggers automatically when you paste apackage.json/lockfile/SBOM, give a GitHub repo URL, or ask to check/audit your dependencies, or invoke it directly. Seeskills/dependency-audit/SKILL.md. -
/npmscan:package-trust-checkskill — a deep, single-package investigation for "is X safe / was X compromised" questions: a malware check (including versions npm has since removed for being malicious), maintainer add/remove history (account-takeover patterns), publish-provenance cross-checks, and install-script scanning, in one report. Triggers automatically on a trust question about one named package; not for auditing a whole dependency list (that'sdependency-audit). Seeskills/package-trust-check/SKILL.md. -
/npmscan:new-dependency-evaluationskill — for a forward-looking choice about what to add, not what's already installed: comparing 2-5 named candidates ("axios vs got vs node-fetch"), evaluating one candidate against its real peers, or shortlisting candidates from a described need. Orchestratescompare_packages/suggest_alternative/search_packagesinto a structured side-by-side with a deterministic pick. Seeskills/new-dependency-evaluation/SKILL.md. -
/npmscan:incident-responseskill — turns an existing finding, or just a vague symptom description ("npm install did something weird"), into concreteget_remediation_playbooksteps: real incident references, severity, and prevention tips, not improvised advice. Seeskills/incident-response/SKILL.md. -
/npmscan:ci-pr-gateskill — turns a dependency change (a before/after snapshot, or one or more named "bump X from A to B" upgrades) into one deterministic PASS/WARN/FAIL verdict formatted for a CI check or PR-comment bot, applying a fixed policy on top ofdiff_dependencies/simulate_dependency_upgrade— not a conversational report (that'sdependency-audit's job). Seeskills/ci-pr-gate/SKILL.md.
Tools
NPMScan provides twenty-three tools:
| Tool | Description |
|---|---|
search_packages | Search the npm registry by name or keywords. Each result includes weekly/monthly download counts, dependent-package counts, and rank among npmscan's own top-100k-by-downloads snapshot, so you can tell an established package from an abandoned or squatted one that merely matches the query text — flags possibleTyposquatOf when a low-popularity result's name is one typo away from a top-5,000 package. |
get_package | Latest version, install scripts (preinstall/install/postinstall/prepare), maintainers, license, recent version history, weekly downloads, GitHub stars, TypeScript support, days since last publish, ecosystem-wide download rank, a 3-month download trend, and an isLatestVersionVulnerable/highestSeverity verdict (with fixed versions and isMalware per finding) — plus a rule-based (not model-generated) maintenance/popularity summary and typosquat flag computed from those numbers. |
get_package_version | Metadata for one exact version plus an OSV.dev check scoped to that version — isVulnerable/highestSeverity as a direct safe/not-safe answer, with each finding's severity, summary, fixed version and isMalware. For checking a version pinned in a lockfile. A version npm has removed but OSV still has advisories for (usually one pulled for being malicious) comes back with versionExists: false and those findings, not a bare "not found". |
get_maintainer_profile | Packages an npm username currently maintains via npm's own maintainer:<username> search index, plus precomputed download/dependent totals across all of them. Lists the most-downloaded limit packages (default 50, max 250); totals still cover every package found. A plain info lookup, not a security check — pair it with check_maintainer_blast_radius for the actual compromised-account signal. |
query_vulnerabilities | OSV.dev lookup for known vulnerabilities affecting a package, optionally scoped to a version, with isVulnerable/highestSeverity as a direct verdict and each finding's severity, summary, fixed version and isMalware. For npm it also cross-checks the name/version against the registry: a name or version that isn't on npm still returns its OSV data, with packageExists: false and an existenceCheckNote — so a typo doesn't read as "clean", and a version removed for malware still shows its findings. Accepts packageName as an alias for name, and other ecosystems via ecosystem (e.g. "PyPI"). |
batch_query_vulnerabilities | OSV.dev lookup across a whole dependency inventory at once — pass a flat packages list, or paste raw package.json/lockfile/CycloneDX JSON/SPDX JSON content via content and it parses that for you. Chunks larg |
// HOW IT'S BUILT
// FILES
3 files shipped with this skill. Inline text is the catalog copy. The upstream link is the source repository.
skills/new-dependency-evaluation/SKILL.md15 KB3bc53f6cb9a7upstream ↗
--- name: new-dependency-evaluation description: Help decide what to add as a NEW npm dependency — comparing 2-5 named candidates for the same job, evaluating one named candidate against its real peers, or shortlisting candidates from a described need, before anything is installed. Use for "which should we use for X," "axios vs got vs node-fetch," "is X a good pick for Y," "what should we use to do Z," "should we add X or is there something better." Not for auditing packages already in the project (see dependency-audit), not for a deep single-package compromise/trust investigation (see package-trust-check), and not for a plain factual question with no choice being made ("what does X do"). --- # NPMScan new dependency evaluation Use this skill when the user is making a **forward-looking choice** about what to add to a project — not investigating something already installed. It orchestrates two tools that already do the hard work individually: `suggest_alternative` (turns one candidate name into a real shortlist of peers) and `compare_packages` (fans out enrichment across 2-5 named candidates and returns a structured side-by-side with a deterministic pick). This skill's only job is routing to the right combination of the two based on how many candidates the user actually named, then presenting the result. If the user instead asks whether a package **already in their project** is safe to keep, use `package-trust-check` (single package) or `dependency-audit` (a pasted inventory) — those investigate what's already there; this skill evaluates what to add next. If the question has no choice or decision angle at all ("what does X do," "what's the latest version of X"), just answer directly with `get_package` — don't invoke this skill's tool chain for that. ## Connecting the npmscan tools This skill calls the npmscan MCP server's tools (listed under "Tools used" below). They only read public package data: no API key or account, nothing is installed or changed on the user's machine, and the only server contacted is `https://npmscan.com/api/mcp`. - **Claude Code, Codex, Gemini CLI, Kimi, Grok:** the npmscan plugin connects the server for you. - **OpenClaw:** `openclaw mcp add npmscan --url https://npmscan.com/api/mcp --transport streamable-http`, then `openclaw mcp doctor npmscan --probe` to check it. - **Any other MCP client:** add a remote (streamable HTTP) server with that URL. Some clients prefix tool names with the server name (for example `npmscan__get_package`). If the tools aren't available at all, tell the user how to connect them for their client instead of answering from memory. ## Determining what to compare Count how many named candidates the user actually gave, then route: 1. **2-5 named candidates for the same job** (e.g. "axios vs got vs node-fetch," "should we use dayjs or date-fns") — go straight to `compare_packages({ packages })`. This is the common case and needs no extra tool call first. 2. **Exactly 1 named candidate** ("should we add uuid," "is left-pad a good choice," "can we use X for Y") — a single package has nothing to be compared against yet. Call `get_package({ name })` for the named candidate's own `description` (`suggest_alternative`'s `source` object doesn't include one), then `suggest_alternative({ name, reason: "general", limit: 4 })` to generate real peers (never invent plausible-sounding package names yourself). Screen the suggestions against that description per [Screening candidates before comparing](#screening-candidates-before-comparing-routing-cases-2-3) below, then call `compare_packages` with `[name, ...screened suggestions, up to 4]` so the original candidate is scored against real competition instead of judged in isolation. If `suggestions` comes back with fewer than 1 usable peer after screening (e.g. a built-in replacement fully covers the case, like `left-pad` → `String.prototype.padStart()`), skip `compare_packages` — there's nothing left to compare — and report the `nonPackageAlternatives` plus the `get_package` baseline on the named candidate instead. 3. **0 named candidates, just a described need** ("what should we use to parse dates," "we need something for HTTP retries") — call `search_packages({ query })` using the user's own description as the query. Build a 2-5 name shortlist from the results, preferring the highest `popularityTier`/`maintenanceTier` matches, skipping any result carrying `possibleTyposquatOf`, and screening each result's `description` against the user's *stated need* (their own words are the comparison anchor here — no extra fetch needed) the same way as case 2 — then run `compare_packages` on that shortlist. If nothing in the search results looks like a real contender (all very-low popularity/stale, or nothing actually matches the described need), say so rather than forcing a comparison, and ask the user for a starting name or two. 4. **More than 5 named candidates** — `compare_packages` caps at 5. Don't silently drop candidates without saying so: run it on the first 5 and name which were left out, or ask the user to narrow the list if the ones dropped seem like they'd matter to the decision. ### Screening candidates before comparing (routing cases 2-3) `suggest_alternative`'s `categoryOverlap` and `search_packages`'s result ordering are both keyword/token-overlap signals, not semantic relevance — and a single shared generic word (e.g. both packages' descriptions mention "guid") combined with high popularity can rank an unrelated package above genuinely relevant ones. This was confirmed directly: comparing candidates for `uuid` (an RFC9562 UUID *generator*, `description: "RFC9562 UUIDs"`) surfaced `win-guid` (`description: "Windows legacy GUID parser"` — an unrelated Windows binary-format tool) as the top suggestion, ranked above the real UUID library `@paralleldrive/cuid2`, purely because `win-guid` happens to have very high download counts and shares the single word "guid." Reading the two descriptions side by side makes the mismatch obvious immediately ("generates RFC-standard UUIDs" vs. "parses legacy Windows binary GUID structures") in a way `categoryOverlap`'s token count alone does not catch. So for every candidate before it enters `compare_packages`: - Actually read and compare full description text, not just token overlap — the source's own `description` (from `get_package` in case 2, or the user's stated need in case 3) against the candidate's `description`. Ask in plain terms: does this candidate do the same job, or does it just share vocabulary with something that does? Drop candidates that fail this even if their `categoryOverlap` list looks populated — shared words are a hint to go check, not a verdict on their own. - Treat a `categoryOverlap` of exactly one generic word (`"guid"`, `"data"`, `"util"`, etc.) as weak supporting evidence at best; two or more overlapping tokens, or overlap on a specific/technical term, is stronger — but the description comparison above is the actual decision, not the token count. - Don't let a high `weeklyDownloads`/`popularityTier` on its own excuse a poor description match — a package can be extremely popular as a transitive dependency of something unrelated to the job at hand. ## Steps 1. Route per the table above and make the tool call(s). 2. Read `differentiators` before `recommendation` — it names which candidate(s) stand out on downloads, GitHub stars, TypeScript support, known vulnerabilities, deprecation, typosquat flag, install-script risk, and install-size footprint. This is what makes the comparison legible; don't just report the final pick with no supporting detail. 3. Report `recommendation.pick`, `runnerUp`, and `rationale` verbatim — don't substitute your own judgment for the deterministic score unless a `candidates[]` entry shows something the score can't see (e.g. the user already said they need TypeScript-first and two candidates are close). Always state `confidence` too — a `"low"` confidence pick between two close candidates is a materially different answer than a `"high"` confidence one. 4. Surface every `found: false` candidate with its `resolutionError` (typo? unpublished? malformed name?) rather than silently dropping it from the comparison you present. 5. Note that `installScriptRisk` here is the **lifecycle-scripts-only** signal (`scanScope: "lifecycle-scripts-only"`) — it scans the command strings, not the tarball. If the recommended pick has a nonzero `installScriptRisk.totalScore` and the user is about to actually install it, mention that `analyze_install_script` (via `package-trust-check`) gives the deeper, tarball-aware scan before they commit — don't run it automatically as part of this skill, just point at it. A candidate whose only lifecycle script is `prepare` (uuid's `lefthook install`) scores 0: npm never runs a dependency's `prepare` on install, so it is not a risk to weigh against it. 6. If the user's decision also turns on license policy (they mention a license constraint, or ask "which of these is safe to use license-wise"), follow up with `check_license_compliance` on the shortlist — it's not part of the default flow, only pull it in when license is actually in play. 7. Sanity-check `githubStars` against `weeklyDownloads` per candidate: `githubStars` is attributed to whatever repository the candidate's own `package.json` declares, unverified — a tiny, low-download package showing a huge star count (e.g. thousands of stars on a package with under a thousand weekly downloads) can mean its declared `repository` field points at a different, unrelated project's repo rather than its own (confirmed directly: `@aigne/uuid`, ~850 weekly downloads, declares `repository: github.com/uuidjs/uuid` — the real `uuid` package's repo, not its own — and so inherits that repo's star count). Flag a large downloads/stars mismatch like this as worth independent verification before adopting the package, rather than reporting the star count at face value as a credibility signal; this skill's tools don't run the deeper source-attestation check that would confirm or rule this out (`check_package_provenance`, via `package-trust-check`). 8. Treat `downloadTrend.changePercent` with caution when `weeklyDownloads` is low (roughly under a few thousand) — a small absolute change produces a large, noisy percentage (e.g. a candidate with 850 weekly downloads showing `"growing"` at 800%+ off a tiny prior base is statistical noise, not real momentum). Lead with the absolute download figure, not the percentage, for any low-volume candidate. 9. Note that `installSize.transitive.transitiveUnpackedSize` (a rollup across the candidate's resolved dependency tree, up to depth 2 / 60 nodes) is often the more useful figure than the candidate's own `unpackedSize` — a small package can still drag in a large tree. ## Output requirements - Always include each candidate's `npmscanUrl` so the user can read the full write-up. - Present the comparison as a table (or clearly separated per-candidate summary) with at minimum: downloads/trend, popularity/maintenance tier, deprecated status, latest-version vulnerability status, TypeScript support, GitHub stars, and install-script risk tier — then the pick and rationale below it, not interleaved. - When `suggest_alternative` was used to generate the peer set (routing case 2), say so explicitly ("compared against N real peers in the same category, not just this one package in isolation") so the user understands the comparison isn't limited to what they originally named. - State plainly that this is a point-in-time snapshot (downloads, vulnerabilities, and maintenance activity all change) — not a permanent verdict, especially if the user's decision is time-sensitive. ## Do not - Do not invent candidate package names yourself when the user gave 0 or 1 — `search_packages`/`suggest_alternative` exist specifically so the shortlist is real, current registry data instead of names recalled from training knowledge that may be renamed, abandoned, or gone since. - Do not call `compare_packages` with fewer than 2 or more than 5 packages — dedupe first (case-insensitive; the tool itself rejects exact duplicates with a 400), and route through cases 2-4 above instead of forcing a single name through it. - Do not treat a deprecated or typosquat-flagged candidate as excluded from the comparison — `compare_packages` still returns them (with `deprecated`/ `possibleTyposquatOf` set) so the user can see exactly why they lost; only `recommendation.pick` is guaranteed to skip them, not the `candidates` list itself. - Do not silently narrow a >5-candidate list without telling the user which names were dropped and why. - Do not use this skill to re-investigate a package the user already has installed and is worried about — that's `package-trust-check` or `dependency-audit`; this skill's tools are tuned for choosing among healthy-looking options, not for compromise/takeover forensics. - Do not present `recommendation.pick` as a security clearance — it's a weighted popularity/maintenance/vulnerability/typosquat/install-script score, not a guarantee the package is free of issues the lighter scan can't see. - Do not pass every `suggest_alternative`/`search_packages` result straight into `compare_packages` on the strength of `categoryOverlap` alone — a single generic shared token plus high popularity can rank an unrelated package first (verified: `win-guid`, a Windows GUID *parser*, outranked a real UUID library when comparing alternatives to `uuid`). Read each candidate's `description` and drop ones that aren't actually the same tool for the job before comparing them. - Do not report a candidate's `githubStars` as a plain credibility signal without checking it against `weeklyDownloads` first — a low-download package with implausibly high stars likely has a `repository` field pointing at a different project's repo, not evidence of its own popularity. - Do not attempt to install, upgrade, or publish packages yourself; this skill only reads data through NPMScan's read-only MCP tools. ## Tools used `compare_packages`, `suggest_alternative`, `search_packages`, `get_package` (for the source description in routing case 2), and optionally `check_license_compliance` — all provided by the `npmscan` MCP server bundled with this plugin (`.mcp.json`). See [references/test-prompts.md](references/test-prompts.md) for prompts to manually verify this skill after installing or editing it.skills/new-dependency-evaluation/references/test-prompts.md10 KB9727fc2f4352upstream ↗
# Test prompts for `new-dependency-evaluation` Run these manually with the plugin loaded (`claude --plugin-dir ./npmscan-mcp-plugin`) before publishing a change to this skill. Each case names the exact tool calls and fields the response should surface — not just "did a tool get called," but "did the routing logic pick the right case and did the real data survive into the answer." 1. **Three named candidates for the same job (routing case 1)** — ask: > "Should we use axios, got, or node-fetch for our new HTTP client?" Expect `compare_packages({ packages: ["axios", "got", "node-fetch"] })` directly, no `suggest_alternative`/`search_packages` call first. All three resolve (`found: true`), and `recommendation.pick` is non-null. Expect the response to lead with `differentiators` (downloads, GitHub stars, TS support) before stating the pick and its `rationale`/ `confidence`. 2. **A deprecated candidate is named alongside healthy ones** — ask: > "We're picking between axios, request, and got — which one?" `compare_packages({ packages: ["axios", "request", "got"] })` returns `request` with `deprecated` set (it really is deprecated) and `differentiators.deprecated` including `"request"`. `recommendation.pick` must NOT be `"request"`. Expect the response to still list `request` in the comparison table (not silently drop it) while clearly stating why it lost. 3. **A typosquat stub named alongside its real target** — ask: > "Comparing lodash, lodahs, and underscore for utility functions — any > concerns?" `compare_packages({ packages: ["lodash", "lodahs", "underscore"] })` returns `lodahs` with `possibleTyposquatOf: { name: "lodash", ... }`. `recommendation.pick` must NOT be `"lodahs"`. Expect the response to flag the typosquat explicitly and prominently — not bury it in the table — as a real supply-chain risk to verify, matching the tool's own hedged framing. 4. **Exactly one named candidate (routing case 2)** — ask: > "Should we add uuid to the project, or is there something better?" Expect `suggest_alternative({ name: "uuid", reason: "general", limit: 4 })` first — its `suggestions` exclude `"uuid"` itself and exclude any deprecated package — then `compare_packages` with `uuid` plus up to 4 of those suggestion names (5 total, at the tool's max). Expect the response to say explicitly that `uuid` was compared against real peers in its category, not evaluated alone, before giving the pick. 4b. **Screening catches a real false-positive match (routing case 2)** — same prompt as case 4. `suggest_alternative({ name: "uuid", reason: "general", limit: 4 })` returns `win-guid` in its `suggestions` with `description: "Windows legacy GUID parser"` and `categoryOverlap: ["guid"]` (a single generic token) — a real result, confirmed live: it is not a UUID-generation library, it's an unrelated Windows binary- format parser that happens to have very high weekly downloads. Expect the response to exclude `win-guid` from the `compare_packages` call (or if it slipped through, to flag it explicitly as not actually comparable rather than silently including it in the pick) — not treat its high popularity as making it a legitimate contender for a UUID library comparison. 5. **One named candidate whose only real alternative is a language built-in (routing case 2, no-compare fallback)** — ask: > "Do we need the left-pad package, or is there a better option?" `suggest_alternative({ name: "left-pad", reason: "general", limit: 4 })` returns `nonPackageAlternatives` including `"String.prototype.padStart()"` and an empty (or near-empty) `suggestions` array. Expect the response to skip `compare_packages` (nothing left to compare against) and instead recommend the built-in directly, naming it exactly — not a vague "there might be a native way to do this." 6. **A described need with zero named candidates (routing case 3)** — ask: > "What should we use to format dates? We don't have a preference yet." Expect `search_packages({ query: "date formatting" })` (or an equivalent close paraphrase of the described need) first, a 2-5 name shortlist built from results that excludes anything with `possibleTyposquatOf` set or very-low popularity, then `compare_packages` on that shortlist. Expect the response to name which candidates were shortlisted and why before giving the comparison. 7. **Two comparably healthy candidates — a real "too close to call" result** — ask: > "dayjs or date-fns for our new date-handling code?" `compare_packages({ packages: ["dayjs", "date-fns"] })` returns both `found: true`, a non-null `recommendation.pick` among the two, and a valid `confidence`. Expect the response to report `confidence` plainly — if it comes back `"low"` or `"medium"`, say the two are close rather than overstating the pick as a clear winner. 8. **A legitimate low-traffic package should not be misflagged** — ask: > "Comparing is-number against lodash for a small numeric check — worth > adding a whole extra dependency?" `compare_packages({ packages: ["is-number", "lodash"] })` returns `is-number` with `found: true`, `deprecated: null`, and `possibleTyposquatOf: null` despite its much lower download count. Expect the response to not treat low popularity alone as a red flag — only `deprecated`/`possibleTyposquatOf`/vulnerability findings are. 9. **Non-triggering — a plain factual question, no decision being made** — ask: > "What does the axios package do?" Expect this skill NOT to activate — at most one `get_package` call, no `compare_packages`/`suggest_alternative`/`search_packages` calls. 10. **Non-triggering — investigating something already installed** — ask: > "We already have `event-stream` in our lockfile — is it safe?" Expect `package-trust-check` to activate instead of this skill (a single already-installed package's trust question), not `compare_packages`/`suggest_alternative`. 11. **More than 5 named candidates (routing case 4)** — ask: > "We're choosing an HTTP client — considering axios, got, node-fetch, > undici, superagent, and ky. Thoughts?" `compare_packages` accepts at most 5 names. Expect the response to either run it on the first 5 and explicitly name `ky` (or whichever was dropped) as excluded, or ask the user to narrow the list to 5 — not a silent truncation with no mention of what was left out. 12. **License-constrained comparison excludes a copyleft candidate even if competitive (step 6)** — ask: > "Legal says nothing GPL — is graphviz an option compared to lodash > for our use case?" Expect `check_license_compliance({ packages: [{ name: "graphviz" }, { name: "lodash" }] })` to run alongside/after the comparison, returning `graphviz` as `rawLicense: "GPL-3.0"`, `category: "copyleft"`, `isCompliant: false`, and `lodash` compliant. Expect the response to explicitly rule graphviz out on license grounds, not just report scores side by side and leave the license violation buried in a table cell. 13. **A non-SPDX license stays "needs review," not silently pass or fail (step 6)** — ask: > "Is nocodb's license going to be a problem if we only allow > MIT-licensed dependencies?" Expect `check_license_compliance({ packages: [{ name: "nocodb" }], policy: { allow: ["MIT"] } })` to return `rawLicense: "Sustainable Use License"`, `category: "unknown"`, `needsReview: true`, `isCompliant: false`. Expect the response to distinguish "flagged because it's unproven under your allow-list" from "flagged because it's confirmed copyleft" — nocodb's category is genuinely `unknown`, not a known-bad one. 14. **`compare_packages` rejects a duplicate name outright** — ask: > "Compare axios against Axios for us" (the same package, different casing — simulating a user accidentally naming the same package twice). Expect `compare_packages` to either be called with the names deduped first, or, if called with the duplicate, to come back as `tool_error` with a detail mentioning "duplicate" — not a comparison of a package against itself presented as a real result. 15. **A genuinely nonexistent candidate name (distinct from the typosquat- stub case in scenario 3)** — ask: > "Compare axios, got, and reqeust-lib-xyz for our HTTP client" (a name that's simply unpublished, not a typo of a real popular package). Expect `compare_packages` to still return all 3 entries, the unresolved one flagged `found: false` with a `resolutionError`, and `recommendation.pick` landing on `axios` or `got`. Expect the response to describe this candidate as "not found / doesn't appear to be a real package," not conflate it with scenario 3's "impersonating a real package" typosquat framing. 16. **A malformed/garbled candidate name doesn't abort the whole call** — ask: > "Compare axios against `%` for our HTTP client" (simulating a corrupted copy-paste). Expect `compare_packages({ packages: ["axios", "%"] })` to return a normal response where `axios` resolves fully and the `%` candidate comes back `found: false` with a `resolutionError` mentioning percent-encoding — not a total failure of the tool call. 17. **A `prepare`-only candidate is not an install-script risk** — ask: > "nanoid vs uuid vs @paralleldrive/cuid2 for generating ids?" uuid (`prepare: lefthook install`) and cuid2 (`prepare: husky`) used to get an install-script penalty that decided the pick. Verified live: all three now report `installScriptRisk.riskTier: "none"`. Expect the comparison not to cite install scripts against uuid or cuid2. 18. **A question in Russian** — ask: > "Какую библиотеку выбрать для генерации уникальных ID в Node.js?" Expect the skill to trigger, `search_packages` to be called with English terms (e.g. "unique id"), the answer to come back in Russian, and no package names that the tools didn't return. To confirm the skill loaded and is namespaced correctly, run `/help` and check the **Custom commands** tab for `/npmscan:new-dependency-evaluation`, or just invoke it directly with that name.README.mdupstream ↗
Contents are not inlined in the catalog. Open the upstream file.
Plain-text copy, no login: /skill-bundles/salemalem-npmscan-mcp-plugin-skills-new-dependency-evaluation.md