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

@davidorex/pi-context-cli

v0.31.0

Published

Auto-tracking command-line interface over the pi-context op-registry — every substrate op surfaces as a CLI command by reflection, no hardcoded command list

Readme

@davidorex/pi-context-cli

A command-line interface over the @davidorex/pi-context substrate operations.

The command set is auto-tracking: every operation in pi-context's op-registry whose surface is "use" surfaces as a CLI command by reflection. There is no hardcoded command list — adding an op to pi-context makes a new CLI command appear with zero changes to this package. Operations that depend on a pi runtime handle (e.g. list-tools) carry surface: "process" and are not surfaced here.

Install

npm i -g @davidorex/pi-context-cli

This provides a pi-context binary.

Usage

pi-context --help                 # grouped op index (by command class) + global flags
pi-context --version              # print the package version (alias -v)
pi-context <op> --help            # per-op help: synopsis + flags + examples + related commands
pi-context <op> --help --format json  # the same help as a machine-readable JSON model
pi-context <op> [flags]           # run an op

Each op's flags derive from its parameter schema:

  • scalar fields take --field value (string / number); boolean fields are presence flags (--flag, or --flag true|false)
  • object / array / typeless fields take a JSON argument: --field '<inline json>' or --field @path/to.json

Example:

pi-context read-block --block tasks
pi-context append-block-item --block issues --arrayKey issues --item @new-issue.json --autoId
pi-context read-block-page --block framework-gaps --offset 0 --limit 50
pi-context update --dryRun

Input affordances

On top of the schema-derived flags, the CLI accepts a set of input conveniences. Each is additive — the schema-exact form (camelCase flags, explicit --arrayKey, a JSON --writer, separate --field/--op/--value) keeps working unchanged.

  • kebab-case flags are accepted alongside the camelCase op-schema keys. --dry-run resolves to --dryRun; any conventional kebab form resolves when its camelCase key exists. An unrecognized flag (kebab or otherwise) is still rejected.
  • --id aliases the op's single id-param. When an op declares exactly one id-shaped parameter (itemId / parentId / taskId / unitId / …), --id <value> resolves to it. An op that already declares a literal id parameter takes --id directly. An op with two id-params (e.g. complete-task, rename-canonical-id) rejects --id as ambiguous — name the explicit flag.
  • --arrayKey is derived from config for the block-mutation ops (append-block-item, update-block-item, upsert-block-item, remove-block-item, and the nested variants). Pass only --block <name>; the array key is read from that block's config.block_kinds[].array_key. An explicit --arrayKey overrides the derivation.
  • --writer kind:id shorthand. --writer human:[email protected] expands to {"kind":"human","user":"[email protected]"}; --writer agent:claude to {"kind":"agent","agent_id":"claude"} (monitor:monitor_name, workflow:workflow_step_id). The first colon delimits the kind; the identifier may itself contain colons.
  • --where field:op:value shorthand for the filter predicate: --where status:eq:done sets --field status --op eq --value done. Split on the first two colons only, so the value may contain colons.
  • CSV --op in. When the comparison operator is in, a comma-separated --value a,b,c is split into the array ["a","b","c"]. Order-independent — --op in --value a,b,c and --value a,b,c --op in are equivalent.
pi-context append-block-item --block framework-gaps --item @gap.json        # arrayKey derived from config
pi-context find-references --id TASK-1                                       # --id → itemId
pi-context append-block-item --block tasks --item @t.json --writer human:[email protected]
pi-context filter-block-items --block tasks --where status:eq:done          # field/op/value from one token
pi-context filter-block-items --block tasks --field tag --op in --value a,b,c

Contract preview + dry-run

For the block-mutation ops the CLI offers two pre-write affordances:

  • --show-schema previews a block op's contract and exits before any write — the array key, the required-field set, every field with its type (and enum values when declared), and the id pattern. Pass it with the op and --block <name>; no --item is needed.
  • append-block-item --dry-run (or --dryRun) validates the prospective whole file — {...existing, <arrayKey>: [...items, newItem]} against the block schema, exactly what a real append validates — and writes nothing. With --autoId it reports the id that would be allocated. The output is [dry-run] PASS (or [dry-run] PASS — would append <id>); a schema-invalid item surfaces the field-named validation error.
