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

@louphq/cli

v0.1.4

Published

Official Loup workshop CLI with separate browser-approved attendee and staff connections stored in the operating system credential store.

Readme

@louphq/cli

Official Loup workshop CLI. It connects this computer to your Loup account through an explicit approval in your browser and keeps the resulting machine connection in the operating system credential store (macOS Keychain or Windows Credential Manager). Claude Code and Codex on the same computer share that one connection.

Requires Node.js 24.x. If your computer has a different Node version, run the CLI with the pinned runtime without changing your other projects. On Windows, type npx.cmd wherever these commands say npx: Windows PowerShell refuses the plain npx script under its default execution policy, while npx.cmd runs in PowerShell, Command Prompt and Git Bash. The commands the CLI prints already use npx.cmd on Windows.

npx --yes [email protected] --package=@louphq/[email protected] loup auth login

With Node 24 already present:

npx --yes --package=@louphq/[email protected] loup auth login
npx --yes --package=@louphq/[email protected] loup auth status --json
npx --yes --package=@louphq/[email protected] loup kits list
npx --yes --package=@louphq/[email protected] loup kits feed --json
npx --yes --package=@louphq/[email protected] loup kits download all --json
npx --yes --package=@louphq/[email protected] loup kits download <kit-id>

Secrets never appear in output, arguments, prompts or files. Public availability of this package grants no workshop access; every request is authorised by the Loup server.

kits list contains only releases this connected computer may retrieve now. A successful download is stored under ~/.loup/kits/<kit>/<release> and includes the verified source archive and a non-secret receipt. Repeating the command reuses that verified local copy without spending another allowance unit. Pass --fresh only when another retrieval is intentional; it creates a separate copy and spends one additional unit. --json reports the release digest, local path, outcome, and used/reserved/remaining allowance accounting.

kits feed lists the same kits in the Skill Tracker's catalogue format: name, version, Community catalogue details, one generic install prompt and the kit's own DETECT.json checks. --json prints the feed exactly as Loup served it.

kits download all --json discovers the open entitled set, sorts it into a stable queue and rechecks live access before starting every item. It keeps successful copies if another item fails and exits non-zero with per-kit recovery steps. Its output reports verified download state separately from installation: the command never claims a kit is installed. The CLI holds no per-kit install data: for every download it reports where the kit was unpacked and says to follow the setup prompt inside that folder, working from a copy. Bulk --fresh is rejected; request a fresh copy for one named kit only.

Loup writes a non-secret operation record under ~/.loup/operations before requesting bytes and checkpoints the archive in the matching .partial-* directory as it arrives. If a transfer is interrupted or the process crashes, rerun the same command without --fresh: it resumes the pinned release from the last durable byte on the original download record, or reconciles a download Loup already completed, without spending another allowance unit. Do not delete the record or partial files and retry as though the first transfer never happened; if Loup reports recovery_required, keep them for staff reconciliation.

Kits from one workspace are listed and downloaded with that workspace named:

loup kits list --workspace <workspace-id> --json
loup kits download <kit-id> --workspace <workspace-id> --release <release-id> --json

kits list --workspace contains the kits that workspace gives this connected computer now, each with the release the workspace has pinned. kits download takes that exact release ID and counts against the named workspace's allowance. Its output adds workspaceId, downloaded: true, installed: false and a handoff object: handoff.ready is true only when the release carries a SETUP-PROMPT.md at its root, and handoff.setupPrompt is that file's path. Use the reported path rather than building one from the kit and release IDs. A release other than the workspace's pin stops with scope_conflict. There is no download all for a workspace. Against a Loup server without workspace delivery the command stops: the CLI never falls back to the commands without --workspace.

courses action reads and changes the links between a workspace's courses and its assets through the same attendee connection:

loup courses action course-assets --data '{"workspaceId":"<uuid>","resourceId":"<classroom-channel-uuid>","courseId":"<course-id>"}' --json
loup courses action asset-courses --data '{"workspaceId":"<uuid>","assetId":"<kit-id>"}' --json

course-asset-set and course-asset-remove change a link and need a requestId; keep the same one when retrying a write.

Staff administration

Staff authority is never added to the attendee connection. An operator starts a second, explicit browser approval and Loup stores that credential under the separate native account staff@<origin host>:

npx --yes --package=@louphq/[email protected] loup staff login
npx --yes --package=@louphq/[email protected] loup staff status --json

The approval page identifies the request as staff access and explains that actions are attributable. The current operator role is checked on every command, so removing an operator denies their next request without signing them out as an attendee.

Inspection commands return a structured { status, operation, actor, result, audit } envelope:

loup staff overview --json
loup staff roster <run-id> --json

overview includes runs, kit releases, publication failures, operators and recent audit outcomes. roster includes effective access, grant sources, overrides and per-kit usage.

Room readiness for one workshop, least ready first:

loup staff prep <run-id>          # headline and one line per attendee
loup staff prep <run-id> --csv    # the same report as the dashboard's CSV download
loup staff prep <run-id> --json   # structured envelope

loup staff connections --json lists the operator's own staff connections as { current, connections }, where current is this computer's staff connection ID.

