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

@super-repo/rune

v0.2.0

Published

Rune — runtime script orchestrator. Move package.json scripts into a shareable, sectioned config file.

Downloads

1,821

Readme

@super-repo/rune

Rune — runtime script orchestrator. Replace package.json#scripts with a shareable, comment-friendly config file that supports sequential commands, per-script env, and .env.<name> overlays.

Why

package.json#scripts is a flat string-only map: no comments, no grouping, no way to share a chunk of build/test commands across packages. Rune keeps that flat shape (so pnpm exec rune <name> still feels like pnpm <name>) but lets each value be a string, an array, or a rich object — and pulls descriptions straight from your source-file comments.

Install

pnpm add -D @super-repo/rune

Quick start

Scaffold a config (imports your existing package.json scripts if any):

pnpm exec rune init

Drop in a rune.config.ts:

export default {
  scripts: {
    build: 'tsc -p config/tsconfig.build.json',     // Compile this package
    test: 'vitest run',                             // Run vitest once

    clean: ['rm -rf dist', 'rm -rf .nx'],           // sequential, stop on first failure

    publish: {                                      // rich object form
      run: 'npm publish',
      description: 'Publish with provenance metadata',
      env: { NPM_CONFIG_PROVENANCE: 'true' },
    },
  },
}

Run any script:

pnpm exec rune build              # → tsc -p ...
pnpm exec rune build -- --watch   # forward extra args to the underlying command
pnpm exec rune list               # print every script with its description
pnpm exec rune init               # scaffold rune.config.ts (imports package.json#scripts)
pnpm exec rune sync               # mirror rune scripts → package.json as 'rune <name>' proxies

Script value forms

Each entry in scripts may be:

| Form | Example | When to use | | --- | --- | --- | | string | test: 'vitest run' | Single command — drop-in for what you'd put in package.json#scripts. | | string[] | release: ['nx version', 'nx changelog', 'nx publish'] | Sequential commands, stops on first non-zero exit. | | object | { run, description?, cwd?, env? } | When a script needs its own cwd, env overlay, or an explicit description. run accepts string or string[]. |

Trailing // comment (or a single // comment line directly above the entry) becomes the description shown by rune list. Multi-line prose belongs in a /* … */ block — section dividers stacked above a key are intentionally ignored so they don't get pulled into the description.

{
  scripts: {
    // ─── build ────────────  (section divider — ignored)
    // Compile every package    ← this becomes build's description
    build: 'nx run-many -t build',

    test: 'vitest run', // Run unit tests once
  },
}

Env-file overlay

Pass -e <name> (or --env <name>) to load an env file before the script runs. Files resolve against the package root — the closest package.json walking up from cwd:

pnpm exec rune dev:cli -e dev    # loads <packageRoot>/.env.dev
pnpm exec rune dev:cli -e prod   # loads <packageRoot>/.env.prod
pnpm exec rune dev:cli -e ./custom.env   # explicit path

Pin custom locations via envFiles in the config:

export default {
  envFiles: {
    dev: '.env.dev',
    prod: 'env/prod.env',
    test: '/abs/path/.env.test',
  },
  scripts: {
    'dev:cli': 'tsx src/main.ts',
  },
}

Layering — last write wins:

  1. host process.env (real shell exports always win)
  2. config-level env
  3. per-script env (rich form)
  4. file picked by -e (only fills keys not yet set)

Top-level options

| Option | Type | Purpose | | -------------- | --------------------------------- | -------------------------------------------------------------------- | | scripts | Record<string, ScriptSpec> | Required. Flat map of script name → command(s). | | extends | string \| string[] | Inherit + override scripts from another rune config. | | shell | string | Shell to use (default: /bin/sh on POSIX). Set to 'bash' for arrays. | | defaultCwd | string | Default cwd for every script. Relative paths resolve against the config file. | | env | Record<string, string> | Env vars injected into every script run. | | envFiles | Record<string, string> | Map --env <name> → path (relative to the package root). | | descriptions | Record<string, string> | Override / supply descriptions when comments aren't possible (JSON configs). |

CLI

