Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 30 additions & 11 deletions .cursor/skills/runly/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@ name: runly
description: >-
Runs the same Node.js command under multiple Node versions from one config file
(runly.config.mjs/js/cjs), resolving each runtime via npx and the npm `node`
package. Use when the user mentions Runly, @hamdymohamedak/runly, multi-version
Node testing, Node matrix in CI, runly.config, or running tests across Node 18/20/22.
package. Use `runly init` to scaffold config and npm script; use `loadConfig()` in code.
Use when the user mentions Runly, @hamdymohamedak/runly, multi-version Node testing,
Node matrix in CI, runly.config, or running tests across Node 18/20/22.
---

# Runly

## What it is

- **npm package**: `@hamdymohamedak/runly` (scoped; unscoped name `runly` is blocked on npm as too similar to `runjs`).
- **CLI binary name**: `runly` (after `npm install`, use `npx runly` from the project root).
- **CLI binary name**: `runly` — use **`npx runly init`** once to create config + **`npm run runly`**, or **`npx runly`** for one-off runs.
- **Purpose**: For each entry in `versions`, resolve a real `node` binary for that spec, prepend its directory to `PATH`, then spawn the configured command so that command’s default `node` is that matrix version—without requiring nvm/fnm/asdf on the machine.

## Requirements
Expand All @@ -30,8 +31,25 @@ One-off without saving to `package.json`:

```bash
npx @hamdymohamedak/runly
npx @hamdymohamedak/runly init
```

## `runly init` (scaffold)

From the **project root** (after **`npm install -D @hamdymohamedak/runly`**):

```bash
npx runly init
```

- Creates **`runly.config.js`** only if none of **`runly.config.mjs`**, **`runly.config.js`**, or **`runly.config.cjs`** exists (otherwise prints a message and exits **0**).
- Writes **`SKILL.md`** in the project root when missing (Cursor agent skill template from the package); you may move it to **`.cursor/skills/runly/SKILL.md`**.
- Uses **`export default`** when **`package.json`** has **`"type": "module"`**, else **`module.exports`**.
- Adds **`"runly": "runly"`** under **`scripts`** in **`package.json`** when the file exists and **`scripts.runly`** is not already set.
- Default **`run`** in the scaffold is a small **`node -e`** smoke command; edit to **`node --test`**, **`npm test`**, etc.

Programmatic: **`initRunlyProject(cwd)`** from **`@hamdymohamedak/runly`**.

## Config file discovery

From **current working directory**, first file that exists:
Expand All @@ -40,7 +58,7 @@ From **current working directory**, first file that exists:
2. `runly.config.js`
3. `runly.config.cjs`

Override: `runly -c /path/to/config.mjs` or `runly --config /path/to/config.mjs`.
Override: `runly -c /path/to/config.mjs` or `runly --config /path/to/runly.config.mjs`.

Config must be **JavaScript** (ESM or CJS). Runly does **not** load `.ts` configs unless the user wires a loader themselves. Export **`default`** as the config object (or the module’s default export after dynamic `import()`).

