⏳ This skill is pending AI review.

Scores will appear once the review pipeline completes.

version unknown

new-dependency-evaluation

@salemalem⭐ 503 stars

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.

—/10

// RATINGS

⭐GitHub Stars
⭐⭐⭐⭐ 503 on GitHubGitHub ↗

Popular

🟢ProSkills Score
—
📍

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

Pending:

What it adds

  • MCP server (npmscan, https://npmscan.com/api/mcp) with twenty-three tools — see Tools below. Every tool result includes an npmscanUrl linking 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 carries isMalware, so a confirmed-malicious package is reported as malware to remove, never as an ordinary bug.

  • /npmscan:dependency-audit skill — chains batch_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 via diff_dependencies, raw npm audit --json output via enrich_npm_audit, and a bare GitHub repo URL via audit_github_repository. Triggers automatically when you paste a package.json/lockfile/SBOM, give a GitHub repo URL, or ask to check/audit your dependencies, or invoke it directly. See skills/dependency-audit/SKILL.md.

  • /npmscan:package-trust-check skill — 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's dependency-audit). See skills/package-trust-check/SKILL.md.

  • /npmscan:new-dependency-evaluation skill — 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. Orchestrates compare_packages/suggest_alternative/search_packages into a structured side-by-side with a deterministic pick. See skills/new-dependency-evaluation/SKILL.md.

  • /npmscan:incident-response skill — turns an existing finding, or just a vague symptom description ("npm install did something weird"), into concrete get_remediation_playbook steps: real incident references, severity, and prevention tips, not improvised advice. See skills/incident-response/SKILL.md.

  • /npmscan:ci-pr-gate skill — 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 of diff_dependencies/simulate_dependency_upgrade — not a conversational report (that's dependency-audit's job). See skills/ci-pr-gate/SKILL.md.

Tools

NPMScan provides twenty-three tools:

ToolDescription
search_packagesSearch 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_packageLatest 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_versionMetadata 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_profilePackages 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_vulnerabilitiesOSV.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_vulnerabilitiesOSV.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

// REPO STATS

503 stars