@icyfenix-dmla/cli 2026.5.24-1015 → 2026.5.24-2045
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/package.json +1 -1
- package/src/commands/data.js +134 -9
- package/src/commands/manage.js +1 -1
- package/src/commands/server.js +1 -1
- package/src/commands/update.js +1 -1
- package/src/index.js +8 -0
- package/src/verbose.js +51 -0
- package/version.json +2 -2
package/package.json
CHANGED
package/src/commands/data.js
CHANGED
|
@@ -8,8 +8,7 @@ const { prompt } = pkg
|
|
|
8
8
|
import fs from 'fs'
|
|
9
9
|
import path from 'path'
|
|
10
10
|
import os from 'os'
|
|
11
|
-
import { spawn } from '
|
|
12
|
-
import { execSync } from 'child_process'
|
|
11
|
+
import { spawn, execSync } from '../verbose.js'
|
|
13
12
|
import AdmZip from 'adm-zip'
|
|
14
13
|
|
|
15
14
|
// 配置文件路径
|
|
@@ -310,10 +309,11 @@ async function showMainMenu(dataPath) {
|
|
|
310
309
|
const choices = [
|
|
311
310
|
{ name: '1', message: '挂载路径设置 ' + chalk.gray(`[当前: ${dataPath}]`) },
|
|
312
311
|
{ name: '2', message: '下载数据集' },
|
|
313
|
-
{ name: '3', message: '
|
|
314
|
-
{ name: '4', message: '
|
|
315
|
-
{ name: '5', message: '
|
|
316
|
-
{ name: '6', message: '
|
|
312
|
+
{ name: '3', message: '删除数据集' },
|
|
313
|
+
{ name: '4', message: '查看数据集列表' },
|
|
314
|
+
{ name: '5', message: '清空数据内容' },
|
|
315
|
+
{ name: '6', message: '删除数据卷' },
|
|
316
|
+
{ name: '7', message: '退出' }
|
|
317
317
|
]
|
|
318
318
|
|
|
319
319
|
const { action } = await prompt({
|
|
@@ -461,6 +461,117 @@ async function removeData() {
|
|
|
461
461
|
console.log(chalk.green('数据卷已删除'))
|
|
462
462
|
}
|
|
463
463
|
|
|
464
|
+
/**
|
|
465
|
+
* 删除数据集子菜单
|
|
466
|
+
*/
|
|
467
|
+
async function deleteDatasets() {
|
|
468
|
+
const dataPath = getDataVolumePath()
|
|
469
|
+
|
|
470
|
+
console.log()
|
|
471
|
+
console.log(chalk.bold('删除数据集'))
|
|
472
|
+
console.log()
|
|
473
|
+
|
|
474
|
+
// 收集已下载(含不完整)的数据集
|
|
475
|
+
const existingDatasets = DATASETS.filter(d => isDatasetExists(dataPath, d.id))
|
|
476
|
+
|
|
477
|
+
if (existingDatasets.length === 0) {
|
|
478
|
+
console.log(chalk.yellow('没有已下载的数据集'))
|
|
479
|
+
return
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// 构建选项列表
|
|
483
|
+
const choices = existingDatasets.map((dataset) => {
|
|
484
|
+
const downloaded = isDatasetDownloaded(dataPath, dataset.id)
|
|
485
|
+
const incomplete = isDatasetIncomplete(dataPath, dataset.id)
|
|
486
|
+
|
|
487
|
+
let message = `${dataset.name} (${dataset.size})`
|
|
488
|
+
if (downloaded) {
|
|
489
|
+
message += ' [可用]'
|
|
490
|
+
} else if (incomplete) {
|
|
491
|
+
message += ' [不完整]'
|
|
492
|
+
} else {
|
|
493
|
+
message += ' [存在]'
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
return {
|
|
497
|
+
name: dataset.id,
|
|
498
|
+
message
|
|
499
|
+
}
|
|
500
|
+
})
|
|
501
|
+
|
|
502
|
+
console.log(chalk.gray('操作: 上下键移动,空格勾选/取消,回车确认,ESC 返回'))
|
|
503
|
+
console.log()
|
|
504
|
+
|
|
505
|
+
try {
|
|
506
|
+
const { selected } = await prompt({
|
|
507
|
+
type: 'multiselect',
|
|
508
|
+
name: 'selected',
|
|
509
|
+
message: '选择要删除的数据集',
|
|
510
|
+
choices,
|
|
511
|
+
hint: '空格选择,回车确认删除',
|
|
512
|
+
styles: {
|
|
513
|
+
primary: chalk.cyan.bold
|
|
514
|
+
}
|
|
515
|
+
})
|
|
516
|
+
|
|
517
|
+
if (!selected || selected.length === 0) {
|
|
518
|
+
console.log(chalk.yellow('未选择任何数据集'))
|
|
519
|
+
return
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
// 确认删除
|
|
523
|
+
const selectedNames = selected.map(id => {
|
|
524
|
+
const ds = existingDatasets.find(d => d.id === id)
|
|
525
|
+
return ds.name
|
|
526
|
+
})
|
|
527
|
+
|
|
528
|
+
console.log()
|
|
529
|
+
console.log(chalk.red(`将删除以下数据集: ${selectedNames.join(', ')}`))
|
|
530
|
+
|
|
531
|
+
const { confirm } = await prompt({
|
|
532
|
+
type: 'confirm',
|
|
533
|
+
name: 'confirm',
|
|
534
|
+
message: '确认删除?',
|
|
535
|
+
initial: false
|
|
536
|
+
})
|
|
537
|
+
|
|
538
|
+
if (!confirm) {
|
|
539
|
+
console.log(chalk.yellow('操作已取消'))
|
|
540
|
+
return
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
// 执行删除
|
|
544
|
+
for (const datasetId of selected) {
|
|
545
|
+
const dataset = DATASETS.find(d => d.id === datasetId)
|
|
546
|
+
const targetDir = path.join(dataPath, dataset.targetDir)
|
|
547
|
+
|
|
548
|
+
if (fs.existsSync(targetDir)) {
|
|
549
|
+
fs.rmSync(targetDir, { recursive: true, force: true })
|
|
550
|
+
console.log(chalk.green(`已删除: ${dataset.name}`))
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
// 更新配置
|
|
554
|
+
const config = readConfig()
|
|
555
|
+
if (config.installedDatasets) {
|
|
556
|
+
config.installedDatasets = config.installedDatasets.filter(id => id !== datasetId)
|
|
557
|
+
}
|
|
558
|
+
if (config.incompleteDatasets) {
|
|
559
|
+
config.incompleteDatasets = config.incompleteDatasets.filter(id => id !== datasetId)
|
|
560
|
+
}
|
|
561
|
+
writeConfig(config)
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
console.log()
|
|
565
|
+
console.log(chalk.green('删除完成'))
|
|
566
|
+
} catch (error) {
|
|
567
|
+
if (isUserCancel(error)) {
|
|
568
|
+
console.log(chalk.gray('返回上一级'))
|
|
569
|
+
return
|
|
570
|
+
}
|
|
571
|
+
throw error
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
|
|
464
575
|
/**
|
|
465
576
|
* 查看数据集列表
|
|
466
577
|
*/
|
|
@@ -1002,9 +1113,20 @@ export async function runDataTUI() {
|
|
|
1002
1113
|
}
|
|
1003
1114
|
break
|
|
1004
1115
|
case 3:
|
|
1005
|
-
|
|
1116
|
+
try {
|
|
1117
|
+
await deleteDatasets()
|
|
1118
|
+
} catch (error) {
|
|
1119
|
+
if (isUserCancel(error)) {
|
|
1120
|
+
console.log(chalk.gray('返回主菜单'))
|
|
1121
|
+
} else {
|
|
1122
|
+
throw error
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1006
1125
|
break
|
|
1007
1126
|
case 4:
|
|
1127
|
+
listDatasets()
|
|
1128
|
+
break
|
|
1129
|
+
case 5:
|
|
1008
1130
|
try {
|
|
1009
1131
|
await clearData()
|
|
1010
1132
|
} catch (error) {
|
|
@@ -1015,7 +1137,7 @@ export async function runDataTUI() {
|
|
|
1015
1137
|
}
|
|
1016
1138
|
}
|
|
1017
1139
|
break
|
|
1018
|
-
case
|
|
1140
|
+
case 6:
|
|
1019
1141
|
try {
|
|
1020
1142
|
await removeData()
|
|
1021
1143
|
} catch (error) {
|
|
@@ -1026,7 +1148,7 @@ export async function runDataTUI() {
|
|
|
1026
1148
|
}
|
|
1027
1149
|
}
|
|
1028
1150
|
break
|
|
1029
|
-
case
|
|
1151
|
+
case 7:
|
|
1030
1152
|
console.log()
|
|
1031
1153
|
console.log(chalk.gray('已退出数据管理'))
|
|
1032
1154
|
console.log()
|
|
@@ -1077,6 +1199,9 @@ export async function runDataCommand(subCommand, options) {
|
|
|
1077
1199
|
case 'download':
|
|
1078
1200
|
await downloadDatasets()
|
|
1079
1201
|
break
|
|
1202
|
+
case 'delete':
|
|
1203
|
+
await deleteDatasets()
|
|
1204
|
+
break
|
|
1080
1205
|
default:
|
|
1081
1206
|
// 无子命令时进入 TUI
|
|
1082
1207
|
await runDataTUI()
|
package/src/commands/manage.js
CHANGED
package/src/commands/server.js
CHANGED
package/src/commands/update.js
CHANGED
package/src/index.js
CHANGED
|
@@ -12,6 +12,7 @@ import { runDoctor } from './commands/manage.js'
|
|
|
12
12
|
import { runDataTUI, runDataCommand } from './commands/data.js'
|
|
13
13
|
import { runImagesTUI } from './commands/images.js'
|
|
14
14
|
import { runUpdate } from './commands/update.js'
|
|
15
|
+
import { setVerbose } from './verbose.js'
|
|
15
16
|
|
|
16
17
|
// 从 package.json 读取版本号
|
|
17
18
|
const __filename = fileURLToPath(import.meta.url)
|
|
@@ -85,6 +86,13 @@ program
|
|
|
85
86
|
.version(VERSION, '-v, --version', '显示版本号')
|
|
86
87
|
.helpOption('-h, --help', '显示帮助信息')
|
|
87
88
|
.addHelpCommand('help [command]', '显示命令帮助信息')
|
|
89
|
+
.option('--verbose', '显示所有执行的外部命令,便于调试')
|
|
90
|
+
|
|
91
|
+
// 解析全局选项(需要在子命令 action 之前解析,以便设置 verbose 开关)
|
|
92
|
+
program.parseOptions(process.argv)
|
|
93
|
+
if (program.opts().verbose) {
|
|
94
|
+
setVerbose(true)
|
|
95
|
+
}
|
|
88
96
|
|
|
89
97
|
// ─────────────────────────────────────────────────────────────
|
|
90
98
|
// start 命令
|
package/src/verbose.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 命令执行封装
|
|
3
|
+
* --verbose 模式下打印所有执行的外部命令,方便调试
|
|
4
|
+
*/
|
|
5
|
+
import { execSync as nodeExecSync, spawn as nodeSpawn } from 'child_process'
|
|
6
|
+
|
|
7
|
+
// 全局 verbose 开关
|
|
8
|
+
let verboseEnabled = false
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 启用/禁用 verbose 模式
|
|
12
|
+
*/
|
|
13
|
+
export function setVerbose(enabled) {
|
|
14
|
+
verboseEnabled = !!enabled
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* 查询 verbose 模式状态
|
|
19
|
+
*/
|
|
20
|
+
export function isVerbose() {
|
|
21
|
+
return verboseEnabled
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 打印 verbose 日志(仅在 verbose 模式下输出)
|
|
26
|
+
*/
|
|
27
|
+
function verboseLog(cmd, args) {
|
|
28
|
+
if (!verboseEnabled) return
|
|
29
|
+
const fullCmd = args && args.length > 0
|
|
30
|
+
? `${cmd} ${args.map(a => `'${a}'`).join(' ')}`
|
|
31
|
+
: cmd
|
|
32
|
+
console.log(`[verbose] $ ${fullCmd}`)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 封装 execSync,verbose 模式下打印命令
|
|
37
|
+
* 参数与原生 execSync 完全一致
|
|
38
|
+
*/
|
|
39
|
+
export function execSync(command, options) {
|
|
40
|
+
verboseLog(command)
|
|
41
|
+
return nodeExecSync(command, options)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* 封装 spawn,verbose 模式下打印命令
|
|
46
|
+
* 参数与原生 spawn 完全一致
|
|
47
|
+
*/
|
|
48
|
+
export function spawn(command, args, options) {
|
|
49
|
+
verboseLog(command, args)
|
|
50
|
+
return nodeSpawn(command, args, options)
|
|
51
|
+
}
|
package/version.json
CHANGED