numux 1.19.0 → 1.21.0
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 -0
- package/dist/numux.js +65 -6
- package/dist/types.d.ts +18 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -193,6 +193,11 @@ Top-level options apply to all processes (process-level settings override):
|
|
|
193
193
|
| `env` | `Record<string, string>` | Environment variables merged into all processes (process `env` overrides per key) |
|
|
194
194
|
| `envFile` | `string \| string[] \| false` | `.env` file(s) for all processes (process `envFile` replaces if set; `false` disables) |
|
|
195
195
|
| `showCommand` | `boolean` | Print the command being run as the first line of output (default: `true`) |
|
|
196
|
+
| `maxRestarts` | `number` | Restart limit for all processes (default: `Infinity`) |
|
|
197
|
+
| `readyTimeout` | `number` | Ready timeout in ms for all processes |
|
|
198
|
+
| `stopSignal` | `'SIGTERM' \| 'SIGINT' \| 'SIGHUP'` | Stop signal for all processes (default: `'SIGTERM'`) |
|
|
199
|
+
| `errorMatcher` | `boolean \| string` | Error detection for all processes (`true` = ANSI red, string = regex) |
|
|
200
|
+
| `watch` | `string \| string[]` | Watch patterns for all processes (process `watch` replaces if set) |
|
|
196
201
|
|
|
197
202
|
```ts
|
|
198
203
|
export default defineConfig({
|
|
@@ -223,6 +228,7 @@ Each process accepts:
|
|
|
223
228
|
| `maxRestarts` | `number` | `Infinity` | Max auto-restart attempts before giving up |
|
|
224
229
|
| `delay` | `number` | — | Milliseconds to wait before starting the process |
|
|
225
230
|
| `condition` | `string` | — | Env var name; process skipped if falsy. Prefix with `!` to negate |
|
|
231
|
+
| `platform` | `string \| string[]` | — | OS(es) this process runs on (e.g. `'darwin'`, `'linux'`). Non-matching processes are removed; dependents still start |
|
|
226
232
|
| `stopSignal` | `string` | `SIGTERM` | Signal for graceful stop (`SIGTERM`, `SIGINT`, or `SIGHUP`) |
|
|
227
233
|
| `color` | `string \| string[]` | auto | Hex (e.g. `"#ff6600"`) or basic name: black, red, green, yellow, blue, magenta, cyan, white, gray, orange, purple |
|
|
228
234
|
| `watch` | `string \| string[]` | — | Glob patterns — restart process when matching files change |
|
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: "1.
|
|
39
|
+
version: "1.21.0",
|
|
40
40
|
description: "Terminal multiplexer with dependency orchestration",
|
|
41
41
|
type: "module",
|
|
42
42
|
license: "MIT",
|
|
@@ -826,6 +826,34 @@ async function autoDetectConfig(cwd) {
|
|
|
826
826
|
throw new Error(`No numux config found. Create one of: ${CONFIG_FILES.join(", ")}, or add a "numux" key to package.json`);
|
|
827
827
|
}
|
|
828
828
|
|
|
829
|
+
// src/config/platform.ts
|
|
830
|
+
function filterByPlatform(config, currentPlatform = process.platform) {
|
|
831
|
+
const excluded = new Set;
|
|
832
|
+
for (const [name, proc] of Object.entries(config.processes)) {
|
|
833
|
+
if (!proc.platform)
|
|
834
|
+
continue;
|
|
835
|
+
const platforms = Array.isArray(proc.platform) ? proc.platform : [proc.platform];
|
|
836
|
+
if (!platforms.includes(currentPlatform)) {
|
|
837
|
+
excluded.add(name);
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
if (excluded.size === 0)
|
|
841
|
+
return config;
|
|
842
|
+
const processes = {};
|
|
843
|
+
for (const [name, proc] of Object.entries(config.processes)) {
|
|
844
|
+
if (excluded.has(name))
|
|
845
|
+
continue;
|
|
846
|
+
const copy = { ...proc };
|
|
847
|
+
if (copy.dependsOn) {
|
|
848
|
+
copy.dependsOn = copy.dependsOn.filter((d) => !excluded.has(d));
|
|
849
|
+
if (copy.dependsOn.length === 0)
|
|
850
|
+
copy.dependsOn = undefined;
|
|
851
|
+
}
|
|
852
|
+
processes[name] = copy;
|
|
853
|
+
}
|
|
854
|
+
return { processes };
|
|
855
|
+
}
|
|
856
|
+
|
|
829
857
|
// src/config/resolver.ts
|
|
830
858
|
function resolveDependencyTiers(config) {
|
|
831
859
|
const names = Object.keys(config.processes);
|
|
@@ -1007,6 +1035,11 @@ function validateConfig(raw, warnings) {
|
|
|
1007
1035
|
const globalCwd = typeof config.cwd === "string" ? config.cwd : undefined;
|
|
1008
1036
|
const globalShowCommand = typeof config.showCommand === "boolean" ? config.showCommand : undefined;
|
|
1009
1037
|
const globalEnvFile = validateEnvFile(config.envFile);
|
|
1038
|
+
const globalMaxRestarts = typeof config.maxRestarts === "number" && config.maxRestarts >= 0 ? config.maxRestarts : undefined;
|
|
1039
|
+
const globalReadyTimeout = typeof config.readyTimeout === "number" && config.readyTimeout > 0 ? config.readyTimeout : undefined;
|
|
1040
|
+
const globalStopSignal = validateStopSignal(config.stopSignal);
|
|
1041
|
+
const globalErrorMatcher = validateErrorMatcher("(global)", config.errorMatcher);
|
|
1042
|
+
const globalWatch = validateStringOrStringArray(config.watch);
|
|
1010
1043
|
let globalEnv;
|
|
1011
1044
|
if (config.env && typeof config.env === "object") {
|
|
1012
1045
|
for (const [k, v] of Object.entries(config.env)) {
|
|
@@ -1086,6 +1119,12 @@ function validateConfig(raw, warnings) {
|
|
|
1086
1119
|
const processEnv = p.env && typeof p.env === "object" ? p.env : undefined;
|
|
1087
1120
|
const processEnvFile = validateEnvFile(p.envFile);
|
|
1088
1121
|
const showCommand = typeof p.showCommand === "boolean" ? p.showCommand : globalShowCommand ?? true;
|
|
1122
|
+
const platform = validatePlatform(name, p.platform);
|
|
1123
|
+
const processMaxRestarts = typeof p.maxRestarts === "number" && p.maxRestarts >= 0 ? p.maxRestarts : undefined;
|
|
1124
|
+
const processReadyTimeout = typeof p.readyTimeout === "number" && p.readyTimeout > 0 ? p.readyTimeout : undefined;
|
|
1125
|
+
const processStopSignal = validateStopSignal(p.stopSignal);
|
|
1126
|
+
const processErrorMatcher = validateErrorMatcher(name, p.errorMatcher);
|
|
1127
|
+
const processWatch = validateStringOrStringArray(p.watch);
|
|
1089
1128
|
validated[name] = {
|
|
1090
1129
|
command: p.command,
|
|
1091
1130
|
cwd: processCwd ?? globalCwd,
|
|
@@ -1094,15 +1133,16 @@ function validateConfig(raw, warnings) {
|
|
|
1094
1133
|
dependsOn: Array.isArray(p.dependsOn) ? p.dependsOn : undefined,
|
|
1095
1134
|
readyPattern,
|
|
1096
1135
|
persistent,
|
|
1097
|
-
maxRestarts:
|
|
1098
|
-
readyTimeout:
|
|
1136
|
+
maxRestarts: processMaxRestarts ?? globalMaxRestarts,
|
|
1137
|
+
readyTimeout: processReadyTimeout ?? globalReadyTimeout,
|
|
1099
1138
|
delay: typeof p.delay === "number" && p.delay > 0 ? p.delay : undefined,
|
|
1100
1139
|
condition: typeof p.condition === "string" && p.condition.trim() ? p.condition.trim() : undefined,
|
|
1101
|
-
|
|
1140
|
+
platform,
|
|
1141
|
+
stopSignal: processStopSignal ?? globalStopSignal,
|
|
1102
1142
|
color: typeof p.color === "string" ? p.color : Array.isArray(p.color) ? p.color : undefined,
|
|
1103
|
-
watch:
|
|
1143
|
+
watch: processWatch ?? globalWatch,
|
|
1104
1144
|
interactive: typeof p.interactive === "boolean" ? p.interactive : false,
|
|
1105
|
-
errorMatcher:
|
|
1145
|
+
errorMatcher: processErrorMatcher ?? globalErrorMatcher,
|
|
1106
1146
|
showCommand
|
|
1107
1147
|
};
|
|
1108
1148
|
}
|
|
@@ -1136,6 +1176,19 @@ function validateErrorMatcher(name, value) {
|
|
|
1136
1176
|
}
|
|
1137
1177
|
return;
|
|
1138
1178
|
}
|
|
1179
|
+
var VALID_PLATFORMS = new Set(["aix", "darwin", "freebsd", "linux", "openbsd", "sunos", "win32"]);
|
|
1180
|
+
function validatePlatform(name, value) {
|
|
1181
|
+
const arr = validateStringOrStringArray(value);
|
|
1182
|
+
if (arr === undefined)
|
|
1183
|
+
return;
|
|
1184
|
+
const values = typeof arr === "string" ? [arr] : arr;
|
|
1185
|
+
for (const v of values) {
|
|
1186
|
+
if (!VALID_PLATFORMS.has(v)) {
|
|
1187
|
+
throw new Error(`Process "${name}".platform "${v}" is not valid. Must be one of: ${[...VALID_PLATFORMS].join(", ")}`);
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
return arr;
|
|
1191
|
+
}
|
|
1139
1192
|
var VALID_STOP_SIGNALS = new Set(["SIGTERM", "SIGINT", "SIGHUP"]);
|
|
1140
1193
|
function validateStopSignal(value) {
|
|
1141
1194
|
if (typeof value === "string" && VALID_STOP_SIGNALS.has(value)) {
|
|
@@ -3302,6 +3355,7 @@ async function main() {
|
|
|
3302
3355
|
const raw = expandScriptPatterns(await loadConfig(parsed.configPath));
|
|
3303
3356
|
const warnings2 = [];
|
|
3304
3357
|
let config2 = validateConfig(raw, warnings2);
|
|
3358
|
+
config2 = filterByPlatform(config2);
|
|
3305
3359
|
if (parsed.only || parsed.exclude) {
|
|
3306
3360
|
config2 = filterConfig(config2, parsed.only, parsed.exclude);
|
|
3307
3361
|
}
|
|
@@ -3325,6 +3379,10 @@ async function main() {
|
|
|
3325
3379
|
flags.push(`delay: ${proc.delay}ms`);
|
|
3326
3380
|
if (proc.condition)
|
|
3327
3381
|
flags.push(`if: ${proc.condition}`);
|
|
3382
|
+
if (proc.platform) {
|
|
3383
|
+
const p = Array.isArray(proc.platform) ? proc.platform : [proc.platform];
|
|
3384
|
+
flags.push(`platform: ${p.join(", ")}`);
|
|
3385
|
+
}
|
|
3328
3386
|
if (proc.watch) {
|
|
3329
3387
|
const patterns = Array.isArray(proc.watch) ? proc.watch : [proc.watch];
|
|
3330
3388
|
flags.push(`watch: ${patterns.join(", ")}`);
|
|
@@ -3414,6 +3472,7 @@ async function main() {
|
|
|
3414
3472
|
} else {
|
|
3415
3473
|
const raw = expandScriptPatterns(await loadConfig(parsed.configPath));
|
|
3416
3474
|
config = validateConfig(raw, warnings);
|
|
3475
|
+
config = filterByPlatform(config);
|
|
3417
3476
|
if (parsed.noRestart) {
|
|
3418
3477
|
for (const proc of Object.values(config.processes)) {
|
|
3419
3478
|
proc.maxRestarts = 0;
|
package/dist/types.d.ts
CHANGED
|
@@ -31,6 +31,8 @@ export interface NumuxProcessConfig<K extends string = string> {
|
|
|
31
31
|
delay?: number;
|
|
32
32
|
/** Env var name (prefix with `!` to negate); process skipped if condition is falsy */
|
|
33
33
|
condition?: string;
|
|
34
|
+
/** OS(es) this process runs on (e.g. `'darwin'`, `'linux'`). Non-matching processes are removed, their dependents still start */
|
|
35
|
+
platform?: string | string[];
|
|
34
36
|
/**
|
|
35
37
|
* Signal for graceful stop
|
|
36
38
|
* @default 'SIGTERM'
|
|
@@ -70,6 +72,22 @@ export interface NumuxConfig<K extends string = string> {
|
|
|
70
72
|
* @default true
|
|
71
73
|
*/
|
|
72
74
|
showCommand?: boolean;
|
|
75
|
+
/**
|
|
76
|
+
* Global restart limit, inherited by all processes
|
|
77
|
+
* @default Infinity
|
|
78
|
+
*/
|
|
79
|
+
maxRestarts?: number;
|
|
80
|
+
/** Global ready timeout (ms), inherited by all processes */
|
|
81
|
+
readyTimeout?: number;
|
|
82
|
+
/**
|
|
83
|
+
* Global stop signal, inherited by all processes
|
|
84
|
+
* @default 'SIGTERM'
|
|
85
|
+
*/
|
|
86
|
+
stopSignal?: 'SIGTERM' | 'SIGINT' | 'SIGHUP';
|
|
87
|
+
/** Global error matcher, inherited by all processes. `true` = detect ANSI red output, string = regex */
|
|
88
|
+
errorMatcher?: boolean | string;
|
|
89
|
+
/** Global watch patterns, inherited by processes without their own watch */
|
|
90
|
+
watch?: string | string[];
|
|
73
91
|
processes: Record<K, NumuxProcessConfig<K> | NumuxScriptPattern<K> | string>;
|
|
74
92
|
}
|
|
75
93
|
/** Process config after validation — dependsOn is always normalized to an array */
|