qat-cli 0.3.3 → 0.3.4

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.js CHANGED
@@ -8,10 +8,10 @@ import {
8
8
 
9
9
  // src/cli.ts
10
10
  import { Command } from "commander";
11
- import chalk12 from "chalk";
11
+ import chalk13 from "chalk";
12
12
 
13
13
  // src/commands/init.ts
14
- import chalk2 from "chalk";
14
+ import chalk3 from "chalk";
15
15
  import inquirer from "inquirer";
16
16
  import ora from "ora";
17
17
  import fs6 from "fs";
@@ -843,6 +843,15 @@ var NoopAIProvider = class {
843
843
  };
844
844
 
845
845
  // src/ai/openai-provider.ts
846
+ import chalk2 from "chalk";
847
+ function isDebug() {
848
+ return process.env.QAT_DEBUG === "true";
849
+ }
850
+ function debugLog(tag, ...args) {
851
+ if (!isDebug()) return;
852
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().slice(11, 19);
853
+ console.error(chalk2.gray(`[DEBUG ${timestamp}] [${tag}]`), ...args);
854
+ }
846
855
  var OpenAICompatibleProvider = class {
847
856
  constructor(config) {
848
857
  this.capabilities = {
@@ -856,25 +865,20 @@ var OpenAICompatibleProvider = class {
856
865
  this.baseUrl = config.baseUrl || this.getDefaultBaseUrl(config.provider);
857
866
  }
858
867
  async generateTest(req) {
868
+ debugLog("GENERATE", `type=${req.type} target=${req.target}`);
859
869
  const systemPrompt = this.buildGenerateTestSystemPrompt(req);
860
870
  const userPrompt = this.buildGenerateTestUserPrompt(req);
861
871
  const content = await this.chat(systemPrompt, userPrompt);
862
- return this.parseGenerateTestResponse(content);
872
+ const result = this.parseGenerateTestResponse(content);
873
+ debugLog("GENERATE", `done code=${result.code.length}chars confidence=${result.confidence}`);
874
+ return result;
863
875
  }
864
876
  async analyzeResult(req) {
865
- const systemPrompt = `\u4F60\u662F\u4E00\u4E2A\u4E13\u4E1A\u7684\u6D4B\u8BD5\u5206\u6790\u4E13\u5BB6\u3002\u5206\u6790\u6D4B\u8BD5\u8FD0\u884C\u7ED3\u679C\uFF0C\u627E\u51FA\u95EE\u9898\u6839\u56E0\uFF0C\u7ED9\u51FA\u5177\u4F53\u53EF\u64CD\u4F5C\u7684\u6539\u8FDB\u5EFA\u8BAE\u3002
866
- \u8F93\u51FA\u683C\u5F0F\uFF1A
867
- 1. \u5206\u6790\u6458\u8981\uFF081-3\u53E5\u8BDD\uFF09
868
- 2. \u6539\u8FDB\u5EFA\u8BAE\u5217\u8868\uFF08\u6BCF\u6761\u5EFA\u8BAE\u5177\u4F53\u3001\u53EF\u64CD\u4F5C\uFF09`;
869
- const resultSummary = req.testResults.map((r) => {
870
- const failed = r.suites.flatMap((s) => s.tests.filter((t) => t.status === "failed"));
871
- return `\u7C7B\u578B: ${r.type}, \u72B6\u6001: ${r.status}, \u8017\u65F6: ${r.duration}ms, \u5931\u8D25\u7528\u4F8B: ${failed.length}`;
872
- }).join("\n");
873
- const errorDetails = req.errorLogs?.join("\n") || req.testResults.flatMap((r) => r.suites.flatMap((s) => s.tests.filter((t) => t.status === "failed" && t.error))).map((t) => `[${t.name}] ${t.error?.message}`).join("\n") || "\u65E0\u9519\u8BEF\u8BE6\u60C5";
874
- const userPrompt = `\u6D4B\u8BD5\u7ED3\u679C:
875
- ${resultSummary}
876
-
877
- \u9519\u8BEF\u8BE6\u60C5:
877
+ const systemPrompt = `\u6D4B\u8BD5\u5206\u6790\u4E13\u5BB6\u3002\u627E\u95EE\u9898\u6839\u56E0\uFF0C\u7ED9\u53EF\u64CD\u4F5C\u5EFA\u8BAE\u3002
878
+ \u8F93\u51FA:1.\u6458\u8981(1-3\u53E5) 2.\u5EFA\u8BAE\u5217\u8868`;
879
+ const failed = req.testResults.flatMap((r) => r.suites.flatMap((s) => s.tests.filter((t) => t.status === "failed")));
880
+ const errorDetails = req.errorLogs?.join("\n") || failed.map((t) => `[${t.name}] ${t.error?.message}`).join("\n") || "\u65E0";
881
+ const userPrompt = `\u5931\u8D25:${failed.length}
878
882
  ${errorDetails}`;
879
883
  const content = await this.chat(systemPrompt, userPrompt);
880
884
  return {
@@ -884,23 +888,22 @@ ${errorDetails}`;
884
888
  };
885
889
  }
886
890
  async suggestFix(error) {
887
- const systemPrompt = `\u4F60\u662F\u4E00\u4E2A\u4E13\u4E1A\u7684\u4EE3\u7801\u4FEE\u590D\u4E13\u5BB6\u3002\u6839\u636E\u6D4B\u8BD5\u9519\u8BEF\u4FE1\u606F\uFF0C\u7ED9\u51FA\u5177\u4F53\u7684\u4FEE\u590D\u5EFA\u8BAE\u3002
888
- \u6BCF\u6761\u5EFA\u8BAE\u5E94\u8BE5\u5305\u542B\uFF1A
889
- 1. \u95EE\u9898\u5B9A\u4F4D
890
- 2. \u4FEE\u590D\u65B9\u6848
891
- 3. \u793A\u4F8B\u4EE3\u7801\uFF08\u5982\u679C\u9002\u7528\uFF09`;
892
- const userPrompt = `\u9519\u8BEF\u4FE1\u606F: ${error.message}
893
- ${error.stack ? `\u5806\u6808: ${error.stack}` : ""}
894
- ${error.expected ? `\u671F\u671B\u503C: ${error.expected}` : ""}
895
- ${error.actual ? `\u5B9E\u9645\u503C: ${error.actual}` : ""}`;
891
+ const systemPrompt = `\u4EE3\u7801\u4FEE\u590D\u4E13\u5BB6\u3002\u7ED9\u51FA:1.\u95EE\u9898\u5B9A\u4F4D 2.\u4FEE\u590D\u65B9\u6848 3.\u793A\u4F8B\u4EE3\u7801`;
892
+ const userPrompt = `\u9519\u8BEF:${error.message}${error.stack ? `
893
+ \u5806\u6808:${error.stack}` : ""}${error.expected ? `
894
+ \u671F\u671B:${error.expected}` : ""}${error.actual ? `
895
+ \u5B9E\u9645:${error.actual}` : ""}`;
896
896
  const content = await this.chat(systemPrompt, userPrompt);
897
897
  return content.split("\n").filter((l) => l.trim().startsWith("-") || l.trim().startsWith("\u2022") || l.trim().match(/^\d+\./)).map((l) => l.replace(/^[-•\d.]+\s*/, "").trim()).filter(Boolean);
898
898
  }
899
899
  async reviewTest(req) {
900
+ debugLog("REVIEW", `target=${req.target} type=${req.testType}`);
900
901
  const systemPrompt = this.buildReviewTestSystemPrompt(req);
901
902
  const userPrompt = this.buildReviewTestUserPrompt(req);
902
903
  const content = await this.chat(systemPrompt, userPrompt);
903
- return this.parseReviewTestResponse(content);
904
+ const result = this.parseReviewTestResponse(content);
905
+ debugLog("REVIEW", `approved=${result.approved} score=${result.score} feedback=${result.feedback}`);
906
+ return result;
904
907
  }
905
908
  // ─── 内部方法 ──────────────────────────────────────────────
906
909
  /**
@@ -964,8 +967,9 @@ ${error.actual ? `\u5B9E\u9645\u503C: ${error.actual}` : ""}`;
964
967
  return { ok: false, message: `\u8FDE\u63A5\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`, latencyMs };
965
968
  }
966
969
  }
967
- async chat(systemPrompt, userPrompt) {
970
+ async chat(systemPrompt, userPrompt, retries = 2) {
968
971
  const url = `${this.baseUrl}/chat/completions`;
972
+ const useStream = isDebug();
969
973
  const body = {
970
974
  model: this.model,
971
975
  messages: [
@@ -975,101 +979,189 @@ ${error.actual ? `\u5B9E\u9645\u503C: ${error.actual}` : ""}`;
975
979
  temperature: 0.3,
976
980
  max_tokens: 4096
977
981
  };
982
+ if (useStream) {
983
+ body.stream = true;
984
+ }
978
985
  const headers = {
979
986
  "Content-Type": "application/json"
980
987
  };
981
988
  if (this.apiKey) {
982
989
  headers["Authorization"] = `Bearer ${this.apiKey}`;
983
990
  }
984
- const response = await fetch(url, {
985
- method: "POST",
986
- headers,
987
- body: JSON.stringify(body),
988
- signal: AbortSignal.timeout(6e4)
989
- // 60s timeout
990
- });
991
- if (!response.ok) {
992
- const text = await response.text().catch(() => "");
993
- throw new Error(`AI API \u8BF7\u6C42\u5931\u8D25 (${response.status}): ${text.slice(0, 500)}`);
991
+ debugLog("REQUEST", `POST ${url}`);
992
+ debugLog("REQUEST", `model=${this.model} stream=${useStream}`);
993
+ debugLog("SYSTEM", systemPrompt.length > 500 ? `${systemPrompt.slice(0, 500)}...` : systemPrompt);
994
+ debugLog("USER", userPrompt.length > 1e3 ? `${userPrompt.slice(0, 1e3)}...` : userPrompt);
995
+ let lastError = null;
996
+ for (let attempt = 0; attempt <= retries; attempt++) {
997
+ try {
998
+ if (attempt > 0) {
999
+ debugLog("RETRY", `\u7B2C${attempt}\u6B21\u91CD\u8BD5...`);
1000
+ }
1001
+ const response = await fetch(url, {
1002
+ method: "POST",
1003
+ headers,
1004
+ body: JSON.stringify(body),
1005
+ signal: AbortSignal.timeout(12e4)
1006
+ // 120s timeout
1007
+ });
1008
+ if (!response.ok) {
1009
+ const text = await response.text().catch(() => "");
1010
+ if ((response.status === 429 || response.status >= 500) && attempt < retries) {
1011
+ const delay = Math.min(1e3 * Math.pow(2, attempt), 8e3);
1012
+ debugLog("RETRY", `HTTP ${response.status}, ${delay}ms\u540E\u91CD\u8BD5`);
1013
+ await new Promise((r) => setTimeout(r, delay));
1014
+ lastError = new Error(`AI API \u8BF7\u6C42\u5931\u8D25 (${response.status}): ${text.slice(0, 200)}`);
1015
+ continue;
1016
+ }
1017
+ throw new Error(`AI API \u8BF7\u6C42\u5931\u8D25 (${response.status}): ${text.slice(0, 500)}`);
1018
+ }
1019
+ if (useStream && response.body) {
1020
+ const content = await this.readStream(response.body);
1021
+ debugLog("RESPONSE", content.length > 500 ? `${content.slice(0, 500)}...` : content);
1022
+ return content;
1023
+ }
1024
+ const data = await response.json();
1025
+ if (!data.choices?.[0]?.message?.content) {
1026
+ throw new Error("AI API \u8FD4\u56DE\u7A7A\u54CD\u5E94");
1027
+ }
1028
+ debugLog("RESPONSE", `tokens: prompt=${data.usage?.prompt_tokens} completion=${data.usage?.completion_tokens} total=${data.usage?.total_tokens}`);
1029
+ debugLog("RESPONSE", data.choices[0].message.content.length > 500 ? `${data.choices[0].message.content.slice(0, 500)}...` : data.choices[0].message.content);
1030
+ return data.choices[0].message.content;
1031
+ } catch (error) {
1032
+ if (error instanceof Error && error.name === "TimeoutError" && attempt < retries) {
1033
+ debugLog("TIMEOUT", `\u7B2C${attempt}\u6B21\u8D85\u65F6\uFF0C\u91CD\u8BD5\u4E2D...`);
1034
+ lastError = error;
1035
+ continue;
1036
+ }
1037
+ throw error;
1038
+ }
994
1039
  }
995
- const data = await response.json();
996
- if (!data.choices?.[0]?.message?.content) {
997
- throw new Error("AI API \u8FD4\u56DE\u7A7A\u54CD\u5E94");
1040
+ throw lastError || new Error("AI API \u8BF7\u6C42\u5931\u8D25");
1041
+ }
1042
+ /**
1043
+ * 读取 SSE 流式响应,实时输出内容
1044
+ */
1045
+ async readStream(body) {
1046
+ const chunks = [];
1047
+ const decoder = new TextDecoder();
1048
+ const reader = body.getReader();
1049
+ let buffer = "";
1050
+ let lineCount = 0;
1051
+ try {
1052
+ while (true) {
1053
+ const { done, value } = await reader.read();
1054
+ if (done) break;
1055
+ buffer += decoder.decode(value, { stream: true });
1056
+ const lines = buffer.split("\n");
1057
+ buffer = lines.pop() || "";
1058
+ for (const line of lines) {
1059
+ const trimmed = line.trim();
1060
+ if (!trimmed || trimmed === "data: [DONE]") continue;
1061
+ if (!trimmed.startsWith("data: ")) continue;
1062
+ try {
1063
+ const json = JSON.parse(trimmed.slice(6));
1064
+ const delta = json.choices?.[0]?.delta?.content;
1065
+ if (delta) {
1066
+ chunks.push(delta);
1067
+ lineCount++;
1068
+ process.stderr.write(chalk2.gray(delta));
1069
+ if (lineCount % 20 === 0) {
1070
+ process.stderr.write("\n");
1071
+ }
1072
+ }
1073
+ if (json.choices?.[0]?.finish_reason === "stop") {
1074
+ debugLog("STREAM", "\u5B8C\u6210");
1075
+ }
1076
+ } catch {
1077
+ }
1078
+ }
1079
+ }
1080
+ } finally {
1081
+ reader.releaseLock();
998
1082
  }
999
- return data.choices[0].message.content;
1083
+ if (chunks.length > 0) {
1084
+ process.stderr.write("\n");
1085
+ }
1086
+ return chunks.join("");
1087
+ }
1088
+ /**
1089
+ * 压缩源码:保留签名和关键逻辑,剔除注释、空行、样式块
1090
+ * 目标:在保留准确性的前提下减少 token 消耗
1091
+ */
1092
+ compressSourceCode(code, maxLength = 3e3) {
1093
+ let compressed = code;
1094
+ compressed = compressed.replace(/<style[^>]*>[\s\S]*?<\/style>/gi, "");
1095
+ compressed = compressed.replace(/<template[^>]*>([\s\S]*?)<\/template>/gi, (_match, content) => {
1096
+ return `<template>${content.replace(/\s*(?:class|style)\s*=\s*["'][^"']*["']/gi, "")}</template>`;
1097
+ });
1098
+ compressed = compressed.replace(/\/\*[\s\S]*?\*\//g, "");
1099
+ compressed = compressed.replace(/(^|[^:])(\/\/.*$)/gm, "$1");
1100
+ compressed = compressed.replace(/\n\s*\n\s*\n/g, "\n\n");
1101
+ compressed = compressed.split("\n").map((line) => line.trimEnd()).join("\n").trim();
1102
+ if (compressed.length > maxLength) {
1103
+ const scriptMatch = compressed.match(/<script[^>]*>([\s\S]*?)<\/script>/i);
1104
+ const templateMatch = compressed.match(/<template[^>]*>([\s\S]*?)<\/template>/i);
1105
+ if (scriptMatch) {
1106
+ let scriptPart = scriptMatch[1].trim();
1107
+ scriptPart = compressFunctionBodies(scriptPart, maxLength * 0.7);
1108
+ const templatePart = templateMatch ? `<template>${templateMatch[1].replace(/\s+/g, " ").trim().slice(0, 300)}...</template>` : "";
1109
+ compressed = `${templatePart}
1110
+ <script${scriptMatch[0].match(/<script[^>]*>/)?.[0]?.slice(7) || ">"}>${scriptPart}</script>`;
1111
+ } else {
1112
+ compressed = compressFunctionBodies(compressed, maxLength);
1113
+ }
1114
+ }
1115
+ return compressed;
1000
1116
  }
1001
1117
  buildGenerateTestSystemPrompt(req) {
1002
1118
  const typeMap = {
1003
- unit: "\u5355\u5143\u6D4B\u8BD5\uFF08Vitest + @vue/test-utils\uFF09",
1004
- component: "\u7EC4\u4EF6\u6D4B\u8BD5\uFF08Vitest + @vue/test-utils + mount\uFF09",
1005
- e2e: "E2E\u7AEF\u5230\u7AEF\u6D4B\u8BD5\uFF08Playwright\uFF09",
1006
- api: "API\u63A5\u53E3\u6D4B\u8BD5\uFF08Vitest + fetch\uFF09",
1007
- visual: "\u89C6\u89C9\u56DE\u5F52\u6D4B\u8BD5\uFF08Playwright screenshot\uFF09",
1008
- performance: "\u6027\u80FD\u6D4B\u8BD5\uFF08Playwright + performance metrics\uFF09"
1119
+ unit: "\u5355\u5143\u6D4B\u8BD5(Vitest)",
1120
+ component: "\u7EC4\u4EF6\u6D4B\u8BD5(Vitest+@vue/test-utils)",
1121
+ e2e: "E2E\u6D4B\u8BD5(Playwright)",
1122
+ api: "API\u6D4B\u8BD5(Vitest+fetch)",
1123
+ visual: "\u89C6\u89C9\u56DE\u5F52\u6D4B\u8BD5(Playwright)",
1124
+ performance: "\u6027\u80FD\u6D4B\u8BD5(Playwright)"
1009
1125
  };
1010
- return `\u4F60\u662F\u4E00\u4E2A\u4E13\u4E1A\u7684\u524D\u7AEF\u6D4B\u8BD5\u5DE5\u7A0B\u5E08\uFF0C\u64C5\u957F\u7F16\u5199\u9AD8\u8D28\u91CF\u7684${typeMap[req.type] || req.type}\u3002
1011
- \u8981\u6C42\uFF1A
1012
- 1. \u53EA\u8F93\u51FA\u6D4B\u8BD5\u4EE3\u7801\uFF0C\u4E0D\u8981\u591A\u4F59\u7684\u89E3\u91CA
1013
- 2. \u4EE3\u7801\u5FC5\u987B\u53EF\u76F4\u63A5\u8FD0\u884C\uFF0C\u5305\u542B\u6240\u6709\u5FC5\u8981\u7684 import
1014
- 3. \u6D4B\u8BD5\u7528\u4F8B\u8986\u76D6\uFF1A\u6B63\u5E38\u8DEF\u5F84\u3001\u8FB9\u754C\u6761\u4EF6\u3001\u9519\u8BEF\u5904\u7406
1015
- 4. \u4F7F\u7528\u4E2D\u6587\u63CF\u8FF0 it/test \u5757\u540D\u79F0
1016
- 5. Vue \u7EC4\u4EF6\u6D4B\u8BD5\u4F7F\u7528 @vue/test-utils \u7684 mount
1017
- 6. \u5982\u679C\u6709 props/emits \u4FE1\u606F\uFF0C\u52A1\u5FC5\u9488\u5BF9\u6BCF\u4E2A prop \u548C emit \u751F\u6210\u6D4B\u8BD5`;
1126
+ return `\u4F60\u662F\u524D\u7AEF\u6D4B\u8BD5\u5DE5\u7A0B\u5E08\uFF0C\u7F16\u5199${typeMap[req.type] || req.type}\u3002
1127
+ \u89C4\u5219:1.\u53EA\u8F93\u51FA\u6D4B\u8BD5\u4EE3\u7801 2.\u5305\u542B\u6240\u6709import 3.\u8986\u76D6\u6B63\u5E38/\u8FB9\u754C/\u9519\u8BEF 4.it\u540D\u7528\u4E2D\u6587 5.Vue\u7528mount 6.\u5FC5\u6D4B\u6BCF\u4E2Aprop\u548Cemit`;
1018
1128
  }
1019
1129
  buildGenerateTestUserPrompt(req) {
1020
1130
  const importPath = this.computeTestImportPath(req.type, req.target);
1021
- let prompt = `\u8BF7\u4E3A\u4EE5\u4E0B\u6587\u4EF6\u751F\u6210${req.type}\u6D4B\u8BD5\u4EE3\u7801:
1022
- \u76EE\u6807\u6587\u4EF6: ${req.target}
1023
- \u6D4B\u8BD5\u6587\u4EF6\u5C06\u653E\u5728: ${this.getTestOutputDir(req.type)}/
1024
- \u6B63\u786E\u7684 import \u8DEF\u5F84: ${importPath}
1025
-
1026
- \u91CD\u8981\uFF1Aimport \u8BED\u53E5\u4E2D\u5FC5\u987B\u4F7F\u7528\u4E0A\u8FF0\u6B63\u786E\u7684\u76F8\u5BF9\u8DEF\u5F84 ${importPath}\uFF0C\u4E0D\u8981\u4F7F\u7528 ${req.target} \u6216\u5176\u4ED6\u8DEF\u5F84\uFF01
1131
+ let prompt = `\u4E3A${req.target}\u751F\u6210${req.type}\u6D4B\u8BD5\u3002import\u8DEF\u5F84:${importPath}
1027
1132
  `;
1028
1133
  if (req.analysis) {
1029
- prompt += "\n\u6E90\u7801\u5206\u6790\u7ED3\u679C:\n";
1134
+ const parts = [];
1030
1135
  if (req.analysis.exports?.length > 0) {
1031
- prompt += `\u5BFC\u51FA\u9879:
1032
- ${req.analysis.exports.map((e) => {
1033
- const params = e.params?.length ? `(${e.params.join(", ")})` : "";
1034
- const asyncFlag = e.isAsync ? "async " : "";
1035
- return ` - ${asyncFlag}${e.name}${params} [${e.kind}]`;
1036
- }).join("\n")}
1037
- `;
1136
+ parts.push(`\u5BFC\u51FA:${req.analysis.exports.map((e) => {
1137
+ const p = e.params?.length ? `(${e.params.join(",")})` : "";
1138
+ return `${e.isAsync ? "async " : ""}${e.name}${p}[${e.kind}]`;
1139
+ }).join(",")}`);
1038
1140
  }
1039
1141
  if (req.analysis.props?.length) {
1040
- prompt += `Props:
1041
- ${req.analysis.props.map(
1042
- (p) => ` - ${p.name}: ${p.type}${p.required ? " (\u5FC5\u586B)" : " (\u53EF\u9009)"}`
1043
- ).join("\n")}
1044
- `;
1142
+ parts.push(`Props:${req.analysis.props.map((p) => `${p.name}:${p.type}${p.required ? "!" : "?"}`).join(",")}`);
1045
1143
  }
1046
1144
  if (req.analysis.emits?.length) {
1047
- prompt += `Emits:
1048
- ${req.analysis.emits.map(
1049
- (e) => ` - ${e.name}${e.params?.length ? `(${e.params.join(", ")})` : ""}`
1050
- ).join("\n")}
1051
- `;
1145
+ parts.push(`Emits:${req.analysis.emits.map((e) => `${e.name}(${e.params?.join(",") || ""})`).join(",")}`);
1052
1146
  }
1053
1147
  if (req.analysis.methods?.length) {
1054
- prompt += `Methods: ${req.analysis.methods.join(", ")}
1055
- `;
1148
+ parts.push(`Methods:${req.analysis.methods.join(",")}`);
1056
1149
  }
1057
1150
  if (req.analysis.computed?.length) {
1058
- prompt += `Computed: ${req.analysis.computed.join(", ")}
1059
- `;
1151
+ parts.push(`Computed:${req.analysis.computed.join(",")}`);
1060
1152
  }
1153
+ prompt += parts.join("\n") + "\n";
1061
1154
  }
1062
1155
  if (req.context) {
1063
1156
  prompt += `
1064
- \u6E90\u7801\u5185\u5BB9:
1065
- \`\`\`typescript
1066
- ${req.context}
1157
+ \u6E90\u7801:
1158
+ \`\`\`
1159
+ ${this.compressSourceCode(req.context)}
1067
1160
  \`\`\`
1068
1161
  `;
1069
1162
  }
1070
1163
  if (req.framework) {
1071
- prompt += `
1072
- \u6846\u67B6: ${req.framework}`;
1164
+ prompt += `\u6846\u67B6:${req.framework}`;
1073
1165
  }
1074
1166
  return prompt;
1075
1167
  }
@@ -1099,20 +1191,6 @@ ${req.context}
1099
1191
  }
1100
1192
  return `${prefix}${cleanPath}`;
1101
1193
  }
1102
- /**
1103
- * 获取测试输出目录
1104
- */
1105
- getTestOutputDir(testType) {
1106
- const dirMap = {
1107
- unit: "tests/unit",
1108
- component: "tests/component",
1109
- e2e: "tests/e2e",
1110
- api: "tests/api",
1111
- visual: "tests/visual",
1112
- performance: "tests/e2e"
1113
- };
1114
- return dirMap[testType] || "tests/unit";
1115
- }
1116
1194
  parseGenerateTestResponse(content) {
1117
1195
  const codeBlockMatch = content.match(/```(?:typescript|ts|javascript|js)?\s*\n([\s\S]*?)```/);
1118
1196
  const code = codeBlockMatch ? codeBlockMatch[1].trim() : content.replace(/^(?:```[\s\S]*?\n)?/, "").replace(/\n?```$/, "").trim();
@@ -1124,69 +1202,49 @@ ${req.context}
1124
1202
  };
1125
1203
  }
1126
1204
  buildReviewTestSystemPrompt(_req) {
1127
- return `\u4F60\u662F\u4E00\u4F4D\u4E25\u8C28\u7684\u6D4B\u8BD5\u5BA1\u8BA1\u4E13\u5BB6\u3002\u4F60\u7684\u804C\u8D23\u662F\u5BA1\u67E5 AI \u751F\u6210\u7684\u6D4B\u8BD5\u7528\u4F8B\u662F\u5426\u4E0E\u6E90\u7801\u8D34\u5207\u4E14\u51C6\u786E\u3002
1128
-
1129
- \u5BA1\u67E5\u6807\u51C6\uFF1A
1130
- 1. **\u6D4B\u8BD5\u7C7B\u578B\u5339\u914D**\uFF1A\u6D4B\u8BD5\u7C7B\u578B\u662F\u5426\u4E0E\u6E90\u7801\u6587\u4EF6\u6027\u8D28\u5339\u914D\uFF08\u5982 .vue \u5E94\u4E3A\u7EC4\u4EF6\u6D4B\u8BD5\uFF0Cutils \u5E94\u4E3A\u5355\u5143\u6D4B\u8BD5\uFF09
1131
- 2. **\u8986\u76D6\u5B8C\u6574\u6027**\uFF1A\u662F\u5426\u8986\u76D6\u4E86\u6E90\u7801\u4E2D\u7684\u6838\u5FC3\u5BFC\u51FA\u9879\uFF08\u51FD\u6570\u3001\u7EC4\u4EF6\u7684 props/emits/methods\uFF09
1132
- 3. **\u65AD\u8A00\u6709\u6548\u6027**\uFF1A\u65AD\u8A00\u662F\u5426\u771F\u5B9E\u68C0\u9A8C\u4E86\u88AB\u6D4B\u884C\u4E3A\uFF0C\u800C\u975E\u7A7A\u65AD\u8A00\u6216\u6C38\u771F\u65AD\u8A00
1133
- 4. **\u5BFC\u5165\u6B63\u786E\u6027**\uFF1Aimport \u8DEF\u5F84\u548C\u6A21\u5757\u662F\u5426\u6B63\u786E
1134
- 5. **\u4EE3\u7801\u53EF\u8FD0\u884C\u6027**\uFF1A\u6D4B\u8BD5\u4EE3\u7801\u662F\u5426\u53EF\u76F4\u63A5\u8FD0\u884C\uFF0C\u65E0\u8BED\u6CD5\u9519\u8BEF
1135
-
1136
- \u8F93\u51FA\u683C\u5F0F\uFF08\u4E25\u683C\u9075\u5B88\uFF09\uFF1A
1137
- APPROVED: true \u6216 false
1138
- SCORE: 0.0 \u5230 1.0 \u4E4B\u95F4\u7684\u8BC4\u5206
1139
- FEEDBACK: \u4E00\u53E5\u8BDD\u5BA1\u8BA1\u610F\u89C1
1140
- ISSUES: \u95EE\u9898\u5217\u8868\uFF08\u6BCF\u884C\u4E00\u4E2A\uFF0C\u683C\u5F0F "- \u95EE\u9898\u63CF\u8FF0"\uFF09
1141
- SUGGESTIONS: \u6539\u8FDB\u5EFA\u8BAE\u5217\u8868\uFF08\u6BCF\u884C\u4E00\u4E2A\uFF0C\u683C\u5F0F "- \u5EFA\u8BAE\u63CF\u8FF0"\uFF09`;
1205
+ return `\u4F60\u662F\u6D4B\u8BD5\u5BA1\u8BA1\u4E13\u5BB6\u3002\u5BA1\u67E5\u6D4B\u8BD5\u4EE3\u7801\u662F\u5426\u51C6\u786E\u3002
1206
+ \u6807\u51C6:1.\u7C7B\u578B\u5339\u914D 2.\u8986\u76D6\u6838\u5FC3\u5BFC\u51FA/props/emits 3.\u65AD\u8A00\u6709\u6548(\u975E\u6C38\u771F) 4.import\u6B63\u786E 5.\u53EF\u8FD0\u884C
1207
+ \u8F93\u51FA:
1208
+ APPROVED:true\u6216false
1209
+ SCORE:0.0-1.0
1210
+ FEEDBACK:\u4E00\u53E5\u8BDD
1211
+ ISSUES:- \u95EE\u9898(\u6BCF\u884C\u4E00\u4E2A)
1212
+ SUGGESTIONS:- \u5EFA\u8BAE(\u6BCF\u884C\u4E00\u4E2A)`;
1142
1213
  }
1143
1214
  buildReviewTestUserPrompt(req) {
1144
1215
  const importPath = this.computeTestImportPath(req.testType, req.target);
1145
- let prompt = `\u8BF7\u5BA1\u67E5\u4EE5\u4E0B\u6D4B\u8BD5\u7528\u4F8B\u662F\u5426\u4E0E\u6E90\u7801\u8D34\u5207\u4E14\u51C6\u786E\u3002
1146
-
1147
- \u88AB\u6D4B\u6587\u4EF6: ${req.target}
1148
- \u6D4B\u8BD5\u7C7B\u578B: ${req.testType}
1149
- \u6B63\u786E\u7684 import \u8DEF\u5F84\u5E94\u4E3A: ${importPath}\uFF08\u6D4B\u8BD5\u6587\u4EF6\u4F4D\u4E8E ${this.getTestOutputDir(req.testType)}/\uFF09
1150
-
1151
- --- \u6E90\u7801\u5185\u5BB9 ---
1152
- \`\`\`typescript
1153
- ${req.sourceCode}
1216
+ let prompt = `\u5BA1\u67E5\u6D4B\u8BD5\u4EE3\u7801\u3002\u88AB\u6D4B:${req.target} \u7C7B\u578B:${req.testType} import\u8DEF\u5F84:${importPath}
1217
+ `;
1218
+ prompt += `
1219
+ \u6E90\u7801:
1220
+ \`\`\`
1221
+ ${this.compressSourceCode(req.sourceCode, 2e3)}
1222
+ \`\`\`
1223
+ `;
1224
+ prompt += `
1225
+ \u6D4B\u8BD5\u4EE3\u7801:
1154
1226
  \`\`\`
1155
-
1156
- --- \u751F\u6210\u7684\u6D4B\u8BD5\u4EE3\u7801 ---
1157
- \`\`\`typescript
1158
1227
  ${req.testCode}
1159
1228
  \`\`\``;
1160
1229
  if (req.analysis) {
1161
- prompt += "\n\n--- \u6E90\u7801\u5206\u6790 ---";
1230
+ const parts = [];
1162
1231
  if (req.analysis.exports?.length > 0) {
1163
- prompt += `
1164
- \u5BFC\u51FA\u9879:
1165
- ${req.analysis.exports.map((e) => {
1166
- const params = e.params?.length ? `(${e.params.join(", ")})` : "";
1167
- const asyncFlag = e.isAsync ? "async " : "";
1168
- return ` - ${asyncFlag}${e.name}${params} [${e.kind}]`;
1169
- }).join("\n")}`;
1232
+ parts.push(`\u5BFC\u51FA:${req.analysis.exports.map((e) => `${e.isAsync ? "async " : ""}${e.name}(${e.params?.join(",") || ""})[${e.kind}]`).join(",")}`);
1170
1233
  }
1171
1234
  if (req.analysis.props?.length) {
1172
- prompt += `
1173
- Props:
1174
- ${req.analysis.props.map(
1175
- (p) => ` - ${p.name}: ${p.type}${p.required ? " (\u5FC5\u586B)" : " (\u53EF\u9009)"}`
1176
- ).join("\n")}`;
1235
+ parts.push(`Props:${req.analysis.props.map((p) => `${p.name}:${p.type}${p.required ? "!" : "?"}`).join(",")}`);
1177
1236
  }
1178
1237
  if (req.analysis.emits?.length) {
1238
+ parts.push(`Emits:${req.analysis.emits.map((e) => `${e.name}(${e.params?.join(",") || ""})`).join(",")}`);
1239
+ }
1240
+ if (parts.length > 0) {
1179
1241
  prompt += `
1180
- Emits:
1181
- ${req.analysis.emits.map(
1182
- (e) => ` - ${e.name}${e.params?.length ? `(${e.params.join(", ")})` : ""}`
1183
- ).join("\n")}`;
1242
+ \u5206\u6790:${parts.join("|")}`;
1184
1243
  }
1185
1244
  }
1186
1245
  if (req.generationDescription) {
1187
1246
  prompt += `
1188
-
1189
- \u751F\u6210\u8005\u8BF4\u660E: ${req.generationDescription}`;
1247
+ \u8BF4\u660E:${req.generationDescription}`;
1190
1248
  }
1191
1249
  return prompt;
1192
1250
  }
@@ -1246,6 +1304,61 @@ ${req.analysis.emits.map(
1246
1304
  return urlMap[provider] || "https://api.openai.com/v1";
1247
1305
  }
1248
1306
  };
1307
+ function compressFunctionBodies(code, maxLength) {
1308
+ const lines = code.split("\n");
1309
+ const result = [];
1310
+ let depth = 0;
1311
+ let fnDepth = 0;
1312
+ let inFunction = false;
1313
+ let braceBalance = 0;
1314
+ let capturedLines = 0;
1315
+ for (const line of lines) {
1316
+ const trimmed = line.trim();
1317
+ for (const ch of trimmed) {
1318
+ if (ch === "{") {
1319
+ braceBalance++;
1320
+ depth++;
1321
+ }
1322
+ if (ch === "}") {
1323
+ braceBalance--;
1324
+ depth = Math.max(0, depth - 1);
1325
+ }
1326
+ }
1327
+ const isFnSignature = /^(export\s+)?(async\s+)?function\s|=>\s*\{|=>\s*$/m.test(trimmed) || /^(const|let|var)\s+\w+\s*=\s*(async\s+)?(\([^)]*\)|[^=])\s*=>/.test(trimmed);
1328
+ if (isFnSignature && !inFunction) {
1329
+ inFunction = true;
1330
+ fnDepth = depth;
1331
+ result.push(line);
1332
+ capturedLines++;
1333
+ continue;
1334
+ }
1335
+ if (inFunction) {
1336
+ const isReturn = trimmed.startsWith("return ");
1337
+ const isBranch = /^(if|else|switch|case|try|catch|finally|for|while)/.test(trimmed);
1338
+ const isClosing = trimmed === "}" && depth <= fnDepth - 1;
1339
+ if (isClosing) {
1340
+ result.push(line);
1341
+ inFunction = false;
1342
+ capturedLines++;
1343
+ } else if (isReturn || isBranch) {
1344
+ result.push(trimmed.length > 120 ? `${trimmed.slice(0, 120)}...` : line);
1345
+ capturedLines++;
1346
+ } else if (trimmed.startsWith("//") || trimmed === "") {
1347
+ } else if (capturedLines < maxLength / 30) {
1348
+ result.push(trimmed.length > 100 ? `${trimmed.slice(0, 100)}...` : line);
1349
+ capturedLines++;
1350
+ }
1351
+ } else {
1352
+ result.push(line);
1353
+ capturedLines++;
1354
+ }
1355
+ if (result.join("\n").length > maxLength) {
1356
+ result.push("// ... (truncated)");
1357
+ break;
1358
+ }
1359
+ }
1360
+ return result.join("\n");
1361
+ }
1249
1362
 
1250
1363
  // src/ai/provider.ts
1251
1364
  var providerRegistry = /* @__PURE__ */ new Map();
@@ -1794,7 +1907,7 @@ function registerInitCommand(program2) {
1794
1907
  try {
1795
1908
  await executeInit(options);
1796
1909
  } catch (error) {
1797
- console.error(chalk2.red(`
1910
+ console.error(chalk3.red(`
1798
1911
  \u2717 ${error instanceof Error ? error.message : String(error)}
1799
1912
  `));
1800
1913
  process.exit(1);
@@ -1816,19 +1929,19 @@ async function executeInit(options) {
1816
1929
  }
1817
1930
  ]);
1818
1931
  if (!proceed) {
1819
- console.log(chalk2.gray("\n \u5DF2\u53D6\u6D88\u521D\u59CB\u5316\n"));
1932
+ console.log(chalk3.gray("\n \u5DF2\u53D6\u6D88\u521D\u59CB\u5316\n"));
1820
1933
  return;
1821
1934
  }
1822
1935
  }
1823
1936
  let globalAI = loadGlobalAIConfig();
1824
1937
  if (!globalAI) {
1825
- console.log(chalk2.cyan(" AI \u6A21\u578B\u914D\u7F6E (\u9996\u6B21\u4F7F\u7528\u9700\u914D\u7F6E\uFF0C\u4E4B\u540E\u53EF\u901A\u8FC7 qat change \u4FEE\u6539)\n"));
1938
+ console.log(chalk3.cyan(" AI \u6A21\u578B\u914D\u7F6E (\u9996\u6B21\u4F7F\u7528\u9700\u914D\u7F6E\uFF0C\u4E4B\u540E\u53EF\u901A\u8FC7 qat change \u4FEE\u6539)\n"));
1826
1939
  globalAI = await promptAIConfig();
1827
1940
  saveGlobalAIConfig(globalAI);
1828
- console.log(chalk2.gray(` \u914D\u7F6E\u5DF2\u4FDD\u5B58\u81F3 ${getAIConfigPath()}
1941
+ console.log(chalk3.gray(` \u914D\u7F6E\u5DF2\u4FDD\u5B58\u81F3 ${getAIConfigPath()}
1829
1942
  `));
1830
1943
  } else {
1831
- console.log(chalk2.green(` \u2713 \u5F53\u524D AI \u6A21\u578B: ${chalk2.white(globalAI.model)} @ ${chalk2.gray(globalAI.baseUrl)} (${maskApiKey(globalAI.apiKey)})
1944
+ console.log(chalk3.green(` \u2713 \u5F53\u524D AI \u6A21\u578B: ${chalk3.white(globalAI.model)} @ ${chalk3.gray(globalAI.baseUrl)} (${maskApiKey(globalAI.apiKey)})
1832
1945
  `));
1833
1946
  }
1834
1947
  const aiConfig = toAIConfig(globalAI);
@@ -1837,10 +1950,10 @@ async function executeInit(options) {
1837
1950
  try {
1838
1951
  const result = await testAIConnection(aiConfig);
1839
1952
  if (result.ok) {
1840
- testSpinner.succeed(`AI \u8FDE\u901A\u6B63\u5E38 ${chalk2.gray(`${globalAI.model} (${result.latencyMs}ms)`)}`);
1953
+ testSpinner.succeed(`AI \u8FDE\u901A\u6B63\u5E38 ${chalk3.gray(`${globalAI.model} (${result.latencyMs}ms)`)}`);
1841
1954
  } else {
1842
1955
  testSpinner.fail(`AI \u8FDE\u901A\u5F02\u5E38: ${result.message}`);
1843
- console.log(chalk2.yellow(" \u53EF\u8FD0\u884C qat change \u4FEE\u6539 AI \u914D\u7F6E\u3002"));
1956
+ console.log(chalk3.yellow(" \u53EF\u8FD0\u884C qat change \u4FEE\u6539 AI \u914D\u7F6E\u3002"));
1844
1957
  }
1845
1958
  } catch (error) {
1846
1959
  testSpinner.fail(`AI \u8FDE\u901A\u6D4B\u8BD5\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`);
@@ -1861,7 +1974,7 @@ async function executeInit(options) {
1861
1974
  }
1862
1975
  ]);
1863
1976
  if (!overwrite) {
1864
- console.log(chalk2.gray(" \u4FDD\u7559\u73B0\u6709\u914D\u7F6E\u6587\u4EF6\uFF0C\u7EE7\u7EED\u540E\u7EED\u6B65\u9AA4..."));
1977
+ console.log(chalk3.gray(" \u4FDD\u7559\u73B0\u6709\u914D\u7F6E\u6587\u4EF6\uFF0C\u7EE7\u7EED\u540E\u7EED\u6B65\u9AA4..."));
1865
1978
  configPath = existingConfigPath;
1866
1979
  } else {
1867
1980
  const fileSpinner = ora("\u6B63\u5728\u8986\u76D6\u914D\u7F6E\u6587\u4EF6...").start();
@@ -1896,10 +2009,10 @@ async function executeInit(options) {
1896
2009
  const mockFilePath = path6.join(process.cwd(), mockDir, "auto-generated.json");
1897
2010
  if (!fs6.existsSync(mockFilePath)) {
1898
2011
  fs6.writeFileSync(mockFilePath, JSON.stringify(mockRoutes, null, 2), "utf-8");
1899
- console.log(chalk2.green(` \u81EA\u52A8\u53D1\u73B0 ${apiCalls.length} \u4E2A API \u63A5\u53E3\uFF0C\u5DF2\u751F\u6210 Mock \u8DEF\u7531`));
2012
+ console.log(chalk3.green(` \u81EA\u52A8\u53D1\u73B0 ${apiCalls.length} \u4E2A API \u63A5\u53E3\uFF0C\u5DF2\u751F\u6210 Mock \u8DEF\u7531`));
1900
2013
  }
1901
2014
  } else {
1902
- console.log(chalk2.gray(" \u672A\u53D1\u73B0 API \u8C03\u7528\uFF0C\u5DF2\u751F\u6210\u793A\u4F8B Mock \u8DEF\u7531"));
2015
+ console.log(chalk3.gray(" \u672A\u53D1\u73B0 API \u8C03\u7528\uFF0C\u5DF2\u751F\u6210\u793A\u4F8B Mock \u8DEF\u7531"));
1903
2016
  }
1904
2017
  }
1905
2018
  const srcDir = config.project?.srcDir || "src";
@@ -1907,7 +2020,7 @@ async function executeInit(options) {
1907
2020
  const utilities = discoverUtilityFiles(process.cwd(), srcDir);
1908
2021
  const totalFiles = components.length + utilities.length;
1909
2022
  if (totalFiles > 0) {
1910
- console.log(chalk2.cyan(`
2023
+ console.log(chalk3.cyan(`
1911
2024
  \u53D1\u73B0 ${totalFiles} \u4E2A\u53EF\u6D4B\u8BD5\u6587\u4EF6 (${components.length} \u7EC4\u4EF6, ${utilities.length} \u5DE5\u5177/\u670D\u52A1)`));
1912
2025
  }
1913
2026
  displayResult(configPath, createdDirs, totalFiles, projectInfo);
@@ -1994,8 +2107,8 @@ function buildProjectConfig(projectInfo) {
1994
2107
  };
1995
2108
  }
1996
2109
  function displayProjectInfo(info) {
1997
- console.log(chalk2.cyan("\n \u9879\u76EE\u68C0\u6D4B\u7ED3\u679C:"));
1998
- console.log(chalk2.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
2110
+ console.log(chalk3.cyan("\n \u9879\u76EE\u68C0\u6D4B\u7ED3\u679C:"));
2111
+ console.log(chalk3.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
1999
2112
  const items = [
2000
2113
  ["\u9879\u76EE\u540D\u79F0", info.name],
2001
2114
  ["\u6846\u67B6", info.frameworkConfidence > 0.5 ? `${info.frameworkDisplayName} (\u7F6E\u4FE1\u5EA6 ${Math.round(info.frameworkConfidence * 100)}%)` : info.frameworkDisplayName],
@@ -2017,8 +2130,8 @@ function displayProjectInfo(info) {
2017
2130
  items.push(["\u7EC4\u4EF6\u76EE\u5F55", info.componentDirs.join(", ")]);
2018
2131
  }
2019
2132
  for (const [label, value] of items) {
2020
- const displayValue = value === true ? chalk2.green("\u2713") : value === false ? chalk2.red("\u2717") : String(value);
2021
- console.log(` ${chalk2.white(label.padEnd(12))} ${displayValue}`);
2133
+ const displayValue = value === true ? chalk3.green("\u2713") : value === false ? chalk3.red("\u2717") : String(value);
2134
+ console.log(` ${chalk3.white(label.padEnd(12))} ${displayValue}`);
2022
2135
  }
2023
2136
  console.log();
2024
2137
  }
@@ -2049,34 +2162,34 @@ function createTestDirectories(config) {
2049
2162
  }
2050
2163
  function displayResult(configPath, createdDirs, totalTestableFiles, projectInfo) {
2051
2164
  const relativeConfig = path6.relative(process.cwd(), configPath);
2052
- console.log(chalk2.green("\n \u2713 \u9879\u76EE\u521D\u59CB\u5316\u5B8C\u6210!\n"));
2053
- console.log(chalk2.white(" \u5DF2\u751F\u6210\u914D\u7F6E:"));
2054
- console.log(chalk2.gray(` ${relativeConfig}`));
2165
+ console.log(chalk3.green("\n \u2713 \u9879\u76EE\u521D\u59CB\u5316\u5B8C\u6210!\n"));
2166
+ console.log(chalk3.white(" \u5DF2\u751F\u6210\u914D\u7F6E:"));
2167
+ console.log(chalk3.gray(` ${relativeConfig}`));
2055
2168
  console.log();
2056
2169
  if (createdDirs.length > 0) {
2057
- console.log(chalk2.white(" \u5DF2\u521B\u5EFA\u76EE\u5F55:"));
2170
+ console.log(chalk3.white(" \u5DF2\u521B\u5EFA\u76EE\u5F55:"));
2058
2171
  for (const dir of createdDirs) {
2059
- console.log(chalk2.gray(` ${dir}/`));
2172
+ console.log(chalk3.gray(` ${dir}/`));
2060
2173
  }
2061
2174
  console.log();
2062
2175
  }
2063
- console.log(chalk2.cyan(" \u4E0B\u4E00\u6B65:"));
2176
+ console.log(chalk3.cyan(" \u4E0B\u4E00\u6B65:"));
2064
2177
  if (totalTestableFiles > 0) {
2065
- console.log(chalk2.gray(` 1. qat create \u9009\u62E9\u6587\u4EF6\u5E76\u751F\u6210\u6D4B\u8BD5\u7528\u4F8B (\u53D1\u73B0 ${totalTestableFiles} \u4E2A\u53EF\u6D4B\u8BD5\u6587\u4EF6)`));
2178
+ console.log(chalk3.gray(` 1. qat create \u9009\u62E9\u6587\u4EF6\u5E76\u751F\u6210\u6D4B\u8BD5\u7528\u4F8B (\u53D1\u73B0 ${totalTestableFiles} \u4E2A\u53EF\u6D4B\u8BD5\u6587\u4EF6)`));
2066
2179
  } else {
2067
- console.log(chalk2.gray(" 1. qat create \u521B\u5EFA\u6D4B\u8BD5\u7528\u4F8B"));
2180
+ console.log(chalk3.gray(" 1. qat create \u521B\u5EFA\u6D4B\u8BD5\u7528\u4F8B"));
2068
2181
  }
2069
- console.log(chalk2.gray(" 2. qat run \u6267\u884C\u6D4B\u8BD5"));
2070
- console.log(chalk2.gray(" 3. qat status \u67E5\u770B AI \u6A21\u578B\u72B6\u6001"));
2182
+ console.log(chalk3.gray(" 2. qat run \u6267\u884C\u6D4B\u8BD5"));
2183
+ console.log(chalk3.gray(" 3. qat status \u67E5\u770B AI \u6A21\u578B\u72B6\u6001"));
2071
2184
  if (projectInfo.testFrameworks.length === 0) {
2072
2185
  console.log();
2073
- console.log(chalk2.yellow(" \u26A0 \u672A\u68C0\u6D4B\u5230\u6D4B\u8BD5\u6846\u67B6\u4F9D\u8D56\uFF0C\u8FD0\u884C qat run \u65F6\u4F1A\u63D0\u793A\u5B89\u88C5"));
2186
+ console.log(chalk3.yellow(" \u26A0 \u672A\u68C0\u6D4B\u5230\u6D4B\u8BD5\u6846\u67B6\u4F9D\u8D56\uFF0C\u8FD0\u884C qat run \u65F6\u4F1A\u63D0\u793A\u5B89\u88C5"));
2074
2187
  }
2075
2188
  console.log();
2076
2189
  }
2077
2190
 
2078
2191
  // src/commands/create.ts
2079
- import chalk4 from "chalk";
2192
+ import chalk5 from "chalk";
2080
2193
  import inquirer2 from "inquirer";
2081
2194
  import ora3 from "ora";
2082
2195
  import fs8 from "fs";
@@ -2537,7 +2650,7 @@ function toPascalCase(str) {
2537
2650
  }
2538
2651
 
2539
2652
  // src/services/test-reviewer.ts
2540
- import chalk3 from "chalk";
2653
+ import chalk4 from "chalk";
2541
2654
  import ora2 from "ora";
2542
2655
  var MAX_RETRIES = 3;
2543
2656
  var REVIEW_THRESHOLD = 0.6;
@@ -2557,6 +2670,9 @@ async function generateWithReview(params) {
2557
2670
  for (let i = 0; i < MAX_RETRIES; i++) {
2558
2671
  attempts = i + 1;
2559
2672
  onAttempt?.(attempts, MAX_RETRIES);
2673
+ if (process.env.QAT_DEBUG === "true") {
2674
+ console.error(chalk4.gray(`[DEBUG] \u2500\u2500\u2500 \u751F\u6210\u8005 AI \u7B2C${attempts}\u6B21\u5C1D\u8BD5 \u2500\u2500\u2500`));
2675
+ }
2560
2676
  const generationPrompt = i === 0 ? void 0 : `\u4E0A\u6B21\u751F\u6210\u7684\u6D4B\u8BD5\u672A\u901A\u8FC7\u5BA1\u8BA1\uFF0C\u8BF7\u6839\u636E\u4EE5\u4E0B\u53CD\u9988\u91CD\u65B0\u751F\u6210\uFF1A
2561
2677
  \u5BA1\u8BA1\u8BC4\u5206: ${(lastReview.score * 100).toFixed(0)}%
2562
2678
  \u5BA1\u8BA1\u610F\u89C1: ${lastReview.feedback}
@@ -2569,16 +2685,17 @@ ${lastReview.suggestions.map((s) => `- ${s}`).join("\n")}
2569
2685
  const generateResponse = await generatorProvider.generateTest({
2570
2686
  type: testType,
2571
2687
  target: targetPath,
2572
- context: i === 0 ? sourceCode : `${sourceCode}
2573
-
2574
- --- \u5BA1\u8BA1\u53CD\u9988 ---
2575
- ${generationPrompt}`,
2688
+ // 重试时:源码已压缩在分析摘要中,context只传审计反馈以减少token
2689
+ context: i === 0 ? sourceCode : generationPrompt,
2576
2690
  framework: framework || void 0,
2577
2691
  analysis
2578
2692
  });
2579
2693
  currentCode = generateResponse.code;
2580
2694
  currentDescription = generateResponse.description;
2581
2695
  currentConfidence = generateResponse.confidence;
2696
+ if (process.env.QAT_DEBUG === "true") {
2697
+ console.error(chalk4.gray(`[DEBUG] \u2500\u2500\u2500 \u5BA1\u8BA1\u5458 AI \u5BA1\u67E5 \u2500\u2500\u2500`));
2698
+ }
2582
2699
  const reviewRequest = {
2583
2700
  target: targetPath,
2584
2701
  sourceCode,
@@ -2610,20 +2727,20 @@ function printReviewReport(report) {
2610
2727
  const approved = report.filter((r) => r.approved);
2611
2728
  const failed = report.filter((r) => !r.approved);
2612
2729
  console.log();
2613
- console.log(chalk3.cyan(" \u5BA1\u8BA1\u62A5\u544A:"));
2614
- console.log(chalk3.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
2730
+ console.log(chalk4.cyan(" \u5BA1\u8BA1\u62A5\u544A:"));
2731
+ console.log(chalk4.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
2615
2732
  for (const entry of approved) {
2616
- console.log(` ${chalk3.green("\u2713")} ${chalk3.gray(entry.target)} ${chalk3.green(`(${(entry.score * 100).toFixed(0)}%`)}${entry.attempts > 1 ? chalk3.yellow(` ${entry.attempts}\u6B21\u5C1D\u8BD5`) : ""})`);
2733
+ console.log(` ${chalk4.green("\u2713")} ${chalk4.gray(entry.target)} ${chalk4.green(`(${(entry.score * 100).toFixed(0)}%`)}${entry.attempts > 1 ? chalk4.yellow(` ${entry.attempts}\u6B21\u5C1D\u8BD5`) : ""})`);
2617
2734
  }
2618
2735
  for (const entry of failed) {
2619
- console.log(` ${chalk3.red("\u2717")} ${chalk3.gray(entry.target)} ${chalk3.red(`(${(entry.score * 100).toFixed(0)}%)`)}`);
2736
+ console.log(` ${chalk4.red("\u2717")} ${chalk4.gray(entry.target)} ${chalk4.red(`(${(entry.score * 100).toFixed(0)}%)`)}`);
2620
2737
  if (entry.issues.length > 0) {
2621
2738
  for (const issue of entry.issues.slice(0, 3)) {
2622
- console.log(chalk3.gray(` - ${issue}`));
2739
+ console.log(chalk4.gray(` - ${issue}`));
2623
2740
  }
2624
2741
  }
2625
2742
  if (entry.feedback) {
2626
- console.log(chalk3.gray(` \u53CD\u9988: ${entry.feedback}`));
2743
+ console.log(chalk4.gray(` \u53CD\u9988: ${entry.feedback}`));
2627
2744
  }
2628
2745
  }
2629
2746
  console.log();
@@ -2651,7 +2768,7 @@ function registerCreateCommand(program2) {
2651
2768
  try {
2652
2769
  await executeCreate(options);
2653
2770
  } catch (error) {
2654
- console.error(chalk4.red(`
2771
+ console.error(chalk5.red(`
2655
2772
  \u2717 ${error instanceof Error ? error.message : String(error)}
2656
2773
  `));
2657
2774
  process.exit(1);
@@ -2676,7 +2793,7 @@ async function executeCreate(options) {
2676
2793
  name: "types",
2677
2794
  message: "\u9009\u62E9\u6D4B\u8BD5\u7C7B\u578B (\u7A7A\u683C\u9009\u62E9/\u53D6\u6D88\uFF0C\u56DE\u8F66\u786E\u8BA4):",
2678
2795
  choices: Object.entries(TEST_TYPE_LABELS).map(([value, label]) => ({
2679
- name: `${label} - ${chalk4.gray(TEST_TYPE_DESCRIPTIONS[value])}`,
2796
+ name: `${label} - ${chalk5.gray(TEST_TYPE_DESCRIPTIONS[value])}`,
2680
2797
  value,
2681
2798
  short: label,
2682
2799
  checked: value === "unit" || value === "component"
@@ -2793,7 +2910,7 @@ async function executeCreate(options) {
2793
2910
  createdFiles.push({ type: testType, filePath });
2794
2911
  } catch (error) {
2795
2912
  spinner.fail(`${TEST_TYPE_LABELS[testType]} - ${path8.basename(testTarget)} \u521B\u5EFA\u5931\u8D25`);
2796
- console.log(chalk4.gray(` ${error instanceof Error ? error.message : String(error)}`));
2913
+ console.log(chalk5.gray(` ${error instanceof Error ? error.message : String(error)}`));
2797
2914
  }
2798
2915
  }
2799
2916
  }
@@ -2807,13 +2924,13 @@ async function selectTargets(types, projectInfo, srcDir) {
2807
2924
  if (types.includes("unit")) {
2808
2925
  const utils = discoverUtilityFiles(process.cwd(), srcDir);
2809
2926
  for (const f of utils.slice(0, 30)) {
2810
- allTargets.push({ name: `${chalk4.gray("[unit]")} ${f}`, value: f });
2927
+ allTargets.push({ name: `${chalk5.gray("[unit]")} ${f}`, value: f });
2811
2928
  }
2812
2929
  }
2813
2930
  if (types.includes("component")) {
2814
2931
  const components = discoverVueComponents(process.cwd(), srcDir);
2815
2932
  for (const f of components.slice(0, 30)) {
2816
- allTargets.push({ name: `${chalk4.gray("[comp]")} ${f}`, value: f });
2933
+ allTargets.push({ name: `${chalk5.gray("[comp]")} ${f}`, value: f });
2817
2934
  }
2818
2935
  }
2819
2936
  if (allTargets.length === 0) {
@@ -2834,7 +2951,7 @@ async function selectTargets(types, projectInfo, srcDir) {
2834
2951
  message: "\u9009\u62E9\u88AB\u6D4B\u76EE\u6807 (\u7A7A\u683C\u9009\u62E9/\u53D6\u6D88\uFF0C\u56DE\u8F66\u786E\u8BA4):",
2835
2952
  choices: [
2836
2953
  ...allTargets,
2837
- { name: chalk4.gray("\u624B\u52A8\u8F93\u5165\u8DEF\u5F84"), value: "__manual__" }
2954
+ { name: chalk5.gray("\u624B\u52A8\u8F93\u5165\u8DEF\u5F84"), value: "__manual__" }
2838
2955
  ],
2839
2956
  validate: (input) => {
2840
2957
  if (input.length === 0) return "\u8BF7\u81F3\u5C11\u9009\u62E9\u4E00\u4E2A\u76EE\u6807";
@@ -2933,38 +3050,38 @@ function getTestOutputDir(type) {
2933
3050
  }
2934
3051
  function displayCreateResult(createdFiles, skippedCount, usedAI) {
2935
3052
  if (createdFiles.length === 0 && skippedCount === 0) {
2936
- console.log(chalk4.yellow("\n \u6CA1\u6709\u521B\u5EFA\u4EFB\u4F55\u6D4B\u8BD5\u6587\u4EF6\n"));
3053
+ console.log(chalk5.yellow("\n \u6CA1\u6709\u521B\u5EFA\u4EFB\u4F55\u6D4B\u8BD5\u6587\u4EF6\n"));
2937
3054
  return;
2938
3055
  }
2939
- console.log(chalk4.green(`
3056
+ console.log(chalk5.green(`
2940
3057
  \u2713 \u5DF2\u521B\u5EFA ${createdFiles.length} \u4E2A\u6D4B\u8BD5\u6587\u4EF6`));
2941
3058
  if (skippedCount > 0) {
2942
- console.log(chalk4.yellow(` \u26A0 \u8DF3\u8FC7 ${skippedCount} \u4E2A\u5DF2\u5B58\u5728\u7684\u6587\u4EF6`));
3059
+ console.log(chalk5.yellow(` \u26A0 \u8DF3\u8FC7 ${skippedCount} \u4E2A\u5DF2\u5B58\u5728\u7684\u6587\u4EF6`));
2943
3060
  }
2944
3061
  console.log();
2945
3062
  for (const { type, filePath } of createdFiles) {
2946
3063
  const relativePath = path8.relative(process.cwd(), filePath);
2947
- console.log(chalk4.white(` ${chalk4.cyan(TEST_TYPE_LABELS[type])} ${chalk4.gray(relativePath)}`));
3064
+ console.log(chalk5.white(` ${chalk5.cyan(TEST_TYPE_LABELS[type])} ${chalk5.gray(relativePath)}`));
2948
3065
  }
2949
3066
  if (usedAI) {
2950
3067
  console.log();
2951
- console.log(chalk4.magenta(" \u751F\u6210\u65B9\u5F0F: AI \u8F85\u52A9"));
3068
+ console.log(chalk5.magenta(" \u751F\u6210\u65B9\u5F0F: AI \u8F85\u52A9"));
2952
3069
  }
2953
3070
  console.log();
2954
- console.log(chalk4.gray(" \u8FD0\u884C\u6D4B\u8BD5:"));
3071
+ console.log(chalk5.gray(" \u8FD0\u884C\u6D4B\u8BD5:"));
2955
3072
  const uniqueTypes = [...new Set(createdFiles.map((f) => f.type))];
2956
3073
  if (uniqueTypes.length === 1) {
2957
- console.log(chalk4.cyan(` qat run -t ${uniqueTypes[0]}`));
3074
+ console.log(chalk5.cyan(` qat run -t ${uniqueTypes[0]}`));
2958
3075
  } else {
2959
- console.log(chalk4.cyan(` qat run -t ${uniqueTypes.join(" -t ")}`));
2960
- console.log(chalk4.gray(" # \u6216\u8FD0\u884C\u5168\u90E8"));
2961
- console.log(chalk4.cyan(" qat run"));
3076
+ console.log(chalk5.cyan(` qat run -t ${uniqueTypes.join(" -t ")}`));
3077
+ console.log(chalk5.gray(" # \u6216\u8FD0\u884C\u5168\u90E8"));
3078
+ console.log(chalk5.cyan(" qat run"));
2962
3079
  }
2963
3080
  console.log();
2964
3081
  }
2965
3082
 
2966
3083
  // src/commands/run.ts
2967
- import chalk5 from "chalk";
3084
+ import chalk6 from "chalk";
2968
3085
  import inquirer3 from "inquirer";
2969
3086
  import ora4 from "ora";
2970
3087
  import fs11 from "fs";
@@ -4055,7 +4172,7 @@ function registerRunCommand(program2) {
4055
4172
  try {
4056
4173
  await executeRun(options);
4057
4174
  } catch (error) {
4058
- console.error(chalk5.red(`
4175
+ console.error(chalk6.red(`
4059
4176
  \u2717 ${error instanceof Error ? error.message : String(error)}
4060
4177
  `));
4061
4178
  process.exit(1);
@@ -4075,15 +4192,15 @@ async function executeRun(options) {
4075
4192
  }
4076
4193
  let typesToRun = await determineTypesToRun(type, file, config);
4077
4194
  if (typesToRun.length === 0) {
4078
- 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"));
4195
+ console.log(chalk6.yellow("\n \u6CA1\u6709\u53EF\u8FD0\u884C\u7684\u6D4B\u8BD5\u7C7B\u578B\uFF08\u8BF7\u5728 qat.config.ts \u4E2D\u542F\u7528\uFF09\n"));
4079
4196
  return;
4080
4197
  }
4081
4198
  const missingDeps = checkTestDependencies(typesToRun);
4082
4199
  if (missingDeps.length > 0) {
4083
- console.log(chalk5.yellow("\n \u26A0 \u4EE5\u4E0B\u6D4B\u8BD5\u6846\u67B6\u4F9D\u8D56\u672A\u5B89\u88C5:\n"));
4200
+ console.log(chalk6.yellow("\n \u26A0 \u4EE5\u4E0B\u6D4B\u8BD5\u6846\u67B6\u4F9D\u8D56\u672A\u5B89\u88C5:\n"));
4084
4201
  for (const dep of missingDeps) {
4085
- console.log(chalk5.white(` ${dep.runner} (${dep.pkg})`));
4086
- console.log(chalk5.gray(` \u5B89\u88C5\u547D\u4EE4: ${chalk5.cyan(dep.installCmd)}`));
4202
+ console.log(chalk6.white(` ${dep.runner} (${dep.pkg})`));
4203
+ console.log(chalk6.gray(` \u5B89\u88C5\u547D\u4EE4: ${chalk6.cyan(dep.installCmd)}`));
4087
4204
  }
4088
4205
  console.log();
4089
4206
  const { action } = await inquirer3.prompt([
@@ -4100,13 +4217,13 @@ async function executeRun(options) {
4100
4217
  }
4101
4218
  ]);
4102
4219
  if (action === "cancel") {
4103
- console.log(chalk5.gray("\n \u5DF2\u53D6\u6D88\u8FD0\u884C\n"));
4220
+ console.log(chalk6.gray("\n \u5DF2\u53D6\u6D88\u8FD0\u884C\n"));
4104
4221
  return;
4105
4222
  }
4106
4223
  if (action === "install") {
4107
4224
  const installed = await installTestDependencies(missingDeps);
4108
4225
  if (!installed) {
4109
- console.log(chalk5.yellow(" \u90E8\u5206\u4F9D\u8D56\u5B89\u88C5\u5931\u8D25\uFF0C\u5C06\u8DF3\u8FC7\u5BF9\u5E94\u7684\u6D4B\u8BD5\u7C7B\u578B"));
4226
+ console.log(chalk6.yellow(" \u90E8\u5206\u4F9D\u8D56\u5B89\u88C5\u5931\u8D25\uFF0C\u5C06\u8DF3\u8FC7\u5BF9\u5E94\u7684\u6D4B\u8BD5\u7C7B\u578B"));
4110
4227
  }
4111
4228
  const stillMissing = checkTestDependencies(typesToRun);
4112
4229
  if (stillMissing.length > 0) {
@@ -4116,7 +4233,7 @@ async function executeRun(options) {
4116
4233
  return !dep || !missingRunners.has(dep.pkg);
4117
4234
  });
4118
4235
  if (typesToRun.length === 0) {
4119
- console.log(chalk5.yellow("\n \u6CA1\u6709\u53EF\u8FD0\u884C\u7684\u6D4B\u8BD5\u7C7B\u578B\uFF08\u4F9D\u8D56\u672A\u5B89\u88C5\uFF09\n"));
4236
+ console.log(chalk6.yellow("\n \u6CA1\u6709\u53EF\u8FD0\u884C\u7684\u6D4B\u8BD5\u7C7B\u578B\uFF08\u4F9D\u8D56\u672A\u5B89\u88C5\uFF09\n"));
4120
4237
  return;
4121
4238
  }
4122
4239
  }
@@ -4128,7 +4245,7 @@ async function executeRun(options) {
4128
4245
  return !dep || !missingRunners.has(dep.pkg);
4129
4246
  });
4130
4247
  if (typesToRun.length === 0) {
4131
- console.log(chalk5.yellow("\n \u6CA1\u6709\u53EF\u8FD0\u884C\u7684\u6D4B\u8BD5\u7C7B\u578B\n"));
4248
+ console.log(chalk6.yellow("\n \u6CA1\u6709\u53EF\u8FD0\u884C\u7684\u6D4B\u8BD5\u7C7B\u578B\n"));
4132
4249
  return;
4133
4250
  }
4134
4251
  }
@@ -4151,13 +4268,13 @@ async function executeRun(options) {
4151
4268
  }
4152
4269
  ]);
4153
4270
  if (action === "cancel") {
4154
- console.log(chalk5.gray("\n \u5DF2\u53D6\u6D88\u8FD0\u884C\n"));
4271
+ console.log(chalk6.gray("\n \u5DF2\u53D6\u6D88\u8FD0\u884C\n"));
4155
4272
  return;
4156
4273
  }
4157
4274
  if (action === "skip") {
4158
4275
  typesToRun = typesToRun.filter((t) => !SERVER_REQUIRED_TYPES.includes(t));
4159
4276
  if (typesToRun.length === 0) {
4160
- console.log(chalk5.yellow("\n \u6CA1\u6709\u53EF\u8FD0\u884C\u7684\u6D4B\u8BD5\u7C7B\u578B\n"));
4277
+ console.log(chalk6.yellow("\n \u6CA1\u6709\u53EF\u8FD0\u884C\u7684\u6D4B\u8BD5\u7C7B\u578B\n"));
4161
4278
  return;
4162
4279
  }
4163
4280
  }
@@ -4177,12 +4294,12 @@ async function executeRun(options) {
4177
4294
  }
4178
4295
  ]);
4179
4296
  if (fallback === "cancel") {
4180
- console.log(chalk5.gray("\n \u5DF2\u53D6\u6D88\u8FD0\u884C\n"));
4297
+ console.log(chalk6.gray("\n \u5DF2\u53D6\u6D88\u8FD0\u884C\n"));
4181
4298
  return;
4182
4299
  }
4183
4300
  typesToRun = typesToRun.filter((t) => !SERVER_REQUIRED_TYPES.includes(t));
4184
4301
  if (typesToRun.length === 0) {
4185
- console.log(chalk5.yellow("\n \u6CA1\u6709\u53EF\u8FD0\u884C\u7684\u6D4B\u8BD5\u7C7B\u578B\n"));
4302
+ console.log(chalk6.yellow("\n \u6CA1\u6709\u53EF\u8FD0\u884C\u7684\u6D4B\u8BD5\u7C7B\u578B\n"));
4186
4303
  return;
4187
4304
  }
4188
4305
  }
@@ -4240,8 +4357,8 @@ async function executeRun(options) {
4240
4357
  const outputDir = config.report.outputDir || "qat-report";
4241
4358
  const reportPath = writeReportToDisk(reportData, outputDir);
4242
4359
  const relativePath = path12.relative(process.cwd(), reportPath);
4243
- console.log(chalk5.gray(`
4244
- \u62A5\u544A\u5DF2\u751F\u6210: ${chalk5.cyan(relativePath)}`));
4360
+ console.log(chalk6.gray(`
4361
+ \u62A5\u544A\u5DF2\u751F\u6210: ${chalk6.cyan(relativePath)}`));
4245
4362
  console.log();
4246
4363
  const hasFailures = results.some((r) => r.status === "failed");
4247
4364
  if (hasFailures && isAIAvailable(config.ai)) {
@@ -4250,7 +4367,7 @@ async function executeRun(options) {
4250
4367
  }
4251
4368
  function printDryRunCommands(types, options, config) {
4252
4369
  console.log();
4253
- console.log(chalk5.cyan(" \u53EF\u6267\u884C\u7684\u6D4B\u8BD5\u547D\u4EE4:\n"));
4370
+ console.log(chalk6.cyan(" \u53EF\u6267\u884C\u7684\u6D4B\u8BD5\u547D\u4EE4:\n"));
4254
4371
  for (const testType of types) {
4255
4372
  const label = TYPE_LABELS2[testType];
4256
4373
  const runner = TYPE_RUNNERS[testType];
@@ -4287,17 +4404,17 @@ function printDryRunCommands(types, options, config) {
4287
4404
  default:
4288
4405
  cmd = `# ${label}: \u672A\u77E5\u8FD0\u884C\u5668`;
4289
4406
  }
4290
- console.log(chalk5.white(` ${label}:`));
4291
- console.log(chalk5.cyan(` ${cmd}`));
4407
+ console.log(chalk6.white(` ${label}:`));
4408
+ console.log(chalk6.cyan(` ${cmd}`));
4292
4409
  console.log();
4293
4410
  }
4294
- console.log(chalk5.gray(" \u6216\u4F7F\u7528 QAT \u7EDF\u4E00\u8FD0\u884C:"));
4411
+ console.log(chalk6.gray(" \u6216\u4F7F\u7528 QAT \u7EDF\u4E00\u8FD0\u884C:"));
4295
4412
  if (types.length === 1) {
4296
- console.log(chalk5.cyan(` qat run -t ${types[0]}`));
4413
+ console.log(chalk6.cyan(` qat run -t ${types[0]}`));
4297
4414
  } else {
4298
- console.log(chalk5.cyan(` qat run -t ${types.join(" -t ")}`));
4299
- console.log(chalk5.gray(" # \u5E76\u884C\u8FD0\u884C"));
4300
- console.log(chalk5.cyan(" qat run -p"));
4415
+ console.log(chalk6.cyan(` qat run -t ${types.join(" -t ")}`));
4416
+ console.log(chalk6.gray(" # \u5E76\u884C\u8FD0\u884C"));
4417
+ console.log(chalk6.cyan(" qat run -p"));
4301
4418
  }
4302
4419
  console.log();
4303
4420
  }
@@ -4320,7 +4437,7 @@ async function determineTypesToRun(type, file, config) {
4320
4437
  name: "selectedTypes",
4321
4438
  message: "\u9009\u62E9\u8981\u8FD0\u884C\u7684\u6D4B\u8BD5\u7C7B\u578B (\u7A7A\u683C\u9009\u62E9/\u53D6\u6D88\uFF0C\u56DE\u8F66\u786E\u8BA4):",
4322
4439
  choices: enabledTypes.map((t) => ({
4323
- name: `${TYPE_LABELS2[t]} (${chalk5.gray(TYPE_RUNNERS[t])})`,
4440
+ name: `${TYPE_LABELS2[t]} (${chalk6.gray(TYPE_RUNNERS[t])})`,
4324
4441
  value: t,
4325
4442
  checked: true
4326
4443
  })),
@@ -4380,7 +4497,7 @@ async function runTestType(testType, config, options) {
4380
4497
  }
4381
4498
  }
4382
4499
  async function runWatchMode(_config, options) {
4383
- console.log(chalk5.cyan(" \u76D1\u542C\u6A21\u5F0F\u5DF2\u542F\u52A8 (Ctrl+C \u9000\u51FA)\n"));
4500
+ console.log(chalk6.cyan(" \u76D1\u542C\u6A21\u5F0F\u5DF2\u542F\u52A8 (Ctrl+C \u9000\u51FA)\n"));
4384
4501
  const { spawn } = await import("child_process");
4385
4502
  const args = ["vitest", "--watch"];
4386
4503
  if (options.file) {
@@ -4404,7 +4521,7 @@ async function runWatchMode(_config, options) {
4404
4521
  shell: true
4405
4522
  });
4406
4523
  child.on("error", (err) => {
4407
- console.error(chalk5.red(`
4524
+ console.error(chalk6.red(`
4408
4525
  Vitest \u542F\u52A8\u5931\u8D25: ${err.message}
4409
4526
  `));
4410
4527
  });
@@ -4459,17 +4576,17 @@ function displayJestStyleResults(results) {
4459
4576
  for (const result of results) {
4460
4577
  const typeLabel = TYPE_LABELS2[result.type] || result.type;
4461
4578
  if (result.suites.length === 0) {
4462
- console.log(chalk5.gray(` ${typeLabel}: \u65E0\u6D4B\u8BD5\u7ED3\u679C`));
4579
+ console.log(chalk6.gray(` ${typeLabel}: \u65E0\u6D4B\u8BD5\u7ED3\u679C`));
4463
4580
  continue;
4464
4581
  }
4465
4582
  for (const suite of result.suites) {
4466
4583
  if (suite.tests.length === 0) continue;
4467
- const suiteIcon = suite.status === "passed" ? chalk5.green("PASS") : chalk5.red("FAIL");
4468
- console.log(` ${suiteIcon} ${chalk5.white(suite.name)} ${chalk5.gray(`(${formatDuration2(suite.duration)})`)}`);
4584
+ const suiteIcon = suite.status === "passed" ? chalk6.green("PASS") : chalk6.red("FAIL");
4585
+ console.log(` ${suiteIcon} ${chalk6.white(suite.name)} ${chalk6.gray(`(${formatDuration2(suite.duration)})`)}`);
4469
4586
  for (const test of suite.tests) {
4470
- const icon = test.status === "passed" ? chalk5.green(" \u2713") : test.status === "failed" ? chalk5.red(" \u2715") : chalk5.yellow(" \u25CB");
4471
- const name = test.status === "failed" ? chalk5.red(test.name) : test.name;
4472
- console.log(` ${icon} ${name} ${chalk5.gray(formatDuration2(test.duration))}`);
4587
+ const icon = test.status === "passed" ? chalk6.green(" \u2713") : test.status === "failed" ? chalk6.red(" \u2715") : chalk6.yellow(" \u25CB");
4588
+ const name = test.status === "failed" ? chalk6.red(test.name) : test.name;
4589
+ console.log(` ${icon} ${name} ${chalk6.gray(formatDuration2(test.duration))}`);
4473
4590
  }
4474
4591
  }
4475
4592
  console.log();
@@ -4501,28 +4618,28 @@ function displayJestStyleResults(results) {
4501
4618
  }
4502
4619
  }
4503
4620
  const total = totalPassed + totalFailed + totalSkipped;
4504
- console.log(chalk5.cyan(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
4505
- console.log(chalk5.white(" \u6D4B\u8BD5\u7ED3\u679C\u6C47\u603B"));
4506
- console.log(chalk5.cyan(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
4621
+ console.log(chalk6.cyan(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
4622
+ console.log(chalk6.white(" \u6D4B\u8BD5\u7ED3\u679C\u6C47\u603B"));
4623
+ console.log(chalk6.cyan(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
4507
4624
  console.log();
4508
- console.log(` ${chalk5.white("\u7C7B\u578B".padEnd(14))} ${chalk5.white("\u901A\u8FC7".padStart(6))} ${chalk5.white("\u5931\u8D25".padStart(6))} ${chalk5.white("\u8DF3\u8FC7".padStart(6))} ${chalk5.white("\u603B\u8BA1".padStart(6))} ${chalk5.white("\u901A\u8FC7\u7387".padStart(8))} ${chalk5.white("\u8017\u65F6".padStart(8))}`);
4625
+ console.log(` ${chalk6.white("\u7C7B\u578B".padEnd(14))} ${chalk6.white("\u901A\u8FC7".padStart(6))} ${chalk6.white("\u5931\u8D25".padStart(6))} ${chalk6.white("\u8DF3\u8FC7".padStart(6))} ${chalk6.white("\u603B\u8BA1".padStart(6))} ${chalk6.white("\u901A\u8FC7\u7387".padStart(8))} ${chalk6.white("\u8017\u65F6".padStart(8))}`);
4509
4626
  console.log(` ${"\u2500".repeat(14)} ${"\u2500".repeat(6)} ${"\u2500".repeat(6)} ${"\u2500".repeat(6)} ${"\u2500".repeat(6)} ${"\u2500".repeat(8)} ${"\u2500".repeat(8)}`);
4510
4627
  for (const [type, stats] of Object.entries(typeStats)) {
4511
4628
  const label = (TYPE_LABELS2[type] || type).padEnd(14);
4512
4629
  const typeTotal = stats.passed + stats.failed + stats.skipped;
4513
4630
  const rate = typeTotal > 0 ? (stats.passed / typeTotal * 100).toFixed(0) + "%" : "-";
4514
- const rateColored = typeTotal > 0 && stats.passed === typeTotal ? chalk5.green(rate.padStart(8)) : stats.failed > 0 ? chalk5.red(rate.padStart(8)) : rate.padStart(8);
4631
+ const rateColored = typeTotal > 0 && stats.passed === typeTotal ? chalk6.green(rate.padStart(8)) : stats.failed > 0 ? chalk6.red(rate.padStart(8)) : rate.padStart(8);
4515
4632
  console.log(` ${label} ${String(stats.passed).padStart(6)} ${String(stats.failed).padStart(6)} ${String(stats.skipped).padStart(6)} ${String(typeTotal).padStart(6)} ${rateColored} ${formatDuration2(stats.duration).padStart(8)}`);
4516
4633
  }
4517
4634
  console.log(` ${"\u2500".repeat(14)} ${"\u2500".repeat(6)} ${"\u2500".repeat(6)} ${"\u2500".repeat(6)} ${"\u2500".repeat(6)} ${"\u2500".repeat(8)} ${"\u2500".repeat(8)}`);
4518
4635
  const totalRate = total > 0 ? (totalPassed / total * 100).toFixed(0) + "%" : "-";
4519
- const totalRateColored = total > 0 && totalFailed === 0 ? chalk5.green(totalRate.padStart(8)) : totalFailed > 0 ? chalk5.red(totalRate.padStart(8)) : totalRate.padStart(8);
4636
+ const totalRateColored = total > 0 && totalFailed === 0 ? chalk6.green(totalRate.padStart(8)) : totalFailed > 0 ? chalk6.red(totalRate.padStart(8)) : totalRate.padStart(8);
4520
4637
  console.log(` ${"\u603B\u8BA1".padEnd(14)} ${String(totalPassed).padStart(6)} ${String(totalFailed).padStart(6)} ${String(totalSkipped).padStart(6)} ${String(total).padStart(6)} ${totalRateColored} ${formatDuration2(totalDuration).padStart(8)}`);
4521
4638
  console.log();
4522
4639
  for (const result of results) {
4523
4640
  if (result.coverage) {
4524
4641
  const c = result.coverage;
4525
- console.log(chalk5.cyan(" \u8986\u76D6\u7387:"));
4642
+ console.log(chalk6.cyan(" \u8986\u76D6\u7387:"));
4526
4643
  console.log(` \u8BED\u53E5: ${coverageColor(c.statements)} \u5206\u652F: ${coverageColor(c.branches)} \u51FD\u6570: ${coverageColor(c.functions)} \u884C: ${coverageColor(c.lines)}`);
4527
4644
  console.log();
4528
4645
  }
@@ -4530,7 +4647,7 @@ function displayJestStyleResults(results) {
4530
4647
  for (const result of results) {
4531
4648
  if (result.type === "performance" && result.performance) {
4532
4649
  const p = result.performance;
4533
- console.log(chalk5.cyan(" \u6027\u80FD\u6307\u6807:"));
4650
+ console.log(chalk6.cyan(" \u6027\u80FD\u6307\u6807:"));
4534
4651
  console.log(` Performance: ${scoreColor(p.performance)} ${p.performance}/100`);
4535
4652
  console.log(` Accessibility: ${scoreColor(p.accessibility)} ${p.accessibility}/100`);
4536
4653
  console.log(` Best Practices: ${scoreColor(p.bestPractices)} ${p.bestPractices}/100`);
@@ -4547,31 +4664,31 @@ function displayJestStyleResults(results) {
4547
4664
  )
4548
4665
  );
4549
4666
  if (failedTests.length > 0) {
4550
- console.log(chalk5.red(" \u5931\u8D25\u8BE6\u60C5:"));
4667
+ console.log(chalk6.red(" \u5931\u8D25\u8BE6\u60C5:"));
4551
4668
  for (const { suite, test } of failedTests) {
4552
- console.log(chalk5.red(` \u2715 ${suite.name} > ${test.name}`));
4669
+ console.log(chalk6.red(` \u2715 ${suite.name} > ${test.name}`));
4553
4670
  if (test.error?.message) {
4554
- console.log(chalk5.gray(` ${test.error.message.split("\n")[0]}`));
4671
+ console.log(chalk6.gray(` ${test.error.message.split("\n")[0]}`));
4555
4672
  }
4556
4673
  }
4557
4674
  console.log();
4558
4675
  }
4559
4676
  if (totalFailed > 0) {
4560
- console.log(chalk5.red(` Tests: ${totalFailed} failed, ${totalPassed} passed, ${total} total`));
4677
+ console.log(chalk6.red(` Tests: ${totalFailed} failed, ${totalPassed} passed, ${total} total`));
4561
4678
  process.exitCode = 1;
4562
4679
  } else if (total === 0) {
4563
- console.log(chalk5.yellow(" \u6CA1\u6709\u53D1\u73B0\u6D4B\u8BD5\u7528\u4F8B"));
4680
+ console.log(chalk6.yellow(" \u6CA1\u6709\u53D1\u73B0\u6D4B\u8BD5\u7528\u4F8B"));
4564
4681
  } else {
4565
- console.log(chalk5.green(` Tests: ${totalPassed} passed, ${total} total`));
4682
+ console.log(chalk6.green(` Tests: ${totalPassed} passed, ${total} total`));
4566
4683
  }
4567
- console.log(chalk5.gray(` Time: ${formatDuration2(totalDuration)}`));
4684
+ console.log(chalk6.gray(` Time: ${formatDuration2(totalDuration)}`));
4568
4685
  console.log();
4569
4686
  }
4570
4687
  function coverageColor(value) {
4571
4688
  const pct3 = `${(value * 100).toFixed(1)}%`;
4572
- if (value >= 0.8) return chalk5.green(pct3);
4573
- if (value >= 0.5) return chalk5.yellow(pct3);
4574
- return chalk5.red(pct3);
4689
+ if (value >= 0.8) return chalk6.green(pct3);
4690
+ if (value >= 0.5) return chalk6.yellow(pct3);
4691
+ return chalk6.red(pct3);
4575
4692
  }
4576
4693
  async function aiAnalyzeFailures(results, aiConfig) {
4577
4694
  const failedTests = results.flatMap(
@@ -4580,23 +4697,23 @@ async function aiAnalyzeFailures(results, aiConfig) {
4580
4697
  )
4581
4698
  );
4582
4699
  if (failedTests.length === 0) return;
4583
- console.log(chalk5.magenta(" \u{1F916} AI \u5206\u6790\u5931\u8D25\u539F\u56E0..."));
4700
+ console.log(chalk6.magenta(" \u{1F916} AI \u5206\u6790\u5931\u8D25\u539F\u56E0..."));
4584
4701
  console.log();
4585
4702
  const provider = getAIProvider(aiConfig);
4586
4703
  if (!provider.capabilities.suggestFix) return;
4587
4704
  for (const { suite, test } of failedTests.slice(0, 5)) {
4588
4705
  try {
4589
4706
  const suggestions = await provider.suggestFix(test.error);
4590
- console.log(chalk5.white(` ${suite.name} > ${test.name}`));
4707
+ console.log(chalk6.white(` ${suite.name} > ${test.name}`));
4591
4708
  if (test.error?.message) {
4592
- console.log(chalk5.gray(` \u9519\u8BEF: ${test.error.message.split("\n")[0]}`));
4709
+ console.log(chalk6.gray(` \u9519\u8BEF: ${test.error.message.split("\n")[0]}`));
4593
4710
  }
4594
4711
  for (const suggestion of suggestions.slice(0, 3)) {
4595
- console.log(chalk5.cyan(` \u2192 ${suggestion}`));
4712
+ console.log(chalk6.cyan(` \u2192 ${suggestion}`));
4596
4713
  }
4597
4714
  console.log();
4598
4715
  } catch (error) {
4599
- console.log(chalk5.gray(` AI \u5206\u6790\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`));
4716
+ console.log(chalk6.gray(` AI \u5206\u6790\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`));
4600
4717
  }
4601
4718
  }
4602
4719
  }
@@ -4608,9 +4725,9 @@ function formatDuration2(ms) {
4608
4725
  return `${min}m ${sec}s`;
4609
4726
  }
4610
4727
  function scoreColor(score) {
4611
- if (score >= 90) return chalk5.green("\u25CF");
4612
- if (score >= 50) return chalk5.yellow("\u25CF");
4613
- return chalk5.red("\u25CF");
4728
+ if (score >= 90) return chalk6.green("\u25CF");
4729
+ if (score >= 50) return chalk6.yellow("\u25CF");
4730
+ return chalk6.red("\u25CF");
4614
4731
  }
4615
4732
  async function checkDevServer(config) {
4616
4733
  const baseUrl = config.playwright.baseURL || "http://localhost:5173";
@@ -4629,7 +4746,7 @@ async function startDevServer(config) {
4629
4746
  const hasPnpm = fs11.existsSync(path12.join(process.cwd(), "pnpm-lock.yaml"));
4630
4747
  const hasYarn = fs11.existsSync(path12.join(process.cwd(), "yarn.lock"));
4631
4748
  const pkgCmd = hasPnpm ? "pnpm" : hasYarn ? "yarn" : "npm";
4632
- console.log(chalk5.cyan(` \u6B63\u5728\u542F\u52A8 dev server (${pkgCmd} run dev) ...`));
4749
+ console.log(chalk6.cyan(` \u6B63\u5728\u542F\u52A8 dev server (${pkgCmd} run dev) ...`));
4633
4750
  const child = spawn(pkgCmd, ["run", "dev"], {
4634
4751
  cwd: process.cwd(),
4635
4752
  stdio: "pipe",
@@ -4645,13 +4762,13 @@ async function startDevServer(config) {
4645
4762
  waited += interval;
4646
4763
  const isUp = await checkDevServer(config);
4647
4764
  if (isUp) {
4648
- console.log(chalk5.green(` \u2713 dev server \u5DF2\u542F\u52A8 (${baseUrl})`));
4765
+ console.log(chalk6.green(` \u2713 dev server \u5DF2\u542F\u52A8 (${baseUrl})`));
4649
4766
  child.unref();
4650
4767
  return true;
4651
4768
  }
4652
4769
  }
4653
4770
  child.kill();
4654
- console.log(chalk5.red(" \u2717 dev server \u542F\u52A8\u8D85\u65F6"));
4771
+ console.log(chalk6.red(" \u2717 dev server \u542F\u52A8\u8D85\u65F6"));
4655
4772
  return false;
4656
4773
  }
4657
4774
  function saveRunResults(results) {
@@ -4743,7 +4860,7 @@ async function installTestDependencies(missingDeps) {
4743
4860
  spinner.succeed(`${dep.pkg} \u5B89\u88C5\u6210\u529F`);
4744
4861
  } catch (error) {
4745
4862
  spinner.fail(`${dep.pkg} \u5B89\u88C5\u5931\u8D25`);
4746
- console.log(chalk5.gray(` \u53EF\u624B\u52A8\u5B89\u88C5: ${chalk5.cyan(dep.installCmd)}`));
4863
+ console.log(chalk6.gray(` \u53EF\u624B\u52A8\u5B89\u88C5: ${chalk6.cyan(dep.installCmd)}`));
4747
4864
  allSuccess = false;
4748
4865
  }
4749
4866
  }
@@ -4751,7 +4868,7 @@ async function installTestDependencies(missingDeps) {
4751
4868
  }
4752
4869
 
4753
4870
  // src/commands/mock.ts
4754
- import chalk6 from "chalk";
4871
+ import chalk7 from "chalk";
4755
4872
  import ora5 from "ora";
4756
4873
  function registerMockCommand(program2) {
4757
4874
  program2.command("mock").description("Mock\u670D\u52A1\u7BA1\u7406 - \u542F\u52A8/\u505C\u6B62Mock API\u670D\u52A1\u5668").argument("<action>", "\u64CD\u4F5C\u7C7B\u578B (start|stop|status)").option("-p, --port <port>", "\u6307\u5B9A\u7AEF\u53E3\u53F7", "3456").action(async (action, options) => {
@@ -4762,7 +4879,7 @@ function registerMockCommand(program2) {
4762
4879
  config: options.config
4763
4880
  });
4764
4881
  } catch (error) {
4765
- console.error(chalk6.red(`
4882
+ console.error(chalk7.red(`
4766
4883
  \u2717 ${error instanceof Error ? error.message : String(error)}
4767
4884
  `));
4768
4885
  process.exit(1);
@@ -4786,9 +4903,9 @@ async function executeMock(options) {
4786
4903
  break;
4787
4904
  }
4788
4905
  default: {
4789
- console.error(chalk6.red(`
4906
+ console.error(chalk7.red(`
4790
4907
  \u672A\u77E5\u64CD\u4F5C: ${options.action}`));
4791
- console.log(chalk6.gray(" \u53EF\u7528\u64CD\u4F5C: start, stop, status\n"));
4908
+ console.log(chalk7.gray(" \u53EF\u7528\u64CD\u4F5C: start, stop, status\n"));
4792
4909
  process.exit(1);
4793
4910
  }
4794
4911
  }
@@ -4796,7 +4913,7 @@ async function executeMock(options) {
4796
4913
  async function startMock(port, routesDir) {
4797
4914
  const state = getMockServerState();
4798
4915
  if (state.running) {
4799
- console.log(chalk6.yellow(`
4916
+ console.log(chalk7.yellow(`
4800
4917
  Mock\u670D\u52A1\u5668\u5DF2\u5728\u8FD0\u884C (\u7AEF\u53E3: ${state.port})
4801
4918
  `));
4802
4919
  return;
@@ -4810,22 +4927,22 @@ async function startMock(port, routesDir) {
4810
4927
  await startMockServer(port, routes);
4811
4928
  spinner.succeed(`Mock\u670D\u52A1\u5668\u5DF2\u542F\u52A8`);
4812
4929
  console.log();
4813
- console.log(chalk6.white(" \u5730\u5740:"), chalk6.cyan(`http://localhost:${port}`));
4814
- console.log(chalk6.white(" \u8DEF\u7531:"), routes.length > 0 ? `${routes.length} \u4E2A` : chalk6.gray("\u4F7F\u7528\u9ED8\u8BA4\u8DEF\u7531"));
4815
- console.log(chalk6.white(" \u5065\u5EB7\u68C0\u67E5:"), chalk6.cyan(`http://localhost:${port}/api/health`));
4930
+ console.log(chalk7.white(" \u5730\u5740:"), chalk7.cyan(`http://localhost:${port}`));
4931
+ console.log(chalk7.white(" \u8DEF\u7531:"), routes.length > 0 ? `${routes.length} \u4E2A` : chalk7.gray("\u4F7F\u7528\u9ED8\u8BA4\u8DEF\u7531"));
4932
+ console.log(chalk7.white(" \u5065\u5EB7\u68C0\u67E5:"), chalk7.cyan(`http://localhost:${port}/api/health`));
4816
4933
  if (routes.length > 0) {
4817
4934
  console.log();
4818
- console.log(chalk6.white(" \u5DF2\u6CE8\u518C\u8DEF\u7531:"));
4935
+ console.log(chalk7.white(" \u5DF2\u6CE8\u518C\u8DEF\u7531:"));
4819
4936
  for (const route of routes.slice(0, 10)) {
4820
- const method = chalk6.gray(route.method.padEnd(6));
4937
+ const method = chalk7.gray(route.method.padEnd(6));
4821
4938
  console.log(` ${method} ${route.path}`);
4822
4939
  }
4823
4940
  if (routes.length > 10) {
4824
- console.log(chalk6.gray(` ... \u8FD8\u6709 ${routes.length - 10} \u4E2A\u8DEF\u7531`));
4941
+ console.log(chalk7.gray(` ... \u8FD8\u6709 ${routes.length - 10} \u4E2A\u8DEF\u7531`));
4825
4942
  }
4826
4943
  }
4827
4944
  console.log();
4828
- console.log(chalk6.gray(" \u6309 Ctrl+C \u505C\u6B62\u670D\u52A1\u5668"));
4945
+ console.log(chalk7.gray(" \u6309 Ctrl+C \u505C\u6B62\u670D\u52A1\u5668"));
4829
4946
  process.on("SIGINT", async () => {
4830
4947
  const stopSpinner = ora5("\u6B63\u5728\u505C\u6B62Mock\u670D\u52A1\u5668...").start();
4831
4948
  await stopMockServer();
@@ -4842,7 +4959,7 @@ async function startMock(port, routesDir) {
4842
4959
  async function stopMock() {
4843
4960
  const state = getMockServerState();
4844
4961
  if (!state.running) {
4845
- console.log(chalk6.yellow("\n Mock\u670D\u52A1\u5668\u672A\u5728\u8FD0\u884C\n"));
4962
+ console.log(chalk7.yellow("\n Mock\u670D\u52A1\u5668\u672A\u5728\u8FD0\u884C\n"));
4846
4963
  return;
4847
4964
  }
4848
4965
  const spinner = ora5("\u6B63\u5728\u505C\u6B62Mock\u670D\u52A1\u5668...").start();
@@ -4859,18 +4976,18 @@ function showStatus() {
4859
4976
  const state = getMockServerState();
4860
4977
  console.log();
4861
4978
  if (state.running) {
4862
- console.log(chalk6.green(" \u25CF Mock\u670D\u52A1\u5668\u8FD0\u884C\u4E2D"));
4863
- console.log(chalk6.white(" \u7AEF\u53E3:"), state.port);
4864
- console.log(chalk6.white(" \u8DEF\u7531:"), state.routes.length);
4979
+ console.log(chalk7.green(" \u25CF Mock\u670D\u52A1\u5668\u8FD0\u884C\u4E2D"));
4980
+ console.log(chalk7.white(" \u7AEF\u53E3:"), state.port);
4981
+ console.log(chalk7.white(" \u8DEF\u7531:"), state.routes.length);
4865
4982
  } else {
4866
- console.log(chalk6.gray(" \u25CB Mock\u670D\u52A1\u5668\u672A\u8FD0\u884C"));
4867
- console.log(chalk6.gray(" \u4F7F\u7528 qat mock start \u542F\u52A8"));
4983
+ console.log(chalk7.gray(" \u25CB Mock\u670D\u52A1\u5668\u672A\u8FD0\u884C"));
4984
+ console.log(chalk7.gray(" \u4F7F\u7528 qat mock start \u542F\u52A8"));
4868
4985
  }
4869
4986
  console.log();
4870
4987
  }
4871
4988
 
4872
4989
  // src/commands/report.ts
4873
- import chalk7 from "chalk";
4990
+ import chalk8 from "chalk";
4874
4991
  import ora6 from "ora";
4875
4992
  import fs12 from "fs";
4876
4993
  import path13 from "path";
@@ -4880,7 +4997,7 @@ function registerReportCommand(program2) {
4880
4997
  try {
4881
4998
  await executeReport(options);
4882
4999
  } catch (error) {
4883
- console.error(chalk7.red(`
5000
+ console.error(chalk8.red(`
4884
5001
  \u2717 ${error instanceof Error ? error.message : String(error)}
4885
5002
  `));
4886
5003
  process.exit(1);
@@ -4894,7 +5011,7 @@ async function executeReport(options) {
4894
5011
  const results = collectResults();
4895
5012
  if (results.length === 0) {
4896
5013
  spinner.info("\u6CA1\u6709\u627E\u5230\u6D4B\u8BD5\u7ED3\u679C");
4897
- console.log(chalk7.gray("\n \u63D0\u793A: \u5148\u8FD0\u884C qat run \u751F\u6210\u6D4B\u8BD5\u7ED3\u679C\n"));
5014
+ console.log(chalk8.gray("\n \u63D0\u793A: \u5148\u8FD0\u884C qat run \u751F\u6210\u6D4B\u8BD5\u7ED3\u679C\n"));
4898
5015
  return;
4899
5016
  }
4900
5017
  spinner.text = "\u6B63\u5728\u751F\u6210\u6D4B\u8BD5\u62A5\u544A...";
@@ -4947,31 +5064,31 @@ function displayReportResult(reportPath, data) {
4947
5064
  const relativePath = path13.relative(process.cwd(), reportPath);
4948
5065
  const passRate = data.summary.total > 0 ? (data.summary.passed / data.summary.total * 100).toFixed(1) : "0";
4949
5066
  console.log();
4950
- console.log(chalk7.green(" \u2713 \u6D4B\u8BD5\u62A5\u544A\u5DF2\u751F\u6210"));
5067
+ console.log(chalk8.green(" \u2713 \u6D4B\u8BD5\u62A5\u544A\u5DF2\u751F\u6210"));
4951
5068
  console.log();
4952
- console.log(chalk7.white(" \u62A5\u544A\u8DEF\u5F84:"), chalk7.cyan(relativePath));
4953
- console.log(chalk7.white(" \u901A\u8FC7\u7387: "), parseFloat(passRate) >= 80 ? chalk7.green(`${passRate}%`) : parseFloat(passRate) >= 50 ? chalk7.yellow(`${passRate}%`) : chalk7.red(`${passRate}%`));
4954
- console.log(chalk7.white(" \u6D4B\u8BD5\u7528\u4F8B:"), `${data.summary.total} total`);
4955
- console.log(chalk7.white(" \u2705 \u901A\u8FC7: "), chalk7.green(String(data.summary.passed)));
5069
+ console.log(chalk8.white(" \u62A5\u544A\u8DEF\u5F84:"), chalk8.cyan(relativePath));
5070
+ console.log(chalk8.white(" \u901A\u8FC7\u7387: "), parseFloat(passRate) >= 80 ? chalk8.green(`${passRate}%`) : parseFloat(passRate) >= 50 ? chalk8.yellow(`${passRate}%`) : chalk8.red(`${passRate}%`));
5071
+ console.log(chalk8.white(" \u6D4B\u8BD5\u7528\u4F8B:"), `${data.summary.total} total`);
5072
+ console.log(chalk8.white(" \u2705 \u901A\u8FC7: "), chalk8.green(String(data.summary.passed)));
4956
5073
  if (data.summary.failed > 0) {
4957
- console.log(chalk7.white(" \u274C \u5931\u8D25: "), chalk7.red(String(data.summary.failed)));
5074
+ console.log(chalk8.white(" \u274C \u5931\u8D25: "), chalk8.red(String(data.summary.failed)));
4958
5075
  }
4959
5076
  if (data.summary.skipped > 0) {
4960
- console.log(chalk7.white(" \u23ED\uFE0F \u8DF3\u8FC7: "), chalk7.yellow(String(data.summary.skipped)));
5077
+ console.log(chalk8.white(" \u23ED\uFE0F \u8DF3\u8FC7: "), chalk8.yellow(String(data.summary.skipped)));
4961
5078
  }
4962
5079
  if (Object.keys(data.byType).length > 0) {
4963
5080
  console.log();
4964
- console.log(chalk7.white(" \u6309\u7C7B\u578B:"));
5081
+ console.log(chalk8.white(" \u6309\u7C7B\u578B:"));
4965
5082
  for (const [type, stats] of Object.entries(data.byType)) {
4966
5083
  const rate = stats.total > 0 ? (stats.passed / stats.total * 100).toFixed(0) : "0";
4967
- const icon = stats.failed > 0 ? chalk7.red("\u274C") : chalk7.green("\u2705");
5084
+ const icon = stats.failed > 0 ? chalk8.red("\u274C") : chalk8.green("\u2705");
4968
5085
  console.log(` ${icon} ${type}: ${stats.passed}/${stats.total} (${rate}%)`);
4969
5086
  }
4970
5087
  }
4971
5088
  if (data.coverage) {
4972
5089
  console.log();
4973
- console.log(chalk7.white(" \u8986\u76D6\u7387:"));
4974
- console.log(` \u8BED\u53E5: ${chalk7.cyan(pct2(data.coverage.statements))} \u5206\u652F: ${chalk7.cyan(pct2(data.coverage.branches))} \u51FD\u6570: ${chalk7.cyan(pct2(data.coverage.functions))} \u884C: ${chalk7.cyan(pct2(data.coverage.lines))}`);
5090
+ console.log(chalk8.white(" \u8986\u76D6\u7387:"));
5091
+ console.log(` \u8BED\u53E5: ${chalk8.cyan(pct2(data.coverage.statements))} \u5206\u652F: ${chalk8.cyan(pct2(data.coverage.branches))} \u51FD\u6570: ${chalk8.cyan(pct2(data.coverage.functions))} \u884C: ${chalk8.cyan(pct2(data.coverage.lines))}`);
4975
5092
  }
4976
5093
  console.log();
4977
5094
  }
@@ -4991,13 +5108,13 @@ async function openReport(reportPath) {
4991
5108
  }
4992
5109
  exec(command, { shell: true }, (error) => {
4993
5110
  if (error) {
4994
- console.log(chalk7.gray(" \u63D0\u793A: \u624B\u52A8\u6253\u5F00\u62A5\u544A\u67E5\u770B"));
5111
+ console.log(chalk8.gray(" \u63D0\u793A: \u624B\u52A8\u6253\u5F00\u62A5\u544A\u67E5\u770B"));
4995
5112
  }
4996
5113
  });
4997
5114
  }
4998
5115
 
4999
5116
  // src/commands/visual.ts
5000
- import chalk8 from "chalk";
5117
+ import chalk9 from "chalk";
5001
5118
  import ora7 from "ora";
5002
5119
 
5003
5120
  // src/services/visual.ts
@@ -5164,7 +5281,7 @@ function registerVisualCommand(program2) {
5164
5281
  config: options.config
5165
5282
  });
5166
5283
  } catch (error) {
5167
- console.error(chalk8.red(`
5284
+ console.error(chalk9.red(`
5168
5285
  \u2717 ${error instanceof Error ? error.message : String(error)}
5169
5286
  `));
5170
5287
  process.exit(1);
@@ -5190,9 +5307,9 @@ async function executeVisual(options) {
5190
5307
  break;
5191
5308
  }
5192
5309
  default: {
5193
- console.error(chalk8.red(`
5310
+ console.error(chalk9.red(`
5194
5311
  \u672A\u77E5\u64CD\u4F5C: ${options.action}`));
5195
- console.log(chalk8.gray(" \u53EF\u7528\u64CD\u4F5C: test, approve, clean\n"));
5312
+ console.log(chalk9.gray(" \u53EF\u7528\u64CD\u4F5C: test, approve, clean\n"));
5196
5313
  process.exit(1);
5197
5314
  }
5198
5315
  }
@@ -5216,7 +5333,7 @@ async function runVisualTest(threshold, baselineDir, diffDir, config) {
5216
5333
  const currentDir = findCurrentScreenshotsDir(baselineDir);
5217
5334
  if (!currentDir) {
5218
5335
  compareSpinner.info("\u6CA1\u6709\u627E\u5230\u622A\u56FE\u6587\u4EF6");
5219
- console.log(chalk8.gray("\n \u63D0\u793A: \u5148\u8FD0\u884C qat run -t visual \u751F\u6210\u622A\u56FE\n"));
5336
+ console.log(chalk9.gray("\n \u63D0\u793A: \u5148\u8FD0\u884C qat run -t visual \u751F\u6210\u622A\u56FE\n"));
5220
5337
  return;
5221
5338
  }
5222
5339
  const results = compareDirectories(baselineDir, currentDir, diffDir, threshold);
@@ -5262,48 +5379,48 @@ function displayVisualResults(results, threshold) {
5262
5379
  const passed = results.filter((r) => r.passed);
5263
5380
  const failed = results.filter((r) => !r.passed);
5264
5381
  console.log();
5265
- console.log(chalk8.cyan(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
5382
+ console.log(chalk9.cyan(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
5266
5383
  if (failed.length === 0) {
5267
- console.log(chalk8.green(` \u2713 \u5168\u90E8\u901A\u8FC7 (${results.length} \u4E2A\u622A\u56FE\u6BD4\u5BF9)`));
5384
+ console.log(chalk9.green(` \u2713 \u5168\u90E8\u901A\u8FC7 (${results.length} \u4E2A\u622A\u56FE\u6BD4\u5BF9)`));
5268
5385
  } else {
5269
- console.log(chalk8.red(` \u2717 ${failed.length} \u4E2A\u622A\u56FE\u5B58\u5728\u5DEE\u5F02`));
5386
+ console.log(chalk9.red(` \u2717 ${failed.length} \u4E2A\u622A\u56FE\u5B58\u5728\u5DEE\u5F02`));
5270
5387
  }
5271
5388
  console.log();
5272
- console.log(` ${chalk8.white("\u9608\u503C:")} ${(threshold * 100).toFixed(0)}%`);
5273
- console.log(` ${chalk8.green("\u901A\u8FC7:")} ${passed.length}`);
5274
- console.log(` ${chalk8.red("\u5931\u8D25:")} ${failed.length}`);
5389
+ console.log(` ${chalk9.white("\u9608\u503C:")} ${(threshold * 100).toFixed(0)}%`);
5390
+ console.log(` ${chalk9.green("\u901A\u8FC7:")} ${passed.length}`);
5391
+ console.log(` ${chalk9.red("\u5931\u8D25:")} ${failed.length}`);
5275
5392
  if (passed.length > 0) {
5276
5393
  console.log();
5277
- console.log(chalk8.green(" \u901A\u8FC7\u7684\u622A\u56FE:"));
5394
+ console.log(chalk9.green(" \u901A\u8FC7\u7684\u622A\u56FE:"));
5278
5395
  for (const result of passed) {
5279
5396
  const name = path15.basename(result.baselinePath);
5280
5397
  if (result.totalPixels > 0) {
5281
5398
  const diffPct = (result.diffRatio * 100).toFixed(2);
5282
- console.log(chalk8.green(` \u2713 ${name} (\u5DEE\u5F02: ${diffPct}%)`));
5399
+ console.log(chalk9.green(` \u2713 ${name} (\u5DEE\u5F02: ${diffPct}%)`));
5283
5400
  } else {
5284
- console.log(chalk8.green(` \u2713 ${name} (\u65B0\u5EFA\u57FA\u7EBF)`));
5401
+ console.log(chalk9.green(` \u2713 ${name} (\u65B0\u5EFA\u57FA\u7EBF)`));
5285
5402
  }
5286
5403
  }
5287
5404
  }
5288
5405
  if (failed.length > 0) {
5289
5406
  console.log();
5290
- console.log(chalk8.red(" \u5931\u8D25\u7684\u622A\u56FE:"));
5407
+ console.log(chalk9.red(" \u5931\u8D25\u7684\u622A\u56FE:"));
5291
5408
  for (const result of failed) {
5292
5409
  const name = path15.basename(result.baselinePath);
5293
5410
  if (result.diffPixels === -1) {
5294
- console.log(chalk8.red(` \u2717 ${name} (\u5C3A\u5BF8\u4E0D\u5339\u914D)`));
5411
+ console.log(chalk9.red(` \u2717 ${name} (\u5C3A\u5BF8\u4E0D\u5339\u914D)`));
5295
5412
  } else {
5296
5413
  const diffPct = (result.diffRatio * 100).toFixed(2);
5297
- console.log(chalk8.red(` \u2717 ${name} (\u5DEE\u5F02: ${diffPct}%)`));
5414
+ console.log(chalk9.red(` \u2717 ${name} (\u5DEE\u5F02: ${diffPct}%)`));
5298
5415
  }
5299
5416
  if (result.diffPath) {
5300
- console.log(chalk8.gray(` \u5DEE\u5F02\u56FE: ${path15.relative(process.cwd(), result.diffPath)}`));
5417
+ console.log(chalk9.gray(` \u5DEE\u5F02\u56FE: ${path15.relative(process.cwd(), result.diffPath)}`));
5301
5418
  }
5302
5419
  }
5303
5420
  console.log();
5304
- console.log(chalk8.yellow(" \u63D0\u793A: \u8FD0\u884C qat visual approve \u66F4\u65B0\u57FA\u7EBF"));
5421
+ console.log(chalk9.yellow(" \u63D0\u793A: \u8FD0\u884C qat visual approve \u66F4\u65B0\u57FA\u7EBF"));
5305
5422
  }
5306
- console.log(chalk8.cyan(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
5423
+ console.log(chalk9.cyan(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
5307
5424
  console.log();
5308
5425
  }
5309
5426
  async function approveBaselines(baselineDir, diffDir) {
@@ -5322,7 +5439,7 @@ async function approveBaselines(baselineDir, diffDir) {
5322
5439
  spinner.succeed(`\u5DF2\u66F4\u65B0 ${updated.length} \u4E2A\u57FA\u7EBF\u5FEB\u7167`);
5323
5440
  console.log();
5324
5441
  for (const file of updated) {
5325
- console.log(chalk8.green(` \u2713 ${file}`));
5442
+ console.log(chalk9.green(` \u2713 ${file}`));
5326
5443
  }
5327
5444
  console.log();
5328
5445
  }
@@ -5332,14 +5449,14 @@ async function cleanAll(baselineDir, diffDir) {
5332
5449
  const diffs = cleanDiffs(diffDir);
5333
5450
  spinner.succeed("\u6E05\u7406\u5B8C\u6210");
5334
5451
  console.log();
5335
- console.log(chalk8.white(" \u5DF2\u5220\u9664:"));
5452
+ console.log(chalk9.white(" \u5DF2\u5220\u9664:"));
5336
5453
  console.log(` \u57FA\u7EBF: ${baselines} \u4E2A`);
5337
5454
  console.log(` \u5DEE\u5F02: ${diffs} \u4E2A`);
5338
5455
  console.log();
5339
5456
  }
5340
5457
 
5341
5458
  // src/commands/setup.ts
5342
- import chalk9 from "chalk";
5459
+ import chalk10 from "chalk";
5343
5460
  import inquirer4 from "inquirer";
5344
5461
  import ora8 from "ora";
5345
5462
  import { execFile as execFile4 } from "child_process";
@@ -5368,7 +5485,7 @@ function registerSetupCommand(program2) {
5368
5485
  try {
5369
5486
  await executeSetup(options);
5370
5487
  } catch (error) {
5371
- console.error(chalk9.red(`
5488
+ console.error(chalk10.red(`
5372
5489
  \u2717 ${error instanceof Error ? error.message : String(error)}
5373
5490
  `));
5374
5491
  process.exit(1);
@@ -5376,20 +5493,20 @@ function registerSetupCommand(program2) {
5376
5493
  });
5377
5494
  }
5378
5495
  async function executeSetup(options) {
5379
- console.log(chalk9.cyan("\n QAT \u4F9D\u8D56\u5B89\u88C5\u5668\n"));
5496
+ console.log(chalk10.cyan("\n QAT \u4F9D\u8D56\u5B89\u88C5\u5668\n"));
5380
5497
  const projectInfo = detectProject();
5381
5498
  if (!fs15.existsSync(path16.join(process.cwd(), "package.json"))) {
5382
5499
  throw new Error("\u672A\u627E\u5230 package.json\uFF0C\u8BF7\u5728\u9879\u76EE\u6839\u76EE\u5F55\u6267\u884C\u6B64\u547D\u4EE4");
5383
5500
  }
5384
5501
  if (projectInfo.frameworkConfidence > 0) {
5385
- console.log(chalk9.white(` \u68C0\u6D4B\u5230\u6846\u67B6: ${chalk9.cyan(projectInfo.frameworkDisplayName)}`));
5502
+ console.log(chalk10.white(` \u68C0\u6D4B\u5230\u6846\u67B6: ${chalk10.cyan(projectInfo.frameworkDisplayName)}`));
5386
5503
  if (projectInfo.uiLibrary !== "none") {
5387
- console.log(chalk9.white(` UI \u7EC4\u4EF6\u5E93: ${chalk9.cyan(projectInfo.uiLibrary)}`));
5504
+ console.log(chalk10.white(` UI \u7EC4\u4EF6\u5E93: ${chalk10.cyan(projectInfo.uiLibrary)}`));
5388
5505
  }
5389
5506
  if (projectInfo.monorepo !== "none") {
5390
- console.log(chalk9.white(` Monorepo: ${chalk9.cyan(projectInfo.monorepo)}`));
5507
+ console.log(chalk10.white(` Monorepo: ${chalk10.cyan(projectInfo.monorepo)}`));
5391
5508
  if (projectInfo.appDirs.length > 0) {
5392
- console.log(chalk9.white(` \u5B50\u9879\u76EE: ${chalk9.gray(projectInfo.appDirs.join(", "))}`));
5509
+ console.log(chalk10.white(` \u5B50\u9879\u76EE: ${chalk10.gray(projectInfo.appDirs.join(", "))}`));
5393
5510
  }
5394
5511
  }
5395
5512
  console.log();
@@ -5425,12 +5542,12 @@ async function executeSetup(options) {
5425
5542
  }
5426
5543
  const groupsToInstall = determineGroups(config, projectInfo, options.force);
5427
5544
  if (groupsToInstall.length === 0) {
5428
- console.log(chalk9.green(" \u2713 \u6240\u6709\u4F9D\u8D56\u5DF2\u5B89\u88C5\uFF0C\u65E0\u9700\u989D\u5916\u64CD\u4F5C\n"));
5545
+ console.log(chalk10.green(" \u2713 \u6240\u6709\u4F9D\u8D56\u5DF2\u5B89\u88C5\uFF0C\u65E0\u9700\u989D\u5916\u64CD\u4F5C\n"));
5429
5546
  return;
5430
5547
  }
5431
5548
  const selectedGroups = await selectGroups(groupsToInstall, options.dryRun);
5432
5549
  if (selectedGroups.length === 0) {
5433
- console.log(chalk9.gray("\n \u5DF2\u53D6\u6D88\u5B89\u88C5\n"));
5550
+ console.log(chalk10.gray("\n \u5DF2\u53D6\u6D88\u5B89\u88C5\n"));
5434
5551
  return;
5435
5552
  }
5436
5553
  const allPackages = selectedGroups.flatMap((g) => g.packages);
@@ -5444,19 +5561,19 @@ ${allPackages.map((p) => ` - ${p}`).join("\n")}`,
5444
5561
  }
5445
5562
  ]);
5446
5563
  if (!confirmed) {
5447
- console.log(chalk9.gray("\n \u5DF2\u53D6\u6D88\u5B89\u88C5\n"));
5564
+ console.log(chalk10.gray("\n \u5DF2\u53D6\u6D88\u5B89\u88C5\n"));
5448
5565
  return;
5449
5566
  }
5450
5567
  if (options.dryRun) {
5451
- console.log(chalk9.yellow("\n [Dry Run] \u4EE5\u4E0B\u547D\u4EE4\u5C06\u88AB\u6267\u884C:\n"));
5568
+ console.log(chalk10.yellow("\n [Dry Run] \u4EE5\u4E0B\u547D\u4EE4\u5C06\u88AB\u6267\u884C:\n"));
5452
5569
  const pm = getPackageManager(projectInfo.packageManager);
5453
5570
  const installCmd = pm === "npm" ? "npm install -D" : pm === "yarn" ? "yarn add -D" : pm === "pnpm" ? "pnpm add -D" : "bun add -D";
5454
5571
  for (const group of selectedGroups) {
5455
5572
  const dirHint = installDir !== process.cwd() ? ` (\u5728 ${path16.relative(process.cwd(), installDir) || installDir})` : "";
5456
- console.log(chalk9.white(` ${installCmd} ${group.packages.join(" ")}${dirHint}`));
5573
+ console.log(chalk10.white(` ${installCmd} ${group.packages.join(" ")}${dirHint}`));
5457
5574
  if (group.postInstall) {
5458
5575
  for (const cmd of group.postInstall) {
5459
- console.log(chalk9.white(` ${cmd}`));
5576
+ console.log(chalk10.white(` ${cmd}`));
5460
5577
  }
5461
5578
  }
5462
5579
  }
@@ -5569,36 +5686,36 @@ ${stderr}` : "")));
5569
5686
  });
5570
5687
  }
5571
5688
  function displaySetupResult(groups) {
5572
- console.log(chalk9.green("\n \u2713 \u4F9D\u8D56\u5B89\u88C5\u5B8C\u6210!\n"));
5573
- console.log(chalk9.white(" \u5DF2\u5B89\u88C5:"));
5689
+ console.log(chalk10.green("\n \u2713 \u4F9D\u8D56\u5B89\u88C5\u5B8C\u6210!\n"));
5690
+ console.log(chalk10.white(" \u5DF2\u5B89\u88C5:"));
5574
5691
  for (const group of groups) {
5575
- console.log(chalk9.cyan(`
5692
+ console.log(chalk10.cyan(`
5576
5693
  ${group.name}`));
5577
5694
  for (const pkg of group.packages) {
5578
- console.log(chalk9.gray(` \u2713 ${pkg}`));
5695
+ console.log(chalk10.gray(` \u2713 ${pkg}`));
5579
5696
  }
5580
5697
  if (group.postInstall) {
5581
5698
  for (const cmd of group.postInstall) {
5582
- console.log(chalk9.gray(` \u2713 ${cmd}`));
5699
+ console.log(chalk10.gray(` \u2713 ${cmd}`));
5583
5700
  }
5584
5701
  }
5585
5702
  }
5586
5703
  console.log();
5587
- console.log(chalk9.cyan(" \u4E0B\u4E00\u6B65:"));
5588
- console.log(chalk9.gray(" 1. \u8FD0\u884C qat create \u521B\u5EFA\u6D4B\u8BD5\u7528\u4F8B"));
5589
- console.log(chalk9.gray(" 2. \u8FD0\u884C qat run \u6267\u884C\u6D4B\u8BD5"));
5704
+ console.log(chalk10.cyan(" \u4E0B\u4E00\u6B65:"));
5705
+ console.log(chalk10.gray(" 1. \u8FD0\u884C qat create \u521B\u5EFA\u6D4B\u8BD5\u7528\u4F8B"));
5706
+ console.log(chalk10.gray(" 2. \u8FD0\u884C qat run \u6267\u884C\u6D4B\u8BD5"));
5590
5707
  console.log();
5591
5708
  }
5592
5709
 
5593
5710
  // src/commands/status.ts
5594
- import chalk10 from "chalk";
5711
+ import chalk11 from "chalk";
5595
5712
  import ora9 from "ora";
5596
5713
  function registerStatusCommand(program2) {
5597
5714
  program2.command("status").description("\u67E5\u770B QAT \u72B6\u6001 - AI \u6A21\u578B\u4FE1\u606F\u3001\u9879\u76EE\u914D\u7F6E").action(async (options) => {
5598
5715
  try {
5599
5716
  await executeStatus(options);
5600
5717
  } catch (error) {
5601
- console.error(chalk10.red(`
5718
+ console.error(chalk11.red(`
5602
5719
  \u2717 ${error instanceof Error ? error.message : String(error)}
5603
5720
  `));
5604
5721
  process.exit(1);
@@ -5606,24 +5723,24 @@ function registerStatusCommand(program2) {
5606
5723
  });
5607
5724
  }
5608
5725
  async function executeStatus(_options) {
5609
- console.log(chalk10.cyan("\n AI \u6A21\u578B\u72B6\u6001"));
5610
- console.log(chalk10.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
5726
+ console.log(chalk11.cyan("\n AI \u6A21\u578B\u72B6\u6001"));
5727
+ console.log(chalk11.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
5611
5728
  const globalAI = loadGlobalAIConfig();
5612
5729
  if (!globalAI) {
5613
- console.log(chalk10.yellow(" \u2717 \u672A\u914D\u7F6E AI \u6A21\u578B"));
5614
- console.log(chalk10.gray(" \u8FD0\u884C qat change \u914D\u7F6E AI \u6A21\u578B"));
5730
+ console.log(chalk11.yellow(" \u2717 \u672A\u914D\u7F6E AI \u6A21\u578B"));
5731
+ console.log(chalk11.gray(" \u8FD0\u884C qat change \u914D\u7F6E AI \u6A21\u578B"));
5615
5732
  } else {
5616
- console.log(` ${chalk10.white("\u6A21\u578B:")} ${chalk10.green(globalAI.model)}`);
5617
- console.log(` ${chalk10.white("API URL:")} ${chalk10.gray(globalAI.baseUrl)}`);
5618
- console.log(` ${chalk10.white("API Key:")} ${chalk10.gray(maskApiKey(globalAI.apiKey))}`);
5619
- console.log(` ${chalk10.white("Provider:")} ${chalk10.gray(globalAI.provider)}`);
5620
- console.log(` ${chalk10.white("\u914D\u7F6E\u6587\u4EF6:")} ${chalk10.gray(getAIConfigPath())}`);
5733
+ console.log(` ${chalk11.white("\u6A21\u578B:")} ${chalk11.green(globalAI.model)}`);
5734
+ console.log(` ${chalk11.white("API URL:")} ${chalk11.gray(globalAI.baseUrl)}`);
5735
+ console.log(` ${chalk11.white("API Key:")} ${chalk11.gray(maskApiKey(globalAI.apiKey))}`);
5736
+ console.log(` ${chalk11.white("Provider:")} ${chalk11.gray(globalAI.provider)}`);
5737
+ console.log(` ${chalk11.white("\u914D\u7F6E\u6587\u4EF6:")} ${chalk11.gray(getAIConfigPath())}`);
5621
5738
  const testSpinner = ora9(" \u6B63\u5728\u6D4B\u8BD5\u8FDE\u901A\u6027...").start();
5622
5739
  try {
5623
5740
  const aiConfig = toAIConfig(globalAI);
5624
5741
  const result = await testAIConnection(aiConfig);
5625
5742
  if (result.ok) {
5626
- testSpinner.succeed(` \u8FDE\u901A\u6B63\u5E38 ${chalk10.gray(`(${result.latencyMs}ms)`)}`);
5743
+ testSpinner.succeed(` \u8FDE\u901A\u6B63\u5E38 ${chalk11.gray(`(${result.latencyMs}ms)`)}`);
5627
5744
  } else {
5628
5745
  testSpinner.fail(` \u8FDE\u901A\u5F02\u5E38: ${result.message}`);
5629
5746
  }
@@ -5632,26 +5749,26 @@ async function executeStatus(_options) {
5632
5749
  }
5633
5750
  }
5634
5751
  console.log();
5635
- console.log(chalk10.cyan(" \u9879\u76EE\u914D\u7F6E"));
5636
- console.log(chalk10.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
5752
+ console.log(chalk11.cyan(" \u9879\u76EE\u914D\u7F6E"));
5753
+ console.log(chalk11.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
5637
5754
  try {
5638
5755
  const config = await loadConfig();
5639
5756
  const projectInfo = detectProject();
5640
- console.log(` ${chalk10.white("\u6846\u67B6:")} ${projectInfo.frameworkDisplayName}`);
5641
- console.log(` ${chalk10.white("\u6E90\u7801\u76EE\u5F55:")} ${config.project.srcDir}`);
5642
- console.log(` ${chalk10.white("Vitest:")} ${config.vitest.enabled ? chalk10.green("\u2713") : chalk10.red("\u2717")} (${config.vitest.environment})`);
5643
- console.log(` ${chalk10.white("Playwright:")} ${config.playwright.enabled ? chalk10.green("\u2713") : chalk10.red("\u2717")} (${config.playwright.browsers.join(", ")})`);
5644
- console.log(` ${chalk10.white("Mock:")} ${config.mock.enabled ? chalk10.green("\u2713") : chalk10.red("\u2717")} (port ${config.mock.port})`);
5645
- console.log(` ${chalk10.white("Visual:")} ${config.visual.enabled ? chalk10.green("\u2713") : chalk10.red("\u2717")}`);
5646
- console.log(` ${chalk10.white("Lighthouse:")} ${config.lighthouse.enabled ? chalk10.green("\u2713") : chalk10.red("\u2717")}`);
5757
+ console.log(` ${chalk11.white("\u6846\u67B6:")} ${projectInfo.frameworkDisplayName}`);
5758
+ console.log(` ${chalk11.white("\u6E90\u7801\u76EE\u5F55:")} ${config.project.srcDir}`);
5759
+ console.log(` ${chalk11.white("Vitest:")} ${config.vitest.enabled ? chalk11.green("\u2713") : chalk11.red("\u2717")} (${config.vitest.environment})`);
5760
+ console.log(` ${chalk11.white("Playwright:")} ${config.playwright.enabled ? chalk11.green("\u2713") : chalk11.red("\u2717")} (${config.playwright.browsers.join(", ")})`);
5761
+ console.log(` ${chalk11.white("Mock:")} ${config.mock.enabled ? chalk11.green("\u2713") : chalk11.red("\u2717")} (port ${config.mock.port})`);
5762
+ console.log(` ${chalk11.white("Visual:")} ${config.visual.enabled ? chalk11.green("\u2713") : chalk11.red("\u2717")}`);
5763
+ console.log(` ${chalk11.white("Lighthouse:")} ${config.lighthouse.enabled ? chalk11.green("\u2713") : chalk11.red("\u2717")}`);
5647
5764
  } catch {
5648
- console.log(chalk10.yellow(" \u2717 \u672A\u627E\u5230\u9879\u76EE\u914D\u7F6E (\u8FD0\u884C qat init \u521D\u59CB\u5316)"));
5765
+ console.log(chalk11.yellow(" \u2717 \u672A\u627E\u5230\u9879\u76EE\u914D\u7F6E (\u8FD0\u884C qat init \u521D\u59CB\u5316)"));
5649
5766
  }
5650
5767
  console.log();
5651
5768
  }
5652
5769
 
5653
5770
  // src/commands/change.ts
5654
- import chalk11 from "chalk";
5771
+ import chalk12 from "chalk";
5655
5772
  import inquirer5 from "inquirer";
5656
5773
  import ora10 from "ora";
5657
5774
  function registerChangeCommand(program2) {
@@ -5659,7 +5776,7 @@ function registerChangeCommand(program2) {
5659
5776
  try {
5660
5777
  await executeChange(options);
5661
5778
  } catch (error) {
5662
- console.error(chalk11.red(`
5779
+ console.error(chalk12.red(`
5663
5780
  \u2717 ${error instanceof Error ? error.message : String(error)}
5664
5781
  `));
5665
5782
  process.exit(1);
@@ -5669,13 +5786,13 @@ function registerChangeCommand(program2) {
5669
5786
  async function executeChange(_options) {
5670
5787
  const current = loadGlobalAIConfig();
5671
5788
  if (current) {
5672
- console.log(chalk11.cyan("\n \u5F53\u524D AI \u914D\u7F6E:"));
5673
- console.log(` ${chalk11.white("\u6A21\u578B:")} ${chalk11.green(current.model)}`);
5674
- console.log(` ${chalk11.white("API URL:")} ${chalk11.gray(current.baseUrl)}`);
5675
- console.log(` ${chalk11.white("API Key:")} ${chalk11.gray(maskApiKey(current.apiKey))}`);
5789
+ console.log(chalk12.cyan("\n \u5F53\u524D AI \u914D\u7F6E:"));
5790
+ console.log(` ${chalk12.white("\u6A21\u578B:")} ${chalk12.green(current.model)}`);
5791
+ console.log(` ${chalk12.white("API URL:")} ${chalk12.gray(current.baseUrl)}`);
5792
+ console.log(` ${chalk12.white("API Key:")} ${chalk12.gray(maskApiKey(current.apiKey))}`);
5676
5793
  console.log();
5677
5794
  } else {
5678
- console.log(chalk11.yellow("\n \u5F53\u524D\u672A\u914D\u7F6E AI \u6A21\u578B\uFF0C\u8BF7\u914D\u7F6E:\n"));
5795
+ console.log(chalk12.yellow("\n \u5F53\u524D\u672A\u914D\u7F6E AI \u6A21\u578B\uFF0C\u8BF7\u914D\u7F6E:\n"));
5679
5796
  }
5680
5797
  const answers = await inquirer5.prompt([
5681
5798
  {
@@ -5713,16 +5830,16 @@ async function executeChange(_options) {
5713
5830
  model: answers.model?.trim() || "deepseek-chat"
5714
5831
  };
5715
5832
  saveGlobalAIConfig(newConfig);
5716
- console.log(chalk11.green(`
5833
+ console.log(chalk12.green(`
5717
5834
  \u2713 AI \u914D\u7F6E\u5DF2\u4FDD\u5B58`));
5718
- console.log(chalk11.gray(` ${getAIConfigPath()}`));
5719
- console.log(` ${chalk11.white("\u6A21\u578B:")} ${chalk11.green(newConfig.model)} @ ${chalk11.gray(newConfig.baseUrl)}`);
5835
+ console.log(chalk12.gray(` ${getAIConfigPath()}`));
5836
+ console.log(` ${chalk12.white("\u6A21\u578B:")} ${chalk12.green(newConfig.model)} @ ${chalk12.gray(newConfig.baseUrl)}`);
5720
5837
  const testSpinner = ora10(" \u6B63\u5728\u6D4B\u8BD5\u8FDE\u901A\u6027...").start();
5721
5838
  try {
5722
5839
  const aiConfig = toAIConfig(newConfig);
5723
5840
  const result = await testAIConnection(aiConfig);
5724
5841
  if (result.ok) {
5725
- testSpinner.succeed(` AI \u8FDE\u901A\u6B63\u5E38 ${chalk11.gray(`(${newConfig.model}, ${result.latencyMs}ms)`)}`);
5842
+ testSpinner.succeed(` AI \u8FDE\u901A\u6B63\u5E38 ${chalk12.gray(`(${newConfig.model}, ${result.latencyMs}ms)`)}`);
5726
5843
  } else {
5727
5844
  testSpinner.fail(` AI \u8FDE\u901A\u5F02\u5E38: ${result.message}`);
5728
5845
  }
@@ -5733,37 +5850,40 @@ async function executeChange(_options) {
5733
5850
  }
5734
5851
 
5735
5852
  // src/cli.ts
5736
- var VERSION = "0.3.03";
5853
+ var VERSION = "0.3.04";
5737
5854
  function printLogo() {
5738
5855
  const logo = `
5739
- ${chalk12.bold.cyan(" ___ _ _ _ _ _____ _ _ ")}
5740
- ${chalk12.bold.cyan(" / _ \\ _ _ (_) ___ | | __ / \\ _ _ | |_ ___ |_ _| ___ ___ | |_ (_) _ __ __ _ ")}
5741
- ${chalk12.bold.cyan(" | | | | | | | | | | / __| | |/ / / _ \\ | | | | | __| / _ \\ | | / _ \\ / __| | __| | | | '_ \\ / _` |")}
5742
- ${chalk12.bold.cyan(" | |_| | | |_| | | | | (__ | < / ___ \\ | |_| | | |_ | (_) | | | | __/ \\__ \\ | |_ | | | | | | | (_| |")}
5743
- ${chalk12.bold.cyan(" \\__\\_\\ \\__,_| |_| \\___| |_|\\_\\ /_/ \\_\\ \\__,_| \\__| \\___/ |_| \\___| |___/ \\__| |_| |_| |_| \\__, |")}
5744
- ${chalk12.bold.cyan(" |___/ ")}
5745
- ${chalk12.gray(" CLI\u81EA\u52A8\u5316\u6D4B\u8BD5\u5DE5\u5177 v")}${chalk12.green(VERSION)}
5856
+ ${chalk13.bold.cyan(" ___ _ _ _ _ _____ _ _ ")}
5857
+ ${chalk13.bold.cyan(" / _ \\ _ _ (_) ___ | | __ / \\ _ _ | |_ ___ |_ _| ___ ___ | |_ (_) _ __ __ _ ")}
5858
+ ${chalk13.bold.cyan(" | | | | | | | | | | / __| | |/ / / _ \\ | | | | | __| / _ \\ | | / _ \\ / __| | __| | | | '_ \\ / _` |")}
5859
+ ${chalk13.bold.cyan(" | |_| | | |_| | | | | (__ | < / ___ \\ | |_| | | |_ | (_) | | | | __/ \\__ \\ | |_ | | | | | | | (_| |")}
5860
+ ${chalk13.bold.cyan(" \\__\\_\\ \\__,_| |_| \\___| |_|\\_\\ /_/ \\_\\ \\__,_| \\__| \\___/ |_| \\___| |___/ \\__| |_| |_| |_| \\__, |")}
5861
+ ${chalk13.bold.cyan(" |___/ ")}
5862
+ ${chalk13.gray(" CLI\u81EA\u52A8\u5316\u6D4B\u8BD5\u5DE5\u5177 v")}${chalk13.green(VERSION)}
5746
5863
  `;
5747
5864
  console.log(logo);
5748
5865
  }
5749
5866
  var program = new Command();
5750
- program.name("qat").description("CLI\u81EA\u52A8\u5316\u6D4B\u8BD5\u5DE5\u5177 - \u9762\u5411Vue\u9879\u76EE\uFF0C\u96C6\u6210Vitest\u3001Playwright\uFF0C\u8986\u76D6\u6D4B\u8BD5\u5168\u6D41\u7A0B").version(VERSION).option("-c, --config <path>", "\u6307\u5B9A\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").option("-v, --verbose", "\u663E\u793A\u8BE6\u7EC6\u8F93\u51FA").hook("preAction", async (thisCommand) => {
5867
+ program.name("qat").description("CLI\u81EA\u52A8\u5316\u6D4B\u8BD5\u5DE5\u5177 - \u9762\u5411Vue\u9879\u76EE\uFF0C\u96C6\u6210Vitest\u3001Playwright\uFF0C\u8986\u76D6\u6D4B\u8BD5\u5168\u6D41\u7A0B").version(VERSION).option("-c, --config <path>", "\u6307\u5B9A\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84").option("-v, --verbose", "\u663E\u793A\u8BE6\u7EC6\u8F93\u51FA").option("-d, --debug", "\u8C03\u8BD5\u6A21\u5F0F\uFF1A\u663E\u793AAI\u8BF7\u6C42/\u54CD\u5E94\u8BE6\u60C5").hook("preAction", async (thisCommand) => {
5751
5868
  printLogo();
5752
5869
  const opts = thisCommand.opts();
5753
5870
  if (opts.verbose) {
5754
5871
  process.env.QAT_VERBOSE = "true";
5755
5872
  }
5873
+ if (opts.debug) {
5874
+ process.env.QAT_DEBUG = "true";
5875
+ }
5756
5876
  if (opts.config) {
5757
5877
  process.env.QAT_CONFIG_PATH = opts.config;
5758
5878
  }
5759
5879
  const { loadExternalFrameworks } = await import("./framework-registry-YGZ63RDX.js");
5760
5880
  const loadResult = await loadExternalFrameworks(process.cwd());
5761
5881
  if (loadResult.loaded > 0 && opts.verbose) {
5762
- console.log(chalk12.gray(` [ext] \u5DF2\u52A0\u8F7D ${loadResult.loaded} \u4E2A\u5916\u90E8\u6269\u5C55\u6587\u4EF6: ${loadResult.files.join(", ")}`));
5882
+ console.log(chalk13.gray(` [ext] \u5DF2\u52A0\u8F7D ${loadResult.loaded} \u4E2A\u5916\u90E8\u6269\u5C55\u6587\u4EF6: ${loadResult.files.join(", ")}`));
5763
5883
  }
5764
5884
  if (loadResult.errors.length > 0) {
5765
5885
  for (const err of loadResult.errors) {
5766
- console.log(chalk12.yellow(` [ext] \u8B66\u544A: ${err.file} - ${err.error}`));
5886
+ console.log(chalk13.yellow(` [ext] \u8B66\u544A: ${err.file} - ${err.error}`));
5767
5887
  }
5768
5888
  }
5769
5889
  });
@@ -5777,9 +5897,9 @@ registerSetupCommand(program);
5777
5897
  registerStatusCommand(program);
5778
5898
  registerChangeCommand(program);
5779
5899
  program.on("command:*", (operands) => {
5780
- console.error(chalk12.red(`
5900
+ console.error(chalk13.red(`
5781
5901
  \u672A\u77E5\u547D\u4EE4: ${operands[0]}`));
5782
- console.log(chalk12.gray(` \u4F7F\u7528 qat --help \u67E5\u770B\u53EF\u7528\u547D\u4EE4
5902
+ console.log(chalk13.gray(` \u4F7F\u7528 qat --help \u67E5\u770B\u53EF\u7528\u547D\u4EE4
5783
5903
  `));
5784
5904
  process.exit(1);
5785
5905
  });