numux 1.24.0 → 1.26.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 CHANGED
@@ -1,6 +1,10 @@
1
1
  # numux
2
2
 
3
- Terminal multiplexer with dependency orchestration. Run multiple processes in a tabbed TUI with a dependency graph controlling startup order.
3
+ Terminal multiplexer with dependency orchestration. Run multiple processes in a tabbed TUI with a dependency graph controlling startup order, readiness detection, and output capture between processes.
4
+
5
+ Works with zero configuration — pass commands as arguments, run a script across monorepo workspaces with `-w`, or match multiple scripts with glob patterns like `'dev:*'`. For advanced setups, define a typed config with conditional processes, file watching with auto-restart, error detection, log persistence, and output capture — e.g. extract a port from one process's stdout and pass it to another process's command or env.
6
+
7
+ Inspired by `sst dev` and `concurrently`
4
8
 
5
9
  ## Install
6
10
 
@@ -162,7 +166,8 @@ Template properties (color, env, dependsOn, etc.) are inherited by all matched p
162
166
  | `-p, --prefix` | Prefixed output mode (no TUI, for CI/scripts) |
163
167
  | `--only <a,b,...>` | Only run these processes (+ their dependencies) |
164
168
  | `--exclude <a,b,...>` | Exclude these processes |
165
- | `--kill-others` | Kill all processes when any exits |
169
+ | `--kill-others` | Kill all processes when any exits (regardless of exit code) |
170
+ | `--kill-others-on-fail` | Kill all processes when any exits with a non-zero exit code |
166
171
  | `--no-restart` | Disable auto-restart for crashed processes |
167
172
  | `-s, --sort <mode>` | Tab display order: `config` (default), `alphabetical`, `topological` |
168
173
  | `--no-watch` | Disable file watching even if config has `watch` patterns |
@@ -194,6 +199,7 @@ Top-level options apply to all processes (process-level settings override):
194
199
  | `env` | `Record<string, string>` | Environment variables merged into all processes (process `env` overrides per key) |
195
200
  | `envFile` | `string \| string[] \| false` | `.env` file(s) for all processes (process `envFile` replaces if set; `false` disables) |
196
201
  | `showCommand` | `boolean` | Print the command being run as the first line of output (default: `true`) |
202
+ | `persistent` | `boolean` | Set to `false` to make all processes one-shot by default (default: `true`) |
197
203
  | `maxRestarts` | `number` | Restart limit for all processes (default: `Infinity`) |
198
204
  | `readyTimeout` | `number` | Ready timeout in ms for all processes |
199
205
  | `stopSignal` | `'SIGTERM' \| 'SIGINT' \| 'SIGHUP'` | Stop signal for all processes (default: `'SIGTERM'`) |
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.24.0",
39
+ version: "1.26.0",
40
40
  description: "Terminal multiplexer with dependency orchestration",
41
41
  type: "module",
42
42
  license: "MIT",
@@ -192,7 +192,13 @@ var FLAGS = [
192
192
  type: "boolean",
193
193
  long: "--kill-others",
194
194
  key: "killOthers",
195
- description: "Kill all processes when any exits"
195
+ description: "Kill all processes when any exits (regardless of exit code)"
196
+ },
197
+ {
198
+ type: "boolean",
199
+ long: "--kill-others-on-fail",
200
+ key: "killOthersOnFail",
201
+ description: "Kill all processes when any exits with non-zero code"
196
202
  },