pi-context append-block-item --block framework-gaps --show-schema     # contract preview, no write
pi-context append-block-item --block tasks --item @t.json --dry-run    # validate the prospective file, no write
pi-context append-block-item --block tasks --item @t.json --dry-run --autoId   # also reports the allocated id

Output rendering

--format text|json|table selects how an op's result is rendered. --json is the exact alias of --format json.

  • text (default) — each op's human render: prose, a JSON.stringify'd value, or a read body with its paging footer.
  • json — the { ok, op, output } envelope ({ ok: false, op, error } on failure). output is the un-stringified value (single-parse), read-capped at 50KB.
  • table — a compact markdown table of a renderable row array (a read whose body is a collection, or a data op that returns an array). The projection is best-effort terse: id first when present, then up to three more fields (≤4 columns), cells one-lined and capped at 80 chars. A result that is not a complete tabular collection (prose, a non-array value, or an over-cap read) renders as text instead — a degenerate table is never substituted for the real output.
pi-context read-block --block tasks --format table       # markdown table of the tasks
pi-context filter-block-items --block tasks --where status:eq:open --format table
pi-context read-block --block tasks --json               # ≡ --format json

Schema-validation failures surface field-named guidance — which field and what constraint (e.g. `/gaps/0`: missing required field `description`) — rather than the raw validator phrasing, on both the text and --json surfaces.

Addressed reads return the whole addressed subtree (50KB-capped): read-schema --schemaName <name> --path <dotted.path> and read-config --registry <name> [--id <id>] return the complete node at that address — including all of its children — not a paged slice of one of its arrays.

pi-context pi-bound — constrained pi session

pi-context pi-bound [--grant <id>]... [...pi-args]

pi-bound is a CLI process mode (not a substrate op): it launches a pi coding-agent session restricted to the composed pi-extension tool surface. On every launch it:

  1. runs pi install -l <@davidorex/pi-project-workflows root> to register the extensions into the target dir's .pi/
  2. derives the static tool allowlist from the installed packages' generated skills/*/SKILL.md (@davidorex/pi-context + @davidorex/pi-project-workflows)
  3. always adds the built-in read-only tools read, ls, grep, find
  4. appends the bounded composites declared in the active substrate's config.tool_operations[]
  5. launches pi --tools <union> ...pi-args

It runs from the process cwd and reads that dir's .pi-context.json for composites (warns, non-fatally, if absent).

Flags:

  • --grant <id> (repeatable) — scope the bounded composites to only the named ids. Default: all declared composites.
  • any other token — passed through verbatim to pi (e.g. --continue / -c to resume a session).
pi-context pi-bound                          # launch with the full composed tool surface
pi-context pi-bound --grant grep-paths       # restrict composites to a single named op
pi-context pi-bound -c                        # pass -c through to pi to resume

This process mode replaces the former scripts/launch-constrained-pi.sh launch script.

pi-context update — drift-aware model update + conflict surfacing

pi-context update [--dryRun]

update brings the installed schema model current with the packaged catalog. Per installed schema it consults the drift classification and routes by state: an in-sync schema is a no-op; a catalog-ahead schema re-syncs through the migration-aware path; a locally-modified / both-diverged schema is reconciled by a deterministic 3-way merge of base (the as-installed schema body in the object store, keyed by the recorded baseline content_hash) × ours (the installed schema) × theirs (the catalog schema). Disjoint edits auto-merge so both the user's and the catalog's changes survive (required / enum / array-valued type nodes merge as sets).

A schema whose per-path edits cannot be reconciled is left unmodified, and the conflict is SURFACED to the calling agent — update does not spawn a subordinate resolver. The conflict set is returned in the op output (the conflicts array, printed under --json) alongside a readable per-schema report on the default text surface. The report ends with a guidance line; the calling agent reconciles each conflicting schema and commits the reconciliation with pi-context resolve-conflict:

pi-context read-schema --schemaName <name>     # inspect the current installed body
# resolve the conflicting paths into a reconciled draft-07 schema, then commit it:
pi-context resolve-conflict --schemaName <name> --schema '<reconciled-json>'

resolve-conflict writes the reconciled body AND advances the merge base for that schema to the catalog, so the next update sees the schema as locally-modified and its deterministic merge takes the reconciled body (base === theirs → ours) — converging with zero conflicts and preserving the resolution. A bare write-schema does not advance the base, so update would re-report the same conflict on every run. Omit --schema to treat the current on-disk body as already reconciled and only advance the base.

