qat-cli 0.2.7 → 0.2.98

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
@@ -4,7 +4,7 @@
4
4
 
5
5
  **Quick Auto Testing — 面向 Vue 项目,集成 Vitest & Playwright,AI 驱动覆盖测试全流程**
6
6
 
7
- [![npm version](https://img.shields.io/badge/version-0.2.7-blue.svg)](https://www.npmjs.com/package/qat-cli)
7
+ [![npm version](https://img.shields.io/badge/version-0.2.98-blue.svg)](https://www.npmjs.com/package/qat-cli)
8
8
  [![Node.js](https://img.shields.io/badge/node-%3E%3D18.0.0-green.svg)](https://nodejs.org/)
9
9
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
10
10
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.6-blue.svg)](https://www.typescriptlang.org/)
package/dist/cli.js CHANGED
@@ -3169,6 +3169,8 @@ function displayCreateResult(createdFiles, skippedCount, usedAI) {
3169
3169
  import chalk5 from "chalk";
3170
3170
  import inquirer3 from "inquirer";
3171
3171
  import ora4 from "ora";
3172
+ import fs9 from "fs";
3173
+ import path11 from "path";
3172
3174
 
3173
3175
  // src/runners/vitest-runner.ts
3174
3176
  import { execFile } from "child_process";
@@ -3834,6 +3836,8 @@ function calculateAverageMetrics(results) {
3834
3836
  }
3835
3837
 
3836
3838
  // src/commands/run.ts
3839
+ var RESULTS_DIR = ".qat-results";
3840
+ var SERVER_REQUIRED_TYPES = ["e2e", "visual", "performance"];
3837
3841
  var TYPE_RUNNERS = {
3838
3842
  unit: "Vitest",
3839
3843
  component: "Vitest",
@@ -3878,6 +3882,62 @@ async function executeRun(options) {
3878
3882
  console.log(chalk5.yellow("\n \u6CA1\u6709\u53EF\u8FD0\u884C\u7684\u6D4B\u8BD5\u7C7B\u578B\uFF08\u8BF7\u5728 qat.config.ts \u4E2D\u542F\u7528\uFF09\n"));
3879
3883
  return;
3880
3884
  }
3885
+ const serverNeededTypes = typesToRun.filter((t) => SERVER_REQUIRED_TYPES.includes(t));
3886
+ if (serverNeededTypes.length > 0) {
3887
+ const serverOk = await checkDevServer(config);
3888
+ if (!serverOk) {
3889
+ const { action } = await inquirer3.prompt([
3890
+ {
3891
+ type: "list",
3892
+ name: "action",
3893
+ message: `\u8FD0\u884C ${serverNeededTypes.map((t) => TYPE_LABELS[t]).join("\u3001")} \u9700\u8981\u9879\u76EE\u670D\u52A1\u8FD0\u884C\uFF0C\u5982\u4F55\u5904\u7406\uFF1F`,
3894
+ choices: [
3895
+ { name: "\u81EA\u52A8\u542F\u52A8 dev server \u5E76\u8FD0\u884C", value: "start" },
3896
+ { name: "\u8DF3\u8FC7\u8FD9\u4E9B\u6D4B\u8BD5\u7C7B\u578B\uFF0C\u4EC5\u8FD0\u884C\u5176\u4ED6\u6D4B\u8BD5", value: "skip" },
3897
+ { name: "\u53D6\u6D88\u8FD0\u884C", value: "cancel" }
3898
+ ],
3899
+ default: "start"
3900
+ }
3901
+ ]);
3902
+ if (action === "cancel") {
3903
+ console.log(chalk5.gray("\n \u5DF2\u53D6\u6D88\u8FD0\u884C\n"));
3904
+ return;
3905
+ }
3906
+ if (action === "skip") {
3907
+ typesToRun = typesToRun.filter((t) => !SERVER_REQUIRED_TYPES.includes(t));
3908
+ if (typesToRun.length === 0) {
3909
+ console.log(chalk5.yellow("\n \u6CA1\u6709\u53EF\u8FD0\u884C\u7684\u6D4B\u8BD5\u7C7B\u578B\n"));
3910
+ return;
3911
+ }
3912
+ }
3913
+ if (action === "start") {
3914
+ const started = await startDevServer(config);
3915
+ if (!started) {
3916
+ const { fallback } = await inquirer3.prompt([
3917
+ {
3918
+ type: "list",
3919
+ name: "fallback",
3920
+ message: "dev server \u542F\u52A8\u5931\u8D25\uFF0C\u5982\u4F55\u5904\u7406\uFF1F",
3921
+ choices: [
3922
+ { name: "\u8DF3\u8FC7\u9700\u8981\u670D\u52A1\u7684\u6D4B\u8BD5\uFF0C\u4EC5\u8FD0\u884C\u5176\u4ED6\u6D4B\u8BD5", value: "skip" },
3923
+ { name: "\u53D6\u6D88\u8FD0\u884C", value: "cancel" }
3924
+ ],
3925
+ default: "skip"
3926
+ }
3927
+ ]);
3928
+ if (fallback === "cancel") {
3929
+ console.log(chalk5.gray("\n \u5DF2\u53D6\u6D88\u8FD0\u884C\n"));
3930
+ return;
3931
+ }
3932
+ typesToRun = typesToRun.filter((t) => !SERVER_REQUIRED_TYPES.includes(t));
3933
+ if (typesToRun.length === 0) {
3934
+ console.log(chalk5.yellow("\n \u6CA1\u6709\u53EF\u8FD0\u884C\u7684\u6D4B\u8BD5\u7C7B\u578B\n"));
3935
+ return;
3936
+ }
3937
+ }
3938
+ }
3939
+ }
3940
+ }
3881
3941
  if (!type && !file) {
3882
3942
  const { runMode } = await inquirer3.prompt([
3883
3943
  {
@@ -3924,6 +3984,7 @@ async function executeRun(options) {
3924
3984
  }
3925
3985
  }
3926
3986
  displaySummary(results, config);
3987
+ saveRunResults(results);
3927
3988
  }
3928
3989
  function printDryRunCommands(types, options, config) {
3929
3990
  console.log();
@@ -4251,6 +4312,71 @@ function scoreColor(score) {
4251
4312
  if (score >= 50) return chalk5.yellow("\u25CF");
4252
4313
  return chalk5.red("\u25CF");
4253
4314
  }
4315
+ async function checkDevServer(config) {
4316
+ const baseUrl = config.playwright.baseURL || "http://localhost:5173";
4317
+ try {
4318
+ const controller = new AbortController();
4319
+ const timer = setTimeout(() => controller.abort(), 3e3);
4320
+ const response = await fetch(baseUrl, { signal: controller.signal, method: "HEAD" });
4321
+ clearTimeout(timer);
4322
+ return response.status > 0;
4323
+ } catch {
4324
+ return false;
4325
+ }
4326
+ }
4327
+ async function startDevServer(config) {
4328
+ const { spawn } = await import("child_process");
4329
+ const hasPnpm = fs9.existsSync(path11.join(process.cwd(), "pnpm-lock.yaml"));
4330
+ const hasYarn = fs9.existsSync(path11.join(process.cwd(), "yarn.lock"));
4331
+ const pkgCmd = hasPnpm ? "pnpm" : hasYarn ? "yarn" : "npm";
4332
+ console.log(chalk5.cyan(` \u6B63\u5728\u542F\u52A8 dev server (${pkgCmd} run dev) ...`));
4333
+ const child = spawn(pkgCmd, ["run", "dev"], {
4334
+ cwd: process.cwd(),
4335
+ stdio: "pipe",
4336
+ shell: true,
4337
+ detached: true
4338
+ });
4339
+ const baseUrl = config.playwright.baseURL || "http://localhost:5173";
4340
+ const maxWait = 3e4;
4341
+ const interval = 1e3;
4342
+ let waited = 0;
4343
+ while (waited < maxWait) {
4344
+ await new Promise((r) => setTimeout(r, interval));
4345
+ waited += interval;
4346
+ const isUp = await checkDevServer(config);
4347
+ if (isUp) {
4348
+ console.log(chalk5.green(` \u2713 dev server \u5DF2\u542F\u52A8 (${baseUrl})`));
4349
+ child.unref();
4350
+ return true;
4351
+ }
4352
+ }
4353
+ child.kill();
4354
+ console.log(chalk5.red(" \u2717 dev server \u542F\u52A8\u8D85\u65F6"));
4355
+ return false;
4356
+ }
4357
+ function saveRunResults(results) {
4358
+ if (results.length === 0) return;
4359
+ const resultsPath = path11.join(process.cwd(), RESULTS_DIR);
4360
+ if (!fs9.existsSync(resultsPath)) {
4361
+ fs9.mkdirSync(resultsPath, { recursive: true });
4362
+ }
4363
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
4364
+ const fileName = `result-${timestamp}.json`;
4365
+ const filePath = path11.join(resultsPath, fileName);
4366
+ const data = {
4367
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
4368
+ results
4369
+ };
4370
+ fs9.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf-8");
4371
+ try {
4372
+ const files = fs9.readdirSync(resultsPath).filter((f) => f.startsWith("result-") && f.endsWith(".json")).sort();
4373
+ while (files.length > 20) {
4374
+ const oldest = files.shift();
4375
+ fs9.unlinkSync(path11.join(resultsPath, oldest));
4376
+ }
4377
+ } catch {
4378
+ }
4379
+ }
4254
4380
 
4255
4381
  // src/commands/mock.ts
4256
4382
  import chalk6 from "chalk";
@@ -4374,12 +4500,12 @@ function showStatus() {
4374
4500
  // src/commands/report.ts
4375
4501
  import chalk7 from "chalk";
4376
4502
  import ora6 from "ora";
4377
- import fs10 from "fs";
4378
- import path12 from "path";
4503
+ import fs11 from "fs";
4504
+ import path13 from "path";
4379
4505
 
4380
4506
  // src/services/reporter.ts
4381
- import fs9 from "fs";
4382
- import path11 from "path";
4507
+ import fs10 from "fs";
4508
+ import path12 from "path";
4383
4509
  function aggregateResults(results) {
4384
4510
  const summary = {
4385
4511
  total: 0,
@@ -4634,17 +4760,17 @@ function generateHTMLReport(data) {
4634
4760
  }
4635
4761
  function writeReportToDisk(data, outputDir) {
4636
4762
  const html = generateHTMLReport(data);
4637
- const dir = path11.resolve(outputDir);
4638
- if (!fs9.existsSync(dir)) {
4639
- fs9.mkdirSync(dir, { recursive: true });
4763
+ const dir = path12.resolve(outputDir);
4764
+ if (!fs10.existsSync(dir)) {
4765
+ fs10.mkdirSync(dir, { recursive: true });
4640
4766
  }
4641
- const indexPath = path11.join(dir, "index.html");
4642
- fs9.writeFileSync(indexPath, html, "utf-8");
4767
+ const indexPath = path12.join(dir, "index.html");
4768
+ fs10.writeFileSync(indexPath, html, "utf-8");
4643
4769
  return indexPath;
4644
4770
  }
4645
4771
 
4646
4772
  // src/commands/report.ts
4647
- var RESULTS_DIR = ".qat-results";
4773
+ var RESULTS_DIR2 = ".qat-results";
4648
4774
  function registerReportCommand(program2) {
4649
4775
  program2.command("report").description("\u751F\u6210\u6D4B\u8BD5\u62A5\u544A - \u805A\u5408\u6240\u6709\u6D4B\u8BD5\u7ED3\u679C\u5E76\u8F93\u51FAHTML").option("-o, --output <dir>", "\u62A5\u544A\u8F93\u51FA\u76EE\u5F55").option("--open", "\u751F\u6210\u540E\u81EA\u52A8\u6253\u5F00\u62A5\u544A", false).action(async (options) => {
4650
4776
  try {
@@ -4679,15 +4805,15 @@ async function executeReport(options) {
4679
4805
  }
4680
4806
  function collectResults() {
4681
4807
  const results = [];
4682
- const resultsPath = path12.join(process.cwd(), RESULTS_DIR);
4683
- if (!fs10.existsSync(resultsPath)) {
4808
+ const resultsPath = path13.join(process.cwd(), RESULTS_DIR2);
4809
+ if (!fs11.existsSync(resultsPath)) {
4684
4810
  return results;
4685
4811
  }
4686
- const files = fs10.readdirSync(resultsPath).filter((f) => f.endsWith(".json")).sort().reverse();
4812
+ const files = fs11.readdirSync(resultsPath).filter((f) => f.endsWith(".json")).sort().reverse();
4687
4813
  if (files.length > 0) {
4688
- const latestFile = path12.join(resultsPath, files[0]);
4814
+ const latestFile = path13.join(resultsPath, files[0]);
4689
4815
  try {
4690
- const data = JSON.parse(fs10.readFileSync(latestFile, "utf-8"));
4816
+ const data = JSON.parse(fs11.readFileSync(latestFile, "utf-8"));
4691
4817
  if (Array.isArray(data)) {
4692
4818
  results.push(...data);
4693
4819
  } else if (data.results) {
@@ -4699,22 +4825,22 @@ function collectResults() {
4699
4825
  return results;
4700
4826
  }
4701
4827
  function saveResultToHistory(reportData) {
4702
- const resultsPath = path12.join(process.cwd(), RESULTS_DIR);
4703
- if (!fs10.existsSync(resultsPath)) {
4704
- fs10.mkdirSync(resultsPath, { recursive: true });
4828
+ const resultsPath = path13.join(process.cwd(), RESULTS_DIR2);
4829
+ if (!fs11.existsSync(resultsPath)) {
4830
+ fs11.mkdirSync(resultsPath, { recursive: true });
4705
4831
  }
4706
4832
  const timestamp = new Date(reportData.timestamp).toISOString().replace(/[:.]/g, "-");
4707
4833
  const fileName = `result-${timestamp}.json`;
4708
- const filePath = path12.join(resultsPath, fileName);
4709
- fs10.writeFileSync(filePath, JSON.stringify(reportData, null, 2), "utf-8");
4710
- const files = fs10.readdirSync(resultsPath).filter((f) => f.startsWith("result-") && f.endsWith(".json")).sort();
4834
+ const filePath = path13.join(resultsPath, fileName);
4835
+ fs11.writeFileSync(filePath, JSON.stringify(reportData, null, 2), "utf-8");
4836
+ const files = fs11.readdirSync(resultsPath).filter((f) => f.startsWith("result-") && f.endsWith(".json")).sort();
4711
4837
  while (files.length > 20) {
4712
4838
  const oldest = files.shift();
4713
- fs10.unlinkSync(path12.join(resultsPath, oldest));
4839
+ fs11.unlinkSync(path13.join(resultsPath, oldest));
4714
4840
  }
4715
4841
  }
4716
4842
  function displayReportResult(reportPath, data) {
4717
- const relativePath = path12.relative(process.cwd(), reportPath);
4843
+ const relativePath = path13.relative(process.cwd(), reportPath);
4718
4844
  console.log();
4719
4845
  console.log(chalk7.green(" \u2713 \u6D4B\u8BD5\u62A5\u544A\u5DF2\u751F\u6210"));
4720
4846
  console.log();
@@ -4761,19 +4887,19 @@ import chalk8 from "chalk";
4761
4887
  import ora7 from "ora";
4762
4888
 
4763
4889
  // src/services/visual.ts
4764
- import fs11 from "fs";
4765
- import path13 from "path";
4890
+ import fs12 from "fs";
4891
+ import path14 from "path";
4766
4892
  import pixelmatch from "pixelmatch";
4767
4893
  import { PNG } from "pngjs";
4768
4894
  function compareImages(baselinePath, currentPath, diffOutputPath, threshold = 0.1) {
4769
- if (!fs11.existsSync(baselinePath)) {
4895
+ if (!fs12.existsSync(baselinePath)) {
4770
4896
  throw new Error(`\u57FA\u7EBF\u56FE\u7247\u4E0D\u5B58\u5728: ${baselinePath}`);
4771
4897
  }
4772
- if (!fs11.existsSync(currentPath)) {
4898
+ if (!fs12.existsSync(currentPath)) {
4773
4899
  throw new Error(`\u5F53\u524D\u56FE\u7247\u4E0D\u5B58\u5728: ${currentPath}`);
4774
4900
  }
4775
- const baseline = PNG.sync.read(fs11.readFileSync(baselinePath));
4776
- const current = PNG.sync.read(fs11.readFileSync(currentPath));
4901
+ const baseline = PNG.sync.read(fs12.readFileSync(baselinePath));
4902
+ const current = PNG.sync.read(fs12.readFileSync(currentPath));
4777
4903
  if (baseline.width !== current.width || baseline.height !== current.height) {
4778
4904
  return {
4779
4905
  passed: false,
@@ -4801,11 +4927,11 @@ function compareImages(baselinePath, currentPath, diffOutputPath, threshold = 0.
4801
4927
  const passed = diffRatio <= threshold;
4802
4928
  let diffPath;
4803
4929
  if (diffPixels > 0) {
4804
- const diffDir = path13.dirname(diffOutputPath);
4805
- if (!fs11.existsSync(diffDir)) {
4806
- fs11.mkdirSync(diffDir, { recursive: true });
4930
+ const diffDir = path14.dirname(diffOutputPath);
4931
+ if (!fs12.existsSync(diffDir)) {
4932
+ fs12.mkdirSync(diffDir, { recursive: true });
4807
4933
  }
4808
- fs11.writeFileSync(diffOutputPath, PNG.sync.write(diff));
4934
+ fs12.writeFileSync(diffOutputPath, PNG.sync.write(diff));
4809
4935
  diffPath = diffOutputPath;
4810
4936
  }
4811
4937
  return {
@@ -4819,69 +4945,69 @@ function compareImages(baselinePath, currentPath, diffOutputPath, threshold = 0.
4819
4945
  };
4820
4946
  }
4821
4947
  function createBaseline(currentPath, baselinePath) {
4822
- if (!fs11.existsSync(currentPath)) {
4948
+ if (!fs12.existsSync(currentPath)) {
4823
4949
  throw new Error(`\u5F53\u524D\u622A\u56FE\u4E0D\u5B58\u5728: ${currentPath}`);
4824
4950
  }
4825
- const baselineDir = path13.dirname(baselinePath);
4826
- if (!fs11.existsSync(baselineDir)) {
4827
- fs11.mkdirSync(baselineDir, { recursive: true });
4951
+ const baselineDir = path14.dirname(baselinePath);
4952
+ if (!fs12.existsSync(baselineDir)) {
4953
+ fs12.mkdirSync(baselineDir, { recursive: true });
4828
4954
  }
4829
- fs11.copyFileSync(currentPath, baselinePath);
4955
+ fs12.copyFileSync(currentPath, baselinePath);
4830
4956
  return baselinePath;
4831
4957
  }
4832
4958
  function updateAllBaselines(currentDir, baselineDir) {
4833
4959
  const updated = [];
4834
- if (!fs11.existsSync(currentDir)) {
4960
+ if (!fs12.existsSync(currentDir)) {
4835
4961
  return updated;
4836
4962
  }
4837
- const files = fs11.readdirSync(currentDir).filter((f) => f.endsWith(".png"));
4963
+ const files = fs12.readdirSync(currentDir).filter((f) => f.endsWith(".png"));
4838
4964
  for (const file of files) {
4839
- const currentPath = path13.join(currentDir, file);
4840
- const baselinePath = path13.join(baselineDir, file);
4841
- const baselineDirAbs = path13.dirname(baselinePath);
4842
- if (!fs11.existsSync(baselineDirAbs)) {
4843
- fs11.mkdirSync(baselineDirAbs, { recursive: true });
4965
+ const currentPath = path14.join(currentDir, file);
4966
+ const baselinePath = path14.join(baselineDir, file);
4967
+ const baselineDirAbs = path14.dirname(baselinePath);
4968
+ if (!fs12.existsSync(baselineDirAbs)) {
4969
+ fs12.mkdirSync(baselineDirAbs, { recursive: true });
4844
4970
  }
4845
- fs11.copyFileSync(currentPath, baselinePath);
4971
+ fs12.copyFileSync(currentPath, baselinePath);
4846
4972
  updated.push(file);
4847
4973
  }
4848
4974
  return updated;
4849
4975
  }
4850
4976
  function cleanBaselines(baselineDir) {
4851
- if (!fs11.existsSync(baselineDir)) {
4977
+ if (!fs12.existsSync(baselineDir)) {
4852
4978
  return 0;
4853
4979
  }
4854
- const files = fs11.readdirSync(baselineDir).filter((f) => f.endsWith(".png"));
4980
+ const files = fs12.readdirSync(baselineDir).filter((f) => f.endsWith(".png"));
4855
4981
  let count = 0;
4856
4982
  for (const file of files) {
4857
- fs11.unlinkSync(path13.join(baselineDir, file));
4983
+ fs12.unlinkSync(path14.join(baselineDir, file));
4858
4984
  count++;
4859
4985
  }
4860
4986
  return count;
4861
4987
  }
4862
4988
  function cleanDiffs(diffDir) {
4863
- if (!fs11.existsSync(diffDir)) {
4989
+ if (!fs12.existsSync(diffDir)) {
4864
4990
  return 0;
4865
4991
  }
4866
- const files = fs11.readdirSync(diffDir).filter((f) => f.endsWith(".png"));
4992
+ const files = fs12.readdirSync(diffDir).filter((f) => f.endsWith(".png"));
4867
4993
  let count = 0;
4868
4994
  for (const file of files) {
4869
- fs11.unlinkSync(path13.join(diffDir, file));
4995
+ fs12.unlinkSync(path14.join(diffDir, file));
4870
4996
  count++;
4871
4997
  }
4872
4998
  return count;
4873
4999
  }
4874
5000
  function compareDirectories(baselineDir, currentDir, diffDir, threshold = 0.1) {
4875
5001
  const results = [];
4876
- if (!fs11.existsSync(currentDir)) {
5002
+ if (!fs12.existsSync(currentDir)) {
4877
5003
  return results;
4878
5004
  }
4879
- const currentFiles = fs11.readdirSync(currentDir).filter((f) => f.endsWith(".png"));
5005
+ const currentFiles = fs12.readdirSync(currentDir).filter((f) => f.endsWith(".png"));
4880
5006
  for (const file of currentFiles) {
4881
- const currentPath = path13.join(currentDir, file);
4882
- const baselinePath = path13.join(baselineDir, file);
4883
- const diffPath = path13.join(diffDir, file);
4884
- if (!fs11.existsSync(baselinePath)) {
5007
+ const currentPath = path14.join(currentDir, file);
5008
+ const baselinePath = path14.join(baselineDir, file);
5009
+ const diffPath = path14.join(diffDir, file);
5010
+ if (!fs12.existsSync(baselinePath)) {
4885
5011
  createBaseline(currentPath, baselinePath);
4886
5012
  results.push({
4887
5013
  passed: true,
@@ -4913,8 +5039,8 @@ function compareDirectories(baselineDir, currentDir, diffDir, threshold = 0.1) {
4913
5039
  }
4914
5040
 
4915
5041
  // src/commands/visual.ts
4916
- import fs12 from "fs";
4917
- import path14 from "path";
5042
+ import fs13 from "fs";
5043
+ import path15 from "path";
4918
5044
  function registerVisualCommand(program2) {
4919
5045
  program2.command("visual").description("\u89C6\u89C9\u56DE\u5F52\u6D4B\u8BD5 - \u622A\u56FE\u6BD4\u5BF9\u4E0E\u57FA\u7EBF\u7BA1\u7406").argument("<action>", "\u64CD\u4F5C\u7C7B\u578B (test|approve|clean)").option("--threshold <number>", "\u50CF\u7D20\u5DEE\u5F02\u9608\u503C (0-1)", "0.1").action(async (action, options) => {
4920
5046
  try {
@@ -4989,12 +5115,12 @@ async function runVisualTest(threshold, baselineDir, diffDir, config) {
4989
5115
  }
4990
5116
  function findCurrentScreenshotsDir(baselineDir) {
4991
5117
  const possibleDirs = [
4992
- path14.join(process.cwd(), "test-results"),
4993
- path14.join(process.cwd(), "tests", "visual", "current"),
4994
- path14.join(process.cwd(), baselineDir, "..", "current")
5118
+ path15.join(process.cwd(), "test-results"),
5119
+ path15.join(process.cwd(), "tests", "visual", "current"),
5120
+ path15.join(process.cwd(), baselineDir, "..", "current")
4995
5121
  ];
4996
5122
  for (const dir of possibleDirs) {
4997
- if (fs12.existsSync(dir)) {
5123
+ if (fs13.existsSync(dir)) {
4998
5124
  const pngs = findPngFiles(dir);
4999
5125
  if (pngs.length > 0) return dir;
5000
5126
  }
@@ -5004,10 +5130,10 @@ function findCurrentScreenshotsDir(baselineDir) {
5004
5130
  function findPngFiles(dir) {
5005
5131
  const files = [];
5006
5132
  function walk(d) {
5007
- if (!fs12.existsSync(d)) return;
5008
- const entries = fs12.readdirSync(d, { withFileTypes: true });
5133
+ if (!fs13.existsSync(d)) return;
5134
+ const entries = fs13.readdirSync(d, { withFileTypes: true });
5009
5135
  for (const entry of entries) {
5010
- const fullPath = path14.join(d, entry.name);
5136
+ const fullPath = path15.join(d, entry.name);
5011
5137
  if (entry.isDirectory() && entry.name !== "node_modules") {
5012
5138
  walk(fullPath);
5013
5139
  } else if (entry.name.endsWith(".png")) {
@@ -5036,7 +5162,7 @@ function displayVisualResults(results, threshold) {
5036
5162
  console.log();
5037
5163
  console.log(chalk8.green(" \u901A\u8FC7\u7684\u622A\u56FE:"));
5038
5164
  for (const result of passed) {
5039
- const name = path14.basename(result.baselinePath);
5165
+ const name = path15.basename(result.baselinePath);
5040
5166
  if (result.totalPixels > 0) {
5041
5167
  const diffPct = (result.diffRatio * 100).toFixed(2);
5042
5168
  console.log(chalk8.green(` \u2713 ${name} (\u5DEE\u5F02: ${diffPct}%)`));
@@ -5049,7 +5175,7 @@ function displayVisualResults(results, threshold) {
5049
5175
  console.log();
5050
5176
  console.log(chalk8.red(" \u5931\u8D25\u7684\u622A\u56FE:"));
5051
5177
  for (const result of failed) {
5052
- const name = path14.basename(result.baselinePath);
5178
+ const name = path15.basename(result.baselinePath);
5053
5179
  if (result.diffPixels === -1) {
5054
5180
  console.log(chalk8.red(` \u2717 ${name} (\u5C3A\u5BF8\u4E0D\u5339\u914D)`));
5055
5181
  } else {
@@ -5057,7 +5183,7 @@ function displayVisualResults(results, threshold) {
5057
5183
  console.log(chalk8.red(` \u2717 ${name} (\u5DEE\u5F02: ${diffPct}%)`));
5058
5184
  }
5059
5185
  if (result.diffPath) {
5060
- console.log(chalk8.gray(` \u5DEE\u5F02\u56FE: ${path14.relative(process.cwd(), result.diffPath)}`));
5186
+ console.log(chalk8.gray(` \u5DEE\u5F02\u56FE: ${path15.relative(process.cwd(), result.diffPath)}`));
5061
5187
  }
5062
5188
  }
5063
5189
  console.log();
@@ -5103,8 +5229,8 @@ import chalk9 from "chalk";
5103
5229
  import inquirer4 from "inquirer";
5104
5230
  import ora8 from "ora";
5105
5231
  import { execFile as execFile4 } from "child_process";
5106
- import fs13 from "fs";
5107
- import path15 from "path";
5232
+ import fs14 from "fs";
5233
+ import path16 from "path";
5108
5234
  var DEPENDENCY_GROUPS = [
5109
5235
  {
5110
5236
  name: "Vitest (\u5355\u5143/\u7EC4\u4EF6/API\u6D4B\u8BD5)",
@@ -5138,7 +5264,7 @@ function registerSetupCommand(program2) {
5138
5264
  async function executeSetup(options) {
5139
5265
  console.log(chalk9.cyan("\n QAT \u4F9D\u8D56\u5B89\u88C5\u5668\n"));
5140
5266
  const projectInfo = detectProject();
5141
- if (!fs13.existsSync(path15.join(process.cwd(), "package.json"))) {
5267
+ if (!fs14.existsSync(path16.join(process.cwd(), "package.json"))) {
5142
5268
  throw new Error("\u672A\u627E\u5230 package.json\uFF0C\u8BF7\u5728\u9879\u76EE\u6839\u76EE\u5F55\u6267\u884C\u6B64\u547D\u4EE4");
5143
5269
  }
5144
5270
  if (projectInfo.frameworkConfidence > 0) {
@@ -5172,8 +5298,8 @@ async function executeSetup(options) {
5172
5298
  }
5173
5299
  ]);
5174
5300
  if (chooseDir !== "root") {
5175
- installDir = path15.join(process.cwd(), chooseDir);
5176
- if (!fs13.existsSync(path15.join(installDir, "package.json"))) {
5301
+ installDir = path16.join(process.cwd(), chooseDir);
5302
+ if (!fs14.existsSync(path16.join(installDir, "package.json"))) {
5177
5303
  throw new Error(`${chooseDir} \u4E0B\u6CA1\u6709 package.json`);
5178
5304
  }
5179
5305
  }
@@ -5212,7 +5338,7 @@ ${allPackages.map((p) => ` - ${p}`).join("\n")}`,
5212
5338
  const pm = getPackageManager(projectInfo.packageManager);
5213
5339
  const installCmd = pm === "npm" ? "npm install -D" : pm === "yarn" ? "yarn add -D" : pm === "pnpm" ? "pnpm add -D" : "bun add -D";
5214
5340
  for (const group of selectedGroups) {
5215
- const dirHint = installDir !== process.cwd() ? ` (\u5728 ${path15.relative(process.cwd(), installDir) || installDir})` : "";
5341
+ const dirHint = installDir !== process.cwd() ? ` (\u5728 ${path16.relative(process.cwd(), installDir) || installDir})` : "";
5216
5342
  console.log(chalk9.white(` ${installCmd} ${group.packages.join(" ")}${dirHint}`));
5217
5343
  if (group.postInstall) {
5218
5344
  for (const cmd of group.postInstall) {
@@ -5493,7 +5619,7 @@ async function executeChange(_options) {
5493
5619
  }
5494
5620
 
5495
5621
  // src/cli.ts
5496
- var VERSION = "0.2.7";
5622
+ var VERSION = "0.2.98";
5497
5623
  function printLogo() {
5498
5624
  const logo = `
5499
5625
  ${chalk12.bold.cyan(" ___ _ _ _ _ _____ _ _ ")}