@nmakarov/cli-toolkit 0.73.0 → 0.76.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/dist/init.js CHANGED
@@ -2505,7 +2505,8 @@ var LEVEL_COLORS = {
2505
2505
  silly: chalk.gray,
2506
2506
  request: chalk.green,
2507
2507
  response: chalk.yellow,
2508
- progress: chalk.green,
2508
+ // Magenta stands out from white info / green request lines.
2509
+ progress: chalk.magentaBright,
2509
2510
  results: chalk.magenta
2510
2511
  };
2511
2512
  var Logger = class _Logger {
@@ -2524,7 +2525,8 @@ var Logger = class _Logger {
2524
2525
  this.updateTransport();
2525
2526
  }
2526
2527
  /**
2527
- * Configure logger options. Accepts both LoggerOptions shape and flat param names (levels string, progressWithTimes, progressThrottleMs).
2528
+ * Configure logger options. Accepts both LoggerOptions shape and flat param names
2529
+ * (levels string, progressWithTimes, progressWithRate, progressThrottleMs).
2528
2530
  */
2529
2531
  configure(options) {
2530
2532
  if (options.mode !== void 0) {
@@ -2544,10 +2546,12 @@ var Logger = class _Logger {
2544
2546
  }
2545
2547
  if (options.progress !== void 0) {
2546
2548
  if (options.progress.withTimes !== void 0) this.options.progressTimes = options.progress.withTimes;
2549
+ if (options.progress.withRate !== void 0) this.options.progressRate = options.progress.withRate;
2547
2550
  if (options.progress.throttleMs !== void 0) this.options.progressThrottle = options.progress.throttleMs;
2548
2551
  }
2549
2552
  const flat = options;
2550
2553
  if (flat.progressWithTimes !== void 0) this.options.progressTimes = flat.progressWithTimes;
2554
+ if (flat.progressWithRate !== void 0) this.options.progressRate = flat.progressWithRate;
2551
2555
  if (flat.progressThrottleMs !== void 0) this.options.progressThrottle = flat.progressThrottleMs;
2552
2556
  }
2553
2557
  /**
@@ -2564,6 +2568,7 @@ var Logger = class _Logger {
2564
2568
  timestamp: "boolean default false",
2565
2569
  levels: "string",
2566
2570
  progressWithTimes: "boolean default false",
2571
+ progressWithRate: "boolean default false",
2567
2572
  progressThrottleMs: "number"
2568
2573
  };
2569
2574
  const discovered = context.params.getAllForModule("logger", paramDefs);
@@ -2582,6 +2587,7 @@ var Logger = class _Logger {
2582
2587
  timestamp: false,
2583
2588
  levels: DEFAULT_LEVELS,
2584
2589
  progressTimes: false,
2590
+ progressRate: false,
2585
2591
  progressThrottle: void 0
2586
2592
  };
2587
2593
  }
@@ -2647,15 +2653,23 @@ var Logger = class _Logger {
2647
2653
  if (!this.startTimes[prefix ?? ""]) {
2648
2654
  this.startTimes[prefix ?? ""] = Date.now();
2649
2655
  }
2650
- if (this.options.progressTimes) {
2656
+ const wantTimes = this.options.progressTimes;
2657
+ const wantRate = this.options.progressRate;
2658
+ if (wantTimes || wantRate) {
2651
2659
  const elapsedSeconds = (Date.now() - this.startTimes[prefix ?? ""]) / 1e3;
2652
- let remaining = -1;
2653
- if (count > 1) {
2654
- const rate = elapsedSeconds / (count - 1);
2655
- remaining = (total - count) * rate;
2660
+ const intervals = count > 1 ? count - 1 : 0;
2661
+ const itemsPerSec = intervals > 0 && elapsedSeconds > 0 ? intervals / elapsedSeconds : -1;
2662
+ if (wantTimes) {
2663
+ let remaining = -1;
2664
+ if (itemsPerSec > 0) {
2665
+ remaining = (total - count) / itemsPerSec;
2666
+ }
2667
+ payload.elapsed = this.round(elapsedSeconds, 2);
2668
+ payload.remaining = remaining >= 0 ? this.round(remaining, 2) : remaining;
2669
+ }
2670
+ if (wantRate) {
2671
+ payload.rate = itemsPerSec >= 0 ? this.round(itemsPerSec, 2) : itemsPerSec;
2656
2672
  }
2657
- payload.elapsed = this.round(elapsedSeconds, 2);
2658
- payload.remaining = remaining >= 0 ? this.round(remaining, 2) : remaining;
2659
2673
  }
2660
2674
  if (count >= total) {
2661
2675
  delete this.startTimes[prefix ?? ""];
@@ -2720,10 +2734,13 @@ var Logger = class _Logger {
2720
2734
  parts.push(formatter.bold(struct.message));
2721
2735
  }
2722
2736
  if (struct.level === "progress") {
2737
+ const formatter = LEVEL_COLORS[struct.level];
2723
2738
  if (struct.elapsed !== void 0 && struct.remaining !== void 0) {
2724
- const formatter = LEVEL_COLORS[struct.level];
2725
2739
  parts.push(formatter(`${struct.elapsed}/${struct.remaining}`));
2726
2740
  }
2741
+ if (struct.rate !== void 0) {
2742
+ parts.push(formatter(struct.rate >= 0 ? `${struct.rate}/s` : "-/s"));
2743
+ }
2727
2744
  }
2728
2745
  if (struct.chunks && struct.chunks.length) {
2729
2746
  parts.push(this.inspectChunks(struct.chunks));
@@ -2783,6 +2800,7 @@ function setup(opts = {}) {
2783
2800
  const partialContext = {
2784
2801
  emitter: new EventEmitter(),
2785
2802
  isStop: () => false,
2803
+ isKill: () => false,
2786
2804
  cleanupFunctions: [],
2787
2805
  registerCleanup: (fn) => {
2788
2806
  partialContext.cleanupFunctions.push(fn);
@@ -2804,6 +2822,7 @@ function setup(opts = {}) {
2804
2822
  logger,
2805
2823
  emitter: partialContext.emitter,
2806
2824
  isStop: partialContext.isStop,
2825
+ isKill: partialContext.isKill,
2807
2826
  cleanupFunctions: partialContext.cleanupFunctions,
2808
2827
  registerCleanup: partialContext.registerCleanup,
2809
2828
  // For long-running scripts (servers): with --showUsedParams=top, print
@@ -2853,6 +2872,7 @@ function printAllParameters(context) {
2853
2872
  }
2854
2873
  async function init(flow, opts = {}) {
2855
2874
  let stop = false;
2875
+ let kill = false;
2856
2876
  let context = null;
2857
2877
  let cleanupRan = false;
2858
2878
  const runRegisteredCleanups = async (ctx) => {
@@ -2882,6 +2902,7 @@ async function init(flow, opts = {}) {
2882
2902
  }
2883
2903
  context = setup(opts);
2884
2904
  context.isStop = () => stop;
2905
+ context.isKill = () => kill;
2885
2906
  context = await setupModules(context, opts);
2886
2907
  const stopAfter = context.args.get("stopAfter");
2887
2908
  const stopAllowanceSec = Number(context.params.get("stopAllowance", "number default 60"));
@@ -2920,6 +2941,14 @@ async function init(flow, opts = {}) {
2920
2941
  );
2921
2942
  context.emitter.emit("stop", stopAllowanceMs);
2922
2943
  });
2944
+ process.on("SIGUSR2", () => {
2945
+ if (!context || kill) return;
2946
+ kill = true;
2947
+ stop = true;
2948
+ context.logger.warn(">> SIGUSR2: emitting kill (urgent stop)");
2949
+ context.emitter.emit("kill");
2950
+ context.emitter.emit("stop", stopAllowanceMs);
2951
+ });
2923
2952
  await flow(context);
2924
2953
  } catch (error) {
2925
2954
  const errorLocation = error instanceof Error && error.stack ? error.stack.split("\n")[1]?.trim() || "Unknown location" : "Unknown location";
@@ -2946,7 +2975,7 @@ async function init(flow, opts = {}) {
2946
2975
  }
2947
2976
  if (process.exitCode && process.exitCode !== 0) {
2948
2977
  process.exit(process.exitCode);
2949
- } else if (stop) {
2978
+ } else if (stop || kill) {
2950
2979
  process.exit(0);
2951
2980
  }
2952
2981
  }