update also additively propagates catalog-new config-registry entries (relation_types / invariants / block_kinds / lenses) absent from the substrate config, preserving every user-authored entry and any locally-diverged body of an existing entry (additive-only — present entries are never overwritten; the added ids are reported under registryAdditions).

A catalog-ahead schema whose resync is refused (blocked) carries its diagnostic under blockedDetail (one entry per blocked schema): the refusal reason — no-migration-chain (no shipped chain reaches the catalog version) vs validation-failed (the forward-migrated items fail the catalog schema) — the installed→catalog version pair, and for a validation failure the per-item failures naming the failing item id, field, and constraint. Under --json the blockedDetail array rides in the op-result envelope; on the default text surface the CLI renders a readable per-schema report below the op output (blocked: <name> (<from> -> <to>) then the no-chain line or the per-item failure lines), ending with a guidance line. A live blocked update also persists a pending-blocked record pinning the target catalog schema, and — for a validation-failed block — writes git-style failure markers INTO the block file at the offending items (full-line <<<<<<< BLOCKED … / >>>>>>> target: … sentinels), pinning the pre-marker bytes (the schema and migrations.json stay byte-unchanged). The resolution loop is: open the block file, fix the items between the markers (or widen the local schema) → pi-context resolve-blocked --schemaName <name>, which strips the markers, re-validates the corrected block against the pinned target and, on pass, writes the target schema + advances the merge base so a subsequent update converges (in-sync) instead of re-blocking. The standalone pi-context validate-block-items --block <name> runs the same per-item check on demand (read-only, returns { block, from?, to?, valid, failures[] }).

--dryRun predicts the precise per-schema outcome (resync / migrate / block / merge / conflict) by running the forward-migration and re-validation in memory, alongside the per-blocked-schema diagnostic detail and the config-registry entries that would be added, and writes nothing.

pi-context update --dryRun                   # predict the precise per-schema outcome (in-memory migrate + re-validate) + config-registry additions
pi-context update                            # apply: resync + auto-merge; conflicts → surfaced (op output + report) for the caller to reconcile + commit via resolve-conflict

Global flags

  • --cwd <dir> — substrate root (default: current working directory; relative paths resolve against it)
  • --json — emit a { ok, op, output } envelope on success ({ ok: false, op, error } on failure) instead of raw output (≡ --format json)
  • --format <text|json|table> — select the output render (default text, or json with --json); see Output rendering
  • --yes, --force — pre-authorize an auth-gated op in a non-interactive context
  • --writer <json> — override the auto-resolved writer identity
  • --show-schema — preview a block op's contract (array key / required fields / field types / id pattern) and exit; see Contract preview + dry-run
  • --dry-run, --dryRun — for append-block-item, validate the prospective file and write nothing; see Contract preview + dry-run
  • --version, -v — print the package version and exit
  • --help, -h — grouped top-level help (ops by command class + a Process modes section), or per-op help after an op name

Writer identity

Ops that declare a writer parameter (e.g. promote-item, write-schema-migration) get it injected automatically when not passed via --writer. The identity is resolved by cascade: git config user.email, then $USER, then the literal "operator". Pass --writer '{"kind":"human","user":"[email protected]"}' to override.

An explicit --writer is validated as a well-formed WriterIdentity: it must carry a kind of human / agent / monitor / workflow and that kind's identifier field as a non-empty string (user for human, agent_id for agent, monitor_name for monitor, workflow_step_id for workflow). A malformed --writer is an error — the CLI no longer silently stamps a garbage identity such as human/undefined.

The CLI builds a DispatchContext from the resolved (or explicit, validated) identity and threads it to every op, so writes stamp created_by / created_at. Filing through the CLI no longer fails on schemas that require author fields. The context builder is exported as buildCliDispatchContext.

Auth-gated ops

Ops marked authGated (writes that mutate config / schemas / migrations) require authorization, mirroring the in-pi dispatch gate:

  • --yes / --force proceeds immediately
  • on an interactive terminal you are prompted (Authorize <op>? [y/N])
  • in a non-interactive context without --yes the op refuses

Exit codes

| Code | Meaning | | --- | --- | | 0 | success | | 1 | op/runtime error, or declined authorization | | 2 | usage error (unknown op, unknown flag, missing required field) | | 3 | schema absent (the block's schema is not installed) | | 4 | id-allocation failure (--autoId could not allocate the next id) | | 5 | schema validation failure |