numux 1.26.0 → 2.0.1
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 +6 -12
- package/dist/numux.js +57 -56
- package/dist/types.d.ts +4 -15
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -40,7 +40,6 @@ export default defineConfig({
|
|
|
40
40
|
migrate: {
|
|
41
41
|
command: 'bun run migrate',
|
|
42
42
|
dependsOn: ['db'],
|
|
43
|
-
persistent: false,
|
|
44
43
|
},
|
|
45
44
|
api: {
|
|
46
45
|
command: 'bun run dev:api',
|
|
@@ -53,7 +52,6 @@ export default defineConfig({
|
|
|
53
52
|
confirm: {
|
|
54
53
|
command: 'sh -c "printf \'Deploy to staging? [y/n] \' && read answer && echo $answer"',
|
|
55
54
|
interactive: true,
|
|
56
|
-
persistent: false,
|
|
57
55
|
},
|
|
58
56
|
},
|
|
59
57
|
})
|
|
@@ -168,7 +166,7 @@ Template properties (color, env, dependsOn, etc.) are inherited by all matched p
|
|
|
168
166
|
| `--exclude <a,b,...>` | Exclude these processes |
|
|
169
167
|
| `--kill-others` | Kill all processes when any exits (regardless of exit code) |
|
|
170
168
|
| `--kill-others-on-fail` | Kill all processes when any exits with a non-zero exit code |
|
|
171
|
-
| `--
|
|
169
|
+
| `--max-restarts <n>` | Max auto-restarts for crashed processes |
|
|
172
170
|
| `-s, --sort <mode>` | Tab display order: `config` (default), `alphabetical`, `topological` |
|
|
173
171
|
| `--no-watch` | Disable file watching even if config has `watch` patterns |
|
|
174
172
|
| `-t, --timestamps` | Add `[HH:MM:SS]` timestamps to prefixed output |
|
|
@@ -199,8 +197,7 @@ Top-level options apply to all processes (process-level settings override):
|
|
|
199
197
|
| `env` | `Record<string, string>` | Environment variables merged into all processes (process `env` overrides per key) |
|
|
200
198
|
| `envFile` | `string \| string[] \| false` | `.env` file(s) for all processes (process `envFile` replaces if set; `false` disables) |
|
|
201
199
|
| `showCommand` | `boolean` | Print the command being run as the first line of output (default: `true`) |
|
|
202
|
-
| `
|
|
203
|
-
| `maxRestarts` | `number` | Restart limit for all processes (default: `Infinity`) |
|
|
200
|
+
| `maxRestarts` | `number` | Restart limit for all processes (default: `0`) |
|
|
204
201
|
| `readyTimeout` | `number` | Ready timeout in ms for all processes |
|
|
205
202
|
| `stopSignal` | `'SIGTERM' \| 'SIGINT' \| 'SIGHUP'` | Stop signal for all processes (default: `'SIGTERM'`) |
|
|
206
203
|
| `errorMatcher` | `boolean \| string` | Error detection for all processes (`true` = ANSI red, string = regex) |
|
|
@@ -232,8 +229,7 @@ Each process accepts:
|
|
|
232
229
|
| `dependsOn` | `string[]` | — | Processes that must be ready first |
|
|
233
230
|
| `readyPattern` | `string \| RegExp` | — | Regex matched against stdout to signal readiness. Use `RegExp` to capture groups (see below) |
|
|
234
231
|
| `readyTimeout` | `number` | — | Milliseconds to wait for `readyPattern` before failing |
|
|
235
|
-
| `
|
|
236
|
-
| `maxRestarts` | `number` | `Infinity` | Max auto-restart attempts before giving up |
|
|
232
|
+
| `maxRestarts` | `number` | `0` | Max auto-restart attempts on non-zero exit (0 = no restarts) |
|
|
237
233
|
| `delay` | `number` | — | Milliseconds to wait before starting the process |
|
|
238
234
|
| `condition` | `string` | — | Env var name; process skipped if falsy. Prefix with `!` to negate |
|
|
239
235
|
| `platform` | `string \| string[]` | — | OS(es) this process runs on (e.g. `'darwin'`, `'linux'`). Non-matching processes are removed; dependents still start |
|
|
@@ -301,7 +297,6 @@ export default defineConfig({
|
|
|
301
297
|
processes: {
|
|
302
298
|
seed: {
|
|
303
299
|
command: 'bun run seed',
|
|
304
|
-
persistent: false,
|
|
305
300
|
condition: 'SEED_DB', // only runs when SEED_DB is set and truthy
|
|
306
301
|
},
|
|
307
302
|
storybook: {
|
|
@@ -319,11 +314,10 @@ Falsy values: unset, empty string, `"0"`, `"false"`, `"no"`, `"off"` (case-insen
|
|
|
319
314
|
Each process starts as soon as its declared `dependsOn` dependencies are ready — it does not wait for unrelated processes. If a process fails, its dependents are skipped.
|
|
320
315
|
|
|
321
316
|
A process becomes **ready** when:
|
|
322
|
-
- **
|
|
323
|
-
- **
|
|
324
|
-
- **non-persistent** — exits with code 0
|
|
317
|
+
- **Has `readyPattern`** — the pattern matches in stdout (long-running server)
|
|
318
|
+
- **No `readyPattern`** — exits with code 0 (one-shot task)
|
|
325
319
|
|
|
326
|
-
|
|
320
|
+
Processes that crash (non-zero exit) can be auto-restarted by setting `maxRestarts` (default: `0`). Restarts use exponential backoff (1s–30s), which resets after 10s of uptime.
|
|
327
321
|
|
|
328
322
|
### Dependency output capture
|
|
329
323
|
|
package/dist/numux.js
CHANGED
|
@@ -36,7 +36,7 @@ var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports,
|
|
|
36
36
|
var require_package = __commonJS((exports, module) => {
|
|
37
37
|
module.exports = {
|
|
38
38
|
name: "numux",
|
|
39
|
-
version: "
|
|
39
|
+
version: "2.0.1",
|
|
40
40
|
description: "Terminal multiplexer with dependency orchestration",
|
|
41
41
|
type: "module",
|
|
42
42
|
license: "MIT",
|
|
@@ -72,7 +72,8 @@ var require_package = __commonJS((exports, module) => {
|
|
|
72
72
|
test: "bun test",
|
|
73
73
|
typecheck: "bunx tsc --noEmit",
|
|
74
74
|
lint: "biome check .",
|
|
75
|
-
fix: "biome check . --fix --unsafe"
|
|
75
|
+
fix: "biome check . --fix --unsafe",
|
|
76
|
+
prepare: "git config core.hooksPath .githooks"
|
|
76
77
|
},
|
|
77
78
|
files: [
|
|
78
79
|
"dist/"
|
|
@@ -83,6 +84,8 @@ var require_package = __commonJS((exports, module) => {
|
|
|
83
84
|
},
|
|
84
85
|
devDependencies: {
|
|
85
86
|
"@biomejs/biome": "^2.4.4",
|
|
87
|
+
"@commitlint/cli": "^20.4.2",
|
|
88
|
+
"@commitlint/config-conventional": "^20.4.2",
|
|
86
89
|
"@types/bun": "^1.3.9"
|
|
87
90
|
}
|
|
88
91
|
};
|
|
@@ -201,10 +204,18 @@ var FLAGS = [
|
|
|
201
204
|
description: "Kill all processes when any exits with non-zero code"
|
|
202
205
|
},
|
|
203
206
|
{
|
|
204
|
-
type: "
|
|
205
|
-
long: "--
|
|
206
|
-
key: "
|
|
207
|
-
description: "
|
|
207
|
+
type: "value",
|
|
208
|
+
long: "--max-restarts",
|
|
209
|
+
key: "maxRestarts",
|
|
210
|
+
description: "Max auto-restarts for crashed processes",
|
|
211
|
+
valueName: "<n>",
|
|
212
|
+
completionHint: "none",
|
|
213
|
+
parse(raw, flag) {
|
|
214
|
+
const n = Number(raw);
|
|
215
|
+
if (!Number.isInteger(n) || n < 0)
|
|
216
|
+
throw new Error(`${flag} must be a non-negative integer, got "${raw}"`);
|
|
217
|
+
return n;
|
|
218
|
+
}
|
|
208
219
|
},
|
|
209
220
|
{
|
|
210
221
|
type: "boolean",
|
|
@@ -350,7 +361,6 @@ function parseArgs(argv) {
|
|
|
350
361
|
killOthers: false,
|
|
351
362
|
killOthersOnFail: false,
|
|
352
363
|
timestamps: false,
|
|
353
|
-
noRestart: false,
|
|
354
364
|
noWatch: false,
|
|
355
365
|
autoColors: false,
|
|
356
366
|
configPath: undefined,
|
|
@@ -395,23 +405,31 @@ function parseArgs(argv) {
|
|
|
395
405
|
}
|
|
396
406
|
return result;
|
|
397
407
|
}
|
|
408
|
+
var RUNNERS = new Set(["npm", "npx", "yarn", "pnpm", "bun", "bunx"]);
|
|
409
|
+
function deriveProcessName(cmd) {
|
|
410
|
+
const parts = cmd.split(/\s+/);
|
|
411
|
+
const first = parts[0].split("/").pop();
|
|
412
|
+
if (parts.length > 1 && RUNNERS.has(first)) {
|
|
413
|
+
return parts[parts.length - 1];
|
|
414
|
+
}
|
|
415
|
+
return first;
|
|
416
|
+
}
|
|
398
417
|
function buildConfigFromArgs(commands, named, options) {
|
|
399
418
|
const processes = {};
|
|
400
|
-
const maxRestarts = options?.noRestart ? 0 : undefined;
|
|
401
419
|
const colors = options?.colors;
|
|
402
420
|
let colorIndex = 0;
|
|
403
421
|
for (const { name, command } of named) {
|
|
404
422
|
const color = colors?.[colorIndex++ % colors.length];
|
|
405
|
-
processes[name] = { command,
|
|
423
|
+
processes[name] = { command, ...color ? { color } : {} };
|
|
406
424
|
}
|
|
407
425
|
for (let i = 0;i < commands.length; i++) {
|
|
408
426
|
const cmd = commands[i];
|
|
409
|
-
let name = cmd
|
|
427
|
+
let name = deriveProcessName(cmd);
|
|
410
428
|
if (processes[name]) {
|
|
411
429
|
name = `${name}-${i}`;
|
|
412
430
|
}
|
|
413
431
|
const color = colors?.[colorIndex++ % colors.length];
|
|
414
|
-
processes[name] = { command: cmd,
|
|
432
|
+
processes[name] = { command: cmd, ...color ? { color } : {} };
|
|
415
433
|
}
|
|
416
434
|
return { processes };
|
|
417
435
|
}
|
|
@@ -1035,7 +1053,7 @@ function buildProcessHexColorMap(names, config) {
|
|
|
1035
1053
|
}
|
|
1036
1054
|
|
|
1037
1055
|
// src/config/validator.ts
|
|
1038
|
-
function validateConfig(raw,
|
|
1056
|
+
function validateConfig(raw, _warnings) {
|
|
1039
1057
|
if (!raw || typeof raw !== "object") {
|
|
1040
1058
|
throw new Error("Config must be an object");
|
|
1041
1059
|
}
|
|
@@ -1053,7 +1071,6 @@ function validateConfig(raw, warnings) {
|
|
|
1053
1071
|
const globalEnvFile = validateEnvFile(config.envFile);
|
|
1054
1072
|
const globalMaxRestarts = typeof config.maxRestarts === "number" && config.maxRestarts >= 0 ? config.maxRestarts : undefined;
|
|
1055
1073
|
const globalReadyTimeout = typeof config.readyTimeout === "number" && config.readyTimeout > 0 ? config.readyTimeout : undefined;
|
|
1056
|
-
const globalPersistent = typeof config.persistent === "boolean" ? config.persistent : undefined;
|
|
1057
1074
|
const globalStopSignal = validateStopSignal(config.stopSignal);
|
|
1058
1075
|
const globalErrorMatcher = validateErrorMatcher("(global)", config.errorMatcher);
|
|
1059
1076
|
const globalWatch = validateStringOrStringArray(config.watch);
|
|
@@ -1115,7 +1132,6 @@ function validateConfig(raw, warnings) {
|
|
|
1115
1132
|
}
|
|
1116
1133
|
}
|
|
1117
1134
|
}
|
|
1118
|
-
const persistent = typeof p.persistent === "boolean" ? p.persistent : globalPersistent ?? true;
|
|
1119
1135
|
const readyPattern = p.readyPattern instanceof RegExp ? p.readyPattern : typeof p.readyPattern === "string" ? p.readyPattern : undefined;
|
|
1120
1136
|
if (typeof readyPattern === "string") {
|
|
1121
1137
|
try {
|
|
@@ -1126,12 +1142,6 @@ function validateConfig(raw, warnings) {
|
|
|
1126
1142
|
});
|
|
1127
1143
|
}
|
|
1128
1144
|
}
|
|
1129
|
-
if (readyPattern && !persistent) {
|
|
1130
|
-
warnings?.push({
|
|
1131
|
-
process: name,
|
|
1132
|
-
message: "readyPattern is ignored on non-persistent processes (readiness is determined by exit code)"
|
|
1133
|
-
});
|
|
1134
|
-
}
|
|
1135
1145
|
if (p.env && typeof p.env === "object") {
|
|
1136
1146
|
for (const [k, v] of Object.entries(p.env)) {
|
|
1137
1147
|
if (typeof v !== "string") {
|
|
@@ -1156,8 +1166,7 @@ function validateConfig(raw, warnings) {
|
|
|
1156
1166
|
envFile: processEnvFile ?? globalEnvFile,
|
|
1157
1167
|
dependsOn: Array.isArray(p.dependsOn) ? p.dependsOn : undefined,
|
|
1158
1168
|
readyPattern,
|
|
1159
|
-
|
|
1160
|
-
maxRestarts: processMaxRestarts ?? globalMaxRestarts,
|
|
1169
|
+
maxRestarts: processMaxRestarts ?? globalMaxRestarts ?? 0,
|
|
1161
1170
|
readyTimeout: processReadyTimeout ?? globalReadyTimeout,
|
|
1162
1171
|
delay: typeof p.delay === "number" && p.delay > 0 ? p.delay : undefined,
|
|
1163
1172
|
condition: typeof p.condition === "string" && p.condition.trim() ? p.condition.trim() : undefined,
|
|
@@ -1293,8 +1302,7 @@ function resolveWorkspaceProcesses(script, cwd) {
|
|
|
1293
1302
|
usedNames.add(name);
|
|
1294
1303
|
processes[name] = {
|
|
1295
1304
|
command: `${pm} run ${script}`,
|
|
1296
|
-
cwd: dir
|
|
1297
|
-
persistent: true
|
|
1305
|
+
cwd: dir
|
|
1298
1306
|
};
|
|
1299
1307
|
}
|
|
1300
1308
|
if (Object.keys(processes).length === 0) {
|
|
@@ -1467,12 +1475,11 @@ function extractCaptures(match) {
|
|
|
1467
1475
|
function createReadinessChecker(config) {
|
|
1468
1476
|
const shouldCapture = config.readyPattern instanceof RegExp;
|
|
1469
1477
|
const pattern = config.readyPattern ? config.readyPattern instanceof RegExp ? config.readyPattern : new RegExp(config.readyPattern) : null;
|
|
1470
|
-
const persistent = config.persistent !== false;
|
|
1471
1478
|
let outputBuffer = "";
|
|
1472
1479
|
let _captures = null;
|
|
1473
1480
|
return {
|
|
1474
1481
|
feedOutput(data) {
|
|
1475
|
-
if (!
|
|
1482
|
+
if (!pattern)
|
|
1476
1483
|
return false;
|
|
1477
1484
|
outputBuffer += data;
|
|
1478
1485
|
if (outputBuffer.length > BUFFER_CAP2) {
|
|
@@ -1491,11 +1498,8 @@ function createReadinessChecker(config) {
|
|
|
1491
1498
|
get captures() {
|
|
1492
1499
|
return _captures;
|
|
1493
1500
|
},
|
|
1494
|
-
get isImmediatelyReady() {
|
|
1495
|
-
return persistent && !pattern;
|
|
1496
|
-
},
|
|
1497
1501
|
get dependsOnExit() {
|
|
1498
|
-
return !
|
|
1502
|
+
return !pattern;
|
|
1499
1503
|
}
|
|
1500
1504
|
};
|
|
1501
1505
|
}
|
|
@@ -1585,10 +1589,7 @@ class ProcessRunner {
|
|
|
1585
1589
|
`;
|
|
1586
1590
|
this.handler.onOutput(encoder.encode(msg));
|
|
1587
1591
|
}
|
|
1588
|
-
this.handler.onStatus(
|
|
1589
|
-
if (this.readiness.isImmediatelyReady) {
|
|
1590
|
-
this.markReady();
|
|
1591
|
-
}
|
|
1592
|
+
this.handler.onStatus("running");
|
|
1592
1593
|
this.startReadyTimeout(gen);
|
|
1593
1594
|
this.proc.exited.then((code) => {
|
|
1594
1595
|
if (this.generation !== gen)
|
|
@@ -1636,7 +1637,7 @@ class ProcessRunner {
|
|
|
1636
1637
|
}
|
|
1637
1638
|
startReadyTimeout(gen) {
|
|
1638
1639
|
const timeout = this.config.readyTimeout;
|
|
1639
|
-
if (!(timeout && this.config.readyPattern)
|
|
1640
|
+
if (!(timeout && this.config.readyPattern))
|
|
1640
1641
|
return;
|
|
1641
1642
|
this.readyTimer = setTimeout(() => {
|
|
1642
1643
|
this.readyTimer = null;
|
|
@@ -1894,8 +1895,6 @@ class ProcessManager {
|
|
|
1894
1895
|
if (this.stopping)
|
|
1895
1896
|
return;
|
|
1896
1897
|
const proc = this.config.processes[name];
|
|
1897
|
-
if (proc.persistent === false)
|
|
1898
|
-
return;
|
|
1899
1898
|
if (exitCode === 0)
|
|
1900
1899
|
return;
|
|
1901
1900
|
if (exitCode === null)
|
|
@@ -1906,8 +1905,8 @@ class ProcessManager {
|
|
|
1906
1905
|
this.restartAttempts.set(name, 0);
|
|
1907
1906
|
}
|
|
1908
1907
|
const attempt = this.restartAttempts.get(name) ?? 0;
|
|
1909
|
-
const maxRestarts = proc.maxRestarts;
|
|
1910
|
-
if (
|
|
1908
|
+
const maxRestarts = proc.maxRestarts ?? 0;
|
|
1909
|
+
if (attempt >= maxRestarts) {
|
|
1911
1910
|
log(`[${name}] Reached maxRestarts limit (${maxRestarts}), not restarting`);
|
|
1912
1911
|
if (maxRestarts > 0) {
|
|
1913
1912
|
const encoder2 = new TextEncoder;
|
|
@@ -1922,7 +1921,7 @@ class ProcessManager {
|
|
|
1922
1921
|
this.restartAttempts.set(name, attempt + 1);
|
|
1923
1922
|
const encoder = new TextEncoder;
|
|
1924
1923
|
const msg = `\r
|
|
1925
|
-
\x1B[33m[numux] restarting in ${(delay / 1000).toFixed(0)}s (attempt ${attempt + 1}${maxRestarts
|
|
1924
|
+
\x1B[33m[numux] restarting in ${(delay / 1000).toFixed(0)}s (attempt ${attempt + 1}${Number.isFinite(maxRestarts) ? `/${maxRestarts}` : ""})...\x1B[0m\r
|
|
1926
1925
|
`;
|
|
1927
1926
|
this.emit({ type: "output", name, data: encoder.encode(msg) });
|
|
1928
1927
|
const timer = setTimeout(() => {
|
|
@@ -1953,7 +1952,7 @@ class ProcessManager {
|
|
|
1953
1952
|
const state = this.states.get(name);
|
|
1954
1953
|
if (!state)
|
|
1955
1954
|
return;
|
|
1956
|
-
if (state.status === "pending" || state.status === "stopped" || state.status === "
|
|
1955
|
+
if (state.status === "pending" || state.status === "stopped" || state.status === "stopping" || state.status === "skipped")
|
|
1957
1956
|
return;
|
|
1958
1957
|
log(`[${name}] File changed: ${changedFile}, restarting`);
|
|
1959
1958
|
const msg = `\r
|
|
@@ -2196,10 +2195,14 @@ function openLink(link) {
|
|
|
2196
2195
|
}
|
|
2197
2196
|
|
|
2198
2197
|
// src/ui/pane.ts
|
|
2198
|
+
var MAX_SCROLLBACK_LINES = 50000;
|
|
2199
|
+
var MAX_BUFFER_BYTES = 10 * 1024 * 1024;
|
|
2200
|
+
|
|
2199
2201
|
class Pane {
|
|
2200
2202
|
scrollBox;
|
|
2201
2203
|
terminal;
|
|
2202
2204
|
decoder = new TextDecoder;
|
|
2205
|
+
bytesFed = 0;
|
|
2203
2206
|
_onScroll = null;
|
|
2204
2207
|
_onCopy = null;
|
|
2205
2208
|
_onLinkClick = null;
|
|
@@ -2247,6 +2250,11 @@ class Pane {
|
|
|
2247
2250
|
this.scrollBox.add(this.terminal);
|
|
2248
2251
|
}
|
|
2249
2252
|
feed(data) {
|
|
2253
|
+
this.bytesFed += data.length;
|
|
2254
|
+
if (this.terminal.lineCount > MAX_SCROLLBACK_LINES || this.bytesFed > MAX_BUFFER_BYTES) {
|
|
2255
|
+
this.terminal.reset();
|
|
2256
|
+
this.bytesFed = 0;
|
|
2257
|
+
}
|
|
2250
2258
|
const text = this.decoder.decode(data, { stream: true });
|
|
2251
2259
|
this.terminal.feed(text);
|
|
2252
2260
|
}
|
|
@@ -2324,6 +2332,7 @@ class Pane {
|
|
|
2324
2332
|
}
|
|
2325
2333
|
clear() {
|
|
2326
2334
|
this.terminal.reset();
|
|
2335
|
+
this.bytesFed = 0;
|
|
2327
2336
|
}
|
|
2328
2337
|
destroy() {
|
|
2329
2338
|
this.terminal.destroy();
|
|
@@ -3674,7 +3683,7 @@ async function main() {
|
|
|
3674
3683
|
flags.push(`depends on: ${proc.dependsOn.join(", ")}`);
|
|
3675
3684
|
if (proc.readyPattern)
|
|
3676
3685
|
flags.push(`ready: /${proc.readyPattern}/`);
|
|
3677
|
-
if (proc.
|
|
3686
|
+
if (!proc.readyPattern)
|
|
3678
3687
|
flags.push("one-shot");
|
|
3679
3688
|
if (proc.delay)
|
|
3680
3689
|
flags.push(`delay: ${proc.delay}ms`);
|
|
@@ -3739,7 +3748,7 @@ async function main() {
|
|
|
3739
3748
|
}
|
|
3740
3749
|
for (let i = 0;i < otherCommands.length; i++) {
|
|
3741
3750
|
const cmd = otherCommands[i];
|
|
3742
|
-
let name = cmd
|
|
3751
|
+
let name = deriveProcessName(cmd);
|
|
3743
3752
|
if (processes[name])
|
|
3744
3753
|
name = `${name}-${i}`;
|
|
3745
3754
|
processes[name] = cmd;
|
|
@@ -3751,7 +3760,6 @@ async function main() {
|
|
|
3751
3760
|
config = validateConfig(expanded, warnings);
|
|
3752
3761
|
} else {
|
|
3753
3762
|
config = buildConfigFromArgs(parsed.commands, parsed.named, {
|
|
3754
|
-
noRestart: parsed.noRestart,
|
|
3755
3763
|
colors: parsed.colors
|
|
3756
3764
|
});
|
|
3757
3765
|
}
|
|
@@ -3765,8 +3773,6 @@ async function main() {
|
|
|
3765
3773
|
suffix++;
|
|
3766
3774
|
finalName = `${finalName}-${suffix}`;
|
|
3767
3775
|
}
|
|
3768
|
-
if (parsed.noRestart)
|
|
3769
|
-
proc.maxRestarts = 0;
|
|
3770
3776
|
config.processes[finalName] = proc;
|
|
3771
3777
|
}
|
|
3772
3778
|
}
|
|
@@ -3774,11 +3780,6 @@ async function main() {
|
|
|
3774
3780
|
const raw = expandScriptPatterns(await loadConfig(parsed.configPath));
|
|
3775
3781
|
config = validateConfig(raw, warnings);
|
|
3776
3782
|
config = filterByPlatform(config);
|
|
3777
|
-
if (parsed.noRestart) {
|
|
3778
|
-
for (const proc of Object.values(config.processes)) {
|
|
3779
|
-
proc.maxRestarts = 0;
|
|
3780
|
-
}
|
|
3781
|
-
}
|
|
3782
3783
|
}
|
|
3783
3784
|
if (parsed.sort) {
|
|
3784
3785
|
config.sort = parsed.sort;
|
|
@@ -3788,6 +3789,11 @@ async function main() {
|
|
|
3788
3789
|
proc.envFile = parsed.envFile;
|
|
3789
3790
|
}
|
|
3790
3791
|
}
|
|
3792
|
+
if (parsed.maxRestarts !== undefined) {
|
|
3793
|
+
for (const proc of Object.values(config.processes)) {
|
|
3794
|
+
proc.maxRestarts = parsed.maxRestarts;
|
|
3795
|
+
}
|
|
3796
|
+
}
|
|
3791
3797
|
if (parsed.noWatch || config.noWatch) {
|
|
3792
3798
|
for (const proc of Object.values(config.processes)) {
|
|
3793
3799
|
delete proc.watch;
|
|
@@ -3809,11 +3815,6 @@ async function main() {
|
|
|
3809
3815
|
printWarnings(warnings);
|
|
3810
3816
|
const usePrefix = parsed.prefix || config.prefix;
|
|
3811
3817
|
if (usePrefix) {
|
|
3812
|
-
if (!parsed.noRestart) {
|
|
3813
|
-
for (const proc of Object.values(config.processes)) {
|
|
3814
|
-
proc.maxRestarts ??= 0;
|
|
3815
|
-
}
|
|
3816
|
-
}
|
|
3817
3818
|
const display = new PrefixDisplay(manager, config, {
|
|
3818
3819
|
logWriter,
|
|
3819
3820
|
killOthers: parsed.killOthers || config.killOthers,
|
package/dist/types.d.ts
CHANGED
|
@@ -17,13 +17,8 @@ export interface NumuxProcessConfig<K extends string = string> {
|
|
|
17
17
|
/** Regex matched against stdout to signal readiness. Use `RegExp` to capture groups for `$dep.group` expansion */
|
|
18
18
|
readyPattern?: string | RegExp;
|
|
19
19
|
/**
|
|
20
|
-
*
|
|
21
|
-
* @default
|
|
22
|
-
*/
|
|
23
|
-
persistent?: boolean;
|
|
24
|
-
/**
|
|
25
|
-
* Limit auto-restart attempts
|
|
26
|
-
* @default Infinity
|
|
20
|
+
* Limit auto-restart attempts (only restarts on non-zero exit)
|
|
21
|
+
* @default 0
|
|
27
22
|
*/
|
|
28
23
|
maxRestarts?: number;
|
|
29
24
|
/** Milliseconds to wait for readyPattern before failing */
|
|
@@ -74,18 +69,12 @@ export interface NumuxConfig<K extends string = string> {
|
|
|
74
69
|
*/
|
|
75
70
|
showCommand?: boolean;
|
|
76
71
|
/**
|
|
77
|
-
* Global restart limit, inherited by all processes
|
|
78
|
-
* @default
|
|
72
|
+
* Global restart limit, inherited by all processes (only restarts on non-zero exit)
|
|
73
|
+
* @default 0
|
|
79
74
|
*/
|
|
80
75
|
maxRestarts?: number;
|
|
81
76
|
/** Global ready timeout (ms), inherited by all processes */
|
|
82
77
|
readyTimeout?: number;
|
|
83
|
-
/**
|
|
84
|
-
* Set to `false` to make all processes non-persistent (one-shot) by default.
|
|
85
|
-
* Individual processes can still override with their own `persistent` value.
|
|
86
|
-
* @default true
|
|
87
|
-
*/
|
|
88
|
-
persistent?: boolean;
|
|
89
78
|
/**
|
|
90
79
|
* Global stop signal, inherited by all processes
|
|
91
80
|
* @default 'SIGTERM'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "numux",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "Terminal multiplexer with dependency orchestration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -36,7 +36,8 @@
|
|
|
36
36
|
"test": "bun test",
|
|
37
37
|
"typecheck": "bunx tsc --noEmit",
|
|
38
38
|
"lint": "biome check .",
|
|
39
|
-
"fix": "biome check . --fix --unsafe"
|
|
39
|
+
"fix": "biome check . --fix --unsafe",
|
|
40
|
+
"prepare": "git config core.hooksPath .githooks"
|
|
40
41
|
},
|
|
41
42
|
"files": [
|
|
42
43
|
"dist/"
|
|
@@ -47,6 +48,8 @@
|
|
|
47
48
|
},
|
|
48
49
|
"devDependencies": {
|
|
49
50
|
"@biomejs/biome": "^2.4.4",
|
|
51
|
+
"@commitlint/cli": "^20.4.2",
|
|
52
|
+
"@commitlint/config-conventional": "^20.4.2",
|
|
50
53
|
"@types/bun": "^1.3.9"
|
|
51
54
|
}
|
|
52
55
|
}
|