@zendero/runctl 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +64 -23
- package/bin/runctl +175 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,59 +10,100 @@ Picks a **free port**, runs your **dev server in the background**, and keeps **P
|
|
|
10
10
|
|
|
11
11
|
## Install
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Published name on npm is **`@zendero/runctl`**; the CLI on your PATH is **`runctl`**.
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
| Goal | What to run |
|
|
16
|
+
|------|-------------|
|
|
17
|
+
| Use runctl **inside one repo** (recommended) | `pnpm add -D @zendero/runctl` — also `npm install -D` / `yarn add -D` |
|
|
18
|
+
| **`runctl` everywhere** (global) | `pnpm add -g @zendero/runctl` or the curl installer below |
|
|
19
|
+
| Track **main from GitHub** as a dev dependency | `pnpm add -D "github:DoctorKhan/runctl#main"` (still resolves as `@zendero/runctl`; reinstall to update) |
|
|
20
|
+
|
|
21
|
+
### Global install: package manager vs script
|
|
22
|
+
|
|
23
|
+
**Package manager** is the straightforward choice if you already use pnpm or npm:
|
|
16
24
|
|
|
17
25
|
```bash
|
|
18
|
-
pnpm add -
|
|
26
|
+
pnpm add -g @zendero/runctl
|
|
19
27
|
```
|
|
20
28
|
|
|
21
|
-
|
|
29
|
+
From Git only:
|
|
22
30
|
|
|
23
31
|
```bash
|
|
24
|
-
pnpm add -g
|
|
32
|
+
pnpm add -g "github:DoctorKhan/runctl#main"
|
|
25
33
|
```
|
|
26
34
|
|
|
27
|
-
**
|
|
35
|
+
**[`scripts/install-global.sh`](scripts/install-global.sh)** is for “one command” setup, **CI**, or when you want **npm first, then Git** without writing two install lines yourself. It requires **bash**, **pnpm or npm** on `PATH`, and network access.
|
|
36
|
+
|
|
37
|
+
One-liner (same URL the script header documents):
|
|
28
38
|
|
|
29
39
|
```bash
|
|
30
|
-
curl -fsSL "https://raw.githubusercontent.com/DoctorKhan/runctl/main/scripts/install-global.sh" |
|
|
31
|
-
bash
|
|
40
|
+
curl -fsSL "https://raw.githubusercontent.com/DoctorKhan/runctl/main/scripts/install-global.sh" | bash
|
|
32
41
|
```
|
|
33
42
|
|
|
34
|
-
|
|
43
|
+
Pass script arguments after `bash` (stdin pipe has no argv). To pick a **mode** explicitly:
|
|
35
44
|
|
|
36
45
|
```bash
|
|
37
|
-
curl -fsSL "https://raw.githubusercontent.com/DoctorKhan/runctl/main/scripts/install-global.sh" |
|
|
38
|
-
bash -s -- --registry
|
|
46
|
+
curl -fsSL "https://raw.githubusercontent.com/DoctorKhan/runctl/main/scripts/install-global.sh" | bash -s -- --registry
|
|
39
47
|
```
|
|
40
48
|
|
|
49
|
+
### `install-global.sh` reference
|
|
50
|
+
|
|
51
|
+
If you do **not** pass **`--registry`**, **`--git`**, **`--auto`**, or **`--interactive`**: on an **interactive TTY** with **`CI` not `1`**, the script **prompts** for install source (and related choices). Otherwise it behaves like **`--auto`**: **global install from the npm registry** first; if that fails, **retry from Git** (same URL/ref as `--git`).
|
|
52
|
+
|
|
53
|
+
**Modes** — each mode picks *where* the global install comes from. Under the hood the script runs **`pnpm add -g …`** or **`npm install -g …`** once per successful path (auto can run **twice**: registry attempt, then Git if the first fails).
|
|
54
|
+
|
|
55
|
+
| Mode | What it does | When to use it |
|
|
56
|
+
|------|----------------|----------------|
|
|
57
|
+
| **`--registry`** | **Only** installs `RUNCTL_PACKAGE` (default `@zendero/runctl`) from the npm registry. **No** Git fallback. | You want the published package only—e.g. CI that must not clone Git, or you know npm is enough. |
|
|
58
|
+
| **`--git`** | **Only** installs from Git: `RUNCTL_GIT_BASE` + `#` + ref (default ref `main`, overridable with `--ref`). **No** registry attempt first. | You want `main`/a branch/tag from the repo, or the registry is unreachable. |
|
|
59
|
+
| **`--auto`** | Tries **`--registry`** first; on **failure**, runs the same Git install as **`--git`**. | Headless installs, pipes, CI: resilient default when you’re fine with either source. |
|
|
60
|
+
| **`--interactive`** | Prompts for **registry / git / auto**, optional **Git ref** when git/auto applies, and **pnpm vs npm** if both exist—**only** when a TTY is available. | You want to choose at install time instead of memorizing flags. |
|
|
61
|
+
|
|
62
|
+
If **`--interactive`** is requested but there is **no usable TTY** (or `CI=1`), the script **falls back to `--auto`** and prints a short notice.
|
|
63
|
+
|
|
64
|
+
**Flags**
|
|
65
|
+
|
|
66
|
+
| Flag | Meaning |
|
|
67
|
+
|------|---------|
|
|
68
|
+
| `--pm pnpm` \| `--pm npm` | Use that package manager (must exist on `PATH`) |
|
|
69
|
+
| `--ref <ref>` | Git ref for `--git` or for the Git step of `--auto` (default: `main`) |
|
|
70
|
+
|
|
71
|
+
**Environment variables** (optional)
|
|
72
|
+
|
|
73
|
+
| Variable | Purpose |
|
|
74
|
+
|----------|---------|
|
|
75
|
+
| `RUNCTL_PACKAGE` | npm package name (default: `@zendero/runctl`) |
|
|
76
|
+
| `RUNCTL_GIT_BASE` | Git URL without fragment (default: `git+https://github.com/DoctorKhan/runctl.git`) |
|
|
77
|
+
| `RUNCTL_GIT_REF` | Default ref when not overridden by `--ref` (default: `main`) |
|
|
78
|
+
|
|
79
|
+
**Examples**
|
|
80
|
+
|
|
81
|
+
Registry only (good for locked-down CI that should not hit Git):
|
|
82
|
+
|
|
41
83
|
```bash
|
|
42
|
-
curl -fsSL "https://raw.githubusercontent.com/DoctorKhan/runctl/main/scripts/install-global.sh" |
|
|
43
|
-
bash -s -- --auto
|
|
84
|
+
curl -fsSL "https://raw.githubusercontent.com/DoctorKhan/runctl/main/scripts/install-global.sh" | bash -s -- --registry
|
|
44
85
|
```
|
|
45
86
|
|
|
87
|
+
Explicit auto (same as non-interactive default, but spelled out):
|
|
88
|
+
|
|
46
89
|
```bash
|
|
47
|
-
curl -fsSL "https://raw.githubusercontent.com/DoctorKhan/runctl/main/scripts/install-global.sh" |
|
|
48
|
-
bash -s -- --git --ref main
|
|
90
|
+
curl -fsSL "https://raw.githubusercontent.com/DoctorKhan/runctl/main/scripts/install-global.sh" | bash -s -- --auto
|
|
49
91
|
```
|
|
50
92
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
**Without curl:**
|
|
93
|
+
Git only, specific ref:
|
|
54
94
|
|
|
55
95
|
```bash
|
|
56
|
-
|
|
57
|
-
pnpm add -g "github:DoctorKhan/runctl#main"
|
|
96
|
+
curl -fsSL "https://raw.githubusercontent.com/DoctorKhan/runctl/main/scripts/install-global.sh" | bash -s -- --git --ref main
|
|
58
97
|
```
|
|
59
98
|
|
|
60
|
-
|
|
99
|
+
Use npm explicitly (e.g. no pnpm on the machine):
|
|
61
100
|
|
|
62
101
|
```bash
|
|
63
|
-
|
|
102
|
+
curl -fsSL "https://raw.githubusercontent.com/DoctorKhan/runctl/main/scripts/install-global.sh" | bash -s -- --pm npm --registry
|
|
64
103
|
```
|
|
65
104
|
|
|
105
|
+
`--help` on the script prints the same usage summary.
|
|
106
|
+
|
|
66
107
|
---
|
|
67
108
|
|
|
68
109
|
## Quick start
|
|
@@ -100,7 +141,7 @@ Add scripts to your `package.json`:
|
|
|
100
141
|
| `runctl ports gc` | Clean up stale port claims |
|
|
101
142
|
| `runctl env expand <manifest> [--out file]` | Generate `.env.local` from manifest |
|
|
102
143
|
| `runctl doctor [dir]` | Check Node 18+, `lsof`, package manager, `package.json` |
|
|
103
|
-
| `runctl update` |
|
|
144
|
+
| `runctl update` | Refresh global CLI: default **`auto`** (npm `@latest`, then Git). **`runctl update npm`** / **`git`** / **`auto`** or flags **`--registry`** / **`--git`** / **`--auto`**; **`runctl update --help`**; env `RUNCTL_PACKAGE`, `RUNCTL_GIT_BASE`, `RUNCTL_GIT_REF` (aligned with [`install-global.sh`](scripts/install-global.sh)) |
|
|
104
145
|
| `runctl version` | Print package version and install path |
|
|
105
146
|
|
|
106
147
|
**Monorepo:** `runctl start ./apps/web --script dev:server`
|
package/bin/runctl
CHANGED
|
@@ -25,7 +25,7 @@ ${_y}Commands${_r}
|
|
|
25
25
|
${_c}ports gc${_r} Clean up stale port claims
|
|
26
26
|
${_c}env expand${_r} <manifest> [opts] Generate .env.local from manifest
|
|
27
27
|
${_c}doctor${_r} Check Node, tooling, and project basics
|
|
28
|
-
${_c}update${_r}
|
|
28
|
+
${_c}update${_r} [npm|git|auto] [opts] Update global runctl ${_d}(default: auto; see runctl update --help)${_r}
|
|
29
29
|
|
|
30
30
|
${_y}Options${_r}
|
|
31
31
|
${_c}--script${_r} <name> Package script to run ${_d}(default: dev)${_r}
|
|
@@ -174,16 +174,182 @@ cmd_env() {
|
|
|
174
174
|
esac
|
|
175
175
|
}
|
|
176
176
|
|
|
177
|
-
|
|
178
|
-
|
|
177
|
+
cmd_update_usage() {
|
|
178
|
+
cat <<EOF
|
|
179
|
+
${_b}runctl update${_r} — refresh the global CLI (pnpm/npm global install)
|
|
180
|
+
|
|
181
|
+
${_y}Usage:${_r} runctl update [npm|git|auto] [options]
|
|
182
|
+
|
|
183
|
+
${_y}Source${_r} ${_d}(pick one; default when omitted: ${_c}auto${_r})${_r}
|
|
184
|
+
${_c}npm${_r} | ${_c}--registry${_r} Latest from npm only (${_d}${RUNCTL_PACKAGE:-@zendero/runctl}@latest${_r})
|
|
185
|
+
${_c}git${_r} | ${_c}--git${_r} From Git only (${_d}RUNCTL_GIT_BASE + ref${_r})
|
|
186
|
+
${_c}auto${_r} | ${_c}--auto${_r} Try npm @latest, then Git if that fails
|
|
187
|
+
|
|
188
|
+
${_y}Options${_r}
|
|
189
|
+
${_c}--pm${_r} ${_d}pnpm|npm${_r} Package manager ${_d}(default: pnpm if on PATH, else npm)${_r}
|
|
190
|
+
${_c}--ref${_r} ${_d}<ref>${_r} Git ref for --git / Git fallback ${_d}(default: RUNCTL_GIT_REF or main)${_r}
|
|
191
|
+
${_c}-h${_r}, ${_c}--help${_r} This help
|
|
192
|
+
|
|
193
|
+
${_y}Environment${_r} ${_d}(optional; same as install-global.sh)${_r}
|
|
194
|
+
RUNCTL_PACKAGE npm name ${_d}(default: @zendero/runctl)${_r}
|
|
195
|
+
RUNCTL_GIT_BASE Git URL without fragment ${_d}(default: git+https://github.com/DoctorKhan/runctl.git)${_r}
|
|
196
|
+
RUNCTL_GIT_REF default Git ref ${_d}(default: main)${_r}
|
|
197
|
+
EOF
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
cmd_update_pick_pm() {
|
|
201
|
+
if [[ -n "$1" ]]; then
|
|
202
|
+
case "$1" in
|
|
203
|
+
pnpm | npm) ;;
|
|
204
|
+
*)
|
|
205
|
+
echo "runctl update: unsupported --pm: $1 (use pnpm or npm)" >&2
|
|
206
|
+
return 1
|
|
207
|
+
;;
|
|
208
|
+
esac
|
|
209
|
+
if ! command -v "$1" >/dev/null 2>&1; then
|
|
210
|
+
echo "runctl update: package manager not on PATH: $1" >&2
|
|
211
|
+
return 1
|
|
212
|
+
fi
|
|
213
|
+
printf '%s' "$1"
|
|
214
|
+
return 0
|
|
215
|
+
fi
|
|
179
216
|
if command -v pnpm >/dev/null 2>&1; then
|
|
180
|
-
pnpm
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
217
|
+
printf 'pnpm'
|
|
218
|
+
return 0
|
|
219
|
+
fi
|
|
220
|
+
if command -v npm >/dev/null 2>&1; then
|
|
221
|
+
printf 'npm'
|
|
222
|
+
return 0
|
|
223
|
+
fi
|
|
224
|
+
echo "runctl update: pnpm or npm required on PATH." >&2
|
|
225
|
+
return 1
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
cmd_update() {
|
|
229
|
+
local MODE="" PM="" GIT_REF="${RUNCTL_GIT_REF:-main}"
|
|
230
|
+
local PKG="${RUNCTL_PACKAGE:-@zendero/runctl}"
|
|
231
|
+
local GIT_BASE="${RUNCTL_GIT_BASE:-git+https://github.com/DoctorKhan/runctl.git}"
|
|
232
|
+
local -a POS=()
|
|
233
|
+
|
|
234
|
+
while [[ $# -gt 0 ]]; do
|
|
235
|
+
case "$1" in
|
|
236
|
+
--registry)
|
|
237
|
+
MODE="registry"
|
|
238
|
+
shift
|
|
239
|
+
;;
|
|
240
|
+
--git)
|
|
241
|
+
MODE="git"
|
|
242
|
+
shift
|
|
243
|
+
;;
|
|
244
|
+
--auto)
|
|
245
|
+
MODE="auto"
|
|
246
|
+
shift
|
|
247
|
+
;;
|
|
248
|
+
--pm)
|
|
249
|
+
[[ $# -ge 2 ]] || {
|
|
250
|
+
echo "runctl update: --pm requires a value" >&2
|
|
251
|
+
exit 1
|
|
252
|
+
}
|
|
253
|
+
PM="$2"
|
|
254
|
+
shift 2
|
|
255
|
+
;;
|
|
256
|
+
--ref)
|
|
257
|
+
[[ $# -ge 2 ]] || {
|
|
258
|
+
echo "runctl update: --ref requires a value" >&2
|
|
259
|
+
exit 1
|
|
260
|
+
}
|
|
261
|
+
GIT_REF="$2"
|
|
262
|
+
shift 2
|
|
263
|
+
;;
|
|
264
|
+
-h | --help)
|
|
265
|
+
cmd_update_usage
|
|
266
|
+
exit 0
|
|
267
|
+
;;
|
|
268
|
+
-*)
|
|
269
|
+
echo "runctl update: unknown option: $1" >&2
|
|
270
|
+
cmd_update_usage >&2
|
|
271
|
+
exit 1
|
|
272
|
+
;;
|
|
273
|
+
*)
|
|
274
|
+
POS+=("$1")
|
|
275
|
+
shift
|
|
276
|
+
;;
|
|
277
|
+
esac
|
|
278
|
+
done
|
|
279
|
+
|
|
280
|
+
local POS_MODE=""
|
|
281
|
+
if [[ ${#POS[@]} -gt 1 ]]; then
|
|
282
|
+
echo "runctl update: too many arguments (${POS[*]}). Use at most one of: npm, git, auto" >&2
|
|
185
283
|
exit 1
|
|
186
284
|
fi
|
|
285
|
+
if [[ ${#POS[@]} -eq 1 ]]; then
|
|
286
|
+
case "${POS[0]}" in
|
|
287
|
+
npm)
|
|
288
|
+
POS_MODE="registry"
|
|
289
|
+
;;
|
|
290
|
+
git)
|
|
291
|
+
POS_MODE="git"
|
|
292
|
+
;;
|
|
293
|
+
auto)
|
|
294
|
+
POS_MODE="auto"
|
|
295
|
+
;;
|
|
296
|
+
*)
|
|
297
|
+
echo "runctl update: unknown argument: ${POS[0]} (expected: npm, git, auto — runctl update --help)" >&2
|
|
298
|
+
exit 1
|
|
299
|
+
;;
|
|
300
|
+
esac
|
|
301
|
+
fi
|
|
302
|
+
if [[ -n "$MODE" && -n "$POS_MODE" && "$MODE" != "$POS_MODE" ]]; then
|
|
303
|
+
echo "runctl update: conflicting source (npm/git/auto vs --registry/--git/--auto)" >&2
|
|
304
|
+
exit 1
|
|
305
|
+
fi
|
|
306
|
+
if [[ -n "$POS_MODE" ]]; then
|
|
307
|
+
MODE="$POS_MODE"
|
|
308
|
+
fi
|
|
309
|
+
[[ -n "$MODE" ]] || MODE="auto"
|
|
310
|
+
|
|
311
|
+
local pm git_target
|
|
312
|
+
pm="$(cmd_update_pick_pm "$PM")" || exit 1
|
|
313
|
+
git_target="${GIT_BASE}#${GIT_REF}"
|
|
314
|
+
|
|
315
|
+
_update_registry() {
|
|
316
|
+
local spec="${PKG}@latest"
|
|
317
|
+
echo "runctl update: installing latest from registry ($spec)..."
|
|
318
|
+
if [[ "$pm" == "pnpm" ]]; then
|
|
319
|
+
pnpm add -g "$spec"
|
|
320
|
+
else
|
|
321
|
+
npm install -g "$spec"
|
|
322
|
+
fi
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
_update_git() {
|
|
326
|
+
echo "runctl update: installing from Git ($git_target)..."
|
|
327
|
+
if [[ "$pm" == "pnpm" ]]; then
|
|
328
|
+
pnpm add -g "$git_target"
|
|
329
|
+
else
|
|
330
|
+
npm install -g "$git_target"
|
|
331
|
+
fi
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
case "$MODE" in
|
|
335
|
+
registry)
|
|
336
|
+
_update_registry
|
|
337
|
+
;;
|
|
338
|
+
git)
|
|
339
|
+
_update_git
|
|
340
|
+
;;
|
|
341
|
+
auto)
|
|
342
|
+
if _update_registry; then
|
|
343
|
+
return 0
|
|
344
|
+
fi
|
|
345
|
+
echo "runctl update: registry install failed; trying Git..." >&2
|
|
346
|
+
_update_git
|
|
347
|
+
;;
|
|
348
|
+
*)
|
|
349
|
+
echo "runctl update: internal error: unknown mode $MODE" >&2
|
|
350
|
+
exit 1
|
|
351
|
+
;;
|
|
352
|
+
esac
|
|
187
353
|
}
|
|
188
354
|
|
|
189
355
|
cmd_doctor() {
|
|
@@ -287,7 +453,7 @@ main() {
|
|
|
287
453
|
ports) cmd_ports "$@" ;;
|
|
288
454
|
env) cmd_env "$@" ;;
|
|
289
455
|
doctor) cmd_doctor "$@" ;;
|
|
290
|
-
update) cmd_update ;;
|
|
456
|
+
update) cmd_update "$@" ;;
|
|
291
457
|
|
|
292
458
|
# Plumbing
|
|
293
459
|
lib-path) printf '%s\n' "$RUNCTL_PKG_ROOT/lib/run-lib.sh" ;;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zendero/runctl",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Picks a free port, runs your dev server in the background, and keeps PID + port state in .run/ so projects don't collide.",
|
|
5
5
|
"author": "DoctorKhan",
|
|
6
6
|
"homepage": "https://github.com/DoctorKhan/runctl#readme",
|