@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.cjs CHANGED
@@ -2530,7 +2530,8 @@ var LEVEL_COLORS = {
2530
2530
  silly: import_chalk.default.gray,
2531
2531
  request: import_chalk.default.green,
2532
2532
  response: import_chalk.default.yellow,
2533
- progress: import_chalk.default.green,
2533
+ // Magenta stands out from white info / green request lines.
2534
+ progress: import_chalk.default.magentaBright,
2534
2535
  results: import_chalk.default.magenta
2535
2536
  };
2536
2537
  var Logger = class _Logger {
@@ -2549,7 +2550,8 @@ var Logger = class _Logger {
2549
2550
  this.updateTransport();
2550
2551
  }
2551
2552
  /**
2552
- * Configure logger options. Accepts both LoggerOptions shape and flat param names (levels string, progressWithTimes, progressThrottleMs).
2553
+ * Configure logger options. Accepts both LoggerOptions shape and flat param names
2554
+ * (levels string, progressWithTimes, progressWithRate, progressThrottleMs).
2553
2555
  */
2554
2556
  configure(options) {
2555
2557
  if (options.mode !== void 0) {
@@ -2569,10 +2571,12 @@ var Logger = class _Logger {
2569
2571
  }
2570
2572
  if (options.progress !== void 0) {
2571
2573
  if (options.progress.withTimes !== void 0) this.options.progressTimes = options.progress.withTimes;
2574
+ if (options.progress.withRate !== void 0) this.options.progressRate = options.progress.withRate;
2572
2575
  if (options.progress.throttleMs !== void 0) this.options.progressThrottle = options.progress.throttleMs;
2573
2576
  }
2574
2577
  const flat = options;
2575
2578
  if (flat.progressWithTimes !== void 0) this.options.progressTimes = flat.progressWithTimes;
2579
+ if (flat.progressWithRate !== void 0) this.options.progressRate = flat.progressWithRate;
2576
2580
  if (flat.progressThrottleMs !== void 0) this.options.progressThrottle = flat.progressThrottleMs;
2577
2581
  }
2578
2582
  /**
@@ -2589,6 +2593,7 @@ var Logger = class _Logger {
2589
2593
  timestamp: "boolean default false",
2590
2594
  levels: "string",
2591
2595
  progressWithTimes: "boolean default false",
2596
+ progressWithRate: "boolean default false",
2592
2597
  progressThrottleMs: "number"
2593
2598
  };
2594
2599
  const discovered = context.params.getAllForModule("logger", paramDefs);
@@ -2607,6 +2612,7 @@ var Logger = class _Logger {
2607
2612
  timestamp: false,
2608
2613
  levels: DEFAULT_LEVELS,
2609
2614
  progressTimes: false,
2615
+ progressRate: false,
2610
2616
  progressThrottle: void 0
2611
2617
  };
2612
2618
  }
@@ -2672,15 +2678,23 @@ var Logger = class _Logger {
2672
2678
  if (!this.startTimes[prefix ?? ""]) {
2673
2679
  this.startTimes[prefix ?? ""] = Date.now();
2674
2680
  }
2675
- if (this.options.progressTimes) {
2681
+ const wantTimes = this.options.progressTimes;
2682
+ const wantRate = this.options.progressRate;
2683
+ if (wantTimes || wantRate) {
2676
2684
  const elapsedSeconds = (Date.now() - this.startTimes[prefix ?? ""]) / 1e3;
2677
- let remaining = -1;
2678
- if (count > 1) {
2679
- const rate = elapsedSeconds / (count - 1);
2680
- remaining = (total - count) * rate;
2685
+ const intervals = count > 1 ? count - 1 : 0;
2686
+ const itemsPerSec = intervals > 0 && elapsedSeconds > 0 ? intervals / elapsedSeconds : -1;
2687
+ if (wantTimes) {
2688
+ let remaining = -1;
2689
+ if (itemsPerSec > 0) {
2690
+ remaining = (total - count) / itemsPerSec;
2691
+ }
2692
+ payload.elapsed = this.round(elapsedSeconds, 2);
2693
+ payload.remaining = remaining >= 0 ? this.round(remaining, 2) : remaining;
2694
+ }
2695
+ if (wantRate) {
2696
+ payload.rate = itemsPerSec >= 0 ? this.round(itemsPerSec, 2) : itemsPerSec;
2681
2697
  }
2682
- payload.elapsed = this.round(elapsedSeconds, 2);
2683
- payload.remaining = remaining >= 0 ? this.round(remaining, 2) : remaining;
2684
2698
  }
2685
2699
  if (count >= total) {
2686
2700
  delete this.startTimes[prefix ?? ""];
@@ -2745,10 +2759,13 @@ var Logger = class _Logger {
2745
2759
  parts.push(formatter.bold(struct.message));
2746
2760
  }
2747
2761
  if (struct.level === "progress") {
2762
+ const formatter = LEVEL_COLORS[struct.level];
2748
2763
  if (struct.elapsed !== void 0 && struct.remaining !== void 0) {
2749
- const formatter = LEVEL_COLORS[struct.level];
2750
2764
  parts.push(formatter(`${struct.elapsed}/${struct.remaining}`));
2751
2765
  }
2766
+ if (struct.rate !== void 0) {
2767
+ parts.push(formatter(struct.rate >= 0 ? `${struct.rate}/s` : "-/s"));
2768
+ }
2752
2769
  }
2753
2770
  if (struct.chunks && struct.chunks.length) {
2754
2771
  parts.push(this.inspectChunks(struct.chunks));
@@ -2808,6 +2825,7 @@ function setup(opts = {}) {
2808
2825
  const partialContext = {
2809
2826
  emitter: new import_events.EventEmitter(),
2810
2827
  isStop: () => false,
2828
+ isKill: () => false,
2811
2829
  cleanupFunctions: [],
2812
2830
  registerCleanup: (fn) => {
2813
2831
  partialContext.cleanupFunctions.push(fn);
@@ -2829,6 +2847,7 @@ function setup(opts = {}) {
2829
2847
  logger,
2830
2848
  emitter: partialContext.emitter,
2831
2849
  isStop: partialContext.isStop,
2850
+ isKill: partialContext.isKill,
2832
2851
  cleanupFunctions: partialContext.cleanupFunctions,
2833
2852
  registerCleanup: partialContext.registerCleanup,
2834
2853
  // For long-running scripts (servers): with --showUsedParams=top, print
@@ -2878,6 +2897,7 @@ function printAllParameters(context) {
2878
2897
  }
2879
2898
  async function init(flow, opts = {}) {
2880
2899
  let stop = false;
2900
+ let kill = false;
2881
2901
  let context = null;
2882
2902
  let cleanupRan = false;
2883
2903
  const runRegisteredCleanups = async (ctx) => {
@@ -2907,6 +2927,7 @@ async function init(flow, opts = {}) {
2907
2927
  }
2908
2928
  context = setup(opts);
2909
2929
  context.isStop = () => stop;
2930
+ context.isKill = () => kill;
2910
2931
  context = await setupModules(context, opts);
2911
2932
  const stopAfter = context.args.get("stopAfter");
2912
2933
  const stopAllowanceSec = Number(context.params.get("stopAllowance", "number default 60"));
@@ -2945,6 +2966,14 @@ async function init(flow, opts = {}) {
2945
2966
  );
2946
2967
  context.emitter.emit("stop", stopAllowanceMs);
2947
2968
  });
2969
+ process.on("SIGUSR2", () => {
2970
+ if (!context || kill) return;
2971
+ kill = true;
2972
+ stop = true;
2973
+ context.logger.warn(">> SIGUSR2: emitting kill (urgent stop)");
2974
+ context.emitter.emit("kill");
2975
+ context.emitter.emit("stop", stopAllowanceMs);
2976
+ });
2948
2977
  await flow(context);
2949
2978
  } catch (error) {
2950
2979
  const errorLocation = error instanceof Error && error.stack ? error.stack.split("\n")[1]?.trim() || "Unknown location" : "Unknown location";
@@ -2971,7 +3000,7 @@ async function init(flow, opts = {}) {
2971
3000
  }
2972
3001
  if (process.exitCode && process.exitCode !== 0) {
2973
3002
  process.exit(process.exitCode);
2974
- } else if (stop) {
3003
+ } else if (stop || kill) {
2975
3004
  process.exit(0);
2976
3005
  }
2977
3006
  }