@zendero/runctl 0.1.2 → 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.
Files changed (3) hide show
  1. package/README.md +67 -16
  2. package/bin/runctl +175 -9
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -10,49 +10,100 @@ Picks a **free port**, runs your **dev server in the background**, and keeps **P
10
10
 
11
11
  ## Install
12
12
 
13
- The published package on npm is **`@zendero/runctl`**. The CLI binary on your PATH is still **`runctl`**.
13
+ Published name on npm is **`@zendero/runctl`**; the CLI on your PATH is **`runctl`**.
14
14
 
15
- **From the npm registry (recommended):**
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 -D @zendero/runctl # or npm install -D / yarn add -D
26
+ pnpm add -g @zendero/runctl
19
27
  ```
20
28
 
21
- **Global CLI** (`runctl` on your PATH everywhere):
29
+ From Git only:
22
30
 
23
31
  ```bash
24
- pnpm add -g @zendero/runctl # or npm install -g
32
+ pnpm add -g "github:DoctorKhan/runctl#main"
25
33
  ```
26
34
 
27
- **Global install via curl** uses a single script: [`scripts/install-global.sh`](scripts/install-global.sh)
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
40
  curl -fsSL "https://raw.githubusercontent.com/DoctorKhan/runctl/main/scripts/install-global.sh" | bash
31
41
  ```
32
42
 
33
- With no arguments, `install-global.sh` prompts on a TTY; otherwise it defaults to registry install with Git fallback. Pass arguments to force a mode:
43
+ Pass script arguments after `bash` (stdin pipe has no argv). To pick a **mode** explicitly:
44
+
45
+ ```bash
46
+ curl -fsSL "https://raw.githubusercontent.com/DoctorKhan/runctl/main/scripts/install-global.sh" | bash -s -- --registry
47
+ ```
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):
34
82
 
35
83
  ```bash
36
84
  curl -fsSL "https://raw.githubusercontent.com/DoctorKhan/runctl/main/scripts/install-global.sh" | bash -s -- --registry
37
- curl -fsSL "https://raw.githubusercontent.com/DoctorKhan/runctl/main/scripts/install-global.sh" | bash -s -- --auto
38
- curl -fsSL "https://raw.githubusercontent.com/DoctorKhan/runctl/main/scripts/install-global.sh" | bash -s -- --git --ref main
39
85
  ```
40
86
 
41
- Optional flags: `--pm pnpm|npm`, `--ref <git-ref>`. Optional env: `RUNCTL_PACKAGE`, `RUNCTL_GIT_BASE`, `RUNCTL_GIT_REF`.
87
+ Explicit auto (same as non-interactive default, but spelled out):
42
88
 
43
- **Without curl:**
89
+ ```bash
90
+ curl -fsSL "https://raw.githubusercontent.com/DoctorKhan/runctl/main/scripts/install-global.sh" | bash -s -- --auto
91
+ ```
92
+
93
+ Git only, specific ref:
44
94
 
45
95
  ```bash
46
- pnpm add -g @zendero/runctl
47
- 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
48
97
  ```
49
98
 
50
- **Project dependency from GitHub** (not global): dependency resolves to **`@zendero/runctl`**. Reinstall to pull the latest `main`:
99
+ Use npm explicitly (e.g. no pnpm on the machine):
51
100
 
52
101
  ```bash
53
- pnpm add -D "github:DoctorKhan/runctl#main"
102
+ curl -fsSL "https://raw.githubusercontent.com/DoctorKhan/runctl/main/scripts/install-global.sh" | bash -s -- --pm npm --registry
54
103
  ```
55
104
 
105
+ `--help` on the script prints the same usage summary.
106
+
56
107
  ---
57
108
 
58
109
  ## Quick start
@@ -90,7 +141,7 @@ Add scripts to your `package.json`:
90
141
  | `runctl ports gc` | Clean up stale port claims |
91
142
  | `runctl env expand <manifest> [--out file]` | Generate `.env.local` from manifest |
92
143
  | `runctl doctor [dir]` | Check Node 18+, `lsof`, package manager, `package.json` |
93
- | `runctl update` | Update the global `@zendero/runctl` install |
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)) |
94
145
  | `runctl version` | Print package version and install path |
95
146
 
96
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} Update runctl to latest version
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
- cmd_update() {
178
- echo "runctl update: installing latest @zendero/runctl..."
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 add -g @zendero/runctl@latest
181
- elif command -v npm >/dev/null 2>&1; then
182
- npm install -g @zendero/runctl@latest
183
- else
184
- echo "runctl: pnpm or npm required to update." >&2
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.2",
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",