Mutations use the same names and strict JSON input schemas as the dashboard API:

loup staff action save-run --data '{"name":"Brisbane workshop","location":"Brisbane","date":"2026-09-23","advertisedStartLocal":"09:00","closesLocal":"16:30","whiteboardUrl":"https://link.excalidraw.com/l/<workspace>/<link>"}' --json
# The day opens 30 minutes before the start unless "opensLocal":"07:45" sets it; "opensLocal":null resets it.
loup staff action save-kit --data '{"id":"agent-kit","name":"Agent kit"}' --json
loup staff action set-run-kit --data '{"runId":"<uuid>","kitId":"agent-kit","limit":3}' --json
loup staff action remove-run-kit --data '{"runId":"<uuid>","kitId":"agent-kit"}' --json
loup staff action add-attendee --data '{"runId":"<uuid>","method":"email","destination":"[email protected]"}' --json
loup staff action remove-attendee --data '{"runId":"<uuid>","personId":"<uuid>","note":"Cancelled"}' --json
loup staff action reprovision-attendee --data '{"runId":"<uuid>","personId":"<uuid>"}' --json
loup staff action set-access-window --data '{"runId":"<uuid>","personId":"<uuid>","resource":"kit","kitId":"agent-kit","requestId":"<uuid>","opensAt":"2026-09-23T07:00:00.000Z","closesAt":"2026-09-23T08:00:00.000Z","note":"One-hour post-day rescue"}' --json
loup staff action add-downloads --data '{"runId":"<uuid>","personId":"<uuid>","kitId":"agent-kit","requestId":"<uuid>","amount":1,"note":"One recovery copy"}' --json
loup staff action revoke-attendee-connection --data '{"runId":"<uuid>","personId":"<uuid>","connectionId":"<uuid>"}' --json
loup staff action add-kit-grant --data '{"kitId":"agent-kit","method":"sms","destination":"+61400000000","limit":3}' --json
loup staff action add-operator --data '{"method":"email","destination":"[email protected]","name":"Operator"}' --json
loup staff action remove-operator --data '{"personId":"<uuid>"}' --json
loup staff action remove-pending-operator --data '{"method":"email","destination":"[email protected]"}' --json
loup staff action select-release --data '{"kitId":"agent-kit","runId":"<uuid>","releaseId":"<uuid>"}' --json
# Workspace provisioning (staff only; see docs/workspaces.md and docs/provisioning-staging.md)
loup staff action workspace-provisioning --data '{"operation":"describe","relayHost":"relay.example.com"}' --json
loup staff action workspace-provisioning --data '{"operation":"set_relay","workspaceId":"<uuid>","communityId":"<relay community uuid>","relayHost":"relay.example.com"}' --json
loup staff action workspace-provisioning --data '{"operation":"ensure_resource","workspaceId":"<uuid>","resourceId":"<channel uuid>","section":"channels","restricted":false}' --json
loup staff action workspace-provisioning --data '{"operation":"unregister_resource","workspaceId":"<uuid>","resourceId":"<channel uuid>"}' --json

Publish a kit version by uploading its files, with the staff connection:

loup assets publish ./agent-kit --kit agent-kit --name "Agent kit" --description "Builds your first agent." --json
loup assets publish ./agent-kit.tar.gz --kit agent-kit

A folder is packed on this computer into a temporary .tar.gz (removed afterwards) with paths relative to the folder. It holds regular files and symbolic links; .git, .DS_Store, Thumbs.db and ._* files are skipped and counted, and sockets, pipes or devices stop the command. Windows has no execute bit, so a folder packed there marks no file executable. An existing .tar.gz or .tgz is uploaded as is. Limits: 20,000 files, 32 MiB per file, 256 MiB unpacked and 128 MiB compressed. --name creates or renames the kit first, --description sets its short description (up to 280 characters; on its own it needs an existing kit). The archive goes straight to private quarantine storage, then Loup validates it, repacks it and returns the new release (--json prints the release). Loup allocates the version number. Publishing never changes what attendees receive: select the release to make it current:

loup staff action select-release --data '{"kitId":"agent-kit","releaseId":"<release-id>"}' --json

Publishing from GitHub runs the same immutable snapshot pipeline:

loup staff publish --data '{"kitId":"agent-kit","repository":"owner/repository","ref":"main"}' --json

Use loup staff revoke <connection-id> or loup staff logout for the operator's own staff credential. These commands do not alter the attendee credential. revoke-attendee-connection is a separately audited workshop action for one attendee machine. Resource windows and download increments remain separate actions; reuse the same requestId when retrying an uncertain command so allowance cannot be added twice.

Correct an attendee only after staff verification in person or through the pre-day support request. The action preserves the person, access, usage, machine connections and stable linked contact:

loup staff action correct-contact --data '{"personId":"<person-id>","method":"sms","destination":"+61412345678","verification":"staff_in_person","note":"Checked photo ID at registration"}' --json

Loup succeeds locally even if the connected contact service is unavailable and reports a sanitised, attendee-specific writeback state in the roster. Retry and recovery remain automatic responsibilities of the separate connector; the staff product exposes no provider queue or recovery control.