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

create-opentray

v0.34.1

Published

Turn any start command that serves HTTP locally into an OpenTray-hosted desktop app.

Readme

create-opentray

Turn any start command that serves HTTP locally — or any http(s) URL — into an OpenTray-hosted desktop app: through a browser wizard or fully non-interactively, without writing OpenTray code.

npx create-opentray

Requires Node >= 20.

Command tree

create-opentray                        # WebUI wizard (compatibility default)
create-opentray web [--port <n>] [--no-open]
create-opentray create [options]       # non-interactive creation
create-opentray app list|edit|copy|export|uninstall
create-opentray skill [list|read]      # packaged English AI skill

Every command accepts --json for a machine-readable typed result on stdout (progress and diagnostics then use stderr only).

Non-interactive create

npx create-opentray create \
  --app-id app.local.mytool \
  --app-name "My Tool" \
  --exec npm --arg run --arg dev \
  --cwd /path/to/project \
  --app-icon https://example.com/logo.png \
  --tray-icon ./tray.png \
  --pm npm
  • --arg is repeatable; each value is ONE exact argv element — never a shell string (&& stays a literal argument).
  • --url <address> packages the http(s) URL directly as an application (no command): npx create-opentray create --url https://example.com derives the app id/name from the address (https://example.com/app → app.com.example / App); override with --app-id/--app-name. It is mutually exclusive with --exec/--arg/--cwd/--env, and the generated app opens one window at the address with no terminal or PTY. Because the address is known up front (unlike a command that must run first), creation scrapes the page once and adopts its <title> and best favicon as defaults — explicit flags always win, failures fall back silently (address-derived name + glyph icon), and --no-scrape disables the fetch.
  • Window options (--toolbar, URL and command applications): --toolbar composes the native navigation toolbar over the target/service page — one toolbar webview at a fixed top strip (back/forward/reload buttons, address input, and the ⌘/Ctrl+←→, ⌘/Ctrl+[], ⌘/Ctrl+R, F5, ⌘/Ctrl+L shortcuts while the toolbar holds native focus) plus one content webview loading the address directly as a top-level browsing context. The address bar follows the content webview's URL events as its source of truth, and back/forward drive the content webview's native history. Embedding policy is never consulted — an embedding-hostile site renders the same as any other address because the content webview is not an embedded context; creation does not probe, warn about, or downgrade the toolbar request. Toolbar mode is off by default and maps to the single canonical window.toolbar config field (the legacy showAddressBar input no longer exists; stale occurrences in old frozen configs are ignored). Every URL app's tray menu offers Reload regardless of toolbar mode. By default the window title follows the page (--no-title-follow to stop) and the icon does NOT follow favicon changes at runtime (--icon-follow to enable); both persist in the v1 config and round-trip through export.
  • Icon sources: local files, http(s) URLs, or data: URLs. Outside URL-mode enrichment the CLI never scrapes names or favicons.
  • --config <file> loads a complete v1 document; explicit flags override only their named fields.
  • --dry-run prints the plan without mutating anything.
  • --force replaces only a VERIFIED create-opentray payload — it never adopts or clears a user directory.
  • --no-image-smoothing renders icons with nearest-neighbor sampling (pixel-art safe: enlarged app/tray icons keep hard edges).
  • --developer-mode admits WebView DevTools in the generated app (default off; it means nothing else).
  • --window <WxH> sets the window size (default 1200x800).

The v1 registry layout

~/.opentray/create/<encoded-app-id>/
  create-opentray.json      # the SOLE editable authority (schemaVersion 1)
  app/                      # generated payload (managed dir, or a link)
  app-icon.<ext>            # committed icon snapshots (hash-verified)
  tray-icon.<ext>

create-opentray.json is the only file you edit: identity/name, exact command vector (executable/args/cwd/env), package manager, icon resource references with content hashes and provenance, icon-rendering options (including imageSmoothingEnabled), window options, and developerMode. Generated files are derived output and are regenerated on every apply.

Key rules:

  • appId is immutable — a new identity is app copy, never an edit.
  • The registry root is fixed at ~/.opentray/create/.
  • Snapshots are stable — URL-fetched icons are committed locally; later URL drift never changes an existing registration.
  • Breaking boundary: projects identified only by the older opentray.app.json marker are not discovered, listed, or migrated.

Managing applications

npx create-opentray app list
npx create-opentray app edit app.local.mytool --app-name "Renamed" --force
npx create-opentray app copy app.local.mytool --new-app-id app.local.tool2
npx create-opentray app export app.local.mytool --format sh -o make.sh
npx create-opentray app uninstall app.local.mytool
  • app list reports health: healthy, invalid-config, incompatible-version, missing-payload, broken-link, or running, with registration and payload paths.
  • A running instance blocks edits/uninstalls with a typed app_running result until --stop-running is passed. Processes are terminated only when the recorded PID, ownership token, and start fingerprint still match; a reused PID is refused, never killed.
  • app uninstall retains a linked external target unless --purge-target explicitly authorizes deletion after revalidation. macOS Dock pins and Windows taskbar pins are user-managed.

Export

app export produces a complete recreation artifact:

  • --format command — exact argv command line (uploads embed as data URLs only with --force-copy).
  • --format sh / --format ps1 — self-contained scripts (LF / CRLF); uploaded icon bytes are embedded and reconstructed into a temp file before invocation.
  • Any environment entry makes complete export require --acknowledge-env. create-opentray never guesses which values are sensitive — it always asks once, and never echoes env values in ordinary output.

WebUI wizard

create-opentray (or create-opentray web) starts a token-guarded WebUI on 127.0.0.1 and opens your browser: paste a start command, watch it run in a real interactive terminal, confirmed HTTP services open as tabs, and identity/icon defaults are suggested from the served page (every suggestion is a placeholder you can override). The wizard speaks the same Core as the CLI, so both produce identical plans.

Generated project

The entry (main.mjs) spawns the recorded command (output → app.log), continuously discovers the command's OWNED HTTP listening ports (foreign listeners such as browser DevTools sockets are never adopted), hosts each verified port in an application-mode WebView window, and owns the tray session (Quit lives in the tray menu). Optional startup-terminal and navigation-toolbar (--toolbar) shells are available through the wizard's advanced options and the CLI; the toolbar composes a native toolbar webview above each service window's content webview.

Platform notes

  • macOS: the stable .app bundle is materialized by the OpenTray runtime on first launch; pin it to the Dock (removing a pin is manual).
  • Windows: directory links use junctions (or symlinks when permitted); failure is a typed error, never a silent copy. The appMode window joins the taskbar/Alt-Tab. Native acceptance runs on Windows agents — non-Windows fixtures are preparatory evidence only.
  • Linux: taskbar pinning depends on the desktop environment.

AI skill

The package ships an English AI skill (skill/) readable without any network access:

npx create-opentray skill                 # read SKILL.md
npx create-opentray skill list references # list one directory
npx create-opentray skill read SKILL.md   # read any packaged file

Skill access is read-only and contained: absolute paths, .. traversal, NUL bytes, and symlink escapes are rejected before any filesystem read, and the output is always the canonical English tree regardless of host locale.

Programmatic use

import { createWizardSession, deriveDefaultAppId } from "create-opentray";

See the package's TypeScript definitions (dist/index.d.mts) for the full surface (wizard session, server, discovery, scraping, launch-vector resolution, scaffold, materialize).