@nmakarov/cli-toolkit 0.27.0 → 0.29.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
@@ -1813,7 +1813,8 @@ var Params = class _Params {
1813
1813
  /**
1814
1814
  * Resolved early in constructor so cleanup does not read params lazily.
1815
1815
  * One of: false (off) | "end" (print at exit) | "top" (print after init,
1816
- * via context.showUsedParamsIfNeeded()).
1816
+ * via context.showUsedParamsIfNeeded()) | "stop" (print after init, then
1817
+ * exit the process — also via context.showUsedParamsIfNeeded()).
1817
1818
  */
1818
1819
  _showUsedParamsMode = false;
1819
1820
  /** Guard so the dump prints at most once (top OR end, never both). */
@@ -1837,8 +1838,9 @@ var Params = class _Params {
1837
1838
  * (absent) / --no-showUsedParams / =false -> false (off)
1838
1839
  * --showUsedParams / =true -> "end" (print at exit)
1839
1840
  * --showUsedParams=top -> "top" (print after init)
1840
- * Read raw (uncoerced) from args so the string "top" isn't forced to a
1841
- * boolean, then track it under the "script" module for the dump itself.
1841
+ * --showUsedParams=stop -> "stop" (print after init, then exit)
1842
+ * Read raw (uncoerced) from args so the string "top"/"stop" isn't forced to
1843
+ * a boolean, then track it under the "script" module for the dump itself.
1842
1844
  */
1843
1845
  _resolveShowUsedParams() {
1844
1846
  const raw = this.args.get("showUsedParams");
@@ -1848,6 +1850,8 @@ var Params = class _Params {
1848
1850
  mode = false;
1849
1851
  } else if (typeof raw === "string" && raw.trim().toLowerCase() === "top") {
1850
1852
  mode = "top";
1853
+ } else if (typeof raw === "string" && raw.trim().toLowerCase() === "stop") {
1854
+ mode = "stop";
1851
1855
  } else {
1852
1856
  const s = typeof raw === "string" ? raw.trim().toLowerCase() : raw;
1853
1857
  const falsey = s === false || s === "false" || s === "0" || s === "no" || s === "off";
@@ -1861,7 +1865,7 @@ var Params = class _Params {
1861
1865
  getShowUsedParams() {
1862
1866
  return this._showUsedParamsMode !== false;
1863
1867
  }
1864
- /** Resolved mode: false | "end" | "top". */
1868
+ /** Resolved mode: false | "end" | "top" | "stop". */
1865
1869
  getShowUsedParamsMode() {
1866
1870
  return this._showUsedParamsMode;
1867
1871
  }
@@ -3896,6 +3900,7 @@ var S3 = class _S3 {
3896
3900
  secretAccessKey: config2.secretAccessKey
3897
3901
  };
3898
3902
  }
3903
+ process.env.AWS_SDK_JS_NODE_VERSION_SUPPORT_WARNING_DISABLED ??= "true";
3899
3904
  this.client = new import_client_s3.S3Client(clientConfig);
3900
3905
  }
3901
3906
  // ── info ────────────────────────────────────────────────────────────────
@@ -4427,9 +4432,18 @@ function setup(opts = {}) {
4427
4432
  // the used-params list now (after the script has initialized all its
4428
4433
  // own components), instead of at exit. No-op for the default mode,
4429
4434
  // which prints at exit via the cleanup registered by Params.
4435
+ //
4436
+ // --showUsedParams=stop behaves like "top" but then exits immediately —
4437
+ // a quick "show me the figured params and quit" that skips the flow's
4438
+ // actual work. Like --stopAfter=init, this is a hard exit(0) (registered
4439
+ // cleanups are skipped); call it once components/params are resolved.
4430
4440
  showUsedParamsIfNeeded: () => {
4431
- if (params.getShowUsedParamsMode?.() === "top") {
4432
- params.printUsedParams(logger);
4441
+ const mode = params.getShowUsedParamsMode?.();
4442
+ if (mode !== "top" && mode !== "stop") return;
4443
+ params.printUsedParams(logger);
4444
+ if (mode === "stop") {
4445
+ logger.debug?.("[showUsedParams=stop] params printed \u2014 exiting");
4446
+ process.exit(0);
4433
4447
  }
4434
4448
  }
4435
4449
  };
@@ -4553,7 +4567,7 @@ function defineTasksTable(t, db, tableNameForIndex) {
4553
4567
  t.timestamp("past_due").defaultTo(null);
4554
4568
  t.text("name").notNullable();
4555
4569
  t.text("opid");
4556
- t.json("params");
4570
+ t.jsonb("params");
4557
4571
  t.text("service_group");
4558
4572
  t.integer("instance_number");
4559
4573
  t.text("service_name");
@@ -4562,7 +4576,7 @@ function defineTasksTable(t, db, tableNameForIndex) {
4562
4576
  t.timestamp("status_changed_at").defaultTo(null);
4563
4577
  t.text("progress");
4564
4578
  t.boolean("success");
4565
- t.json("results");
4579
+ t.jsonb("results");
4566
4580
  t.index(["service_group", "status", "priority", "created_at"], `${tableNameForIndex}_claim_idx`);
4567
4581
  t.index(["service_group", "name"], `${tableNameForIndex}_group_name_idx`);
4568
4582
  }
@@ -4577,11 +4591,29 @@ function taskHistoryInsertFromQueueRow(row, overrides) {
4577
4591
  async function ensureTaskTables(context, options = {}) {
4578
4592
  const queueName = options.queueName ?? "tasks";
4579
4593
  const recreate = options.recreate ?? false;
4594
+ const dryRun = options.dryRun ?? false;
4580
4595
  const db = getDb(context);
4596
+ const log = context.logger ?? console;
4581
4597
  const { tasksTable, historyTable, registryTable } = queueToTableNames(queueName);
4582
4598
  const needsTasks = recreate ? true : !await db.tableExists(tasksTable);
4583
4599
  const needsHistory = recreate ? true : !await db.tableExists(historyTable);
4584
4600
  const needsRegistry = recreate ? true : !await db.tableExists(registryTable);
4601
+ if (dryRun) {
4602
+ const plan = [];
4603
+ if (recreate) {
4604
+ plan.push(`DROP TABLE IF EXISTS ${historyTable}, ${tasksTable}, ${registryTable}`);
4605
+ }
4606
+ if (needsTasks) plan.push(`CREATE TABLE ${tasksTable} (tasks queue)`);
4607
+ if (needsHistory) plan.push(`CREATE TABLE ${historyTable} (history mirror)`);
4608
+ if (needsRegistry) plan.push(`CREATE TABLE ${registryTable} (services registry)`);
4609
+ if (plan.length === 0) {
4610
+ log.info?.(`[tasks-schema] dryRun \u2014 queue "${queueName}" already up to date; no DDL`);
4611
+ } else {
4612
+ log.info?.(`[tasks-schema] dryRun \u2014 would run ${plan.length} statement(s) for queue "${queueName}":`);
4613
+ for (const s of plan) log.info?.(` - ${s}`);
4614
+ }
4615
+ return;
4616
+ }
4585
4617
  if (recreate) {
4586
4618
  await db.schema.dropTableIfExists(historyTable);
4587
4619
  await db.schema.dropTableIfExists(tasksTable);
@@ -6024,8 +6056,7 @@ function forwardChildLogToParent(context, prefix, message) {
6024
6056
  }
6025
6057
  function buildNodeArgs(scriptPath, cliArgs) {
6026
6058
  const inheritedExecArgs = Array.isArray(process.execArgv) ? [...process.execArgv] : [];
6027
- const hasTsRuntimeInParent = inheritedExecArgs.some((arg) => /tsx|ts-node/i.test(arg));
6028
- return hasTsRuntimeInParent ? [...inheritedExecArgs, scriptPath, ...cliArgs] : ["--import", "tsx", scriptPath, ...cliArgs];
6059
+ return [...inheritedExecArgs, scriptPath, ...cliArgs];
6029
6060
  }
6030
6061
  function resolveTasksTableName(context) {
6031
6062
  return context.tasksQueueName || context.params?.get?.("table") || "tasks";
@@ -6265,9 +6296,8 @@ async function executeClaimedTask(context, tasksTable, historyTable, row, regist
6265
6296
  const dbName = String(context?.params?.get?.("dbName") || "local");
6266
6297
  const tableName = String(context?.params?.get?.("table") || "tasks");
6267
6298
  const fallbackRecoverCommand = [
6268
- "npx",
6269
- "tsx",
6270
- "examples/tasks/recover-task.ts",
6299
+ "node",
6300
+ "examples/tasks/recover-task.js",
6271
6301
  `--dbName='${dbName.replace(/'/g, `'\\''`)}'`,
6272
6302
  `--table='${tableName.replace(/'/g, `'\\''`)}'`,
6273
6303
  `--id='${String(row.id).replace(/'/g, `'\\''`)}'`
@@ -6333,6 +6363,8 @@ async function claimNextRunnableTask(context, tasksTable, serviceGroup, registry
6333
6363
  const db = getDb3(context);
6334
6364
  let query = db(tasksTable).where({ status: "idle" }).where(function() {
6335
6365
  this.whereNull("service_group").orWhere({ service_group: serviceGroup });
6366
+ }).where(function() {
6367
+ this.whereNull("next_run_at").orWhere("next_run_at", "<=", db.fn.now());
6336
6368
  }).orderByRaw("CASE WHEN past_due IS NULL THEN 1 ELSE 0 END ASC").orderBy([{ column: "priority", order: "asc" }]).orderByRaw("CASE WHEN completed_at IS NULL THEN 0 ELSE 1 END ASC").orderBy([{ column: "completed_at", order: "asc" }, { column: "created_at", order: "asc" }]).limit(scanLimit);
6337
6369
  if (taskNames && taskNames.length > 0) {
6338
6370
  query = query.whereIn("name", taskNames);