@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/tasks.cjs CHANGED
@@ -49,6 +49,7 @@ __export(tasks_exports, {
49
49
  coerceRuntimeValue: () => coerceRuntimeValue,
50
50
  controlLaneTaskNames: () => controlLaneTaskNames,
51
51
  convertPattern: () => convertPattern,
52
+ createTaskProgressReporter: () => createTaskProgressReporter,
52
53
  defaultTasksRegistry: () => defaultTasksRegistry,
53
54
  enqueueStopTask: () => enqueueStopTask,
54
55
  enqueueTask: () => enqueueTask,
@@ -548,6 +549,34 @@ async function updateTaskProgress(context, tasksTable, taskId, progress) {
548
549
  progress: typeof progress === "string" ? progress : JSON.stringify(progress)
549
550
  });
550
551
  }
552
+ function createTaskProgressReporter(context, tasksTable, taskId) {
553
+ let pump = null;
554
+ let pending = void 0;
555
+ let hasPending = false;
556
+ return (progress) => {
557
+ pending = progress;
558
+ hasPending = true;
559
+ if (pump) return pump;
560
+ pump = (async () => {
561
+ try {
562
+ while (hasPending) {
563
+ hasPending = false;
564
+ const value = pending;
565
+ try {
566
+ await updateTaskProgress(context, tasksTable, taskId, value);
567
+ } catch (err) {
568
+ context.logger?.warn?.(
569
+ `[tasks] progress update failed for ${taskId}: ${err?.message ?? err}`
570
+ );
571
+ }
572
+ }
573
+ } finally {
574
+ pump = null;
575
+ }
576
+ })();
577
+ return pump;
578
+ };
579
+ }
551
580
 
552
581
  // src/tasks/servicesRegistry.js
553
582
  function getDb2(context) {
@@ -961,8 +990,13 @@ var FileDatabase = class _FileDatabase {
961
990
  this.currentVersionFolder = await ensurePath(this.getDestinationPath(), version);
962
991
  }
963
992
  /**
964
- * Create a new version folder with comprehensive timestamp logic
965
- * Only works in versioned mode
993
+ * Create a new version folder named with the current UTC second.
994
+ * Only works in versioned mode.
995
+ *
996
+ * Clash protection: if that name already exists (two writers in the same
997
+ * second, or wall clock behind the latest version), advance +1s until free.
998
+ * Do NOT always derive from max(existing)+1s — that made successive harvests
999
+ * hours apart still land one second apart on disk.
966
1000
  */
967
1001
  async makeNewVersion() {
968
1002
  if (!this.versioned) {
@@ -970,19 +1004,22 @@ var FileDatabase = class _FileDatabase {
970
1004
  }
971
1005
  this.metadata = this.getDefaultMetadata();
972
1006
  const existingVersions = await this.getVersions();
973
- let versionName;
1007
+ const existingSet = new Set(existingVersions);
1008
+ let candidateMs = Date.now();
974
1009
  if (existingVersions.length > 0) {
975
- const maxTimestamp = existingVersions.reduce((max, version) => {
976
- const versionDate = new Date(version.replace("Z", ""));
977
- const maxDate2 = new Date(max.replace("Z", ""));
978
- return versionDate > maxDate2 ? version : max;
979
- });
980
- const maxDate = new Date(maxTimestamp.replace("Z", ""));
981
- const nextDate = new Date(maxDate.getTime() + 1e3);
982
- versionName = nextDate.toISOString().split(".")[0] + "Z";
983
- } else {
984
- const now = /* @__PURE__ */ new Date();
985
- versionName = now.toISOString().split(".")[0] + "Z";
1010
+ let maxMs = 0;
1011
+ for (const version of existingVersions) {
1012
+ const ms = new Date(version).getTime();
1013
+ if (Number.isFinite(ms) && ms > maxMs) maxMs = ms;
1014
+ }
1015
+ if (candidateMs <= maxMs) {
1016
+ candidateMs = maxMs + 1e3;
1017
+ }
1018
+ }
1019
+ let versionName = new Date(candidateMs).toISOString().split(".")[0] + "Z";
1020
+ while (existingSet.has(versionName)) {
1021
+ candidateMs += 1e3;
1022
+ versionName = new Date(candidateMs).toISOString().split(".")[0] + "Z";
986
1023
  }
987
1024
  await this.setCurrentVersion(versionName);
988
1025
  this.currentFileNumber = 0;
@@ -3461,7 +3498,8 @@ async function executeClaimedTask(context, tasksTable, historyTable, row, regist
3461
3498
  try {
3462
3499
  taskInstance = new TaskClass(context, row);
3463
3500
  runningTaskInstances.set(row.id, taskInstance);
3464
- const runResult = await taskInstance.run((progress) => updateTaskProgress(context, tasksTable, row.id, progress));
3501
+ const reportProgress = createTaskProgressReporter(context, tasksTable, row.id);
3502
+ const runResult = await taskInstance.run(reportProgress);
3465
3503
  success = !!runResult?.success;
3466
3504
  results = runResult?.results ?? null;
3467
3505
  } catch (error) {
@@ -3974,6 +4012,7 @@ var TasksManager = class _TasksManager {
3974
4012
  coerceRuntimeValue,
3975
4013
  controlLaneTaskNames,
3976
4014
  convertPattern,
4015
+ createTaskProgressReporter,
3977
4016
  defaultTasksRegistry,
3978
4017
  enqueueStopTask,
3979
4018
  enqueueTask,