numux 1.18.0 → 1.20.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 +7 -4
- package/dist/config.d.ts +1 -1
- package/dist/numux.js +53 -2
- package/dist/types.d.ts +56 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -191,7 +191,8 @@ Top-level options apply to all processes (process-level settings override):
|
|
|
191
191
|
|-------|------|-------------|
|
|
192
192
|
| `cwd` | `string` | Working directory for all processes (process `cwd` overrides) |
|
|
193
193
|
| `env` | `Record<string, string>` | Environment variables merged into all processes (process `env` overrides per key) |
|
|
194
|
-
| `envFile` | `string \| string[]` | `.env` file(s) for all processes (process `envFile` replaces if set) |
|
|
194
|
+
| `envFile` | `string \| string[] \| false` | `.env` file(s) for all processes (process `envFile` replaces if set; `false` disables) |
|
|
195
|
+
| `showCommand` | `boolean` | Print the command being run as the first line of output (default: `true`) |
|
|
195
196
|
|
|
196
197
|
```ts
|
|
197
198
|
export default defineConfig({
|
|
@@ -211,10 +212,10 @@ Each process accepts:
|
|
|
211
212
|
|
|
212
213
|
| Field | Type | Default | Description |
|
|
213
214
|
|-------|------|---------|-------------|
|
|
214
|
-
| `command` | `string` | *required* | Shell command to run |
|
|
215
|
+
| `command` | `string` | *required* | Shell command to run. Supports `$dep.group` references from dependency capture groups |
|
|
215
216
|
| `cwd` | `string` | `process.cwd()` | Working directory |
|
|
216
|
-
| `env` | `Record<string, string>` | — | Extra environment variables |
|
|
217
|
-
| `envFile` | `string \| string[]` | — | `.env` file path(s) to load (relative to `cwd`) |
|
|
217
|
+
| `env` | `Record<string, string>` | — | Extra environment variables. Values support `$dep.group` references from dependency capture groups |
|
|
218
|
+
| `envFile` | `string \| string[] \| false` | — | `.env` file path(s) to load (relative to `cwd`); `false` disables inherited envFile |
|
|
218
219
|
| `dependsOn` | `string[]` | — | Processes that must be ready first |
|
|
219
220
|
| `readyPattern` | `string \| RegExp` | — | Regex matched against stdout to signal readiness. Use `RegExp` to capture groups (see below) |
|
|
220
221
|
| `readyTimeout` | `number` | — | Milliseconds to wait for `readyPattern` before failing |
|
|
@@ -222,11 +223,13 @@ Each process accepts:
|
|
|
222
223
|
| `maxRestarts` | `number` | `Infinity` | Max auto-restart attempts before giving up |
|
|
223
224
|
| `delay` | `number` | — | Milliseconds to wait before starting the process |
|
|
224
225
|
| `condition` | `string` | — | Env var name; process skipped if falsy. Prefix with `!` to negate |
|
|
226
|
+
| `platform` | `string \| string[]` | — | OS(es) this process runs on (e.g. `'darwin'`, `'linux'`). Non-matching processes are removed; dependents still start |
|
|
225
227
|
| `stopSignal` | `string` | `SIGTERM` | Signal for graceful stop (`SIGTERM`, `SIGINT`, or `SIGHUP`) |
|
|
226
228
|
| `color` | `string \| string[]` | auto | Hex (e.g. `"#ff6600"`) or basic name: black, red, green, yellow, blue, magenta, cyan, white, gray, orange, purple |
|
|
227
229
|
| `watch` | `string \| string[]` | — | Glob patterns — restart process when matching files change |
|
|
228
230
|
| `interactive` | `boolean` | `false` | When `true`, keyboard input is forwarded to the process |
|
|
229
231
|
| `errorMatcher` | `boolean \| string` | — | `true` detects ANSI red output, string = regex pattern — shows error indicator on tab |
|
|
232
|
+
| `showCommand` | `boolean` | `true` | Print the command being run as the first line of output |
|
|
230
233
|
|
|
231
234
|
### File watching
|
|
232
235
|
|
package/dist/config.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { NumuxConfig } from './types';
|
|
2
2
|
export type { NumuxConfig, NumuxProcessConfig } from './types';
|
|
3
3
|
/** Type-safe helper for numux.config.ts files. */
|
|
4
|
-
export declare function defineConfig(config: NumuxConfig): NumuxConfig
|
|
4
|
+
export declare function defineConfig<K extends string>(config: NumuxConfig<K>): NumuxConfig<K>;
|
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.20.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);
|
|
@@ -1030,8 +1058,10 @@ function validateConfig(raw, warnings) {
|
|
|
1030
1058
|
throw new Error(`Process "${name}" must have a non-empty "command" string`);
|
|
1031
1059
|
}
|
|
1032
1060
|
if (p.dependsOn !== undefined) {
|
|
1061
|
+
if (typeof p.dependsOn === "string")
|
|
1062
|
+
p.dependsOn = [p.dependsOn];
|
|
1033
1063
|
if (!Array.isArray(p.dependsOn)) {
|
|
1034
|
-
throw new Error(`Process "${name}".dependsOn must be
|
|
1064
|
+
throw new Error(`Process "${name}".dependsOn must be a string or array`);
|
|
1035
1065
|
}
|
|
1036
1066
|
for (const dep of p.dependsOn) {
|
|
1037
1067
|
if (typeof dep !== "string") {
|
|
@@ -1084,6 +1114,7 @@ function validateConfig(raw, warnings) {
|
|
|
1084
1114
|
const processEnv = p.env && typeof p.env === "object" ? p.env : undefined;
|
|
1085
1115
|
const processEnvFile = validateEnvFile(p.envFile);
|
|
1086
1116
|
const showCommand = typeof p.showCommand === "boolean" ? p.showCommand : globalShowCommand ?? true;
|
|
1117
|
+
const platform = validatePlatform(name, p.platform);
|
|
1087
1118
|
validated[name] = {
|
|
1088
1119
|
command: p.command,
|
|
1089
1120
|
cwd: processCwd ?? globalCwd,
|
|
@@ -1096,6 +1127,7 @@ function validateConfig(raw, warnings) {
|
|
|
1096
1127
|
readyTimeout: typeof p.readyTimeout === "number" && p.readyTimeout > 0 ? p.readyTimeout : undefined,
|
|
1097
1128
|
delay: typeof p.delay === "number" && p.delay > 0 ? p.delay : undefined,
|
|
1098
1129
|
condition: typeof p.condition === "string" && p.condition.trim() ? p.condition.trim() : undefined,
|
|
1130
|
+
platform,
|
|
1099
1131
|
stopSignal: validateStopSignal(p.stopSignal),
|
|
1100
1132
|
color: typeof p.color === "string" ? p.color : Array.isArray(p.color) ? p.color : undefined,
|
|
1101
1133
|
watch: validateStringOrStringArray(p.watch),
|
|
@@ -1134,6 +1166,19 @@ function validateErrorMatcher(name, value) {
|
|
|
1134
1166
|
}
|
|
1135
1167
|
return;
|
|
1136
1168
|
}
|
|
1169
|
+
var VALID_PLATFORMS = new Set(["aix", "darwin", "freebsd", "linux", "openbsd", "sunos", "win32"]);
|
|
1170
|
+
function validatePlatform(name, value) {
|
|
1171
|
+
const arr = validateStringOrStringArray(value);
|
|
1172
|
+
if (arr === undefined)
|
|
1173
|
+
return;
|
|
1174
|
+
const values = typeof arr === "string" ? [arr] : arr;
|
|
1175
|
+
for (const v of values) {
|
|
1176
|
+
if (!VALID_PLATFORMS.has(v)) {
|
|
1177
|
+
throw new Error(`Process "${name}".platform "${v}" is not valid. Must be one of: ${[...VALID_PLATFORMS].join(", ")}`);
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
return arr;
|
|
1181
|
+
}
|
|
1137
1182
|
var VALID_STOP_SIGNALS = new Set(["SIGTERM", "SIGINT", "SIGHUP"]);
|
|
1138
1183
|
function validateStopSignal(value) {
|
|
1139
1184
|
if (typeof value === "string" && VALID_STOP_SIGNALS.has(value)) {
|
|
@@ -3300,6 +3345,7 @@ async function main() {
|
|
|
3300
3345
|
const raw = expandScriptPatterns(await loadConfig(parsed.configPath));
|
|
3301
3346
|
const warnings2 = [];
|
|
3302
3347
|
let config2 = validateConfig(raw, warnings2);
|
|
3348
|
+
config2 = filterByPlatform(config2);
|
|
3303
3349
|
if (parsed.only || parsed.exclude) {
|
|
3304
3350
|
config2 = filterConfig(config2, parsed.only, parsed.exclude);
|
|
3305
3351
|
}
|
|
@@ -3323,6 +3369,10 @@ async function main() {
|
|
|
3323
3369
|
flags.push(`delay: ${proc.delay}ms`);
|
|
3324
3370
|
if (proc.condition)
|
|
3325
3371
|
flags.push(`if: ${proc.condition}`);
|
|
3372
|
+
if (proc.platform) {
|
|
3373
|
+
const p = Array.isArray(proc.platform) ? proc.platform : [proc.platform];
|
|
3374
|
+
flags.push(`platform: ${p.join(", ")}`);
|
|
3375
|
+
}
|
|
3326
3376
|
if (proc.watch) {
|
|
3327
3377
|
const patterns = Array.isArray(proc.watch) ? proc.watch : [proc.watch];
|
|
3328
3378
|
flags.push(`watch: ${patterns.join(", ")}`);
|
|
@@ -3412,6 +3462,7 @@ async function main() {
|
|
|
3412
3462
|
} else {
|
|
3413
3463
|
const raw = expandScriptPatterns(await loadConfig(parsed.configPath));
|
|
3414
3464
|
config = validateConfig(raw, warnings);
|
|
3465
|
+
config = filterByPlatform(config);
|
|
3415
3466
|
if (parsed.noRestart) {
|
|
3416
3467
|
for (const proc of Object.values(config.processes)) {
|
|
3417
3468
|
proc.maxRestarts = 0;
|
package/dist/types.d.ts
CHANGED
|
@@ -1,42 +1,91 @@
|
|
|
1
|
-
export interface NumuxProcessConfig {
|
|
1
|
+
export interface NumuxProcessConfig<K extends string = string> {
|
|
2
|
+
/** Shell command to run. Supports `$dep.group` references from dependency capture groups */
|
|
2
3
|
command: string;
|
|
4
|
+
/** Working directory for the process */
|
|
3
5
|
cwd?: string;
|
|
6
|
+
/**
|
|
7
|
+
* Extra environment variables. Values support `$dep.group` references
|
|
8
|
+
* from dependency capture groups.
|
|
9
|
+
* @example { DB_PORT: '$db.port' }
|
|
10
|
+
*/
|
|
4
11
|
env?: Record<string, string>;
|
|
12
|
+
/** .env file path(s) to load, or `false` to disable */
|
|
5
13
|
envFile?: string | string[] | false;
|
|
6
|
-
|
|
14
|
+
/** Processes that must be ready before this one starts */
|
|
15
|
+
dependsOn?: NoInfer<K> | NoInfer<K>[];
|
|
16
|
+
/** Regex matched against stdout to signal readiness. Use `RegExp` to capture groups for `$dep.group` expansion */
|
|
7
17
|
readyPattern?: string | RegExp;
|
|
18
|
+
/**
|
|
19
|
+
* Set to `false` for one-shot processes
|
|
20
|
+
* @default true
|
|
21
|
+
*/
|
|
8
22
|
persistent?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Limit auto-restart attempts
|
|
25
|
+
* @default Infinity
|
|
26
|
+
*/
|
|
9
27
|
maxRestarts?: number;
|
|
28
|
+
/** Milliseconds to wait for readyPattern before failing */
|
|
10
29
|
readyTimeout?: number;
|
|
30
|
+
/** Milliseconds to wait before starting the process */
|
|
11
31
|
delay?: number;
|
|
32
|
+
/** Env var name (prefix with `!` to negate); process skipped if condition is falsy */
|
|
12
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[];
|
|
36
|
+
/**
|
|
37
|
+
* Signal for graceful stop
|
|
38
|
+
* @default 'SIGTERM'
|
|
39
|
+
*/
|
|
13
40
|
stopSignal?: 'SIGTERM' | 'SIGINT' | 'SIGHUP';
|
|
41
|
+
/** Hex color (e.g. `"#ff6600"`) or color name. Array for round-robin in script patterns */
|
|
14
42
|
color?: string | string[];
|
|
43
|
+
/** Glob patterns — restart process when matching files change */
|
|
15
44
|
watch?: string | string[];
|
|
45
|
+
/**
|
|
46
|
+
* When true, keyboard input is forwarded to the process
|
|
47
|
+
* @default false
|
|
48
|
+
*/
|
|
16
49
|
interactive?: boolean;
|
|
50
|
+
/** `true` = detect ANSI red output, string = regex pattern */
|
|
17
51
|
errorMatcher?: boolean | string;
|
|
52
|
+
/**
|
|
53
|
+
* Print the command being run as the first line of output
|
|
54
|
+
* @default true
|
|
55
|
+
*/
|
|
18
56
|
showCommand?: boolean;
|
|
19
57
|
}
|
|
20
58
|
/** Config for npm: wildcard entries — command is derived from package.json scripts */
|
|
21
|
-
export type NumuxScriptPattern = Omit<NumuxProcessConfig
|
|
59
|
+
export type NumuxScriptPattern<K extends string = string> = Omit<NumuxProcessConfig<K>, 'command'> & {
|
|
22
60
|
command?: never;
|
|
23
61
|
};
|
|
24
62
|
/** Raw config as authored — processes can be string shorthand, full objects, or wildcard patterns */
|
|
25
|
-
export interface NumuxConfig {
|
|
63
|
+
export interface NumuxConfig<K extends string = string> {
|
|
64
|
+
/** Global working directory, inherited by all processes */
|
|
26
65
|
cwd?: string;
|
|
66
|
+
/** Global env vars, merged into each process (process-level overrides) */
|
|
27
67
|
env?: Record<string, string>;
|
|
68
|
+
/** Global .env file(s), inherited by processes without their own envFile; `false` disables */
|
|
28
69
|
envFile?: string | string[] | false;
|
|
70
|
+
/**
|
|
71
|
+
* Global showCommand flag, inherited by all processes
|
|
72
|
+
* @default true
|
|
73
|
+
*/
|
|
29
74
|
showCommand?: boolean;
|
|
30
|
-
processes: Record<
|
|
75
|
+
processes: Record<K, NumuxProcessConfig<K> | NumuxScriptPattern<K> | string>;
|
|
76
|
+
}
|
|
77
|
+
/** Process config after validation — dependsOn is always normalized to an array */
|
|
78
|
+
export interface ResolvedProcessConfig extends Omit<NumuxProcessConfig, 'dependsOn'> {
|
|
79
|
+
dependsOn?: string[];
|
|
31
80
|
}
|
|
32
81
|
/** Validated config with all shorthand expanded to full objects */
|
|
33
82
|
export interface ResolvedNumuxConfig {
|
|
34
|
-
processes: Record<string,
|
|
83
|
+
processes: Record<string, ResolvedProcessConfig>;
|
|
35
84
|
}
|
|
36
85
|
export type ProcessStatus = 'pending' | 'starting' | 'ready' | 'running' | 'stopping' | 'stopped' | 'finished' | 'failed' | 'skipped';
|
|
37
86
|
export interface ProcessState {
|
|
38
87
|
name: string;
|
|
39
|
-
config:
|
|
88
|
+
config: ResolvedProcessConfig;
|
|
40
89
|
status: ProcessStatus;
|
|
41
90
|
exitCode: number | null;
|
|
42
91
|
restartCount: number;
|