numux 2.3.1 → 2.5.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.
Files changed (2) hide show
  1. package/dist/numux.js +44 -9
  2. package/package.json +1 -1
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: "2.3.1",
39
+ version: "2.5.0",
40
40
  description: "Terminal multiplexer with dependency orchestration",
41
41
  type: "module",
42
42
  license: "MIT",
@@ -2159,7 +2159,8 @@ var SHORTCUTS = {
2159
2159
  clear: { key: "l", label: "L", description: "clear" },
2160
2160
  timestamps: { key: "t", label: "T", description: "timestamps" },
2161
2161
  scrollToTop: { key: "g", label: "G", description: "top" },
2162
- scrollToBottom: { key: "g", label: "Shift+G", description: "bottom", shift: true }
2162
+ scrollToBottom: { key: "g", label: "Shift+G", description: "bottom", shift: true },
2163
+ openLogs: { key: "o", label: "O", description: "open logs" }
2163
2164
  };
2164
2165
  var STATUS_HINTS = [
2165
2166
  ["\u2190\u2192/1-9", "tabs"],
@@ -2170,6 +2171,7 @@ var STATUS_HINTS = [
2170
2171
  [SHORTCUTS.copy.label, SHORTCUTS.copy.description],
2171
2172
  [SHORTCUTS.clear.label, SHORTCUTS.clear.description],
2172
2173
  [SHORTCUTS.timestamps.label, SHORTCUTS.timestamps.description],
2174
+ [SHORTCUTS.openLogs.label, SHORTCUTS.openLogs.description],
2173
2175
  ["Ctrl+Click", "open link"],
2174
2176
  ["Ctrl+C", "quit"]
2175
2177
  ];
@@ -3193,6 +3195,10 @@ class App {
3193
3195
  }
3194
3196
  return;
3195
3197
  }
3198
+ if (name === SHORTCUTS.openLogs.key) {
3199
+ this.openLogDirectory();
3200
+ return;
3201
+ }
3196
3202
  const num = Number.parseInt(name, 10);
3197
3203
  if (num >= 1 && num <= 9 && num <= this.tabBar.count) {
3198
3204
  this.tabBar.setSelectedIndex(num - 1);
@@ -3292,6 +3298,16 @@ class App {
3292
3298
  } catch {}
3293
3299
  }
3294
3300
  }
3301
+ openLogDirectory() {
3302
+ const dir = this.logWriter.getDirectory();
3303
+ const cmd = process.platform === "darwin" ? "open" : "xdg-open";
3304
+ try {
3305
+ Bun.spawn([cmd, dir], { stdout: "ignore", stderr: "ignore" });
3306
+ this.statusBar.showTemporaryMessage(`Opening ${dir}`);
3307
+ } catch {
3308
+ this.statusBar.showTemporaryMessage("Could not open log directory");
3309
+ }
3310
+ }
3295
3311
  copyAllText() {
3296
3312
  if (!this.activePane)
3297
3313
  return;
@@ -3353,6 +3369,7 @@ class PrefixDisplay {
3353
3369
  timestampFormat;
3354
3370
  stopping = false;
3355
3371
  startTime = 0;
3372
+ processTimes = new Map;
3356
3373
  constructor(manager, config, options = {}) {
3357
3374
  this.manager = manager;
3358
3375
  this.logWriter = options.logWriter;
@@ -3426,7 +3443,17 @@ class PrefixDisplay {
3426
3443
  this.printLine(name, lastCr === -1 ? line : line.slice(lastCr + 1));
3427
3444
  }
3428
3445
  }
3429
- handleStatus(_name, _status) {}
3446
+ handleStatus(name, status) {
3447
+ if (status === "running" || status === "starting") {
3448
+ if (!this.processTimes.has(name)) {
3449
+ this.processTimes.set(name, { start: Date.now() });
3450
+ }
3451
+ } else if (status === "finished" || status === "failed" || status === "stopped") {
3452
+ const t = this.processTimes.get(name);
3453
+ if (t && !t.end)
3454
+ t.end = Date.now();
3455
+ }
3456
+ }
3430
3457
  printLine(name, line) {
3431
3458
  const fmt = this.timestampFormat;
3432
3459
  const ts = fmt ? `${DIM}[${formatTimestamp(new Date, fmt)}]${RESET} ` : "";
@@ -3479,8 +3506,7 @@ class PrefixDisplay {
3479
3506
  process.exit(code === 0 ? 0 : 1);
3480
3507
  });
3481
3508
  }
3482
- formatElapsed() {
3483
- const ms = Date.now() - this.startTime;
3509
+ formatDuration(ms) {
3484
3510
  if (ms < 1000)
3485
3511
  return `${ms}ms`;
3486
3512
  const s = ms / 1000;
@@ -3490,21 +3516,30 @@ class PrefixDisplay {
3490
3516
  const rem = s % 60;
3491
3517
  return `${m}m ${rem.toFixed(0)}s`;
3492
3518
  }
3519
+ formatElapsed() {
3520
+ return this.formatDuration(Date.now() - this.startTime);
3521
+ }
3493
3522
  printSummary() {
3494
3523
  const states = this.manager.getAllStates();
3495
3524
  const namePad = Math.max(...states.map((s) => s.name.length));
3525
+ const statusPad = Math.max(...states.map((s) => s.status.length));
3496
3526
  process.stdout.write(`
3497
3527
  `);
3498
3528
  for (const s of states) {
3499
3529
  const name = s.name.padEnd(namePad);
3500
- const exitStr = s.exitCode !== null ? `exit ${s.exitCode}` : "";
3530
+ const exitStr = s.exitCode !== null ? `(exit ${s.exitCode})` : "";
3531
+ const t = this.processTimes.get(s.name);
3532
+ const duration = t ? this.formatDuration((t.end ?? Date.now()) - t.start) : "";
3501
3533
  if (this.noColor) {
3502
- process.stdout.write(` ${name} ${s.status}${exitStr ? ` (${exitStr})` : ""}
3534
+ const status = s.status.padEnd(statusPad);
3535
+ process.stdout.write(` ${name} ${status} ${exitStr.padEnd(9)} ${duration}
3503
3536
  `);
3504
3537
  } else {
3505
3538
  const ansi = STATUS_ANSI[s.status] ?? "";
3506
- const statusText = ansi ? `${ansi}${s.status}${RESET}` : s.status;
3507
- process.stdout.write(` ${name} ${statusText}${exitStr ? ` ${DIM}(${exitStr})${RESET}` : ""}
3539
+ const statusPlain = s.status.padEnd(statusPad);
3540
+ const statusText = ansi ? `${ansi}${statusPlain}${RESET}` : statusPlain;
3541
+ const exitPart = exitStr ? `${DIM}${exitStr.padEnd(9)}${RESET}` : " ".repeat(9);
3542
+ process.stdout.write(` ${name} ${statusText} ${exitPart} ${DIM}${duration}${RESET}
3508
3543
  `);
3509
3544
  }
3510
3545
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "numux",
3
- "version": "2.3.1",
3
+ "version": "2.5.0",
4
4
  "description": "Terminal multiplexer with dependency orchestration",
5
5
  "type": "module",
6
6
  "license": "MIT",