numux 1.20.0 → 1.22.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
@@ -164,6 +164,7 @@ Template properties (color, env, dependsOn, etc.) are inherited by all matched p
164
164
  | `--exclude <a,b,...>` | Exclude these processes |
165
165
  | `--kill-others` | Kill all processes when any exits |
166
166
  | `--no-restart` | Disable auto-restart for crashed processes |
167
+ | `-s, --sort <mode>` | Tab display order: `config` (default), `alphabetical`, `topological` |
167
168
  | `--no-watch` | Disable file watching even if config has `watch` patterns |
168
169
  | `-t, --timestamps` | Add `[HH:MM:SS]` timestamps to prefixed output |
169
170
  | `--log-dir <path>` | Write per-process output to `<path>/<name>.log` |
@@ -193,6 +194,12 @@ Top-level options apply to all processes (process-level settings override):
193
194
  | `env` | `Record<string, string>` | Environment variables merged into all processes (process `env` overrides per key) |
194
195
  | `envFile` | `string \| string[] \| false` | `.env` file(s) for all processes (process `envFile` replaces if set; `false` disables) |
195
196
  | `showCommand` | `boolean` | Print the command being run as the first line of output (default: `true`) |
197
+ | `maxRestarts` | `number` | Restart limit for all processes (default: `Infinity`) |
198
+ | `readyTimeout` | `number` | Ready timeout in ms for all processes |
199
+ | `stopSignal` | `'SIGTERM' \| 'SIGINT' \| 'SIGHUP'` | Stop signal for all processes (default: `'SIGTERM'`) |
200
+ | `errorMatcher` | `boolean \| string` | Error detection for all processes (`true` = ANSI red, string = regex) |
201
+ | `watch` | `string \| string[]` | Watch patterns for all processes (process `watch` replaces if set) |
202
+ | `sort` | `'config' \| 'alphabetical' \| 'topological'` | Tab display order (default: `'config'` — definition order) |
196
203
 
