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

wiki-plugin-terminal

v0.9.24

Published

Federated Wiki plugin — a live shell terminal in the page; successor to wiki-plugin-shell

Readme

Federated Wiki - Terminal Plugin

A live shell terminal in a wiki page — the successor to wiki-plugin-shell, keeping its item text semantics and run-and-capture model, adding an interactive xterm attached to named pty sessions.

Design: Terminal Plugin

How it works

  • Client (src/client/terminal.js): bundles @xterm/xterm with the fit addon, styled for the 400px wiki column. Probes the local pty service; unreachable → code-style display only (public servers), reachable → run / terminal / send / zoom / tab toolbar.
  • Service (service/terminal_service.py): FastAPI router owning ptys keyed by session name. Sessions survive detach (tmux semantics) so the column view, the zoom overlay, and the fullscreen tab share one shell. Spawned zsh emits OSC 133 shell-integration markers; the client scanner turns them into per-command {output, exit} results fired as the terminal-result event on the item.
  • Wiki server (server/server.js): intentionally a no-op — live capabilities are local-first only.

Build

npm install
npm run build        # clean + test + esbuild → client/terminal.{js,css}
npm run dev          # watch mode

Install into a local wiki farm

ln -s $(pwd) <wiki>/node_modules/wiki-plugin-terminal
# add "wiki-plugin-terminal": "^0.1.0" to <wiki>/package.json dependencies
# restart the wiki server

Wire the pty service into the local FastAPI app

cp service/terminal_service.py <fastapi-app-dir>/
# in main.py:
#   from terminal_service import router as terminal_router
#   app.include_router(terminal_router)

Or standalone: uvicorn terminal_service:app --host 127.0.0.1 --port 4288.

The client first looks for the service at http://terminal.localhost (and https://) — a Caddy route on the default ports, per the hitchhiker 42xx port policy. When nothing answers there it tries http://terminal.localhost:4288 directly (since 0.9.5), which is where the Dojo installer runs the service on a newcomer's laptop with no proxy in front. Whichever answers is used for every later call. Browsers resolve *.localhost to loopback on their own, so no hosts-file entry is needed. Port 8000 was abandoned: Bitfocus Companion owns it; 4248 is avoided because other local services use it.

Safari may refuse to let an https page reach plain-http loopback; a page forked into your own local wiki is a local page and works in every browser.

Succession

Legacy shell items can be redirected to this plugin via wiki-client's window.pluginSuccessor table (shell: 'terminal' — one line, precedent mathjax: 'math'). factory.json carries a forward-looking "supersedes": ["shell"] field proposing that the server aggregate succession declarations from plugins into /system/factories.json.

PAGE: a run whose output is a page