rune                          List all scripts (default when no subcommand)
rune list                     Same as above, with comment descriptions
rune <name> [args...]         Run a script
rune <name> -- <raw args>     Forward raw args to the underlying command
rune init                     Scaffold rune.config.ts (imports package.json#scripts)
rune sync                     Mirror rune scripts → package.json as 'rune <name>' proxies
rune --ai <request>           Interpret a free-form request: pick the best
                              existing script, or generate one ad-hoc and run it
rune --ai-suggest <request>   Same as --ai but only print the suggestion (no exec)

Options:
  -c, --config <path>         Path to rune.config.{ts,js,mjs,json}
  -e, --env <name|path>       Load .env file before running
      --no-banner             Skip the banner on list/init/sync output
  -h, --help                  Show this message

rune sync keeps pnpm <name> working for everyone who hasn't installed rune yet — it writes "<name>": "rune <name>" proxies into package.json#scripts while preserving lifecycle keys (prepare, postinstall, preinstall).

Config discovery

Rune resolves its config in this order:

  1. -c <path> if passed on the command line.
  2. rune.config.{ts,mjs,js,cjs,json} in the current working directory.
  3. The closest package.json walking up from cwd — read its rune field.

The package.json fallback accepts three shapes:

// (a) Single config file
{
  "rune": {
    "config": "./rune.config.ts"
  }
}

// (b) Array of config files — loaded in order, merged left-to-right
//     (later overlays earlier; each entry may have its own `extends`)
{
  "rune": {
    "config": ["./shared/base.config.ts", "./local/overrides.ts"]
  }
}

// (c) Inline config (with optional `extends`, resolved relative to package.json)
{
  "rune": {
    "extends": "./shared/base.config.ts",
    "scripts": {
      "lint:custom": "eslint . --fix"
    }
  }
}

This makes rune's config sit alongside super and czar blocks in a single package.json — useful when a package wants one canonical place for tooling config.

Extending configs

Any rune config (file or package.json inline) can declare an extends field — same idea as tsconfig.json. Relative paths resolve against the config file's directory (or the package.json's directory for inline blocks).

// rune.config.ts
import { defineConfig } from '@super-repo/rune'

export default defineConfig({
  extends: './shared/base.config.ts',
  // or: extends: ['./shared/base.config.ts', './shared/lint-presets.ts'],
  scripts: {
    'lint:custom': 'eslint . --fix',
  },
})

Merge semantics: later configs overlay earlier ones; scripts, env, descriptions shallow-merged per key; shell / defaultCwd / etc. last-defined wins. Circular extends chains throw RuneConfigError.

AI mode

When a free-form request doesn't map to an obvious script, rune can ask Claude to either pick the best existing script or generate a new shell command on the fly:

export ANTHROPIC_API_KEY=...

rune --ai build a docker image and tag it as latest
rune --ai-suggest "lint everything and fix what you can"
rune --ai="ship the demo branch to staging"

Behavior:

  • Claude returns strict JSON: matched (existing script name), generated (new shell command + suggested name), or unsure.
  • --ai runs the matched/generated command. Successful generated runs print a tip showing how to save the new command as a permanent script.
  • --ai-suggest only prints the proposal — no execution. Useful for discovery and CI.

The model defaults to claude-sonnet-4-6; the request is the verbatim natural-language input, and the system prompt anchors Claude to either pick an existing script or produce a portable POSIX shell command (no sudo, no destructive ops outside the project).

Use with NX

For monorepos that drive builds through NX, point each project's project.json at the shared rune config via nx:run-commands:

{
  "name": "@super-repo/cli",
  "targets": {
    "build": {
      "executor": "nx:run-commands",
      "options": {
        "command": "rune -c ../../config/rune.config.ts build",
        "cwd": "{projectRoot}"
      },
      "dependsOn": ["^build", "@super-repo/rune:build"],
      "outputs": ["{projectRoot}/dist"],
      "cache": true
    }
  }
}

The shared config can then expose generic build / test keys that work cwd-relative for every package, plus workspace-wide variants (build:all, test:all).

Examples

Live, runnable configs covering every feature live in examples/:

| File | Demonstrates | | --- | --- | | basic.config.ts | Shorthand strings + arrays. | | expanded.config.ts | Rich object form (cwd, env, description). | | env-files.config.ts | envFiles map plus -e <name> invocation. | | .env.dev, .env.prod, .env.test | Sample env files referenced by the env-files example. |

pnpm exec rune -c packages/rune/examples/env-files.config.ts env:show -e dev

Programmatic API

import {
  loadConfig,
  runScript,
  findScript,
  renderList,
  loadEnvByName,
} from '@super-repo/rune'

const { config, path } = (await loadConfig({ cwd: process.cwd() }))!
const { spec } = findScript(config, 'build')!
const result = await runScript({ config, configPath: path, script: spec })
process.exit(result.exitCode)

Full surface — including parseConfig, extractDescriptionsFromSource, findPackageRoot, and syncToPackageJson — is exported from src/index.ts.