opencode-supertask 0.1.24 → 0.1.26

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/README.md CHANGED
@@ -13,7 +13,13 @@ Documentation: [current architecture](docs/architecture.md) · [operations and t
13
13
 
14
14
  ### Quick Install
15
15
 
16
- Add the plugin to `~/.config/opencode/opencode.json`:
16
+ Install the CLI globally:
17
+
18
+ ```bash
19
+ npm install -g opencode-supertask
20
+ ```
21
+
22
+ Then add the plugin to `~/.config/opencode/opencode.json`:
17
23
 
18
24
  ```json
19
25
  {
@@ -36,13 +42,14 @@ The plugin never installs global dependencies by itself. Without a running Gatew
36
42
  2. Remove `"opencode-supertask"` from `~/.config/opencode/opencode.json`
37
43
  3. Restart OpenCode
38
44
 
39
- To clear all task data safely, stop the Gateway and use the backup-first database command:
45
+ To clear all task data safely, use the backup-first database command:
40
46
 
41
47
  ```bash
42
- pm2 stop supertask-gateway
43
48
  supertask db clear --confirm CLEAR
44
49
  ```
45
50
 
51
+ If the matching Gateway is managed by PM2, the CLI stops it first and restarts it after maintenance.
52
+
46
53
  ### CLI Install / Uninstall
47
54
 
48
55
  ```bash
@@ -114,11 +121,18 @@ supertask template enable --id 1
114
121
  # Database maintenance
115
122
  supertask db check
116
123
  supertask db backup [--output /path/to/tasks-backup.db]
117
- supertask db clear --confirm CLEAR
118
- supertask db restore --from /path/to/tasks-backup.db --confirm RESTORE
124
+ supertask db clear --confirm CLEAR [--keep-stopped]
125
+ supertask db restore --from /path/to/tasks-backup.db --confirm RESTORE [--keep-stopped]
119
126
  ```
120
127
 
121
- `db backup` creates and validates a standalone SQLite snapshot. `db clear` and `db restore` refuse to run while another Gateway or task is active; both create a safety backup before changing data. Stop the PM2 Gateway before using the destructive CLI commands.
128
+ `db backup` creates and validates a standalone SQLite snapshot. For `db clear` and `db restore`, the CLI automatically stops a PM2 Gateway whose PID matches the current database's fresh ready lock, then restores its previous running state. Both commands create a safety backup before changing data and still refuse active tasks or an unverified/foreground Gateway. Use `--keep-stopped` to leave a previously running PM2 Gateway stopped.
129
+
130
+ All four `db` commands print a concise human-readable summary when stdout is an interactive terminal. Pipes, command substitution, and other non-interactive callers continue to receive JSON; pass `--json` to force JSON in a terminal:
131
+
132
+ ```bash
133
+ supertask db check --json
134
+ supertask db check | jq '.counts'
135
+ ```
122
136
 
123
137
  ### Duration Format
124
138
 
@@ -214,7 +228,13 @@ SuperTask 是一个基于 SQLite 的 AI Agent 任务调度系统,专为 [OpenC
214
228
 
215
229
  ### 安装
216
230
 
217
- `~/.config/opencode/opencode.json` 中添加:
231
+ 先安装全局 CLI:
232
+
233
+ ```bash
234
+ npm install -g opencode-supertask
235
+ ```
236
+
237
+ 然后在 `~/.config/opencode/opencode.json` 中添加:
218
238
 
219
239
  ```json
220
240
  {
@@ -240,10 +260,11 @@ supertask gateway # 前台运行:不需要 pm2
240
260
  安全清理所有任务数据:
241
261
 
242
262
  ```bash
243
- pm2 stop supertask-gateway
244
263
  supertask db clear --confirm CLEAR
245
264
  ```
246
265
 
266
+ 若当前数据库对应的 Gateway 由 PM2 管理,CLI 会自动停止并在维护结束后恢复运行。
267
+
247
268
  ### 定时任务
248
269
 
249
270
  支持友好的时间格式:
@@ -274,11 +295,18 @@ supertask template add --type cron --cron "0 9 * * *" ...
274
295
  ```bash
275
296
  supertask db check
276
297
  supertask db backup [--output /path/to/tasks-backup.db]
277
- supertask db clear --confirm CLEAR
278
- supertask db restore --from /path/to/tasks-backup.db --confirm RESTORE
298
+ supertask db clear --confirm CLEAR [--keep-stopped]
299
+ supertask db restore --from /path/to/tasks-backup.db --confirm RESTORE [--keep-stopped]
279
300
  ```
280
301
 
281
- `db backup` 会生成并校验可独立恢复的 SQLite 快照。CLI 清空和恢复会拒绝活跃 Gateway 或运行中任务,并在修改数据前自动保留安全备份;执行这两个危险命令前应先停止 PM2 Gateway
302
+ `db backup` 会生成并校验可独立恢复的 SQLite 快照。CLI 清空和恢复会先确认 PM2 PID 与当前数据库的新鲜 ready 锁一致,再自动停止并按原状态重启 Gateway;操作失败时也会尝试恢复 Gateway。它们仍会拒绝运行中任务、前台 Gateway 或无法确认归属的进程,并在修改数据前自动保留安全备份。传入 `--keep-stopped` 可让原本运行的 PM2 Gateway 保持停止。
303
+
304
+ 四个 `db` 命令在交互式终端默认输出简洁的人类可读摘要;管道、命令替换和其他非交互调用继续得到 JSON。终端内需要 JSON 时传入 `--json`:
305
+
306
+ ```bash
307
+ supertask db check --json
308
+ supertask db check | jq '.counts'
309
+ ```
282
310
 
283
311
  ### 数据位置
284
312
 
package/dist/cli/index.js CHANGED
@@ -19562,7 +19562,7 @@ var init_database_maintenance_service = __esm({
19562
19562
  if (!lock || !isProcessAlive(lock.pid)) return;
19563
19563
  if (allowCurrentGateway && lock.pid === process.pid) return;
19564
19564
  throw new DatabaseMaintenanceConflictError(
19565
- `Gateway PID ${lock.pid} \u4ECD\u5728\u8FD0\u884C\uFF0C\u8BF7\u5148\u6267\u884C pm2 stop supertask-gateway`
19565
+ `Gateway PID ${lock.pid} \u4ECD\u5728\u8FD0\u884C\uFF0C\u4F46\u672A\u786E\u8BA4\u7531\u5F53\u524D\u6570\u636E\u5E93\u5BF9\u5E94\u7684 PM2 \u8FDB\u7A0B\u7BA1\u7406\uFF1B\u8BF7\u5148\u505C\u6B62\u8BE5 Gateway\uFF08PM2 \u53EF\u6267\u884C pm2 stop supertask-gateway\uFF09`
19566
19566
  );
19567
19567
  }
19568
19568
  static assertNoRunningWork(sqlite2) {
@@ -19718,6 +19718,8 @@ __export(pm2_exports, {
19718
19718
  isGatewayRunning: () => isGatewayRunning,
19719
19719
  isPm2Installed: () => isPm2Installed,
19720
19720
  resolveGatewayEntry: () => resolveGatewayEntry,
19721
+ restartGatewayAfterMaintenance: () => restartGatewayAfterMaintenance,
19722
+ stopGatewayForMaintenance: () => stopGatewayForMaintenance,
19721
19723
  uninstall: () => uninstall,
19722
19724
  upgrade: () => upgrade
19723
19725
  });
@@ -19937,6 +19939,28 @@ function waitForGatewayReady(pid) {
19937
19939
  }
19938
19940
  return isGatewayReady(pid);
19939
19941
  }
19942
+ function stopGatewayForMaintenance() {
19943
+ if (!isPm2Installed()) return { wasRunning: false };
19944
+ const proc = pm2JsonList().find((item) => item.name === PROCESS_NAME);
19945
+ const managedCurrentDatabase = proc?.pm2_env?.status === "online" && typeof proc.pid === "number" && isGatewayReady(proc.pid);
19946
+ if (!managedCurrentDatabase) return { wasRunning: false };
19947
+ requirePm2(["stop", PROCESS_NAME], "pm2 stop Gateway for database maintenance");
19948
+ return { wasRunning: true };
19949
+ }
19950
+ function restartGatewayAfterMaintenance(state2) {
19951
+ if (!state2.wasRunning) return false;
19952
+ requirePm2(["start", PROCESS_NAME], "pm2 restart Gateway after database maintenance");
19953
+ const started = pm2JsonList().find((item) => item.name === PROCESS_NAME);
19954
+ if (started?.pm2_env?.status !== "online") {
19955
+ throw new Error(
19956
+ `[supertask] Gateway \u6570\u636E\u5E93\u7EF4\u62A4\u540E\u672A\u6062\u590D online\uFF08\u72B6\u6001\uFF1A${started?.pm2_env?.status ?? "missing"}\uFF09`
19957
+ );
19958
+ }
19959
+ if (typeof started.pid !== "number" || !waitForGatewayReady(started.pid)) {
19960
+ throw new Error("[supertask] Gateway \u6570\u636E\u5E93\u7EF4\u62A4\u540E\u5DF2 online\uFF0C\u4F46\u672A\u5728\u9650\u5B9A\u65F6\u95F4\u5185\u5C31\u7EEA\uFF1B\u8BF7\u67E5\u770B pm2 logs supertask-gateway");
19961
+ }
19962
+ return true;
19963
+ }
19940
19964
  function findBunPath() {
19941
19965
  const override = process.env.SUPERTASK_BUN_BIN;
19942
19966
  if (override) return override;
@@ -24273,17 +24297,151 @@ function parseDuration(input) {
24273
24297
 
24274
24298
  // src/cli/index.ts
24275
24299
  init_pm2();
24276
- async function withDb(fn) {
24300
+
24301
+ // src/cli/database-output.ts
24302
+ function useJson(options) {
24303
+ const isTTY = options.isTTY ?? process.stdout.isTTY === true;
24304
+ return options.forceJson === true || !isTTY;
24305
+ }
24306
+ function formatBytes(bytes) {
24307
+ const units = ["B", "KiB", "MiB", "GiB"];
24308
+ let value = bytes;
24309
+ let unit = 0;
24310
+ while (value >= 1024 && unit < units.length - 1) {
24311
+ value /= 1024;
24312
+ unit += 1;
24313
+ }
24314
+ const rendered = Number.isInteger(value) ? String(value) : value.toFixed(1);
24315
+ return `${rendered} ${units[unit]}`;
24316
+ }
24317
+ function formatCounts(counts) {
24318
+ return `\u4EFB\u52A1 ${counts.tasks} \xB7 \u6267\u884C\u8BB0\u5F55 ${counts.taskRuns} \xB7 \u8C03\u5EA6\u6A21\u677F ${counts.taskTemplates}`;
24319
+ }
24320
+ function formatGateway(gateway) {
24321
+ if (gateway.restarted) return "\u5DF2\u81EA\u52A8\u505C\u6B62\u3001\u91CD\u542F\u5E76\u6062\u590D\u5C31\u7EEA";
24322
+ if (gateway.keptStopped) return "\u5DF2\u81EA\u52A8\u505C\u6B62\uFF0C\u6309\u8981\u6C42\u4FDD\u6301\u505C\u6B62";
24323
+ if (!gateway.wasRunning) return "\u65E0\u9700\u81EA\u52A8\u505C\u542F\uFF08\u672A\u53D1\u73B0\u5339\u914D\u5F53\u524D\u6570\u636E\u5E93\u7684 PM2 Gateway\uFF09";
24324
+ return "\u539F Gateway \u672A\u6062\u590D\u8FD0\u884C";
24325
+ }
24326
+ function formatCheck(result) {
24327
+ const lines = [
24328
+ result.ok ? "\u2713 \u6570\u636E\u5E93\u68C0\u67E5\u901A\u8FC7" : "\u2717 \u6570\u636E\u5E93\u68C0\u67E5\u672A\u901A\u8FC7",
24329
+ "",
24330
+ `\u6570\u636E\u5E93\uFF1A${result.path}`,
24331
+ `\u5927\u5C0F\uFF1A${formatBytes(result.sizeBytes)}`,
24332
+ `\u65E5\u5FD7\u6A21\u5F0F\uFF1A${result.journalMode}`,
24333
+ `\u6570\u636E\u7EDF\u8BA1\uFF1A${formatCounts(result.counts)}`,
24334
+ `\u8FD0\u884C\u4E2D\uFF1A\u4EFB\u52A1 ${result.runningTasks} \xB7 \u6267\u884C\u8BB0\u5F55 ${result.runningRuns}`
24335
+ ];
24336
+ if (!result.ok) {
24337
+ lines.push(
24338
+ `\u5B8C\u6574\u6027\uFF1A${result.integrityMessages.join("\uFF1B") || "\u65E0\u7ED3\u679C"}`,
24339
+ `\u5916\u952E\u8FDD\u89C4\uFF1A${result.foreignKeyViolations}`,
24340
+ `\u7F3A\u5931\u8868\uFF1A${result.missingTables.join("\u3001") || "\u65E0"}`
24341
+ );
24342
+ }
24343
+ return lines.join("\n");
24344
+ }
24345
+ function formatHuman(operation, result) {
24346
+ switch (operation) {
24347
+ case "check":
24348
+ return formatCheck(result);
24349
+ case "backup": {
24350
+ const backup = result;
24351
+ return [
24352
+ "\u2713 \u6570\u636E\u5E93\u5907\u4EFD\u5B8C\u6210",
24353
+ "",
24354
+ `\u5907\u4EFD\u6587\u4EF6\uFF1A${backup.path}`,
24355
+ `\u5927\u5C0F\uFF1A${formatBytes(backup.sizeBytes)}`,
24356
+ `\u6570\u636E\u7EDF\u8BA1\uFF1A${formatCounts(backup.check.counts)}`,
24357
+ `\u6570\u636E\u5E93\u5B8C\u6574\u6027\uFF1A${backup.check.ok ? "\u901A\u8FC7" : "\u672A\u901A\u8FC7"}`
24358
+ ].join("\n");
24359
+ }
24360
+ case "clear": {
24361
+ const cleared = result;
24362
+ return [
24363
+ "\u2713 \u6570\u636E\u5E93\u5DF2\u5B89\u5168\u6E05\u7A7A",
24364
+ "",
24365
+ `\u5DF2\u5220\u9664\uFF1A${formatCounts(cleared.deleted)}`,
24366
+ `\u5B89\u5168\u5907\u4EFD\uFF1A${cleared.backupPath}`,
24367
+ `Gateway\uFF1A${formatGateway(cleared.gateway)}`,
24368
+ `\u6570\u636E\u5E93\u5B8C\u6574\u6027\uFF1A${cleared.check.ok ? "\u901A\u8FC7" : "\u672A\u901A\u8FC7"}`
24369
+ ].join("\n");
24370
+ }
24371
+ case "restore": {
24372
+ const restored = result;
24373
+ return [
24374
+ "\u2713 \u6570\u636E\u5E93\u6062\u590D\u5B8C\u6210",
24375
+ "",
24376
+ `\u6062\u590D\u6765\u6E90\uFF1A${restored.sourcePath}`,
24377
+ `\u6062\u590D\u524D\u5B89\u5168\u5907\u4EFD\uFF1A${restored.safetyBackupPath}`,
24378
+ `\u8FD0\u884C\u6001\u6536\u655B\uFF1A\u4EFB\u52A1 ${restored.recoveredRunningTasks} \xB7 \u6267\u884C\u8BB0\u5F55 ${restored.closedRunningRuns}`,
24379
+ `\u6570\u636E\u7EDF\u8BA1\uFF1A${formatCounts(restored.check.counts)}`,
24380
+ `Gateway\uFF1A${formatGateway(restored.gateway)}`,
24381
+ `\u6570\u636E\u5E93\u5B8C\u6574\u6027\uFF1A${restored.check.ok ? "\u901A\u8FC7" : "\u672A\u901A\u8FC7"}`
24382
+ ].join("\n");
24383
+ }
24384
+ }
24385
+ }
24386
+ function renderDatabaseResult(operation, result, options = {}) {
24387
+ return useJson(options) ? JSON.stringify(result, null, 2) : formatHuman(operation, result);
24388
+ }
24389
+ function renderDatabaseError(error, options = {}) {
24390
+ const message = error instanceof Error ? error.message : String(error);
24391
+ return useJson(options) ? JSON.stringify({ error: message }) : `\u2717 ${message}`;
24392
+ }
24393
+
24394
+ // src/cli/index.ts
24395
+ async function withDb(fn, formatError = (error) => JSON.stringify({
24396
+ error: error instanceof Error ? error.message : String(error)
24397
+ })) {
24277
24398
  try {
24278
24399
  return await fn();
24279
24400
  } catch (error) {
24280
- console.error(JSON.stringify({ error: error instanceof Error ? error.message : String(error) }));
24401
+ console.error(formatError(error));
24281
24402
  closeDb();
24282
24403
  process.exit(1);
24283
24404
  } finally {
24284
24405
  closeDb();
24285
24406
  }
24286
24407
  }
24408
+ function messageOf(error) {
24409
+ return error instanceof Error ? error.message : String(error);
24410
+ }
24411
+ function runDestructiveDatabaseMaintenance(keepStopped, operation) {
24412
+ const gatewayState = stopGatewayForMaintenance();
24413
+ let result;
24414
+ try {
24415
+ result = operation();
24416
+ } catch (error) {
24417
+ if (gatewayState.wasRunning && !keepStopped) {
24418
+ try {
24419
+ restartGatewayAfterMaintenance(gatewayState);
24420
+ } catch (restartError) {
24421
+ throw new Error(
24422
+ `${messageOf(error)}\uFF1BGateway \u81EA\u52A8\u6062\u590D\u4E5F\u5931\u8D25\uFF1A${messageOf(restartError)}`
24423
+ );
24424
+ }
24425
+ }
24426
+ throw error;
24427
+ }
24428
+ let restarted = false;
24429
+ if (gatewayState.wasRunning && !keepStopped) {
24430
+ try {
24431
+ restarted = restartGatewayAfterMaintenance(gatewayState);
24432
+ } catch (error) {
24433
+ throw new Error(`\u6570\u636E\u5E93\u7EF4\u62A4\u5DF2\u5B8C\u6210\uFF0C\u4F46 Gateway \u81EA\u52A8\u91CD\u542F\u5931\u8D25\uFF1A${messageOf(error)}`);
24434
+ }
24435
+ }
24436
+ return {
24437
+ ...result,
24438
+ gateway: {
24439
+ wasRunning: gatewayState.wasRunning,
24440
+ restarted,
24441
+ keptStopped: gatewayState.wasRunning && keepStopped
24442
+ }
24443
+ };
24444
+ }
24287
24445
  var program2 = new Command();
24288
24446
  program2.name("supertask").description("\u901A\u7528\u4EFB\u52A1\u7BA1\u7406\u7CFB\u7EDF - AI Agent \u4EFB\u52A1\u8C03\u5EA6\u5668").version(getPackageVersion());
24289
24447
  program2.command("add").description("\u521B\u5EFA\u65B0\u4EFB\u52A1").requiredOption("-n, --name <name>", "\u4EFB\u52A1\u540D\u79F0").requiredOption("-a, --agent <agent>", "\u4E3B Agent \u540D\u79F0").requiredOption("-p, --prompt <prompt>", "\u63D0\u793A\u8BCD").option("-m, --model <model>", "\u6A21\u578B").option("-c, --category <category>", "\u5206\u7C7B", "general").option("-i, --importance <number>", "\u91CD\u8981\u7A0B\u5EA6 (1-5)", "3").option("-u, --urgency <number>", "\u7D27\u6025\u7A0B\u5EA6 (1-5)", "3").option("-b, --batch <batchId>", "\u6279\u6B21 ID").option("-d, --depends <taskId>", "\u4F9D\u8D56\u7684\u4EFB\u52A1 ID").option("--max-retries <number>", "\u9996\u6B21\u6267\u884C\u4E4B\u5916\u5141\u8BB8\u7684\u91CD\u8BD5\u6B21\u6570", "3").option("--retry-backoff <duration>", "\u91CD\u8BD5\u9000\u907F\u57FA\u7840\u95F4\u9694\uFF0C\u5982 30s / 5min", "30s").option("--timeout <duration>", "\u4EFB\u52A1\u786C\u8D85\u65F6\uFF0C\u5982 30min / 2h").option("-w, --cwd <path>", "(\u5DF2\u5E9F\u5F03) \u5DE5\u4F5C\u76EE\u5F55\u3002\u7CFB\u7EDF\u4F1A\u81EA\u52A8\u8BB0\u5F55\u63D0\u4EA4\u4EFB\u52A1\u65F6\u7684\u5F53\u524D\u76EE\u5F55").action(async (options) => withDb(async () => {
@@ -24489,24 +24647,34 @@ program2.command("template").description("\u7BA1\u7406\u4EFB\u52A1\u8C03\u5EA6\u
24489
24647
  }))
24490
24648
  );
24491
24649
  var databaseCommand = new Command("db").description("\u6570\u636E\u5E93\u68C0\u67E5\u3001\u5907\u4EFD\u3001\u6E05\u7A7A\u4E0E\u6062\u590D");
24492
- databaseCommand.command("check").description("\u68C0\u67E5\u6570\u636E\u5E93\u5B8C\u6574\u6027\u3001\u5916\u952E\u548C\u4E1A\u52A1\u8868\u7EDF\u8BA1").action(async () => withDb(async () => {
24493
- console.log(JSON.stringify(DatabaseMaintenanceService.check(), null, 2));
24494
- }));
24495
- databaseCommand.command("backup").description("\u521B\u5EFA\u7ECF\u8FC7\u5B8C\u6574\u6027\u6821\u9A8C\u7684\u4E00\u81F4\u6027\u5907\u4EFD").option("-o, --output <path>", "\u5907\u4EFD\u6587\u4EF6\u8DEF\u5F84\uFF08\u9ED8\u8BA4\u5199\u5165\u6570\u636E\u5E93\u76EE\u5F55\uFF09").action(async (options) => withDb(async () => {
24496
- console.log(JSON.stringify(DatabaseMaintenanceService.backup(options.output), null, 2));
24497
- }));
24498
- databaseCommand.command("clear").description("\u5907\u4EFD\u540E\u4E8B\u52A1\u6027\u6E05\u7A7A\u4EFB\u52A1\u3001\u6267\u884C\u8BB0\u5F55\u548C\u8C03\u5EA6\u6A21\u677F").option("--confirm <word>", "\u5371\u9669\u64CD\u4F5C\u786E\u8BA4\uFF0C\u5FC5\u987B\u586B\u5199 CLEAR").action(async (options) => withDb(async () => {
24650
+ databaseCommand.command("check").description("\u68C0\u67E5\u6570\u636E\u5E93\u5B8C\u6574\u6027\u3001\u5916\u952E\u548C\u4E1A\u52A1\u8868\u7EDF\u8BA1").option("--json", "\u5F3A\u5236\u8F93\u51FA JSON\uFF08\u975E\u4EA4\u4E92\u8C03\u7528\u9ED8\u8BA4\u5DF2\u8F93\u51FA JSON\uFF09").action(async (options) => withDb(async () => {
24651
+ const result = DatabaseMaintenanceService.check();
24652
+ console.log(renderDatabaseResult("check", result, { forceJson: options.json }));
24653
+ }, (error) => renderDatabaseError(error, { forceJson: options.json })));
24654
+ databaseCommand.command("backup").description("\u521B\u5EFA\u7ECF\u8FC7\u5B8C\u6574\u6027\u6821\u9A8C\u7684\u4E00\u81F4\u6027\u5907\u4EFD").option("-o, --output <path>", "\u5907\u4EFD\u6587\u4EF6\u8DEF\u5F84\uFF08\u9ED8\u8BA4\u5199\u5165\u6570\u636E\u5E93\u76EE\u5F55\uFF09").option("--json", "\u5F3A\u5236\u8F93\u51FA JSON\uFF08\u975E\u4EA4\u4E92\u8C03\u7528\u9ED8\u8BA4\u5DF2\u8F93\u51FA JSON\uFF09").action(async (options) => withDb(async () => {
24655
+ const result = DatabaseMaintenanceService.backup(options.output);
24656
+ console.log(renderDatabaseResult("backup", result, { forceJson: options.json }));
24657
+ }, (error) => renderDatabaseError(error, { forceJson: options.json })));
24658
+ databaseCommand.command("clear").description("\u5907\u4EFD\u540E\u4E8B\u52A1\u6027\u6E05\u7A7A\u4EFB\u52A1\u3001\u6267\u884C\u8BB0\u5F55\u548C\u8C03\u5EA6\u6A21\u677F").option("--confirm <word>", "\u5371\u9669\u64CD\u4F5C\u786E\u8BA4\uFF0C\u5FC5\u987B\u586B\u5199 CLEAR").option("--keep-stopped", "\u7EF4\u62A4\u7ED3\u675F\u540E\u4E0D\u91CD\u542F\u539F\u672C\u7531 PM2 \u7BA1\u7406\u7684 Gateway").option("--json", "\u5F3A\u5236\u8F93\u51FA JSON\uFF08\u975E\u4EA4\u4E92\u8C03\u7528\u9ED8\u8BA4\u5DF2\u8F93\u51FA JSON\uFF09").action(async (options) => withDb(async () => {
24499
24659
  if (options.confirm !== "CLEAR") {
24500
24660
  throw new Error("\u6E05\u7A7A\u6570\u636E\u5E93\u5FC5\u987B\u663E\u5F0F\u4F20\u5165 --confirm CLEAR");
24501
24661
  }
24502
- console.log(JSON.stringify(DatabaseMaintenanceService.clear(), null, 2));
24503
- }));
24504
- databaseCommand.command("restore").description("\u81EA\u52A8\u5907\u4EFD\u5F53\u524D\u5E93\u540E\uFF0C\u4ECE\u6307\u5B9A\u5907\u4EFD\u6062\u590D\u6570\u636E\u5E93").requiredOption("--from <path>", "\u8981\u6062\u590D\u7684 SQLite \u5907\u4EFD\u6587\u4EF6").option("--confirm <word>", "\u5371\u9669\u64CD\u4F5C\u786E\u8BA4\uFF0C\u5FC5\u987B\u586B\u5199 RESTORE").action(async (options) => withDb(async () => {
24662
+ const result = runDestructiveDatabaseMaintenance(
24663
+ options.keepStopped ?? false,
24664
+ () => DatabaseMaintenanceService.clear()
24665
+ );
24666
+ console.log(renderDatabaseResult("clear", result, { forceJson: options.json }));
24667
+ }, (error) => renderDatabaseError(error, { forceJson: options.json })));
24668
+ databaseCommand.command("restore").description("\u81EA\u52A8\u5907\u4EFD\u5F53\u524D\u5E93\u540E\uFF0C\u4ECE\u6307\u5B9A\u5907\u4EFD\u6062\u590D\u6570\u636E\u5E93").requiredOption("--from <path>", "\u8981\u6062\u590D\u7684 SQLite \u5907\u4EFD\u6587\u4EF6").option("--confirm <word>", "\u5371\u9669\u64CD\u4F5C\u786E\u8BA4\uFF0C\u5FC5\u987B\u586B\u5199 RESTORE").option("--keep-stopped", "\u7EF4\u62A4\u7ED3\u675F\u540E\u4E0D\u91CD\u542F\u539F\u672C\u7531 PM2 \u7BA1\u7406\u7684 Gateway").option("--json", "\u5F3A\u5236\u8F93\u51FA JSON\uFF08\u975E\u4EA4\u4E92\u8C03\u7528\u9ED8\u8BA4\u5DF2\u8F93\u51FA JSON\uFF09").action(async (options) => withDb(async () => {
24505
24669
  if (options.confirm !== "RESTORE") {
24506
24670
  throw new Error("\u6062\u590D\u6570\u636E\u5E93\u5FC5\u987B\u663E\u5F0F\u4F20\u5165 --confirm RESTORE");
24507
24671
  }
24508
- console.log(JSON.stringify(DatabaseMaintenanceService.restore(options.from), null, 2));
24509
- }));
24672
+ const result = runDestructiveDatabaseMaintenance(
24673
+ options.keepStopped ?? false,
24674
+ () => DatabaseMaintenanceService.restore(options.from)
24675
+ );
24676
+ console.log(renderDatabaseResult("restore", result, { forceJson: options.json }));
24677
+ }, (error) => renderDatabaseError(error, { forceJson: options.json })));
24510
24678
  program2.addCommand(databaseCommand);
24511
24679
  program2.command("init").description("Initialize SuperTask (create config + run migrations)").action(async () => withDb(async () => {
24512
24680
  const { existsSync: existsSync7, mkdirSync: mkdirSync5, writeFileSync: writeFileSync4 } = await import("fs");