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

@tendee/cli

v0.5.0

Published

CLI for vendoring Tendee icon bundles (React, Vue, Svelte, React Native, Swift, Jetpack Compose, and more) into a repository.

Readme

@tendee/cli

Vendors a curated icon collection from Tendee into your repository as plain source files you own and commit — no runtime dependency, no icon font, no bundle of SVGs loaded at runtime.

npx @tendee/cli sync my-collection --target react --out components/icons

That writes one component per icon, a shared types module, and a lock file. From then on the icons are ordinary files in your project.

Install

Nothing to install — npx @tendee/cli <command> works. To pin it:

npm install --save-dev @tendee/cli

Requires Node 20 or newer.

Authenticate

tendee login

Opens a browser and waits for you to approve. Tokens are stored in ~/.config/tendee/config.json and are scoped to one organization.

In CI, issue a token in the dashboard and pass it in the environment instead:

TENDEE_TOKEN=tnd_... tendee sync my-collection --target react --frozen-lockfile

Never pass a token as a command-line argument — it lands in your shell history and in the process list.

Two directions

Installing a collection — someone has curated a collection and you want it in your code:

tendee collections                                          # find the slug
tendee sync <collection> --target react --out src/icons --dry-run
tendee sync <collection> --target react --out src/icons

Building a collection — your project already has icons scattered around it and you are consolidating them:

tendee scan                          # read-only; writes .tendee/scan.json
tendee push <collection> --dry-run   # preview uploads of the SVG files it found
tendee push <collection> --yes
tendee link <collection> --dry-run   # preview catalog matches for icon-library imports
tendee link <collection> --yes

sync needs neither scan nor push nor link. You can be in the first workflow without ever touching the second.

Adding a missing icon from the catalog

If a project needs an icon that already exists in Tendee but the project hasn't imported it yet, add it directly without having to mock up a fake import first:

tendee search heart                                # find the icon
tendee add my-collection heart --provider lucide-icons  # add it, confirmed with --yes
tendee sync my-collection --target react          # pull it back into code

search is read-only and shows icons from the catalog with their metadata. add places an icon into your collection; without --yes, it previews the plan first and you confirm. Both commands require --provider — look it up in the search output. After add, run sync to materialize it alongside the rest of your collection.

Commands

| Command | What it does | |---|---| | tendee login | Browser login. Requires a human | | tendee login --stdin | Read an already-issued token from stdin (CI-friendly) | | tendee collections [--json] | List collections in your organization | | tendee scan [--dir .] [--json] | Read-only project scan → .tendee/scan.json | | tendee push <collection> [--dry-run] [--yes] [--json] | Upload the SVG files the scan found | | tendee link <collection> [--dry-run] [--yes] [--json] | Link catalog icons matching the library imports the scan found | | tendee search <query> [--provider <org-slug>] [--style <style>] [--limit 20] [--json] | Search the Tendee catalog for icons (read-only, no --yes) | | tendee add <collection> <name...> --provider <org-slug> [--style <style>] [--dry-run] [--yes] [--json] | Add icons from the catalog to your collection without requiring them to exist in your project | | tendee audit <collection> [--json] | Check if the collection is a single visual family | | tendee sync <collection> --target <target> [--out DIR] | Materialize a collection into source files | | tendee agent init | Install a skill file so a coding agent knows how to drive this CLI | | tendee --version | Print the installed version |

Run tendee sync --help for the full flag list. scan, push, link, search, add, collections and audit accept --json — parse that rather than scraping the human-readable output, which is free to change. --json works on --dry-run as well as the real invocation (except sync, which has no --json at all; its file list and rename report are text only).

JSON on the decision step

--dry-run --json exists precisely for the step where you decide whether to --yes. Before committing icons to your collection, you need the exact matching logic and any unresolved names:

{"dry_run":true,"collection":"my-set","plan":[{"input":"Trash2","base_name":"trash-2","matched_by":"digit_boundary"},{"input":"X","base_name":"x","matched_by":"exact"}],"unresolved":[{"library":"lucide-react","input":"NoSuchIcon","reason":"no_match"}],"counts":{"plan":2,"unresolved":1,"non_exact":1}}

Key fields:

  • matched_by — how the icon name resolved: exact (perfect match), suffix_icon (removed trailing Icon), digit_boundary (split on letter→digit boundaries), alias (cross-referenced upstream aliases). Only the first kind requires no human review; the rest mean "close but check."
  • unresolved — names that could not be matched to the catalog, with a reason (no_match, unknown_library, etc.).
  • counts.non_exact — how many items in the plan matched by anything other than exact. Unresolved count is counts.unresolved.

This structure exists on the preview step (above) and on the real --yes call too — so you can parse JSON consistently without switching to text scraping once you decide to proceed. The decision point is JSON; the execution is JSON.