A PAGE directive (it implies RUN) treats the run's stdout as page JSON — {title, story, journal?} — and opens it as a ghost page beside the page the item is on, the way the Voice Tool and the Plan Tool open theirs. Fork the ghost to save it. A ghost whose title names a page already on the site is written over that page in place; a script that refreshes a report sends the page's existing journal plus one create action carrying the new story, so the previous report stays one click back in the journal (wiki-client's revision replay restores a whole story from a create), rather than one step per paragraph. ~/bin/pi5-disk-report --page is the first such script.

TIMEOUT: a longer one-shot run

A run from the toolbar (or a RUN/PAGE item, or a workflow step) is a one-shot capture, and the service stops it after 30 seconds. An item that needs longer says so in a leading directive: TIMEOUT: 300, TIMEOUT: 300s, TIMEOUT: 5m or TIMEOUT: 2 min. The service clamps the ask to its own ceiling, 600 seconds unless WIKI_TERMINAL_RUN_TIMEOUT_MAX says otherwise, and the reply names the limit it used and whether the ask was cut down. The client caps the ask at 600 seconds as well, so a page never asks a service older than 0.9.14, which accepts any timeout, for more than a new one would give. A page can ask for time; it cannot grant itself any. Work longer than the ceiling belongs in a live session (BUTTON with SESSION), which has no limit. When a run does time out, the message says which of the two to reach for.

Security

The pty service is remote code execution by design. It binds to 127.0.0.1; Caddy proxies terminal.localhost to it from loopback only, and it is simply absent on public servers, where the plugin renders display-only. Two trusts decide whether a script runs, and they are kept apart.

Page trust — whose text may run. A page of a local site (localhost, *.localhost, or the local mirror farm, where the wiki-security-author client sets window.isLocalMirror) runs as before. A page from any other site runs only if that site is listed in ~/.config/wiki-plugin-terminal/trust.json ({"sites": ["plan.ide.earth"]}, mode 600, reloaded on change) AND the service, fetching the page from that site itself, finds the item text byte-equal to what the browser sent. Publication is the signature: only the site's owner can publish there. A trusted page's toolbar wears a tick and the site's name (a shield for a signed item, a cross for a copy that does not match); a stale or edited copy is refused. Directives travel with the text, so a page cannot strip or alter a GUARD, and service: is honoured on local pages only.

Farm trust — the farm default. Listing every site by hand does not scale on a farm where almost every wiki carries a plan page, so trust.json also takes farms: {"farms": ["https://fab.fish"]}. A farm anchor is a site of your own farm; the service reads the farm's site list from the anchor's /system/api.json (x-fedwiki-farm.sites, Farm plugin ≥ 0.10) and trusts every site on it as if it were in sites. The list is your box's word, so a stranger's site cannot claim its way in; it is refreshed every ten minutes, and an anchor that does not answer contributes nothing. Sites of other people on your farm are still verified by publication, but they are trusted — name the ones you do not want under except: {"farms": ["https://fab.fish"], "except": ["lena.solidarity.quest"]}. Or trust only the sites one login owns there — {"farms": [{"anchor": "https://fab.fish", "owner": "david"}]} — which the service reads from the farm's /system/api/farm/sites.json?owner=david (Farm plugin 0.10.2), so a new site of yours is trusted the moment its owner.json says so and nobody else's ever is. CORS and the consent popup follow the same list, per request, so no restart.

Keyboard trust — the person consents. A request from a non-local origin (the public page itself, opened in a browser on this machine) also needs a grant: the toolbar shows a closed padlock and no run button. The person clicks the padlock, a popup on terminal.localhost asks whether that origin may run verified scripts for 30 minutes, and hands the page an origin-bound HMAC token by postMessage. The padlock opens and the run button appears; clicking the open padlock forgets the grant for that tab. The token lives in that tab's sessionStorage, is sent as a bearer and as the first websocket frame, and dies with the service (the secret is minted at start). Never a cookie. Nothing runs on view: a GUARD on a non-local page is a button, not a poll.

Standing Unlock — your own sites need no padlock (0.9.24). An owner entry under farms may add "standing": true: {"farms": [{"anchor": "https://fab.fish", "owner": "david", "standing": true}]}. Every site that owner has on that farm then passes the keyboard trust with no grant, in every tab and across restarts; the padlock shows open and says so. Publication is still checked on every run, except still removes a site, a whole-farm entry (no owner) never stands, and Lock everything on the Unlock page pauses the standing Unlock until you press Resume there or the service restarts. Turn it off for good by removing the flag.

Claude sessions, read-only. GET /terminal/agents runs claude agents --json on this machine and returns the sessions plus, for each pid the wiki started, the name of its terminal session. It never returns a process environment, and no text from the page runs, so it needs only an allowed origin and the Unlock (or a standing one). The Plan Tool's Claude Sessions face uses it.

Signed items — trust that follows the author. Since 0.9.0 an item may carry a signature ({alg: "bip340", pubkey, created_at, sig}): the item's text, directives included, signed as a nostr event (NIP-01, kind 30078, tags d=fedwiki-item and type=terminal) with a BIP-340 key shown as an npub. A key listed under keys in trust.json ({"npub1…": {"id": "david"}}) passes offline on any site, with no page fetch, and the toolbar reads signed by david; an edited text reads signature stale. The signer is a person: wiki-sign-item keygen --trust makes a key into the login Keychain, wiki-sign-item sign <site> <slug> signs a page's terminal items, wiki-sign-item verify checks them. service/bip340.py is the verifier, pure Python, proven against the official vectors.

The health probe remains the backstop — no service, no toolbar — and the browser adds its own consent when a public https page first reaches a loopback address (Chrome's Local Network Access prompt). The Terminal Trust Plan on the private security wiki records the audit this answers.

License

MIT