mioku 1.1.1 → 1.2.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/index.cjs +308 -143
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +308 -143
- package/dist/cli/index.js.map +1 -1
- package/dist/{exec-CoLrq043.cjs → exec-C18L88s9.cjs} +2 -2
- package/dist/{exec-CoLrq043.cjs.map → exec-C18L88s9.cjs.map} +1 -1
- package/dist/{exec-vSS4BZ4z.js → exec-JBR-IZk0.js} +2 -2
- package/dist/{exec-vSS4BZ4z.js.map → exec-JBR-IZk0.js.map} +1 -1
- package/dist/index.cjs +5 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { clearCommandCache, commandExists, resolveCommand, runCommandInherit, version } from "../exec-
|
|
2
|
+
import { clearCommandCache, commandExists, resolveCommand, runCommandInherit, version } from "../exec-JBR-IZk0.js";
|
|
3
3
|
import fs, { readFileSync } from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import mri from "mri";
|
|
@@ -52,6 +52,10 @@ async function searchMiokuPackages(prefix) {
|
|
|
52
52
|
}
|
|
53
53
|
return hits.sort((a, b) => a.name.localeCompare(b.name));
|
|
54
54
|
}
|
|
55
|
+
/** 取官方注册表中某类别需要隐藏的包短名 */
|
|
56
|
+
function hiddenShortNames(registry, type) {
|
|
57
|
+
return new Set(registry?.hidden?.[type] ?? []);
|
|
58
|
+
}
|
|
55
59
|
async function fetchOfficialRegistry() {
|
|
56
60
|
try {
|
|
57
61
|
const res = await fetch(OFFICIAL_REGISTRY_URL, { headers: {
|
|
@@ -126,6 +130,15 @@ async function multiSelect(message, items, initial = [], options = {}) {
|
|
|
126
130
|
});
|
|
127
131
|
return result.map((item) => typeof item === "string" ? item : item.value);
|
|
128
132
|
}
|
|
133
|
+
/** 单选框,取消时抛出(调用方负责兜底) */
|
|
134
|
+
async function selectOne(message, items) {
|
|
135
|
+
const result = await consola.prompt(message, {
|
|
136
|
+
type: "select",
|
|
137
|
+
options: items,
|
|
138
|
+
cancel: "reject"
|
|
139
|
+
});
|
|
140
|
+
return result;
|
|
141
|
+
}
|
|
129
142
|
function runAdapterCli(name, cwd) {
|
|
130
143
|
const isWin = process.platform === "win32";
|
|
131
144
|
const exts = isWin ? [
|
|
@@ -277,11 +290,20 @@ async function getInstalledPackages(cwd) {
|
|
|
277
290
|
...pkg.dependencies,
|
|
278
291
|
...pkg.devDependencies
|
|
279
292
|
};
|
|
280
|
-
return Object.keys(deps).filter((k) => k.startsWith("mioku-"));
|
|
293
|
+
return Object.keys(deps).filter((k) => k === "mioku" || k.startsWith("mioku-"));
|
|
281
294
|
} catch {
|
|
282
295
|
return [];
|
|
283
296
|
}
|
|
284
297
|
}
|
|
298
|
+
/** 读取已安装包的版本,未安装返回 null */
|
|
299
|
+
function installedVersionOf(cwd, pkgName) {
|
|
300
|
+
try {
|
|
301
|
+
const pkg = JSON.parse(readFileSync(path.join(cwd, "node_modules", pkgName, "package.json"), "utf-8"));
|
|
302
|
+
return String(pkg.version || "") || null;
|
|
303
|
+
} catch {
|
|
304
|
+
return null;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
285
307
|
function withRoot(p) {
|
|
286
308
|
return path.resolve(process.cwd(), p);
|
|
287
309
|
}
|
|
@@ -324,11 +346,14 @@ function buildHelpInfo(version$1) {
|
|
|
324
346
|
用法: mioku <命令> [选项]
|
|
325
347
|
|
|
326
348
|
命令:
|
|
327
|
-
install
|
|
328
|
-
|
|
349
|
+
install [类型] [名称] 安装包;不带参数时进入交互选择
|
|
350
|
+
install - 选择安装 mioku 框架 / 插件 / 服务 / 适配器
|
|
351
|
+
install plugin <名称> 安装插件,自动补全 mioku-plugin- 前缀
|
|
352
|
+
install service <名称> 安装服务,自动补全 mioku-service- 前缀
|
|
353
|
+
install adapter <名称> 安装适配器并运行配置向导
|
|
329
354
|
update [包名|self|all] 更新插件或服务
|
|
330
|
-
update -
|
|
331
|
-
update all - 更新所有 mioku
|
|
355
|
+
update - 检查可用更新(含 mioku 框架)并选择更新
|
|
356
|
+
update all - 更新所有 mioku 包(含框架)
|
|
332
357
|
update self - 更新 mioku 框架
|
|
333
358
|
update xxx - 更新指定包
|
|
334
359
|
|
|
@@ -364,118 +389,39 @@ async function input(message, options) {
|
|
|
364
389
|
}
|
|
365
390
|
|
|
366
391
|
//#endregion
|
|
367
|
-
//#region src/cli/
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
return
|
|
381
|
-
}
|
|
382
|
-
const prefix = type === "plugin" ? PLUGIN_PREFIX : SERVICE_PREFIX;
|
|
383
|
-
const normalized = `${prefix}${name}`;
|
|
384
|
-
if (type === "plugin") {
|
|
385
|
-
const proceed = await warnIfPrivatePlugin(normalized);
|
|
386
|
-
if (!proceed) {
|
|
387
|
-
consola.info("已取消安装");
|
|
388
|
-
return 1;
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
try {
|
|
392
|
-
execAdd([normalized], cwd);
|
|
393
|
-
consola.success(`已安装 ${normalized}`);
|
|
394
|
-
if (type === "plugin") {
|
|
395
|
-
const shortName = normalized.slice(PLUGIN_PREFIX.length);
|
|
396
|
-
if (appendToMiokuPlugins(cwd, normalized)) consola.success(`已在 mioku.plugins 中启用 ${shortName}`);
|
|
397
|
-
else consola.info(`${shortName} 已在 mioku.plugins 中,跳过`);
|
|
398
|
-
}
|
|
399
|
-
return 0;
|
|
400
|
-
} catch {
|
|
401
|
-
consola.error(`安装失败: ${normalized}`);
|
|
402
|
-
return 1;
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
async function warnIfPrivatePlugin(pkgName) {
|
|
406
|
-
const keywords = await fetchNpmKeywords(pkgName);
|
|
407
|
-
if (keywords === null) return true;
|
|
408
|
-
if (keywords.includes("mioku")) return true;
|
|
409
|
-
consola.warn(`${pkgName} 看起来是私有插件"`);
|
|
410
|
-
consola.warn("该插件未上架插件市场,可能存在风险");
|
|
411
|
-
return confirm("仍要继续安装吗?", { initial: false });
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
//#endregion
|
|
415
|
-
//#region src/cli/update.ts
|
|
416
|
-
async function updatePackages(packages, cwd) {
|
|
417
|
-
if (packages.length === 0) {
|
|
418
|
-
consola.info("未找到 mioku- 相关依赖");
|
|
419
|
-
return;
|
|
420
|
-
}
|
|
421
|
-
console.log(`执行: bun update ${packages.join(" ")} --latest`);
|
|
422
|
-
run("bun", [
|
|
423
|
-
"update",
|
|
424
|
-
...packages,
|
|
425
|
-
"--latest"
|
|
426
|
-
], { cwd });
|
|
427
|
-
}
|
|
428
|
-
async function updateByPrefix(prefix, cwd, name) {
|
|
429
|
-
if (name) {
|
|
430
|
-
const normalized = name.startsWith(prefix) ? name : `${prefix}${name}`;
|
|
431
|
-
console.log(`执行: bun update ${normalized} --latest`);
|
|
432
|
-
run("bun", [
|
|
433
|
-
"update",
|
|
434
|
-
normalized,
|
|
435
|
-
"--latest"
|
|
436
|
-
], { cwd });
|
|
437
|
-
return;
|
|
438
|
-
}
|
|
439
|
-
const packages = (await getInstalledPackages(cwd)).filter((p) => p.startsWith(prefix));
|
|
440
|
-
if (packages.length === 0) {
|
|
441
|
-
consola.info(`未找到 ${prefix}* 相关依赖`);
|
|
442
|
-
return;
|
|
443
|
-
}
|
|
444
|
-
await updatePackages(packages, cwd);
|
|
445
|
-
}
|
|
446
|
-
async function updateCommand(cmdArgs) {
|
|
447
|
-
ensurePackageManager();
|
|
448
|
-
const cwd = process.cwd();
|
|
449
|
-
const [target, name] = cmdArgs;
|
|
450
|
-
if (!target || target === "check") {
|
|
451
|
-
run("bun", ["update", "-i"], { cwd });
|
|
452
|
-
return 0;
|
|
453
|
-
}
|
|
454
|
-
if (target === "all") {
|
|
455
|
-
await updatePackages(await getInstalledPackages(cwd), cwd);
|
|
456
|
-
return 0;
|
|
457
|
-
}
|
|
458
|
-
if (target === "self") {
|
|
459
|
-
console.log("执行: bun update mioku --latest");
|
|
460
|
-
run("bun", [
|
|
461
|
-
"update",
|
|
462
|
-
"mioku",
|
|
463
|
-
"--latest"
|
|
464
|
-
], { cwd });
|
|
465
|
-
return 0;
|
|
466
|
-
}
|
|
467
|
-
if (target === "plugin" || target === "service") {
|
|
468
|
-
const prefix = target === "plugin" ? PLUGIN_PREFIX : SERVICE_PREFIX;
|
|
469
|
-
await updateByPrefix(prefix, cwd, name);
|
|
470
|
-
return 0;
|
|
392
|
+
//#region src/cli/market-select.ts
|
|
393
|
+
const PACKAGE_TYPE_PREFIX = {
|
|
394
|
+
plugin: PLUGIN_PREFIX,
|
|
395
|
+
service: SERVICE_PREFIX,
|
|
396
|
+
adapter: ADAPTER_PREFIX
|
|
397
|
+
};
|
|
398
|
+
/** 从 npm 拉取市场包并让用户多选;官方注册表 hidden 名单内的包不展示 */
|
|
399
|
+
async function pickMarketPackages(type, message, options = {}) {
|
|
400
|
+
const prefix = PACKAGE_TYPE_PREFIX[type];
|
|
401
|
+
console.log(`\n正在从 npm 拉取 ${prefix}* 包...`);
|
|
402
|
+
const [hits, registry] = await Promise.all([searchMiokuPackages(prefix), fetchOfficialRegistry()]);
|
|
403
|
+
if (hits.length === 0) {
|
|
404
|
+
consola.warn(`未在 npm 上找到任何 ${prefix}* 包`);
|
|
405
|
+
return [];
|
|
471
406
|
}
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
]
|
|
478
|
-
|
|
407
|
+
const official = new Set();
|
|
408
|
+
for (const group of [
|
|
409
|
+
registry?.plugins,
|
|
410
|
+
registry?.services,
|
|
411
|
+
registry?.adapters
|
|
412
|
+
]) for (const entry of Object.values(group ?? {})) if (entry?.npm) official.add(entry.npm);
|
|
413
|
+
const hidden = hiddenShortNames(registry, type);
|
|
414
|
+
const excludeSet = new Set(options.exclude ?? []);
|
|
415
|
+
const items = hits.filter((hit) => !excludeSet.has(hit.name) && !hidden.has(shortNameOfPackage(hit.name))).map((hit) => {
|
|
416
|
+
const shortName = shortNameOfPackage(hit.name);
|
|
417
|
+
const desc = hit.description || "暂无介绍";
|
|
418
|
+
const badge = official.has(hit.name) ? "官方" : "社区";
|
|
419
|
+
return {
|
|
420
|
+
label: `${shortName} (${badge} · ${desc})`,
|
|
421
|
+
value: hit.name
|
|
422
|
+
};
|
|
423
|
+
});
|
|
424
|
+
return multiSelect(message, items, [], { required: false });
|
|
479
425
|
}
|
|
480
426
|
|
|
481
427
|
//#endregion
|
|
@@ -513,30 +459,8 @@ async function createNewProject(name, fileTree) {
|
|
|
513
459
|
run("bun", ["i"], { cwd: projectPath });
|
|
514
460
|
return projectPath;
|
|
515
461
|
}
|
|
516
|
-
async function selectPackages(message,
|
|
517
|
-
|
|
518
|
-
const [hits, registry] = await Promise.all([searchMiokuPackages(prefix), fetchOfficialRegistry()]);
|
|
519
|
-
if (hits.length === 0) {
|
|
520
|
-
consola.warn(`未在 npm 上找到任何 ${prefix}* 包`);
|
|
521
|
-
return [];
|
|
522
|
-
}
|
|
523
|
-
const official = new Set();
|
|
524
|
-
for (const group of [
|
|
525
|
-
registry?.plugins,
|
|
526
|
-
registry?.services,
|
|
527
|
-
registry?.adapters
|
|
528
|
-
]) for (const entry of Object.values(group ?? {})) if (entry?.npm) official.add(entry.npm);
|
|
529
|
-
const excludeSet = new Set(options.exclude ?? []);
|
|
530
|
-
const items = hits.filter((hit) => !excludeSet.has(hit.name)).map((hit) => {
|
|
531
|
-
const shortName = shortNameOfPackage(hit.name);
|
|
532
|
-
const desc = hit.description || "暂无介绍";
|
|
533
|
-
const badge = official.has(hit.name) ? "官方" : "社区";
|
|
534
|
-
return {
|
|
535
|
-
label: `${shortName} (${badge} · ${desc})`,
|
|
536
|
-
value: hit.name
|
|
537
|
-
};
|
|
538
|
-
});
|
|
539
|
-
return multiSelect(message, items, initial, { required: false });
|
|
462
|
+
async function selectPackages(message, type, options = {}) {
|
|
463
|
+
return pickMarketPackages(type, message, options);
|
|
540
464
|
}
|
|
541
465
|
async function scaffoldCommand() {
|
|
542
466
|
const name = await input("请输入项目名称", {
|
|
@@ -551,7 +475,7 @@ async function scaffoldCommand() {
|
|
|
551
475
|
});
|
|
552
476
|
ensurePackageManager();
|
|
553
477
|
const ownersList = [...String(owners).split(",").map((o) => o.trim()).filter(Boolean), STDIN_OWNER];
|
|
554
|
-
const adapterNames = await selectPackages("选择要安装的适配器(上下键选择,空格勾选,回车确认)",
|
|
478
|
+
const adapterNames = await selectPackages("选择要安装的适配器(上下键选择,空格勾选,回车确认)", "adapter", { exclude: SYSTEM_ADAPTERS });
|
|
555
479
|
const allAdapterNames = [...SYSTEM_ADAPTERS, ...adapterNames];
|
|
556
480
|
if (adapterNames.length === 0) consola.info("未选择其他适配器,仅启用标准输入");
|
|
557
481
|
const pkgJsonObj = {
|
|
@@ -613,7 +537,7 @@ async function scaffoldCommand() {
|
|
|
613
537
|
runAdapterCli(adapterName, projectPath);
|
|
614
538
|
}
|
|
615
539
|
consola.info(`已自动安装并启用系统适配器: ${SYSTEM_ADAPTERS.map(shortNameOfPackage).join(", ")}`);
|
|
616
|
-
const pluginNames = await selectPackages("选择要安装的插件(上下键选择,空格勾选,回车确认)",
|
|
540
|
+
const pluginNames = await selectPackages("选择要安装的插件(上下键选择,空格勾选,回车确认)", "plugin", { exclude: SYSTEM_PLUGINS });
|
|
617
541
|
consola.info(`系统插件将自动安装: ${SYSTEM_PLUGINS.map(shortNameOfPackage).join(", ")}`);
|
|
618
542
|
const enabledPlugins = [
|
|
619
543
|
"demo",
|
|
@@ -644,6 +568,247 @@ async function scaffoldCommand() {
|
|
|
644
568
|
return 0;
|
|
645
569
|
}
|
|
646
570
|
|
|
571
|
+
//#endregion
|
|
572
|
+
//#region src/cli/install.ts
|
|
573
|
+
const INSTALL_TARGETS = [
|
|
574
|
+
{
|
|
575
|
+
label: "mioku 框架 —— 创建新的机器人项目(同 npx mioku)",
|
|
576
|
+
value: "mioku"
|
|
577
|
+
},
|
|
578
|
+
{
|
|
579
|
+
label: "插件 (plugin) —— 安装到当前项目",
|
|
580
|
+
value: "plugin"
|
|
581
|
+
},
|
|
582
|
+
{
|
|
583
|
+
label: "服务 (service) —— 安装到当前项目",
|
|
584
|
+
value: "service"
|
|
585
|
+
},
|
|
586
|
+
{
|
|
587
|
+
label: "适配器 (adapter) —— 安装到当前项目并运行配置向导",
|
|
588
|
+
value: "adapter"
|
|
589
|
+
}
|
|
590
|
+
];
|
|
591
|
+
async function installCommand(cmdArgs, helpInfo) {
|
|
592
|
+
const [type, name] = cmdArgs;
|
|
593
|
+
if (!type) return installInteractive();
|
|
594
|
+
if (type === "plugin" || type === "service" || type === "adapter") {
|
|
595
|
+
if (!name) return installInteractive(type);
|
|
596
|
+
ensurePackageManager();
|
|
597
|
+
return installNamed(type, name);
|
|
598
|
+
}
|
|
599
|
+
consola.error(`无效的类型 "${type}",请使用 plugin、service 或 adapter`);
|
|
600
|
+
console.log(helpInfo);
|
|
601
|
+
return 1;
|
|
602
|
+
}
|
|
603
|
+
/** 不带参数:选择安装 mioku 框架或插件/服务/适配器 */
|
|
604
|
+
async function installInteractive(type) {
|
|
605
|
+
let target;
|
|
606
|
+
if (type) target = type;
|
|
607
|
+
else try {
|
|
608
|
+
target = await selectOne("要安装什么?(上下键选择,回车确认)", INSTALL_TARGETS);
|
|
609
|
+
} catch {
|
|
610
|
+
consola.info("已取消");
|
|
611
|
+
return 0;
|
|
612
|
+
}
|
|
613
|
+
if (target === "mioku") return scaffoldCommand();
|
|
614
|
+
ensurePackageManager();
|
|
615
|
+
const cwd = process.cwd();
|
|
616
|
+
if (!fs.existsSync(path.join(cwd, "package.json"))) {
|
|
617
|
+
consola.error("当前目录不是 mioku 项目(未找到 package.json),请先运行 mioku 创建项目或切换到项目目录");
|
|
618
|
+
return 1;
|
|
619
|
+
}
|
|
620
|
+
const packages = await pickMarketPackages(target, "选择要安装的包(上下键选择,空格勾选,回车确认)");
|
|
621
|
+
if (packages.length === 0) {
|
|
622
|
+
consola.info("未选择任何包,已取消安装");
|
|
623
|
+
return 0;
|
|
624
|
+
}
|
|
625
|
+
const ok = await confirm(`确认安装以下 ${packages.length} 个包?\n${packages.map((p) => ` - ${p}`).join("\n")}`);
|
|
626
|
+
if (!ok) {
|
|
627
|
+
consola.info("已取消安装");
|
|
628
|
+
return 1;
|
|
629
|
+
}
|
|
630
|
+
return installPackages(target, packages, cwd);
|
|
631
|
+
}
|
|
632
|
+
/** 带类型和名称:直接安装指定包 */
|
|
633
|
+
async function installNamed(type, name) {
|
|
634
|
+
const cwd = process.cwd();
|
|
635
|
+
const prefix = type === "plugin" ? PLUGIN_PREFIX : type === "service" ? SERVICE_PREFIX : ADAPTER_PREFIX;
|
|
636
|
+
const normalized = name.startsWith(prefix) ? name : `${prefix}${name}`;
|
|
637
|
+
if (type === "plugin") {
|
|
638
|
+
const proceed = await warnIfPrivatePlugin(normalized);
|
|
639
|
+
if (!proceed) {
|
|
640
|
+
consola.info("已取消安装");
|
|
641
|
+
return 1;
|
|
642
|
+
}
|
|
643
|
+
const services = await resolveRequiredServices([normalized]);
|
|
644
|
+
if (services.length > 0) {
|
|
645
|
+
consola.info(`将一并安装插件声明的服务: ${services.map(shortNameOfPackage).join(", ")}`);
|
|
646
|
+
return installPackages("plugin", [normalized, ...services], cwd);
|
|
647
|
+
}
|
|
648
|
+
return installPackages("plugin", [normalized], cwd);
|
|
649
|
+
}
|
|
650
|
+
return installPackages(type, [normalized], cwd);
|
|
651
|
+
}
|
|
652
|
+
async function installPackages(type, packages, cwd) {
|
|
653
|
+
try {
|
|
654
|
+
execAdd(packages, cwd);
|
|
655
|
+
consola.success(`已安装 ${packages.join(" ")}`);
|
|
656
|
+
} catch {
|
|
657
|
+
consola.error(`安装失败: ${packages.join(" ")}`);
|
|
658
|
+
return 1;
|
|
659
|
+
}
|
|
660
|
+
if (type === "plugin") for (const pkg of packages) {
|
|
661
|
+
if (!pkg.startsWith(PLUGIN_PREFIX)) continue;
|
|
662
|
+
if (appendToMiokuPlugins(cwd, pkg)) consola.success(`已在 mioku.plugins 中启用 ${shortNameOfPackage(pkg)}`);
|
|
663
|
+
else consola.info(`${shortNameOfPackage(pkg)} 已在 mioku.plugins 中,跳过`);
|
|
664
|
+
}
|
|
665
|
+
if (type === "adapter") for (const pkg of packages) {
|
|
666
|
+
const adapterName = shortNameOfPackage(pkg);
|
|
667
|
+
consola.info(`正在运行 ${pkg} 配置向导...`);
|
|
668
|
+
runAdapterCli(adapterName, cwd);
|
|
669
|
+
}
|
|
670
|
+
return 0;
|
|
671
|
+
}
|
|
672
|
+
async function warnIfPrivatePlugin(pkgName) {
|
|
673
|
+
const keywords = await fetchNpmKeywords(pkgName);
|
|
674
|
+
if (keywords === null) return true;
|
|
675
|
+
if (keywords.includes("mioku")) return true;
|
|
676
|
+
consola.warn(`${pkgName} 看起来是私有插件"`);
|
|
677
|
+
consola.warn("该插件未上架插件市场,可能存在风险");
|
|
678
|
+
return confirm("仍要继续安装吗?", { initial: false });
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
//#endregion
|
|
682
|
+
//#region src/cli/update.ts
|
|
683
|
+
async function updatePackages(packages, cwd) {
|
|
684
|
+
if (packages.length === 0) {
|
|
685
|
+
consola.info("未找到 mioku 相关依赖");
|
|
686
|
+
return;
|
|
687
|
+
}
|
|
688
|
+
console.log(`执行: bun update ${packages.join(" ")} --latest`);
|
|
689
|
+
run("bun", [
|
|
690
|
+
"update",
|
|
691
|
+
...packages,
|
|
692
|
+
"--latest"
|
|
693
|
+
], { cwd });
|
|
694
|
+
}
|
|
695
|
+
async function updateByPrefix(prefix, cwd, name) {
|
|
696
|
+
if (name) {
|
|
697
|
+
const normalized = name.startsWith(prefix) ? name : `${prefix}${name}`;
|
|
698
|
+
console.log(`执行: bun update ${normalized} --latest`);
|
|
699
|
+
run("bun", [
|
|
700
|
+
"update",
|
|
701
|
+
normalized,
|
|
702
|
+
"--latest"
|
|
703
|
+
], { cwd });
|
|
704
|
+
return;
|
|
705
|
+
}
|
|
706
|
+
const packages = (await getInstalledPackages(cwd)).filter((p) => p.startsWith(prefix));
|
|
707
|
+
if (packages.length === 0) {
|
|
708
|
+
consola.info(`未找到 ${prefix}* 相关依赖`);
|
|
709
|
+
return;
|
|
710
|
+
}
|
|
711
|
+
await updatePackages(packages, cwd);
|
|
712
|
+
}
|
|
713
|
+
/** latest 是否比 current 更新(按数字段比较,避免把已装的新版本倒退回去) */
|
|
714
|
+
function isNewerVersion(latest, current) {
|
|
715
|
+
const parse = (v) => {
|
|
716
|
+
const [core, pre = ""] = v.split("-");
|
|
717
|
+
return {
|
|
718
|
+
nums: core.split(".").map((n) => Number(n) || 0),
|
|
719
|
+
pre
|
|
720
|
+
};
|
|
721
|
+
};
|
|
722
|
+
const a = parse(latest);
|
|
723
|
+
const b = parse(current);
|
|
724
|
+
for (let i = 0; i < 3; i++) {
|
|
725
|
+
const diff = (a.nums[i] ?? 0) - (b.nums[i] ?? 0);
|
|
726
|
+
if (diff !== 0) return diff > 0;
|
|
727
|
+
}
|
|
728
|
+
if (!a.pre && b.pre) return true;
|
|
729
|
+
if (a.pre && !b.pre) return false;
|
|
730
|
+
return a.pre > b.pre;
|
|
731
|
+
}
|
|
732
|
+
/** 对比 npm 上的最新版本,找出所有可更新的 mioku 包(含框架本身) */
|
|
733
|
+
async function collectOutdated(cwd) {
|
|
734
|
+
const packages = await getInstalledPackages(cwd);
|
|
735
|
+
const checked = await Promise.all(packages.map(async (name) => ({
|
|
736
|
+
name,
|
|
737
|
+
current: installedVersionOf(cwd, name),
|
|
738
|
+
meta: await fetchNpmPackageMeta(name)
|
|
739
|
+
})));
|
|
740
|
+
const outdated = [];
|
|
741
|
+
for (const { name, current, meta } of checked) {
|
|
742
|
+
if (!current) continue;
|
|
743
|
+
const latest = meta?.version;
|
|
744
|
+
if (!latest || !isNewerVersion(latest, current)) continue;
|
|
745
|
+
outdated.push({
|
|
746
|
+
name,
|
|
747
|
+
current,
|
|
748
|
+
latest
|
|
749
|
+
});
|
|
750
|
+
}
|
|
751
|
+
return outdated.sort((a, b) => a.name.localeCompare(b.name));
|
|
752
|
+
}
|
|
753
|
+
/** 检查更新并列出选择框(含 mioku 框架本身),确认后更新选中项 */
|
|
754
|
+
async function updateCheckFlow(cwd) {
|
|
755
|
+
consola.info("正在检查 mioku 包更新...");
|
|
756
|
+
const outdated = await collectOutdated(cwd);
|
|
757
|
+
if (outdated.length === 0) {
|
|
758
|
+
consola.success("所有 mioku 包均已是最新版本");
|
|
759
|
+
return 0;
|
|
760
|
+
}
|
|
761
|
+
consola.info(`发现 ${outdated.length} 个可更新包`);
|
|
762
|
+
const items = outdated.map((o) => ({
|
|
763
|
+
label: `${o.name} ${o.current} → ${o.latest}`,
|
|
764
|
+
value: o.name
|
|
765
|
+
}));
|
|
766
|
+
let selected;
|
|
767
|
+
try {
|
|
768
|
+
selected = await multiSelect("选择要更新的包(空格勾选,回车确认)", items, []);
|
|
769
|
+
} catch {
|
|
770
|
+
consola.info("已取消");
|
|
771
|
+
return 0;
|
|
772
|
+
}
|
|
773
|
+
if (selected.length === 0) {
|
|
774
|
+
consola.info("未选择任何包");
|
|
775
|
+
return 0;
|
|
776
|
+
}
|
|
777
|
+
await updatePackages(selected, cwd);
|
|
778
|
+
return 0;
|
|
779
|
+
}
|
|
780
|
+
async function updateCommand(cmdArgs) {
|
|
781
|
+
ensurePackageManager();
|
|
782
|
+
const cwd = process.cwd();
|
|
783
|
+
const [target, name] = cmdArgs;
|
|
784
|
+
if (!target || target === "check") return updateCheckFlow(cwd);
|
|
785
|
+
if (target === "all") {
|
|
786
|
+
await updatePackages(await getInstalledPackages(cwd), cwd);
|
|
787
|
+
return 0;
|
|
788
|
+
}
|
|
789
|
+
if (target === "self") {
|
|
790
|
+
console.log("执行: bun update mioku --latest");
|
|
791
|
+
run("bun", [
|
|
792
|
+
"update",
|
|
793
|
+
"mioku",
|
|
794
|
+
"--latest"
|
|
795
|
+
], { cwd });
|
|
796
|
+
return 0;
|
|
797
|
+
}
|
|
798
|
+
if (target === "plugin" || target === "service") {
|
|
799
|
+
const prefix = target === "plugin" ? PLUGIN_PREFIX : SERVICE_PREFIX;
|
|
800
|
+
await updateByPrefix(prefix, cwd, name);
|
|
801
|
+
return 0;
|
|
802
|
+
}
|
|
803
|
+
console.log(`执行: bun update ${target} --latest`);
|
|
804
|
+
run("bun", [
|
|
805
|
+
"update",
|
|
806
|
+
target,
|
|
807
|
+
"--latest"
|
|
808
|
+
], { cwd });
|
|
809
|
+
return 0;
|
|
810
|
+
}
|
|
811
|
+
|
|
647
812
|
//#endregion
|
|
648
813
|
//#region src/cli/index.ts
|
|
649
814
|
const args = process.argv.slice(2);
|