Skip to content

Commit 750784d

Browse files
Merge pull request #1 from hamdymohamedak/main
Implement runly init CLI and improve postinstall configuration
2 parents 9411657 + 71788b7 commit 750784d

28 files changed

Lines changed: 743 additions & 64 deletions

.cursor/skills/runly/SKILL.md

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,17 @@ name: runly
33
description: >-
44
Runs the same Node.js command under multiple Node versions from one config file
55
(runly.config.mjs/js/cjs), resolving each runtime via npx and the npm `node`
6-
package. Use when the user mentions Runly, @hamdymohamedak/runly, multi-version
7-
Node testing, Node matrix in CI, runly.config, or running tests across Node 18/20/22.
6+
package. Use `runly init` to scaffold config and npm script; use `loadConfig()` in code.
7+
Use when the user mentions Runly, @hamdymohamedak/runly, multi-version Node testing,
8+
Node matrix in CI, runly.config, or running tests across Node 18/20/22.
89
---
910

1011
# Runly
1112

1213
## What it is
1314

1415
- **npm package**: `@hamdymohamedak/runly` (scoped; unscoped name `runly` is blocked on npm as too similar to `runjs`).
15-
- **CLI binary name**: `runly` (after `npm install`, use `npx runly` from the project root).
16+
- **CLI binary name**: `runly` — use **`npx runly init`** once to create config + **`npm run runly`**, or **`npx runly`** for one-off runs.
1617
- **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.
1718

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

3132
```bash
3233
npx @hamdymohamedak/runly
34+
npx @hamdymohamedak/runly init
3335
```
3436

37+
## `runly init` (scaffold)
38+
39+
From the **project root** (after **`npm install -D @hamdymohamedak/runly`**):
40+
41+
```bash
42+
npx runly init
43+
```
44+
45+
- 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**).
46+
- 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`**.
47+
- Uses **`export default`** when **`package.json`** has **`"type": "module"`**, else **`module.exports`**.
48+
- Adds **`"runly": "runly"`** under **`scripts`** in **`package.json`** when the file exists and **`scripts.runly`** is not already set.
49+
- Default **`run`** in the scaffold is a small **`node -e`** smoke command; edit to **`node --test`**, **`npm test`**, etc.
50+
51+
Programmatic: **`initRunlyProject(cwd)`** from **`@hamdymohamedak/runly`**.
52+
3553
## Config file discovery
3654

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

43-
Override: `runly -c /path/to/config.mjs` or `runly --config /path/to/config.mjs`.
61+
Override: `runly -c /path/to/config.mjs` or `runly --config /path/to/runly.config.mjs`.
4462

4563
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()`).
4664

@@ -95,15 +113,16 @@ export default defineConfig({
95113
});
96114
```
97115

98-
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.
116+
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.
99117

100118
## CLI
101119

102-
| Flag | Meaning |
103-
|------|---------|
120+
| Command / flag | Meaning |
121+
|----------------|---------|
122+
| `runly init` | Scaffold **`runly.config.js`**, **`SKILL.md`** (if missing), and **`scripts.runly`** (see above). |
123+
| `runly` | Run matrix using config in cwd. |
104124
| `-c`, `--config` | Path to config file. |
105-
106-
No other flags in the current CLI.
125+
| `runly help` | Usage. |
107126

108127
## Exit codes
109128

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

119138
## CI
120139

121-
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.
140+
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.
122141

123142
## Limitations
124143

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

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

134153
## Links
135154

.cursor/skills/runly/skill/SKILL.md

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,17 @@ name: runly
33
description: >-
44
Runs the same Node.js command under multiple Node versions from one config file
55
(runly.config.mjs/js/cjs), resolving each runtime via npx and the npm `node`
6-
package. Use when the user mentions Runly, @hamdymohamedak/runly, multi-version
7-
Node testing, Node matrix in CI, runly.config, or running tests across Node 18/20/22.
6+
package. Use `runly init` to scaffold config and npm script; use `loadConfig()` in code.
7+
Use when the user mentions Runly, @hamdymohamedak/runly, multi-version Node testing,
8+
Node matrix in CI, runly.config, or running tests across Node 18/20/22.
89
---
910

1011
# Runly
1112

1213
## What it is
1314

1415
- **npm package**: `@hamdymohamedak/runly` (scoped; unscoped name `runly` is blocked on npm as too similar to `runjs`).
15-
- **CLI binary name**: `runly` (after `npm install`, use `npx runly` from the project root).
16+
- **CLI binary name**: `runly` — use **`npx runly init`** once to create config + **`npm run runly`**, or **`npx runly`** for one-off runs.
1617
- **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.
1718

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

3132
```bash
3233
npx @hamdymohamedak/runly
34+
npx @hamdymohamedak/runly init
3335
```
3436

37+
## `runly init` (scaffold)
38+
39+
From the **project root** (after **`npm install -D @hamdymohamedak/runly`**):
40+
41+
```bash
42+
npx runly init
43+
```
44+
45+
- 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**).
46+
- 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`**.
47+
- Uses **`export default`** when **`package.json`** has **`"type": "module"`**, else **`module.exports`**.
48+
- Adds **`"runly": "runly"`** under **`scripts`** in **`package.json`** when the file exists and **`scripts.runly`** is not already set.
49+
- Default **`run`** in the scaffold is a small **`node -e`** smoke command; edit to **`node --test`**, **`npm test`**, etc.
50+
51+
Programmatic: **`initRunlyProject(cwd)`** from **`@hamdymohamedak/runly`**.
52+
3553
## Config file discovery
3654

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

