@nmakarov/cli-toolkit 0.72.0 → 0.75.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/cli-runner.cjs +243 -4
- package/dist/cli-runner.cjs.map +1 -1
- package/dist/cli-runner.js +243 -4
- package/dist/cli-runner.js.map +1 -1
- package/dist/index.cjs +242 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +238 -3
- package/dist/index.js.map +1 -1
- package/dist/init.cjs +13 -1
- package/dist/init.cjs.map +1 -1
- package/dist/init.js +13 -1
- package/dist/init.js.map +1 -1
- package/dist/tasks.cjs +240 -3
- package/dist/tasks.cjs.map +1 -1
- package/dist/tasks.js +236 -3
- package/dist/tasks.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1348,7 +1348,9 @@ __export(src_exports, {
|
|
|
1348
1348
|
ScrollableText: () => ScrollableText,
|
|
1349
1349
|
TaskGetLogs: () => TaskGetLogs,
|
|
1350
1350
|
TaskPauseRunner: () => TaskPauseRunner,
|
|
1351
|
+
TaskPauseTask: () => TaskPauseTask,
|
|
1351
1352
|
TaskPing: () => TaskPing,
|
|
1353
|
+
TaskResumeTask: () => TaskResumeTask,
|
|
1352
1354
|
TaskSampleProcess: () => TaskSampleProcess,
|
|
1353
1355
|
TaskSetRuntimeParam: () => TaskSetRuntimeParam,
|
|
1354
1356
|
TaskShellCommand: () => TaskShellCommand,
|
|
@@ -1363,6 +1365,8 @@ __export(src_exports, {
|
|
|
1363
1365
|
activateRelease: () => activateRelease,
|
|
1364
1366
|
appendDeployLog: () => appendDeployLog,
|
|
1365
1367
|
appendTaskIpcLog: () => appendTaskIpcLog,
|
|
1368
|
+
applyPauseTask: () => applyPauseTask,
|
|
1369
|
+
applyResumeTask: () => applyResumeTask,
|
|
1366
1370
|
applyRunnerPaused: () => applyRunnerPaused,
|
|
1367
1371
|
applyRuntimeParam: () => applyRuntimeParam,
|
|
1368
1372
|
applyRuntimePatch: () => applyRuntimePatch,
|
|
@@ -5630,6 +5634,7 @@ function setup(opts = {}) {
|
|
|
5630
5634
|
const partialContext = {
|
|
5631
5635
|
emitter: new import_events.EventEmitter(),
|
|
5632
5636
|
isStop: () => false,
|
|
5637
|
+
isKill: () => false,
|
|
5633
5638
|
cleanupFunctions: [],
|
|
5634
5639
|
registerCleanup: (fn) => {
|
|
5635
5640
|
partialContext.cleanupFunctions.push(fn);
|
|
@@ -5651,6 +5656,7 @@ function setup(opts = {}) {
|
|
|
5651
5656
|
logger,
|
|
5652
5657
|
emitter: partialContext.emitter,
|
|
5653
5658
|
isStop: partialContext.isStop,
|
|
5659
|
+
isKill: partialContext.isKill,
|
|
5654
5660
|
cleanupFunctions: partialContext.cleanupFunctions,
|
|
5655
5661
|
registerCleanup: partialContext.registerCleanup,
|
|
5656
5662
|
// For long-running scripts (servers): with --showUsedParams=top, print
|
|
@@ -7864,6 +7870,8 @@ var AbstractTask = class _AbstractTask {
|
|
|
7864
7870
|
constructor(context, task) {
|
|
7865
7871
|
this.context = context;
|
|
7866
7872
|
this.task = task;
|
|
7873
|
+
this._stopRequested = false;
|
|
7874
|
+
this._pauseRequested = false;
|
|
7867
7875
|
}
|
|
7868
7876
|
/**
|
|
7869
7877
|
* Return a short reason string when the task should be deferred (e.g. "locked
|
|
@@ -7881,6 +7889,26 @@ var AbstractTask = class _AbstractTask {
|
|
|
7881
7889
|
* @param {number} [_allowanceMs] Grace period the runner promises before hard exit.
|
|
7882
7890
|
*/
|
|
7883
7891
|
requestStop(_allowanceMs) {
|
|
7892
|
+
this._stopRequested = true;
|
|
7893
|
+
}
|
|
7894
|
+
/**
|
|
7895
|
+
* Cooperative pause signal (from `pauseTask` control-lane task). Long-running
|
|
7896
|
+
* tasks should finish the current unit of work, persist a checkpoint, and
|
|
7897
|
+
* return `{ success: true, results: { taskPaused: true, … } }` so the runner
|
|
7898
|
+
* keeps the row as `status=paused` instead of deleting it.
|
|
7899
|
+
*
|
|
7900
|
+
* @param {number} [_allowanceMs]
|
|
7901
|
+
*/
|
|
7902
|
+
requestPause(_allowanceMs) {
|
|
7903
|
+
this._pauseRequested = true;
|
|
7904
|
+
}
|
|
7905
|
+
/** @returns {boolean} */
|
|
7906
|
+
isStopRequested() {
|
|
7907
|
+
return this._stopRequested === true;
|
|
7908
|
+
}
|
|
7909
|
+
/** @returns {boolean} */
|
|
7910
|
+
isPauseRequested() {
|
|
7911
|
+
return this._pauseRequested === true;
|
|
7884
7912
|
}
|
|
7885
7913
|
/**
|
|
7886
7914
|
* Perform the task. Must be implemented by subclasses.
|
|
@@ -8587,6 +8615,8 @@ var CONTROL_LANE_TASK_NAMES = [
|
|
|
8587
8615
|
"pause",
|
|
8588
8616
|
"unpauseRunner",
|
|
8589
8617
|
"unpause",
|
|
8618
|
+
"pauseTask",
|
|
8619
|
+
"resumeTask",
|
|
8590
8620
|
"setRuntimeParam",
|
|
8591
8621
|
"setRunnerParam"
|
|
8592
8622
|
];
|
|
@@ -8791,6 +8821,190 @@ var TaskUnpauseRunner = class extends AbstractTask {
|
|
|
8791
8821
|
}
|
|
8792
8822
|
};
|
|
8793
8823
|
|
|
8824
|
+
// src/tasks/coreTasks/TaskPauseTask.js
|
|
8825
|
+
function parseProgressObject(progress) {
|
|
8826
|
+
if (progress == null || progress === "") return {};
|
|
8827
|
+
if (typeof progress === "object" && !Array.isArray(progress)) {
|
|
8828
|
+
return { ...progress };
|
|
8829
|
+
}
|
|
8830
|
+
if (typeof progress === "string") {
|
|
8831
|
+
const t = progress.trim();
|
|
8832
|
+
if (t.startsWith("{") || t.startsWith("[")) {
|
|
8833
|
+
try {
|
|
8834
|
+
const parsed = JSON.parse(t);
|
|
8835
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) return { ...parsed };
|
|
8836
|
+
} catch {
|
|
8837
|
+
}
|
|
8838
|
+
}
|
|
8839
|
+
return { message: progress };
|
|
8840
|
+
}
|
|
8841
|
+
return { message: String(progress) };
|
|
8842
|
+
}
|
|
8843
|
+
async function applyPauseTask(context, taskId) {
|
|
8844
|
+
const db = context.db;
|
|
8845
|
+
if (!db) throw new Error("pauseTask: context.db is required");
|
|
8846
|
+
const id = String(taskId ?? "").trim();
|
|
8847
|
+
if (!id) throw new ParamError('pauseTask: param "taskId" is required');
|
|
8848
|
+
const { tasksTable } = queueToTableNames(context.tasksQueueName ?? "tasks");
|
|
8849
|
+
const row = await db(tasksTable).where({ id }).first();
|
|
8850
|
+
if (!row) {
|
|
8851
|
+
return { success: false, results: { error: `Task ${id} not found`, taskId: id } };
|
|
8852
|
+
}
|
|
8853
|
+
if (row.status === "paused") {
|
|
8854
|
+
return {
|
|
8855
|
+
success: true,
|
|
8856
|
+
results: { taskId: id, status: "paused", message: "Task already paused" }
|
|
8857
|
+
};
|
|
8858
|
+
}
|
|
8859
|
+
if (row.status === "idle") {
|
|
8860
|
+
const progress = parseProgressObject(row.progress);
|
|
8861
|
+
progress.pauseRequested = true;
|
|
8862
|
+
progress.pausedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
8863
|
+
await db(tasksTable).where({ id }).update({
|
|
8864
|
+
status: "paused",
|
|
8865
|
+
status_changed_at: db.fn.now(),
|
|
8866
|
+
progress: toJsonColumn(progress)
|
|
8867
|
+
});
|
|
8868
|
+
context.logger?.warn?.(`[pauseTask] idle task ${id} (${row.name}) \u2192 paused`);
|
|
8869
|
+
return {
|
|
8870
|
+
success: true,
|
|
8871
|
+
results: { taskId: id, status: "paused", message: "Idle task paused" }
|
|
8872
|
+
};
|
|
8873
|
+
}
|
|
8874
|
+
if (row.status === "running") {
|
|
8875
|
+
const progress = parseProgressObject(row.progress);
|
|
8876
|
+
progress.pauseRequested = true;
|
|
8877
|
+
progress.pauseRequestedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
8878
|
+
await db(tasksTable).where({ id }).update({
|
|
8879
|
+
progress: toJsonColumn(progress)
|
|
8880
|
+
});
|
|
8881
|
+
const inst = context.runningTaskInstances?.get?.(id);
|
|
8882
|
+
if (inst && typeof inst.requestPause === "function") {
|
|
8883
|
+
await inst.requestPause();
|
|
8884
|
+
context.logger?.warn?.(
|
|
8885
|
+
`[pauseTask] signaled running task ${id} (${row.name}) to pause after current unit`
|
|
8886
|
+
);
|
|
8887
|
+
return {
|
|
8888
|
+
success: true,
|
|
8889
|
+
results: {
|
|
8890
|
+
taskId: id,
|
|
8891
|
+
status: "running",
|
|
8892
|
+
signaled: true,
|
|
8893
|
+
message: "Pause requested; task will finish current unit then park as paused"
|
|
8894
|
+
}
|
|
8895
|
+
};
|
|
8896
|
+
}
|
|
8897
|
+
context.logger?.warn?.(
|
|
8898
|
+
`[pauseTask] stamped pauseRequested on ${id} (${row.name}) \u2014 not running in this process`
|
|
8899
|
+
);
|
|
8900
|
+
return {
|
|
8901
|
+
success: true,
|
|
8902
|
+
results: {
|
|
8903
|
+
taskId: id,
|
|
8904
|
+
status: "running",
|
|
8905
|
+
signaled: false,
|
|
8906
|
+
message: "pauseRequested stamped on task row; target runner must observe it (enqueue pauseTask on that service)"
|
|
8907
|
+
}
|
|
8908
|
+
};
|
|
8909
|
+
}
|
|
8910
|
+
return {
|
|
8911
|
+
success: false,
|
|
8912
|
+
results: {
|
|
8913
|
+
error: `Cannot pause task in status "${row.status}"`,
|
|
8914
|
+
taskId: id,
|
|
8915
|
+
status: row.status
|
|
8916
|
+
}
|
|
8917
|
+
};
|
|
8918
|
+
}
|
|
8919
|
+
async function applyResumeTask(context, taskId) {
|
|
8920
|
+
const db = context.db;
|
|
8921
|
+
if (!db) throw new Error("resumeTask: context.db is required");
|
|
8922
|
+
const id = String(taskId ?? "").trim();
|
|
8923
|
+
if (!id) throw new ParamError('resumeTask: param "taskId" is required');
|
|
8924
|
+
const { tasksTable } = queueToTableNames(context.tasksQueueName ?? "tasks");
|
|
8925
|
+
const row = await db(tasksTable).where({ id }).first();
|
|
8926
|
+
if (!row) {
|
|
8927
|
+
return { success: false, results: { error: `Task ${id} not found`, taskId: id } };
|
|
8928
|
+
}
|
|
8929
|
+
if (row.status === "idle") {
|
|
8930
|
+
return {
|
|
8931
|
+
success: true,
|
|
8932
|
+
results: { taskId: id, status: "idle", message: "Task already idle (runnable)" }
|
|
8933
|
+
};
|
|
8934
|
+
}
|
|
8935
|
+
if (row.status !== "paused") {
|
|
8936
|
+
return {
|
|
8937
|
+
success: false,
|
|
8938
|
+
results: {
|
|
8939
|
+
error: `Cannot resume task in status "${row.status}" (expected paused)`,
|
|
8940
|
+
taskId: id,
|
|
8941
|
+
status: row.status
|
|
8942
|
+
}
|
|
8943
|
+
};
|
|
8944
|
+
}
|
|
8945
|
+
const progress = parseProgressObject(row.progress);
|
|
8946
|
+
delete progress.pauseRequested;
|
|
8947
|
+
delete progress.pauseRequestedAt;
|
|
8948
|
+
delete progress.pausedAt;
|
|
8949
|
+
progress.resumedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
8950
|
+
await db(tasksTable).where({ id }).update({
|
|
8951
|
+
status: "idle",
|
|
8952
|
+
status_changed_at: db.fn.now(),
|
|
8953
|
+
started_at: null,
|
|
8954
|
+
completed_at: null,
|
|
8955
|
+
success: null,
|
|
8956
|
+
progress: toJsonColumn(progress),
|
|
8957
|
+
// Clear claim binding so any matching worker can pick it up.
|
|
8958
|
+
service_name: null,
|
|
8959
|
+
server_name: null,
|
|
8960
|
+
instance_number: null,
|
|
8961
|
+
next_run_at: null
|
|
8962
|
+
});
|
|
8963
|
+
context.logger?.warn?.(`[resumeTask] paused task ${id} (${row.name}) \u2192 idle`);
|
|
8964
|
+
return {
|
|
8965
|
+
success: true,
|
|
8966
|
+
results: { taskId: id, status: "idle", message: "Task resumed (idle; will be claimed)" }
|
|
8967
|
+
};
|
|
8968
|
+
}
|
|
8969
|
+
var TaskPauseTask = class extends AbstractTask {
|
|
8970
|
+
static taskName = "pauseTask";
|
|
8971
|
+
static description = "Pause a specific task: finish current unit, persist status=paused";
|
|
8972
|
+
static defaultWaitForResult = true;
|
|
8973
|
+
static async resolveCustomParams(context, overrides = {}) {
|
|
8974
|
+
const merged = AbstractTask._mergeTypedParams(
|
|
8975
|
+
context,
|
|
8976
|
+
"task-pause-task",
|
|
8977
|
+
{ taskId: "string" },
|
|
8978
|
+
overrides
|
|
8979
|
+
);
|
|
8980
|
+
const taskId = typeof merged.taskId === "string" ? merged.taskId.trim() : "";
|
|
8981
|
+
if (!taskId) throw new ParamError('pauseTask: param "taskId" is required');
|
|
8982
|
+
return { taskId };
|
|
8983
|
+
}
|
|
8984
|
+
async run() {
|
|
8985
|
+
return applyPauseTask(this.context, this.task?.params?.taskId);
|
|
8986
|
+
}
|
|
8987
|
+
};
|
|
8988
|
+
var TaskResumeTask = class extends AbstractTask {
|
|
8989
|
+
static taskName = "resumeTask";
|
|
8990
|
+
static description = "Resume a paused task (status paused \u2192 idle)";
|
|
8991
|
+
static defaultWaitForResult = true;
|
|
8992
|
+
static async resolveCustomParams(context, overrides = {}) {
|
|
8993
|
+
const merged = AbstractTask._mergeTypedParams(
|
|
8994
|
+
context,
|
|
8995
|
+
"task-resume-task",
|
|
8996
|
+
{ taskId: "string" },
|
|
8997
|
+
overrides
|
|
8998
|
+
);
|
|
8999
|
+
const taskId = typeof merged.taskId === "string" ? merged.taskId.trim() : "";
|
|
9000
|
+
if (!taskId) throw new ParamError('resumeTask: param "taskId" is required');
|
|
9001
|
+
return { taskId };
|
|
9002
|
+
}
|
|
9003
|
+
async run() {
|
|
9004
|
+
return applyResumeTask(this.context, this.task?.params?.taskId);
|
|
9005
|
+
}
|
|
9006
|
+
};
|
|
9007
|
+
|
|
8794
9008
|
// src/tasks/coreTasks/TaskGetLogs.js
|
|
8795
9009
|
var TaskGetLogs = class extends AbstractTask {
|
|
8796
9010
|
/**
|
|
@@ -9009,7 +9223,7 @@ var TasksRegistry = class _TasksRegistry {
|
|
|
9009
9223
|
* @returns {TasksRegistry}
|
|
9010
9224
|
*/
|
|
9011
9225
|
static withCoreTasks() {
|
|
9012
|
-
return new _TasksRegistry().add("ping", TaskPing).add("sampleProcess", TaskSampleProcess).add("shellCommand", TaskShellCommand).add("systemInfo", TaskSystemInfo).add("info", TaskSystemInfo).add("taskSumAB", TaskSumAB).add("stopRunner", TaskStopRunner).add("stop", TaskStopRunner).add("pauseRunner", TaskPauseRunner).add("pause", TaskPauseRunner).add("unpauseRunner", TaskUnpauseRunner).add("unpause", TaskUnpauseRunner).add("getLogs", TaskGetLogs).add("setRuntimeParam", TaskSetRuntimeParam).add("setRunnerParam", TaskSetRuntimeParam);
|
|
9226
|
+
return new _TasksRegistry().add("ping", TaskPing).add("sampleProcess", TaskSampleProcess).add("shellCommand", TaskShellCommand).add("systemInfo", TaskSystemInfo).add("info", TaskSystemInfo).add("taskSumAB", TaskSumAB).add("stopRunner", TaskStopRunner).add("stop", TaskStopRunner).add("pauseRunner", TaskPauseRunner).add("pause", TaskPauseRunner).add("unpauseRunner", TaskUnpauseRunner).add("unpause", TaskUnpauseRunner).add("pauseTask", TaskPauseTask).add("resumeTask", TaskResumeTask).add("getLogs", TaskGetLogs).add("setRuntimeParam", TaskSetRuntimeParam).add("setRunnerParam", TaskSetRuntimeParam);
|
|
9013
9227
|
}
|
|
9014
9228
|
/**
|
|
9015
9229
|
* Register a single task class under a name. Overwrites any previous entry.
|
|
@@ -9116,6 +9330,8 @@ var SERVICE_TASK_NAMES = [
|
|
|
9116
9330
|
"pauseRunner",
|
|
9117
9331
|
"unpause",
|
|
9118
9332
|
"unpauseRunner",
|
|
9333
|
+
"pauseTask",
|
|
9334
|
+
"resumeTask",
|
|
9119
9335
|
"shellCommand",
|
|
9120
9336
|
"systemInfo",
|
|
9121
9337
|
"info",
|
|
@@ -9411,11 +9627,12 @@ async function executeClaimedTask(context, tasksTable, historyTable, row, regist
|
|
|
9411
9627
|
} finally {
|
|
9412
9628
|
runningTaskInstances.delete(row.id);
|
|
9413
9629
|
}
|
|
9630
|
+
const taskPaused = success && results && typeof results === "object" && results.taskPaused === true;
|
|
9414
9631
|
await db(historyTable).insert(
|
|
9415
9632
|
taskHistoryInsertFromQueueRow(row, {
|
|
9416
9633
|
completed_at: /* @__PURE__ */ new Date(),
|
|
9417
9634
|
success,
|
|
9418
|
-
status: success ? "completed" : "failed",
|
|
9635
|
+
status: taskPaused ? "paused" : success ? "completed" : "failed",
|
|
9419
9636
|
status_changed_at: db.fn.now(),
|
|
9420
9637
|
params: toJsonColumn(row.params),
|
|
9421
9638
|
results: toJsonColumn(results)
|
|
@@ -9438,7 +9655,24 @@ async function executeClaimedTask(context, tasksTable, historyTable, row, regist
|
|
|
9438
9655
|
details: results
|
|
9439
9656
|
});
|
|
9440
9657
|
}
|
|
9441
|
-
if (
|
|
9658
|
+
if (taskPaused) {
|
|
9659
|
+
const checkpointParams = results.checkpointParams && typeof results.checkpointParams === "object" ? results.checkpointParams : row.params;
|
|
9660
|
+
const progressPayload = results.progress != null ? results.progress : { paused: true, pausedAt: (/* @__PURE__ */ new Date()).toISOString(), message: "paused" };
|
|
9661
|
+
await db(tasksTable).where({ id: row.id }).update({
|
|
9662
|
+
started_at: null,
|
|
9663
|
+
completed_at: /* @__PURE__ */ new Date(),
|
|
9664
|
+
success: true,
|
|
9665
|
+
results: toJsonColumn(results),
|
|
9666
|
+
params: toJsonColumn(checkpointParams),
|
|
9667
|
+
progress: toJsonColumn(progressPayload),
|
|
9668
|
+
status: "paused",
|
|
9669
|
+
status_changed_at: db.fn.now(),
|
|
9670
|
+
past_due: null,
|
|
9671
|
+
service_name: null,
|
|
9672
|
+
server_name: null,
|
|
9673
|
+
instance_number: null
|
|
9674
|
+
});
|
|
9675
|
+
} else if (row.schedule) {
|
|
9442
9676
|
if (success) {
|
|
9443
9677
|
let nextRunAt = null;
|
|
9444
9678
|
try {
|
|
@@ -9566,6 +9800,7 @@ async function runTasksLoop(context, options) {
|
|
|
9566
9800
|
}
|
|
9567
9801
|
const runningPromises = /* @__PURE__ */ new Set();
|
|
9568
9802
|
const runningTaskInstances = /* @__PURE__ */ new Map();
|
|
9803
|
+
context.runningTaskInstances = runningTaskInstances;
|
|
9569
9804
|
let runningControlPromise = null;
|
|
9570
9805
|
let stopRequested = false;
|
|
9571
9806
|
let stopAllowanceMs = Number(context.stopAllowanceMs) > 0 ? Number(context.stopAllowanceMs) : 6e4;
|
|
@@ -9954,7 +10189,9 @@ var TasksManager = class _TasksManager {
|
|
|
9954
10189
|
ScrollableText,
|
|
9955
10190
|
TaskGetLogs,
|
|
9956
10191
|
TaskPauseRunner,
|
|
10192
|
+
TaskPauseTask,
|
|
9957
10193
|
TaskPing,
|
|
10194
|
+
TaskResumeTask,
|
|
9958
10195
|
TaskSampleProcess,
|
|
9959
10196
|
TaskSetRuntimeParam,
|
|
9960
10197
|
TaskShellCommand,
|
|
@@ -9969,6 +10206,8 @@ var TasksManager = class _TasksManager {
|
|
|
9969
10206
|
activateRelease,
|
|
9970
10207
|
appendDeployLog,
|
|
9971
10208
|
appendTaskIpcLog,
|
|
10209
|
+
applyPauseTask,
|
|
10210
|
+
applyResumeTask,
|
|
9972
10211
|
applyRunnerPaused,
|
|
9973
10212
|
applyRuntimeParam,
|
|
9974
10213
|
applyRuntimePatch,
|