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

@testsigma/testsigma-cli

v0.0.2

Published

The CLI: validate, pull, push and run, as thin shims over the library seams.

Readme

@testsigma/cli

validate, pull, push and run as thin shims over the library seams. Behaviour is tested at S1–S3; the tests here are smoke tests, which is what the ticket asks for.

testsigma validate [--root <dir>] [--json]
testsigma push     <file> [--root <dir>] [--json] [--dry-run]
                   [--overwrite-remote] [--discard-healing]
testsigma run      [--root <dir>] [--test <name>]
testsigma pull     <file | kind name-or-id> [--root <dir>] [--json]
                   [--write | --adopt-id]

pull and push read a live tenant, so they need credentials in the environment — env vars only, no flags (prototype §1):

export TESTSIGMA_API_KEY=<a key from Settings → API keys>
export TESTSIGMA_HOST=https://app.testsigma.com

The CLI's own piece of work

Everything except one file is a shim. src/workspace.ts is the exception, and it exists because nothing below the CLI reads a directory:

  • Discovery is by convention — tests/testsigma/<project>/<application>/<version>/ and its kind roots, so any repo's tests are found the same way (SPEC user story 9). Environments and the variable pool hang off the project, because that is the only scope the server gives them, and one project's environments are read once and shared by every version under it.
  • The server coordinates live in the markers and nowhere else, one per level. project.sigma carries the project id, application.sigma the application id, version.sigma the version id, folder.sigma a server folder's canonical name and id. The four names are reserved: a working copy taking one is refused (TSF2064) rather than read as a marker. They are entity files like any other, so their coordinates are read by the same compiler rather than by a second parser. An application missing one is reported as TSF2051 against its own path, and the walk carries on to the others: an author fixing a workspace wants everything wrong with it, not the first thing wrong with it.
  • The walk is total. Every .sigma file under the workspace root is read and handed on with its real path, however oddly placed, because placementOf is what decides whether a path is in the layout. Walking only the paths the layout allows left every misplaced file invisible — which is exactly the file worth reporting.

Cross-file checks run through validateWorkspace. A screen filed under tests/ is TSF2050, because the kind root is what tells push which endpoint a file goes to; so is a test under tests/ named login.screen.sigma, which is the misfiling an author actually makes. Two screens claiming one element name is TSF2052 — the name is unique per application version on the server, so a push would collide, and a locator lookup would otherwise silently pick one. Where a file sits in the folder mirror is TSF2058 (at a foldered kind's root, so in no server folder), TSF2059 (project-scoped kind inside an application) and TSF2060 (a folder directory whose marker is missing, so it names no folder — the directory name is a derived handle and never stands in for one).

validate is the contract

--json emits diagnosticsToJson over every file in the workspace — the same shape a single file's diagnostics take, so the authoring loop parses one format whether it asked about one file or all of them (SPEC user story 2). A workspace that cannot be opened at all answers in that shape too, as TSF2051, so the loop's parser is not conditional on which failure it hit.

pull is the first command that reaches the server

testsigma pull <file> fetches the entity the file's identity binding names, renders the canonical pull, and prints a unified text diff of the local bytes against it. It touches nothing unless asked, which is what makes it the safe first thing to run against a live tenant; --write and --adopt-id are the two ways of asking, and the read-only report names them both.

The one-spelling law is what makes that diff worth reading: every authoring state has exactly one surface form, so two files differ textually exactly when they differ semantically. There are no structured hunks under --json, only the one diff string and a changed boolean.

  • A changed diff still exits 0. A nonzero exit would poison a set -e script that only wanted to look; changed is what carries the answer (prototype decision 3).
  • A file that does not compile still diffs, with a notice — the diff is pure text, and a broken file is exactly when a reader wants to see the server's.
  • A stale binding is "entity gone" (TSS1401), reported with both exits named and exit 2 — the same shape and exit as push's stale-id refusal (decision 5).
  • Prose goes to stdout when the command did its job and to stderr when it did not, so testsigma pull … > review.diff holds a diff and nothing else. --json always goes to stdout, because it is the answer.

pull --write and --adopt-id are the only two writes

src/write.ts is the disk half of them, and it is the CLI's second piece of real work for the same reason src/workspace.ts is the first: nothing below the CLI knows there is a filesystem.

  • The canonical file is the stamped file. --write stamps the content baseline (ADR-0008), so the text it writes carries its own hash. The read-only diff is taken against that same text — against the unstamped render, every file pull had ever written would differ on its own hash line for ever.
  • One derivation, planned before it is performed. destinationFor runs in every mode, so the read-only report can say which rename --write would follow and which numeric suffix a taken handle would take; only performWrite touches disk. A report naming one path and a write using another is the drift the one-handle rule exists to prevent.
  • A folder directory is recognised by its marker's id, never by its name — the directory name is a derived handle that does not round-trip, so matching on it would mirror one server folder twice the moment it was renamed. Only the levels no marker claims are created.
  • What is already there is read off the disk, not off the workspace walk: a file that failed to compile never reaches the walk and is very much on the filesystem, and the numeric suffix is what stops it being written over.
  • --adopt-id is a text insertion, not a re-render. Everything but the binding stays byte-identical, so a file whose spacing an author has not got round to fixing keeps it; a model rendered back out would canonicalise it. The insertion point comes from the format's own lexer (tokensOf), because a name may hold a bracket and a second tokeniser would be a second answer to what a bracket is. It stamps no baseline — adopt claims identity, not content reconciliation, so adopt-then-push honestly gets the missing-baseline notice.
  • A failed write reports what landed, exit 3, with the untried rows marked not-attempted — the same account push's ledger keeps (ADR-0007), because the caller's next move is decided by what is on disk, not by what was meant.

src/report.ts renders the envelope @testsigma/sync builds. Two rules from the prototype are binding and tested: a TSS code sits in its own right-hand column, and every exit is indented under its finding, so a refusal is never printed without a way out. One deviation is deliberate — §7 prints its exits flush left while §5c indents them; both cannot be the rule, and the indent is what keeps a report with two findings readable.

Two commands still stop at a boundary

There is still no write client for the server and no execution for bt. Rather than pretend, each does its pure half and says where it stops — and exits non-zero, because it did not do the thing it is named for:

| Command | Does | Stops at | | --- | --- | --- | | run | builds the bt payload, refusing everything the payload cannot represent | executing it |

push no longer stops short: it runs the preflight, sends the writes in the order the spec fixes, and writes each id back into the file as it lands. --dry-run is the preflight and the plan alone.

Exit codes are distinct, because that is what a pipeline gates on — and they are a function of the report's outcome rather than a second table (prototype §2): 0 success, 1 invalid, 2 refused, 3 a write phase died partway, 4 auth, 69 (EX_UNAVAILABLE) unreachable.

push refuses outright if the file it was given does not validate — a push of something nobody has checked. Not the whole workspace: push is per-entity, and refusing to push one file because another one is broken would make a workspace a unit it is not.