Expand Down Expand Up @@ -95,15 +113,16 @@ export default defineConfig({
});
```

Exported types: **`RunlyConfig`**, **`RunlyRun`**. The matrix runner **`runMatrix`** lives in source but is **not** part of the published `exports`—treat **`defineConfig` + types** as the library surface for dependents.
Exported types: **`RunlyConfig`**, **`RunlyRun`**. **`loadConfig(cwd?)`** loads the default config or throws with a hint to run **`npx runly init`**. The matrix runner **`runMatrix`** is not exported—use the CLI or compose from source.

## CLI

| Flag | Meaning |
|------|---------|
| Command / flag | Meaning |
|----------------|---------|
| `runly init` | Scaffold **`runly.config.js`**, **`SKILL.md`** (if missing), and **`scripts.runly`** (see above). |
| `runly` | Run matrix using config in cwd. |
| `-c`, `--config` | Path to config file. |

No other flags in the current CLI.
| `runly help` | Usage. |

## Exit codes

Expand All @@ -118,7 +137,7 @@ No other flags in the current CLI.

## CI

Install deps, `cd` to repo root (or set `cwd` in config), run `npx runly`. No global version manager required if `npx` can fetch the `node` package.
Install deps, `cd` to repo root, run **`npx runly init`** once if the repo has no config, then **`npm run runly`** or **`npx runly`**. No global version manager required if `npx` can fetch the `node` package.

## Limitations

Expand All @@ -129,7 +148,7 @@ Install deps, `cd` to repo root (or set `cwd` in config), run `npx runly`. No gl
## Reference in this repo

- User-facing docs: [README.md](../../../README.md)
- Working demo: [matrix-demo/](../../../matrix-demo/) (`npm install` + `npm run matrix` from that folder; uses `file:..` to depend on the parent package).
- Example config: [examples/all-versions-pass/runly.config.mjs](../../../examples/all-versions-pass/runly.config.mjs)

## Links

Expand Down
43 changes: 31 additions & 12 deletions .cursor/skills/runly/skill/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@ name: runly
description: >-
Runs the same Node.js command under multiple Node versions from one config file
(runly.config.mjs/js/cjs), resolving each runtime via npx and the npm `node`
package. Use when the user mentions Runly, @hamdymohamedak/runly, multi-version
Node testing, Node matrix in CI, runly.config, or running tests across Node 18/20/22.
package. Use `runly init` to scaffold config and npm script; use `loadConfig()` in code.
Use when the user mentions Runly, @hamdymohamedak/runly, multi-version Node testing,
Node matrix in CI, runly.config, or running tests across Node 18/20/22.
---

# Runly

## What it is

- **npm package**: `@hamdymohamedak/runly` (scoped; unscoped name `runly` is blocked on npm as too similar to `runjs`).
- **CLI binary name**: `runly` (after `npm install`, use `npx runly` from the project root).
- **CLI binary name**: `runly` — use **`npx runly init`** once to create config + **`npm run runly`**, or **`npx runly`** for one-off runs.
- **Purpose**: For each entry in `versions`, resolve a real `node` binary for that spec, prepend its directory to `PATH`, then spawn the configured command so that command’s default `node` is that matrix version—without requiring nvm/fnm/asdf on the machine.

## Requirements
Expand All @@ -30,8 +31,25 @@ One-off without saving to `package.json`:

```bash
npx @hamdymohamedak/runly
npx @hamdymohamedak/runly init
```

## `runly init` (scaffold)

From the **project root** (after **`npm install -D @hamdymohamedak/runly`**):

```bash
npx runly init
```

- Creates **`runly.config.js`** only if none of **`runly.config.mjs`**, **`runly.config.js`**, or **`runly.config.cjs`** exists (otherwise prints a message and exits **0**).
- Writes **`SKILL.md`** in the project root when missing (Cursor agent skill template from the package); you may move it to **`.cursor/skills/runly/SKILL.md`**.
- Uses **`export default`** when **`package.json`** has **`"type": "module"`**, else **`module.exports`**.
- Adds **`"runly": "runly"`** under **`scripts`** in **`package.json`** when the file exists and **`scripts.runly`** is not already set.
- Default **`run`** in the scaffold is a small **`node -e`** smoke command; edit to **`node --test`**, **`npm test`**, etc.

Programmatic: **`initRunlyProject(cwd)`** from **`@hamdymohamedak/runly`**.

## Config file discovery

From **current working directory**, first file that exists:
Expand All @@ -40,7 +58,7 @@ From **current working directory**, first file that exists:
2. `runly.config.js`
3. `runly.config.cjs`

Override: `runly -c /path/to/config.mjs` or `runly --config /path/to/config.mjs`.
Override: `runly -c /path/to/config.mjs` or `runly --config /path/to/runly.config.mjs`.

Config must be **JavaScript** (ESM or CJS). Runly does **not** load `.ts` configs unless the user wires a loader themselves. Export **`default`** as the config object (or the module’s default export after dynamic `import()`).

Expand Down Expand Up @@ -95,15 +113,16 @@ export default defineConfig({
});
```

Exported types: **`RunlyConfig`**, **`RunlyRun`**. The matrix runner **`runMatrix`** lives in source but is **not** part of the published `exports`—treat **`defineConfig` + types** as the library surface for dependents.
Exported types: **`RunlyConfig`**, **`RunlyRun`**. **`loadConfig(cwd?)`** loads the default config or throws with a hint to run **`npx runly init`**. The matrix runner **`runMatrix`** is not exported—use the CLI or compose from source.

## CLI

| Flag | Meaning |
|------|---------|
| Command / flag | Meaning |
|----------------|---------|
| `runly init` | Scaffold **`runly.config.js`**, **`SKILL.md`** (if missing), and **`scripts.runly`** (see above). |
| `runly` | Run matrix using config in cwd. |
| `-c`, `--config` | Path to config file. |

No other flags in the current CLI.
| `runly help` | Usage. |

## Exit codes