Two things this CLI deliberately does not do. There is no delete — removing icons or collections happens in the dashboard. And there is no Figma import: pulling icons out of a Figma file is a dashboard flow too. Both are product decisions, not missing flags.

Auditing a collection

tendee audit my-collection
tendee audit my-collection --json

Answers the question: is this collection a single visual family? Reads metadata only (never svg_content), so it's cheap and meant to run repeatedly as you curate. Read-only operation: no --yes or --dry-run flags.

dogfood-run-2026-08-21: 97 icons

Render styles: outline 94, filled 3
  Mixed styles in one set — usually the thing to fix before measuring anything else.

Stroke width: median 2, 94 sampled.
  ~ custom-bolt  6  (off by 4)
  3 outline icon(s) carry no stroke measurement, so they were not compared.

Exact duplicates: none.

The report prints:

  • Icon count — total in the collection.
  • Render styles — breakdown by outline, filled, duotone, etc. If more than one style is present, a warning that mixed styles usually need fixing first.
  • Upstream sources — if more than one, notes that icons from different repositories are mixed by construction.
  • Stroke width — median, sample size, and a list of outliers (only for outline icons; filled and duotone have no strokes by construction). Anchors to the actual icon slug so you can look it up in the dashboard.
  • Coverage note — how many icons carry visual metadata. Without it, "no outliers" and "nothing to measure" read the same.
  • Exact duplicates — groups of icons with byte-for-byte identical SVG content.

--json parses as strict JSON (audit_report object), suitable for scripting or agent use.

Targets

react, vue, svelte, web-component, react-native, swift, compose, sprite.

Default output directories, overridden by --out:

| target | default | |---|---| | react, vue, svelte, web-component, react-native | src/icons | | swift | TendeeIcons | | compose | src/main/kotlin/io/tendee/icons | | sprite | public/icons |

A repository without a src/ directory almost certainly wants an explicit --out.

What lands on disk

For the React target:

  • one <PascalName>.tsx per icon,
  • tendee-icon.ts, exporting the TendeeIconProps and TendeeIcon types,
  • tendee.lock.json at the repository root,
  • a manifest under .tendee/.

Pass --as-package to also get an index.ts barrel and a generated package.json.

Updating after the collection changes

Re-run the same sync. It reports what moved, and — this is the part that matters — names the files that still import an icon which has left the collection:

Changes since the last sync:
  - RotateCcwClock.tsx
  + Sparkles.tsx
  ~ Camera.tsx

Still imported, but no longer in the collection:
  RotateCcwClock
      src/components/HistoryPanel.tsx
      src/components/Timeline.tsx
Point these at another icon, or put the icon back in the collection.

Without that list, removing an icon in the dashboard turns into a build error somewhere else with nothing connecting the two events.

Commit the generated files and the lock. tendee.lock.json is what lets the next person who clones the repository re-materialize the exact same icons — it is the direct analogue of package-lock.json, not build output. .tendee/ is the opposite case: its manifest records an absolute output path and is machine-local, so ignore it.

Do not hand-edit a generated file. Each one starts with Generated by Tendee. Do not edit directly. That marker is load-bearing: it is how sync decides a file is safe to overwrite, and safe to delete once its icon leaves the collection. An edit is lost on the next sync, and a file that loses the marker is never cleaned up. To change an icon, change the collection and sync again.

Component names are not your old library's export names

This is the most common way a migration breaks. Names come from the icon's canonical name in the registry:

| what your old library exported | what Tendee generates | |---|---| | AlertCircle | CircleAlert | | Loader2 | LoaderCircle | | History | RotateCcwClock |

Run --dry-run first. It prints the exact file list, plus a rename map. If you have run tendee scan in this project, the map is keyed on the names in your code:

3 names in your code map to a differently named component:
  AlertCircle    -> CircleAlert
  Loader2        -> LoaderCircle
  PanelLeftIcon  -> PanelLeft

Rewrite exactly those imports; every other binding keeps its name.

Without a scan there is nothing to key on, so the report falls back to what upstream records — CircleAlert <- AlertCircle, read right to left. That form is weaker: it lists old upstream names whether or not your project ever used them, and it cannot see conventions your library invented, such as the trailing Icon in PanelLeftIcon. Run tendee scan first and you get the better one.

Drift checking in CI

tendee sync <collection> --target react --frozen-lockfile

Writes nothing. Exits non-zero if the registry has moved away from the committed lock, so a pull request can fail on icons that changed underneath it.

Already up to date means the collection has not changed since your last sync. That is a success, not a warning.

Coding agents

tendee agent init

Writes a skill file describing this CLI — .claude/skills/tendee/SKILL.md for Claude Code, .cursor/rules/tendee.mdc for Cursor, or an AGENTS.md block otherwise.

Detection works off agent config that already exists (.claude/, .cursor/, AGENTS.md), so a project that has none gets AGENTS.md and says so. Pass --target claude|cursor|codex to choose.

License

MIT.