{"id":25710,"plugin_id":"plugin_asdk_app_6a6a699e6f3481918d5e6034432894f2","kind":"skill","collection_source":"plugin_package","comparison_source":null,"observed_at":"2026-10-02T00:16:00.878Z","digest":"d8d738caa798bc8d66415c6a5fb867e90b445ae6965e081a15179bc4aeb099df","against":null,"payload":{"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\").","included_files":[{"relative_path":"agents/openai.yaml","size_in_bytes":294},{"relative_path":"references/test-prompts.md","size_in_bytes":9542}],"name":"new-dependency-evaluation","skill_md_contents":"---\nname: new-dependency-evaluation\ndescription: 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\").\n---\n\n# New dependency evaluation\n\nUse this skill when the user is making a **forward-looking choice** about\nwhat to add to a project — not investigating something already installed.\nIt orchestrates two tools that already do the hard work individually:\n`suggest_alternative` (turns one candidate name into a real shortlist of\npeers) and `compare_packages` (fans out enrichment across 2-5 named\ncandidates and returns a structured side-by-side with a deterministic pick).\nThis skill's only job is routing to the right combination of the two based\non how many candidates the user actually named, then presenting the result.\n\nIf the user instead asks whether a package **already in their project** is\nsafe to keep, use `package-trust-check` (single package) or `dependency-audit`\n(a pasted inventory) — those investigate what's already there; this skill\nevaluates what to add next. If the question has no choice or decision angle\nat all (\"what does X do,\" \"what's the latest version of X\"), just answer\ndirectly with `get_package` — don't invoke this skill's tool chain for that.\n\n## Determining what to compare\n\nCount how many named candidates the user actually gave, then route:\n\n1. **2-5 named candidates for the same job** (e.g. \"axios vs got vs\n   node-fetch,\" \"should we use dayjs or date-fns\") — go straight to\n   `compare_packages({ packages })`. This is the common case and needs no\n   extra tool call first.\n2. **Exactly 1 named candidate** (\"should we add uuid,\" \"is left-pad a good\n   choice,\" \"can we use X for Y\") — a single package has nothing to be\n   compared against yet. Call `get_package({ name })` for the named\n   candidate's own `description` (`suggest_alternative`'s `source` object\n   doesn't include one), then `suggest_alternative({ name, reason:\n   \"general\", limit: 4 })` to generate real peers (never invent\n   plausible-sounding package names yourself). Screen the suggestions\n   against that description per\n   [Screening candidates before comparing](#screening-candidates-before-comparing-routing-cases-2-3)\n   below, then call `compare_packages` with `[name, ...screened\n   suggestions, up to 4]` so the original candidate is scored against real\n   competition instead of judged in isolation. If `suggestions` comes back\n   with fewer than 1 usable peer after screening (e.g. a built-in\n   replacement fully covers the case, like `left-pad` →\n   `String.prototype.padStart()`), skip `compare_packages` — there's\n   nothing left to compare — and report the `nonPackageAlternatives` plus\n   the `get_package` baseline on the named candidate instead.\n3. **0 named candidates, just a described need** (\"what should we use to\n   parse dates,\" \"we need something for HTTP retries\") — call\n   `search_packages({ query })` using the user's own description as the\n   query. Build a 2-5 name shortlist from the results, preferring the\n   highest `popularityTier`/`maintenanceTier` matches, skipping any result\n   carrying `possibleTyposquatOf`, and screening each result's\n   `description` against the user's *stated need* (their own words are the\n   comparison anchor here — no extra fetch needed) the same way as case 2\n   — then run `compare_packages` on that shortlist. If nothing in the\n   search results looks like a real contender (all very-low\n   popularity/stale, or nothing actually matches the described need), say\n   so rather than forcing a comparison, and ask the user for a starting\n   name or two.\n4. **More than 5 named candidates** — `compare_packages` caps at 5. Don't\n   silently drop candidates without saying so: run it on the first 5 and\n   name which were left out, or ask the user to narrow the list if the\n   ones dropped seem like they'd matter to the decision.\n\n### Screening candidates before comparing (routing cases 2-3)\n\n`suggest_alternative`'s `categoryOverlap` and `search_packages`'s result\nordering are both keyword/token-overlap signals, not semantic relevance —\nand a single shared generic word (e.g. both packages' descriptions mention\n\"guid\") combined with high popularity can rank an unrelated package above\ngenuinely relevant ones. This was confirmed directly: comparing candidates\nfor `uuid` (an RFC9562 UUID *generator*, `description: \"RFC9562 UUIDs\"`)\nsurfaced `win-guid` (`description: \"Windows legacy GUID parser\"` — an\nunrelated Windows binary-format tool) as the top suggestion, ranked above\nthe real UUID library `@paralleldrive/cuid2`, purely because `win-guid`\nhappens to have very high download counts and shares the single word\n\"guid.\" Reading the two descriptions side by side makes the mismatch\nobvious immediately (\"generates RFC-standard UUIDs\" vs. \"parses legacy\nWindows binary GUID structures\") in a way `categoryOverlap`'s token count\nalone does not catch. So for every candidate before it enters\n`compare_packages`:\n\n- Actually read and compare full description text, not just token\n  overlap — the source's own `description` (from `get_package` in case 2,\n  or the user's stated need in case 3) against the candidate's\n  `description`. Ask in plain terms: does this candidate do the same job,\n  or does it just share vocabulary with something that does? Drop\n  candidates that fail this even if their `categoryOverlap` list looks\n  populated — shared words are a hint to go check, not a verdict on their\n  own.\n- Treat a `categoryOverlap` of exactly one generic word (`\"guid\"`,\n  `\"data\"`, `\"util\"`, etc.) as weak supporting evidence at best; two or\n  more overlapping tokens, or overlap on a specific/technical term, is\n  stronger — but the description comparison above is the actual decision,\n  not the token count.\n- Don't let a high `weeklyDownloads`/`popularityTier` on its own excuse a\n  poor description match — a package can be extremely popular as a\n  transitive dependency of something unrelated to the job at hand.\n\n## Steps\n\n1. Route per the table above and make the tool call(s).\n2. Read `differentiators` before `recommendation` — it names which\n   candidate(s) stand out on downloads, GitHub stars, TypeScript support,\n   known vulnerabilities, deprecation, typosquat flag, and install-script\n   risk. This is what makes the comparison legible; don't just report the\n   final pick with no supporting detail.\n3. Report `recommendation.pick`, `runnerUp`, and `rationale` verbatim —\n   don't substitute your own judgment for the deterministic score unless a\n   `candidates[]` entry shows something the score can't see (e.g. the user\n   already said they need TypeScript-first and two candidates are close).\n   Always state `confidence` too — a `\"low\"` confidence pick between two\n   close candidates is a materially different answer than a `\"high\"`\n   confidence one.\n4. Surface every `found: false` candidate with its `resolutionError`\n   (typo? unpublished? malformed name?) rather than silently dropping it\n   from the comparison you present.\n5. Note that `installScriptRisk` here is the **lifecycle-scripts-only**\n   signal (`scanScope: \"lifecycle-scripts-only\"`) — it scans the command\n   strings, not the tarball. If the recommended pick has a nonzero\n   `installScriptRisk.totalScore` and the user is about to actually install\n   it, mention that `analyze_install_script` (via `package-trust-check`)\n   gives the deeper, tarball-aware scan before they commit — don't run it\n   automatically as part of this skill, just point at it.\n6. If the user's decision also turns on license policy (they mention a\n   license constraint, or ask \"which of these is safe to use license-wise\"),\n   follow up with `check_license_compliance` on the shortlist — it's not\n   part of the default flow, only pull it in when license is actually in\n   play.\n7. Sanity-check `githubStars` against `weeklyDownloads` per candidate:\n   `githubStars` is attributed to whatever repository the candidate's own\n   `package.json` declares, unverified — a tiny, low-download package\n   showing a huge star count (e.g. thousands of stars on a package with\n   under a thousand weekly downloads) can mean its declared `repository`\n   field points at a different, unrelated project's repo rather than its\n   own (confirmed directly: `@aigne/uuid`, ~850 weekly downloads, declares\n   `repository: github.com/uuidjs/uuid` — the real `uuid` package's repo,\n   not its own — and so inherits that repo's star count). Flag a large\n   downloads/stars mismatch like this as worth independent verification\n   before adopting the package, rather than reporting the star count at\n   face value as a credibility signal; this skill's tools don't run the\n   deeper source-attestation check that would confirm or rule this out\n   (`check_package_provenance`, via `package-trust-check`).\n8. Treat `downloadTrend.changePercent` with caution when\n   `weeklyDownloads` is low (roughly under a few thousand) — a small\n   absolute change produces a large, noisy percentage (e.g. a candidate\n   with 850 weekly downloads showing `\"growing\"` at 800%+ off a tiny prior\n   base is statistical noise, not real momentum). Lead with the absolute\n   download figure, not the percentage, for any low-volume candidate.\n\n## Output requirements\n\n- Always include each candidate's `npmscanUrl` so the user can read the full\n  write-up.\n- Present the comparison as a table (or clearly separated per-candidate\n  summary) with at minimum: downloads/trend, popularity/maintenance tier,\n  deprecated status, latest-version vulnerability status, TypeScript\n  support, GitHub stars, and install-script risk tier — then the pick and\n  rationale below it, not interleaved.\n- When `suggest_alternative` was used to generate the peer set (routing\n  case 2), say so explicitly (\"compared against N real peers in the same\n  category, not just this one package in isolation\") so the user\n  understands the comparison isn't limited to what they originally named.\n- State plainly that this is a point-in-time snapshot (downloads,\n  vulnerabilities, and maintenance activity all change) — not a permanent\n  verdict, especially if the user's decision is time-sensitive.\n\n## Do not\n\n- Do not invent candidate package names yourself when the user gave 0 or 1\n  — `search_packages`/`suggest_alternative` exist specifically so the\n  shortlist is real, current registry data instead of names recalled from\n  training knowledge that may be renamed, abandoned, or gone since.\n- Do not call `compare_packages` with fewer than 2 or more than 5 packages\n  — dedupe first (case-insensitive; the tool itself rejects exact\n  duplicates with a 400), and route through cases 2-4 above instead of\n  forcing a single name through it.\n- Do not treat a deprecated or typosquat-flagged candidate as excluded from\n  the comparison — `compare_packages` still returns them (with `deprecated`/\n  `possibleTyposquatOf` set) so the user can see exactly why they lost; only\n  `recommendation.pick` is guaranteed to skip them, not the `candidates`\n  list itself.\n- Do not silently narrow a >5-candidate list without telling the user which\n  names were dropped and why.\n- Do not use this skill to re-investigate a package the user already has\n  installed and is worried about — that's `package-trust-check` or\n  `dependency-audit`; this skill's tools are tuned for choosing among\n  healthy-looking options, not for compromise/takeover forensics.\n- Do not present `recommendation.pick` as a security clearance — it's a\n  weighted popularity/maintenance/vulnerability/typosquat/install-script\n  score, not a guarantee the package is free of issues the lighter scan\n  can't see.\n- Do not pass every `suggest_alternative`/`search_packages` result straight\n  into `compare_packages` on the strength of `categoryOverlap` alone — a\n  single generic shared token plus high popularity can rank an unrelated\n  package first (verified: `win-guid`, a Windows GUID *parser*, outranked\n  a real UUID library when comparing alternatives to `uuid`). Read each\n  candidate's `description` and drop ones that aren't actually the same\n  tool for the job before comparing them.\n- Do not report a candidate's `githubStars` as a plain credibility signal\n  without checking it against `weeklyDownloads` first — a low-download\n  package with implausibly high stars likely has a `repository` field\n  pointing at a different project's repo, not evidence of its own\n  popularity.\n\n## Tools used\n\n`compare_packages`, `suggest_alternative`, `search_packages`, `get_package`\n(for the source description in routing case 2), and optionally\n`check_license_compliance` — see `agents/openai.yaml` for the MCP server\ndependency, and `references/test-prompts.md` for the test cases to run in\nChatGPT Developer Mode before submitting.\n"},"changes":[],"summary":"First saved snapshot. No earlier version is available for comparison.","summary_kind":"deterministic","summary_metadata":{}}