@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.
@@ -2532,7 +2532,8 @@ var LEVEL_COLORS = {
2532
2532
  silly: import_chalk.default.gray,
2533
2533
  request: import_chalk.default.green,
2534
2534
  response: import_chalk.default.yellow,
2535
- progress: import_chalk.default.green,
2535
+ // Magenta stands out from white info / green request lines.
2536
+ progress: import_chalk.default.magentaBright,
2536
2537
  results: import_chalk.default.magenta
2537
2538
  };
2538
2539
  var Logger = class _Logger {
@@ -2551,7 +2552,8 @@ var Logger = class _Logger {
2551
2552
  this.updateTransport();
2552
2553
  }
2553
2554
  /**
2554
- * Configure logger options. Accepts both LoggerOptions shape and flat param names (levels string, progressWithTimes, progressThrottleMs).
2555
+ * Configure logger options. Accepts both LoggerOptions shape and flat param names
2556
+ * (levels string, progressWithTimes, progressWithRate, progressThrottleMs).
2555
2557
  */
2556
2558
  configure(options) {
2557
2559
  if (options.mode !== void 0) {
@@ -2571,10 +2573,12 @@ var Logger = class _Logger {
2571
2573
  }
2572
2574
  if (options.progress !== void 0) {
2573
2575
  if (options.progress.withTimes !== void 0) this.options.progressTimes = options.progress.withTimes;
2576
+ if (options.progress.withRate !== void 0) this.options.progressRate = options.progress.withRate;
2574
2577
  if (options.progress.throttleMs !== void 0) this.options.progressThrottle = options.progress.throttleMs;
2575
2578
  }
2576
2579
  const flat = options;
2577
2580
  if (flat.progressWithTimes !== void 0) this.options.progressTimes = flat.progressWithTimes;
2581
+ if (flat.progressWithRate !== void 0) this.options.progressRate = flat.progressWithRate;
2578
2582
  if (flat.progressThrottleMs !== void 0) this.options.progressThrottle = flat.progressThrottleMs;
2579
2583
  }
2580
2584
  /**
@@ -2591,6 +2595,7 @@ var Logger = class _Logger {
2591
2595
  timestamp: "boolean default false",
2592
2596
  levels: "string",
2593
2597
  progressWithTimes: "boolean default false",
2598
+ progressWithRate: "boolean default false",
2594
2599
  progressThrottleMs: "number"
2595
2600
  };
2596
2601
  const discovered = context.params.getAllForModule("logger", paramDefs);
@@ -2609,6 +2614,7 @@ var Logger = class _Logger {
2609
2614
  timestamp: false,
2610
2615
  levels: DEFAULT_LEVELS,
2611
2616
  progressTimes: false,
2617
+ progressRate: false,
2612
2618
  progressThrottle: void 0
2613
2619
  };
2614
2620
  }
@@ -2674,15 +2680,23 @@ var Logger = class _Logger {
2674
2680
  if (!this.startTimes[prefix ?? ""]) {
2675
2681
  this.startTimes[prefix ?? ""] = Date.now();
2676
2682
  }
2677
- if (this.options.progressTimes) {
2683
+ const wantTimes = this.options.progressTimes;
2684
+ const wantRate = this.options.progressRate;
2685
+ if (wantTimes || wantRate) {
2678
2686
  const elapsedSeconds = (Date.now() - this.startTimes[prefix ?? ""]) / 1e3;
2679
- let remaining = -1;
2680
- if (count > 1) {
2681
- const rate = elapsedSeconds / (count - 1);
2682
- remaining = (total - count) * rate;
2687
+ const intervals = count > 1 ? count - 1 : 0;
2688
+ const itemsPerSec = intervals > 0 && elapsedSeconds > 0 ? intervals / elapsedSeconds : -1;
2689
+ if (wantTimes) {
2690
+ let remaining = -1;
2691
+ if (itemsPerSec > 0) {
2692
+ remaining = (total - count) / itemsPerSec;
2693
+ }
2694
+ payload.elapsed = this.round(elapsedSeconds, 2);
2695
+ payload.remaining = remaining >= 0 ? this.round(remaining, 2) : remaining;
2696
+ }
2697
+ if (wantRate) {
2698
+ payload.rate = itemsPerSec >= 0 ? this.round(itemsPerSec, 2) : itemsPerSec;
2683
2699
  }
2684
- payload.elapsed = this.round(elapsedSeconds, 2);
2685
- payload.remaining = remaining >= 0 ? this.round(remaining, 2) : remaining;
2686
2700
  }
2687
2701
  if (count >= total) {
2688
2702
  delete this.startTimes[prefix ?? ""];
@@ -2747,10 +2761,13 @@ var Logger = class _Logger {
2747
2761
  parts.push(formatter.bold(struct.message));
2748
2762
  }
2749
2763
  if (struct.level === "progress") {
2764
+ const formatter = LEVEL_COLORS[struct.level];
2750
2765
  if (struct.elapsed !== void 0 && struct.remaining !== void 0) {
2751
- const formatter = LEVEL_COLORS[struct.level];
2752
2766
  parts.push(formatter(`${struct.elapsed}/${struct.remaining}`));
2753
2767
  }
2768
+ if (struct.rate !== void 0) {
2769
+ parts.push(formatter(struct.rate >= 0 ? `${struct.rate}/s` : "-/s"));
2770
+ }
2754
2771
  }
2755
2772
  if (struct.chunks && struct.chunks.length) {
2756
2773
  parts.push(this.inspectChunks(struct.chunks));
@@ -2810,6 +2827,7 @@ function setup(opts = {}) {
2810
2827
  const partialContext = {
2811
2828
  emitter: new import_events.EventEmitter(),
2812
2829
  isStop: () => false,
2830
+ isKill: () => false,
2813
2831
  cleanupFunctions: [],
2814
2832
  registerCleanup: (fn) => {
2815
2833
  partialContext.cleanupFunctions.push(fn);
@@ -2831,6 +2849,7 @@ function setup(opts = {}) {
2831
2849
  logger,
2832
2850
  emitter: partialContext.emitter,
2833
2851
  isStop: partialContext.isStop,
2852
+ isKill: partialContext.isKill,
2834
2853
  cleanupFunctions: partialContext.cleanupFunctions,
2835
2854
  registerCleanup: partialContext.registerCleanup,
2836
2855
  // For long-running scripts (servers): with --showUsedParams=top, print
@@ -2880,6 +2899,7 @@ function printAllParameters(context) {
2880
2899
  }
2881
2900
  async function init(flow2, opts = {}) {
2882
2901
  let stop = false;
2902
+ let kill = false;
2883
2903
  let context = null;
2884
2904
  let cleanupRan = false;
2885
2905
  const runRegisteredCleanups = async (ctx) => {
@@ -2909,6 +2929,7 @@ async function init(flow2, opts = {}) {
2909
2929
  }
2910
2930
  context = setup(opts);
2911
2931
  context.isStop = () => stop;
2932
+ context.isKill = () => kill;
2912
2933
  context = await setupModules(context, opts);
2913
2934
  const stopAfter = context.args.get("stopAfter");
2914
2935
  const stopAllowanceSec = Number(context.params.get("stopAllowance", "number default 60"));
@@ -2947,6 +2968,14 @@ async function init(flow2, opts = {}) {
2947
2968
  );
2948
2969
  context.emitter.emit("stop", stopAllowanceMs);
2949
2970
  });
2971
+ process.on("SIGUSR2", () => {
2972
+ if (!context || kill) return;
2973
+ kill = true;
2974
+ stop = true;
2975
+ context.logger.warn(">> SIGUSR2: emitting kill (urgent stop)");
2976
+ context.emitter.emit("kill");
2977
+ context.emitter.emit("stop", stopAllowanceMs);
2978
+ });
2950
2979
  await flow2(context);
2951
2980
  } catch (error) {
2952
2981
  const errorLocation = error instanceof Error && error.stack ? error.stack.split("\n")[1]?.trim() || "Unknown location" : "Unknown location";
@@ -2973,7 +3002,7 @@ async function init(flow2, opts = {}) {
2973
3002
  }
2974
3003
  if (process.exitCode && process.exitCode !== 0) {
2975
3004
  process.exit(process.exitCode);
2976
- } else if (stop) {
3005
+ } else if (stop || kill) {
2977
3006
  process.exit(0);
2978
3007
  }
2979
3008
  }
@@ -6546,6 +6575,7 @@ var LOGGER_RUNTIME_KEYS = [
6546
6575
  "route",
6547
6576
  "prefix",
6548
6577
  "progressWithTimes",
6578
+ "progressWithRate",
6549
6579
  "progressThrottleMs"
6550
6580
  ];
6551
6581
  var DEFAULT_RUNTIME_PARAM_SPECS = [
@@ -6649,6 +6679,7 @@ function coerceRuntimeValue(key, value) {
6649
6679
  case "showLevel":
6650
6680
  case "timestamp":
6651
6681
  case "progressWithTimes":
6682
+ case "progressWithRate":
6652
6683
  if (typeof value === "boolean") return value;
6653
6684
  if (value === "true" || value === "1") return true;
6654
6685
  if (value === "false" || value === "0") return false;