@nmakarov/cli-toolkit 0.61.0 → 0.65.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/index.cjs CHANGED
@@ -1125,6 +1125,7 @@ __export(src_exports, {
1125
1125
  controlLaneTaskNames: () => controlLaneTaskNames,
1126
1126
  convertPattern: () => convertPattern,
1127
1127
  createRelease: () => createRelease,
1128
+ createTaskProgressReporter: () => createTaskProgressReporter,
1128
1129
  defaultFileSynopsisFunction: () => defaultFileSynopsisFunction,
1129
1130
  defaultTasksRegistry: () => defaultTasksRegistry,
1130
1131
  defaultVersionSynopsisFunction: () => defaultVersionSynopsisFunction,
@@ -2642,8 +2643,13 @@ var FileDatabase = class _FileDatabase {
2642
2643
  this.currentVersionFolder = await ensurePath(this.getDestinationPath(), version);
2643
2644
  }
2644
2645
  /**
2645
- * Create a new version folder with comprehensive timestamp logic
2646
- * Only works in versioned mode
2646
+ * Create a new version folder named with the current UTC second.
2647
+ * Only works in versioned mode.
2648
+ *
2649
+ * Clash protection: if that name already exists (two writers in the same
2650
+ * second, or wall clock behind the latest version), advance +1s until free.
2651
+ * Do NOT always derive from max(existing)+1s — that made successive harvests
2652
+ * hours apart still land one second apart on disk.
2647
2653
  */
2648
2654
  async makeNewVersion() {
2649
2655
  if (!this.versioned) {
@@ -2651,19 +2657,22 @@ var FileDatabase = class _FileDatabase {
2651
2657
  }
2652
2658
  this.metadata = this.getDefaultMetadata();
2653
2659
  const existingVersions = await this.getVersions();
2654
- let versionName;
2660
+ const existingSet = new Set(existingVersions);
2661
+ let candidateMs = Date.now();
2655
2662
  if (existingVersions.length > 0) {
2656
- const maxTimestamp = existingVersions.reduce((max, version) => {
2657
- const versionDate = new Date(version.replace("Z", ""));
2658
- const maxDate2 = new Date(max.replace("Z", ""));
2659
- return versionDate > maxDate2 ? version : max;
2660
- });
2661
- const maxDate = new Date(maxTimestamp.replace("Z", ""));
2662
- const nextDate = new Date(maxDate.getTime() + 1e3);
2663
- versionName = nextDate.toISOString().split(".")[0] + "Z";
2664
- } else {
2665
- const now = /* @__PURE__ */ new Date();
2666
- versionName = now.toISOString().split(".")[0] + "Z";
2663
+ let maxMs = 0;
2664
+ for (const version of existingVersions) {
2665
+ const ms = new Date(version).getTime();
2666
+ if (Number.isFinite(ms) && ms > maxMs) maxMs = ms;
2667
+ }
2668
+ if (candidateMs <= maxMs) {
2669
+ candidateMs = maxMs + 1e3;
2670
+ }
2671
+ }
2672
+ let versionName = new Date(candidateMs).toISOString().split(".")[0] + "Z";
2673
+ while (existingSet.has(versionName)) {
2674
+ candidateMs += 1e3;
2675
+ versionName = new Date(candidateMs).toISOString().split(".")[0] + "Z";
2667
2676
  }
2668
2677
  await this.setCurrentVersion(versionName);
2669
2678
  this.currentFileNumber = 0;
@@ -3693,13 +3702,15 @@ var CONNECTION_ERROR_CODES = /* @__PURE__ */ new Set([
3693
3702
  "57P02",
3694
3703
  "57P03"
3695
3704
  ]);
3696
- var CONNECTION_ERROR_MESSAGE_RE = /connection (terminated|ended|closed|destroyed|reset|refused|not open)|Connection terminated unexpectedly|Client has encountered a connection error|server closed the connection|Cannot use a pool after calling end|This socket has been ended|connect ECONNRESET|Timeout acquiring a connection/i;
3705
+ var CONNECTION_ERROR_MESSAGE_RE = /connection (terminated|ended|closed|destroyed|reset|refused|not open)|Connection terminated unexpectedly|Client has encountered a connection error|server closed the connection|Cannot use a pool after calling end|This socket has been ended|connect ECONNRESET/i;
3697
3706
  var Db = class _Db {
3698
3707
  static async init(context, options = {}) {
3699
3708
  const buildConfig = async () => {
3700
3709
  const defs = {
3701
3710
  dbName: "string",
3702
- dbProfile: "boolean default false"
3711
+ dbProfile: "boolean default false",
3712
+ /** Cap knex pool size (default 10). Size ≈ expected concurrency + headroom. */
3713
+ dbPoolMax: "number"
3703
3714
  };
3704
3715
  const discovered = context?.params?.getAllForModule?.("db", defs) ?? {};
3705
3716
  const merged = { ...discovered, ...options };
@@ -3758,12 +3769,23 @@ var Db = class _Db {
3758
3769
  context?.args?.env,
3759
3770
  merged.name
3760
3771
  );
3772
+ const poolMaxRaw = merged.dbPoolMax ?? merged.pool?.max;
3773
+ const poolMax = Number(poolMaxRaw);
3774
+ const pool = {
3775
+ ...KNEX_DEFAULTS.pool,
3776
+ ...merged.pool && typeof merged.pool === "object" ? merged.pool : {}
3777
+ };
3778
+ if (Number.isFinite(poolMax) && poolMax >= 1) {
3779
+ pool.max = Math.floor(poolMax);
3780
+ }
3761
3781
  return {
3762
3782
  ...KNEX_DEFAULTS,
3763
3783
  connectionString: dbConnectionString,
3764
3784
  name: displayName,
3765
3785
  profile: !!dbProfile,
3766
- logger: context.logger
3786
+ logger: context.logger,
3787
+ pool,
3788
+ ...merged.acquireConnectionTimeout != null ? { acquireConnectionTimeout: merged.acquireConnectionTimeout } : {}
3767
3789
  };
3768
3790
  };
3769
3791
  const config2 = context?.params?.runWithModuleAsync ? await context.params.runWithModuleAsync("db", buildConfig) : await buildConfig();
@@ -5190,6 +5212,9 @@ var Logger = class _Logger {
5190
5212
  const message = this.inspectChunks([operation, ...chunks]);
5191
5213
  this.out({ level: "response", message });
5192
5214
  }
5215
+ /**
5216
+ * @returns {boolean} true when the progress line was emitted (not throttled)
5217
+ */
5193
5218
  progress(message, opts) {
5194
5219
  const { prefix, count, total } = opts;
5195
5220
  const paddedTotal = String(total).length;
@@ -5223,7 +5248,9 @@ var Logger = class _Logger {
5223
5248
  if (this.options.progressThrottle && prefix) {
5224
5249
  this.lastProgressTimes[prefix] = Date.now();
5225
5250
  }
5251
+ return true;
5226
5252
  }
5253
+ return false;
5227
5254
  }
5228
5255
  shouldOutputProgress(prefix, count, total) {
5229
5256
  if (!this.options.progressThrottle) {
@@ -7063,6 +7090,34 @@ async function updateTaskProgress(context, tasksTable, taskId, progress) {
7063
7090
  progress: typeof progress === "string" ? progress : JSON.stringify(progress)
7064
7091
  });
7065
7092
  }
7093
+ function createTaskProgressReporter(context, tasksTable, taskId) {
7094
+ let pump = null;
7095
+ let pending = void 0;
7096
+ let hasPending = false;
7097
+ return (progress) => {
7098
+ pending = progress;
7099
+ hasPending = true;
7100
+ if (pump) return pump;
7101
+ pump = (async () => {
7102
+ try {
7103
+ while (hasPending) {
7104
+ hasPending = false;
7105
+ const value = pending;
7106
+ try {
7107
+ await updateTaskProgress(context, tasksTable, taskId, value);
7108
+ } catch (err) {
7109
+ context.logger?.warn?.(
7110
+ `[tasks] progress update failed for ${taskId}: ${err?.message ?? err}`
7111
+ );
7112
+ }
7113
+ }
7114
+ } finally {
7115
+ pump = null;
7116
+ }
7117
+ })();
7118
+ return pump;
7119
+ };
7120
+ }
7066
7121
 
7067
7122
  // src/tasks/servicesRegistry.js
7068
7123
  function getDb2(context) {
@@ -8914,7 +8969,8 @@ async function executeClaimedTask(context, tasksTable, historyTable, row, regist
8914
8969
  try {
8915
8970
  taskInstance = new TaskClass(context, row);
8916
8971
  runningTaskInstances.set(row.id, taskInstance);
8917
- const runResult = await taskInstance.run((progress) => updateTaskProgress(context, tasksTable, row.id, progress));
8972
+ const reportProgress = createTaskProgressReporter(context, tasksTable, row.id);
8973
+ const runResult = await taskInstance.run(reportProgress);
8918
8974
  success = !!runResult?.success;
8919
8975
  results = runResult?.results ?? null;
8920
8976
  } catch (error) {
@@ -9462,6 +9518,7 @@ var TasksManager = class _TasksManager {
9462
9518
  controlLaneTaskNames,
9463
9519
  convertPattern,
9464
9520
  createRelease,
9521
+ createTaskProgressReporter,
9465
9522
  defaultFileSynopsisFunction,
9466
9523
  defaultTasksRegistry,
9467
9524
  defaultVersionSynopsisFunction,