Expand All @@ -118,7 +137,7 @@ No other flags in the current CLI.

## CI

Install deps, `cd` to repo root (or set `cwd` in config), run `npx runly`. No global version manager required if `npx` can fetch the `node` package.
Install deps, `cd` to repo root, run **`npx runly init`** once if the repo has no config, then **`npm run runly`** or **`npx runly`**. No global version manager required if `npx` can fetch the `node` package.

## Limitations

Expand All @@ -128,8 +147,8 @@ Install deps, `cd` to repo root (or set `cwd` in config), run `npx runly`. No gl

## Reference in this repo

- User-facing docs: [README.md](../../../README.md)
- Working demo: [matrix-demo/](../../../matrix-demo/) (`npm install` + `npm run matrix` from that folder; uses `file:..` to depend on the parent package).
- User-facing docs: [README.md](../../../../README.md)
- Example config: [examples/all-versions-pass/runly.config.mjs](../../../../examples/all-versions-pass/runly.config.mjs)

## Links

Expand Down
8 changes: 6 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Cross-OS × host Node matrix: build Runly, run smoke tests, execute Runly against
# multiple Node runtimes via npx (no nvm on the runner).
# Cross-OS × host Node matrix: build Runly, verify `runly init` scaffolds a consumer
# (runly.config.js + scripts.runly + npm run runly) from the packed tarball, smoke tests,
# then Runly e2e against multiple Node runtimes via npx (no nvm on the runner).
name: CI

on:
Expand Down Expand Up @@ -39,6 +40,9 @@ jobs:
- name: Typecheck / build
run: npm run build

- name: runly init scaffold (pack tarball → CJS & ESM consumers → npm run runly)
run: npm run ci:verify-init

- name: Unit smoke (repo test/)
run: node --test test/smoke.test.js

Expand Down
30 changes: 26 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,35 @@ npm install -D @hamdymohamedak/runly

The executable name is **`runly`** (see `bin` in `package.json`).

### First-time setup (`init`)

From your project root, create a default `runly.config.js`, a **`SKILL.md`** agent-skill template (when `SKILL.md` is not already present), and add an npm script **`runly`** when `package.json` exists:

```bash
npx runly init
```

If any of `runly.config.mjs`, `runly.config.js`, or `runly.config.cjs` already exists, `init` does nothing for the config (idempotent). Existing **`SKILL.md`** is never overwritten.

### Run the matrix

From the directory that contains your config:

```bash
npx runly
```

Or, after `init`:

```bash
npm run runly
```

Without adding a dev dependency:

```bash
npx @hamdymohamedak/runly
npx @hamdymohamedak/runly init # scaffold config in cwd
```

---
Expand Down Expand Up @@ -114,15 +133,18 @@ export default defineConfig({
});
```

Exported types include `RunlyConfig` and `RunlyRun` for use in your own tooling.
Exported types include `RunlyConfig` and `RunlyRun`. **`loadConfig(cwd?)`** loads the first config file in `cwd` (same discovery as the CLI) or throws with a hint to run **`npx runly init`**. **`initRunlyProject(cwd?)`** is the programmatic equivalent of **`runly init`**.

---

## CLI

| Flag | Description |
|------|-------------|
| Command / flag | Description |
|----------------|-------------|
| `runly init` | Create `runly.config.js` with defaults, copy **`SKILL.md`** when missing, and add `"runly": "runly"` to `package.json` when present. No-op for config if a config file already exists. |
| `runly`, `runly -c <path>` | Run the matrix (search for config in cwd, or use `-c` / `--config`). |
| `-c`, `--config` | Path to a config file. If omitted, Runly searches for `runly.config.mjs`, then `.js`, then `.cjs` in the current working directory. |
| `runly help` | Print usage. |

---

Expand All @@ -147,7 +169,7 @@ On Windows, `npx.cmd` is used for the resolution step.

## Continuous integration

Install dependencies as usual, ensure Node and npm are available, then invoke `npx runly` (or `npx @hamdymohamedak/runly`) from the repository root where the config lives. No extra global Node switcher is required on the runner image as long as `npx` can fetch the `node` package.
Install dependencies as usual, ensure Node and npm are available. If the repo has no Runly config yet, run **`npx runly init`** once at the root (or commit a config file). Then invoke **`npx runly`** (or **`npm run runly`**) from the repository root. No extra global Node switcher is required on the runner image as long as `npx` can fetch the `node` package.

---

Expand Down
43 changes: 30 additions & 13 deletions dist/cli.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion dist/cli.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading