opencode-supertask 0.1.25 → 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
@@ -127,6 +127,13 @@ supertask db restore --from /path/to/tasks-backup.db --confirm RESTORE [--keep-s
127
127
 
128
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
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
+ ```
136
+
130
137
  ### Duration Format
131
138
 
132
139
  Schedule supports friendly duration strings:
@@ -294,6 +301,13 @@ supertask db restore --from /path/to/tasks-backup.db --confirm RESTORE [--keep-s
294
301
 
295
302
  `db backup` 会生成并校验可独立恢复的 SQLite 快照。CLI 清空和恢复会先确认 PM2 PID 与当前数据库的新鲜 ready 锁一致,再自动停止并按原状态重启 Gateway;操作失败时也会尝试恢复 Gateway。它们仍会拒绝运行中任务、前台 Gateway 或无法确认归属的进程,并在修改数据前自动保留安全备份。传入 `--keep-stopped` 可让原本运行的 PM2 Gateway 保持停止。
296
303
 
304
+ 四个 `db` 命令在交互式终端默认输出简洁的人类可读摘要;管道、命令替换和其他非交互调用继续得到 JSON。终端内需要 JSON 时传入 `--json`:
305
+
306
+ ```bash
307
+ supertask db check --json
308
+ supertask db check | jq '.counts'
309
+ ```
310
+
297
311
  ### 数据位置
298
312
 
299
313
  - 数据库:`~/.local/share/opencode/tasks.db`
package/dist/cli/index.js CHANGED
@@ -24297,11 +24297,108 @@ function parseDuration(input) {
24297
24297
 
24298
24298
  // src/cli/index.ts
24299
24299
  init_pm2();
24300
- 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
+ })) {
24301
24398
  try {
24302
24399
  return await fn();
24303
24400
  } catch (error) {
24304
- console.error(JSON.stringify({ error: error instanceof Error ? error.message : String(error) }));
24401
+ console.error(formatError(error));
24305
24402
  closeDb();
24306
24403
  process.exit(1);
24307
24404
  } finally {
@@ -24550,13 +24647,15 @@ program2.command("template").description("\u7BA1\u7406\u4EFB\u52A1\u8C03\u5EA6\u
24550
24647
  }))
24551
24648
  );
24552
24649
  var databaseCommand = new Command("db").description("\u6570\u636E\u5E93\u68C0\u67E5\u3001\u5907\u4EFD\u3001\u6E05\u7A7A\u4E0E\u6062\u590D");
24553
- 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 () => {
24554
- console.log(JSON.stringify(DatabaseMaintenanceService.check(), null, 2));
24555
- }));
24556
- 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 () => {
24557
- console.log(JSON.stringify(DatabaseMaintenanceService.backup(options.output), null, 2));
24558
- }));
24559
- 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").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 () => {
24560
24659
  if (options.confirm !== "CLEAR") {
24561
24660
  throw new Error("\u6E05\u7A7A\u6570\u636E\u5E93\u5FC5\u987B\u663E\u5F0F\u4F20\u5165 --confirm CLEAR");
24562
24661
  }
@@ -24564,9 +24663,9 @@ databaseCommand.command("clear").description("\u5907\u4EFD\u540E\u4E8B\u52A1\u60
24564
24663
  options.keepStopped ?? false,
24565
24664
  () => DatabaseMaintenanceService.clear()
24566
24665
  );
24567
- console.log(JSON.stringify(result, null, 2));
24568
- }));
24569
- 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").action(async (options) => withDb(async () => {
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 () => {
24570
24669
  if (options.confirm !== "RESTORE") {
24571
24670
  throw new Error("\u6062\u590D\u6570\u636E\u5E93\u5FC5\u987B\u663E\u5F0F\u4F20\u5165 --confirm RESTORE");
24572
24671
  }
@@ -24574,8 +24673,8 @@ databaseCommand.command("restore").description("\u81EA\u52A8\u5907\u4EFD\u5F53\u
24574
24673
  options.keepStopped ?? false,
24575
24674
  () => DatabaseMaintenanceService.restore(options.from)
24576
24675
  );
24577
- console.log(JSON.stringify(result, null, 2));
24578
- }));
24676
+ console.log(renderDatabaseResult("restore", result, { forceJson: options.json }));
24677
+ }, (error) => renderDatabaseError(error, { forceJson: options.json })));
24579
24678
  program2.addCommand(databaseCommand);
24580
24679
  program2.command("init").description("Initialize SuperTask (create config + run migrations)").action(async () => withDb(async () => {
24581
24680
  const { existsSync: existsSync7, mkdirSync: mkdirSync5, writeFileSync: writeFileSync4 } = await import("fs");