@agile-team/wl-skills-kit 2.4.1 → 2.5.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/bin/wl-skills.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  /**
4
- * wl-skills-kit CLI v2.4.0
4
+ * wl-skills-kit CLI v2.5.0
5
5
  *
6
6
  * 命令:
7
7
  * init 全量安装(默认,向后兼容)
@@ -9,7 +9,9 @@
9
9
  * clean 构建清理(移除 AI 指令/文档/样例,保留组件和类型)
10
10
  * check 环境预检(工具链 / MCP 配置 / manifest)
11
11
  * diff 对比已安装文件与当前 kit 版本
12
- * validate 静态检查 src/views 页面文件完整性
12
+ * validate 静态检查 src/views 页面文件完整性、AGGrid、skills-ui runtime、mock
13
+ * validate-page validate 的别名,适用于单页/目录检查
14
+ * doctor-ui 检查 @agile-team/wk-skills-ui 接入完整性
13
15
  * export 导出 SYS_MENU / SYS_DICT / SYS_PERMISSION 为 xlsx
14
16
  * --help 帮助
15
17
  * --dry-run 预览模式(所有命令均支持)
@@ -44,7 +46,9 @@ if (showHelp) {
44
46
  clean 构建清理(移除开发期 AI 文件,保留 src/components + src/types)
45
47
  check 环境预检(Node / 工具链 / MCP 配置 / manifest)
46
48
  diff 对比已安装文件与当前 kit 版本的差异
47
- validate 静态检查 src/views 页面文件完整性
49
+ validate 静态检查 src/views 页面文件、AGGrid、skills-ui runtime、mock
50
+ validate-page validate 的别名,适用于单页/目录检查
51
+ doctor-ui 检查 @agile-team/wk-skills-ui 接入完整性
48
52
  export 导出 reports/SYS_* 数据为 xlsx
49
53
 
50
54
  选项:
@@ -60,6 +64,8 @@ if (showHelp) {
60
64
  npx @agile-team/wl-skills-kit check 检查本地环境
61
65
  npx @agile-team/wl-skills-kit diff 查看当前项目与最新 kit 差异
62
66
  npx @agile-team/wl-skills-kit validate 检查 src/views 页面文件
67
+ npx @agile-team/wl-skills-kit validate-page src/views/mdata/model/demo
68
+ npx @agile-team/wl-skills-kit doctor-ui 检查 wk-skills-ui 接入
63
69
  npx @agile-team/wl-skills-kit export 导出菜单/字典/权限 xlsx
64
70
  npx @agile-team/wl-skills-kit clean 清理开发期文件
65
71
  npx @agile-team/wl-skills-kit clean --keep-reports 保留 reports/中的菜单/字典数据
@@ -143,7 +149,7 @@ function removeFileAndEmptyParents(filePath) {
143
149
  } else {
144
150
  break;
145
151
  }
146
- } catch (e) {
152
+ } catch {
147
153
  break;
148
154
  }
149
155
  }
@@ -154,7 +160,7 @@ function readManifest() {
154
160
  if (fs.existsSync(MANIFEST_PATH)) {
155
161
  try {
156
162
  return JSON.parse(fs.readFileSync(MANIFEST_PATH, "utf8"));
157
- } catch (e) {
163
+ } catch {
158
164
  return null;
159
165
  }
160
166
  }
@@ -332,9 +338,11 @@ function runInstall(incremental) {
332
338
  if (dryRun) {
333
339
  const exists = fs.existsSync(dest);
334
340
  console.log(" " + (exists ? "覆盖" : "新增") + " " + relPath);
335
- exists ? updated++ : created++;
341
+ if (exists) updated++;
342
+ else created++;
336
343
  } else {
337
- copyFileSafe(src, dest) === "created" ? created++ : updated++;
344
+ if (copyFileSafe(src, dest) === "created") created++;
345
+ else updated++;
338
346
  }
339
347
  }
340
348
 
@@ -372,9 +380,11 @@ function runInstall(incremental) {
372
380
  console.log(
373
381
  " " + (ecExists ? "覆盖" : "新增") + " [编辑器] " + ecPath,
374
382
  );
375
- ecExists ? updated++ : created++;
383
+ if (ecExists) updated++;
384
+ else created++;
376
385
  } else {
377
- writeFile(ecDest, ecContent) === "created" ? created++ : updated++;
386
+ if (writeFile(ecDest, ecContent) === "created") created++;
387
+ else updated++;
378
388
  }
379
389
  }
380
390
  }
@@ -411,6 +421,20 @@ function runInstall(incremental) {
411
421
 
412
422
  if (!dryRun) writeManifest(newManifest);
413
423
 
424
+ // ── Step 5: 非耦合桥接提醒(不自动安装 wk-skills-ui)───────────────────────
425
+
426
+ const targetPkgPath = path.join(TARGET_DIR, "package.json");
427
+ let hasUiPackage = false;
428
+ if (fs.existsSync(targetPkgPath)) {
429
+ try {
430
+ const targetPkg = JSON.parse(fs.readFileSync(targetPkgPath, "utf8"));
431
+ const deps = { ...targetPkg.dependencies, ...targetPkg.devDependencies };
432
+ hasUiPackage = Boolean(deps["@agile-team/wk-skills-ui"]);
433
+ } catch {
434
+ hasUiPackage = false;
435
+ }
436
+ }
437
+
414
438
  // ── 输出统计 ──────────────────────────────────────────────────────
415
439
 
416
440
  const total = created + updated + unchanged;
@@ -455,6 +479,19 @@ function runInstall(incremental) {
455
479
  }
456
480
  }
457
481
  console.log("");
482
+ if (hasUiPackage) {
483
+ console.log(
484
+ " ℹ 检测到 @agile-team/wk-skills-ui:两包独立分工,可组合触发 UI 风格对齐流程。",
485
+ );
486
+ } else {
487
+ console.log(
488
+ " ℹ 可选桥接:如需统一 UI 风格/老项目化妆层,可安装 @agile-team/wk-skills-ui。",
489
+ );
490
+ }
491
+ console.log(
492
+ " ℹ 规范插件:建议执行 npx @robot-admin/git-standards init 接入代码质量与提交规范。",
493
+ );
494
+ console.log("");
458
495
  }
459
496
 
460
497
  // ─── 命令: clean ────────────────────────────────────────────────────────
@@ -537,7 +574,11 @@ function expectedManifestFiles() {
537
574
  for (const relPath of files) {
538
575
  expected[relPath] = fileMd5(path.join(FILES_DIR, relPath));
539
576
  }
540
- const instructionsSrc = path.join(FILES_DIR, ".github", "copilot-instructions.md");
577
+ const instructionsSrc = path.join(
578
+ FILES_DIR,
579
+ ".github",
580
+ "copilot-instructions.md",
581
+ );
541
582
  if (fs.existsSync(instructionsSrc)) {
542
583
  const raw = fs.readFileSync(instructionsSrc, "utf8");
543
584
  for (const [ecPath, ecContent] of getEditorConfigs(raw)) {
@@ -567,19 +608,34 @@ function runCheck() {
567
608
 
568
609
  const toolFiles = [".prettierrc.js", "eslint.config.ts", ".husky"];
569
610
  for (const rel of toolFiles) {
570
- add(rel, fs.existsSync(path.join(TARGET_DIR, rel)), fs.existsSync(path.join(TARGET_DIR, rel)) ? "存在" : "缺失");
611
+ add(
612
+ rel,
613
+ fs.existsSync(path.join(TARGET_DIR, rel)),
614
+ fs.existsSync(path.join(TARGET_DIR, rel)) ? "存在" : "缺失",
615
+ );
571
616
  }
572
617
 
573
618
  const manifest = readManifest();
574
- add(MANIFEST_NAME, Boolean(manifest), manifest ? "已安装 v" + manifest.version : "未安装");
619
+ add(
620
+ MANIFEST_NAME,
621
+ Boolean(manifest),
622
+ manifest ? "已安装 v" + manifest.version : "未安装",
623
+ );
575
624
 
576
- const envPath = path.join(TARGET_DIR, ".github", "skills", "sync", "env.local.json");
625
+ const envPath = path.join(
626
+ TARGET_DIR,
627
+ ".github",
628
+ "skills",
629
+ "sync",
630
+ "env.local.json",
631
+ );
577
632
  let envOk = false;
578
633
  let envDetail = "缺失";
579
634
  if (fs.existsSync(envPath)) {
580
635
  try {
581
636
  const env = JSON.parse(fs.readFileSync(envPath, "utf8"));
582
- const gatewayOk = env.gatewayPath && !String(env.gatewayPath).includes("你的网关");
637
+ const gatewayOk =
638
+ env.gatewayPath && !String(env.gatewayPath).includes("你的网关");
583
639
  const tokenOk = env.token && !String(env.token).includes("Bearer Token");
584
640
  envOk = Boolean(gatewayOk && tokenOk);
585
641
  envDetail = envOk ? "已填写 gatewayPath/token" : "存在但仍含占位值";
@@ -589,15 +645,33 @@ function runCheck() {
589
645
  }
590
646
  add("MCP env.local.json", envOk, envDetail);
591
647
 
592
- const mcpServer = path.join(TARGET_DIR, "node_modules", "@agile-team", "wl-skills-kit", "mcp", "server.js");
593
- add("MCP server", fs.existsSync(mcpServer) || fs.existsSync(path.join(__dirname, "..", "mcp", "server.js")), "server.js 可发现");
648
+ const mcpServer = path.join(
649
+ TARGET_DIR,
650
+ "node_modules",
651
+ "@agile-team",
652
+ "wl-skills-kit",
653
+ "mcp",
654
+ "server.js",
655
+ );
656
+ add(
657
+ "MCP server",
658
+ fs.existsSync(mcpServer) ||
659
+ fs.existsSync(path.join(__dirname, "..", "mcp", "server.js")),
660
+ "server.js 可发现",
661
+ );
594
662
 
595
663
  for (const item of checks) {
596
- console.log(" " + statusIcon(item.ok) + " " + item.name + " — " + item.detail);
664
+ console.log(
665
+ " " + statusIcon(item.ok) + " " + item.name + " — " + item.detail,
666
+ );
597
667
  }
598
668
  const failed = checks.filter((item) => !item.ok).length;
599
669
  console.log("");
600
- console.log(failed === 0 ? " ✔ 环境预检通过" : " ⚠ 环境预检完成,发现 " + failed + " 项需处理");
670
+ console.log(
671
+ failed === 0
672
+ ? " ✔ 环境预检通过"
673
+ : " ⚠ 环境预检完成,发现 " + failed + " 项需处理",
674
+ );
601
675
  console.log("");
602
676
  if (failed > 0) process.exitCode = 1;
603
677
  }
@@ -633,7 +707,9 @@ function runDiff() {
633
707
  }
634
708
  }
635
709
 
636
- console.log(" 当前 manifest: " + (manifest ? "v" + manifest.version : "未找到"));
710
+ console.log(
711
+ " 当前 manifest: " + (manifest ? "v" + manifest.version : "未找到"),
712
+ );
637
713
  console.log(" 最新 kit: v" + PKG.version);
638
714
  console.log(" 新增/缺失: " + added.length);
639
715
  console.log(" 内容不同: " + changed.length);
@@ -645,7 +721,8 @@ function runDiff() {
645
721
  if (list.length === 0) return;
646
722
  console.log(" " + title + ":");
647
723
  for (const relPath of list.slice(0, 80)) console.log(" - " + relPath);
648
- if (list.length > 80) console.log(" ... 还有 " + (list.length - 80) + " 项");
724
+ if (list.length > 80)
725
+ console.log(" ... 还有 " + (list.length - 80) + " 项");
649
726
  console.log("");
650
727
  }
651
728
 
@@ -668,27 +745,53 @@ function scanPageDirs(scanRel) {
668
745
  const pages = [];
669
746
  for (const [dir, names] of dirs.entries()) {
670
747
  if (!names.has("index.vue")) continue;
671
- let apiConfigCount = 0;
748
+ const indexPath = path.join(TARGET_DIR, dir, "index.vue");
749
+ const indexContent = fs.existsSync(indexPath)
750
+ ? fs.readFileSync(indexPath, "utf8")
751
+ : "";
672
752
  const dataPath = path.join(TARGET_DIR, dir, "data.ts");
673
- if (fs.existsSync(dataPath)) {
674
- apiConfigCount = (fs.readFileSync(dataPath, "utf8").match(/API_CONFIG/g) || []).length;
675
- }
753
+ const dataContent = fs.existsSync(dataPath)
754
+ ? fs.readFileSync(dataPath, "utf8")
755
+ : "";
756
+ let apiConfigCount = 0;
757
+ if (dataContent)
758
+ apiConfigCount = (dataContent.match(/API_CONFIG/g) || []).length;
676
759
  pages.push({
677
760
  dir,
678
761
  hasDataTs: names.has("data.ts"),
679
762
  hasIndexScss: names.has("index.scss"),
680
763
  hasApiMd: names.has("api.md"),
681
764
  apiConfigCount,
765
+ baseTableCount: (indexContent.match(/<BaseTable\b/g) || []).length,
766
+ agGridCount: (indexContent.match(/render-type=["']agGrid["']/g) || [])
767
+ .length,
768
+ cidBindCount: (indexContent.match(/\bcid=|:cid=/g) || []).length,
769
+ hasDefineColumns: /defineColumns\s*\(/.test(dataContent),
770
+ hasRenderOps: /renderOps\s*\(/.test(dataContent),
771
+ hasOperationsArray: /operations\s*:/.test(dataContent),
772
+ hasEmptyOnClick: /onClick\s*:\s*\(\s*[^)]*\s*\)\s*=>\s*\{\s*\}/.test(
773
+ dataContent,
774
+ ),
775
+ apiUrls: Array.from(
776
+ dataContent.matchAll(/:\s*["']([^"']+\/[^"']+)["']/g),
777
+ ).map((m) => m[1]),
682
778
  });
683
779
  }
684
780
  return pages.sort((a, b) => a.dir.localeCompare(b.dir));
685
781
  }
686
782
 
783
+ function findMockFiles() {
784
+ const mockDir = path.join(TARGET_DIR, "mock");
785
+ if (!fs.existsSync(mockDir)) return [];
786
+ return walkDir(mockDir, TARGET_DIR).filter((rel) => /\.(ts|js)$/.test(rel));
787
+ }
788
+
687
789
  function runValidate() {
688
- const scanPath = args.find((a) => !a.startsWith("-") && a !== command) || "src/views";
790
+ const scanPath =
791
+ args.find((a) => !a.startsWith("-") && a !== command) || "src/views";
689
792
  const pages = scanPageDirs(scanPath);
690
793
  console.log("");
691
- console.log(" wl-skills-kit v" + PKG.version + " [validate]");
794
+ console.log(" wl-skills-kit v" + PKG.version + " [" + command + "]");
692
795
  console.log(" 扫描目录: " + scanPath);
693
796
  console.log("");
694
797
 
@@ -700,28 +803,195 @@ function runValidate() {
700
803
  }
701
804
 
702
805
  const issues = [];
806
+ const mockFiles = findMockFiles();
807
+ const mockContent = mockFiles
808
+ .map((rel) => fs.readFileSync(path.join(TARGET_DIR, rel), "utf8"))
809
+ .join("\n");
703
810
  for (const page of pages) {
704
- if (!page.hasDataTs) issues.push({ level: "warn", dir: page.dir, text: "缺 data.ts(需结合页面复杂度判断)" });
705
- if (!page.hasIndexScss) issues.push({ level: "warn", dir: page.dir, text: "缺 index.scss" });
706
- if (page.apiConfigCount > 0 && !page.hasApiMd) issues.push({ level: "warn", dir: page.dir, text: "检测到 API_CONFIG 但缺 api.md" });
811
+ if (!page.hasDataTs)
812
+ issues.push({
813
+ level: "warn",
814
+ dir: page.dir,
815
+ text: "缺 data.ts(需结合页面复杂度判断)",
816
+ });
817
+ if (!page.hasIndexScss)
818
+ issues.push({ level: "warn", dir: page.dir, text: "缺 index.scss" });
819
+ if (page.apiConfigCount > 0 && !page.hasApiMd)
820
+ issues.push({
821
+ level: "warn",
822
+ dir: page.dir,
823
+ text: "检测到 API_CONFIG 但缺 api.md",
824
+ });
825
+ if (page.baseTableCount > 0 && page.agGridCount < page.baseTableCount)
826
+ issues.push({
827
+ level: "error",
828
+ dir: page.dir,
829
+ text: 'BaseTable 必须显式 render-type="agGrid"',
830
+ });
831
+ if (page.baseTableCount > 0 && page.cidBindCount < page.baseTableCount)
832
+ issues.push({
833
+ level: "error",
834
+ dir: page.dir,
835
+ text: "BaseTable 必须配置全局唯一 cid / :cid",
836
+ });
837
+ if (page.hasDataTs && page.baseTableCount > 0 && !page.hasDefineColumns)
838
+ issues.push({
839
+ level: "error",
840
+ dir: page.dir,
841
+ text: "表格列必须使用 wk-skills-ui defineColumns()",
842
+ });
843
+ if (page.hasOperationsArray)
844
+ issues.push({
845
+ level: "error",
846
+ dir: page.dir,
847
+ text: "操作列禁止 operations 数组,必须使用 defaultSlot + renderOps()",
848
+ });
849
+ if (
850
+ page.hasDataTs &&
851
+ page.baseTableCount > 0 &&
852
+ !page.hasRenderOps &&
853
+ /操作|_action/.test(
854
+ fs.readFileSync(path.join(TARGET_DIR, page.dir, "data.ts"), "utf8"),
855
+ )
856
+ )
857
+ issues.push({
858
+ level: "warn",
859
+ dir: page.dir,
860
+ text: "疑似存在操作列但未使用 renderOps()",
861
+ });
862
+ if (page.hasEmptyOnClick)
863
+ issues.push({
864
+ level: "error",
865
+ dir: page.dir,
866
+ text: "存在空 onClick: () => {}",
867
+ });
868
+ if (page.apiConfigCount > 0 && mockFiles.length === 0)
869
+ issues.push({
870
+ level: "warn",
871
+ dir: page.dir,
872
+ text: "检测到 API_CONFIG 但项目 mock/ 目录无 mock 文件",
873
+ });
874
+ for (const url of page.apiUrls.filter((item) => item.startsWith("/"))) {
875
+ const mockUrl = `/dev-api${url}`;
876
+ if (mockContent && !mockContent.includes(mockUrl))
877
+ issues.push({
878
+ level: "warn",
879
+ dir: page.dir,
880
+ text: "mock 中未发现端点 " + mockUrl,
881
+ });
882
+ }
707
883
  }
708
884
 
709
885
  console.log(" 页面目录: " + pages.length);
710
886
  console.log(" 提示项: " + issues.length);
711
887
  console.log("");
888
+ const errors = issues.filter((issue) => issue.level === "error").length;
712
889
  for (const issue of issues) {
713
- console.log(" ⚠ " + issue.dir + " " + issue.text);
890
+ const icon = issue.level === "error" ? "✖" : "⚠";
891
+ console.log(" " + icon + " " + issue.dir + " — " + issue.text);
714
892
  }
715
893
  if (issues.length === 0) console.log(" ✔ 页面文件完整性检查通过");
716
894
  console.log("");
717
- if (issues.length > 0) process.exitCode = 1;
895
+ if (errors > 0 || issues.length > 0) process.exitCode = 1;
896
+ }
897
+
898
+ function readJsonSafe(filePath) {
899
+ if (!fs.existsSync(filePath)) return null;
900
+ try {
901
+ return JSON.parse(fs.readFileSync(filePath, "utf8"));
902
+ } catch {
903
+ return null;
904
+ }
905
+ }
906
+
907
+ function runDoctorUi() {
908
+ console.log("");
909
+ console.log(" wl-skills-kit v" + PKG.version + " [doctor-ui]");
910
+ console.log(" 目标目录: " + TARGET_DIR);
911
+ console.log("");
912
+
913
+ const checks = [];
914
+ function add(name, ok, detail) {
915
+ checks.push({ name, ok, detail });
916
+ }
917
+
918
+ const pkg = readJsonSafe(path.join(TARGET_DIR, "package.json"));
919
+ const deps = pkg ? { ...pkg.dependencies, ...pkg.devDependencies } : {};
920
+ add(
921
+ "@agile-team/wk-skills-ui",
922
+ Boolean(deps["@agile-team/wk-skills-ui"]),
923
+ deps["@agile-team/wk-skills-ui"] || "未安装",
924
+ );
925
+ add(
926
+ "@element-plus/icons-vue",
927
+ Boolean(deps["@element-plus/icons-vue"]),
928
+ deps["@element-plus/icons-vue"] || "未安装",
929
+ );
930
+
931
+ const files = fs.existsSync(TARGET_DIR)
932
+ ? walkDir(TARGET_DIR, TARGET_DIR)
933
+ : [];
934
+ const sourceFiles = files.filter(
935
+ (rel) =>
936
+ /\.(ts|vue|scss|html)$/.test(rel) && !rel.startsWith("node_modules/"),
937
+ );
938
+ const readAll = (pattern) =>
939
+ sourceFiles
940
+ .filter((rel) => pattern.test(rel))
941
+ .map((rel) => fs.readFileSync(path.join(TARGET_DIR, rel), "utf8"))
942
+ .join("\n");
943
+ const allSource = readAll(/.*/);
944
+
945
+ add(
946
+ "design tokens",
947
+ /@agile-team\/wk-skills-ui\/design\/tokens|dist\/tokens\.css/.test(
948
+ allSource,
949
+ ),
950
+ "需引入 design tokens",
951
+ );
952
+ add(
953
+ "styles preset",
954
+ /@agile-team\/wk-skills-ui\/styles/.test(allSource),
955
+ "需引入 styles 或 skin preset",
956
+ );
957
+ add(
958
+ "installCommonPreset",
959
+ /installCommonPreset\s*\(/.test(allSource),
960
+ "需在入口或业务 preset 中调用",
961
+ );
962
+ add(
963
+ "defineColumns",
964
+ /defineColumns\s*\(/.test(allSource),
965
+ "页面列定义需使用 defineColumns",
966
+ );
967
+ add("renderOps", /renderOps\s*\(/.test(allSource), "操作列需使用 renderOps");
968
+
969
+ for (const item of checks) {
970
+ console.log(
971
+ " " + statusIcon(item.ok) + " " + item.name + " — " + item.detail,
972
+ );
973
+ }
974
+ const failed = checks.filter((item) => !item.ok).length;
975
+ console.log("");
976
+ console.log(
977
+ failed === 0
978
+ ? " ✔ wk-skills-ui 接入检查通过"
979
+ : " ⚠ wk-skills-ui 接入仍有 " + failed + " 项需处理",
980
+ );
981
+ console.log("");
982
+ if (failed > 0) process.exitCode = 1;
718
983
  }
719
984
 
720
985
  function parseMarkdownTable(content) {
721
986
  return content
722
987
  .split(/\r?\n/)
723
988
  .filter((line) => /^\|.*\|$/.test(line) && !/^\|\s*-+/.test(line))
724
- .map((line) => line.split("|").slice(1, -1).map((cell) => cell.trim()));
989
+ .map((line) =>
990
+ line
991
+ .split("|")
992
+ .slice(1, -1)
993
+ .map((cell) => cell.trim()),
994
+ );
725
995
  }
726
996
 
727
997
  function runExport() {
@@ -743,7 +1013,11 @@ function runExport() {
743
1013
  if (!fs.existsSync(full)) continue;
744
1014
  const content = fs.readFileSync(full, "utf8");
745
1015
  let rows = parseMarkdownTable(content);
746
- if (rows.length === 0) rows = content.split(/\r?\n/).filter(Boolean).map((line) => [line]);
1016
+ if (rows.length === 0)
1017
+ rows = content
1018
+ .split(/\r?\n/)
1019
+ .filter(Boolean)
1020
+ .map((line) => [line]);
747
1021
  sheets.push([sheetName, rows]);
748
1022
  addedSheets++;
749
1023
  }
@@ -764,13 +1038,19 @@ function runExport() {
764
1038
  let XLSX;
765
1039
  try {
766
1040
  XLSX = require("xlsx");
767
- } catch (e) {
768
- console.error(" ✖ 未找到 xlsx 依赖,请重新安装最新 @agile-team/wl-skills-kit");
1041
+ } catch {
1042
+ console.error(
1043
+ " ✖ 未找到 xlsx 依赖,请重新安装最新 @agile-team/wl-skills-kit",
1044
+ );
769
1045
  process.exit(1);
770
1046
  }
771
1047
  const wb = XLSX.utils.book_new();
772
1048
  for (const [sheetName, rows] of sheets) {
773
- XLSX.utils.book_append_sheet(wb, XLSX.utils.aoa_to_sheet(rows), sheetName);
1049
+ XLSX.utils.book_append_sheet(
1050
+ wb,
1051
+ XLSX.utils.aoa_to_sheet(rows),
1052
+ sheetName,
1053
+ );
774
1054
  }
775
1055
  fs.mkdirSync(outDir, { recursive: true });
776
1056
  XLSX.writeFile(wb, outFile);
@@ -783,14 +1063,34 @@ function runExport() {
783
1063
  // ─── 主路由 ─────────────────────────────────────────────────────────────
784
1064
 
785
1065
  switch (command) {
786
- case "init": runInstall(false); break;
787
- case "update": runInstall(true); break;
788
- case "clean": runClean(); break;
789
- case "check": runCheck(); break;
790
- case "diff": runDiff(); break;
791
- case "validate": runValidate(); break;
792
- case "export": runExport(); break;
1066
+ case "init":
1067
+ runInstall(false);
1068
+ break;
1069
+ case "update":
1070
+ runInstall(true);
1071
+ break;
1072
+ case "clean":
1073
+ runClean();
1074
+ break;
1075
+ case "check":
1076
+ runCheck();
1077
+ break;
1078
+ case "diff":
1079
+ runDiff();
1080
+ break;
1081
+ case "validate":
1082
+ case "validate-page":
1083
+ runValidate();
1084
+ break;
1085
+ case "doctor-ui":
1086
+ runDoctorUi();
1087
+ break;
1088
+ case "export":
1089
+ runExport();
1090
+ break;
793
1091
  default:
794
- console.error(' ✖ 未知命令: "' + command + '",请使用 --help 查看可用命令');
1092
+ console.error(
1093
+ ' ✖ 未知命令: "' + command + '",请使用 --help 查看可用命令',
1094
+ );
795
1095
  process.exit(1);
796
1096
  }
@@ -1,6 +1,6 @@
1
1
  # AI 辅助开发全景分析 & 架构演进蓝图
2
2
 
3
- > **基于 wl-skills-kit v2.4.0 架构**
3
+ > **基于 wl-skills-kit v2.4.x 架构**
4
4
  > **日期**:2026-05-02
5
5
  > **目标**:企业级通用 · 质量精度高 · 速度快 · 节省 token · 还原度高 · 开箱即用 · 支持 Agent Pipeline
6
6
 
@@ -33,7 +33,7 @@ L7 自演化体系 🔭 需要足够审计报告与模板样本后再规
33
33
 
34
34
  ---
35
35
 
36
- ## 3. v2.4.0 关键新增
36
+ ## 3. v2.4.x 关键能力
37
37
 
38
38
  ### 3.1 Agent Pipeline
39
39
 
@@ -134,7 +134,7 @@ wls_code_scan
134
134
 
135
135
  ## 6. 结论
136
136
 
137
- v2.4.0 后,wl-skills-kit 已具备搭建通用智能体的基础条件:
137
+ v2.4.x 后,wl-skills-kit 已具备搭建通用智能体的基础条件:
138
138
 
139
139
  - 有 Skills 作为结构化能力单元
140
140
  - 有 MCP 作为实时项目感知与副作用执行工具