numux 2.14.1 → 2.16.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 +3 -1
- package/dist/man/numux.1 +4 -2
- package/dist/numux.js +62 -52
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -245,7 +245,9 @@ Auto-exits when all processes finish. Exit code 1 if any process failed.
|
|
|
245
245
|
|
|
246
246
|
## Logging
|
|
247
247
|
|
|
248
|
-
numux writes per-process log files (ANSI-stripped)
|
|
248
|
+
numux writes per-process log files (ANSI-stripped) for every run. By default they go to `<tmpdir>/numux/<project-name>/`, or to `--log-dir` / the `logDir` config when set. Each session creates a timestamped subdirectory with a `latest` symlink pointing to the most recent run.
|
|
249
|
+
|
|
250
|
+
The TUI prints `Logs saved to: <session-dir>` on exit (Ctrl+C or signal). Multiple numux instances in the same project share the default base dir, so each session has its own timestamped folder but the `latest` symlink will point at whichever started most recently. If `numux logs` falls back to the default and a `latest` symlink is in use, it prints a warning. To avoid the collision, set `logDir` per config or pass `--log-dir`.
|
|
249
251
|
|
|
250
252
|
<!-- generated:logging-usage -->
|
|
251
253
|
```sh
|
package/dist/man/numux.1
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
.TH "NUMUX" "1" "
|
|
1
|
+
.TH "NUMUX" "1" "May 2026" "2.16.0" "numux manual"
|
|
2
2
|
.SH "NAME"
|
|
3
3
|
\fBnumux\fR
|
|
4
4
|
.P
|
|
@@ -380,7 +380,9 @@ numux \-\-prefix
|
|
|
380
380
|
Auto\-exits when all processes finish\. Exit code 1 if any process failed\.
|
|
381
381
|
.SH Logging
|
|
382
382
|
.P
|
|
383
|
-
numux writes per\-process log files (ANSI\-stripped)
|
|
383
|
+
numux writes per\-process log files (ANSI\-stripped) for every run\. By default they go to \fB<tmpdir>/numux/<project\-name>/\fP, or to \fB\-\-log\-dir\fP / the \fBlogDir\fP config when set\. Each session creates a timestamped subdirectory with a \fBlatest\fP symlink pointing to the most recent run\.
|
|
384
|
+
.P
|
|
385
|
+
The TUI prints \fBLogs saved to: <session\-dir>\fP on exit (Ctrl+C or signal)\. Multiple numux instances in the same project share the default base dir, so each session has its own timestamped folder but the \fBlatest\fP symlink will point at whichever started most recently\. If \fBnumux logs\fP falls back to the default and a \fBlatest\fP symlink is in use, it prints a warning\. To avoid the collision, set \fBlogDir\fP per config or pass \fB\-\-log\-dir\fP\|\.
|
|
384
386
|
<!\-\- generated:logging\-usage \-\->
|
|
385
387
|
.RS 2
|
|
386
388
|
.nf
|
package/dist/numux.js
CHANGED
|
@@ -257,7 +257,9 @@ numux --prefix
|
|
|
257
257
|
\`\`\`
|
|
258
258
|
|
|
259
259
|
Auto-exits when all processes finish. Exit code 1 if any process failed.` },
|
|
260
|
-
logging: { title: "Logging", body: `numux writes per-process log files (ANSI-stripped)
|
|
260
|
+
logging: { title: "Logging", body: `numux writes per-process log files (ANSI-stripped) for every run. By default they go to \`<tmpdir>/numux/<project-name>/\`, or to \`--log-dir\` / the \`logDir\` config when set. Each session creates a timestamped subdirectory with a \`latest\` symlink pointing to the most recent run.
|
|
261
|
+
|
|
262
|
+
The TUI prints \`Logs saved to: <session-dir>\` on exit (Ctrl+C or signal). Multiple numux instances in the same project share the default base dir, so each session has its own timestamped folder but the \`latest\` symlink will point at whichever started most recently. If \`numux logs\` falls back to the default and a \`latest\` symlink is in use, it prints a warning. To avoid the collision, set \`logDir\` per config or pass \`--log-dir\`.
|
|
261
263
|
|
|
262
264
|
<!-- generated:logging-usage -->
|
|
263
265
|
\`\`\`sh
|
|
@@ -546,7 +548,7 @@ var init_help = __esm(() => {
|
|
|
546
548
|
var require_package = __commonJS((exports, module) => {
|
|
547
549
|
module.exports = {
|
|
548
550
|
name: "numux",
|
|
549
|
-
version: "2.
|
|
551
|
+
version: "2.16.0",
|
|
550
552
|
description: "Terminal multiplexer with dependency orchestration",
|
|
551
553
|
type: "module",
|
|
552
554
|
license: "MIT",
|
|
@@ -2900,6 +2902,53 @@ function evaluateCondition(condition) {
|
|
|
2900
2902
|
// src/ui/app.ts
|
|
2901
2903
|
import { BoxRenderable as BoxRenderable3, createCliRenderer } from "@opentui/core";
|
|
2902
2904
|
|
|
2905
|
+
// src/utils/shutdown.ts
|
|
2906
|
+
var finalized = false;
|
|
2907
|
+
function finalizeShutdown(logWriter, exitCode) {
|
|
2908
|
+
if (finalized)
|
|
2909
|
+
process.exit(exitCode);
|
|
2910
|
+
finalized = true;
|
|
2911
|
+
if (logWriter && !logWriter.isTemporary) {
|
|
2912
|
+
process.stderr.write(`Logs saved to: ${logWriter.getDirectory()}
|
|
2913
|
+
`);
|
|
2914
|
+
}
|
|
2915
|
+
logWriter?.cleanup();
|
|
2916
|
+
process.exit(exitCode);
|
|
2917
|
+
}
|
|
2918
|
+
function setupShutdownHandlers(app, logWriter) {
|
|
2919
|
+
let shuttingDown = false;
|
|
2920
|
+
const shutdown = () => {
|
|
2921
|
+
if (shuttingDown) {
|
|
2922
|
+
process.exit(1);
|
|
2923
|
+
}
|
|
2924
|
+
shuttingDown = true;
|
|
2925
|
+
app.shutdown().finally(() => {
|
|
2926
|
+
finalizeShutdown(logWriter, app.hasFailures() ? 1 : 0);
|
|
2927
|
+
});
|
|
2928
|
+
};
|
|
2929
|
+
process.on("SIGINT", shutdown);
|
|
2930
|
+
process.on("SIGTERM", shutdown);
|
|
2931
|
+
process.on("uncaughtException", (err) => {
|
|
2932
|
+
log("Uncaught exception:", err?.message ?? err);
|
|
2933
|
+
app.shutdown().finally(() => {
|
|
2934
|
+
process.stderr.write(`numux: unexpected error: ${err?.stack ?? err}
|
|
2935
|
+
`);
|
|
2936
|
+
logWriter?.cleanup();
|
|
2937
|
+
process.exit(1);
|
|
2938
|
+
});
|
|
2939
|
+
});
|
|
2940
|
+
process.on("unhandledRejection", (reason) => {
|
|
2941
|
+
const stack = reason instanceof Error ? reason.stack : String(reason);
|
|
2942
|
+
log("Unhandled rejection:", stack);
|
|
2943
|
+
app.shutdown().finally(() => {
|
|
2944
|
+
process.stderr.write(`numux: unhandled rejection: ${stack}
|
|
2945
|
+
`);
|
|
2946
|
+
logWriter?.cleanup();
|
|
2947
|
+
process.exit(1);
|
|
2948
|
+
});
|
|
2949
|
+
});
|
|
2950
|
+
}
|
|
2951
|
+
|
|
2903
2952
|
// src/ui/help-overlay.ts
|
|
2904
2953
|
import { BoxRenderable, TextRenderable } from "@opentui/core";
|
|
2905
2954
|
|
|
@@ -2921,7 +2970,7 @@ function toHintPair(hint) {
|
|
|
2921
2970
|
}
|
|
2922
2971
|
var STATUS_HINTS_COMPACT = [
|
|
2923
2972
|
["\u2190\u2192", "tabs"],
|
|
2924
|
-
SHORTCUTS.
|
|
2973
|
+
SHORTCUTS.stopStart,
|
|
2925
2974
|
SHORTCUTS.copy,
|
|
2926
2975
|
["Enter", "input"],
|
|
2927
2976
|
["H", "help"]
|
|
@@ -4274,9 +4323,6 @@ class TabBar {
|
|
|
4274
4323
|
setSelectedIndex(index) {
|
|
4275
4324
|
this.renderable.setSelectedIndex(index);
|
|
4276
4325
|
}
|
|
4277
|
-
focus() {
|
|
4278
|
-
this.renderable.focus();
|
|
4279
|
-
}
|
|
4280
4326
|
}
|
|
4281
4327
|
|
|
4282
4328
|
// src/ui/app.ts
|
|
@@ -4433,7 +4479,7 @@ class App {
|
|
|
4433
4479
|
return;
|
|
4434
4480
|
}
|
|
4435
4481
|
this.shutdown().then(() => {
|
|
4436
|
-
|
|
4482
|
+
finalizeShutdown(this.logWriter, this.hasFailures() ? 1 : 0);
|
|
4437
4483
|
});
|
|
4438
4484
|
return;
|
|
4439
4485
|
}
|
|
@@ -4569,7 +4615,6 @@ class App {
|
|
|
4569
4615
|
});
|
|
4570
4616
|
if (this.names.length > 0) {
|
|
4571
4617
|
this.switchPane(this.names[0]);
|
|
4572
|
-
this.tabBar.focus();
|
|
4573
4618
|
}
|
|
4574
4619
|
await this.manager.startAll(termCols, termRows);
|
|
4575
4620
|
}
|
|
@@ -5155,46 +5200,6 @@ function defaultLogDir(cwd) {
|
|
|
5155
5200
|
return join2(tmpdir2(), "numux", resolveProjectName(cwd));
|
|
5156
5201
|
}
|
|
5157
5202
|
|
|
5158
|
-
// src/utils/shutdown.ts
|
|
5159
|
-
function setupShutdownHandlers(app, logWriter) {
|
|
5160
|
-
let shuttingDown = false;
|
|
5161
|
-
const shutdown = () => {
|
|
5162
|
-
if (shuttingDown) {
|
|
5163
|
-
process.exit(1);
|
|
5164
|
-
}
|
|
5165
|
-
shuttingDown = true;
|
|
5166
|
-
app.shutdown().finally(() => {
|
|
5167
|
-
if (logWriter && !logWriter.isTemporary) {
|
|
5168
|
-
process.stderr.write(`Logs saved to: ${logWriter.getDirectory()}
|
|
5169
|
-
`);
|
|
5170
|
-
}
|
|
5171
|
-
logWriter?.cleanup();
|
|
5172
|
-
process.exit(app.hasFailures() ? 1 : 0);
|
|
5173
|
-
});
|
|
5174
|
-
};
|
|
5175
|
-
process.on("SIGINT", shutdown);
|
|
5176
|
-
process.on("SIGTERM", shutdown);
|
|
5177
|
-
process.on("uncaughtException", (err) => {
|
|
5178
|
-
log("Uncaught exception:", err?.message ?? err);
|
|
5179
|
-
app.shutdown().finally(() => {
|
|
5180
|
-
process.stderr.write(`numux: unexpected error: ${err?.stack ?? err}
|
|
5181
|
-
`);
|
|
5182
|
-
logWriter?.cleanup();
|
|
5183
|
-
process.exit(1);
|
|
5184
|
-
});
|
|
5185
|
-
});
|
|
5186
|
-
process.on("unhandledRejection", (reason) => {
|
|
5187
|
-
const stack = reason instanceof Error ? reason.stack : String(reason);
|
|
5188
|
-
log("Unhandled rejection:", stack);
|
|
5189
|
-
app.shutdown().finally(() => {
|
|
5190
|
-
process.stderr.write(`numux: unhandled rejection: ${stack}
|
|
5191
|
-
`);
|
|
5192
|
-
logWriter?.cleanup();
|
|
5193
|
-
process.exit(1);
|
|
5194
|
-
});
|
|
5195
|
-
});
|
|
5196
|
-
}
|
|
5197
|
-
|
|
5198
5203
|
// src/index.ts
|
|
5199
5204
|
var HELP = generateHelp();
|
|
5200
5205
|
var INIT_TEMPLATE = `import { defineConfig } from 'numux'
|
|
@@ -5250,9 +5255,14 @@ async function main() {
|
|
|
5250
5255
|
process.exit(0);
|
|
5251
5256
|
}
|
|
5252
5257
|
if (parsed.logs) {
|
|
5253
|
-
const
|
|
5258
|
+
const resolved = parsed.logDir ? { dir: parsed.logDir, explicit: true } : await resolveLogDir(parsed.configPath);
|
|
5259
|
+
const logDir2 = resolved.dir;
|
|
5254
5260
|
const latestDir = resolve8(logDir2, "latest");
|
|
5255
|
-
const
|
|
5261
|
+
const usingLatest = existsSync6(latestDir);
|
|
5262
|
+
const target = usingLatest ? latestDir : logDir2;
|
|
5263
|
+
if (!resolved.explicit && usingLatest) {
|
|
5264
|
+
console.warn('Warning: using default log directory; "latest" may have been overwritten by another numux instance in this project.');
|
|
5265
|
+
}
|
|
5256
5266
|
if (parsed.logsProcess) {
|
|
5257
5267
|
const logFile2 = resolve8(target, `${parsed.logsProcess}.log`);
|
|
5258
5268
|
if (!existsSync6(logFile2)) {
|
|
@@ -5451,10 +5461,10 @@ async function resolveLogDir(configPath) {
|
|
|
5451
5461
|
try {
|
|
5452
5462
|
const raw = await loadConfig(configPath);
|
|
5453
5463
|
if (typeof raw.logDir === "string" && raw.logDir.trim()) {
|
|
5454
|
-
return resolve8(raw.logDir.trim());
|
|
5464
|
+
return { dir: resolve8(raw.logDir.trim()), explicit: true };
|
|
5455
5465
|
}
|
|
5456
5466
|
} catch {}
|
|
5457
|
-
return defaultLogDir(process.cwd());
|
|
5467
|
+
return { dir: defaultLogDir(process.cwd()), explicit: false };
|
|
5458
5468
|
}
|
|
5459
5469
|
main().catch((err) => {
|
|
5460
5470
|
console.error(err instanceof Error ? err.message : err);
|