@nmakarov/cli-toolkit 0.51.0 → 0.55.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
@@ -1147,11 +1147,14 @@ __export(src_exports, {
1147
1147
  ensureTasksRuntime: () => ensureTasksRuntime,
1148
1148
  flushTaskIpcLogs: () => flushTaskIpcLogs,
1149
1149
  getArgsInstance: () => getArgsInstance,
1150
+ getPm2Process: () => getPm2Process,
1150
1151
  h: () => import_react5.createElement,
1151
1152
  initServiceStructure: () => initServiceStructure,
1152
1153
  installDeps: () => installDeps,
1153
1154
  installOperatorShell: () => installOperatorShell,
1154
1155
  ipcFileLogsTableNameForSourceResource: () => ipcFileLogsTableNameForSourceResource,
1156
+ isFreshOnline: () => isFreshOnline,
1157
+ isPidAlive: () => isPidAlive,
1155
1158
  joiEdateType: () => joiEdateType,
1156
1159
  joiStringArrayType: () => joiStringArrayType,
1157
1160
  listAliveRunnerHeartbeats: () => listServicesRegistry,
@@ -1193,6 +1196,7 @@ __export(src_exports, {
1193
1196
  resolveSteps: () => resolveSteps,
1194
1197
  rollbackService: () => rollbackService,
1195
1198
  run: () => run,
1199
+ runCapture: () => runCapture,
1196
1200
  runNodeTaskScript: () => runNodeTaskScript,
1197
1201
  runReleaseTests: () => runReleaseTests,
1198
1202
  runRemoteCli: () => runRemoteCli,
@@ -1210,6 +1214,8 @@ __export(src_exports, {
1210
1214
  showScreen: () => showScreen,
1211
1215
  showWordGridScreen: () => showWordGridScreen,
1212
1216
  sshRun: () => sshRun,
1217
+ startPm2: () => startPm2,
1218
+ stopPm2: () => stopPm2,
1213
1219
  syncEnv: () => syncEnv,
1214
1220
  taskHistoryInsertFromQueueRow: () => taskHistoryInsertFromQueueRow,
1215
1221
  timeMatcher: () => timeMatcher,
@@ -1227,6 +1233,7 @@ __export(src_exports, {
1227
1233
  useRef: () => import_react5.useRef,
1228
1234
  useState: () => import_react5.useState,
1229
1235
  waitForTaskResult: () => waitForTaskResult,
1236
+ waitPm2: () => waitPm2,
1230
1237
  writeReleaseBuildInfo: () => writeReleaseBuildInfo
1231
1238
  });
1232
1239
  module.exports = __toCommonJS(src_exports);
@@ -5383,8 +5390,13 @@ function defineService(service) {
5383
5390
  const pm2 = {
5384
5391
  appName: service.name,
5385
5392
  args: "",
5393
+ stopAllowance: 60,
5386
5394
  ...service.pm2
5387
5395
  };
5396
+ if (pm2.killTimeout == null) {
5397
+ const stopSec = Number(pm2.stopAllowance);
5398
+ pm2.killTimeout = Number.isFinite(stopSec) && stopSec > 0 ? Math.floor(stopSec * 1e3) + 5e3 : 65e3;
5399
+ }
5388
5400
  const nginx = service.nginx ? { siteName: service.name, ...service.nginx } : null;
5389
5401
  return {
5390
5402
  repoDirName: deriveRepoDirName(service.repoUrl),
@@ -5465,6 +5477,30 @@ function run(cmd, args, options = {}) {
5465
5477
  function runShell(command, options = {}) {
5466
5478
  return run("bash", ["-lc", command], options);
5467
5479
  }
5480
+ function runCapture(cmd, args, options = {}) {
5481
+ const { cwd, env, logger, allowFail = false } = options;
5482
+ return new Promise((resolve3, reject) => {
5483
+ logger?.info?.(`$ ${cmd} ${args.join(" ")}${cwd ? ` (cwd=${cwd})` : ""}`);
5484
+ const child = (0, import_node_child_process.spawn)(cmd, args, {
5485
+ cwd,
5486
+ env: env ?? process.env,
5487
+ stdio: ["ignore", "pipe", "pipe"]
5488
+ });
5489
+ let stdout = "";
5490
+ let stderr = "";
5491
+ child.stdout?.on("data", (chunk) => {
5492
+ stdout += chunk.toString();
5493
+ });
5494
+ child.stderr?.on("data", (chunk) => {
5495
+ stderr += chunk.toString();
5496
+ });
5497
+ child.on("error", reject);
5498
+ child.on("close", (code) => {
5499
+ if (code === 0 || allowFail) resolve3({ stdout, stderr, code });
5500
+ else reject(new Error(`${cmd} exited with code ${code}${stderr ? `: ${stderr.trim()}` : ""}`));
5501
+ });
5502
+ });
5503
+ }
5468
5504
 
5469
5505
  // src/deploy/log.js
5470
5506
  var import_promises = require("fs/promises");
@@ -5682,7 +5718,7 @@ async function runReleaseTests(service, releasePath, paths, options = {}) {
5682
5718
  // src/deploy/prune.js
5683
5719
  var import_promises7 = require("fs/promises");
5684
5720
  async function pruneReleases(service, paths, options = {}) {
5685
- const { dryRun = false, logger = console } = options;
5721
+ const { dryRun = false, logger = console, protect = [] } = options;
5686
5722
  const keep = service.keepReleases ?? 3;
5687
5723
  const releases = await listReleases(paths);
5688
5724
  let activeName = null;
@@ -5696,6 +5732,9 @@ async function pruneReleases(service, paths, options = {}) {
5696
5732
  if (keepSet.size < keep) keepSet.add(rel.name);
5697
5733
  }
5698
5734
  if (activeName) keepSet.add(activeName);
5735
+ for (const name of protect) {
5736
+ if (name) keepSet.add(name);
5737
+ }
5699
5738
  const toRemove = releases.filter((rel) => !keepSet.has(rel.name));
5700
5739
  for (const rel of toRemove) {
5701
5740
  if (dryRun) {
@@ -5709,14 +5748,139 @@ async function pruneReleases(service, paths, options = {}) {
5709
5748
  }
5710
5749
 
5711
5750
  // src/deploy/pm2.js
5751
+ function sleep(ms) {
5752
+ return new Promise((resolve3) => setTimeout(resolve3, ms));
5753
+ }
5754
+ function isPidAlive(pid) {
5755
+ const n = Number(pid);
5756
+ if (!Number.isFinite(n) || n <= 0) return false;
5757
+ try {
5758
+ process.kill(n, 0);
5759
+ return true;
5760
+ } catch {
5761
+ return false;
5762
+ }
5763
+ }
5764
+ async function getPm2Process(appName, options = {}) {
5765
+ const { logger } = options;
5766
+ const { stdout } = await runCapture("bash", ["-lc", "pm2 jlist"], { logger });
5767
+ let list;
5768
+ try {
5769
+ list = JSON.parse(stdout || "[]");
5770
+ } catch (err) {
5771
+ throw new Error(`pm2 jlist: invalid JSON (${err?.message ?? err})`);
5772
+ }
5773
+ if (!Array.isArray(list)) return null;
5774
+ return list.find((p) => p?.name === appName) ?? null;
5775
+ }
5776
+ async function waitPm2(appName, predicate, options = {}) {
5777
+ const {
5778
+ timeoutMs = 65e3,
5779
+ pollMs = 500,
5780
+ dryRun = false,
5781
+ logger = console,
5782
+ label = "condition"
5783
+ } = options;
5784
+ if (dryRun) {
5785
+ logger.info?.(`[dryRun] would wait pm2 ${appName} for ${label}`);
5786
+ return null;
5787
+ }
5788
+ const deadline = Date.now() + timeoutMs;
5789
+ let lastStatus = "(unknown)";
5790
+ while (Date.now() < deadline) {
5791
+ const proc = await getPm2Process(appName, { logger });
5792
+ lastStatus = proc?.pm2_env?.status ?? "(missing)";
5793
+ if (predicate(proc)) return proc;
5794
+ await sleep(pollMs);
5795
+ }
5796
+ throw new Error(
5797
+ `pm2 wait timed out after ${timeoutMs}ms for ${appName} (${label}); last status=${lastStatus}`
5798
+ );
5799
+ }
5800
+ function isFreshOnline(proc, oldPid) {
5801
+ if (proc?.pm2_env?.status !== "online") return false;
5802
+ const pid = Number(proc.pid);
5803
+ if (!Number.isFinite(pid) || pid <= 0) return false;
5804
+ if (oldPid != null) {
5805
+ if (pid === oldPid) return false;
5806
+ if (isPidAlive(oldPid)) return false;
5807
+ }
5808
+ return true;
5809
+ }
5712
5810
  async function reloadPm2(paths, options = {}) {
5713
- const { dryRun = false, logger = console } = options;
5811
+ const { dryRun = false, logger = console, appName = null, waitTimeoutMs = 65e3 } = options;
5714
5812
  if (dryRun) {
5715
5813
  logger.info(`[dryRun] would pm2 startOrReload ${paths.ecosystem} --update-env`);
5716
5814
  return;
5717
5815
  }
5816
+ let oldPid = null;
5817
+ if (appName) {
5818
+ const before = await getPm2Process(appName, { logger });
5819
+ const n = Number(before?.pid);
5820
+ if (Number.isFinite(n) && n > 0 && before?.pm2_env?.status === "online") {
5821
+ oldPid = n;
5822
+ logger.info(`pm2 ${appName}: reloading (old pid=${oldPid})`);
5823
+ }
5824
+ }
5718
5825
  await runShell(`pm2 startOrReload "${paths.ecosystem}" --update-env`, { logger });
5719
5826
  logger.info("pm2 reloaded");
5827
+ if (appName) {
5828
+ const proc = await waitPm2(
5829
+ appName,
5830
+ (p) => isFreshOnline(p, oldPid),
5831
+ {
5832
+ timeoutMs: waitTimeoutMs,
5833
+ logger,
5834
+ label: oldPid ? `online on new pid (old ${oldPid} gone)` : "online after reload"
5835
+ }
5836
+ );
5837
+ logger.info(`pm2 ${appName} online pid=${proc?.pid ?? "?"}`);
5838
+ }
5839
+ }
5840
+ async function stopPm2(appName, options = {}) {
5841
+ const { dryRun = false, logger = console, waitTimeoutMs = 65e3 } = options;
5842
+ if (dryRun) {
5843
+ logger.info(`[dryRun] would pm2 stop ${appName}`);
5844
+ return;
5845
+ }
5846
+ const before = await getPm2Process(appName, { logger });
5847
+ if (!before) {
5848
+ logger.info(`pm2 ${appName}: not present (already stopped)`);
5849
+ return;
5850
+ }
5851
+ if (before.pm2_env?.status === "stopped") {
5852
+ logger.info(`pm2 ${appName}: already stopped`);
5853
+ return;
5854
+ }
5855
+ const oldPid = Number(before.pid);
5856
+ await runShell(`pm2 stop "${appName}"`, { logger });
5857
+ await waitPm2(
5858
+ appName,
5859
+ (proc) => {
5860
+ if (proc && proc.pm2_env?.status !== "stopped") return false;
5861
+ if (Number.isFinite(oldPid) && oldPid > 0 && isPidAlive(oldPid)) return false;
5862
+ return true;
5863
+ },
5864
+ { timeoutMs: waitTimeoutMs, logger, label: "stopped" }
5865
+ );
5866
+ logger.info(`pm2 ${appName} stopped`);
5867
+ }
5868
+ async function startPm2(paths, options = {}) {
5869
+ const { dryRun = false, logger = console, appName = null, waitTimeoutMs = 65e3 } = options;
5870
+ if (dryRun) {
5871
+ logger.info(`[dryRun] would pm2 start ${paths.ecosystem} --update-env`);
5872
+ return;
5873
+ }
5874
+ await runShell(`pm2 start "${paths.ecosystem}" --update-env`, { logger });
5875
+ logger.info("pm2 started");
5876
+ if (appName) {
5877
+ const proc = await waitPm2(
5878
+ appName,
5879
+ (p) => isFreshOnline(p, null),
5880
+ { timeoutMs: waitTimeoutMs, logger, label: "online after start" }
5881
+ );
5882
+ logger.info(`pm2 ${appName} online pid=${proc?.pid ?? "?"}`);
5883
+ }
5720
5884
  }
5721
5885
 
5722
5886
  // src/deploy/nginx.js
@@ -5945,10 +6109,26 @@ async function requireDeployRoot(parentDir, serviceRoot) {
5945
6109
  This is meant to run on the target host (where ${parentDir} exists). For a local dry run use --appsRoot=/tmp/<service>.`
5946
6110
  );
5947
6111
  }
6112
+ function resolveKillTimeoutMs(pm2) {
6113
+ const explicit = Number(pm2?.killTimeout);
6114
+ if (Number.isFinite(explicit) && explicit > 0) return Math.floor(explicit);
6115
+ const stopSec = Number(pm2?.stopAllowance);
6116
+ if (Number.isFinite(stopSec) && stopSec > 0) return Math.floor(stopSec * 1e3) + 5e3;
6117
+ return 65e3;
6118
+ }
6119
+ function resolvePm2Args(pm2) {
6120
+ const base = String(pm2?.args ?? "").trim();
6121
+ const stopSec = Number(pm2?.stopAllowance);
6122
+ if (!Number.isFinite(stopSec) || stopSec <= 0) return base;
6123
+ if (/(?:^|\s)--stopAllowance=/.test(base)) return base;
6124
+ return `${base}${base ? " " : ""}--stopAllowance=${Math.floor(stopSec)}`.trim();
6125
+ }
5948
6126
  function buildEcosystemConfig(service, paths) {
5949
6127
  const { pm2 } = service;
5950
6128
  const outLog = (0, import_node_path8.join)(paths.logs, `${pm2.appName}.out.log`);
5951
6129
  const errLog = (0, import_node_path8.join)(paths.logs, `${pm2.appName}.err.log`);
6130
+ const killTimeoutMs = resolveKillTimeoutMs(pm2);
6131
+ const args = resolvePm2Args(pm2);
5952
6132
  return `/**
5953
6133
  * pm2 ecosystem for ${service.name} \u2014 written by cli-toolkit deploy from the
5954
6134
  * service manifest (init/deploy). Do not hand-edit; change pm2.* in the
@@ -5960,7 +6140,7 @@ module.exports = {
5960
6140
  name: "${pm2.appName}",
5961
6141
  script: "${pm2.script}",
5962
6142
  cwd: "${paths.current}",
5963
- args: "${pm2.args ?? ""}",
6143
+ args: ${JSON.stringify(args)},
5964
6144
  instances: 1,
5965
6145
  exec_mode: "fork",
5966
6146
  autorestart: true,
@@ -5968,6 +6148,8 @@ module.exports = {
5968
6148
  max_restarts: 10,
5969
6149
  restart_delay: 2000,
5970
6150
  max_memory_restart: "1500M",
6151
+ // Grace window after SIGINT/SIGTERM before SIGKILL (ms). Align with --stopAllowance.
6152
+ kill_timeout: ${killTimeoutMs},
5971
6153
  out_file: "${outLog}",
5972
6154
  error_file: "${errLog}",
5973
6155
  merge_logs: true,
@@ -6168,15 +6350,27 @@ async function bootstrapHost(service, options = {}) {
6168
6350
  }
6169
6351
 
6170
6352
  // src/deploy/deploy-service.js
6353
+ var import_promises13 = require("fs/promises");
6354
+ function resolveKillTimeoutMs2(service) {
6355
+ const explicit = Number(service.pm2?.killTimeout);
6356
+ if (Number.isFinite(explicit) && explicit > 0) return Math.floor(explicit);
6357
+ const stopSec = Number(service.pm2?.stopAllowance);
6358
+ if (Number.isFinite(stopSec) && stopSec > 0) return Math.floor(stopSec * 1e3) + 5e3;
6359
+ return 65e3;
6360
+ }
6171
6361
  async function deployService(service, options = {}) {
6172
6362
  const {
6173
6363
  dryRun = false,
6174
6364
  skipPull = false,
6175
6365
  skipTests = false,
6176
6366
  skipNginx = false,
6367
+ stopFirst = false,
6177
6368
  logger = console
6178
6369
  } = options;
6179
6370
  const paths = servicePaths(service);
6371
+ const appName = service.pm2.appName;
6372
+ const killTimeoutMs = resolveKillTimeoutMs2(service);
6373
+ const waitTimeoutMs = killTimeoutMs + 1e4;
6180
6374
  await initServiceStructure(service, { dryRun, logger });
6181
6375
  if (!skipPull) await pullRepo(service, { dryRun, logger });
6182
6376
  await syncEnv(service, { dryRun, logger });
@@ -6184,21 +6378,38 @@ async function deployService(service, options = {}) {
6184
6378
  await writeReleaseBuildInfo(service, releasePath, { stamp, dryRun, logger });
6185
6379
  await installDeps(service, releasePath, paths, { dryRun, logger });
6186
6380
  if (!skipTests) await runReleaseTests(service, releasePath, paths, { dryRun, logger });
6187
- await activateRelease(releasePath, paths, { dryRun, logger });
6188
- await pruneReleases(service, paths, { dryRun, logger });
6189
- await reloadPm2(paths, { dryRun, logger });
6381
+ let previousReleaseName = null;
6382
+ try {
6383
+ const prev = await (0, import_promises13.readlink)(paths.current);
6384
+ previousReleaseName = prev.split("/").pop() || null;
6385
+ } catch {
6386
+ }
6387
+ if (stopFirst) {
6388
+ logger.info(`deploy mode=stopFirst app=${appName} killTimeoutMs=${killTimeoutMs}`);
6389
+ await stopPm2(appName, { dryRun, logger, waitTimeoutMs });
6390
+ await activateRelease(releasePath, paths, { dryRun, logger });
6391
+ await pruneReleases(service, paths, { dryRun, logger });
6392
+ await startPm2(paths, { dryRun, logger, appName, waitTimeoutMs });
6393
+ } else {
6394
+ logger.info(
6395
+ `deploy mode=rolling app=${appName} killTimeoutMs=${killTimeoutMs}` + (previousReleaseName ? ` previous=${previousReleaseName}` : "")
6396
+ );
6397
+ await activateRelease(releasePath, paths, { dryRun, logger });
6398
+ await reloadPm2(paths, { dryRun, logger, appName, waitTimeoutMs });
6399
+ await pruneReleases(service, paths, { dryRun, logger });
6400
+ }
6190
6401
  if (!skipNginx) await enableNginxUpstream(service, { dryRun, logger });
6191
- const summary = `deploy complete stamp=${stamp} dryRun=${dryRun}`;
6402
+ const summary = `deploy complete stamp=${stamp} mode=${stopFirst ? "stopFirst" : "rolling"} dryRun=${dryRun}`;
6192
6403
  logger.info(summary);
6193
6404
  if (!dryRun) await appendDeployLog(paths.deployLog, summary);
6194
- return { stamp, releasePath };
6405
+ return { stamp, releasePath, mode: stopFirst ? "stopFirst" : "rolling" };
6195
6406
  }
6196
6407
 
6197
6408
  // src/deploy/provision-service.js
6198
- var import_promises13 = require("fs/promises");
6409
+ var import_promises14 = require("fs/promises");
6199
6410
  async function pathExists6(path5) {
6200
6411
  try {
6201
- await (0, import_promises13.access)(path5);
6412
+ await (0, import_promises14.access)(path5);
6202
6413
  return true;
6203
6414
  } catch {
6204
6415
  return false;
@@ -6232,7 +6443,7 @@ async function provisionService(service, options = {}) {
6232
6443
  }
6233
6444
 
6234
6445
  // src/deploy/rollback-service.js
6235
- var import_promises14 = require("fs/promises");
6446
+ var import_promises15 = require("fs/promises");
6236
6447
  async function rollbackService(service, options = {}) {
6237
6448
  const { release: targetName, dryRun = false, logger = console } = options;
6238
6449
  const paths = servicePaths(service);
@@ -6240,7 +6451,7 @@ async function rollbackService(service, options = {}) {
6240
6451
  if (releases.length === 0) throw new Error("No releases to roll back to");
6241
6452
  let activeName = null;
6242
6453
  try {
6243
- const target = await (0, import_promises14.readlink)(paths.current);
6454
+ const target = await (0, import_promises15.readlink)(paths.current);
6244
6455
  activeName = target.split("/").pop();
6245
6456
  } catch {
6246
6457
  throw new Error("No active release (current symlink missing)");
@@ -6267,14 +6478,14 @@ async function rollbackService(service, options = {}) {
6267
6478
  }
6268
6479
 
6269
6480
  // src/deploy/ssh-remote.js
6270
- var import_promises15 = require("fs/promises");
6481
+ var import_promises16 = require("fs/promises");
6271
6482
  var import_node_os3 = require("os");
6272
6483
  var import_node_path10 = require("path");
6273
6484
  var import_node_child_process4 = require("child_process");
6274
6485
  var REMOTE_CLI_REL = "node_modules/@nmakarov/cli-toolkit/scripts/deploy/cli.js";
6275
6486
  async function pathExists7(path5) {
6276
6487
  try {
6277
- await (0, import_promises15.access)(path5);
6488
+ await (0, import_promises16.access)(path5);
6278
6489
  return true;
6279
6490
  } catch {
6280
6491
  return false;
@@ -6366,9 +6577,9 @@ async function ensureEnvOnRemote(host, service, options = {}) {
6366
6577
  if (!await pathExists7(localPath)) return false;
6367
6578
  logger.info(`copying .env ${localPath} \u2192 ${host}:${paths.repoEnv}`);
6368
6579
  await sshRun(host, `mkdir -p ${shellQuote((0, import_node_path10.dirname)(paths.repoEnv))}`, { logger });
6369
- const scrubbed = scrubEnvContent(await (0, import_promises15.readFile)(localPath, "utf8"), service.envScrubPatterns ?? []);
6580
+ const scrubbed = scrubEnvContent(await (0, import_promises16.readFile)(localPath, "utf8"), service.envScrubPatterns ?? []);
6370
6581
  const tmp = (0, import_node_path10.join)((0, import_node_os3.tmpdir)(), `deploy-env-${Date.now()}`);
6371
- await (0, import_promises15.writeFile)(tmp, scrubbed, { mode: 384 });
6582
+ await (0, import_promises16.writeFile)(tmp, scrubbed, { mode: 384 });
6372
6583
  await scp(tmp, `${host}:${paths.repoEnv}`, { logger });
6373
6584
  await sshRun(host, `chmod 600 ${shellQuote(paths.repoEnv)}`, { logger });
6374
6585
  return true;
@@ -7702,7 +7913,7 @@ var TaskShellCommand = class extends AbstractTask {
7702
7913
 
7703
7914
  // src/tasks/coreTasks/TaskSystemInfo.js
7704
7915
  var import_node_os5 = __toESM(require("os"), 1);
7705
- var import_promises16 = __toESM(require("fs/promises"), 1);
7916
+ var import_promises17 = __toESM(require("fs/promises"), 1);
7706
7917
  function toGb(valueBytes) {
7707
7918
  return `${(valueBytes / 1024 ** 3).toFixed(2)} GB`;
7708
7919
  }
@@ -7710,7 +7921,7 @@ function toMb(valueBytes) {
7710
7921
  return `${(valueBytes / 1024 ** 2).toFixed(2)} MB`;
7711
7922
  }
7712
7923
  async function getDiskStats() {
7713
- const stats = await import_promises16.default.statfs("/");
7924
+ const stats = await import_promises17.default.statfs("/");
7714
7925
  const total = Number(stats.bsize) * Number(stats.blocks);
7715
7926
  const free = Number(stats.bsize) * Number(stats.bavail);
7716
7927
  const used = total - free;
@@ -7863,7 +8074,7 @@ var TaskStopRunner = class extends AbstractTask {
7863
8074
  */
7864
8075
  static async resolveCustomParams(context, overrides = {}) {
7865
8076
  const merged = AbstractTask._mergeTypedParams(context, "task-stop", {
7866
- allowanceMs: "number default 5000"
8077
+ allowanceMs: "number default 60000"
7867
8078
  }, overrides);
7868
8079
  const allowanceMs = Number(merged.allowanceMs);
7869
8080
  if (!Number.isFinite(allowanceMs) || allowanceMs < 0) {
@@ -7877,7 +8088,7 @@ var TaskStopRunner = class extends AbstractTask {
7877
8088
  * @returns {Promise<{ success: true, results: { stopRunner: true, allowanceMs: number, message: string } }>}
7878
8089
  */
7879
8090
  async run() {
7880
- const allowanceMs = Number(this.task?.params?.allowanceMs ?? 5e3);
8091
+ const allowanceMs = Number(this.task?.params?.allowanceMs ?? 6e4);
7881
8092
  this.context.logger.warn?.(`[TaskStopRunner] stop requested (allowanceMs=${allowanceMs})`);
7882
8093
  return {
7883
8094
  success: true,
@@ -8562,7 +8773,7 @@ function normalizeRegistry(registry) {
8562
8773
  if (registry instanceof TasksRegistry) return registry;
8563
8774
  return new TasksRegistry().addMany(registry);
8564
8775
  }
8565
- async function enqueueStopTask(context, serviceGroup, queueName = "tasks", allowanceMs = 5e3) {
8776
+ async function enqueueStopTask(context, serviceGroup, queueName = "tasks", allowanceMs = 6e4) {
8566
8777
  return enqueueTask(context, {
8567
8778
  queueName,
8568
8779
  name: "stopRunner",
@@ -8701,7 +8912,7 @@ async function executeClaimedTask(context, tasksTable, historyTable, row, regist
8701
8912
  await db(tasksTable).where({ id: row.id }).delete();
8702
8913
  }
8703
8914
  const stopRunnerRequested = !!(results && typeof results === "object" && results.stopRunner === true);
8704
- const stopAllowanceMs = stopRunnerRequested ? Number(results.allowanceMs ?? 5e3) : 0;
8915
+ const stopAllowanceMs = stopRunnerRequested ? Number(results.allowanceMs ?? 6e4) : 0;
8705
8916
  return { stopRunnerRequested, stopAllowanceMs };
8706
8917
  }
8707
8918
  function shuffleTaskRowsInPlace(rows) {
@@ -8791,7 +9002,7 @@ async function runTasksLoop(context, options) {
8791
9002
  const runningTaskInstances = /* @__PURE__ */ new Map();
8792
9003
  let runningControlPromise = null;
8793
9004
  let stopRequested = false;
8794
- let stopAllowanceMs = 5e3;
9005
+ let stopAllowanceMs = Number(context.stopAllowanceMs) > 0 ? Number(context.stopAllowanceMs) : 6e4;
8795
9006
  context.tasksRunnerStop = false;
8796
9007
  let registryReg = null;
8797
9008
  let registryInterval = null;
@@ -8858,7 +9069,7 @@ async function runTasksLoop(context, options) {
8858
9069
  ).then(async (outcome) => {
8859
9070
  if (outcome.stopRunnerRequested && !stopRequested) {
8860
9071
  stopRequested = true;
8861
- stopAllowanceMs = outcome.stopAllowanceMs || 5e3;
9072
+ stopAllowanceMs = outcome.stopAllowanceMs || stopAllowanceMs;
8862
9073
  context.tasksRunnerStop = true;
8863
9074
  await signalRunningTasksStop(context, runningTaskInstances, stopAllowanceMs);
8864
9075
  }
@@ -8884,7 +9095,7 @@ async function runTasksLoop(context, options) {
8884
9095
  const p = executeClaimedTask(context, tasksTable, historyTable, claimed, registry, runningTaskInstances).then(async (outcome) => {
8885
9096
  if (outcome.stopRunnerRequested && !stopRequested) {
8886
9097
  stopRequested = true;
8887
- stopAllowanceMs = outcome.stopAllowanceMs || 5e3;
9098
+ stopAllowanceMs = outcome.stopAllowanceMs || stopAllowanceMs;
8888
9099
  context.tasksRunnerStop = true;
8889
9100
  await signalRunningTasksStop(context, runningTaskInstances, stopAllowanceMs);
8890
9101
  }
@@ -8905,7 +9116,9 @@ async function runTasksLoop(context, options) {
8905
9116
  }
8906
9117
  }
8907
9118
  if (context.isStop() && !stopRequested) {
8908
- await signalRunningTasksStop(context, runningTaskInstances, 5e3);
9119
+ stopRequested = true;
9120
+ stopAllowanceMs = Number(context.stopAllowanceMs) > 0 ? Number(context.stopAllowanceMs) : stopAllowanceMs;
9121
+ await signalRunningTasksStop(context, runningTaskInstances, stopAllowanceMs);
8909
9122
  }
8910
9123
  if (runningPromises.size > 0) {
8911
9124
  if (stopRequested) {
@@ -9190,11 +9403,14 @@ var TasksManager = class _TasksManager {
9190
9403
  ensureTasksRuntime,
9191
9404
  flushTaskIpcLogs,
9192
9405
  getArgsInstance,
9406
+ getPm2Process,
9193
9407
  h,
9194
9408
  initServiceStructure,
9195
9409
  installDeps,
9196
9410
  installOperatorShell,
9197
9411
  ipcFileLogsTableNameForSourceResource,
9412
+ isFreshOnline,
9413
+ isPidAlive,
9198
9414
  joiEdateType,
9199
9415
  joiStringArrayType,
9200
9416
  listAliveRunnerHeartbeats,
@@ -9236,6 +9452,7 @@ var TasksManager = class _TasksManager {
9236
9452
  resolveSteps,
9237
9453
  rollbackService,
9238
9454
  run,
9455
+ runCapture,
9239
9456
  runNodeTaskScript,
9240
9457
  runReleaseTests,
9241
9458
  runRemoteCli,
@@ -9253,6 +9470,8 @@ var TasksManager = class _TasksManager {
9253
9470
  showScreen,
9254
9471
  showWordGridScreen,
9255
9472
  sshRun,
9473
+ startPm2,
9474
+ stopPm2,
9256
9475
  syncEnv,
9257
9476
  taskHistoryInsertFromQueueRow,
9258
9477
  timeMatcher,
@@ -9270,6 +9489,7 @@ var TasksManager = class _TasksManager {
9270
9489
  useRef,
9271
9490
  useState,
9272
9491
  waitForTaskResult,
9492
+ waitPm2,
9273
9493
  writeReleaseBuildInfo
9274
9494
  });
9275
9495
  //# sourceMappingURL=index.cjs.map