197
204
  ```ts
198
205
  export default defineConfig({
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.20.0",
39
+ version: "1.22.0",
40
40
  description: "Terminal multiplexer with dependency orchestration",
41
41
  type: "module",
42
42
  license: "MIT",
@@ -95,6 +95,15 @@ import { resolve as resolve8 } from "path";
95
95
  // src/cli-flags.ts
96
96
  var commaSplit = (raw) => raw.split(",").map((s) => s.trim()).filter(Boolean);
97
97
  var FLAGS = [
98
+ {
99
+ type: "value",
100
+ long: "--sort",
101
+ short: "-s",
102
+ key: "sort",
103
+ description: "Tab display order",
104
+ valueName: "<config|alphabetical|topological>",
105
+ completionHint: "none"
106
+ },
98
107
  {
99
108
  type: "value",
100
109
  long: "--workspace",
@@ -1035,6 +1044,11 @@ function validateConfig(raw, warnings) {
1035
1044
  const globalCwd = typeof config.cwd === "string" ? config.cwd : undefined;
1036
1045
  const globalShowCommand = typeof config.showCommand === "boolean" ? config.showCommand : undefined;
1037
1046
  const globalEnvFile = validateEnvFile(config.envFile);
1047
+ const globalMaxRestarts = typeof config.maxRestarts === "number" && config.maxRestarts >= 0 ? config.maxRestarts : undefined;
1048
+ const globalReadyTimeout = typeof config.readyTimeout === "number" && config.readyTimeout > 0 ? config.readyTimeout : undefined;
1049
+ const globalStopSignal = validateStopSignal(config.stopSignal);
1050
+ const globalErrorMatcher = validateErrorMatcher("(global)", config.errorMatcher);
1051
+ const globalWatch = validateStringOrStringArray(config.watch);
1038
1052
  let globalEnv;
1039
1053
  if (config.env && typeof config.env === "object") {
1040
1054
  for (const [k, v] of Object.entries(config.env)) {
@@ -1044,6 +1058,7 @@ function validateConfig(raw, warnings) {
1044
1058
  }
1045
1059
  globalEnv = config.env;
1046
1060
  }
1061
+ const sort = validateSort(config.sort);
1047
1062
  const validated = {};
1048
1063
  for (const name of names) {
1049
1064
  let proc = processes[name];
@@ -1115,6 +1130,11 @@ function validateConfig(raw, warnings) {
1115
1130
  const processEnvFile = validateEnvFile(p.envFile);
1116
1131
  const showCommand = typeof p.showCommand === "boolean" ? p.showCommand : globalShowCommand ?? true;
1117
1132
  const platform = validatePlatform(name, p.platform);
1133
+ const processMaxRestarts = typeof p.maxRestarts === "number" && p.maxRestarts >= 0 ? p.maxRestarts : undefined;
1134
+ const processReadyTimeout = typeof p.readyTimeout === "number" && p.readyTimeout > 0 ? p.readyTimeout : undefined;
1135
+ const processStopSignal = validateStopSignal(p.stopSignal);
1136
+ const processErrorMatcher = validateErrorMatcher(name, p.errorMatcher);
1137
+ const processWatch = validateStringOrStringArray(p.watch);
1118
1138
  validated[name] = {
1119
1139
  command: p.command,
1120
1140
  cwd: processCwd ?? globalCwd,
@@ -1123,20 +1143,20 @@ function validateConfig(raw, warnings) {
1123
1143
  dependsOn: Array.isArray(p.dependsOn) ? p.dependsOn : undefined,
1124
1144
  readyPattern,
1125
1145
  persistent,
1126
- maxRestarts: typeof p.maxRestarts === "number" && p.maxRestarts >= 0 ? p.maxRestarts : undefined,
1127
- readyTimeout: typeof p.readyTimeout === "number" && p.readyTimeout > 0 ? p.readyTimeout : undefined,
1146
+ maxRestarts: processMaxRestarts ?? globalMaxRestarts,
1147
+ readyTimeout: processReadyTimeout ?? globalReadyTimeout,
1128
1148
  delay: typeof p.delay === "number" && p.delay > 0 ? p.delay : undefined,
1129
1149
  condition: typeof p.condition === "string" && p.condition.trim() ? p.condition.trim() : undefined,
1130
1150
  platform,
1131
- stopSignal: validateStopSignal(p.stopSignal),
1151
+ stopSignal: processStopSignal ?? globalStopSignal,
1132
1152
  color: typeof p.color === "string" ? p.color : Array.isArray(p.color) ? p.color : undefined,
1133
- watch: validateStringOrStringArray(p.watch),
1153
+ watch: processWatch ?? globalWatch,
1134
1154
  interactive: typeof p.interactive === "boolean" ? p.interactive : false,
1135
- errorMatcher: validateErrorMatcher(name, p.errorMatcher),
1155
+ errorMatcher: processErrorMatcher ?? globalErrorMatcher,
1136
1156
  showCommand
1137
1157
  };
1138
1158
  }
1139
- return { processes: validated };
1159
+ return { ...sort ? { sort } : {}, processes: validated };
1140
1160
  }
1141
1161
  function validateStringOrStringArray(value) {
1142
1162
  if (typeof value === "string")
@@ -1166,6 +1186,16 @@ function validateErrorMatcher(name, value) {
1166
1186
  }
1167
1187
  return;
1168
1188
  }
1189
+ var VALID_SORT_VALUES = new Set(["config", "alphabetical", "topological"]);
1190
+ function validateSort(value) {
1191
+ if (typeof value === "string") {
1192
+ if (!VALID_SORT_VALUES.has(value)) {
1193
+ throw new Error(`sort must be one of: ${[...VALID_SORT_VALUES].join(", ")}. Got "${value}"`);
1194
+ }
1195
+ return value;
1196
+ }
1197
+ return;
1198
+ }
1169
1199
  var VALID_PLATFORMS = new Set(["aix", "darwin", "freebsd", "linux", "openbsd", "sunos", "win32"]);
1170
1200
  function validatePlatform(name, value) {
1171
1201
  const arr = validateStringOrStringArray(value);
@@ -1733,7 +1763,14 @@ class ProcessManager {
1733
1763
  return [...this.states.values()];
1734
1764
  }
1735
1765
  getProcessNames() {
1736
- return this.tiers.flat();
1766
+ switch (this.config.sort) {
1767
+ case "alphabetical":
1768
+ return Object.keys(this.config.processes).sort();
1769
+ case "topological":
1770
+ return this.tiers.flat();
1771
+ default:
1772
+ return Object.keys(this.config.processes);
1773
+ }
1737
1774
  }
1738
1775
  async startAll(cols, rows) {
1739
1776
  log("Starting all processes");
@@ -3469,6 +3506,9 @@ async function main() {
3469
3506
  }
3470
3507
  }
3471
3508
  }
3509
+ if (parsed.sort) {
3510
+ config.sort = parsed.sort;
3511
+ }
3472
3512
  if (parsed.envFile !== undefined) {
3473
3513
  for (const proc of Object.values(config.processes)) {
3474
3514
  proc.envFile = parsed.envFile;
package/dist/types.d.ts CHANGED
@@ -72,14 +72,38 @@ export interface NumuxConfig<K extends string = string> {
72
72
  * @default true
73
73
  */
74
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[];
91
+ /**
92
+ * Tab display order. `'config'` preserves definition order (package.json script order for wildcards),
93
+ * `'alphabetical'` sorts by process name, `'topological'` sorts by dependency tiers.
94
+ * @default 'config'
95
+ */
96
+ sort?: SortOrder;
75
97
  processes: Record<K, NumuxProcessConfig<K> | NumuxScriptPattern<K> | string>;
76
98
  }
99
+ export type SortOrder = 'config' | 'alphabetical' | 'topological';
77
100
  /** Process config after validation — dependsOn is always normalized to an array */
78
101
  export interface ResolvedProcessConfig extends Omit<NumuxProcessConfig, 'dependsOn'> {
79
102
  dependsOn?: string[];
80
103
  }
81
104
  /** Validated config with all shorthand expanded to full objects */
82
105
  export interface ResolvedNumuxConfig {
106
+ sort?: SortOrder;
83
107
  processes: Record<string, ResolvedProcessConfig>;
84
108
  }
85
109
  export type ProcessStatus = 'pending' | 'starting' | 'ready' | 'running' | 'stopping' | 'stopped' | 'finished' | 'failed' | 'skipped';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "numux",
3
- "version": "1.20.0",
3
+ "version": "1.22.0",
4
4
  "description": "Terminal multiplexer with dependency orchestration",
5
5
  "type": "module",
6
6
  "license": "MIT",