43-
Override: `runly -c /path/to/config.mjs` or `runly --config /path/to/config.mjs`.
61+
Override: `runly -c /path/to/config.mjs` or `runly --config /path/to/runly.config.mjs`.
4462

4563
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()`).
4664

@@ -95,15 +113,16 @@ export default defineConfig({
95113
});
96114
```
97115

98-
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.
116+
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.
99117

100118
## CLI
101119

102-
| Flag | Meaning |
103-
|------|---------|
120+
| Command / flag | Meaning |
121+
|----------------|---------|
122+
| `runly init` | Scaffold **`runly.config.js`**, **`SKILL.md`** (if missing), and **`scripts.runly`** (see above). |
123+
| `runly` | Run matrix using config in cwd. |
104124
| `-c`, `--config` | Path to config file. |
105-
106-
No other flags in the current CLI.
125+
| `runly help` | Usage. |
107126

108127
## Exit codes
109128

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

119138
## CI
120139

121-
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.
140+
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.
122141

123142
## Limitations
124143

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

129148
## Reference in this repo
130149

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

134153
## Links
135154

.github/workflows/ci.yml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
# Cross-OS × host Node matrix: build Runly, run smoke tests, execute Runly against
2-
# multiple Node runtimes via npx (no nvm on the runner).
1+
# Cross-OS × host Node matrix: build Runly, verify `runly init` scaffolds a consumer
2+
# (runly.config.js + scripts.runly + npm run runly) from the packed tarball, smoke tests,
3+
# then Runly e2e against multiple Node runtimes via npx (no nvm on the runner).
34
name: CI
45

56
on:
@@ -39,6 +40,9 @@ jobs:
3940
- name: Typecheck / build
4041
run: npm run build
4142

43+
- name: runly init scaffold (pack tarball → CJS & ESM consumers → npm run runly)
44+
run: npm run ci:verify-init
45+
4246
- name: Unit smoke (repo test/)
4347
run: node --test test/smoke.test.js
4448

README.md

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,35 @@ npm install -D @hamdymohamedak/runly
2828

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

31+
### First-time setup (`init`)
32+
33+
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:
34+
35+
```bash
36+
npx runly init
37+
```
38+
39+
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.
40+
41+
### Run the matrix
42+
3143
From the directory that contains your config:
3244

3345
```bash
3446
npx runly
3547
```
3648

49+
Or, after `init`:
50+
51+
```bash
52+
npm run runly
53+
```
54+
3755
Without adding a dev dependency:
3856

3957
```bash
4058
npx @hamdymohamedak/runly
59+
npx @hamdymohamedak/runly init # scaffold config in cwd
4160
```
4261

4362
---
@@ -114,15 +133,18 @@ export default defineConfig({
114133
});
115134
```
116135

117-
Exported types include `RunlyConfig` and `RunlyRun` for use in your own tooling.
136+
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`**.
118137

119138
---
120139

121140
## CLI
122141

123-
| Flag | Description |
124-
|------|-------------|
142+
| Command / flag | Description |
143+
|----------------|-------------|
144+
| `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. |
145+
| `runly`, `runly -c <path>` | Run the matrix (search for config in cwd, or use `-c` / `--config`). |
125146
| `-c`, `--config` | Path to a config file. If omitted, Runly searches for `runly.config.mjs`, then `.js`, then `.cjs` in the current working directory. |
147+
| `runly help` | Print usage. |
126148

127149
---
128150

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

148170
## Continuous integration
149171

150-
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.
172+
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.
151173

152174
---
153175

dist/cli.js

Lines changed: 30 additions & 13 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/cli.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)