# @super-repo/rune

> Runtime script orchestrator — a comment-friendly replacement for `package.json#scripts` that supports sequential commands, per-script env, and `.env.<name>` overlays.

[![NPM](https://nodei.co/npm/@super-repo/rune.png?downloads=true&downloadRank=true&stars=true)](https://www.npmjs.com/package/@super-repo/rune)

[![npm version](https://img.shields.io/npm/v/@super-repo/rune.svg)](https://www.npmjs.com/package/@super-repo/rune)
[![npm downloads](https://img.shields.io/npm/dm/@super-repo/rune.svg)](https://www.npmjs.com/package/@super-repo/rune)
[![license](https://img.shields.io/npm/l/@super-repo/rune.svg)](./LICENSE)

`package.json#scripts` is a flat string-only map: no comments, no grouping, no rich shape, no way to share commands across packages. Rune keeps the flat shape (so `npx 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.

It's a small library + a CLI: the CLI runs scripts and scaffolds configs; the library powers everything you'd want from a programmatic runner.

## Getting started

```sh
pnpm add -D @super-repo/rune
```

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

export default defineConfig({
  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: {
      run: 'npm publish',
      description: 'Publish with provenance metadata',
      env: { NPM_CONFIG_PROVENANCE: 'true' },
    },
  },
})
```

```sh
npx rune build              # → tsc -p ...
npx rune build -- --watch   # forward extra args to the underlying command
npx rune list               # print every script with its description
```

For everything else — full schema, env-file overlays, AI mode, hook recipes — see [Docs](#docs).

## Features

- **Comment-friendly config** — trailing `// comment` and leading single-line comments become script descriptions in `rune list`. JSON configs use a `descriptions:` map.
- **Three script shapes** — string, string-array (sequential, stop on first failure), or rich object with its own `cwd` / `env` / `description`.
- **`.env.<name>` overlays** — pass `-e dev` to load `.env.dev` from the package root before the script runs. Pin custom paths with `envFiles:`.
- **Shared configs via `extends`** — same idea as `tsconfig.json`. Inherit a base config and overlay package-specific scripts.
- **Lives in `package.json` too** — drop a `rune` block in `package.json` (single file, array, or inline) so all tooling config sits in one place.
- **`rune sync`** — mirror rune scripts back to `package.json#scripts` as `rune <name>` proxies so `pnpm <name>` keeps working for anyone who hasn't installed rune yet.
- **`rune --ai <request>`** — let Claude pick the best existing script or generate one ad-hoc for a free-form prompt.

## CLI

| command                       | what it does                                                          |
| ----------------------------- | --------------------------------------------------------------------- |
| `rune` / `rune list`          | List every script with its description.                               |
| `rune <name> [args]`          | Run a script. Anything after `--` is forwarded verbatim.              |
| `rune init`                   | Scaffold `rune.config.ts` (imports existing `package.json#scripts`).  |
| `rune sync`                   | Mirror rune scripts → `package.json` as `rune <name>` proxies.        |
| `rune --ai <request>`         | Interpret a free-form request and run the matched/generated command.  |
| `rune --ai-suggest <request>` | Same as `--ai` but only print the proposal (no exec).                 |

Global flags: `-c <path>`, `-e <name|path>`, `--no-banner`, `-h`. Full reference: [docs/cli.md](./docs/cli.md).

## Comparison

| capability                          | `package.json#scripts` | `npm-run-all` | `concurrently` | `@super-repo/rune` |
| ----------------------------------- | :--------------------: | :-----------: | :------------: | :----------------: |
| Flat name → command shape           | ✓                      | ✓             | ✗              | ✓                  |
| Comments / descriptions             | ✗                      | ✗             | ✗              | ✓                  |
| Sequential array form               | ✗ (chained `&&`)       | ✓             | ✗              | ✓                  |
| Per-script `cwd` / `env` overlay    | ✗                      | ✗             | ✗              | ✓                  |
| `.env.<name>` overlays via `-e`     | ✗                      | ✗             | ✗              | ✓                  |
| Shared config via `extends`         | ✗                      | ✗             | ✗              | ✓                  |
| AI script suggestion                | ✗                      | ✗             | ✗              | ✓                  |

Rune is the smallest possible step beyond `package.json#scripts` that gives you comments, grouping, and per-script env overlays — without dragging in a build-graph runner.

## Use from hooks and CI

Rune itself is a runner, not a gate — but the scripts you put in it are what your hooks and CI jobs end up calling. Use `npx rune <script>` so the same incantation works for npm, pnpm, yarn, and bun consumers:

```sh
# .husky/pre-commit
npx rune lint
npx rune test
```

See [docs/integrations.md](./docs/integrations.md) for Husky, lefthook, simple-git-hooks, native-git, and GitHub Actions recipes.

## Embedding

The library API is exported from the package root. Drive rune programmatically:

```ts
import { loadConfig, findScript, runScript } 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`, `loadEnvByName`, `syncToPackageJson`, and `interpretRequest` — see [docs/library-api.md](./docs/library-api.md).

## Docs

Deep references and worked examples live alongside this package in [./docs/](./docs/):

- **[configuration.md](./docs/configuration.md)** — every top-level option, the three script value forms, comments-as-descriptions.
- **[discovery.md](./docs/discovery.md)** — config resolution order, `package.json` fallback shapes, `extends` merge semantics.
- **[env-files.md](./docs/env-files.md)** — `-e <name>` overlay, `envFiles:` map, layering rules.
- **[cli.md](./docs/cli.md)** — full CLI synopsis and per-flag reference.
- **[ai.md](./docs/ai.md)** — `rune --ai` / `--ai-suggest` behaviour and Anthropic auth.
- **[recipes.md](./docs/recipes.md)** — runnable examples and NX integration.
- **[integrations.md](./docs/integrations.md)** — Husky / lefthook / simple-git-hooks / native-git / GitHub Actions recipes.
- **[library-api.md](./docs/library-api.md)** — every exported function and type.

## References

- [Project README](../../../README.md)
- [Related package: @super-repo/cli](../cli) — the `super` linked-repos CLI rune sits alongside.
- [Related package: @super-repo/envx](../../envx/core) — workspace-aware env-file loader; pairs naturally with `rune -e <name>`.

## License

MIT — see [LICENSE](./LICENSE).
