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

tangy-cli

v1.0.0

Published

A small CLI to set up and manage Tangled (tangled.org) repos.

Readme

tangy

A small CLI to set up and manage Tangled repos. (I thought this must exist but I haven't found it.)

It talks to Tangled the same way the website does, but from your terminal: it logs you in with your own ATProto account, creates the repo on a knot, records it on your PDS, and wires up a local git repo pointing at it.

Install

npm install
npm link   # optional: puts `tangy` on your PATH

Requires Node ≥ 20.

Usage

# 1. Log in (opens your browser to authorize; credentials go in the OS keychain)
tangy login alice.tngl.sh

#    log in more accounts whenever you like — earlier logins are kept
tangy login work.example.com

# 2. Choose where each user's repos get created locally
tangy configuration set root ~/Code/tangled                     # default user
tangy configuration set root ~/Work/tangled -u work.example.com

#    (optional) pick a different knot to host on; defaults to knot1.tangled.sh
tangy configuration set knot knot1.tangled.sh

# 3. Create a repo — makes it on Tangled, wires it up locally, and pushes
tangy repo create my-project
tangy repo create my-project -d "A short description"
tangy repo create my-project --no-push   # skip the automatic push
tangy repo create my-project -u work.example.com   # act as another account

# 4. Or move an existing local git repo into Tangled
tangy move ~/Code/some-project

# 5. Bring over a GitHub repo's open issues and PRs (comments, labels,
#    assignees, reactions included)
tangy copy owner/repo my-project
tangy copy https://github.com/owner/repo --dry-run

# See who is logged in, and pick who commands act as by default
tangy user list
tangy user default work.example.com

# …later — logs out the default user, or the one named with -u
tangy logout
tangy logout -u alice.tngl.sh

tangy repo create <name>:

  • creates <root>/<name>/ locally,
  • creates the repo on your knot and announces it on your PDS,
  • runs git init and sets origin to the Tangled repo,
  • writes README.md (# <name>) and a Node-friendly .gitignore,
  • makes an initial commit (if your git identity is configured),
  • pushes that commit to origin — this assumes your SSH key is already added to Tangled.

Pushing is on by default. Pass --no-push to skip it and push yourself later:

tangy repo create my-project --no-push
cd <root>/my-project
git push -u origin main

If the push fails (e.g. your SSH key isn't on Tangled yet), the repo has still been created both locally and remotely — add your key and run git push -u origin main from the repo directory.

tangy move <dir> adopts an existing local git repo into Tangled:

  • creates a repo on your knot named after the directory (so tangy move ~/Code/some-project creates some-project) and announces it on your PDS,
  • moves the directory into <root>/ — it refuses to overwrite anything already there, and if the repo already sits at <root>/<name> it just skips the move,
  • points origin at the Tangled repo (replacing any previous origin),
  • if the repo has a package.json, points its repository field at the Tangled repo and commits just that change (left uncommitted if git has no identity configured or the repo has no commits yet),
  • pushes the current branch (the knot's default branch is set to match it).

The directory must be the root of a git work tree and on a checked-out branch. Other branches and tags are not pushed automatically. --no-push and -d/--description work the same as for repo create. If creating the repo on Tangled fails, the directory is moved back where it was.

Copying issues and PRs from GitHub

tangy copy <github> [repo] copies a GitHub repo's open issues and pull requests (closed ones stay behind) into a Tangled repo you own — by default one with the same name, which must already exist (tangy repo create / tangy move first). It takes -u <user> like everything else, and re-running it is safe: tangy remembers what it already copied (in copies.json next to its config) and only picks up new items and new comments.

What gets copied, and how:

  • Issues and PRs become Tangled issues and pulls, keeping their original timestamps. PR patches are fetched from GitHub and attached, targeting the PR's base branch.
  • Comments come along (conversation comments; inline review comments don't).
  • Labels are recreated as Tangled label definitions (with their colors), the repo is subscribed to them, and they're applied to the copied items.
  • Reactions are summarised in the item ("Reactions: 👍 3 · ❤️ 1"), and any reaction you made on GitHub is also recreated natively as you.
  • Assignees are recreated natively too: Tangled models assignment as the platform's shared DID-valued "assignee" label, so every assignee whose GitHub account maps to an AT account is assigned for real. Assignees without a mapping fall back to an "Assignees: …" line in the item.

Since tangy can't impersonate other people, everything is created by the acting user. Anything authored by someone else gets a provenance line first:

Original by @foo = @foo.eurosky.social.

The = @handle part comes from a GitHub→AT mapping that tangy builds up as it goes: the first time it sees a GitHub account it asks you for the matching AT handle (press Enter to ignore that account), and remembers the answer either way. Items you authored yourself (tangy asks for your GitHub username once) are created as you, with no provenance line. Bots are never asked about.

--dry-run shows what would be copied — and which accounts would need mapping — without writing anything. --no-issues / --no-pulls restrict what gets copied. GitHub access is anonymous unless a GITHUB_TOKEN/GH_TOKEN env var or a logged-in gh CLI is around (recommended for big repos: the anonymous API allows only 60 requests/hour).

Multiple users

Several accounts can be logged in at once, and each keeps its own settings — most importantly its own root, so different identities can keep their repos in different places.

  • tangy login <handle> adds an account without touching existing logins. The first account to log in becomes the default user.
  • Every account-bound command (logout, configuration set/get, repo create, move) takes -u <user> to pick the account: a handle, a DID, or any unique handle prefix (-u alice finds alice.tngl.sh). Without -u, the default user is used.
  • tangy user list shows the logged-in users (* marks the default); tangy user default <user> changes the default, and tangy user default shows it.
  • tangy logout [-u <user>] logs out just that user. If the default user logs out and exactly one account remains, it becomes the default.

Console output always names the account being acted through, e.g. Creating "my-project" on knot1.tangled.sh as alice.tngl.sh….

Config files written by older single-user versions of tangy are upgraded automatically.

How it works

  • Auth uses ATProto OAuth via a loopback redirect (@atproto/oauth-client-node). Sessions (refresh tokens + DPoP key) are stored in the OS keychain via @napi-rs/keyring, never on disk.
  • Repo creation asks your PDS for a short-lived service-auth JWT scoped to the knot, calls the knot's sh.tangled.repo.create XRPC endpoint, then writes the sh.tangled.repo record to your PDS.
  • Issues, pulls, comments, labels and reactions are plain records (sh.tangled.repo.issue, sh.tangled.repo.pull, sh.tangled.feed.comment, sh.tangled.label.*, sh.tangled.feed.reaction) written to the acting user's PDS; appviews pick them up from the firehose. Issues and pulls point at the repo via its own DID, comments reference their issue/pull by strongRef (uri + cid), and PR patches are uploaded as gzipped git format-patch blobs.
  • Settings (root, knot) live per user in ~/.config/tangy/config.json, along with which user is the default and the GitHub→AT account mapping used by tangy copy.

Configuration keys

Each key is stored per user (add -u <user> to set or read another account's value):

| key | meaning | default | | --------- | ---------------------------------------------- | --------------------- | | root | local directory this user's repos are created in | (unset) | | knot | knot hostname to host this user's new repos on | knot1.tangled.sh | | appview | Tangled appview base URL | https://tangled.org |

View them with tangy configuration get [-u <user>].