197
203
  {
198
204
  type: "boolean",
@@ -342,6 +348,7 @@ function parseArgs(argv) {
342
348
  exec: false,
343
349
  prefix: false,
344
350
  killOthers: false,
351
+ killOthersOnFail: false,
345
352
  timestamps: false,
346
353
  noRestart: false,
347
354
  noWatch: false,
@@ -1046,6 +1053,7 @@ function validateConfig(raw, warnings) {
1046
1053
  const globalEnvFile = validateEnvFile(config.envFile);
1047
1054
  const globalMaxRestarts = typeof config.maxRestarts === "number" && config.maxRestarts >= 0 ? config.maxRestarts : undefined;
1048
1055
  const globalReadyTimeout = typeof config.readyTimeout === "number" && config.readyTimeout > 0 ? config.readyTimeout : undefined;
1056
+ const globalPersistent = typeof config.persistent === "boolean" ? config.persistent : undefined;
1049
1057
  const globalStopSignal = validateStopSignal(config.stopSignal);
1050
1058
  const globalErrorMatcher = validateErrorMatcher("(global)", config.errorMatcher);
1051
1059
  const globalWatch = validateStringOrStringArray(config.watch);
@@ -1062,6 +1070,7 @@ function validateConfig(raw, warnings) {
1062
1070
  const prefix = config.prefix === true ? true : undefined;
1063
1071
  const timestamps = config.timestamps === true ? true : undefined;
1064
1072
  const killOthers = config.killOthers === true ? true : undefined;
1073
+ const killOthersOnFail = config.killOthersOnFail === true ? true : undefined;
1065
1074
  const noWatch = config.noWatch === true ? true : undefined;
1066
1075
  const logDir = typeof config.logDir === "string" && config.logDir.trim() ? config.logDir.trim() : undefined;
1067
1076
  const validated = {};
@@ -1106,7 +1115,7 @@ function validateConfig(raw, warnings) {
1106
1115
  }
1107
1116
  }
1108
1117
  }
1109
- const persistent = typeof p.persistent === "boolean" ? p.persistent : true;
1118
+ const persistent = typeof p.persistent === "boolean" ? p.persistent : globalPersistent ?? true;
1110
1119
  const readyPattern = p.readyPattern instanceof RegExp ? p.readyPattern : typeof p.readyPattern === "string" ? p.readyPattern : undefined;
1111
1120
  if (typeof readyPattern === "string") {
1112
1121
  try {
@@ -1166,6 +1175,7 @@ function validateConfig(raw, warnings) {
1166
1175
  ...prefix ? { prefix } : {},
1167
1176
  ...timestamps ? { timestamps } : {},
1168
1177
  ...killOthers ? { killOthers } : {},
1178
+ ...killOthersOnFail ? { killOthersOnFail } : {},
1169
1179
  ...noWatch ? { noWatch } : {},
1170
1180
  ...logDir ? { logDir } : {},
1171
1181
  processes: validated
@@ -3184,6 +3194,7 @@ class PrefixDisplay {
3184
3194
  buffers = new Map;
3185
3195
  logWriter;
3186
3196
  killOthers;
3197
+ killOthersOnFail;
3187
3198
  timestamps;
3188
3199
  stopping = false;
3189
3200
  startTime = 0;
@@ -3191,6 +3202,7 @@ class PrefixDisplay {
3191
3202
  this.manager = manager;
3192
3203
  this.logWriter = options.logWriter;
3193
3204
  this.killOthers = options.killOthers ?? false;
3205
+ this.killOthersOnFail = options.killOthersOnFail ?? false;
3194
3206
  this.timestamps = options.timestamps ?? false;
3195
3207
  this.noColor = "NO_COLOR" in process.env;
3196
3208
  const names = manager.getProcessNames();
@@ -3232,7 +3244,8 @@ class PrefixDisplay {
3232
3244
  this.handleStatus(event.name, event.status);
3233
3245
  } else if (event.type === "exit") {
3234
3246
  this.flushBuffer(event.name);
3235
- if (this.killOthers) {
3247
+ const exitCode = this.manager.getState(event.name)?.exitCode ?? null;
3248
+ if (this.killOthers || this.killOthersOnFail && exitCode !== 0) {
3236
3249
  this.killAllAndExit(event.name);
3237
3250
  } else {
3238
3251
  this.checkAllDone();
@@ -3804,6 +3817,7 @@ async function main() {
3804
3817
  const display = new PrefixDisplay(manager, config, {
3805
3818
  logWriter,
3806
3819
  killOthers: parsed.killOthers || config.killOthers,
3820
+ killOthersOnFail: parsed.killOthersOnFail || config.killOthersOnFail,
3807
3821
  timestamps: parsed.timestamps || config.timestamps
3808
3822
  });
3809
3823
  await display.start();
package/dist/types.d.ts CHANGED
@@ -80,6 +80,12 @@ export interface NumuxConfig<K extends string = string> {
80
80
  maxRestarts?: number;
81
81
  /** Global ready timeout (ms), inherited by all processes */
82
82
  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;
83
89
  /**
84
90
  * Global stop signal, inherited by all processes
85
91
  * @default 'SIGTERM'
@@ -103,10 +109,15 @@ export interface NumuxConfig<K extends string = string> {
103
109
  /** Add timestamps to prefixed output lines (only applies when `prefix` is true) */
104
110
  timestamps?: boolean;
105
111
  /**
106
- * Kill all processes when any one exits
112
+ * Kill all processes when any one exits (regardless of exit code)
107
113
  * @default false
108
114
  */
109
115
  killOthers?: boolean;
116
+ /**
117
+ * Kill all processes when any one exits with a non-zero exit code
118
+ * @default false
119
+ */
120
+ killOthersOnFail?: boolean;
110
121
  /**
111
122
  * Disable file watching even if processes have watch patterns
112
123
  * @default false
@@ -127,6 +138,7 @@ export interface ResolvedNumuxConfig {
127
138
  prefix?: boolean;
128
139
  timestamps?: boolean;
129
140
  killOthers?: boolean;
141
+ killOthersOnFail?: boolean;
130
142
  noWatch?: boolean;
131
143
  logDir?: string;
132
144
  processes: Record<string, ResolvedProcessConfig>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "numux",
3
- "version": "1.24.0",
3
+ "version": "1.26.0",
4
4
  "description": "Terminal multiplexer with dependency orchestration",
5
5
  "type": "module",
6
6
  "license": "MIT",