vite-plugin-ai-diagnostic 1.0.10 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +11 -5
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +11 -5
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -42,7 +42,7 @@ var import_langgraph = require("@langchain/langgraph");
|
|
|
42
42
|
var import_openai = require("@langchain/openai");
|
|
43
43
|
var import_messages = require("@langchain/core/messages");
|
|
44
44
|
var DiagnosticGraph = class {
|
|
45
|
-
constructor(apiKey, apiUrl, model = "gpt-4", maxRetries = 3) {
|
|
45
|
+
constructor(apiKey, apiUrl, model = "gpt-4", maxRetries = 3, temperature = 0.1, maxTokens = 4e3) {
|
|
46
46
|
this.maxRetries = maxRetries;
|
|
47
47
|
console.log("🔧 [LangGraph] 初始化 LLM...");
|
|
48
48
|
console.log("📝 [配置] 模型:", model);
|
|
@@ -54,8 +54,8 @@ var DiagnosticGraph = class {
|
|
|
54
54
|
baseURL: apiUrl
|
|
55
55
|
},
|
|
56
56
|
modelName: model,
|
|
57
|
-
temperature
|
|
58
|
-
maxTokens
|
|
57
|
+
temperature,
|
|
58
|
+
maxTokens
|
|
59
59
|
});
|
|
60
60
|
this.graph = this.buildGraph();
|
|
61
61
|
}
|
|
@@ -274,7 +274,9 @@ var AIErrorDiagnostic = class {
|
|
|
274
274
|
options.apiKey,
|
|
275
275
|
options.apiUrl,
|
|
276
276
|
options.model,
|
|
277
|
-
options.maxRetries
|
|
277
|
+
options.maxRetries,
|
|
278
|
+
options.temperature,
|
|
279
|
+
options.maxTokens
|
|
278
280
|
);
|
|
279
281
|
}
|
|
280
282
|
async diagnose(error, autoFix = false) {
|
|
@@ -1085,6 +1087,8 @@ function vitePluginAIDiagnostic(options = {}) {
|
|
|
1085
1087
|
autoFix = false,
|
|
1086
1088
|
model = "gpt-4",
|
|
1087
1089
|
maxRetries = 3,
|
|
1090
|
+
temperature = 0.1,
|
|
1091
|
+
maxTokens = 4e3,
|
|
1088
1092
|
output = {
|
|
1089
1093
|
console: true,
|
|
1090
1094
|
html: true,
|
|
@@ -1096,7 +1100,9 @@ function vitePluginAIDiagnostic(options = {}) {
|
|
|
1096
1100
|
apiKey,
|
|
1097
1101
|
apiUrl,
|
|
1098
1102
|
model,
|
|
1099
|
-
maxRetries
|
|
1103
|
+
maxRetries,
|
|
1104
|
+
temperature,
|
|
1105
|
+
maxTokens
|
|
1100
1106
|
});
|
|
1101
1107
|
let buildErrors = [];
|
|
1102
1108
|
let lastTransformFile = null;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/langgraph.ts","../src/diagnostic.ts","../src/reporter.ts"],"sourcesContent":["/**\r\n * AI 诊断插件入口\r\n *\r\n * 功能:\r\n * - 自动诊断构建错误\r\n * - 提供修复建议\r\n * - 自动修复代码\r\n */\r\n\r\nimport type { Plugin, ResolvedConfig } from \"vite\";\r\nimport fs from \"fs\";\r\nimport path from \"path\";\r\nimport { AIErrorDiagnostic } from \"./diagnostic\";\r\nimport { extractSourceFile } from \"vite-plugin-ai-shared\";\r\nimport { DiagnosticReporter, type DiagnosticReport } from \"./reporter\";\r\nimport { glob } from \"glob\";\r\n\r\nexport interface AIPluginOptions {\r\n apiKey?: string;\r\n apiUrl?: string;\r\n autoFix?: boolean;\r\n model?: string;\r\n maxRetries?: number;\r\n output?: {\r\n console?: boolean;\r\n html?: boolean;\r\n markdown?: boolean;\r\n json?: boolean;\r\n };\r\n}\r\n\r\nexport function vitePluginAIDiagnostic(options: AIPluginOptions = {}): Plugin {\r\n const {\r\n apiKey = process.env.OPENAI_API_KEY || \"\",\r\n apiUrl = process.env.OPENAI_API_URL || \"https://api.openai.com/v1\",\r\n autoFix = false,\r\n model = \"gpt-4\",\r\n maxRetries = 3,\r\n output = {\r\n console: true,\r\n html: true,\r\n markdown: false,\r\n json: false,\r\n },\r\n } = options;\r\n\r\n const diagnostic = new AIErrorDiagnostic({\r\n apiKey,\r\n apiUrl,\r\n model,\r\n maxRetries,\r\n });\r\n\r\n let buildErrors: any[] = [];\r\n let lastTransformFile: string | null = null;\r\n let processedErrors = new Set<string>(); // 记录已处理的错误\r\n let config: ResolvedConfig;\r\n let diagnosticResults: DiagnosticReport[] = []; // 收集所有诊断结果\r\n\r\n // 处理错误的函数\r\n async function processError(error: any) {\r\n // 生成错误的唯一标识\r\n const errorKey = `${error.file}:${error.message}`;\r\n\r\n // 如果已经处理过,跳过\r\n if (processedErrors.has(errorKey)) {\r\n console.log(\"🔍 [调试] 跳过重复错误:\", errorKey);\r\n return;\r\n }\r\n\r\n processedErrors.add(errorKey);\r\n\r\n try {\r\n console.log(\"\\n⚠️ 检测到错误,正在使用 AI 分析...\\n\");\r\n console.log(`📝 错误信息: ${error.message}`);\r\n console.log(`📂 文件路径: ${error.file || \"未知\"}`);\r\n console.log(\r\n `📄 代码长度: ${error.code ? error.code.length + \" 字符\" : \"无\"}`,\r\n );\r\n console.log(`🔧 自动修复: ${autoFix ? \"是\" : \"否\"}\\n`);\r\n\r\n if (!error.file || !error.code) {\r\n console.log(\"⚠️ 跳过此错误:缺少文件路径或代码内容\\n\");\r\n return;\r\n }\r\n\r\n const result = await diagnostic.diagnose(error, autoFix);\r\n\r\n // 控制台输出\r\n if (output.console !== false) {\r\n console.log(\"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\");\r\n console.log(\"🔍 错误分析:\");\r\n console.log(result.analysis);\r\n console.log(\"\\n💡 修复建议:\");\r\n console.log(result.suggestion);\r\n\r\n if (result.fixedCode && result.filePath) {\r\n console.log(\"\\n✅ 已自动修复代码\");\r\n console.log(\"修复的文件:\", result.filePath);\r\n console.log(\"\\n💡 请重新运行构建命令\");\r\n } else if (autoFix) {\r\n console.log(\"\\n⚠️ 无法自动修复:AI 未生成修复代码\");\r\n }\r\n console.log(\"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\n\");\r\n }\r\n\r\n // 生成报告对象\r\n const report: DiagnosticReport = {\r\n timestamp: new Date().toLocaleString(\"zh-CN\"),\r\n error: {\r\n type: error.type || \"unknown\",\r\n message: error.message,\r\n file: error.file,\r\n stack: error.stack,\r\n },\r\n analysis: result.analysis,\r\n suggestion: result.suggestion,\r\n fixed: !!(result.fixedCode && result.filePath),\r\n fixedFilePath: result.filePath,\r\n };\r\n\r\n // 收集诊断结果,稍后统一生成报告\r\n diagnosticResults.push(report);\r\n } catch (err: any) {\r\n console.error(\"❌ AI 诊断失败:\", err.message);\r\n }\r\n }\r\n\r\n return {\r\n name: \"vite-plugin-ai-diagnostic\",\r\n\r\n // 确保插件在其他插件之后执行,以捕获更多错误\r\n enforce: \"post\",\r\n\r\n configResolved(resolvedConfig) {\r\n config = resolvedConfig;\r\n console.log(\"\\n🤖 AI 诊断助手已启动...\");\r\n console.log(`⚙️ 自动修复: ${autoFix ? \"✅ 已启用\" : \"❌ 未启用\"}`);\r\n console.log(`📝 根目录: ${config.root}`);\r\n console.log(\r\n `📝 入口: ${config.build.rollupOptions?.input || \"index.html\"}\\n`,\r\n );\r\n },\r\n\r\n async buildStart() {\r\n buildErrors = [];\r\n processedErrors.clear();\r\n diagnosticResults = []; // 清空诊断结果\r\n console.log(\"🔍 开始扫描源文件...\");\r\n\r\n // 扫描 src 目录下的所有源文件\r\n const srcDir = path.join(config.root, \"src\");\r\n if (!fs.existsSync(srcDir)) {\r\n console.log(\"⚠️ src 目录不存在,跳过文件扫描\");\r\n return;\r\n }\r\n\r\n try {\r\n // 使用 glob 查找所有源文件\r\n const files = await glob(\"**/*.{vue,ts,tsx,js,jsx}\", {\r\n cwd: srcDir,\r\n absolute: true,\r\n ignore: [\"**/node_modules/**\", \"**/*.d.ts\"],\r\n });\r\n\r\n console.log(`📂 找到 ${files.length} 个源文件`);\r\n\r\n // 检查每个文件的语法\r\n for (const file of files) {\r\n try {\r\n const code = fs.readFileSync(file, \"utf-8\");\r\n\r\n // 基本语法检查\r\n if (file.endsWith(\".vue\")) {\r\n // 检查 Vue 文件的基本结构\r\n if (!code.includes(\"<template>\") && !code.includes(\"<script>\")) {\r\n buildErrors.push({\r\n type: \"syntax\",\r\n message: \"Vue 文件缺少 <template> 或 <script> 标签\",\r\n file: file,\r\n code: code,\r\n });\r\n }\r\n\r\n // 检查未闭合的标签\r\n const templateMatch = code.match(/<template[^>]*>/);\r\n if (templateMatch && !code.includes(\"</template>\")) {\r\n buildErrors.push({\r\n type: \"syntax\",\r\n message: \"Vue 文件中 <template> 标签未闭合\",\r\n file: file,\r\n code: code,\r\n });\r\n }\r\n\r\n const scriptMatch = code.match(/<script[^>]*>/);\r\n if (scriptMatch && !code.includes(\"</script>\")) {\r\n buildErrors.push({\r\n type: \"syntax\",\r\n message: \"Vue 文件中 <script> 标签未闭合\",\r\n file: file,\r\n code: code,\r\n });\r\n }\r\n }\r\n\r\n // 检查 JavaScript/TypeScript 语法错误(简单检查)\r\n if (\r\n file.endsWith(\".ts\") ||\r\n file.endsWith(\".tsx\") ||\r\n file.endsWith(\".js\") ||\r\n file.endsWith(\".jsx\")\r\n ) {\r\n // 检查括号匹配\r\n const openBraces = (code.match(/\\{/g) || []).length;\r\n const closeBraces = (code.match(/\\}/g) || []).length;\r\n if (openBraces !== closeBraces) {\r\n buildErrors.push({\r\n type: \"syntax\",\r\n message: `括号不匹配:{ 有 ${openBraces} 个,} 有 ${closeBraces} 个`,\r\n file: file,\r\n code: code,\r\n });\r\n }\r\n\r\n const openParens = (code.match(/\\(/g) || []).length;\r\n const closeParens = (code.match(/\\)/g) || []).length;\r\n if (openParens !== closeParens) {\r\n buildErrors.push({\r\n type: \"syntax\",\r\n message: `圆括号不匹配:( 有 ${openParens} 个,) 有 ${closeParens} 个`,\r\n file: file,\r\n code: code,\r\n });\r\n }\r\n }\r\n\r\n // 检查导入语句中的不存在模块(这个会在后续构建中被捕获)\r\n const importRegex = /import\\s+.*?\\s+from\\s+['\"](.+?)['\"]/g;\r\n let match;\r\n while ((match = importRegex.exec(code)) !== null) {\r\n const importPath = match[1];\r\n\r\n // 跳过 node_modules 和别名导入\r\n if (importPath.startsWith(\".\") || importPath.startsWith(\"/\")) {\r\n const resolvedPath = path.resolve(\r\n path.dirname(file),\r\n importPath,\r\n );\r\n const extensions = [\".ts\", \".tsx\", \".js\", \".jsx\", \".vue\", \"\"];\r\n\r\n let exists = false;\r\n for (const ext of extensions) {\r\n const fullPath = resolvedPath + ext;\r\n if (fs.existsSync(fullPath)) {\r\n exists = true;\r\n break;\r\n }\r\n // 检查是否为目录,且包含 index 文件\r\n if (\r\n fs.existsSync(resolvedPath) &&\r\n fs.statSync(resolvedPath).isDirectory()\r\n ) {\r\n const indexPath = path.join(resolvedPath, \"index\" + ext);\r\n if (fs.existsSync(indexPath)) {\r\n exists = true;\r\n break;\r\n }\r\n }\r\n }\r\n\r\n if (!exists) {\r\n buildErrors.push({\r\n type: \"module\",\r\n message: `找不到模块: ${importPath}`,\r\n file: file,\r\n code: code,\r\n });\r\n }\r\n }\r\n }\r\n } catch (err: any) {\r\n console.warn(`⚠️ 无法读取文件 ${file}: ${err.message}`);\r\n }\r\n }\r\n\r\n if (buildErrors.length > 0) {\r\n console.log(`⚠️ 扫描发现 ${buildErrors.length} 个潜在问题`);\r\n } else {\r\n console.log(\"✅ 文件扫描完成,未发现明显问题\");\r\n }\r\n } catch (err: any) {\r\n console.error(`❌ 文件扫描失败: ${err.message}`);\r\n }\r\n },\r\n\r\n // 解析模块时捕获错误\r\n async resolveId(source, importer, options) {\r\n // 不要在这里 try-catch,让错误自然传播到 buildEnd\r\n return null;\r\n },\r\n\r\n // 加载模块时捕获错误\r\n async load(id) {\r\n // 不要在这里 try-catch,让错误自然传播到 buildEnd\r\n return null;\r\n },\r\n\r\n // Rollup 钩子:模块解析完成后调用\r\n moduleParsed(moduleInfo) {\r\n // 检查模块是否有导入错误\r\n if (moduleInfo.meta && moduleInfo.meta.error) {\r\n console.log(\"\\n⚠️ moduleParsed 检测到错误:\", moduleInfo.id);\r\n\r\n let code = undefined;\r\n if (moduleInfo.id && fs.existsSync(moduleInfo.id)) {\r\n code = fs.readFileSync(moduleInfo.id, \"utf-8\");\r\n }\r\n\r\n const errorInfo = {\r\n type: \"module\",\r\n message: moduleInfo.meta.error,\r\n stack: \"\",\r\n file: moduleInfo.id,\r\n code: code,\r\n };\r\n\r\n buildErrors.push(errorInfo);\r\n }\r\n },\r\n\r\n buildEnd(error?: Error) {\r\n console.log(\"🔍 [调试] buildEnd 已执行, 有错误:\", !!error);\r\n\r\n if (error) {\r\n console.log(\"\\n⚠️ buildEnd 捕获到错误:\", error.message);\r\n\r\n const realFilePath = extractSourceFile(error, lastTransformFile);\r\n\r\n let code = undefined;\r\n if (realFilePath && fs.existsSync(realFilePath)) {\r\n try {\r\n code = fs.readFileSync(realFilePath, \"utf-8\");\r\n console.log(`📂 读取源文件成功: ${realFilePath}`);\r\n console.log(`📄 源文件长度: ${code.length} 字符`);\r\n } catch (e) {\r\n console.warn(\"⚠️ 无法读取文件:\", realFilePath);\r\n }\r\n }\r\n\r\n const errorInfo = {\r\n type: \"build\",\r\n message: error.message,\r\n stack: error.stack,\r\n file: realFilePath,\r\n code: code,\r\n };\r\n\r\n buildErrors.push(errorInfo);\r\n }\r\n },\r\n\r\n // Rollup 输出生成阶段的钩子\r\n renderStart(outputOptions, inputOptions) {\r\n console.log(\"🔍 [调试] renderStart 已执行\");\r\n },\r\n\r\n renderError(error?: Error) {\r\n console.log(\"🔍 [调试] renderError 已执行\");\r\n if (!error) return;\r\n\r\n console.log(\"\\n⚠️ renderError 捕获到错误:\", error.message);\r\n\r\n const realFilePath = extractSourceFile(error, lastTransformFile);\r\n\r\n let code = undefined;\r\n if (realFilePath && fs.existsSync(realFilePath)) {\r\n try {\r\n code = fs.readFileSync(realFilePath, \"utf-8\");\r\n console.log(`📂 读取源文件成功: ${realFilePath}`);\r\n console.log(`📄 源文件长度: ${code.length} 字符`);\r\n } catch (e) {\r\n console.warn(\"⚠️ 无法读取文件:\", realFilePath);\r\n }\r\n }\r\n\r\n const errorInfo = {\r\n type: \"render\",\r\n message: error.message,\r\n stack: error.stack,\r\n file: realFilePath,\r\n code: code,\r\n };\r\n\r\n buildErrors.push(errorInfo);\r\n },\r\n\r\n // 监听所有阶段的错误\r\n watchChange(id, change) {\r\n console.log(\"🔍 [调试] watchChange:\", id);\r\n },\r\n\r\n async closeBundle() {\r\n if (buildErrors.length > 0) {\r\n console.log(\r\n `\\n🔍 [调试] closeBundle 检测到 ${buildErrors.length} 个错误\\n`,\r\n );\r\n\r\n // 处理所有收集到的错误(去重由 processError 函数处理)\r\n for (const error of buildErrors) {\r\n await processError(error);\r\n }\r\n\r\n // 统一生成合并报告\r\n if (diagnosticResults.length > 0) {\r\n console.log(\r\n `\\n📊 正在生成合并诊断报告 (${diagnosticResults.length} 个错误)...\\n`,\r\n );\r\n await DiagnosticReporter.generateMultiReport(\r\n diagnosticResults,\r\n output,\r\n );\r\n }\r\n } else {\r\n console.log(\"✨ 构建完成,未检测到错误\\n\");\r\n }\r\n },\r\n\r\n transform(code: string, id: string) {\r\n lastTransformFile = id;\r\n\r\n try {\r\n return null;\r\n } catch (error: any) {\r\n console.log(\"\\n⚠️ transform 捕获到错误:\", error.message);\r\n buildErrors.push({\r\n type: \"transform\",\r\n message: error.message,\r\n stack: error.stack,\r\n file: id,\r\n code: code,\r\n });\r\n throw error;\r\n }\r\n },\r\n };\r\n}\r\n\r\n// 默认导出\r\nexport default vitePluginAIDiagnostic;\r\n","/**\r\n * LangGraph 工作流实现\r\n */\r\n\r\nimport { StateGraph, END, START } from \"@langchain/langgraph\";\r\nimport { ChatOpenAI } from \"@langchain/openai\";\r\nimport { HumanMessage, SystemMessage } from \"@langchain/core/messages\";\r\n\r\nexport interface DiagnosticState {\r\n error: any;\r\n analysis: string;\r\n suggestion: string;\r\n fixedCode: string;\r\n filePath: string;\r\n autoFix: boolean;\r\n retryCount: number;\r\n messages: any[];\r\n}\r\n\r\nexport class DiagnosticGraph {\r\n private llm: ChatOpenAI;\r\n private graph: any;\r\n private maxRetries: number;\r\n\r\n constructor(\r\n apiKey: string,\r\n apiUrl: string,\r\n model: string = \"gpt-4\",\r\n maxRetries: number = 3,\r\n ) {\r\n this.maxRetries = maxRetries;\r\n\r\n console.log(\"🔧 [LangGraph] 初始化 LLM...\");\r\n console.log(\"📝 [配置] 模型:\", model);\r\n console.log(\"📝 [配置] API URL:\", apiUrl);\r\n console.log(\"📝 [配置] API Key:\", apiKey ? \"已配置\" : \"未配置\");\r\n\r\n this.llm = new ChatOpenAI({\r\n openAIApiKey: apiKey,\r\n configuration: {\r\n baseURL: apiUrl,\r\n },\r\n modelName: model,\r\n temperature: 0.1,\r\n maxTokens: 4000,\r\n });\r\n\r\n this.graph = this.buildGraph();\r\n }\r\n\r\n private buildGraph() {\r\n const workflow = new StateGraph<DiagnosticState>({\r\n channels: {\r\n error: null,\r\n analysis: null,\r\n suggestion: null,\r\n fixedCode: null,\r\n filePath: null,\r\n autoFix: null,\r\n retryCount: null,\r\n messages: null,\r\n },\r\n });\r\n\r\n workflow.addNode(\"analyze\", this.analyzeNode.bind(this));\r\n workflow.addNode(\"suggest\", this.suggestNode.bind(this));\r\n // 自动修复节点已注释(功能不够稳定)\r\n // workflow.addNode(\"fix\", this.fixNode.bind(this));\r\n // workflow.addNode(\"validate\", this.validateNode.bind(this));\r\n\r\n workflow.addEdge(START, \"analyze\");\r\n workflow.addEdge(\"analyze\", \"suggest\");\r\n // 直接结束,不再进行自动修复\r\n workflow.addEdge(\"suggest\", END);\r\n\r\n // 自动修复流程已注释\r\n // workflow.addConditionalEdges(\"suggest\", this.shouldFix.bind(this), {\r\n // fix: \"fix\",\r\n // end: END,\r\n // });\r\n // workflow.addEdge(\"fix\", \"validate\");\r\n // workflow.addConditionalEdges(\"validate\", this.shouldRetry.bind(this), {\r\n // retry: \"analyze\",\r\n // end: END,\r\n // });\r\n\r\n return workflow.compile();\r\n }\r\n\r\n private async analyzeNode(\r\n state: DiagnosticState,\r\n ): Promise<Partial<DiagnosticState>> {\r\n console.log(\"🔍 [LangGraph] 正在分析错误...\");\r\n\r\n const systemPrompt = new SystemMessage(\r\n \"你是一个专业的前端代码诊断专家,精通 Vue3、TypeScript、Vite 和 uni-app。请简洁明了地分析问题。\",\r\n );\r\n\r\n const userPrompt = new HumanMessage(`\r\n请分析以下构建错误:\r\n\r\n错误类型: ${state.error.type}\r\n错误信息: ${state.error.message}\r\n文件路径: ${state.error.file || \"未知\"}\r\n\r\n请简洁地说明(3-5句话):\r\n1. 错误的根本原因\r\n2. 影响范围\r\n3. 严重程度\r\n`);\r\n\r\n const response = await this.llm.invoke([systemPrompt, userPrompt]);\r\n const analysis = response.content.toString();\r\n\r\n return {\r\n analysis,\r\n messages: [...(state.messages || []), systemPrompt, userPrompt, response],\r\n };\r\n }\r\n\r\n private async suggestNode(\r\n state: DiagnosticState,\r\n ): Promise<Partial<DiagnosticState>> {\r\n console.log(\"💡 [LangGraph] 正在生成修复建议...\");\r\n\r\n // 提取错误相关的代码片段\r\n let codeContext = \"\";\r\n if (state.error.code && state.error.message) {\r\n // 尝试从错误信息中提取行号\r\n const lineMatch = state.error.message.match(/\\((\\d+):(\\d+)\\)/);\r\n if (lineMatch) {\r\n const errorLine = parseInt(lineMatch[1]);\r\n const lines = state.error.code.split(\"\\n\");\r\n\r\n // 提取错误行前后各5行作为上下文\r\n const startLine = Math.max(0, errorLine - 6);\r\n const endLine = Math.min(lines.length, errorLine + 4);\r\n const contextLines = lines.slice(startLine, endLine);\r\n\r\n codeContext = `\r\n相关代码片段(第 ${startLine + 1}-${endLine} 行):\r\n\\`\\`\\`\r\n${contextLines\r\n .map((line, idx) => {\r\n const lineNum = startLine + idx + 1;\r\n const marker = lineNum === errorLine ? \" ← 错误位置\" : \"\";\r\n return `${lineNum}: ${line}${marker}`;\r\n })\r\n .join(\"\\n\")}\r\n\\`\\`\\`\r\n`;\r\n } else if (state.error.code.length < 2000) {\r\n // 如果代码不长,显示完整代码\r\n codeContext = `\r\n完整代码:\r\n\\`\\`\\`\r\n${state.error.code}\r\n\\`\\`\\`\r\n`;\r\n }\r\n }\r\n\r\n const userPrompt = new HumanMessage(`\r\n基于以下错误分析,请提供具体的修复建议:\r\n\r\n错误分析:\r\n${state.analysis}\r\n\r\n错误详情:\r\n- 类型: ${state.error.type}\r\n- 信息: ${state.error.message}\r\n- 文件: ${state.error.file || \"未知\"}\r\n\r\n${codeContext}\r\n\r\n请提供精确的修复建议,格式如下:\r\n\r\n1. 修复步骤:\r\n 1. [具体步骤1]\r\n 2. [具体步骤2]\r\n 3. [具体步骤3]\r\n\r\n2. 需要修改的代码位置: [文件名] 的第 [X] 行\r\n\r\n3. 修改后的代码示例:\r\n \\`\\`\\`[语言]\r\n [只显示需要修改的那几行代码,保持原有缩进]\r\n \\`\\`\\`\r\n\r\n4. 预防建议: [一句话说明如何避免类似错误]\r\n\r\n注意:\r\n- 代码示例必须基于实际的源代码,保持正确的语法和缩进\r\n- 只显示需要修改的关键代码行,不要显示整个文件\r\n- 确保修改后的代码可以直接使用\r\n`);\r\n\r\n const response = await this.llm.invoke([...state.messages, userPrompt]);\r\n const suggestion = response.content.toString();\r\n\r\n return {\r\n suggestion,\r\n messages: [...state.messages, userPrompt, response],\r\n };\r\n }\r\n\r\n // 自动修复节点已注释(功能不够稳定)\r\n // private async fixNode(\r\n // state: DiagnosticState\r\n // ): Promise<Partial<DiagnosticState>> {\r\n // console.log(\"🔧 [LangGraph] 正在生成修复代码...\");\r\n\r\n // if (!state.error.code || !state.error.file) {\r\n // return { fixedCode: \"\", filePath: \"\" };\r\n // }\r\n\r\n // try {\r\n // const systemPrompt = new SystemMessage(\r\n // `你是代码修复助手。返回修复后的完整文件内容,不要解释。`\r\n // );\r\n\r\n // const userPrompt = new HumanMessage(`\r\n // 文件(${state.error.code.split(\"\\n\").length} 行):\r\n // ${state.error.code}\r\n\r\n // 错误:${state.error.message}\r\n\r\n // 输出修复后的完整文件:\r\n // `);\r\n\r\n // console.log(\"📤 [调试] 发送修复请求...\");\r\n // console.log(\r\n // \"📤 [调试] 原始文件行数:\",\r\n // state.error.code.split(\"\\n\").length\r\n // );\r\n\r\n // const response = await this.llm.invoke([systemPrompt, userPrompt]);\r\n // let fixedCode = response.content.toString().trim();\r\n\r\n // console.log(\"📥 [调试] AI 返回内容长度:\", fixedCode.length);\r\n // console.log(\"📥 [调试] 原始代码长度:\", state.error.code.length);\r\n // console.log(\"📥 [调试] 返回内容行数:\", fixedCode.split(\"\\n\").length);\r\n\r\n // if (fixedCode.length === 0) {\r\n // console.error(\"❌ [调试] AI 返回空内容,可能是 API 调用失败\");\r\n // return { fixedCode: \"\", filePath: \"\" };\r\n // }\r\n\r\n // fixedCode = fixedCode\r\n // .replace(/^```[\\w]*\\n?/gm, \"\")\r\n // .replace(/\\n?```$/gm, \"\")\r\n // .trim();\r\n\r\n // console.log(\"📥 [调试] 清理后内容长度:\", fixedCode.length);\r\n\r\n // const finalLengthRatio = fixedCode.length / state.error.code.length;\r\n // console.log(\r\n // `✅ [调试] 最终代码长度比例: ${(finalLengthRatio * 100).toFixed(0)}%`\r\n // );\r\n\r\n // return {\r\n // fixedCode,\r\n // filePath: state.error.file,\r\n // messages: [...state.messages, userPrompt, response],\r\n // };\r\n // } catch (error: any) {\r\n // console.error(\"❌ [调试] fixNode 执行失败:\", error.message);\r\n // return { fixedCode: \"\", filePath: \"\" };\r\n // }\r\n // }\r\n\r\n // private async validateNode(\r\n // state: DiagnosticState\r\n // ): Promise<Partial<DiagnosticState>> {\r\n // console.log(\"✅ [LangGraph] 正在验证修复...\");\r\n // return state;\r\n // }\r\n\r\n // private shouldFix(state: DiagnosticState): string {\r\n // if (state.autoFix && state.error.file && state.error.code) {\r\n // return \"fix\";\r\n // }\r\n // return \"end\";\r\n // }\r\n\r\n // private shouldRetry(state: DiagnosticState): string {\r\n // if (state.retryCount < this.maxRetries && !state.fixedCode) {\r\n // return \"retry\";\r\n // }\r\n // return \"end\";\r\n // }\r\n\r\n async run(error: any, autoFix: boolean = false): Promise<DiagnosticState> {\r\n const initialState: DiagnosticState = {\r\n error,\r\n analysis: \"\",\r\n suggestion: \"\",\r\n fixedCode: \"\",\r\n filePath: \"\",\r\n autoFix,\r\n retryCount: 0,\r\n messages: [],\r\n };\r\n\r\n try {\r\n console.log(\"🚀 [LangGraph] 启动诊断工作流...\\n\");\r\n const result = await this.graph.invoke(initialState);\r\n console.log(\"✨ [LangGraph] 诊断工作流完成\\n\");\r\n return result;\r\n } catch (error: any) {\r\n console.error(\"❌ [LangGraph] 工作流执行失败:\", error.message);\r\n throw error;\r\n }\r\n }\r\n}\r\n","/**\r\n * AI 诊断核心逻辑\r\n */\r\n\r\nimport fs from \"fs\";\r\nimport { DiagnosticGraph } from \"./langgraph\";\r\nimport { CodeValidator } from \"./validator\";\r\n\r\nexport interface DiagnosticOptions {\r\n apiKey: string;\r\n apiUrl: string;\r\n model: string;\r\n maxRetries: number;\r\n}\r\n\r\nexport interface DiagnosticResult {\r\n analysis: string;\r\n suggestion: string;\r\n fixedCode?: string;\r\n filePath?: string;\r\n}\r\n\r\nexport class AIErrorDiagnostic {\r\n private options: DiagnosticOptions;\r\n private graph: DiagnosticGraph;\r\n\r\n constructor(options: DiagnosticOptions) {\r\n this.options = options;\r\n\r\n this.graph = new DiagnosticGraph(\r\n options.apiKey,\r\n options.apiUrl,\r\n options.model,\r\n options.maxRetries\r\n );\r\n }\r\n\r\n async diagnose(\r\n error: any,\r\n autoFix: boolean = false\r\n ): Promise<DiagnosticResult> {\r\n if (!this.options.apiKey) {\r\n return {\r\n analysis: \"未配置 API Key,无法使用 AI 诊断功能\",\r\n suggestion: \"请在 .env 文件中配置 OPENAI_API_KEY\",\r\n fixedCode: undefined,\r\n filePath: undefined,\r\n };\r\n }\r\n\r\n try {\r\n // 注意:自动修复功能已暂时禁用,因为不够稳定\r\n // 强制设置 autoFix 为 false\r\n const result = await this.graph.run(error, false);\r\n\r\n // 自动修复功能已注释(不够稳定)\r\n // if (autoFix && result.fixedCode && result.filePath) {\r\n // console.log(\"\\n🔍 [验证] 正在验证修复后的代码...\");\r\n\r\n // const validation = CodeValidator.validateFix(\r\n // error.code,\r\n // result.fixedCode\r\n // );\r\n\r\n // if (!validation.valid) {\r\n // console.warn(`⚠️ [验证失败] ${validation.reason}`);\r\n // console.log(\"📝 [提示] 将只提供修复建议,不自动应用修复\\n\");\r\n\r\n // return {\r\n // analysis: result.analysis,\r\n // suggestion:\r\n // result.suggestion +\r\n // \"\\n\\n⚠️ 自动修复验证失败:\" +\r\n // validation.reason,\r\n // fixedCode: undefined,\r\n // filePath: undefined,\r\n // };\r\n // }\r\n\r\n // console.log(\"✅ [验证通过] 代码验证成功\\n\");\r\n // this.applyFix(result.filePath, result.fixedCode);\r\n // }\r\n\r\n return {\r\n analysis: result.analysis,\r\n suggestion: result.suggestion,\r\n fixedCode: undefined, // 暂时不返回修复代码\r\n filePath: undefined,\r\n };\r\n } catch (error: any) {\r\n console.error(\"❌ AI 诊断失败:\", error.message);\r\n return {\r\n analysis: `诊断过程出错: ${error.message}`,\r\n suggestion: \"请检查 API 配置和网络连接\",\r\n fixedCode: undefined,\r\n filePath: undefined,\r\n };\r\n }\r\n }\r\n\r\n // 自动修复功能已注释(不够稳定)\r\n // private applyFix(filePath: string, fixedCode: string): void {\r\n // try {\r\n // const backupPath = `${filePath}.backup`;\r\n // if (fs.existsSync(filePath)) {\r\n // fs.copyFileSync(filePath, backupPath);\r\n // console.log(`📦 [备份] 已创建备份: ${backupPath}`);\r\n // }\r\n\r\n // fs.writeFileSync(filePath, fixedCode, \"utf-8\");\r\n // console.log(`✅ [修复] 已修复文件: ${filePath}`);\r\n // console.log(`💡 [提示] 如需恢复,运行: cp \"${backupPath}\" \"${filePath}\"`);\r\n // } catch (error: any) {\r\n // console.error(`❌ [修复失败] ${error.message}`);\r\n // }\r\n // }\r\n}\r\n","/**\r\n * AI 诊断报告生成器\r\n */\r\n\r\nimport fs from \"fs\";\r\nimport path from \"path\";\r\n\r\nexport interface DiagnosticReport {\r\n timestamp: string;\r\n error: {\r\n type: string;\r\n message: string;\r\n file: string;\r\n stack?: string;\r\n };\r\n analysis: string;\r\n suggestion: string;\r\n fixed: boolean;\r\n fixedFilePath?: string;\r\n}\r\n\r\nexport interface MultiDiagnosticReport {\r\n timestamp: string;\r\n totalErrors: number;\r\n errors: DiagnosticReport[];\r\n}\r\n\r\nexport interface ReporterOptions {\r\n console?: boolean;\r\n html?: boolean;\r\n markdown?: boolean;\r\n json?: boolean;\r\n}\r\n\r\nexport class DiagnosticReporter {\r\n /**\r\n * 生成报告(根据配置生成多种格式)\r\n */\r\n static async generate(\r\n report: DiagnosticReport,\r\n options: ReporterOptions = {},\r\n ): Promise<void> {\r\n // HTML 报告\r\n if (options.html) {\r\n await this.generateHTMLReport(report);\r\n }\r\n\r\n // Markdown 报告\r\n if (options.markdown) {\r\n await this.generateMarkdownReport(report);\r\n }\r\n\r\n // JSON 报告\r\n if (options.json) {\r\n await this.generateJSONReport(report);\r\n }\r\n }\r\n\r\n /**\r\n * 生成 HTML 报告\r\n */\r\n static async generateHTMLReport(report: DiagnosticReport): Promise<void> {\r\n const html = `\r\n<!DOCTYPE html>\r\n<html lang=\"zh-CN\">\r\n<head>\r\n <meta charset=\"UTF-8\">\r\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n <title>AI 诊断报告</title>\r\n <style>\r\n * { margin: 0; padding: 0; box-sizing: border-box; }\r\n body {\r\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\r\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\r\n padding: 20px;\r\n min-height: 100vh;\r\n }\r\n .container {\r\n max-width: 1000px;\r\n margin: 0 auto;\r\n background: white;\r\n border-radius: 12px;\r\n box-shadow: 0 8px 32px rgba(0,0,0,0.2);\r\n overflow: hidden;\r\n }\r\n .header {\r\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\r\n color: white;\r\n padding: 30px;\r\n text-align: center;\r\n }\r\n .header h1 {\r\n font-size: 32px;\r\n margin-bottom: 10px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 10px;\r\n }\r\n .header .time {\r\n font-size: 14px;\r\n opacity: 0.9;\r\n }\r\n .content {\r\n padding: 30px;\r\n }\r\n .section {\r\n margin-bottom: 30px;\r\n }\r\n .section-title {\r\n font-size: 20px;\r\n font-weight: bold;\r\n color: #333;\r\n margin-bottom: 15px;\r\n padding-bottom: 10px;\r\n border-bottom: 2px solid #667eea;\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n }\r\n .error-box {\r\n background: #fff5f5;\r\n border-left: 4px solid #f56565;\r\n padding: 20px;\r\n border-radius: 8px;\r\n margin-bottom: 20px;\r\n }\r\n .error-type {\r\n display: inline-block;\r\n background: #f56565;\r\n color: white;\r\n padding: 4px 12px;\r\n border-radius: 12px;\r\n font-size: 12px;\r\n font-weight: bold;\r\n margin-bottom: 10px;\r\n }\r\n .error-message {\r\n font-size: 16px;\r\n color: #c53030;\r\n font-weight: 500;\r\n margin-bottom: 10px;\r\n line-height: 1.6;\r\n }\r\n .error-file {\r\n font-size: 14px;\r\n color: #666;\r\n font-family: 'Courier New', monospace;\r\n background: #f7fafc;\r\n padding: 8px 12px;\r\n border-radius: 4px;\r\n display: inline-block;\r\n }\r\n .analysis-box {\r\n background: #f0f9ff;\r\n border-left: 4px solid #3b82f6;\r\n padding: 20px;\r\n border-radius: 8px;\r\n line-height: 1.8;\r\n color: #1e40af;\r\n }\r\n .suggestion-box {\r\n background: #f0fdf4;\r\n border-left: 4px solid #10b981;\r\n padding: 20px;\r\n border-radius: 8px;\r\n line-height: 1.8;\r\n color: #065f46;\r\n }\r\n .suggestion-box pre {\r\n background: #1e293b;\r\n color: #e2e8f0;\r\n padding: 15px;\r\n border-radius: 6px;\r\n overflow-x: auto;\r\n margin: 10px 0;\r\n font-size: 14px;\r\n line-height: 1.5;\r\n }\r\n .fixed-badge {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 6px;\r\n background: #10b981;\r\n color: white;\r\n padding: 8px 16px;\r\n border-radius: 20px;\r\n font-size: 14px;\r\n font-weight: bold;\r\n }\r\n .not-fixed-badge {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 6px;\r\n background: #f59e0b;\r\n color: white;\r\n padding: 8px 16px;\r\n border-radius: 20px;\r\n font-size: 14px;\r\n font-weight: bold;\r\n }\r\n .footer {\r\n background: #f7fafc;\r\n padding: 20px;\r\n text-align: center;\r\n color: #718096;\r\n font-size: 14px;\r\n border-top: 1px solid #e2e8f0;\r\n }\r\n .stack-trace {\r\n background: #1e293b;\r\n color: #e2e8f0;\r\n padding: 15px;\r\n border-radius: 6px;\r\n overflow-x: auto;\r\n font-family: 'Courier New', monospace;\r\n font-size: 12px;\r\n line-height: 1.5;\r\n margin-top: 10px;\r\n max-height: 300px;\r\n overflow-y: auto;\r\n }\r\n </style>\r\n</head>\r\n<body>\r\n <div class=\"container\">\r\n <div class=\"header\">\r\n <h1>🤖 AI 诊断报告</h1>\r\n <div class=\"time\">生成时间: ${report.timestamp}</div>\r\n </div>\r\n\r\n <div class=\"content\">\r\n <!-- 错误信息 -->\r\n <div class=\"section\">\r\n <div class=\"section-title\">❌ 错误信息</div>\r\n <div class=\"error-box\">\r\n <span class=\"error-type\">${report.error.type}</span>\r\n <div class=\"error-message\">${this.escapeHtml(\r\n report.error.message,\r\n )}</div>\r\n <div class=\"error-file\">📂 ${report.error.file}</div>\r\n ${\r\n report.error.stack\r\n ? `<div class=\"stack-trace\">${this.escapeHtml(\r\n report.error.stack,\r\n )}</div>`\r\n : \"\"\r\n }\r\n </div>\r\n </div>\r\n\r\n <!-- AI 分析 -->\r\n <div class=\"section\">\r\n <div class=\"section-title\">🔍 AI 分析</div>\r\n <div class=\"analysis-box\">\r\n ${this.formatText(report.analysis)}\r\n </div>\r\n </div>\r\n\r\n <!-- 修复建议 -->\r\n <div class=\"section\">\r\n <div class=\"section-title\">💡 修复建议</div>\r\n <div class=\"suggestion-box\">\r\n ${this.formatText(report.suggestion)}\r\n </div>\r\n </div>\r\n\r\n <!-- 修复状态 -->\r\n <div class=\"section\">\r\n <div class=\"section-title\">🔧 修复状态</div>\r\n ${\r\n report.fixed\r\n ? `<div class=\"fixed-badge\">✅ 已自动修复</div>\r\n <div style=\"margin-top: 10px; color: #666;\">修复文件: <code>${report.fixedFilePath}</code></div>`\r\n : `<div class=\"not-fixed-badge\">⚠️ 未自动修复</div>\r\n <div style=\"margin-top: 10px; color: #666;\">请根据上述建议手动修复</div>`\r\n }\r\n </div>\r\n </div>\r\n\r\n <div class=\"footer\">\r\n <p>AI Diagnostic Plugin v1.0.0</p>\r\n <p>Powered by LangGraph & OpenAI</p>\r\n </div>\r\n </div>\r\n</body>\r\n</html>\r\n `.trim();\r\n\r\n // 创建报告目录\r\n const reportsDir = path.resolve(process.cwd(), \"ai-reports\");\r\n if (!fs.existsSync(reportsDir)) {\r\n fs.mkdirSync(reportsDir, { recursive: true });\r\n }\r\n\r\n const reportPath = path.resolve(reportsDir, \"diagnostic-report.html\");\r\n fs.writeFileSync(reportPath, html, \"utf-8\");\r\n console.log(`\\n📄 诊断报告已生成: ${reportPath}\\n`);\r\n }\r\n\r\n /**\r\n * 转义 HTML 特殊字符\r\n */\r\n private static escapeHtml(text: string): string {\r\n const map: Record<string, string> = {\r\n \"&\": \"&\",\r\n \"<\": \"<\",\r\n \">\": \">\",\r\n '\"': \""\",\r\n \"'\": \"'\",\r\n };\r\n return text.replace(/[&<>\"']/g, (m) => map[m]);\r\n }\r\n\r\n /**\r\n * 格式化文本(支持代码块和换行)\r\n */\r\n private static formatText(text: string): string {\r\n // 转义 HTML\r\n let formatted = this.escapeHtml(text);\r\n\r\n // 处理代码块\r\n formatted = formatted.replace(\r\n /```(\\w*)\\n([\\s\\S]*?)```/g,\r\n (_, lang, code) => {\r\n return `<pre><code>${code.trim()}</code></pre>`;\r\n },\r\n );\r\n\r\n // 处理行内代码\r\n formatted = formatted.replace(\r\n /`([^`]+)`/g,\r\n '<code style=\"background: #e2e8f0; padding: 2px 6px; border-radius: 3px; font-family: monospace;\">$1</code>',\r\n );\r\n\r\n // 处理换行\r\n formatted = formatted.replace(/\\n/g, \"<br>\");\r\n\r\n return formatted;\r\n }\r\n\r\n /**\r\n * 生成 Markdown 报告\r\n */\r\n static async generateMarkdownReport(report: DiagnosticReport): Promise<void> {\r\n const markdown = `# 🤖 AI 诊断报告\r\n\r\n**生成时间**: ${report.timestamp}\r\n\r\n---\r\n\r\n## ❌ 错误信息\r\n\r\n**类型**: \\`${report.error.type}\\` \r\n**文件**: \\`${report.error.file}\\` \r\n**消息**: \r\n\\`\\`\\`\r\n${report.error.message}\r\n\\`\\`\\`\r\n\r\n${\r\n report.error.stack\r\n ? `**堆栈跟踪**:\\n\\`\\`\\`\\n${report.error.stack}\\n\\`\\`\\`\\n`\r\n : \"\"\r\n}\r\n\r\n---\r\n\r\n## 🔍 AI 分析\r\n\r\n${report.analysis}\r\n\r\n---\r\n\r\n## 💡 修复建议\r\n\r\n${report.suggestion}\r\n\r\n---\r\n\r\n## 🔧 修复状态\r\n\r\n${\r\n report.fixed\r\n ? `✅ **已自动修复**\\n\\n修复文件: \\`${report.fixedFilePath}\\``\r\n : `⚠️ **未自动修复**\\n\\n请根据上述建议手动修复`\r\n}\r\n\r\n---\r\n\r\n*AI Diagnostic Plugin v1.0.0* \r\n*Powered by LangGraph & OpenAI*\r\n`;\r\n\r\n // 创建报告目录\r\n const reportsDir = path.resolve(process.cwd(), \"ai-reports\");\r\n if (!fs.existsSync(reportsDir)) {\r\n fs.mkdirSync(reportsDir, { recursive: true });\r\n }\r\n\r\n const reportPath = path.resolve(reportsDir, \"diagnostic-report.md\");\r\n fs.writeFileSync(reportPath, markdown, \"utf-8\");\r\n console.log(`📄 Markdown 报告已生成: ${reportPath}`);\r\n }\r\n\r\n /**\r\n * 生成 JSON 报告\r\n */\r\n static async generateJSONReport(report: DiagnosticReport): Promise<void> {\r\n const jsonReport = {\r\n version: \"1.0.0\",\r\n timestamp: report.timestamp,\r\n error: {\r\n type: report.error.type,\r\n message: report.error.message,\r\n file: report.error.file,\r\n stack: report.error.stack || null,\r\n },\r\n diagnosis: {\r\n analysis: report.analysis,\r\n suggestion: report.suggestion,\r\n },\r\n fix: {\r\n applied: report.fixed,\r\n filePath: report.fixedFilePath || null,\r\n },\r\n };\r\n\r\n // 创建报告目录\r\n const reportsDir = path.resolve(process.cwd(), \"ai-reports\");\r\n if (!fs.existsSync(reportsDir)) {\r\n fs.mkdirSync(reportsDir, { recursive: true });\r\n }\r\n\r\n const reportPath = path.resolve(reportsDir, \"diagnostic-report.json\");\r\n fs.writeFileSync(reportPath, JSON.stringify(jsonReport, null, 2), \"utf-8\");\r\n console.log(`📄 JSON 报告已生成: ${reportPath}`);\r\n }\r\n\r\n /**\r\n * 生成多错误合并报告\r\n */\r\n static async generateMultiReport(\r\n reports: DiagnosticReport[],\r\n options: ReporterOptions = {},\r\n ): Promise<void> {\r\n const multiReport: MultiDiagnosticReport = {\r\n timestamp: new Date().toLocaleString(\"zh-CN\"),\r\n totalErrors: reports.length,\r\n errors: reports,\r\n };\r\n\r\n // HTML 报告\r\n if (options.html) {\r\n await this.generateMultiHTMLReport(multiReport);\r\n }\r\n\r\n // Markdown 报告\r\n if (options.markdown) {\r\n await this.generateMultiMarkdownReport(multiReport);\r\n }\r\n\r\n // JSON 报告\r\n if (options.json) {\r\n await this.generateMultiJSONReport(multiReport);\r\n }\r\n }\r\n\r\n /**\r\n * 生成多错误 HTML 报告\r\n */\r\n static async generateMultiHTMLReport(\r\n report: MultiDiagnosticReport,\r\n ): Promise<void> {\r\n const errorsHtml = report.errors\r\n .map(\r\n (error, index) => `\r\n <div class=\"error-item\">\r\n <div class=\"error-number\">错误 ${index + 1} / ${\r\n report.totalErrors\r\n }</div>\r\n <div class=\"error-box\">\r\n <span class=\"error-type\">${error.error.type}</span>\r\n <div class=\"error-message\">${this.escapeHtml(\r\n error.error.message,\r\n )}</div>\r\n <div class=\"error-file\">📂 ${error.error.file}</div>\r\n ${\r\n error.error.stack\r\n ? `<div class=\"stack-trace\">${this.escapeHtml(\r\n error.error.stack,\r\n )}</div>`\r\n : \"\"\r\n }\r\n </div>\r\n\r\n <div class=\"section\">\r\n <div class=\"section-title\">🔍 AI 分析</div>\r\n <div class=\"analysis-box\">\r\n ${this.formatText(error.analysis)}\r\n </div>\r\n </div>\r\n\r\n <div class=\"section\">\r\n <div class=\"section-title\">💡 修复建议</div>\r\n <div class=\"suggestion-box\">\r\n ${this.formatText(error.suggestion)}\r\n </div>\r\n </div>\r\n\r\n <div class=\"section\">\r\n <div class=\"section-title\">🔧 修复状态</div>\r\n ${\r\n error.fixed\r\n ? `<div class=\"fixed-badge\">✅ 已自动修复</div>\r\n <div style=\"margin-top: 10px; color: #666;\">修复文件: <code>${error.fixedFilePath}</code></div>`\r\n : `<div class=\"not-fixed-badge\">⚠️ 未自动修复</div>\r\n <div style=\"margin-top: 10px; color: #666;\">请根据上述建议手动修复</div>`\r\n }\r\n </div>\r\n </div>\r\n `,\r\n )\r\n .join(\"\");\r\n\r\n const html = `\r\n<!DOCTYPE html>\r\n<html lang=\"zh-CN\">\r\n<head>\r\n <meta charset=\"UTF-8\">\r\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n <title>AI 诊断报告 - ${report.totalErrors} 个错误</title>\r\n <style>\r\n * { margin: 0; padding: 0; box-sizing: border-box; }\r\n body {\r\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\r\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\r\n padding: 20px;\r\n min-height: 100vh;\r\n }\r\n .container {\r\n max-width: 1000px;\r\n margin: 0 auto;\r\n background: white;\r\n border-radius: 12px;\r\n box-shadow: 0 8px 32px rgba(0,0,0,0.2);\r\n overflow: hidden;\r\n }\r\n .header {\r\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\r\n color: white;\r\n padding: 30px;\r\n text-align: center;\r\n }\r\n .header h1 {\r\n font-size: 32px;\r\n margin-bottom: 10px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 10px;\r\n }\r\n .header .time {\r\n font-size: 14px;\r\n opacity: 0.9;\r\n }\r\n .header .error-count {\r\n font-size: 18px;\r\n margin-top: 10px;\r\n background: rgba(255,255,255,0.2);\r\n padding: 8px 16px;\r\n border-radius: 20px;\r\n display: inline-block;\r\n }\r\n .content {\r\n padding: 30px;\r\n }\r\n .error-item {\r\n margin-bottom: 40px;\r\n padding-bottom: 40px;\r\n border-bottom: 2px dashed #e2e8f0;\r\n }\r\n .error-item:last-child {\r\n border-bottom: none;\r\n margin-bottom: 0;\r\n padding-bottom: 0;\r\n }\r\n .error-number {\r\n font-size: 16px;\r\n font-weight: bold;\r\n color: #667eea;\r\n margin-bottom: 15px;\r\n padding: 8px 16px;\r\n background: #f0f9ff;\r\n border-radius: 8px;\r\n display: inline-block;\r\n }\r\n .section {\r\n margin-bottom: 20px;\r\n }\r\n .section-title {\r\n font-size: 18px;\r\n font-weight: bold;\r\n color: #333;\r\n margin-bottom: 12px;\r\n padding-bottom: 8px;\r\n border-bottom: 2px solid #667eea;\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n }\r\n .error-box {\r\n background: #fff5f5;\r\n border-left: 4px solid #f56565;\r\n padding: 20px;\r\n border-radius: 8px;\r\n margin-bottom: 20px;\r\n }\r\n .error-type {\r\n display: inline-block;\r\n background: #f56565;\r\n color: white;\r\n padding: 4px 12px;\r\n border-radius: 12px;\r\n font-size: 12px;\r\n font-weight: bold;\r\n margin-bottom: 10px;\r\n }\r\n .error-message {\r\n font-size: 16px;\r\n color: #c53030;\r\n font-weight: 500;\r\n margin-bottom: 10px;\r\n line-height: 1.6;\r\n }\r\n .error-file {\r\n font-size: 14px;\r\n color: #666;\r\n font-family: 'Courier New', monospace;\r\n background: #f7fafc;\r\n padding: 8px 12px;\r\n border-radius: 4px;\r\n display: inline-block;\r\n }\r\n .analysis-box {\r\n background: #f0f9ff;\r\n border-left: 4px solid #3b82f6;\r\n padding: 20px;\r\n border-radius: 8px;\r\n line-height: 1.8;\r\n color: #1e40af;\r\n }\r\n .suggestion-box {\r\n background: #f0fdf4;\r\n border-left: 4px solid #10b981;\r\n padding: 20px;\r\n border-radius: 8px;\r\n line-height: 1.8;\r\n color: #065f46;\r\n }\r\n .suggestion-box pre {\r\n background: #1e293b;\r\n color: #e2e8f0;\r\n padding: 15px;\r\n border-radius: 6px;\r\n overflow-x: auto;\r\n margin: 10px 0;\r\n font-size: 14px;\r\n line-height: 1.5;\r\n }\r\n .fixed-badge {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 6px;\r\n background: #10b981;\r\n color: white;\r\n padding: 8px 16px;\r\n border-radius: 20px;\r\n font-size: 14px;\r\n font-weight: bold;\r\n }\r\n .not-fixed-badge {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 6px;\r\n background: #f59e0b;\r\n color: white;\r\n padding: 8px 16px;\r\n border-radius: 20px;\r\n font-size: 14px;\r\n font-weight: bold;\r\n }\r\n .footer {\r\n background: #f7fafc;\r\n padding: 20px;\r\n text-align: center;\r\n color: #718096;\r\n font-size: 14px;\r\n border-top: 1px solid #e2e8f0;\r\n }\r\n .stack-trace {\r\n background: #1e293b;\r\n color: #e2e8f0;\r\n padding: 15px;\r\n border-radius: 6px;\r\n overflow-x: auto;\r\n font-family: 'Courier New', monospace;\r\n font-size: 12px;\r\n line-height: 1.5;\r\n margin-top: 10px;\r\n max-height: 300px;\r\n overflow-y: auto;\r\n }\r\n </style>\r\n</head>\r\n<body>\r\n <div class=\"container\">\r\n <div class=\"header\">\r\n <h1>🤖 AI 诊断报告</h1>\r\n <div class=\"time\">生成时间: ${report.timestamp}</div>\r\n <div class=\"error-count\">共发现 ${report.totalErrors} 个错误</div>\r\n </div>\r\n\r\n <div class=\"content\">\r\n ${errorsHtml}\r\n </div>\r\n\r\n <div class=\"footer\">\r\n <p>AI Diagnostic Plugin v1.0.7</p>\r\n <p>Powered by LangGraph & OpenAI</p>\r\n </div>\r\n </div>\r\n</body>\r\n</html>\r\n `.trim();\r\n\r\n // 创建报告目录\r\n const reportsDir = path.resolve(process.cwd(), \"ai-reports\");\r\n if (!fs.existsSync(reportsDir)) {\r\n fs.mkdirSync(reportsDir, { recursive: true });\r\n }\r\n\r\n const reportPath = path.resolve(reportsDir, \"diagnostic-report.html\");\r\n fs.writeFileSync(reportPath, html, \"utf-8\");\r\n console.log(\r\n `\\n📄 诊断报告已生成: ${reportPath} (${report.totalErrors} 个错误)\\n`,\r\n );\r\n }\r\n\r\n /**\r\n * 生成多错误 Markdown 报告\r\n */\r\n static async generateMultiMarkdownReport(\r\n report: MultiDiagnosticReport,\r\n ): Promise<void> {\r\n const errorsMarkdown = report.errors\r\n .map(\r\n (error, index) => `\r\n## 错误 ${index + 1} / ${report.totalErrors}\r\n\r\n### ❌ 错误信息\r\n\r\n**类型**: \\`${error.error.type}\\` \r\n**文件**: \\`${error.error.file}\\` \r\n**消息**: \r\n\\`\\`\\`\r\n${error.error.message}\r\n\\`\\`\\`\r\n\r\n${\r\n error.error.stack\r\n ? `**堆栈跟踪**:\\n\\`\\`\\`\\n${error.error.stack}\\n\\`\\`\\`\\n`\r\n : \"\"\r\n}\r\n\r\n### 🔍 AI 分析\r\n\r\n${error.analysis}\r\n\r\n### 💡 修复建议\r\n\r\n${error.suggestion}\r\n\r\n### 🔧 修复状态\r\n\r\n${\r\n error.fixed\r\n ? `✅ **已自动修复**\\n\\n修复文件: \\`${error.fixedFilePath}\\``\r\n : `⚠️ **未自动修复**\\n\\n请根据上述建议手动修复`\r\n}\r\n\r\n---\r\n`,\r\n )\r\n .join(\"\\n\");\r\n\r\n const markdown = `# 🤖 AI 诊断报告\r\n\r\n**生成时间**: ${report.timestamp} \r\n**错误总数**: ${report.totalErrors}\r\n\r\n---\r\n\r\n${errorsMarkdown}\r\n\r\n*AI Diagnostic Plugin v1.0.7* \r\n*Powered by LangGraph & OpenAI*\r\n`;\r\n\r\n // 创建报告目录\r\n const reportsDir = path.resolve(process.cwd(), \"ai-reports\");\r\n if (!fs.existsSync(reportsDir)) {\r\n fs.mkdirSync(reportsDir, { recursive: true });\r\n }\r\n\r\n const reportPath = path.resolve(reportsDir, \"diagnostic-report.md\");\r\n fs.writeFileSync(reportPath, markdown, \"utf-8\");\r\n console.log(`📄 Markdown 报告已生成: ${reportPath}`);\r\n }\r\n\r\n /**\r\n * 生成多错误 JSON 报告\r\n */\r\n static async generateMultiJSONReport(\r\n report: MultiDiagnosticReport,\r\n ): Promise<void> {\r\n const jsonReport = {\r\n version: \"1.0.7\",\r\n timestamp: report.timestamp,\r\n totalErrors: report.totalErrors,\r\n errors: report.errors.map((error) => ({\r\n error: {\r\n type: error.error.type,\r\n message: error.error.message,\r\n file: error.error.file,\r\n stack: error.error.stack || null,\r\n },\r\n diagnosis: {\r\n analysis: error.analysis,\r\n suggestion: error.suggestion,\r\n },\r\n fix: {\r\n applied: error.fixed,\r\n filePath: error.fixedFilePath || null,\r\n },\r\n })),\r\n };\r\n\r\n // 创建报告目录\r\n const reportsDir = path.resolve(process.cwd(), \"ai-reports\");\r\n if (!fs.existsSync(reportsDir)) {\r\n fs.mkdirSync(reportsDir, { recursive: true });\r\n }\r\n\r\n const reportPath = path.resolve(reportsDir, \"diagnostic-report.json\");\r\n fs.writeFileSync(reportPath, JSON.stringify(jsonReport, null, 2), \"utf-8\");\r\n console.log(`📄 JSON 报告已生成: ${reportPath}`);\r\n }\r\n}\r\n"],"mappings":"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","names":["import_fs","import_path","error","error","path","fs","path","fs","options"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/langgraph.ts","../src/diagnostic.ts","../src/reporter.ts"],"sourcesContent":["/**\r\n * AI 诊断插件入口\r\n *\r\n * 功能:\r\n * - 自动诊断构建错误\r\n * - 提供修复建议\r\n * - 自动修复代码\r\n */\r\n\r\nimport type { Plugin, ResolvedConfig } from \"vite\";\r\nimport fs from \"fs\";\r\nimport path from \"path\";\r\nimport { AIErrorDiagnostic } from \"./diagnostic\";\r\nimport { extractSourceFile } from \"vite-plugin-ai-shared\";\r\nimport { DiagnosticReporter, type DiagnosticReport } from \"./reporter\";\r\nimport { glob } from \"glob\";\r\n\r\nexport interface AIPluginOptions {\r\n apiKey?: string;\r\n apiUrl?: string;\r\n autoFix?: boolean;\r\n model?: string;\r\n maxRetries?: number;\r\n temperature?: number;\r\n maxTokens?: number;\r\n output?: {\r\n console?: boolean;\r\n html?: boolean;\r\n markdown?: boolean;\r\n json?: boolean;\r\n };\r\n}\r\n\r\nexport function vitePluginAIDiagnostic(options: AIPluginOptions = {}): Plugin {\r\n const {\r\n apiKey = process.env.OPENAI_API_KEY || \"\",\r\n apiUrl = process.env.OPENAI_API_URL || \"https://api.openai.com/v1\",\r\n autoFix = false,\r\n model = \"gpt-4\",\r\n maxRetries = 3,\r\n temperature = 0.1,\r\n maxTokens = 4000,\r\n output = {\r\n console: true,\r\n html: true,\r\n markdown: false,\r\n json: false,\r\n },\r\n } = options;\r\n\r\n const diagnostic = new AIErrorDiagnostic({\r\n apiKey,\r\n apiUrl,\r\n model,\r\n maxRetries,\r\n temperature,\r\n maxTokens,\r\n });\r\n\r\n let buildErrors: any[] = [];\r\n let lastTransformFile: string | null = null;\r\n let processedErrors = new Set<string>(); // 记录已处理的错误\r\n let config: ResolvedConfig;\r\n let diagnosticResults: DiagnosticReport[] = []; // 收集所有诊断结果\r\n\r\n // 处理错误的函数\r\n async function processError(error: any) {\r\n // 生成错误的唯一标识\r\n const errorKey = `${error.file}:${error.message}`;\r\n\r\n // 如果已经处理过,跳过\r\n if (processedErrors.has(errorKey)) {\r\n console.log(\"🔍 [调试] 跳过重复错误:\", errorKey);\r\n return;\r\n }\r\n\r\n processedErrors.add(errorKey);\r\n\r\n try {\r\n console.log(\"\\n⚠️ 检测到错误,正在使用 AI 分析...\\n\");\r\n console.log(`📝 错误信息: ${error.message}`);\r\n console.log(`📂 文件路径: ${error.file || \"未知\"}`);\r\n console.log(\r\n `📄 代码长度: ${error.code ? error.code.length + \" 字符\" : \"无\"}`,\r\n );\r\n console.log(`🔧 自动修复: ${autoFix ? \"是\" : \"否\"}\\n`);\r\n\r\n if (!error.file || !error.code) {\r\n console.log(\"⚠️ 跳过此错误:缺少文件路径或代码内容\\n\");\r\n return;\r\n }\r\n\r\n const result = await diagnostic.diagnose(error, autoFix);\r\n\r\n // 控制台输出\r\n if (output.console !== false) {\r\n console.log(\"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\");\r\n console.log(\"🔍 错误分析:\");\r\n console.log(result.analysis);\r\n console.log(\"\\n💡 修复建议:\");\r\n console.log(result.suggestion);\r\n\r\n if (result.fixedCode && result.filePath) {\r\n console.log(\"\\n✅ 已自动修复代码\");\r\n console.log(\"修复的文件:\", result.filePath);\r\n console.log(\"\\n💡 请重新运行构建命令\");\r\n } else if (autoFix) {\r\n console.log(\"\\n⚠️ 无法自动修复:AI 未生成修复代码\");\r\n }\r\n console.log(\"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\n\");\r\n }\r\n\r\n // 生成报告对象\r\n const report: DiagnosticReport = {\r\n timestamp: new Date().toLocaleString(\"zh-CN\"),\r\n error: {\r\n type: error.type || \"unknown\",\r\n message: error.message,\r\n file: error.file,\r\n stack: error.stack,\r\n },\r\n analysis: result.analysis,\r\n suggestion: result.suggestion,\r\n fixed: !!(result.fixedCode && result.filePath),\r\n fixedFilePath: result.filePath,\r\n };\r\n\r\n // 收集诊断结果,稍后统一生成报告\r\n diagnosticResults.push(report);\r\n } catch (err: any) {\r\n console.error(\"❌ AI 诊断失败:\", err.message);\r\n }\r\n }\r\n\r\n return {\r\n name: \"vite-plugin-ai-diagnostic\",\r\n\r\n // 确保插件在其他插件之后执行,以捕获更多错误\r\n enforce: \"post\",\r\n\r\n configResolved(resolvedConfig) {\r\n config = resolvedConfig;\r\n console.log(\"\\n🤖 AI 诊断助手已启动...\");\r\n console.log(`⚙️ 自动修复: ${autoFix ? \"✅ 已启用\" : \"❌ 未启用\"}`);\r\n console.log(`📝 根目录: ${config.root}`);\r\n console.log(\r\n `📝 入口: ${config.build.rollupOptions?.input || \"index.html\"}\\n`,\r\n );\r\n },\r\n\r\n async buildStart() {\r\n buildErrors = [];\r\n processedErrors.clear();\r\n diagnosticResults = []; // 清空诊断结果\r\n console.log(\"🔍 开始扫描源文件...\");\r\n\r\n // 扫描 src 目录下的所有源文件\r\n const srcDir = path.join(config.root, \"src\");\r\n if (!fs.existsSync(srcDir)) {\r\n console.log(\"⚠️ src 目录不存在,跳过文件扫描\");\r\n return;\r\n }\r\n\r\n try {\r\n // 使用 glob 查找所有源文件\r\n const files = await glob(\"**/*.{vue,ts,tsx,js,jsx}\", {\r\n cwd: srcDir,\r\n absolute: true,\r\n ignore: [\"**/node_modules/**\", \"**/*.d.ts\"],\r\n });\r\n\r\n console.log(`📂 找到 ${files.length} 个源文件`);\r\n\r\n // 检查每个文件的语法\r\n for (const file of files) {\r\n try {\r\n const code = fs.readFileSync(file, \"utf-8\");\r\n\r\n // 基本语法检查\r\n if (file.endsWith(\".vue\")) {\r\n // 检查 Vue 文件的基本结构\r\n if (!code.includes(\"<template>\") && !code.includes(\"<script>\")) {\r\n buildErrors.push({\r\n type: \"syntax\",\r\n message: \"Vue 文件缺少 <template> 或 <script> 标签\",\r\n file: file,\r\n code: code,\r\n });\r\n }\r\n\r\n // 检查未闭合的标签\r\n const templateMatch = code.match(/<template[^>]*>/);\r\n if (templateMatch && !code.includes(\"</template>\")) {\r\n buildErrors.push({\r\n type: \"syntax\",\r\n message: \"Vue 文件中 <template> 标签未闭合\",\r\n file: file,\r\n code: code,\r\n });\r\n }\r\n\r\n const scriptMatch = code.match(/<script[^>]*>/);\r\n if (scriptMatch && !code.includes(\"</script>\")) {\r\n buildErrors.push({\r\n type: \"syntax\",\r\n message: \"Vue 文件中 <script> 标签未闭合\",\r\n file: file,\r\n code: code,\r\n });\r\n }\r\n }\r\n\r\n // 检查 JavaScript/TypeScript 语法错误(简单检查)\r\n if (\r\n file.endsWith(\".ts\") ||\r\n file.endsWith(\".tsx\") ||\r\n file.endsWith(\".js\") ||\r\n file.endsWith(\".jsx\")\r\n ) {\r\n // 检查括号匹配\r\n const openBraces = (code.match(/\\{/g) || []).length;\r\n const closeBraces = (code.match(/\\}/g) || []).length;\r\n if (openBraces !== closeBraces) {\r\n buildErrors.push({\r\n type: \"syntax\",\r\n message: `括号不匹配:{ 有 ${openBraces} 个,} 有 ${closeBraces} 个`,\r\n file: file,\r\n code: code,\r\n });\r\n }\r\n\r\n const openParens = (code.match(/\\(/g) || []).length;\r\n const closeParens = (code.match(/\\)/g) || []).length;\r\n if (openParens !== closeParens) {\r\n buildErrors.push({\r\n type: \"syntax\",\r\n message: `圆括号不匹配:( 有 ${openParens} 个,) 有 ${closeParens} 个`,\r\n file: file,\r\n code: code,\r\n });\r\n }\r\n }\r\n\r\n // 检查导入语句中的不存在模块(这个会在后续构建中被捕获)\r\n const importRegex = /import\\s+.*?\\s+from\\s+['\"](.+?)['\"]/g;\r\n let match;\r\n while ((match = importRegex.exec(code)) !== null) {\r\n const importPath = match[1];\r\n\r\n // 跳过 node_modules 和别名导入\r\n if (importPath.startsWith(\".\") || importPath.startsWith(\"/\")) {\r\n const resolvedPath = path.resolve(\r\n path.dirname(file),\r\n importPath,\r\n );\r\n const extensions = [\".ts\", \".tsx\", \".js\", \".jsx\", \".vue\", \"\"];\r\n\r\n let exists = false;\r\n for (const ext of extensions) {\r\n const fullPath = resolvedPath + ext;\r\n if (fs.existsSync(fullPath)) {\r\n exists = true;\r\n break;\r\n }\r\n // 检查是否为目录,且包含 index 文件\r\n if (\r\n fs.existsSync(resolvedPath) &&\r\n fs.statSync(resolvedPath).isDirectory()\r\n ) {\r\n const indexPath = path.join(resolvedPath, \"index\" + ext);\r\n if (fs.existsSync(indexPath)) {\r\n exists = true;\r\n break;\r\n }\r\n }\r\n }\r\n\r\n if (!exists) {\r\n buildErrors.push({\r\n type: \"module\",\r\n message: `找不到模块: ${importPath}`,\r\n file: file,\r\n code: code,\r\n });\r\n }\r\n }\r\n }\r\n } catch (err: any) {\r\n console.warn(`⚠️ 无法读取文件 ${file}: ${err.message}`);\r\n }\r\n }\r\n\r\n if (buildErrors.length > 0) {\r\n console.log(`⚠️ 扫描发现 ${buildErrors.length} 个潜在问题`);\r\n } else {\r\n console.log(\"✅ 文件扫描完成,未发现明显问题\");\r\n }\r\n } catch (err: any) {\r\n console.error(`❌ 文件扫描失败: ${err.message}`);\r\n }\r\n },\r\n\r\n // 解析模块时捕获错误\r\n async resolveId(source, importer, options) {\r\n // 不要在这里 try-catch,让错误自然传播到 buildEnd\r\n return null;\r\n },\r\n\r\n // 加载模块时捕获错误\r\n async load(id) {\r\n // 不要在这里 try-catch,让错误自然传播到 buildEnd\r\n return null;\r\n },\r\n\r\n // Rollup 钩子:模块解析完成后调用\r\n moduleParsed(moduleInfo) {\r\n // 检查模块是否有导入错误\r\n if (moduleInfo.meta && moduleInfo.meta.error) {\r\n console.log(\"\\n⚠️ moduleParsed 检测到错误:\", moduleInfo.id);\r\n\r\n let code = undefined;\r\n if (moduleInfo.id && fs.existsSync(moduleInfo.id)) {\r\n code = fs.readFileSync(moduleInfo.id, \"utf-8\");\r\n }\r\n\r\n const errorInfo = {\r\n type: \"module\",\r\n message: moduleInfo.meta.error,\r\n stack: \"\",\r\n file: moduleInfo.id,\r\n code: code,\r\n };\r\n\r\n buildErrors.push(errorInfo);\r\n }\r\n },\r\n\r\n buildEnd(error?: Error) {\r\n console.log(\"🔍 [调试] buildEnd 已执行, 有错误:\", !!error);\r\n\r\n if (error) {\r\n console.log(\"\\n⚠️ buildEnd 捕获到错误:\", error.message);\r\n\r\n const realFilePath = extractSourceFile(error, lastTransformFile);\r\n\r\n let code = undefined;\r\n if (realFilePath && fs.existsSync(realFilePath)) {\r\n try {\r\n code = fs.readFileSync(realFilePath, \"utf-8\");\r\n console.log(`📂 读取源文件成功: ${realFilePath}`);\r\n console.log(`📄 源文件长度: ${code.length} 字符`);\r\n } catch (e) {\r\n console.warn(\"⚠️ 无法读取文件:\", realFilePath);\r\n }\r\n }\r\n\r\n const errorInfo = {\r\n type: \"build\",\r\n message: error.message,\r\n stack: error.stack,\r\n file: realFilePath,\r\n code: code,\r\n };\r\n\r\n buildErrors.push(errorInfo);\r\n }\r\n },\r\n\r\n // Rollup 输出生成阶段的钩子\r\n renderStart(outputOptions, inputOptions) {\r\n console.log(\"🔍 [调试] renderStart 已执行\");\r\n },\r\n\r\n renderError(error?: Error) {\r\n console.log(\"🔍 [调试] renderError 已执行\");\r\n if (!error) return;\r\n\r\n console.log(\"\\n⚠️ renderError 捕获到错误:\", error.message);\r\n\r\n const realFilePath = extractSourceFile(error, lastTransformFile);\r\n\r\n let code = undefined;\r\n if (realFilePath && fs.existsSync(realFilePath)) {\r\n try {\r\n code = fs.readFileSync(realFilePath, \"utf-8\");\r\n console.log(`📂 读取源文件成功: ${realFilePath}`);\r\n console.log(`📄 源文件长度: ${code.length} 字符`);\r\n } catch (e) {\r\n console.warn(\"⚠️ 无法读取文件:\", realFilePath);\r\n }\r\n }\r\n\r\n const errorInfo = {\r\n type: \"render\",\r\n message: error.message,\r\n stack: error.stack,\r\n file: realFilePath,\r\n code: code,\r\n };\r\n\r\n buildErrors.push(errorInfo);\r\n },\r\n\r\n // 监听所有阶段的错误\r\n watchChange(id, change) {\r\n console.log(\"🔍 [调试] watchChange:\", id);\r\n },\r\n\r\n async closeBundle() {\r\n if (buildErrors.length > 0) {\r\n console.log(\r\n `\\n🔍 [调试] closeBundle 检测到 ${buildErrors.length} 个错误\\n`,\r\n );\r\n\r\n // 处理所有收集到的错误(去重由 processError 函数处理)\r\n for (const error of buildErrors) {\r\n await processError(error);\r\n }\r\n\r\n // 统一生成合并报告\r\n if (diagnosticResults.length > 0) {\r\n console.log(\r\n `\\n📊 正在生成合并诊断报告 (${diagnosticResults.length} 个错误)...\\n`,\r\n );\r\n await DiagnosticReporter.generateMultiReport(\r\n diagnosticResults,\r\n output,\r\n );\r\n }\r\n } else {\r\n console.log(\"✨ 构建完成,未检测到错误\\n\");\r\n }\r\n },\r\n\r\n transform(code: string, id: string) {\r\n lastTransformFile = id;\r\n\r\n try {\r\n return null;\r\n } catch (error: any) {\r\n console.log(\"\\n⚠️ transform 捕获到错误:\", error.message);\r\n buildErrors.push({\r\n type: \"transform\",\r\n message: error.message,\r\n stack: error.stack,\r\n file: id,\r\n code: code,\r\n });\r\n throw error;\r\n }\r\n },\r\n };\r\n}\r\n\r\n// 默认导出\r\nexport default vitePluginAIDiagnostic;\r\n","/**\r\n * LangGraph 工作流实现\r\n */\r\n\r\nimport { StateGraph, END, START } from \"@langchain/langgraph\";\r\nimport { ChatOpenAI } from \"@langchain/openai\";\r\nimport { HumanMessage, SystemMessage } from \"@langchain/core/messages\";\r\n\r\nexport interface DiagnosticState {\r\n error: any;\r\n analysis: string;\r\n suggestion: string;\r\n fixedCode: string;\r\n filePath: string;\r\n autoFix: boolean;\r\n retryCount: number;\r\n messages: any[];\r\n}\r\n\r\nexport class DiagnosticGraph {\r\n private llm: ChatOpenAI;\r\n private graph: any;\r\n private maxRetries: number;\r\n\r\n constructor(\r\n apiKey: string,\r\n apiUrl: string,\r\n model: string = \"gpt-4\",\r\n maxRetries: number = 3,\r\n temperature: number = 0.1,\r\n maxTokens: number = 4000,\r\n ) {\r\n this.maxRetries = maxRetries;\r\n\r\n console.log(\"🔧 [LangGraph] 初始化 LLM...\");\r\n console.log(\"📝 [配置] 模型:\", model);\r\n console.log(\"📝 [配置] API URL:\", apiUrl);\r\n console.log(\"📝 [配置] API Key:\", apiKey ? \"已配置\" : \"未配置\");\r\n\r\n this.llm = new ChatOpenAI({\r\n openAIApiKey: apiKey,\r\n configuration: {\r\n baseURL: apiUrl,\r\n },\r\n modelName: model,\r\n temperature,\r\n maxTokens,\r\n });\r\n\r\n this.graph = this.buildGraph();\r\n }\r\n\r\n private buildGraph() {\r\n const workflow = new StateGraph<DiagnosticState>({\r\n channels: {\r\n error: null,\r\n analysis: null,\r\n suggestion: null,\r\n fixedCode: null,\r\n filePath: null,\r\n autoFix: null,\r\n retryCount: null,\r\n messages: null,\r\n },\r\n });\r\n\r\n workflow.addNode(\"analyze\", this.analyzeNode.bind(this));\r\n workflow.addNode(\"suggest\", this.suggestNode.bind(this));\r\n // 自动修复节点已注释(功能不够稳定)\r\n // workflow.addNode(\"fix\", this.fixNode.bind(this));\r\n // workflow.addNode(\"validate\", this.validateNode.bind(this));\r\n\r\n workflow.addEdge(START, \"analyze\");\r\n workflow.addEdge(\"analyze\", \"suggest\");\r\n // 直接结束,不再进行自动修复\r\n workflow.addEdge(\"suggest\", END);\r\n\r\n // 自动修复流程已注释\r\n // workflow.addConditionalEdges(\"suggest\", this.shouldFix.bind(this), {\r\n // fix: \"fix\",\r\n // end: END,\r\n // });\r\n // workflow.addEdge(\"fix\", \"validate\");\r\n // workflow.addConditionalEdges(\"validate\", this.shouldRetry.bind(this), {\r\n // retry: \"analyze\",\r\n // end: END,\r\n // });\r\n\r\n return workflow.compile();\r\n }\r\n\r\n private async analyzeNode(\r\n state: DiagnosticState,\r\n ): Promise<Partial<DiagnosticState>> {\r\n console.log(\"🔍 [LangGraph] 正在分析错误...\");\r\n\r\n const systemPrompt = new SystemMessage(\r\n \"你是一个专业的前端代码诊断专家,精通 Vue3、TypeScript、Vite 和 uni-app。请简洁明了地分析问题。\",\r\n );\r\n\r\n const userPrompt = new HumanMessage(`\r\n请分析以下构建错误:\r\n\r\n错误类型: ${state.error.type}\r\n错误信息: ${state.error.message}\r\n文件路径: ${state.error.file || \"未知\"}\r\n\r\n请简洁地说明(3-5句话):\r\n1. 错误的根本原因\r\n2. 影响范围\r\n3. 严重程度\r\n`);\r\n\r\n const response = await this.llm.invoke([systemPrompt, userPrompt]);\r\n const analysis = response.content.toString();\r\n\r\n return {\r\n analysis,\r\n messages: [...(state.messages || []), systemPrompt, userPrompt, response],\r\n };\r\n }\r\n\r\n private async suggestNode(\r\n state: DiagnosticState,\r\n ): Promise<Partial<DiagnosticState>> {\r\n console.log(\"💡 [LangGraph] 正在生成修复建议...\");\r\n\r\n // 提取错误相关的代码片段\r\n let codeContext = \"\";\r\n if (state.error.code && state.error.message) {\r\n // 尝试从错误信息中提取行号\r\n const lineMatch = state.error.message.match(/\\((\\d+):(\\d+)\\)/);\r\n if (lineMatch) {\r\n const errorLine = parseInt(lineMatch[1]);\r\n const lines = state.error.code.split(\"\\n\");\r\n\r\n // 提取错误行前后各5行作为上下文\r\n const startLine = Math.max(0, errorLine - 6);\r\n const endLine = Math.min(lines.length, errorLine + 4);\r\n const contextLines = lines.slice(startLine, endLine);\r\n\r\n codeContext = `\r\n相关代码片段(第 ${startLine + 1}-${endLine} 行):\r\n\\`\\`\\`\r\n${contextLines\r\n .map((line, idx) => {\r\n const lineNum = startLine + idx + 1;\r\n const marker = lineNum === errorLine ? \" ← 错误位置\" : \"\";\r\n return `${lineNum}: ${line}${marker}`;\r\n })\r\n .join(\"\\n\")}\r\n\\`\\`\\`\r\n`;\r\n } else if (state.error.code.length < 2000) {\r\n // 如果代码不长,显示完整代码\r\n codeContext = `\r\n完整代码:\r\n\\`\\`\\`\r\n${state.error.code}\r\n\\`\\`\\`\r\n`;\r\n }\r\n }\r\n\r\n const userPrompt = new HumanMessage(`\r\n基于以下错误分析,请提供具体的修复建议:\r\n\r\n错误分析:\r\n${state.analysis}\r\n\r\n错误详情:\r\n- 类型: ${state.error.type}\r\n- 信息: ${state.error.message}\r\n- 文件: ${state.error.file || \"未知\"}\r\n\r\n${codeContext}\r\n\r\n请提供精确的修复建议,格式如下:\r\n\r\n1. 修复步骤:\r\n 1. [具体步骤1]\r\n 2. [具体步骤2]\r\n 3. [具体步骤3]\r\n\r\n2. 需要修改的代码位置: [文件名] 的第 [X] 行\r\n\r\n3. 修改后的代码示例:\r\n \\`\\`\\`[语言]\r\n [只显示需要修改的那几行代码,保持原有缩进]\r\n \\`\\`\\`\r\n\r\n4. 预防建议: [一句话说明如何避免类似错误]\r\n\r\n注意:\r\n- 代码示例必须基于实际的源代码,保持正确的语法和缩进\r\n- 只显示需要修改的关键代码行,不要显示整个文件\r\n- 确保修改后的代码可以直接使用\r\n`);\r\n\r\n const response = await this.llm.invoke([...state.messages, userPrompt]);\r\n const suggestion = response.content.toString();\r\n\r\n return {\r\n suggestion,\r\n messages: [...state.messages, userPrompt, response],\r\n };\r\n }\r\n\r\n // 自动修复节点已注释(功能不够稳定)\r\n // private async fixNode(\r\n // state: DiagnosticState\r\n // ): Promise<Partial<DiagnosticState>> {\r\n // console.log(\"🔧 [LangGraph] 正在生成修复代码...\");\r\n\r\n // if (!state.error.code || !state.error.file) {\r\n // return { fixedCode: \"\", filePath: \"\" };\r\n // }\r\n\r\n // try {\r\n // const systemPrompt = new SystemMessage(\r\n // `你是代码修复助手。返回修复后的完整文件内容,不要解释。`\r\n // );\r\n\r\n // const userPrompt = new HumanMessage(`\r\n // 文件(${state.error.code.split(\"\\n\").length} 行):\r\n // ${state.error.code}\r\n\r\n // 错误:${state.error.message}\r\n\r\n // 输出修复后的完整文件:\r\n // `);\r\n\r\n // console.log(\"📤 [调试] 发送修复请求...\");\r\n // console.log(\r\n // \"📤 [调试] 原始文件行数:\",\r\n // state.error.code.split(\"\\n\").length\r\n // );\r\n\r\n // const response = await this.llm.invoke([systemPrompt, userPrompt]);\r\n // let fixedCode = response.content.toString().trim();\r\n\r\n // console.log(\"📥 [调试] AI 返回内容长度:\", fixedCode.length);\r\n // console.log(\"📥 [调试] 原始代码长度:\", state.error.code.length);\r\n // console.log(\"📥 [调试] 返回内容行数:\", fixedCode.split(\"\\n\").length);\r\n\r\n // if (fixedCode.length === 0) {\r\n // console.error(\"❌ [调试] AI 返回空内容,可能是 API 调用失败\");\r\n // return { fixedCode: \"\", filePath: \"\" };\r\n // }\r\n\r\n // fixedCode = fixedCode\r\n // .replace(/^```[\\w]*\\n?/gm, \"\")\r\n // .replace(/\\n?```$/gm, \"\")\r\n // .trim();\r\n\r\n // console.log(\"📥 [调试] 清理后内容长度:\", fixedCode.length);\r\n\r\n // const finalLengthRatio = fixedCode.length / state.error.code.length;\r\n // console.log(\r\n // `✅ [调试] 最终代码长度比例: ${(finalLengthRatio * 100).toFixed(0)}%`\r\n // );\r\n\r\n // return {\r\n // fixedCode,\r\n // filePath: state.error.file,\r\n // messages: [...state.messages, userPrompt, response],\r\n // };\r\n // } catch (error: any) {\r\n // console.error(\"❌ [调试] fixNode 执行失败:\", error.message);\r\n // return { fixedCode: \"\", filePath: \"\" };\r\n // }\r\n // }\r\n\r\n // private async validateNode(\r\n // state: DiagnosticState\r\n // ): Promise<Partial<DiagnosticState>> {\r\n // console.log(\"✅ [LangGraph] 正在验证修复...\");\r\n // return state;\r\n // }\r\n\r\n // private shouldFix(state: DiagnosticState): string {\r\n // if (state.autoFix && state.error.file && state.error.code) {\r\n // return \"fix\";\r\n // }\r\n // return \"end\";\r\n // }\r\n\r\n // private shouldRetry(state: DiagnosticState): string {\r\n // if (state.retryCount < this.maxRetries && !state.fixedCode) {\r\n // return \"retry\";\r\n // }\r\n // return \"end\";\r\n // }\r\n\r\n async run(error: any, autoFix: boolean = false): Promise<DiagnosticState> {\r\n const initialState: DiagnosticState = {\r\n error,\r\n analysis: \"\",\r\n suggestion: \"\",\r\n fixedCode: \"\",\r\n filePath: \"\",\r\n autoFix,\r\n retryCount: 0,\r\n messages: [],\r\n };\r\n\r\n try {\r\n console.log(\"🚀 [LangGraph] 启动诊断工作流...\\n\");\r\n const result = await this.graph.invoke(initialState);\r\n console.log(\"✨ [LangGraph] 诊断工作流完成\\n\");\r\n return result;\r\n } catch (error: any) {\r\n console.error(\"❌ [LangGraph] 工作流执行失败:\", error.message);\r\n throw error;\r\n }\r\n }\r\n}\r\n","/**\r\n * AI 诊断核心逻辑\r\n */\r\n\r\nimport fs from \"fs\";\r\nimport { DiagnosticGraph } from \"./langgraph\";\r\nimport { CodeValidator } from \"./validator\";\r\n\r\nexport interface DiagnosticOptions {\r\n apiKey: string;\r\n apiUrl: string;\r\n model: string;\r\n maxRetries: number;\r\n temperature?: number;\r\n maxTokens?: number;\r\n}\r\n\r\nexport interface DiagnosticResult {\r\n analysis: string;\r\n suggestion: string;\r\n fixedCode?: string;\r\n filePath?: string;\r\n}\r\n\r\nexport class AIErrorDiagnostic {\r\n private options: DiagnosticOptions;\r\n private graph: DiagnosticGraph;\r\n\r\n constructor(options: DiagnosticOptions) {\r\n this.options = options;\r\n\r\n this.graph = new DiagnosticGraph(\r\n options.apiKey,\r\n options.apiUrl,\r\n options.model,\r\n options.maxRetries,\r\n options.temperature,\r\n options.maxTokens,\r\n );\r\n }\r\n\r\n async diagnose(\r\n error: any,\r\n autoFix: boolean = false,\r\n ): Promise<DiagnosticResult> {\r\n if (!this.options.apiKey) {\r\n return {\r\n analysis: \"未配置 API Key,无法使用 AI 诊断功能\",\r\n suggestion: \"请在 .env 文件中配置 OPENAI_API_KEY\",\r\n fixedCode: undefined,\r\n filePath: undefined,\r\n };\r\n }\r\n\r\n try {\r\n // 注意:自动修复功能已暂时禁用,因为不够稳定\r\n // 强制设置 autoFix 为 false\r\n const result = await this.graph.run(error, false);\r\n\r\n // 自动修复功能已注释(不够稳定)\r\n // if (autoFix && result.fixedCode && result.filePath) {\r\n // console.log(\"\\n🔍 [验证] 正在验证修复后的代码...\");\r\n\r\n // const validation = CodeValidator.validateFix(\r\n // error.code,\r\n // result.fixedCode\r\n // );\r\n\r\n // if (!validation.valid) {\r\n // console.warn(`⚠️ [验证失败] ${validation.reason}`);\r\n // console.log(\"📝 [提示] 将只提供修复建议,不自动应用修复\\n\");\r\n\r\n // return {\r\n // analysis: result.analysis,\r\n // suggestion:\r\n // result.suggestion +\r\n // \"\\n\\n⚠️ 自动修复验证失败:\" +\r\n // validation.reason,\r\n // fixedCode: undefined,\r\n // filePath: undefined,\r\n // };\r\n // }\r\n\r\n // console.log(\"✅ [验证通过] 代码验证成功\\n\");\r\n // this.applyFix(result.filePath, result.fixedCode);\r\n // }\r\n\r\n return {\r\n analysis: result.analysis,\r\n suggestion: result.suggestion,\r\n fixedCode: undefined, // 暂时不返回修复代码\r\n filePath: undefined,\r\n };\r\n } catch (error: any) {\r\n console.error(\"❌ AI 诊断失败:\", error.message);\r\n return {\r\n analysis: `诊断过程出错: ${error.message}`,\r\n suggestion: \"请检查 API 配置和网络连接\",\r\n fixedCode: undefined,\r\n filePath: undefined,\r\n };\r\n }\r\n }\r\n\r\n // 自动修复功能已注释(不够稳定)\r\n // private applyFix(filePath: string, fixedCode: string): void {\r\n // try {\r\n // const backupPath = `${filePath}.backup`;\r\n // if (fs.existsSync(filePath)) {\r\n // fs.copyFileSync(filePath, backupPath);\r\n // console.log(`📦 [备份] 已创建备份: ${backupPath}`);\r\n // }\r\n\r\n // fs.writeFileSync(filePath, fixedCode, \"utf-8\");\r\n // console.log(`✅ [修复] 已修复文件: ${filePath}`);\r\n // console.log(`💡 [提示] 如需恢复,运行: cp \"${backupPath}\" \"${filePath}\"`);\r\n // } catch (error: any) {\r\n // console.error(`❌ [修复失败] ${error.message}`);\r\n // }\r\n // }\r\n}\r\n","/**\r\n * AI 诊断报告生成器\r\n */\r\n\r\nimport fs from \"fs\";\r\nimport path from \"path\";\r\n\r\nexport interface DiagnosticReport {\r\n timestamp: string;\r\n error: {\r\n type: string;\r\n message: string;\r\n file: string;\r\n stack?: string;\r\n };\r\n analysis: string;\r\n suggestion: string;\r\n fixed: boolean;\r\n fixedFilePath?: string;\r\n}\r\n\r\nexport interface MultiDiagnosticReport {\r\n timestamp: string;\r\n totalErrors: number;\r\n errors: DiagnosticReport[];\r\n}\r\n\r\nexport interface ReporterOptions {\r\n console?: boolean;\r\n html?: boolean;\r\n markdown?: boolean;\r\n json?: boolean;\r\n}\r\n\r\nexport class DiagnosticReporter {\r\n /**\r\n * 生成报告(根据配置生成多种格式)\r\n */\r\n static async generate(\r\n report: DiagnosticReport,\r\n options: ReporterOptions = {},\r\n ): Promise<void> {\r\n // HTML 报告\r\n if (options.html) {\r\n await this.generateHTMLReport(report);\r\n }\r\n\r\n // Markdown 报告\r\n if (options.markdown) {\r\n await this.generateMarkdownReport(report);\r\n }\r\n\r\n // JSON 报告\r\n if (options.json) {\r\n await this.generateJSONReport(report);\r\n }\r\n }\r\n\r\n /**\r\n * 生成 HTML 报告\r\n */\r\n static async generateHTMLReport(report: DiagnosticReport): Promise<void> {\r\n const html = `\r\n<!DOCTYPE html>\r\n<html lang=\"zh-CN\">\r\n<head>\r\n <meta charset=\"UTF-8\">\r\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n <title>AI 诊断报告</title>\r\n <style>\r\n * { margin: 0; padding: 0; box-sizing: border-box; }\r\n body {\r\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\r\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\r\n padding: 20px;\r\n min-height: 100vh;\r\n }\r\n .container {\r\n max-width: 1000px;\r\n margin: 0 auto;\r\n background: white;\r\n border-radius: 12px;\r\n box-shadow: 0 8px 32px rgba(0,0,0,0.2);\r\n overflow: hidden;\r\n }\r\n .header {\r\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\r\n color: white;\r\n padding: 30px;\r\n text-align: center;\r\n }\r\n .header h1 {\r\n font-size: 32px;\r\n margin-bottom: 10px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 10px;\r\n }\r\n .header .time {\r\n font-size: 14px;\r\n opacity: 0.9;\r\n }\r\n .content {\r\n padding: 30px;\r\n }\r\n .section {\r\n margin-bottom: 30px;\r\n }\r\n .section-title {\r\n font-size: 20px;\r\n font-weight: bold;\r\n color: #333;\r\n margin-bottom: 15px;\r\n padding-bottom: 10px;\r\n border-bottom: 2px solid #667eea;\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n }\r\n .error-box {\r\n background: #fff5f5;\r\n border-left: 4px solid #f56565;\r\n padding: 20px;\r\n border-radius: 8px;\r\n margin-bottom: 20px;\r\n }\r\n .error-type {\r\n display: inline-block;\r\n background: #f56565;\r\n color: white;\r\n padding: 4px 12px;\r\n border-radius: 12px;\r\n font-size: 12px;\r\n font-weight: bold;\r\n margin-bottom: 10px;\r\n }\r\n .error-message {\r\n font-size: 16px;\r\n color: #c53030;\r\n font-weight: 500;\r\n margin-bottom: 10px;\r\n line-height: 1.6;\r\n }\r\n .error-file {\r\n font-size: 14px;\r\n color: #666;\r\n font-family: 'Courier New', monospace;\r\n background: #f7fafc;\r\n padding: 8px 12px;\r\n border-radius: 4px;\r\n display: inline-block;\r\n }\r\n .analysis-box {\r\n background: #f0f9ff;\r\n border-left: 4px solid #3b82f6;\r\n padding: 20px;\r\n border-radius: 8px;\r\n line-height: 1.8;\r\n color: #1e40af;\r\n }\r\n .suggestion-box {\r\n background: #f0fdf4;\r\n border-left: 4px solid #10b981;\r\n padding: 20px;\r\n border-radius: 8px;\r\n line-height: 1.8;\r\n color: #065f46;\r\n }\r\n .suggestion-box pre {\r\n background: #1e293b;\r\n color: #e2e8f0;\r\n padding: 15px;\r\n border-radius: 6px;\r\n overflow-x: auto;\r\n margin: 10px 0;\r\n font-size: 14px;\r\n line-height: 1.5;\r\n }\r\n .fixed-badge {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 6px;\r\n background: #10b981;\r\n color: white;\r\n padding: 8px 16px;\r\n border-radius: 20px;\r\n font-size: 14px;\r\n font-weight: bold;\r\n }\r\n .not-fixed-badge {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 6px;\r\n background: #f59e0b;\r\n color: white;\r\n padding: 8px 16px;\r\n border-radius: 20px;\r\n font-size: 14px;\r\n font-weight: bold;\r\n }\r\n .footer {\r\n background: #f7fafc;\r\n padding: 20px;\r\n text-align: center;\r\n color: #718096;\r\n font-size: 14px;\r\n border-top: 1px solid #e2e8f0;\r\n }\r\n .stack-trace {\r\n background: #1e293b;\r\n color: #e2e8f0;\r\n padding: 15px;\r\n border-radius: 6px;\r\n overflow-x: auto;\r\n font-family: 'Courier New', monospace;\r\n font-size: 12px;\r\n line-height: 1.5;\r\n margin-top: 10px;\r\n max-height: 300px;\r\n overflow-y: auto;\r\n }\r\n </style>\r\n</head>\r\n<body>\r\n <div class=\"container\">\r\n <div class=\"header\">\r\n <h1>🤖 AI 诊断报告</h1>\r\n <div class=\"time\">生成时间: ${report.timestamp}</div>\r\n </div>\r\n\r\n <div class=\"content\">\r\n <!-- 错误信息 -->\r\n <div class=\"section\">\r\n <div class=\"section-title\">❌ 错误信息</div>\r\n <div class=\"error-box\">\r\n <span class=\"error-type\">${report.error.type}</span>\r\n <div class=\"error-message\">${this.escapeHtml(\r\n report.error.message,\r\n )}</div>\r\n <div class=\"error-file\">📂 ${report.error.file}</div>\r\n ${\r\n report.error.stack\r\n ? `<div class=\"stack-trace\">${this.escapeHtml(\r\n report.error.stack,\r\n )}</div>`\r\n : \"\"\r\n }\r\n </div>\r\n </div>\r\n\r\n <!-- AI 分析 -->\r\n <div class=\"section\">\r\n <div class=\"section-title\">🔍 AI 分析</div>\r\n <div class=\"analysis-box\">\r\n ${this.formatText(report.analysis)}\r\n </div>\r\n </div>\r\n\r\n <!-- 修复建议 -->\r\n <div class=\"section\">\r\n <div class=\"section-title\">💡 修复建议</div>\r\n <div class=\"suggestion-box\">\r\n ${this.formatText(report.suggestion)}\r\n </div>\r\n </div>\r\n\r\n <!-- 修复状态 -->\r\n <div class=\"section\">\r\n <div class=\"section-title\">🔧 修复状态</div>\r\n ${\r\n report.fixed\r\n ? `<div class=\"fixed-badge\">✅ 已自动修复</div>\r\n <div style=\"margin-top: 10px; color: #666;\">修复文件: <code>${report.fixedFilePath}</code></div>`\r\n : `<div class=\"not-fixed-badge\">⚠️ 未自动修复</div>\r\n <div style=\"margin-top: 10px; color: #666;\">请根据上述建议手动修复</div>`\r\n }\r\n </div>\r\n </div>\r\n\r\n <div class=\"footer\">\r\n <p>AI Diagnostic Plugin v1.0.0</p>\r\n <p>Powered by LangGraph & OpenAI</p>\r\n </div>\r\n </div>\r\n</body>\r\n</html>\r\n `.trim();\r\n\r\n // 创建报告目录\r\n const reportsDir = path.resolve(process.cwd(), \"ai-reports\");\r\n if (!fs.existsSync(reportsDir)) {\r\n fs.mkdirSync(reportsDir, { recursive: true });\r\n }\r\n\r\n const reportPath = path.resolve(reportsDir, \"diagnostic-report.html\");\r\n fs.writeFileSync(reportPath, html, \"utf-8\");\r\n console.log(`\\n📄 诊断报告已生成: ${reportPath}\\n`);\r\n }\r\n\r\n /**\r\n * 转义 HTML 特殊字符\r\n */\r\n private static escapeHtml(text: string): string {\r\n const map: Record<string, string> = {\r\n \"&\": \"&\",\r\n \"<\": \"<\",\r\n \">\": \">\",\r\n '\"': \""\",\r\n \"'\": \"'\",\r\n };\r\n return text.replace(/[&<>\"']/g, (m) => map[m]);\r\n }\r\n\r\n /**\r\n * 格式化文本(支持代码块和换行)\r\n */\r\n private static formatText(text: string): string {\r\n // 转义 HTML\r\n let formatted = this.escapeHtml(text);\r\n\r\n // 处理代码块\r\n formatted = formatted.replace(\r\n /```(\\w*)\\n([\\s\\S]*?)```/g,\r\n (_, lang, code) => {\r\n return `<pre><code>${code.trim()}</code></pre>`;\r\n },\r\n );\r\n\r\n // 处理行内代码\r\n formatted = formatted.replace(\r\n /`([^`]+)`/g,\r\n '<code style=\"background: #e2e8f0; padding: 2px 6px; border-radius: 3px; font-family: monospace;\">$1</code>',\r\n );\r\n\r\n // 处理换行\r\n formatted = formatted.replace(/\\n/g, \"<br>\");\r\n\r\n return formatted;\r\n }\r\n\r\n /**\r\n * 生成 Markdown 报告\r\n */\r\n static async generateMarkdownReport(report: DiagnosticReport): Promise<void> {\r\n const markdown = `# 🤖 AI 诊断报告\r\n\r\n**生成时间**: ${report.timestamp}\r\n\r\n---\r\n\r\n## ❌ 错误信息\r\n\r\n**类型**: \\`${report.error.type}\\` \r\n**文件**: \\`${report.error.file}\\` \r\n**消息**: \r\n\\`\\`\\`\r\n${report.error.message}\r\n\\`\\`\\`\r\n\r\n${\r\n report.error.stack\r\n ? `**堆栈跟踪**:\\n\\`\\`\\`\\n${report.error.stack}\\n\\`\\`\\`\\n`\r\n : \"\"\r\n}\r\n\r\n---\r\n\r\n## 🔍 AI 分析\r\n\r\n${report.analysis}\r\n\r\n---\r\n\r\n## 💡 修复建议\r\n\r\n${report.suggestion}\r\n\r\n---\r\n\r\n## 🔧 修复状态\r\n\r\n${\r\n report.fixed\r\n ? `✅ **已自动修复**\\n\\n修复文件: \\`${report.fixedFilePath}\\``\r\n : `⚠️ **未自动修复**\\n\\n请根据上述建议手动修复`\r\n}\r\n\r\n---\r\n\r\n*AI Diagnostic Plugin v1.0.0* \r\n*Powered by LangGraph & OpenAI*\r\n`;\r\n\r\n // 创建报告目录\r\n const reportsDir = path.resolve(process.cwd(), \"ai-reports\");\r\n if (!fs.existsSync(reportsDir)) {\r\n fs.mkdirSync(reportsDir, { recursive: true });\r\n }\r\n\r\n const reportPath = path.resolve(reportsDir, \"diagnostic-report.md\");\r\n fs.writeFileSync(reportPath, markdown, \"utf-8\");\r\n console.log(`📄 Markdown 报告已生成: ${reportPath}`);\r\n }\r\n\r\n /**\r\n * 生成 JSON 报告\r\n */\r\n static async generateJSONReport(report: DiagnosticReport): Promise<void> {\r\n const jsonReport = {\r\n version: \"1.0.0\",\r\n timestamp: report.timestamp,\r\n error: {\r\n type: report.error.type,\r\n message: report.error.message,\r\n file: report.error.file,\r\n stack: report.error.stack || null,\r\n },\r\n diagnosis: {\r\n analysis: report.analysis,\r\n suggestion: report.suggestion,\r\n },\r\n fix: {\r\n applied: report.fixed,\r\n filePath: report.fixedFilePath || null,\r\n },\r\n };\r\n\r\n // 创建报告目录\r\n const reportsDir = path.resolve(process.cwd(), \"ai-reports\");\r\n if (!fs.existsSync(reportsDir)) {\r\n fs.mkdirSync(reportsDir, { recursive: true });\r\n }\r\n\r\n const reportPath = path.resolve(reportsDir, \"diagnostic-report.json\");\r\n fs.writeFileSync(reportPath, JSON.stringify(jsonReport, null, 2), \"utf-8\");\r\n console.log(`📄 JSON 报告已生成: ${reportPath}`);\r\n }\r\n\r\n /**\r\n * 生成多错误合并报告\r\n */\r\n static async generateMultiReport(\r\n reports: DiagnosticReport[],\r\n options: ReporterOptions = {},\r\n ): Promise<void> {\r\n const multiReport: MultiDiagnosticReport = {\r\n timestamp: new Date().toLocaleString(\"zh-CN\"),\r\n totalErrors: reports.length,\r\n errors: reports,\r\n };\r\n\r\n // HTML 报告\r\n if (options.html) {\r\n await this.generateMultiHTMLReport(multiReport);\r\n }\r\n\r\n // Markdown 报告\r\n if (options.markdown) {\r\n await this.generateMultiMarkdownReport(multiReport);\r\n }\r\n\r\n // JSON 报告\r\n if (options.json) {\r\n await this.generateMultiJSONReport(multiReport);\r\n }\r\n }\r\n\r\n /**\r\n * 生成多错误 HTML 报告\r\n */\r\n static async generateMultiHTMLReport(\r\n report: MultiDiagnosticReport,\r\n ): Promise<void> {\r\n const errorsHtml = report.errors\r\n .map(\r\n (error, index) => `\r\n <div class=\"error-item\">\r\n <div class=\"error-number\">错误 ${index + 1} / ${\r\n report.totalErrors\r\n }</div>\r\n <div class=\"error-box\">\r\n <span class=\"error-type\">${error.error.type}</span>\r\n <div class=\"error-message\">${this.escapeHtml(\r\n error.error.message,\r\n )}</div>\r\n <div class=\"error-file\">📂 ${error.error.file}</div>\r\n ${\r\n error.error.stack\r\n ? `<div class=\"stack-trace\">${this.escapeHtml(\r\n error.error.stack,\r\n )}</div>`\r\n : \"\"\r\n }\r\n </div>\r\n\r\n <div class=\"section\">\r\n <div class=\"section-title\">🔍 AI 分析</div>\r\n <div class=\"analysis-box\">\r\n ${this.formatText(error.analysis)}\r\n </div>\r\n </div>\r\n\r\n <div class=\"section\">\r\n <div class=\"section-title\">💡 修复建议</div>\r\n <div class=\"suggestion-box\">\r\n ${this.formatText(error.suggestion)}\r\n </div>\r\n </div>\r\n\r\n <div class=\"section\">\r\n <div class=\"section-title\">🔧 修复状态</div>\r\n ${\r\n error.fixed\r\n ? `<div class=\"fixed-badge\">✅ 已自动修复</div>\r\n <div style=\"margin-top: 10px; color: #666;\">修复文件: <code>${error.fixedFilePath}</code></div>`\r\n : `<div class=\"not-fixed-badge\">⚠️ 未自动修复</div>\r\n <div style=\"margin-top: 10px; color: #666;\">请根据上述建议手动修复</div>`\r\n }\r\n </div>\r\n </div>\r\n `,\r\n )\r\n .join(\"\");\r\n\r\n const html = `\r\n<!DOCTYPE html>\r\n<html lang=\"zh-CN\">\r\n<head>\r\n <meta charset=\"UTF-8\">\r\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n <title>AI 诊断报告 - ${report.totalErrors} 个错误</title>\r\n <style>\r\n * { margin: 0; padding: 0; box-sizing: border-box; }\r\n body {\r\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\r\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\r\n padding: 20px;\r\n min-height: 100vh;\r\n }\r\n .container {\r\n max-width: 1000px;\r\n margin: 0 auto;\r\n background: white;\r\n border-radius: 12px;\r\n box-shadow: 0 8px 32px rgba(0,0,0,0.2);\r\n overflow: hidden;\r\n }\r\n .header {\r\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\r\n color: white;\r\n padding: 30px;\r\n text-align: center;\r\n }\r\n .header h1 {\r\n font-size: 32px;\r\n margin-bottom: 10px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 10px;\r\n }\r\n .header .time {\r\n font-size: 14px;\r\n opacity: 0.9;\r\n }\r\n .header .error-count {\r\n font-size: 18px;\r\n margin-top: 10px;\r\n background: rgba(255,255,255,0.2);\r\n padding: 8px 16px;\r\n border-radius: 20px;\r\n display: inline-block;\r\n }\r\n .content {\r\n padding: 30px;\r\n }\r\n .error-item {\r\n margin-bottom: 40px;\r\n padding-bottom: 40px;\r\n border-bottom: 2px dashed #e2e8f0;\r\n }\r\n .error-item:last-child {\r\n border-bottom: none;\r\n margin-bottom: 0;\r\n padding-bottom: 0;\r\n }\r\n .error-number {\r\n font-size: 16px;\r\n font-weight: bold;\r\n color: #667eea;\r\n margin-bottom: 15px;\r\n padding: 8px 16px;\r\n background: #f0f9ff;\r\n border-radius: 8px;\r\n display: inline-block;\r\n }\r\n .section {\r\n margin-bottom: 20px;\r\n }\r\n .section-title {\r\n font-size: 18px;\r\n font-weight: bold;\r\n color: #333;\r\n margin-bottom: 12px;\r\n padding-bottom: 8px;\r\n border-bottom: 2px solid #667eea;\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n }\r\n .error-box {\r\n background: #fff5f5;\r\n border-left: 4px solid #f56565;\r\n padding: 20px;\r\n border-radius: 8px;\r\n margin-bottom: 20px;\r\n }\r\n .error-type {\r\n display: inline-block;\r\n background: #f56565;\r\n color: white;\r\n padding: 4px 12px;\r\n border-radius: 12px;\r\n font-size: 12px;\r\n font-weight: bold;\r\n margin-bottom: 10px;\r\n }\r\n .error-message {\r\n font-size: 16px;\r\n color: #c53030;\r\n font-weight: 500;\r\n margin-bottom: 10px;\r\n line-height: 1.6;\r\n }\r\n .error-file {\r\n font-size: 14px;\r\n color: #666;\r\n font-family: 'Courier New', monospace;\r\n background: #f7fafc;\r\n padding: 8px 12px;\r\n border-radius: 4px;\r\n display: inline-block;\r\n }\r\n .analysis-box {\r\n background: #f0f9ff;\r\n border-left: 4px solid #3b82f6;\r\n padding: 20px;\r\n border-radius: 8px;\r\n line-height: 1.8;\r\n color: #1e40af;\r\n }\r\n .suggestion-box {\r\n background: #f0fdf4;\r\n border-left: 4px solid #10b981;\r\n padding: 20px;\r\n border-radius: 8px;\r\n line-height: 1.8;\r\n color: #065f46;\r\n }\r\n .suggestion-box pre {\r\n background: #1e293b;\r\n color: #e2e8f0;\r\n padding: 15px;\r\n border-radius: 6px;\r\n overflow-x: auto;\r\n margin: 10px 0;\r\n font-size: 14px;\r\n line-height: 1.5;\r\n }\r\n .fixed-badge {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 6px;\r\n background: #10b981;\r\n color: white;\r\n padding: 8px 16px;\r\n border-radius: 20px;\r\n font-size: 14px;\r\n font-weight: bold;\r\n }\r\n .not-fixed-badge {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 6px;\r\n background: #f59e0b;\r\n color: white;\r\n padding: 8px 16px;\r\n border-radius: 20px;\r\n font-size: 14px;\r\n font-weight: bold;\r\n }\r\n .footer {\r\n background: #f7fafc;\r\n padding: 20px;\r\n text-align: center;\r\n color: #718096;\r\n font-size: 14px;\r\n border-top: 1px solid #e2e8f0;\r\n }\r\n .stack-trace {\r\n background: #1e293b;\r\n color: #e2e8f0;\r\n padding: 15px;\r\n border-radius: 6px;\r\n overflow-x: auto;\r\n font-family: 'Courier New', monospace;\r\n font-size: 12px;\r\n line-height: 1.5;\r\n margin-top: 10px;\r\n max-height: 300px;\r\n overflow-y: auto;\r\n }\r\n </style>\r\n</head>\r\n<body>\r\n <div class=\"container\">\r\n <div class=\"header\">\r\n <h1>🤖 AI 诊断报告</h1>\r\n <div class=\"time\">生成时间: ${report.timestamp}</div>\r\n <div class=\"error-count\">共发现 ${report.totalErrors} 个错误</div>\r\n </div>\r\n\r\n <div class=\"content\">\r\n ${errorsHtml}\r\n </div>\r\n\r\n <div class=\"footer\">\r\n <p>AI Diagnostic Plugin v1.0.7</p>\r\n <p>Powered by LangGraph & OpenAI</p>\r\n </div>\r\n </div>\r\n</body>\r\n</html>\r\n `.trim();\r\n\r\n // 创建报告目录\r\n const reportsDir = path.resolve(process.cwd(), \"ai-reports\");\r\n if (!fs.existsSync(reportsDir)) {\r\n fs.mkdirSync(reportsDir, { recursive: true });\r\n }\r\n\r\n const reportPath = path.resolve(reportsDir, \"diagnostic-report.html\");\r\n fs.writeFileSync(reportPath, html, \"utf-8\");\r\n console.log(\r\n `\\n📄 诊断报告已生成: ${reportPath} (${report.totalErrors} 个错误)\\n`,\r\n );\r\n }\r\n\r\n /**\r\n * 生成多错误 Markdown 报告\r\n */\r\n static async generateMultiMarkdownReport(\r\n report: MultiDiagnosticReport,\r\n ): Promise<void> {\r\n const errorsMarkdown = report.errors\r\n .map(\r\n (error, index) => `\r\n## 错误 ${index + 1} / ${report.totalErrors}\r\n\r\n### ❌ 错误信息\r\n\r\n**类型**: \\`${error.error.type}\\` \r\n**文件**: \\`${error.error.file}\\` \r\n**消息**: \r\n\\`\\`\\`\r\n${error.error.message}\r\n\\`\\`\\`\r\n\r\n${\r\n error.error.stack\r\n ? `**堆栈跟踪**:\\n\\`\\`\\`\\n${error.error.stack}\\n\\`\\`\\`\\n`\r\n : \"\"\r\n}\r\n\r\n### 🔍 AI 分析\r\n\r\n${error.analysis}\r\n\r\n### 💡 修复建议\r\n\r\n${error.suggestion}\r\n\r\n### 🔧 修复状态\r\n\r\n${\r\n error.fixed\r\n ? `✅ **已自动修复**\\n\\n修复文件: \\`${error.fixedFilePath}\\``\r\n : `⚠️ **未自动修复**\\n\\n请根据上述建议手动修复`\r\n}\r\n\r\n---\r\n`,\r\n )\r\n .join(\"\\n\");\r\n\r\n const markdown = `# 🤖 AI 诊断报告\r\n\r\n**生成时间**: ${report.timestamp} \r\n**错误总数**: ${report.totalErrors}\r\n\r\n---\r\n\r\n${errorsMarkdown}\r\n\r\n*AI Diagnostic Plugin v1.0.7* \r\n*Powered by LangGraph & OpenAI*\r\n`;\r\n\r\n // 创建报告目录\r\n const reportsDir = path.resolve(process.cwd(), \"ai-reports\");\r\n if (!fs.existsSync(reportsDir)) {\r\n fs.mkdirSync(reportsDir, { recursive: true });\r\n }\r\n\r\n const reportPath = path.resolve(reportsDir, \"diagnostic-report.md\");\r\n fs.writeFileSync(reportPath, markdown, \"utf-8\");\r\n console.log(`📄 Markdown 报告已生成: ${reportPath}`);\r\n }\r\n\r\n /**\r\n * 生成多错误 JSON 报告\r\n */\r\n static async generateMultiJSONReport(\r\n report: MultiDiagnosticReport,\r\n ): Promise<void> {\r\n const jsonReport = {\r\n version: \"1.0.7\",\r\n timestamp: report.timestamp,\r\n totalErrors: report.totalErrors,\r\n errors: report.errors.map((error) => ({\r\n error: {\r\n type: error.error.type,\r\n message: error.error.message,\r\n file: error.error.file,\r\n stack: error.error.stack || null,\r\n },\r\n diagnosis: {\r\n analysis: error.analysis,\r\n suggestion: error.suggestion,\r\n },\r\n fix: {\r\n applied: error.fixed,\r\n filePath: error.fixedFilePath || null,\r\n },\r\n })),\r\n };\r\n\r\n // 创建报告目录\r\n const reportsDir = path.resolve(process.cwd(), \"ai-reports\");\r\n if (!fs.existsSync(reportsDir)) {\r\n fs.mkdirSync(reportsDir, { recursive: true });\r\n }\r\n\r\n const reportPath = path.resolve(reportsDir, \"diagnostic-report.json\");\r\n fs.writeFileSync(reportPath, JSON.stringify(jsonReport, null, 2), \"utf-8\");\r\n console.log(`📄 JSON 报告已生成: ${reportPath}`);\r\n }\r\n}\r\n"],"mappings":"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","names":["import_fs","import_path","error","error","path","fs","path","fs","options"]}
|
package/dist/index.mjs
CHANGED
|
@@ -7,7 +7,7 @@ import { StateGraph, END, START } from "@langchain/langgraph";
|
|
|
7
7
|
import { ChatOpenAI } from "@langchain/openai";
|
|
8
8
|
import { HumanMessage, SystemMessage } from "@langchain/core/messages";
|
|
9
9
|
var DiagnosticGraph = class {
|
|
10
|
-
constructor(apiKey, apiUrl, model = "gpt-4", maxRetries = 3) {
|
|
10
|
+
constructor(apiKey, apiUrl, model = "gpt-4", maxRetries = 3, temperature = 0.1, maxTokens = 4e3) {
|
|
11
11
|
this.maxRetries = maxRetries;
|
|
12
12
|
console.log("🔧 [LangGraph] 初始化 LLM...");
|
|
13
13
|
console.log("📝 [配置] 模型:", model);
|
|
@@ -19,8 +19,8 @@ var DiagnosticGraph = class {
|
|
|
19
19
|
baseURL: apiUrl
|
|
20
20
|
},
|
|
21
21
|
modelName: model,
|
|
22
|
-
temperature
|
|
23
|
-
maxTokens
|
|
22
|
+
temperature,
|
|
23
|
+
maxTokens
|
|
24
24
|
});
|
|
25
25
|
this.graph = this.buildGraph();
|
|
26
26
|
}
|
|
@@ -239,7 +239,9 @@ var AIErrorDiagnostic = class {
|
|
|
239
239
|
options.apiKey,
|
|
240
240
|
options.apiUrl,
|
|
241
241
|
options.model,
|
|
242
|
-
options.maxRetries
|
|
242
|
+
options.maxRetries,
|
|
243
|
+
options.temperature,
|
|
244
|
+
options.maxTokens
|
|
243
245
|
);
|
|
244
246
|
}
|
|
245
247
|
async diagnose(error, autoFix = false) {
|
|
@@ -1050,6 +1052,8 @@ function vitePluginAIDiagnostic(options = {}) {
|
|
|
1050
1052
|
autoFix = false,
|
|
1051
1053
|
model = "gpt-4",
|
|
1052
1054
|
maxRetries = 3,
|
|
1055
|
+
temperature = 0.1,
|
|
1056
|
+
maxTokens = 4e3,
|
|
1053
1057
|
output = {
|
|
1054
1058
|
console: true,
|
|
1055
1059
|
html: true,
|
|
@@ -1061,7 +1065,9 @@ function vitePluginAIDiagnostic(options = {}) {
|
|
|
1061
1065
|
apiKey,
|
|
1062
1066
|
apiUrl,
|
|
1063
1067
|
model,
|
|
1064
|
-
maxRetries
|
|
1068
|
+
maxRetries,
|
|
1069
|
+
temperature,
|
|
1070
|
+
maxTokens
|
|
1065
1071
|
});
|
|
1066
1072
|
let buildErrors = [];
|
|
1067
1073
|
let lastTransformFile = null;
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/langgraph.ts","../src/diagnostic.ts","../src/reporter.ts"],"sourcesContent":["/**\r\n * AI 诊断插件入口\r\n *\r\n * 功能:\r\n * - 自动诊断构建错误\r\n * - 提供修复建议\r\n * - 自动修复代码\r\n */\r\n\r\nimport type { Plugin, ResolvedConfig } from \"vite\";\r\nimport fs from \"fs\";\r\nimport path from \"path\";\r\nimport { AIErrorDiagnostic } from \"./diagnostic\";\r\nimport { extractSourceFile } from \"vite-plugin-ai-shared\";\r\nimport { DiagnosticReporter, type DiagnosticReport } from \"./reporter\";\r\nimport { glob } from \"glob\";\r\n\r\nexport interface AIPluginOptions {\r\n apiKey?: string;\r\n apiUrl?: string;\r\n autoFix?: boolean;\r\n model?: string;\r\n maxRetries?: number;\r\n output?: {\r\n console?: boolean;\r\n html?: boolean;\r\n markdown?: boolean;\r\n json?: boolean;\r\n };\r\n}\r\n\r\nexport function vitePluginAIDiagnostic(options: AIPluginOptions = {}): Plugin {\r\n const {\r\n apiKey = process.env.OPENAI_API_KEY || \"\",\r\n apiUrl = process.env.OPENAI_API_URL || \"https://api.openai.com/v1\",\r\n autoFix = false,\r\n model = \"gpt-4\",\r\n maxRetries = 3,\r\n output = {\r\n console: true,\r\n html: true,\r\n markdown: false,\r\n json: false,\r\n },\r\n } = options;\r\n\r\n const diagnostic = new AIErrorDiagnostic({\r\n apiKey,\r\n apiUrl,\r\n model,\r\n maxRetries,\r\n });\r\n\r\n let buildErrors: any[] = [];\r\n let lastTransformFile: string | null = null;\r\n let processedErrors = new Set<string>(); // 记录已处理的错误\r\n let config: ResolvedConfig;\r\n let diagnosticResults: DiagnosticReport[] = []; // 收集所有诊断结果\r\n\r\n // 处理错误的函数\r\n async function processError(error: any) {\r\n // 生成错误的唯一标识\r\n const errorKey = `${error.file}:${error.message}`;\r\n\r\n // 如果已经处理过,跳过\r\n if (processedErrors.has(errorKey)) {\r\n console.log(\"🔍 [调试] 跳过重复错误:\", errorKey);\r\n return;\r\n }\r\n\r\n processedErrors.add(errorKey);\r\n\r\n try {\r\n console.log(\"\\n⚠️ 检测到错误,正在使用 AI 分析...\\n\");\r\n console.log(`📝 错误信息: ${error.message}`);\r\n console.log(`📂 文件路径: ${error.file || \"未知\"}`);\r\n console.log(\r\n `📄 代码长度: ${error.code ? error.code.length + \" 字符\" : \"无\"}`,\r\n );\r\n console.log(`🔧 自动修复: ${autoFix ? \"是\" : \"否\"}\\n`);\r\n\r\n if (!error.file || !error.code) {\r\n console.log(\"⚠️ 跳过此错误:缺少文件路径或代码内容\\n\");\r\n return;\r\n }\r\n\r\n const result = await diagnostic.diagnose(error, autoFix);\r\n\r\n // 控制台输出\r\n if (output.console !== false) {\r\n console.log(\"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\");\r\n console.log(\"🔍 错误分析:\");\r\n console.log(result.analysis);\r\n console.log(\"\\n💡 修复建议:\");\r\n console.log(result.suggestion);\r\n\r\n if (result.fixedCode && result.filePath) {\r\n console.log(\"\\n✅ 已自动修复代码\");\r\n console.log(\"修复的文件:\", result.filePath);\r\n console.log(\"\\n💡 请重新运行构建命令\");\r\n } else if (autoFix) {\r\n console.log(\"\\n⚠️ 无法自动修复:AI 未生成修复代码\");\r\n }\r\n console.log(\"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\n\");\r\n }\r\n\r\n // 生成报告对象\r\n const report: DiagnosticReport = {\r\n timestamp: new Date().toLocaleString(\"zh-CN\"),\r\n error: {\r\n type: error.type || \"unknown\",\r\n message: error.message,\r\n file: error.file,\r\n stack: error.stack,\r\n },\r\n analysis: result.analysis,\r\n suggestion: result.suggestion,\r\n fixed: !!(result.fixedCode && result.filePath),\r\n fixedFilePath: result.filePath,\r\n };\r\n\r\n // 收集诊断结果,稍后统一生成报告\r\n diagnosticResults.push(report);\r\n } catch (err: any) {\r\n console.error(\"❌ AI 诊断失败:\", err.message);\r\n }\r\n }\r\n\r\n return {\r\n name: \"vite-plugin-ai-diagnostic\",\r\n\r\n // 确保插件在其他插件之后执行,以捕获更多错误\r\n enforce: \"post\",\r\n\r\n configResolved(resolvedConfig) {\r\n config = resolvedConfig;\r\n console.log(\"\\n🤖 AI 诊断助手已启动...\");\r\n console.log(`⚙️ 自动修复: ${autoFix ? \"✅ 已启用\" : \"❌ 未启用\"}`);\r\n console.log(`📝 根目录: ${config.root}`);\r\n console.log(\r\n `📝 入口: ${config.build.rollupOptions?.input || \"index.html\"}\\n`,\r\n );\r\n },\r\n\r\n async buildStart() {\r\n buildErrors = [];\r\n processedErrors.clear();\r\n diagnosticResults = []; // 清空诊断结果\r\n console.log(\"🔍 开始扫描源文件...\");\r\n\r\n // 扫描 src 目录下的所有源文件\r\n const srcDir = path.join(config.root, \"src\");\r\n if (!fs.existsSync(srcDir)) {\r\n console.log(\"⚠️ src 目录不存在,跳过文件扫描\");\r\n return;\r\n }\r\n\r\n try {\r\n // 使用 glob 查找所有源文件\r\n const files = await glob(\"**/*.{vue,ts,tsx,js,jsx}\", {\r\n cwd: srcDir,\r\n absolute: true,\r\n ignore: [\"**/node_modules/**\", \"**/*.d.ts\"],\r\n });\r\n\r\n console.log(`📂 找到 ${files.length} 个源文件`);\r\n\r\n // 检查每个文件的语法\r\n for (const file of files) {\r\n try {\r\n const code = fs.readFileSync(file, \"utf-8\");\r\n\r\n // 基本语法检查\r\n if (file.endsWith(\".vue\")) {\r\n // 检查 Vue 文件的基本结构\r\n if (!code.includes(\"<template>\") && !code.includes(\"<script>\")) {\r\n buildErrors.push({\r\n type: \"syntax\",\r\n message: \"Vue 文件缺少 <template> 或 <script> 标签\",\r\n file: file,\r\n code: code,\r\n });\r\n }\r\n\r\n // 检查未闭合的标签\r\n const templateMatch = code.match(/<template[^>]*>/);\r\n if (templateMatch && !code.includes(\"</template>\")) {\r\n buildErrors.push({\r\n type: \"syntax\",\r\n message: \"Vue 文件中 <template> 标签未闭合\",\r\n file: file,\r\n code: code,\r\n });\r\n }\r\n\r\n const scriptMatch = code.match(/<script[^>]*>/);\r\n if (scriptMatch && !code.includes(\"</script>\")) {\r\n buildErrors.push({\r\n type: \"syntax\",\r\n message: \"Vue 文件中 <script> 标签未闭合\",\r\n file: file,\r\n code: code,\r\n });\r\n }\r\n }\r\n\r\n // 检查 JavaScript/TypeScript 语法错误(简单检查)\r\n if (\r\n file.endsWith(\".ts\") ||\r\n file.endsWith(\".tsx\") ||\r\n file.endsWith(\".js\") ||\r\n file.endsWith(\".jsx\")\r\n ) {\r\n // 检查括号匹配\r\n const openBraces = (code.match(/\\{/g) || []).length;\r\n const closeBraces = (code.match(/\\}/g) || []).length;\r\n if (openBraces !== closeBraces) {\r\n buildErrors.push({\r\n type: \"syntax\",\r\n message: `括号不匹配:{ 有 ${openBraces} 个,} 有 ${closeBraces} 个`,\r\n file: file,\r\n code: code,\r\n });\r\n }\r\n\r\n const openParens = (code.match(/\\(/g) || []).length;\r\n const closeParens = (code.match(/\\)/g) || []).length;\r\n if (openParens !== closeParens) {\r\n buildErrors.push({\r\n type: \"syntax\",\r\n message: `圆括号不匹配:( 有 ${openParens} 个,) 有 ${closeParens} 个`,\r\n file: file,\r\n code: code,\r\n });\r\n }\r\n }\r\n\r\n // 检查导入语句中的不存在模块(这个会在后续构建中被捕获)\r\n const importRegex = /import\\s+.*?\\s+from\\s+['\"](.+?)['\"]/g;\r\n let match;\r\n while ((match = importRegex.exec(code)) !== null) {\r\n const importPath = match[1];\r\n\r\n // 跳过 node_modules 和别名导入\r\n if (importPath.startsWith(\".\") || importPath.startsWith(\"/\")) {\r\n const resolvedPath = path.resolve(\r\n path.dirname(file),\r\n importPath,\r\n );\r\n const extensions = [\".ts\", \".tsx\", \".js\", \".jsx\", \".vue\", \"\"];\r\n\r\n let exists = false;\r\n for (const ext of extensions) {\r\n const fullPath = resolvedPath + ext;\r\n if (fs.existsSync(fullPath)) {\r\n exists = true;\r\n break;\r\n }\r\n // 检查是否为目录,且包含 index 文件\r\n if (\r\n fs.existsSync(resolvedPath) &&\r\n fs.statSync(resolvedPath).isDirectory()\r\n ) {\r\n const indexPath = path.join(resolvedPath, \"index\" + ext);\r\n if (fs.existsSync(indexPath)) {\r\n exists = true;\r\n break;\r\n }\r\n }\r\n }\r\n\r\n if (!exists) {\r\n buildErrors.push({\r\n type: \"module\",\r\n message: `找不到模块: ${importPath}`,\r\n file: file,\r\n code: code,\r\n });\r\n }\r\n }\r\n }\r\n } catch (err: any) {\r\n console.warn(`⚠️ 无法读取文件 ${file}: ${err.message}`);\r\n }\r\n }\r\n\r\n if (buildErrors.length > 0) {\r\n console.log(`⚠️ 扫描发现 ${buildErrors.length} 个潜在问题`);\r\n } else {\r\n console.log(\"✅ 文件扫描完成,未发现明显问题\");\r\n }\r\n } catch (err: any) {\r\n console.error(`❌ 文件扫描失败: ${err.message}`);\r\n }\r\n },\r\n\r\n // 解析模块时捕获错误\r\n async resolveId(source, importer, options) {\r\n // 不要在这里 try-catch,让错误自然传播到 buildEnd\r\n return null;\r\n },\r\n\r\n // 加载模块时捕获错误\r\n async load(id) {\r\n // 不要在这里 try-catch,让错误自然传播到 buildEnd\r\n return null;\r\n },\r\n\r\n // Rollup 钩子:模块解析完成后调用\r\n moduleParsed(moduleInfo) {\r\n // 检查模块是否有导入错误\r\n if (moduleInfo.meta && moduleInfo.meta.error) {\r\n console.log(\"\\n⚠️ moduleParsed 检测到错误:\", moduleInfo.id);\r\n\r\n let code = undefined;\r\n if (moduleInfo.id && fs.existsSync(moduleInfo.id)) {\r\n code = fs.readFileSync(moduleInfo.id, \"utf-8\");\r\n }\r\n\r\n const errorInfo = {\r\n type: \"module\",\r\n message: moduleInfo.meta.error,\r\n stack: \"\",\r\n file: moduleInfo.id,\r\n code: code,\r\n };\r\n\r\n buildErrors.push(errorInfo);\r\n }\r\n },\r\n\r\n buildEnd(error?: Error) {\r\n console.log(\"🔍 [调试] buildEnd 已执行, 有错误:\", !!error);\r\n\r\n if (error) {\r\n console.log(\"\\n⚠️ buildEnd 捕获到错误:\", error.message);\r\n\r\n const realFilePath = extractSourceFile(error, lastTransformFile);\r\n\r\n let code = undefined;\r\n if (realFilePath && fs.existsSync(realFilePath)) {\r\n try {\r\n code = fs.readFileSync(realFilePath, \"utf-8\");\r\n console.log(`📂 读取源文件成功: ${realFilePath}`);\r\n console.log(`📄 源文件长度: ${code.length} 字符`);\r\n } catch (e) {\r\n console.warn(\"⚠️ 无法读取文件:\", realFilePath);\r\n }\r\n }\r\n\r\n const errorInfo = {\r\n type: \"build\",\r\n message: error.message,\r\n stack: error.stack,\r\n file: realFilePath,\r\n code: code,\r\n };\r\n\r\n buildErrors.push(errorInfo);\r\n }\r\n },\r\n\r\n // Rollup 输出生成阶段的钩子\r\n renderStart(outputOptions, inputOptions) {\r\n console.log(\"🔍 [调试] renderStart 已执行\");\r\n },\r\n\r\n renderError(error?: Error) {\r\n console.log(\"🔍 [调试] renderError 已执行\");\r\n if (!error) return;\r\n\r\n console.log(\"\\n⚠️ renderError 捕获到错误:\", error.message);\r\n\r\n const realFilePath = extractSourceFile(error, lastTransformFile);\r\n\r\n let code = undefined;\r\n if (realFilePath && fs.existsSync(realFilePath)) {\r\n try {\r\n code = fs.readFileSync(realFilePath, \"utf-8\");\r\n console.log(`📂 读取源文件成功: ${realFilePath}`);\r\n console.log(`📄 源文件长度: ${code.length} 字符`);\r\n } catch (e) {\r\n console.warn(\"⚠️ 无法读取文件:\", realFilePath);\r\n }\r\n }\r\n\r\n const errorInfo = {\r\n type: \"render\",\r\n message: error.message,\r\n stack: error.stack,\r\n file: realFilePath,\r\n code: code,\r\n };\r\n\r\n buildErrors.push(errorInfo);\r\n },\r\n\r\n // 监听所有阶段的错误\r\n watchChange(id, change) {\r\n console.log(\"🔍 [调试] watchChange:\", id);\r\n },\r\n\r\n async closeBundle() {\r\n if (buildErrors.length > 0) {\r\n console.log(\r\n `\\n🔍 [调试] closeBundle 检测到 ${buildErrors.length} 个错误\\n`,\r\n );\r\n\r\n // 处理所有收集到的错误(去重由 processError 函数处理)\r\n for (const error of buildErrors) {\r\n await processError(error);\r\n }\r\n\r\n // 统一生成合并报告\r\n if (diagnosticResults.length > 0) {\r\n console.log(\r\n `\\n📊 正在生成合并诊断报告 (${diagnosticResults.length} 个错误)...\\n`,\r\n );\r\n await DiagnosticReporter.generateMultiReport(\r\n diagnosticResults,\r\n output,\r\n );\r\n }\r\n } else {\r\n console.log(\"✨ 构建完成,未检测到错误\\n\");\r\n }\r\n },\r\n\r\n transform(code: string, id: string) {\r\n lastTransformFile = id;\r\n\r\n try {\r\n return null;\r\n } catch (error: any) {\r\n console.log(\"\\n⚠️ transform 捕获到错误:\", error.message);\r\n buildErrors.push({\r\n type: \"transform\",\r\n message: error.message,\r\n stack: error.stack,\r\n file: id,\r\n code: code,\r\n });\r\n throw error;\r\n }\r\n },\r\n };\r\n}\r\n\r\n// 默认导出\r\nexport default vitePluginAIDiagnostic;\r\n","/**\r\n * LangGraph 工作流实现\r\n */\r\n\r\nimport { StateGraph, END, START } from \"@langchain/langgraph\";\r\nimport { ChatOpenAI } from \"@langchain/openai\";\r\nimport { HumanMessage, SystemMessage } from \"@langchain/core/messages\";\r\n\r\nexport interface DiagnosticState {\r\n error: any;\r\n analysis: string;\r\n suggestion: string;\r\n fixedCode: string;\r\n filePath: string;\r\n autoFix: boolean;\r\n retryCount: number;\r\n messages: any[];\r\n}\r\n\r\nexport class DiagnosticGraph {\r\n private llm: ChatOpenAI;\r\n private graph: any;\r\n private maxRetries: number;\r\n\r\n constructor(\r\n apiKey: string,\r\n apiUrl: string,\r\n model: string = \"gpt-4\",\r\n maxRetries: number = 3,\r\n ) {\r\n this.maxRetries = maxRetries;\r\n\r\n console.log(\"🔧 [LangGraph] 初始化 LLM...\");\r\n console.log(\"📝 [配置] 模型:\", model);\r\n console.log(\"📝 [配置] API URL:\", apiUrl);\r\n console.log(\"📝 [配置] API Key:\", apiKey ? \"已配置\" : \"未配置\");\r\n\r\n this.llm = new ChatOpenAI({\r\n openAIApiKey: apiKey,\r\n configuration: {\r\n baseURL: apiUrl,\r\n },\r\n modelName: model,\r\n temperature: 0.1,\r\n maxTokens: 4000,\r\n });\r\n\r\n this.graph = this.buildGraph();\r\n }\r\n\r\n private buildGraph() {\r\n const workflow = new StateGraph<DiagnosticState>({\r\n channels: {\r\n error: null,\r\n analysis: null,\r\n suggestion: null,\r\n fixedCode: null,\r\n filePath: null,\r\n autoFix: null,\r\n retryCount: null,\r\n messages: null,\r\n },\r\n });\r\n\r\n workflow.addNode(\"analyze\", this.analyzeNode.bind(this));\r\n workflow.addNode(\"suggest\", this.suggestNode.bind(this));\r\n // 自动修复节点已注释(功能不够稳定)\r\n // workflow.addNode(\"fix\", this.fixNode.bind(this));\r\n // workflow.addNode(\"validate\", this.validateNode.bind(this));\r\n\r\n workflow.addEdge(START, \"analyze\");\r\n workflow.addEdge(\"analyze\", \"suggest\");\r\n // 直接结束,不再进行自动修复\r\n workflow.addEdge(\"suggest\", END);\r\n\r\n // 自动修复流程已注释\r\n // workflow.addConditionalEdges(\"suggest\", this.shouldFix.bind(this), {\r\n // fix: \"fix\",\r\n // end: END,\r\n // });\r\n // workflow.addEdge(\"fix\", \"validate\");\r\n // workflow.addConditionalEdges(\"validate\", this.shouldRetry.bind(this), {\r\n // retry: \"analyze\",\r\n // end: END,\r\n // });\r\n\r\n return workflow.compile();\r\n }\r\n\r\n private async analyzeNode(\r\n state: DiagnosticState,\r\n ): Promise<Partial<DiagnosticState>> {\r\n console.log(\"🔍 [LangGraph] 正在分析错误...\");\r\n\r\n const systemPrompt = new SystemMessage(\r\n \"你是一个专业的前端代码诊断专家,精通 Vue3、TypeScript、Vite 和 uni-app。请简洁明了地分析问题。\",\r\n );\r\n\r\n const userPrompt = new HumanMessage(`\r\n请分析以下构建错误:\r\n\r\n错误类型: ${state.error.type}\r\n错误信息: ${state.error.message}\r\n文件路径: ${state.error.file || \"未知\"}\r\n\r\n请简洁地说明(3-5句话):\r\n1. 错误的根本原因\r\n2. 影响范围\r\n3. 严重程度\r\n`);\r\n\r\n const response = await this.llm.invoke([systemPrompt, userPrompt]);\r\n const analysis = response.content.toString();\r\n\r\n return {\r\n analysis,\r\n messages: [...(state.messages || []), systemPrompt, userPrompt, response],\r\n };\r\n }\r\n\r\n private async suggestNode(\r\n state: DiagnosticState,\r\n ): Promise<Partial<DiagnosticState>> {\r\n console.log(\"💡 [LangGraph] 正在生成修复建议...\");\r\n\r\n // 提取错误相关的代码片段\r\n let codeContext = \"\";\r\n if (state.error.code && state.error.message) {\r\n // 尝试从错误信息中提取行号\r\n const lineMatch = state.error.message.match(/\\((\\d+):(\\d+)\\)/);\r\n if (lineMatch) {\r\n const errorLine = parseInt(lineMatch[1]);\r\n const lines = state.error.code.split(\"\\n\");\r\n\r\n // 提取错误行前后各5行作为上下文\r\n const startLine = Math.max(0, errorLine - 6);\r\n const endLine = Math.min(lines.length, errorLine + 4);\r\n const contextLines = lines.slice(startLine, endLine);\r\n\r\n codeContext = `\r\n相关代码片段(第 ${startLine + 1}-${endLine} 行):\r\n\\`\\`\\`\r\n${contextLines\r\n .map((line, idx) => {\r\n const lineNum = startLine + idx + 1;\r\n const marker = lineNum === errorLine ? \" ← 错误位置\" : \"\";\r\n return `${lineNum}: ${line}${marker}`;\r\n })\r\n .join(\"\\n\")}\r\n\\`\\`\\`\r\n`;\r\n } else if (state.error.code.length < 2000) {\r\n // 如果代码不长,显示完整代码\r\n codeContext = `\r\n完整代码:\r\n\\`\\`\\`\r\n${state.error.code}\r\n\\`\\`\\`\r\n`;\r\n }\r\n }\r\n\r\n const userPrompt = new HumanMessage(`\r\n基于以下错误分析,请提供具体的修复建议:\r\n\r\n错误分析:\r\n${state.analysis}\r\n\r\n错误详情:\r\n- 类型: ${state.error.type}\r\n- 信息: ${state.error.message}\r\n- 文件: ${state.error.file || \"未知\"}\r\n\r\n${codeContext}\r\n\r\n请提供精确的修复建议,格式如下:\r\n\r\n1. 修复步骤:\r\n 1. [具体步骤1]\r\n 2. [具体步骤2]\r\n 3. [具体步骤3]\r\n\r\n2. 需要修改的代码位置: [文件名] 的第 [X] 行\r\n\r\n3. 修改后的代码示例:\r\n \\`\\`\\`[语言]\r\n [只显示需要修改的那几行代码,保持原有缩进]\r\n \\`\\`\\`\r\n\r\n4. 预防建议: [一句话说明如何避免类似错误]\r\n\r\n注意:\r\n- 代码示例必须基于实际的源代码,保持正确的语法和缩进\r\n- 只显示需要修改的关键代码行,不要显示整个文件\r\n- 确保修改后的代码可以直接使用\r\n`);\r\n\r\n const response = await this.llm.invoke([...state.messages, userPrompt]);\r\n const suggestion = response.content.toString();\r\n\r\n return {\r\n suggestion,\r\n messages: [...state.messages, userPrompt, response],\r\n };\r\n }\r\n\r\n // 自动修复节点已注释(功能不够稳定)\r\n // private async fixNode(\r\n // state: DiagnosticState\r\n // ): Promise<Partial<DiagnosticState>> {\r\n // console.log(\"🔧 [LangGraph] 正在生成修复代码...\");\r\n\r\n // if (!state.error.code || !state.error.file) {\r\n // return { fixedCode: \"\", filePath: \"\" };\r\n // }\r\n\r\n // try {\r\n // const systemPrompt = new SystemMessage(\r\n // `你是代码修复助手。返回修复后的完整文件内容,不要解释。`\r\n // );\r\n\r\n // const userPrompt = new HumanMessage(`\r\n // 文件(${state.error.code.split(\"\\n\").length} 行):\r\n // ${state.error.code}\r\n\r\n // 错误:${state.error.message}\r\n\r\n // 输出修复后的完整文件:\r\n // `);\r\n\r\n // console.log(\"📤 [调试] 发送修复请求...\");\r\n // console.log(\r\n // \"📤 [调试] 原始文件行数:\",\r\n // state.error.code.split(\"\\n\").length\r\n // );\r\n\r\n // const response = await this.llm.invoke([systemPrompt, userPrompt]);\r\n // let fixedCode = response.content.toString().trim();\r\n\r\n // console.log(\"📥 [调试] AI 返回内容长度:\", fixedCode.length);\r\n // console.log(\"📥 [调试] 原始代码长度:\", state.error.code.length);\r\n // console.log(\"📥 [调试] 返回内容行数:\", fixedCode.split(\"\\n\").length);\r\n\r\n // if (fixedCode.length === 0) {\r\n // console.error(\"❌ [调试] AI 返回空内容,可能是 API 调用失败\");\r\n // return { fixedCode: \"\", filePath: \"\" };\r\n // }\r\n\r\n // fixedCode = fixedCode\r\n // .replace(/^```[\\w]*\\n?/gm, \"\")\r\n // .replace(/\\n?```$/gm, \"\")\r\n // .trim();\r\n\r\n // console.log(\"📥 [调试] 清理后内容长度:\", fixedCode.length);\r\n\r\n // const finalLengthRatio = fixedCode.length / state.error.code.length;\r\n // console.log(\r\n // `✅ [调试] 最终代码长度比例: ${(finalLengthRatio * 100).toFixed(0)}%`\r\n // );\r\n\r\n // return {\r\n // fixedCode,\r\n // filePath: state.error.file,\r\n // messages: [...state.messages, userPrompt, response],\r\n // };\r\n // } catch (error: any) {\r\n // console.error(\"❌ [调试] fixNode 执行失败:\", error.message);\r\n // return { fixedCode: \"\", filePath: \"\" };\r\n // }\r\n // }\r\n\r\n // private async validateNode(\r\n // state: DiagnosticState\r\n // ): Promise<Partial<DiagnosticState>> {\r\n // console.log(\"✅ [LangGraph] 正在验证修复...\");\r\n // return state;\r\n // }\r\n\r\n // private shouldFix(state: DiagnosticState): string {\r\n // if (state.autoFix && state.error.file && state.error.code) {\r\n // return \"fix\";\r\n // }\r\n // return \"end\";\r\n // }\r\n\r\n // private shouldRetry(state: DiagnosticState): string {\r\n // if (state.retryCount < this.maxRetries && !state.fixedCode) {\r\n // return \"retry\";\r\n // }\r\n // return \"end\";\r\n // }\r\n\r\n async run(error: any, autoFix: boolean = false): Promise<DiagnosticState> {\r\n const initialState: DiagnosticState = {\r\n error,\r\n analysis: \"\",\r\n suggestion: \"\",\r\n fixedCode: \"\",\r\n filePath: \"\",\r\n autoFix,\r\n retryCount: 0,\r\n messages: [],\r\n };\r\n\r\n try {\r\n console.log(\"🚀 [LangGraph] 启动诊断工作流...\\n\");\r\n const result = await this.graph.invoke(initialState);\r\n console.log(\"✨ [LangGraph] 诊断工作流完成\\n\");\r\n return result;\r\n } catch (error: any) {\r\n console.error(\"❌ [LangGraph] 工作流执行失败:\", error.message);\r\n throw error;\r\n }\r\n }\r\n}\r\n","/**\r\n * AI 诊断核心逻辑\r\n */\r\n\r\nimport fs from \"fs\";\r\nimport { DiagnosticGraph } from \"./langgraph\";\r\nimport { CodeValidator } from \"./validator\";\r\n\r\nexport interface DiagnosticOptions {\r\n apiKey: string;\r\n apiUrl: string;\r\n model: string;\r\n maxRetries: number;\r\n}\r\n\r\nexport interface DiagnosticResult {\r\n analysis: string;\r\n suggestion: string;\r\n fixedCode?: string;\r\n filePath?: string;\r\n}\r\n\r\nexport class AIErrorDiagnostic {\r\n private options: DiagnosticOptions;\r\n private graph: DiagnosticGraph;\r\n\r\n constructor(options: DiagnosticOptions) {\r\n this.options = options;\r\n\r\n this.graph = new DiagnosticGraph(\r\n options.apiKey,\r\n options.apiUrl,\r\n options.model,\r\n options.maxRetries\r\n );\r\n }\r\n\r\n async diagnose(\r\n error: any,\r\n autoFix: boolean = false\r\n ): Promise<DiagnosticResult> {\r\n if (!this.options.apiKey) {\r\n return {\r\n analysis: \"未配置 API Key,无法使用 AI 诊断功能\",\r\n suggestion: \"请在 .env 文件中配置 OPENAI_API_KEY\",\r\n fixedCode: undefined,\r\n filePath: undefined,\r\n };\r\n }\r\n\r\n try {\r\n // 注意:自动修复功能已暂时禁用,因为不够稳定\r\n // 强制设置 autoFix 为 false\r\n const result = await this.graph.run(error, false);\r\n\r\n // 自动修复功能已注释(不够稳定)\r\n // if (autoFix && result.fixedCode && result.filePath) {\r\n // console.log(\"\\n🔍 [验证] 正在验证修复后的代码...\");\r\n\r\n // const validation = CodeValidator.validateFix(\r\n // error.code,\r\n // result.fixedCode\r\n // );\r\n\r\n // if (!validation.valid) {\r\n // console.warn(`⚠️ [验证失败] ${validation.reason}`);\r\n // console.log(\"📝 [提示] 将只提供修复建议,不自动应用修复\\n\");\r\n\r\n // return {\r\n // analysis: result.analysis,\r\n // suggestion:\r\n // result.suggestion +\r\n // \"\\n\\n⚠️ 自动修复验证失败:\" +\r\n // validation.reason,\r\n // fixedCode: undefined,\r\n // filePath: undefined,\r\n // };\r\n // }\r\n\r\n // console.log(\"✅ [验证通过] 代码验证成功\\n\");\r\n // this.applyFix(result.filePath, result.fixedCode);\r\n // }\r\n\r\n return {\r\n analysis: result.analysis,\r\n suggestion: result.suggestion,\r\n fixedCode: undefined, // 暂时不返回修复代码\r\n filePath: undefined,\r\n };\r\n } catch (error: any) {\r\n console.error(\"❌ AI 诊断失败:\", error.message);\r\n return {\r\n analysis: `诊断过程出错: ${error.message}`,\r\n suggestion: \"请检查 API 配置和网络连接\",\r\n fixedCode: undefined,\r\n filePath: undefined,\r\n };\r\n }\r\n }\r\n\r\n // 自动修复功能已注释(不够稳定)\r\n // private applyFix(filePath: string, fixedCode: string): void {\r\n // try {\r\n // const backupPath = `${filePath}.backup`;\r\n // if (fs.existsSync(filePath)) {\r\n // fs.copyFileSync(filePath, backupPath);\r\n // console.log(`📦 [备份] 已创建备份: ${backupPath}`);\r\n // }\r\n\r\n // fs.writeFileSync(filePath, fixedCode, \"utf-8\");\r\n // console.log(`✅ [修复] 已修复文件: ${filePath}`);\r\n // console.log(`💡 [提示] 如需恢复,运行: cp \"${backupPath}\" \"${filePath}\"`);\r\n // } catch (error: any) {\r\n // console.error(`❌ [修复失败] ${error.message}`);\r\n // }\r\n // }\r\n}\r\n","/**\r\n * AI 诊断报告生成器\r\n */\r\n\r\nimport fs from \"fs\";\r\nimport path from \"path\";\r\n\r\nexport interface DiagnosticReport {\r\n timestamp: string;\r\n error: {\r\n type: string;\r\n message: string;\r\n file: string;\r\n stack?: string;\r\n };\r\n analysis: string;\r\n suggestion: string;\r\n fixed: boolean;\r\n fixedFilePath?: string;\r\n}\r\n\r\nexport interface MultiDiagnosticReport {\r\n timestamp: string;\r\n totalErrors: number;\r\n errors: DiagnosticReport[];\r\n}\r\n\r\nexport interface ReporterOptions {\r\n console?: boolean;\r\n html?: boolean;\r\n markdown?: boolean;\r\n json?: boolean;\r\n}\r\n\r\nexport class DiagnosticReporter {\r\n /**\r\n * 生成报告(根据配置生成多种格式)\r\n */\r\n static async generate(\r\n report: DiagnosticReport,\r\n options: ReporterOptions = {},\r\n ): Promise<void> {\r\n // HTML 报告\r\n if (options.html) {\r\n await this.generateHTMLReport(report);\r\n }\r\n\r\n // Markdown 报告\r\n if (options.markdown) {\r\n await this.generateMarkdownReport(report);\r\n }\r\n\r\n // JSON 报告\r\n if (options.json) {\r\n await this.generateJSONReport(report);\r\n }\r\n }\r\n\r\n /**\r\n * 生成 HTML 报告\r\n */\r\n static async generateHTMLReport(report: DiagnosticReport): Promise<void> {\r\n const html = `\r\n<!DOCTYPE html>\r\n<html lang=\"zh-CN\">\r\n<head>\r\n <meta charset=\"UTF-8\">\r\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n <title>AI 诊断报告</title>\r\n <style>\r\n * { margin: 0; padding: 0; box-sizing: border-box; }\r\n body {\r\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\r\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\r\n padding: 20px;\r\n min-height: 100vh;\r\n }\r\n .container {\r\n max-width: 1000px;\r\n margin: 0 auto;\r\n background: white;\r\n border-radius: 12px;\r\n box-shadow: 0 8px 32px rgba(0,0,0,0.2);\r\n overflow: hidden;\r\n }\r\n .header {\r\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\r\n color: white;\r\n padding: 30px;\r\n text-align: center;\r\n }\r\n .header h1 {\r\n font-size: 32px;\r\n margin-bottom: 10px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 10px;\r\n }\r\n .header .time {\r\n font-size: 14px;\r\n opacity: 0.9;\r\n }\r\n .content {\r\n padding: 30px;\r\n }\r\n .section {\r\n margin-bottom: 30px;\r\n }\r\n .section-title {\r\n font-size: 20px;\r\n font-weight: bold;\r\n color: #333;\r\n margin-bottom: 15px;\r\n padding-bottom: 10px;\r\n border-bottom: 2px solid #667eea;\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n }\r\n .error-box {\r\n background: #fff5f5;\r\n border-left: 4px solid #f56565;\r\n padding: 20px;\r\n border-radius: 8px;\r\n margin-bottom: 20px;\r\n }\r\n .error-type {\r\n display: inline-block;\r\n background: #f56565;\r\n color: white;\r\n padding: 4px 12px;\r\n border-radius: 12px;\r\n font-size: 12px;\r\n font-weight: bold;\r\n margin-bottom: 10px;\r\n }\r\n .error-message {\r\n font-size: 16px;\r\n color: #c53030;\r\n font-weight: 500;\r\n margin-bottom: 10px;\r\n line-height: 1.6;\r\n }\r\n .error-file {\r\n font-size: 14px;\r\n color: #666;\r\n font-family: 'Courier New', monospace;\r\n background: #f7fafc;\r\n padding: 8px 12px;\r\n border-radius: 4px;\r\n display: inline-block;\r\n }\r\n .analysis-box {\r\n background: #f0f9ff;\r\n border-left: 4px solid #3b82f6;\r\n padding: 20px;\r\n border-radius: 8px;\r\n line-height: 1.8;\r\n color: #1e40af;\r\n }\r\n .suggestion-box {\r\n background: #f0fdf4;\r\n border-left: 4px solid #10b981;\r\n padding: 20px;\r\n border-radius: 8px;\r\n line-height: 1.8;\r\n color: #065f46;\r\n }\r\n .suggestion-box pre {\r\n background: #1e293b;\r\n color: #e2e8f0;\r\n padding: 15px;\r\n border-radius: 6px;\r\n overflow-x: auto;\r\n margin: 10px 0;\r\n font-size: 14px;\r\n line-height: 1.5;\r\n }\r\n .fixed-badge {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 6px;\r\n background: #10b981;\r\n color: white;\r\n padding: 8px 16px;\r\n border-radius: 20px;\r\n font-size: 14px;\r\n font-weight: bold;\r\n }\r\n .not-fixed-badge {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 6px;\r\n background: #f59e0b;\r\n color: white;\r\n padding: 8px 16px;\r\n border-radius: 20px;\r\n font-size: 14px;\r\n font-weight: bold;\r\n }\r\n .footer {\r\n background: #f7fafc;\r\n padding: 20px;\r\n text-align: center;\r\n color: #718096;\r\n font-size: 14px;\r\n border-top: 1px solid #e2e8f0;\r\n }\r\n .stack-trace {\r\n background: #1e293b;\r\n color: #e2e8f0;\r\n padding: 15px;\r\n border-radius: 6px;\r\n overflow-x: auto;\r\n font-family: 'Courier New', monospace;\r\n font-size: 12px;\r\n line-height: 1.5;\r\n margin-top: 10px;\r\n max-height: 300px;\r\n overflow-y: auto;\r\n }\r\n </style>\r\n</head>\r\n<body>\r\n <div class=\"container\">\r\n <div class=\"header\">\r\n <h1>🤖 AI 诊断报告</h1>\r\n <div class=\"time\">生成时间: ${report.timestamp}</div>\r\n </div>\r\n\r\n <div class=\"content\">\r\n <!-- 错误信息 -->\r\n <div class=\"section\">\r\n <div class=\"section-title\">❌ 错误信息</div>\r\n <div class=\"error-box\">\r\n <span class=\"error-type\">${report.error.type}</span>\r\n <div class=\"error-message\">${this.escapeHtml(\r\n report.error.message,\r\n )}</div>\r\n <div class=\"error-file\">📂 ${report.error.file}</div>\r\n ${\r\n report.error.stack\r\n ? `<div class=\"stack-trace\">${this.escapeHtml(\r\n report.error.stack,\r\n )}</div>`\r\n : \"\"\r\n }\r\n </div>\r\n </div>\r\n\r\n <!-- AI 分析 -->\r\n <div class=\"section\">\r\n <div class=\"section-title\">🔍 AI 分析</div>\r\n <div class=\"analysis-box\">\r\n ${this.formatText(report.analysis)}\r\n </div>\r\n </div>\r\n\r\n <!-- 修复建议 -->\r\n <div class=\"section\">\r\n <div class=\"section-title\">💡 修复建议</div>\r\n <div class=\"suggestion-box\">\r\n ${this.formatText(report.suggestion)}\r\n </div>\r\n </div>\r\n\r\n <!-- 修复状态 -->\r\n <div class=\"section\">\r\n <div class=\"section-title\">🔧 修复状态</div>\r\n ${\r\n report.fixed\r\n ? `<div class=\"fixed-badge\">✅ 已自动修复</div>\r\n <div style=\"margin-top: 10px; color: #666;\">修复文件: <code>${report.fixedFilePath}</code></div>`\r\n : `<div class=\"not-fixed-badge\">⚠️ 未自动修复</div>\r\n <div style=\"margin-top: 10px; color: #666;\">请根据上述建议手动修复</div>`\r\n }\r\n </div>\r\n </div>\r\n\r\n <div class=\"footer\">\r\n <p>AI Diagnostic Plugin v1.0.0</p>\r\n <p>Powered by LangGraph & OpenAI</p>\r\n </div>\r\n </div>\r\n</body>\r\n</html>\r\n `.trim();\r\n\r\n // 创建报告目录\r\n const reportsDir = path.resolve(process.cwd(), \"ai-reports\");\r\n if (!fs.existsSync(reportsDir)) {\r\n fs.mkdirSync(reportsDir, { recursive: true });\r\n }\r\n\r\n const reportPath = path.resolve(reportsDir, \"diagnostic-report.html\");\r\n fs.writeFileSync(reportPath, html, \"utf-8\");\r\n console.log(`\\n📄 诊断报告已生成: ${reportPath}\\n`);\r\n }\r\n\r\n /**\r\n * 转义 HTML 特殊字符\r\n */\r\n private static escapeHtml(text: string): string {\r\n const map: Record<string, string> = {\r\n \"&\": \"&\",\r\n \"<\": \"<\",\r\n \">\": \">\",\r\n '\"': \""\",\r\n \"'\": \"'\",\r\n };\r\n return text.replace(/[&<>\"']/g, (m) => map[m]);\r\n }\r\n\r\n /**\r\n * 格式化文本(支持代码块和换行)\r\n */\r\n private static formatText(text: string): string {\r\n // 转义 HTML\r\n let formatted = this.escapeHtml(text);\r\n\r\n // 处理代码块\r\n formatted = formatted.replace(\r\n /```(\\w*)\\n([\\s\\S]*?)```/g,\r\n (_, lang, code) => {\r\n return `<pre><code>${code.trim()}</code></pre>`;\r\n },\r\n );\r\n\r\n // 处理行内代码\r\n formatted = formatted.replace(\r\n /`([^`]+)`/g,\r\n '<code style=\"background: #e2e8f0; padding: 2px 6px; border-radius: 3px; font-family: monospace;\">$1</code>',\r\n );\r\n\r\n // 处理换行\r\n formatted = formatted.replace(/\\n/g, \"<br>\");\r\n\r\n return formatted;\r\n }\r\n\r\n /**\r\n * 生成 Markdown 报告\r\n */\r\n static async generateMarkdownReport(report: DiagnosticReport): Promise<void> {\r\n const markdown = `# 🤖 AI 诊断报告\r\n\r\n**生成时间**: ${report.timestamp}\r\n\r\n---\r\n\r\n## ❌ 错误信息\r\n\r\n**类型**: \\`${report.error.type}\\` \r\n**文件**: \\`${report.error.file}\\` \r\n**消息**: \r\n\\`\\`\\`\r\n${report.error.message}\r\n\\`\\`\\`\r\n\r\n${\r\n report.error.stack\r\n ? `**堆栈跟踪**:\\n\\`\\`\\`\\n${report.error.stack}\\n\\`\\`\\`\\n`\r\n : \"\"\r\n}\r\n\r\n---\r\n\r\n## 🔍 AI 分析\r\n\r\n${report.analysis}\r\n\r\n---\r\n\r\n## 💡 修复建议\r\n\r\n${report.suggestion}\r\n\r\n---\r\n\r\n## 🔧 修复状态\r\n\r\n${\r\n report.fixed\r\n ? `✅ **已自动修复**\\n\\n修复文件: \\`${report.fixedFilePath}\\``\r\n : `⚠️ **未自动修复**\\n\\n请根据上述建议手动修复`\r\n}\r\n\r\n---\r\n\r\n*AI Diagnostic Plugin v1.0.0* \r\n*Powered by LangGraph & OpenAI*\r\n`;\r\n\r\n // 创建报告目录\r\n const reportsDir = path.resolve(process.cwd(), \"ai-reports\");\r\n if (!fs.existsSync(reportsDir)) {\r\n fs.mkdirSync(reportsDir, { recursive: true });\r\n }\r\n\r\n const reportPath = path.resolve(reportsDir, \"diagnostic-report.md\");\r\n fs.writeFileSync(reportPath, markdown, \"utf-8\");\r\n console.log(`📄 Markdown 报告已生成: ${reportPath}`);\r\n }\r\n\r\n /**\r\n * 生成 JSON 报告\r\n */\r\n static async generateJSONReport(report: DiagnosticReport): Promise<void> {\r\n const jsonReport = {\r\n version: \"1.0.0\",\r\n timestamp: report.timestamp,\r\n error: {\r\n type: report.error.type,\r\n message: report.error.message,\r\n file: report.error.file,\r\n stack: report.error.stack || null,\r\n },\r\n diagnosis: {\r\n analysis: report.analysis,\r\n suggestion: report.suggestion,\r\n },\r\n fix: {\r\n applied: report.fixed,\r\n filePath: report.fixedFilePath || null,\r\n },\r\n };\r\n\r\n // 创建报告目录\r\n const reportsDir = path.resolve(process.cwd(), \"ai-reports\");\r\n if (!fs.existsSync(reportsDir)) {\r\n fs.mkdirSync(reportsDir, { recursive: true });\r\n }\r\n\r\n const reportPath = path.resolve(reportsDir, \"diagnostic-report.json\");\r\n fs.writeFileSync(reportPath, JSON.stringify(jsonReport, null, 2), \"utf-8\");\r\n console.log(`📄 JSON 报告已生成: ${reportPath}`);\r\n }\r\n\r\n /**\r\n * 生成多错误合并报告\r\n */\r\n static async generateMultiReport(\r\n reports: DiagnosticReport[],\r\n options: ReporterOptions = {},\r\n ): Promise<void> {\r\n const multiReport: MultiDiagnosticReport = {\r\n timestamp: new Date().toLocaleString(\"zh-CN\"),\r\n totalErrors: reports.length,\r\n errors: reports,\r\n };\r\n\r\n // HTML 报告\r\n if (options.html) {\r\n await this.generateMultiHTMLReport(multiReport);\r\n }\r\n\r\n // Markdown 报告\r\n if (options.markdown) {\r\n await this.generateMultiMarkdownReport(multiReport);\r\n }\r\n\r\n // JSON 报告\r\n if (options.json) {\r\n await this.generateMultiJSONReport(multiReport);\r\n }\r\n }\r\n\r\n /**\r\n * 生成多错误 HTML 报告\r\n */\r\n static async generateMultiHTMLReport(\r\n report: MultiDiagnosticReport,\r\n ): Promise<void> {\r\n const errorsHtml = report.errors\r\n .map(\r\n (error, index) => `\r\n <div class=\"error-item\">\r\n <div class=\"error-number\">错误 ${index + 1} / ${\r\n report.totalErrors\r\n }</div>\r\n <div class=\"error-box\">\r\n <span class=\"error-type\">${error.error.type}</span>\r\n <div class=\"error-message\">${this.escapeHtml(\r\n error.error.message,\r\n )}</div>\r\n <div class=\"error-file\">📂 ${error.error.file}</div>\r\n ${\r\n error.error.stack\r\n ? `<div class=\"stack-trace\">${this.escapeHtml(\r\n error.error.stack,\r\n )}</div>`\r\n : \"\"\r\n }\r\n </div>\r\n\r\n <div class=\"section\">\r\n <div class=\"section-title\">🔍 AI 分析</div>\r\n <div class=\"analysis-box\">\r\n ${this.formatText(error.analysis)}\r\n </div>\r\n </div>\r\n\r\n <div class=\"section\">\r\n <div class=\"section-title\">💡 修复建议</div>\r\n <div class=\"suggestion-box\">\r\n ${this.formatText(error.suggestion)}\r\n </div>\r\n </div>\r\n\r\n <div class=\"section\">\r\n <div class=\"section-title\">🔧 修复状态</div>\r\n ${\r\n error.fixed\r\n ? `<div class=\"fixed-badge\">✅ 已自动修复</div>\r\n <div style=\"margin-top: 10px; color: #666;\">修复文件: <code>${error.fixedFilePath}</code></div>`\r\n : `<div class=\"not-fixed-badge\">⚠️ 未自动修复</div>\r\n <div style=\"margin-top: 10px; color: #666;\">请根据上述建议手动修复</div>`\r\n }\r\n </div>\r\n </div>\r\n `,\r\n )\r\n .join(\"\");\r\n\r\n const html = `\r\n<!DOCTYPE html>\r\n<html lang=\"zh-CN\">\r\n<head>\r\n <meta charset=\"UTF-8\">\r\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n <title>AI 诊断报告 - ${report.totalErrors} 个错误</title>\r\n <style>\r\n * { margin: 0; padding: 0; box-sizing: border-box; }\r\n body {\r\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\r\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\r\n padding: 20px;\r\n min-height: 100vh;\r\n }\r\n .container {\r\n max-width: 1000px;\r\n margin: 0 auto;\r\n background: white;\r\n border-radius: 12px;\r\n box-shadow: 0 8px 32px rgba(0,0,0,0.2);\r\n overflow: hidden;\r\n }\r\n .header {\r\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\r\n color: white;\r\n padding: 30px;\r\n text-align: center;\r\n }\r\n .header h1 {\r\n font-size: 32px;\r\n margin-bottom: 10px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 10px;\r\n }\r\n .header .time {\r\n font-size: 14px;\r\n opacity: 0.9;\r\n }\r\n .header .error-count {\r\n font-size: 18px;\r\n margin-top: 10px;\r\n background: rgba(255,255,255,0.2);\r\n padding: 8px 16px;\r\n border-radius: 20px;\r\n display: inline-block;\r\n }\r\n .content {\r\n padding: 30px;\r\n }\r\n .error-item {\r\n margin-bottom: 40px;\r\n padding-bottom: 40px;\r\n border-bottom: 2px dashed #e2e8f0;\r\n }\r\n .error-item:last-child {\r\n border-bottom: none;\r\n margin-bottom: 0;\r\n padding-bottom: 0;\r\n }\r\n .error-number {\r\n font-size: 16px;\r\n font-weight: bold;\r\n color: #667eea;\r\n margin-bottom: 15px;\r\n padding: 8px 16px;\r\n background: #f0f9ff;\r\n border-radius: 8px;\r\n display: inline-block;\r\n }\r\n .section {\r\n margin-bottom: 20px;\r\n }\r\n .section-title {\r\n font-size: 18px;\r\n font-weight: bold;\r\n color: #333;\r\n margin-bottom: 12px;\r\n padding-bottom: 8px;\r\n border-bottom: 2px solid #667eea;\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n }\r\n .error-box {\r\n background: #fff5f5;\r\n border-left: 4px solid #f56565;\r\n padding: 20px;\r\n border-radius: 8px;\r\n margin-bottom: 20px;\r\n }\r\n .error-type {\r\n display: inline-block;\r\n background: #f56565;\r\n color: white;\r\n padding: 4px 12px;\r\n border-radius: 12px;\r\n font-size: 12px;\r\n font-weight: bold;\r\n margin-bottom: 10px;\r\n }\r\n .error-message {\r\n font-size: 16px;\r\n color: #c53030;\r\n font-weight: 500;\r\n margin-bottom: 10px;\r\n line-height: 1.6;\r\n }\r\n .error-file {\r\n font-size: 14px;\r\n color: #666;\r\n font-family: 'Courier New', monospace;\r\n background: #f7fafc;\r\n padding: 8px 12px;\r\n border-radius: 4px;\r\n display: inline-block;\r\n }\r\n .analysis-box {\r\n background: #f0f9ff;\r\n border-left: 4px solid #3b82f6;\r\n padding: 20px;\r\n border-radius: 8px;\r\n line-height: 1.8;\r\n color: #1e40af;\r\n }\r\n .suggestion-box {\r\n background: #f0fdf4;\r\n border-left: 4px solid #10b981;\r\n padding: 20px;\r\n border-radius: 8px;\r\n line-height: 1.8;\r\n color: #065f46;\r\n }\r\n .suggestion-box pre {\r\n background: #1e293b;\r\n color: #e2e8f0;\r\n padding: 15px;\r\n border-radius: 6px;\r\n overflow-x: auto;\r\n margin: 10px 0;\r\n font-size: 14px;\r\n line-height: 1.5;\r\n }\r\n .fixed-badge {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 6px;\r\n background: #10b981;\r\n color: white;\r\n padding: 8px 16px;\r\n border-radius: 20px;\r\n font-size: 14px;\r\n font-weight: bold;\r\n }\r\n .not-fixed-badge {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 6px;\r\n background: #f59e0b;\r\n color: white;\r\n padding: 8px 16px;\r\n border-radius: 20px;\r\n font-size: 14px;\r\n font-weight: bold;\r\n }\r\n .footer {\r\n background: #f7fafc;\r\n padding: 20px;\r\n text-align: center;\r\n color: #718096;\r\n font-size: 14px;\r\n border-top: 1px solid #e2e8f0;\r\n }\r\n .stack-trace {\r\n background: #1e293b;\r\n color: #e2e8f0;\r\n padding: 15px;\r\n border-radius: 6px;\r\n overflow-x: auto;\r\n font-family: 'Courier New', monospace;\r\n font-size: 12px;\r\n line-height: 1.5;\r\n margin-top: 10px;\r\n max-height: 300px;\r\n overflow-y: auto;\r\n }\r\n </style>\r\n</head>\r\n<body>\r\n <div class=\"container\">\r\n <div class=\"header\">\r\n <h1>🤖 AI 诊断报告</h1>\r\n <div class=\"time\">生成时间: ${report.timestamp}</div>\r\n <div class=\"error-count\">共发现 ${report.totalErrors} 个错误</div>\r\n </div>\r\n\r\n <div class=\"content\">\r\n ${errorsHtml}\r\n </div>\r\n\r\n <div class=\"footer\">\r\n <p>AI Diagnostic Plugin v1.0.7</p>\r\n <p>Powered by LangGraph & OpenAI</p>\r\n </div>\r\n </div>\r\n</body>\r\n</html>\r\n `.trim();\r\n\r\n // 创建报告目录\r\n const reportsDir = path.resolve(process.cwd(), \"ai-reports\");\r\n if (!fs.existsSync(reportsDir)) {\r\n fs.mkdirSync(reportsDir, { recursive: true });\r\n }\r\n\r\n const reportPath = path.resolve(reportsDir, \"diagnostic-report.html\");\r\n fs.writeFileSync(reportPath, html, \"utf-8\");\r\n console.log(\r\n `\\n📄 诊断报告已生成: ${reportPath} (${report.totalErrors} 个错误)\\n`,\r\n );\r\n }\r\n\r\n /**\r\n * 生成多错误 Markdown 报告\r\n */\r\n static async generateMultiMarkdownReport(\r\n report: MultiDiagnosticReport,\r\n ): Promise<void> {\r\n const errorsMarkdown = report.errors\r\n .map(\r\n (error, index) => `\r\n## 错误 ${index + 1} / ${report.totalErrors}\r\n\r\n### ❌ 错误信息\r\n\r\n**类型**: \\`${error.error.type}\\` \r\n**文件**: \\`${error.error.file}\\` \r\n**消息**: \r\n\\`\\`\\`\r\n${error.error.message}\r\n\\`\\`\\`\r\n\r\n${\r\n error.error.stack\r\n ? `**堆栈跟踪**:\\n\\`\\`\\`\\n${error.error.stack}\\n\\`\\`\\`\\n`\r\n : \"\"\r\n}\r\n\r\n### 🔍 AI 分析\r\n\r\n${error.analysis}\r\n\r\n### 💡 修复建议\r\n\r\n${error.suggestion}\r\n\r\n### 🔧 修复状态\r\n\r\n${\r\n error.fixed\r\n ? `✅ **已自动修复**\\n\\n修复文件: \\`${error.fixedFilePath}\\``\r\n : `⚠️ **未自动修复**\\n\\n请根据上述建议手动修复`\r\n}\r\n\r\n---\r\n`,\r\n )\r\n .join(\"\\n\");\r\n\r\n const markdown = `# 🤖 AI 诊断报告\r\n\r\n**生成时间**: ${report.timestamp} \r\n**错误总数**: ${report.totalErrors}\r\n\r\n---\r\n\r\n${errorsMarkdown}\r\n\r\n*AI Diagnostic Plugin v1.0.7* \r\n*Powered by LangGraph & OpenAI*\r\n`;\r\n\r\n // 创建报告目录\r\n const reportsDir = path.resolve(process.cwd(), \"ai-reports\");\r\n if (!fs.existsSync(reportsDir)) {\r\n fs.mkdirSync(reportsDir, { recursive: true });\r\n }\r\n\r\n const reportPath = path.resolve(reportsDir, \"diagnostic-report.md\");\r\n fs.writeFileSync(reportPath, markdown, \"utf-8\");\r\n console.log(`📄 Markdown 报告已生成: ${reportPath}`);\r\n }\r\n\r\n /**\r\n * 生成多错误 JSON 报告\r\n */\r\n static async generateMultiJSONReport(\r\n report: MultiDiagnosticReport,\r\n ): Promise<void> {\r\n const jsonReport = {\r\n version: \"1.0.7\",\r\n timestamp: report.timestamp,\r\n totalErrors: report.totalErrors,\r\n errors: report.errors.map((error) => ({\r\n error: {\r\n type: error.error.type,\r\n message: error.error.message,\r\n file: error.error.file,\r\n stack: error.error.stack || null,\r\n },\r\n diagnosis: {\r\n analysis: error.analysis,\r\n suggestion: error.suggestion,\r\n },\r\n fix: {\r\n applied: error.fixed,\r\n filePath: error.fixedFilePath || null,\r\n },\r\n })),\r\n };\r\n\r\n // 创建报告目录\r\n const reportsDir = path.resolve(process.cwd(), \"ai-reports\");\r\n if (!fs.existsSync(reportsDir)) {\r\n fs.mkdirSync(reportsDir, { recursive: true });\r\n }\r\n\r\n const reportPath = path.resolve(reportsDir, \"diagnostic-report.json\");\r\n fs.writeFileSync(reportPath, JSON.stringify(jsonReport, null, 2), \"utf-8\");\r\n console.log(`📄 JSON 报告已生成: ${reportPath}`);\r\n }\r\n}\r\n"],"mappings":"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","names":["fs","path","error","error","path","fs","options"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/langgraph.ts","../src/diagnostic.ts","../src/reporter.ts"],"sourcesContent":["/**\r\n * AI 诊断插件入口\r\n *\r\n * 功能:\r\n * - 自动诊断构建错误\r\n * - 提供修复建议\r\n * - 自动修复代码\r\n */\r\n\r\nimport type { Plugin, ResolvedConfig } from \"vite\";\r\nimport fs from \"fs\";\r\nimport path from \"path\";\r\nimport { AIErrorDiagnostic } from \"./diagnostic\";\r\nimport { extractSourceFile } from \"vite-plugin-ai-shared\";\r\nimport { DiagnosticReporter, type DiagnosticReport } from \"./reporter\";\r\nimport { glob } from \"glob\";\r\n\r\nexport interface AIPluginOptions {\r\n apiKey?: string;\r\n apiUrl?: string;\r\n autoFix?: boolean;\r\n model?: string;\r\n maxRetries?: number;\r\n temperature?: number;\r\n maxTokens?: number;\r\n output?: {\r\n console?: boolean;\r\n html?: boolean;\r\n markdown?: boolean;\r\n json?: boolean;\r\n };\r\n}\r\n\r\nexport function vitePluginAIDiagnostic(options: AIPluginOptions = {}): Plugin {\r\n const {\r\n apiKey = process.env.OPENAI_API_KEY || \"\",\r\n apiUrl = process.env.OPENAI_API_URL || \"https://api.openai.com/v1\",\r\n autoFix = false,\r\n model = \"gpt-4\",\r\n maxRetries = 3,\r\n temperature = 0.1,\r\n maxTokens = 4000,\r\n output = {\r\n console: true,\r\n html: true,\r\n markdown: false,\r\n json: false,\r\n },\r\n } = options;\r\n\r\n const diagnostic = new AIErrorDiagnostic({\r\n apiKey,\r\n apiUrl,\r\n model,\r\n maxRetries,\r\n temperature,\r\n maxTokens,\r\n });\r\n\r\n let buildErrors: any[] = [];\r\n let lastTransformFile: string | null = null;\r\n let processedErrors = new Set<string>(); // 记录已处理的错误\r\n let config: ResolvedConfig;\r\n let diagnosticResults: DiagnosticReport[] = []; // 收集所有诊断结果\r\n\r\n // 处理错误的函数\r\n async function processError(error: any) {\r\n // 生成错误的唯一标识\r\n const errorKey = `${error.file}:${error.message}`;\r\n\r\n // 如果已经处理过,跳过\r\n if (processedErrors.has(errorKey)) {\r\n console.log(\"🔍 [调试] 跳过重复错误:\", errorKey);\r\n return;\r\n }\r\n\r\n processedErrors.add(errorKey);\r\n\r\n try {\r\n console.log(\"\\n⚠️ 检测到错误,正在使用 AI 分析...\\n\");\r\n console.log(`📝 错误信息: ${error.message}`);\r\n console.log(`📂 文件路径: ${error.file || \"未知\"}`);\r\n console.log(\r\n `📄 代码长度: ${error.code ? error.code.length + \" 字符\" : \"无\"}`,\r\n );\r\n console.log(`🔧 自动修复: ${autoFix ? \"是\" : \"否\"}\\n`);\r\n\r\n if (!error.file || !error.code) {\r\n console.log(\"⚠️ 跳过此错误:缺少文件路径或代码内容\\n\");\r\n return;\r\n }\r\n\r\n const result = await diagnostic.diagnose(error, autoFix);\r\n\r\n // 控制台输出\r\n if (output.console !== false) {\r\n console.log(\"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\");\r\n console.log(\"🔍 错误分析:\");\r\n console.log(result.analysis);\r\n console.log(\"\\n💡 修复建议:\");\r\n console.log(result.suggestion);\r\n\r\n if (result.fixedCode && result.filePath) {\r\n console.log(\"\\n✅ 已自动修复代码\");\r\n console.log(\"修复的文件:\", result.filePath);\r\n console.log(\"\\n💡 请重新运行构建命令\");\r\n } else if (autoFix) {\r\n console.log(\"\\n⚠️ 无法自动修复:AI 未生成修复代码\");\r\n }\r\n console.log(\"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\\n\");\r\n }\r\n\r\n // 生成报告对象\r\n const report: DiagnosticReport = {\r\n timestamp: new Date().toLocaleString(\"zh-CN\"),\r\n error: {\r\n type: error.type || \"unknown\",\r\n message: error.message,\r\n file: error.file,\r\n stack: error.stack,\r\n },\r\n analysis: result.analysis,\r\n suggestion: result.suggestion,\r\n fixed: !!(result.fixedCode && result.filePath),\r\n fixedFilePath: result.filePath,\r\n };\r\n\r\n // 收集诊断结果,稍后统一生成报告\r\n diagnosticResults.push(report);\r\n } catch (err: any) {\r\n console.error(\"❌ AI 诊断失败:\", err.message);\r\n }\r\n }\r\n\r\n return {\r\n name: \"vite-plugin-ai-diagnostic\",\r\n\r\n // 确保插件在其他插件之后执行,以捕获更多错误\r\n enforce: \"post\",\r\n\r\n configResolved(resolvedConfig) {\r\n config = resolvedConfig;\r\n console.log(\"\\n🤖 AI 诊断助手已启动...\");\r\n console.log(`⚙️ 自动修复: ${autoFix ? \"✅ 已启用\" : \"❌ 未启用\"}`);\r\n console.log(`📝 根目录: ${config.root}`);\r\n console.log(\r\n `📝 入口: ${config.build.rollupOptions?.input || \"index.html\"}\\n`,\r\n );\r\n },\r\n\r\n async buildStart() {\r\n buildErrors = [];\r\n processedErrors.clear();\r\n diagnosticResults = []; // 清空诊断结果\r\n console.log(\"🔍 开始扫描源文件...\");\r\n\r\n // 扫描 src 目录下的所有源文件\r\n const srcDir = path.join(config.root, \"src\");\r\n if (!fs.existsSync(srcDir)) {\r\n console.log(\"⚠️ src 目录不存在,跳过文件扫描\");\r\n return;\r\n }\r\n\r\n try {\r\n // 使用 glob 查找所有源文件\r\n const files = await glob(\"**/*.{vue,ts,tsx,js,jsx}\", {\r\n cwd: srcDir,\r\n absolute: true,\r\n ignore: [\"**/node_modules/**\", \"**/*.d.ts\"],\r\n });\r\n\r\n console.log(`📂 找到 ${files.length} 个源文件`);\r\n\r\n // 检查每个文件的语法\r\n for (const file of files) {\r\n try {\r\n const code = fs.readFileSync(file, \"utf-8\");\r\n\r\n // 基本语法检查\r\n if (file.endsWith(\".vue\")) {\r\n // 检查 Vue 文件的基本结构\r\n if (!code.includes(\"<template>\") && !code.includes(\"<script>\")) {\r\n buildErrors.push({\r\n type: \"syntax\",\r\n message: \"Vue 文件缺少 <template> 或 <script> 标签\",\r\n file: file,\r\n code: code,\r\n });\r\n }\r\n\r\n // 检查未闭合的标签\r\n const templateMatch = code.match(/<template[^>]*>/);\r\n if (templateMatch && !code.includes(\"</template>\")) {\r\n buildErrors.push({\r\n type: \"syntax\",\r\n message: \"Vue 文件中 <template> 标签未闭合\",\r\n file: file,\r\n code: code,\r\n });\r\n }\r\n\r\n const scriptMatch = code.match(/<script[^>]*>/);\r\n if (scriptMatch && !code.includes(\"</script>\")) {\r\n buildErrors.push({\r\n type: \"syntax\",\r\n message: \"Vue 文件中 <script> 标签未闭合\",\r\n file: file,\r\n code: code,\r\n });\r\n }\r\n }\r\n\r\n // 检查 JavaScript/TypeScript 语法错误(简单检查)\r\n if (\r\n file.endsWith(\".ts\") ||\r\n file.endsWith(\".tsx\") ||\r\n file.endsWith(\".js\") ||\r\n file.endsWith(\".jsx\")\r\n ) {\r\n // 检查括号匹配\r\n const openBraces = (code.match(/\\{/g) || []).length;\r\n const closeBraces = (code.match(/\\}/g) || []).length;\r\n if (openBraces !== closeBraces) {\r\n buildErrors.push({\r\n type: \"syntax\",\r\n message: `括号不匹配:{ 有 ${openBraces} 个,} 有 ${closeBraces} 个`,\r\n file: file,\r\n code: code,\r\n });\r\n }\r\n\r\n const openParens = (code.match(/\\(/g) || []).length;\r\n const closeParens = (code.match(/\\)/g) || []).length;\r\n if (openParens !== closeParens) {\r\n buildErrors.push({\r\n type: \"syntax\",\r\n message: `圆括号不匹配:( 有 ${openParens} 个,) 有 ${closeParens} 个`,\r\n file: file,\r\n code: code,\r\n });\r\n }\r\n }\r\n\r\n // 检查导入语句中的不存在模块(这个会在后续构建中被捕获)\r\n const importRegex = /import\\s+.*?\\s+from\\s+['\"](.+?)['\"]/g;\r\n let match;\r\n while ((match = importRegex.exec(code)) !== null) {\r\n const importPath = match[1];\r\n\r\n // 跳过 node_modules 和别名导入\r\n if (importPath.startsWith(\".\") || importPath.startsWith(\"/\")) {\r\n const resolvedPath = path.resolve(\r\n path.dirname(file),\r\n importPath,\r\n );\r\n const extensions = [\".ts\", \".tsx\", \".js\", \".jsx\", \".vue\", \"\"];\r\n\r\n let exists = false;\r\n for (const ext of extensions) {\r\n const fullPath = resolvedPath + ext;\r\n if (fs.existsSync(fullPath)) {\r\n exists = true;\r\n break;\r\n }\r\n // 检查是否为目录,且包含 index 文件\r\n if (\r\n fs.existsSync(resolvedPath) &&\r\n fs.statSync(resolvedPath).isDirectory()\r\n ) {\r\n const indexPath = path.join(resolvedPath, \"index\" + ext);\r\n if (fs.existsSync(indexPath)) {\r\n exists = true;\r\n break;\r\n }\r\n }\r\n }\r\n\r\n if (!exists) {\r\n buildErrors.push({\r\n type: \"module\",\r\n message: `找不到模块: ${importPath}`,\r\n file: file,\r\n code: code,\r\n });\r\n }\r\n }\r\n }\r\n } catch (err: any) {\r\n console.warn(`⚠️ 无法读取文件 ${file}: ${err.message}`);\r\n }\r\n }\r\n\r\n if (buildErrors.length > 0) {\r\n console.log(`⚠️ 扫描发现 ${buildErrors.length} 个潜在问题`);\r\n } else {\r\n console.log(\"✅ 文件扫描完成,未发现明显问题\");\r\n }\r\n } catch (err: any) {\r\n console.error(`❌ 文件扫描失败: ${err.message}`);\r\n }\r\n },\r\n\r\n // 解析模块时捕获错误\r\n async resolveId(source, importer, options) {\r\n // 不要在这里 try-catch,让错误自然传播到 buildEnd\r\n return null;\r\n },\r\n\r\n // 加载模块时捕获错误\r\n async load(id) {\r\n // 不要在这里 try-catch,让错误自然传播到 buildEnd\r\n return null;\r\n },\r\n\r\n // Rollup 钩子:模块解析完成后调用\r\n moduleParsed(moduleInfo) {\r\n // 检查模块是否有导入错误\r\n if (moduleInfo.meta && moduleInfo.meta.error) {\r\n console.log(\"\\n⚠️ moduleParsed 检测到错误:\", moduleInfo.id);\r\n\r\n let code = undefined;\r\n if (moduleInfo.id && fs.existsSync(moduleInfo.id)) {\r\n code = fs.readFileSync(moduleInfo.id, \"utf-8\");\r\n }\r\n\r\n const errorInfo = {\r\n type: \"module\",\r\n message: moduleInfo.meta.error,\r\n stack: \"\",\r\n file: moduleInfo.id,\r\n code: code,\r\n };\r\n\r\n buildErrors.push(errorInfo);\r\n }\r\n },\r\n\r\n buildEnd(error?: Error) {\r\n console.log(\"🔍 [调试] buildEnd 已执行, 有错误:\", !!error);\r\n\r\n if (error) {\r\n console.log(\"\\n⚠️ buildEnd 捕获到错误:\", error.message);\r\n\r\n const realFilePath = extractSourceFile(error, lastTransformFile);\r\n\r\n let code = undefined;\r\n if (realFilePath && fs.existsSync(realFilePath)) {\r\n try {\r\n code = fs.readFileSync(realFilePath, \"utf-8\");\r\n console.log(`📂 读取源文件成功: ${realFilePath}`);\r\n console.log(`📄 源文件长度: ${code.length} 字符`);\r\n } catch (e) {\r\n console.warn(\"⚠️ 无法读取文件:\", realFilePath);\r\n }\r\n }\r\n\r\n const errorInfo = {\r\n type: \"build\",\r\n message: error.message,\r\n stack: error.stack,\r\n file: realFilePath,\r\n code: code,\r\n };\r\n\r\n buildErrors.push(errorInfo);\r\n }\r\n },\r\n\r\n // Rollup 输出生成阶段的钩子\r\n renderStart(outputOptions, inputOptions) {\r\n console.log(\"🔍 [调试] renderStart 已执行\");\r\n },\r\n\r\n renderError(error?: Error) {\r\n console.log(\"🔍 [调试] renderError 已执行\");\r\n if (!error) return;\r\n\r\n console.log(\"\\n⚠️ renderError 捕获到错误:\", error.message);\r\n\r\n const realFilePath = extractSourceFile(error, lastTransformFile);\r\n\r\n let code = undefined;\r\n if (realFilePath && fs.existsSync(realFilePath)) {\r\n try {\r\n code = fs.readFileSync(realFilePath, \"utf-8\");\r\n console.log(`📂 读取源文件成功: ${realFilePath}`);\r\n console.log(`📄 源文件长度: ${code.length} 字符`);\r\n } catch (e) {\r\n console.warn(\"⚠️ 无法读取文件:\", realFilePath);\r\n }\r\n }\r\n\r\n const errorInfo = {\r\n type: \"render\",\r\n message: error.message,\r\n stack: error.stack,\r\n file: realFilePath,\r\n code: code,\r\n };\r\n\r\n buildErrors.push(errorInfo);\r\n },\r\n\r\n // 监听所有阶段的错误\r\n watchChange(id, change) {\r\n console.log(\"🔍 [调试] watchChange:\", id);\r\n },\r\n\r\n async closeBundle() {\r\n if (buildErrors.length > 0) {\r\n console.log(\r\n `\\n🔍 [调试] closeBundle 检测到 ${buildErrors.length} 个错误\\n`,\r\n );\r\n\r\n // 处理所有收集到的错误(去重由 processError 函数处理)\r\n for (const error of buildErrors) {\r\n await processError(error);\r\n }\r\n\r\n // 统一生成合并报告\r\n if (diagnosticResults.length > 0) {\r\n console.log(\r\n `\\n📊 正在生成合并诊断报告 (${diagnosticResults.length} 个错误)...\\n`,\r\n );\r\n await DiagnosticReporter.generateMultiReport(\r\n diagnosticResults,\r\n output,\r\n );\r\n }\r\n } else {\r\n console.log(\"✨ 构建完成,未检测到错误\\n\");\r\n }\r\n },\r\n\r\n transform(code: string, id: string) {\r\n lastTransformFile = id;\r\n\r\n try {\r\n return null;\r\n } catch (error: any) {\r\n console.log(\"\\n⚠️ transform 捕获到错误:\", error.message);\r\n buildErrors.push({\r\n type: \"transform\",\r\n message: error.message,\r\n stack: error.stack,\r\n file: id,\r\n code: code,\r\n });\r\n throw error;\r\n }\r\n },\r\n };\r\n}\r\n\r\n// 默认导出\r\nexport default vitePluginAIDiagnostic;\r\n","/**\r\n * LangGraph 工作流实现\r\n */\r\n\r\nimport { StateGraph, END, START } from \"@langchain/langgraph\";\r\nimport { ChatOpenAI } from \"@langchain/openai\";\r\nimport { HumanMessage, SystemMessage } from \"@langchain/core/messages\";\r\n\r\nexport interface DiagnosticState {\r\n error: any;\r\n analysis: string;\r\n suggestion: string;\r\n fixedCode: string;\r\n filePath: string;\r\n autoFix: boolean;\r\n retryCount: number;\r\n messages: any[];\r\n}\r\n\r\nexport class DiagnosticGraph {\r\n private llm: ChatOpenAI;\r\n private graph: any;\r\n private maxRetries: number;\r\n\r\n constructor(\r\n apiKey: string,\r\n apiUrl: string,\r\n model: string = \"gpt-4\",\r\n maxRetries: number = 3,\r\n temperature: number = 0.1,\r\n maxTokens: number = 4000,\r\n ) {\r\n this.maxRetries = maxRetries;\r\n\r\n console.log(\"🔧 [LangGraph] 初始化 LLM...\");\r\n console.log(\"📝 [配置] 模型:\", model);\r\n console.log(\"📝 [配置] API URL:\", apiUrl);\r\n console.log(\"📝 [配置] API Key:\", apiKey ? \"已配置\" : \"未配置\");\r\n\r\n this.llm = new ChatOpenAI({\r\n openAIApiKey: apiKey,\r\n configuration: {\r\n baseURL: apiUrl,\r\n },\r\n modelName: model,\r\n temperature,\r\n maxTokens,\r\n });\r\n\r\n this.graph = this.buildGraph();\r\n }\r\n\r\n private buildGraph() {\r\n const workflow = new StateGraph<DiagnosticState>({\r\n channels: {\r\n error: null,\r\n analysis: null,\r\n suggestion: null,\r\n fixedCode: null,\r\n filePath: null,\r\n autoFix: null,\r\n retryCount: null,\r\n messages: null,\r\n },\r\n });\r\n\r\n workflow.addNode(\"analyze\", this.analyzeNode.bind(this));\r\n workflow.addNode(\"suggest\", this.suggestNode.bind(this));\r\n // 自动修复节点已注释(功能不够稳定)\r\n // workflow.addNode(\"fix\", this.fixNode.bind(this));\r\n // workflow.addNode(\"validate\", this.validateNode.bind(this));\r\n\r\n workflow.addEdge(START, \"analyze\");\r\n workflow.addEdge(\"analyze\", \"suggest\");\r\n // 直接结束,不再进行自动修复\r\n workflow.addEdge(\"suggest\", END);\r\n\r\n // 自动修复流程已注释\r\n // workflow.addConditionalEdges(\"suggest\", this.shouldFix.bind(this), {\r\n // fix: \"fix\",\r\n // end: END,\r\n // });\r\n // workflow.addEdge(\"fix\", \"validate\");\r\n // workflow.addConditionalEdges(\"validate\", this.shouldRetry.bind(this), {\r\n // retry: \"analyze\",\r\n // end: END,\r\n // });\r\n\r\n return workflow.compile();\r\n }\r\n\r\n private async analyzeNode(\r\n state: DiagnosticState,\r\n ): Promise<Partial<DiagnosticState>> {\r\n console.log(\"🔍 [LangGraph] 正在分析错误...\");\r\n\r\n const systemPrompt = new SystemMessage(\r\n \"你是一个专业的前端代码诊断专家,精通 Vue3、TypeScript、Vite 和 uni-app。请简洁明了地分析问题。\",\r\n );\r\n\r\n const userPrompt = new HumanMessage(`\r\n请分析以下构建错误:\r\n\r\n错误类型: ${state.error.type}\r\n错误信息: ${state.error.message}\r\n文件路径: ${state.error.file || \"未知\"}\r\n\r\n请简洁地说明(3-5句话):\r\n1. 错误的根本原因\r\n2. 影响范围\r\n3. 严重程度\r\n`);\r\n\r\n const response = await this.llm.invoke([systemPrompt, userPrompt]);\r\n const analysis = response.content.toString();\r\n\r\n return {\r\n analysis,\r\n messages: [...(state.messages || []), systemPrompt, userPrompt, response],\r\n };\r\n }\r\n\r\n private async suggestNode(\r\n state: DiagnosticState,\r\n ): Promise<Partial<DiagnosticState>> {\r\n console.log(\"💡 [LangGraph] 正在生成修复建议...\");\r\n\r\n // 提取错误相关的代码片段\r\n let codeContext = \"\";\r\n if (state.error.code && state.error.message) {\r\n // 尝试从错误信息中提取行号\r\n const lineMatch = state.error.message.match(/\\((\\d+):(\\d+)\\)/);\r\n if (lineMatch) {\r\n const errorLine = parseInt(lineMatch[1]);\r\n const lines = state.error.code.split(\"\\n\");\r\n\r\n // 提取错误行前后各5行作为上下文\r\n const startLine = Math.max(0, errorLine - 6);\r\n const endLine = Math.min(lines.length, errorLine + 4);\r\n const contextLines = lines.slice(startLine, endLine);\r\n\r\n codeContext = `\r\n相关代码片段(第 ${startLine + 1}-${endLine} 行):\r\n\\`\\`\\`\r\n${contextLines\r\n .map((line, idx) => {\r\n const lineNum = startLine + idx + 1;\r\n const marker = lineNum === errorLine ? \" ← 错误位置\" : \"\";\r\n return `${lineNum}: ${line}${marker}`;\r\n })\r\n .join(\"\\n\")}\r\n\\`\\`\\`\r\n`;\r\n } else if (state.error.code.length < 2000) {\r\n // 如果代码不长,显示完整代码\r\n codeContext = `\r\n完整代码:\r\n\\`\\`\\`\r\n${state.error.code}\r\n\\`\\`\\`\r\n`;\r\n }\r\n }\r\n\r\n const userPrompt = new HumanMessage(`\r\n基于以下错误分析,请提供具体的修复建议:\r\n\r\n错误分析:\r\n${state.analysis}\r\n\r\n错误详情:\r\n- 类型: ${state.error.type}\r\n- 信息: ${state.error.message}\r\n- 文件: ${state.error.file || \"未知\"}\r\n\r\n${codeContext}\r\n\r\n请提供精确的修复建议,格式如下:\r\n\r\n1. 修复步骤:\r\n 1. [具体步骤1]\r\n 2. [具体步骤2]\r\n 3. [具体步骤3]\r\n\r\n2. 需要修改的代码位置: [文件名] 的第 [X] 行\r\n\r\n3. 修改后的代码示例:\r\n \\`\\`\\`[语言]\r\n [只显示需要修改的那几行代码,保持原有缩进]\r\n \\`\\`\\`\r\n\r\n4. 预防建议: [一句话说明如何避免类似错误]\r\n\r\n注意:\r\n- 代码示例必须基于实际的源代码,保持正确的语法和缩进\r\n- 只显示需要修改的关键代码行,不要显示整个文件\r\n- 确保修改后的代码可以直接使用\r\n`);\r\n\r\n const response = await this.llm.invoke([...state.messages, userPrompt]);\r\n const suggestion = response.content.toString();\r\n\r\n return {\r\n suggestion,\r\n messages: [...state.messages, userPrompt, response],\r\n };\r\n }\r\n\r\n // 自动修复节点已注释(功能不够稳定)\r\n // private async fixNode(\r\n // state: DiagnosticState\r\n // ): Promise<Partial<DiagnosticState>> {\r\n // console.log(\"🔧 [LangGraph] 正在生成修复代码...\");\r\n\r\n // if (!state.error.code || !state.error.file) {\r\n // return { fixedCode: \"\", filePath: \"\" };\r\n // }\r\n\r\n // try {\r\n // const systemPrompt = new SystemMessage(\r\n // `你是代码修复助手。返回修复后的完整文件内容,不要解释。`\r\n // );\r\n\r\n // const userPrompt = new HumanMessage(`\r\n // 文件(${state.error.code.split(\"\\n\").length} 行):\r\n // ${state.error.code}\r\n\r\n // 错误:${state.error.message}\r\n\r\n // 输出修复后的完整文件:\r\n // `);\r\n\r\n // console.log(\"📤 [调试] 发送修复请求...\");\r\n // console.log(\r\n // \"📤 [调试] 原始文件行数:\",\r\n // state.error.code.split(\"\\n\").length\r\n // );\r\n\r\n // const response = await this.llm.invoke([systemPrompt, userPrompt]);\r\n // let fixedCode = response.content.toString().trim();\r\n\r\n // console.log(\"📥 [调试] AI 返回内容长度:\", fixedCode.length);\r\n // console.log(\"📥 [调试] 原始代码长度:\", state.error.code.length);\r\n // console.log(\"📥 [调试] 返回内容行数:\", fixedCode.split(\"\\n\").length);\r\n\r\n // if (fixedCode.length === 0) {\r\n // console.error(\"❌ [调试] AI 返回空内容,可能是 API 调用失败\");\r\n // return { fixedCode: \"\", filePath: \"\" };\r\n // }\r\n\r\n // fixedCode = fixedCode\r\n // .replace(/^```[\\w]*\\n?/gm, \"\")\r\n // .replace(/\\n?```$/gm, \"\")\r\n // .trim();\r\n\r\n // console.log(\"📥 [调试] 清理后内容长度:\", fixedCode.length);\r\n\r\n // const finalLengthRatio = fixedCode.length / state.error.code.length;\r\n // console.log(\r\n // `✅ [调试] 最终代码长度比例: ${(finalLengthRatio * 100).toFixed(0)}%`\r\n // );\r\n\r\n // return {\r\n // fixedCode,\r\n // filePath: state.error.file,\r\n // messages: [...state.messages, userPrompt, response],\r\n // };\r\n // } catch (error: any) {\r\n // console.error(\"❌ [调试] fixNode 执行失败:\", error.message);\r\n // return { fixedCode: \"\", filePath: \"\" };\r\n // }\r\n // }\r\n\r\n // private async validateNode(\r\n // state: DiagnosticState\r\n // ): Promise<Partial<DiagnosticState>> {\r\n // console.log(\"✅ [LangGraph] 正在验证修复...\");\r\n // return state;\r\n // }\r\n\r\n // private shouldFix(state: DiagnosticState): string {\r\n // if (state.autoFix && state.error.file && state.error.code) {\r\n // return \"fix\";\r\n // }\r\n // return \"end\";\r\n // }\r\n\r\n // private shouldRetry(state: DiagnosticState): string {\r\n // if (state.retryCount < this.maxRetries && !state.fixedCode) {\r\n // return \"retry\";\r\n // }\r\n // return \"end\";\r\n // }\r\n\r\n async run(error: any, autoFix: boolean = false): Promise<DiagnosticState> {\r\n const initialState: DiagnosticState = {\r\n error,\r\n analysis: \"\",\r\n suggestion: \"\",\r\n fixedCode: \"\",\r\n filePath: \"\",\r\n autoFix,\r\n retryCount: 0,\r\n messages: [],\r\n };\r\n\r\n try {\r\n console.log(\"🚀 [LangGraph] 启动诊断工作流...\\n\");\r\n const result = await this.graph.invoke(initialState);\r\n console.log(\"✨ [LangGraph] 诊断工作流完成\\n\");\r\n return result;\r\n } catch (error: any) {\r\n console.error(\"❌ [LangGraph] 工作流执行失败:\", error.message);\r\n throw error;\r\n }\r\n }\r\n}\r\n","/**\r\n * AI 诊断核心逻辑\r\n */\r\n\r\nimport fs from \"fs\";\r\nimport { DiagnosticGraph } from \"./langgraph\";\r\nimport { CodeValidator } from \"./validator\";\r\n\r\nexport interface DiagnosticOptions {\r\n apiKey: string;\r\n apiUrl: string;\r\n model: string;\r\n maxRetries: number;\r\n temperature?: number;\r\n maxTokens?: number;\r\n}\r\n\r\nexport interface DiagnosticResult {\r\n analysis: string;\r\n suggestion: string;\r\n fixedCode?: string;\r\n filePath?: string;\r\n}\r\n\r\nexport class AIErrorDiagnostic {\r\n private options: DiagnosticOptions;\r\n private graph: DiagnosticGraph;\r\n\r\n constructor(options: DiagnosticOptions) {\r\n this.options = options;\r\n\r\n this.graph = new DiagnosticGraph(\r\n options.apiKey,\r\n options.apiUrl,\r\n options.model,\r\n options.maxRetries,\r\n options.temperature,\r\n options.maxTokens,\r\n );\r\n }\r\n\r\n async diagnose(\r\n error: any,\r\n autoFix: boolean = false,\r\n ): Promise<DiagnosticResult> {\r\n if (!this.options.apiKey) {\r\n return {\r\n analysis: \"未配置 API Key,无法使用 AI 诊断功能\",\r\n suggestion: \"请在 .env 文件中配置 OPENAI_API_KEY\",\r\n fixedCode: undefined,\r\n filePath: undefined,\r\n };\r\n }\r\n\r\n try {\r\n // 注意:自动修复功能已暂时禁用,因为不够稳定\r\n // 强制设置 autoFix 为 false\r\n const result = await this.graph.run(error, false);\r\n\r\n // 自动修复功能已注释(不够稳定)\r\n // if (autoFix && result.fixedCode && result.filePath) {\r\n // console.log(\"\\n🔍 [验证] 正在验证修复后的代码...\");\r\n\r\n // const validation = CodeValidator.validateFix(\r\n // error.code,\r\n // result.fixedCode\r\n // );\r\n\r\n // if (!validation.valid) {\r\n // console.warn(`⚠️ [验证失败] ${validation.reason}`);\r\n // console.log(\"📝 [提示] 将只提供修复建议,不自动应用修复\\n\");\r\n\r\n // return {\r\n // analysis: result.analysis,\r\n // suggestion:\r\n // result.suggestion +\r\n // \"\\n\\n⚠️ 自动修复验证失败:\" +\r\n // validation.reason,\r\n // fixedCode: undefined,\r\n // filePath: undefined,\r\n // };\r\n // }\r\n\r\n // console.log(\"✅ [验证通过] 代码验证成功\\n\");\r\n // this.applyFix(result.filePath, result.fixedCode);\r\n // }\r\n\r\n return {\r\n analysis: result.analysis,\r\n suggestion: result.suggestion,\r\n fixedCode: undefined, // 暂时不返回修复代码\r\n filePath: undefined,\r\n };\r\n } catch (error: any) {\r\n console.error(\"❌ AI 诊断失败:\", error.message);\r\n return {\r\n analysis: `诊断过程出错: ${error.message}`,\r\n suggestion: \"请检查 API 配置和网络连接\",\r\n fixedCode: undefined,\r\n filePath: undefined,\r\n };\r\n }\r\n }\r\n\r\n // 自动修复功能已注释(不够稳定)\r\n // private applyFix(filePath: string, fixedCode: string): void {\r\n // try {\r\n // const backupPath = `${filePath}.backup`;\r\n // if (fs.existsSync(filePath)) {\r\n // fs.copyFileSync(filePath, backupPath);\r\n // console.log(`📦 [备份] 已创建备份: ${backupPath}`);\r\n // }\r\n\r\n // fs.writeFileSync(filePath, fixedCode, \"utf-8\");\r\n // console.log(`✅ [修复] 已修复文件: ${filePath}`);\r\n // console.log(`💡 [提示] 如需恢复,运行: cp \"${backupPath}\" \"${filePath}\"`);\r\n // } catch (error: any) {\r\n // console.error(`❌ [修复失败] ${error.message}`);\r\n // }\r\n // }\r\n}\r\n","/**\r\n * AI 诊断报告生成器\r\n */\r\n\r\nimport fs from \"fs\";\r\nimport path from \"path\";\r\n\r\nexport interface DiagnosticReport {\r\n timestamp: string;\r\n error: {\r\n type: string;\r\n message: string;\r\n file: string;\r\n stack?: string;\r\n };\r\n analysis: string;\r\n suggestion: string;\r\n fixed: boolean;\r\n fixedFilePath?: string;\r\n}\r\n\r\nexport interface MultiDiagnosticReport {\r\n timestamp: string;\r\n totalErrors: number;\r\n errors: DiagnosticReport[];\r\n}\r\n\r\nexport interface ReporterOptions {\r\n console?: boolean;\r\n html?: boolean;\r\n markdown?: boolean;\r\n json?: boolean;\r\n}\r\n\r\nexport class DiagnosticReporter {\r\n /**\r\n * 生成报告(根据配置生成多种格式)\r\n */\r\n static async generate(\r\n report: DiagnosticReport,\r\n options: ReporterOptions = {},\r\n ): Promise<void> {\r\n // HTML 报告\r\n if (options.html) {\r\n await this.generateHTMLReport(report);\r\n }\r\n\r\n // Markdown 报告\r\n if (options.markdown) {\r\n await this.generateMarkdownReport(report);\r\n }\r\n\r\n // JSON 报告\r\n if (options.json) {\r\n await this.generateJSONReport(report);\r\n }\r\n }\r\n\r\n /**\r\n * 生成 HTML 报告\r\n */\r\n static async generateHTMLReport(report: DiagnosticReport): Promise<void> {\r\n const html = `\r\n<!DOCTYPE html>\r\n<html lang=\"zh-CN\">\r\n<head>\r\n <meta charset=\"UTF-8\">\r\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n <title>AI 诊断报告</title>\r\n <style>\r\n * { margin: 0; padding: 0; box-sizing: border-box; }\r\n body {\r\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\r\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\r\n padding: 20px;\r\n min-height: 100vh;\r\n }\r\n .container {\r\n max-width: 1000px;\r\n margin: 0 auto;\r\n background: white;\r\n border-radius: 12px;\r\n box-shadow: 0 8px 32px rgba(0,0,0,0.2);\r\n overflow: hidden;\r\n }\r\n .header {\r\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\r\n color: white;\r\n padding: 30px;\r\n text-align: center;\r\n }\r\n .header h1 {\r\n font-size: 32px;\r\n margin-bottom: 10px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 10px;\r\n }\r\n .header .time {\r\n font-size: 14px;\r\n opacity: 0.9;\r\n }\r\n .content {\r\n padding: 30px;\r\n }\r\n .section {\r\n margin-bottom: 30px;\r\n }\r\n .section-title {\r\n font-size: 20px;\r\n font-weight: bold;\r\n color: #333;\r\n margin-bottom: 15px;\r\n padding-bottom: 10px;\r\n border-bottom: 2px solid #667eea;\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n }\r\n .error-box {\r\n background: #fff5f5;\r\n border-left: 4px solid #f56565;\r\n padding: 20px;\r\n border-radius: 8px;\r\n margin-bottom: 20px;\r\n }\r\n .error-type {\r\n display: inline-block;\r\n background: #f56565;\r\n color: white;\r\n padding: 4px 12px;\r\n border-radius: 12px;\r\n font-size: 12px;\r\n font-weight: bold;\r\n margin-bottom: 10px;\r\n }\r\n .error-message {\r\n font-size: 16px;\r\n color: #c53030;\r\n font-weight: 500;\r\n margin-bottom: 10px;\r\n line-height: 1.6;\r\n }\r\n .error-file {\r\n font-size: 14px;\r\n color: #666;\r\n font-family: 'Courier New', monospace;\r\n background: #f7fafc;\r\n padding: 8px 12px;\r\n border-radius: 4px;\r\n display: inline-block;\r\n }\r\n .analysis-box {\r\n background: #f0f9ff;\r\n border-left: 4px solid #3b82f6;\r\n padding: 20px;\r\n border-radius: 8px;\r\n line-height: 1.8;\r\n color: #1e40af;\r\n }\r\n .suggestion-box {\r\n background: #f0fdf4;\r\n border-left: 4px solid #10b981;\r\n padding: 20px;\r\n border-radius: 8px;\r\n line-height: 1.8;\r\n color: #065f46;\r\n }\r\n .suggestion-box pre {\r\n background: #1e293b;\r\n color: #e2e8f0;\r\n padding: 15px;\r\n border-radius: 6px;\r\n overflow-x: auto;\r\n margin: 10px 0;\r\n font-size: 14px;\r\n line-height: 1.5;\r\n }\r\n .fixed-badge {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 6px;\r\n background: #10b981;\r\n color: white;\r\n padding: 8px 16px;\r\n border-radius: 20px;\r\n font-size: 14px;\r\n font-weight: bold;\r\n }\r\n .not-fixed-badge {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 6px;\r\n background: #f59e0b;\r\n color: white;\r\n padding: 8px 16px;\r\n border-radius: 20px;\r\n font-size: 14px;\r\n font-weight: bold;\r\n }\r\n .footer {\r\n background: #f7fafc;\r\n padding: 20px;\r\n text-align: center;\r\n color: #718096;\r\n font-size: 14px;\r\n border-top: 1px solid #e2e8f0;\r\n }\r\n .stack-trace {\r\n background: #1e293b;\r\n color: #e2e8f0;\r\n padding: 15px;\r\n border-radius: 6px;\r\n overflow-x: auto;\r\n font-family: 'Courier New', monospace;\r\n font-size: 12px;\r\n line-height: 1.5;\r\n margin-top: 10px;\r\n max-height: 300px;\r\n overflow-y: auto;\r\n }\r\n </style>\r\n</head>\r\n<body>\r\n <div class=\"container\">\r\n <div class=\"header\">\r\n <h1>🤖 AI 诊断报告</h1>\r\n <div class=\"time\">生成时间: ${report.timestamp}</div>\r\n </div>\r\n\r\n <div class=\"content\">\r\n <!-- 错误信息 -->\r\n <div class=\"section\">\r\n <div class=\"section-title\">❌ 错误信息</div>\r\n <div class=\"error-box\">\r\n <span class=\"error-type\">${report.error.type}</span>\r\n <div class=\"error-message\">${this.escapeHtml(\r\n report.error.message,\r\n )}</div>\r\n <div class=\"error-file\">📂 ${report.error.file}</div>\r\n ${\r\n report.error.stack\r\n ? `<div class=\"stack-trace\">${this.escapeHtml(\r\n report.error.stack,\r\n )}</div>`\r\n : \"\"\r\n }\r\n </div>\r\n </div>\r\n\r\n <!-- AI 分析 -->\r\n <div class=\"section\">\r\n <div class=\"section-title\">🔍 AI 分析</div>\r\n <div class=\"analysis-box\">\r\n ${this.formatText(report.analysis)}\r\n </div>\r\n </div>\r\n\r\n <!-- 修复建议 -->\r\n <div class=\"section\">\r\n <div class=\"section-title\">💡 修复建议</div>\r\n <div class=\"suggestion-box\">\r\n ${this.formatText(report.suggestion)}\r\n </div>\r\n </div>\r\n\r\n <!-- 修复状态 -->\r\n <div class=\"section\">\r\n <div class=\"section-title\">🔧 修复状态</div>\r\n ${\r\n report.fixed\r\n ? `<div class=\"fixed-badge\">✅ 已自动修复</div>\r\n <div style=\"margin-top: 10px; color: #666;\">修复文件: <code>${report.fixedFilePath}</code></div>`\r\n : `<div class=\"not-fixed-badge\">⚠️ 未自动修复</div>\r\n <div style=\"margin-top: 10px; color: #666;\">请根据上述建议手动修复</div>`\r\n }\r\n </div>\r\n </div>\r\n\r\n <div class=\"footer\">\r\n <p>AI Diagnostic Plugin v1.0.0</p>\r\n <p>Powered by LangGraph & OpenAI</p>\r\n </div>\r\n </div>\r\n</body>\r\n</html>\r\n `.trim();\r\n\r\n // 创建报告目录\r\n const reportsDir = path.resolve(process.cwd(), \"ai-reports\");\r\n if (!fs.existsSync(reportsDir)) {\r\n fs.mkdirSync(reportsDir, { recursive: true });\r\n }\r\n\r\n const reportPath = path.resolve(reportsDir, \"diagnostic-report.html\");\r\n fs.writeFileSync(reportPath, html, \"utf-8\");\r\n console.log(`\\n📄 诊断报告已生成: ${reportPath}\\n`);\r\n }\r\n\r\n /**\r\n * 转义 HTML 特殊字符\r\n */\r\n private static escapeHtml(text: string): string {\r\n const map: Record<string, string> = {\r\n \"&\": \"&\",\r\n \"<\": \"<\",\r\n \">\": \">\",\r\n '\"': \""\",\r\n \"'\": \"'\",\r\n };\r\n return text.replace(/[&<>\"']/g, (m) => map[m]);\r\n }\r\n\r\n /**\r\n * 格式化文本(支持代码块和换行)\r\n */\r\n private static formatText(text: string): string {\r\n // 转义 HTML\r\n let formatted = this.escapeHtml(text);\r\n\r\n // 处理代码块\r\n formatted = formatted.replace(\r\n /```(\\w*)\\n([\\s\\S]*?)```/g,\r\n (_, lang, code) => {\r\n return `<pre><code>${code.trim()}</code></pre>`;\r\n },\r\n );\r\n\r\n // 处理行内代码\r\n formatted = formatted.replace(\r\n /`([^`]+)`/g,\r\n '<code style=\"background: #e2e8f0; padding: 2px 6px; border-radius: 3px; font-family: monospace;\">$1</code>',\r\n );\r\n\r\n // 处理换行\r\n formatted = formatted.replace(/\\n/g, \"<br>\");\r\n\r\n return formatted;\r\n }\r\n\r\n /**\r\n * 生成 Markdown 报告\r\n */\r\n static async generateMarkdownReport(report: DiagnosticReport): Promise<void> {\r\n const markdown = `# 🤖 AI 诊断报告\r\n\r\n**生成时间**: ${report.timestamp}\r\n\r\n---\r\n\r\n## ❌ 错误信息\r\n\r\n**类型**: \\`${report.error.type}\\` \r\n**文件**: \\`${report.error.file}\\` \r\n**消息**: \r\n\\`\\`\\`\r\n${report.error.message}\r\n\\`\\`\\`\r\n\r\n${\r\n report.error.stack\r\n ? `**堆栈跟踪**:\\n\\`\\`\\`\\n${report.error.stack}\\n\\`\\`\\`\\n`\r\n : \"\"\r\n}\r\n\r\n---\r\n\r\n## 🔍 AI 分析\r\n\r\n${report.analysis}\r\n\r\n---\r\n\r\n## 💡 修复建议\r\n\r\n${report.suggestion}\r\n\r\n---\r\n\r\n## 🔧 修复状态\r\n\r\n${\r\n report.fixed\r\n ? `✅ **已自动修复**\\n\\n修复文件: \\`${report.fixedFilePath}\\``\r\n : `⚠️ **未自动修复**\\n\\n请根据上述建议手动修复`\r\n}\r\n\r\n---\r\n\r\n*AI Diagnostic Plugin v1.0.0* \r\n*Powered by LangGraph & OpenAI*\r\n`;\r\n\r\n // 创建报告目录\r\n const reportsDir = path.resolve(process.cwd(), \"ai-reports\");\r\n if (!fs.existsSync(reportsDir)) {\r\n fs.mkdirSync(reportsDir, { recursive: true });\r\n }\r\n\r\n const reportPath = path.resolve(reportsDir, \"diagnostic-report.md\");\r\n fs.writeFileSync(reportPath, markdown, \"utf-8\");\r\n console.log(`📄 Markdown 报告已生成: ${reportPath}`);\r\n }\r\n\r\n /**\r\n * 生成 JSON 报告\r\n */\r\n static async generateJSONReport(report: DiagnosticReport): Promise<void> {\r\n const jsonReport = {\r\n version: \"1.0.0\",\r\n timestamp: report.timestamp,\r\n error: {\r\n type: report.error.type,\r\n message: report.error.message,\r\n file: report.error.file,\r\n stack: report.error.stack || null,\r\n },\r\n diagnosis: {\r\n analysis: report.analysis,\r\n suggestion: report.suggestion,\r\n },\r\n fix: {\r\n applied: report.fixed,\r\n filePath: report.fixedFilePath || null,\r\n },\r\n };\r\n\r\n // 创建报告目录\r\n const reportsDir = path.resolve(process.cwd(), \"ai-reports\");\r\n if (!fs.existsSync(reportsDir)) {\r\n fs.mkdirSync(reportsDir, { recursive: true });\r\n }\r\n\r\n const reportPath = path.resolve(reportsDir, \"diagnostic-report.json\");\r\n fs.writeFileSync(reportPath, JSON.stringify(jsonReport, null, 2), \"utf-8\");\r\n console.log(`📄 JSON 报告已生成: ${reportPath}`);\r\n }\r\n\r\n /**\r\n * 生成多错误合并报告\r\n */\r\n static async generateMultiReport(\r\n reports: DiagnosticReport[],\r\n options: ReporterOptions = {},\r\n ): Promise<void> {\r\n const multiReport: MultiDiagnosticReport = {\r\n timestamp: new Date().toLocaleString(\"zh-CN\"),\r\n totalErrors: reports.length,\r\n errors: reports,\r\n };\r\n\r\n // HTML 报告\r\n if (options.html) {\r\n await this.generateMultiHTMLReport(multiReport);\r\n }\r\n\r\n // Markdown 报告\r\n if (options.markdown) {\r\n await this.generateMultiMarkdownReport(multiReport);\r\n }\r\n\r\n // JSON 报告\r\n if (options.json) {\r\n await this.generateMultiJSONReport(multiReport);\r\n }\r\n }\r\n\r\n /**\r\n * 生成多错误 HTML 报告\r\n */\r\n static async generateMultiHTMLReport(\r\n report: MultiDiagnosticReport,\r\n ): Promise<void> {\r\n const errorsHtml = report.errors\r\n .map(\r\n (error, index) => `\r\n <div class=\"error-item\">\r\n <div class=\"error-number\">错误 ${index + 1} / ${\r\n report.totalErrors\r\n }</div>\r\n <div class=\"error-box\">\r\n <span class=\"error-type\">${error.error.type}</span>\r\n <div class=\"error-message\">${this.escapeHtml(\r\n error.error.message,\r\n )}</div>\r\n <div class=\"error-file\">📂 ${error.error.file}</div>\r\n ${\r\n error.error.stack\r\n ? `<div class=\"stack-trace\">${this.escapeHtml(\r\n error.error.stack,\r\n )}</div>`\r\n : \"\"\r\n }\r\n </div>\r\n\r\n <div class=\"section\">\r\n <div class=\"section-title\">🔍 AI 分析</div>\r\n <div class=\"analysis-box\">\r\n ${this.formatText(error.analysis)}\r\n </div>\r\n </div>\r\n\r\n <div class=\"section\">\r\n <div class=\"section-title\">💡 修复建议</div>\r\n <div class=\"suggestion-box\">\r\n ${this.formatText(error.suggestion)}\r\n </div>\r\n </div>\r\n\r\n <div class=\"section\">\r\n <div class=\"section-title\">🔧 修复状态</div>\r\n ${\r\n error.fixed\r\n ? `<div class=\"fixed-badge\">✅ 已自动修复</div>\r\n <div style=\"margin-top: 10px; color: #666;\">修复文件: <code>${error.fixedFilePath}</code></div>`\r\n : `<div class=\"not-fixed-badge\">⚠️ 未自动修复</div>\r\n <div style=\"margin-top: 10px; color: #666;\">请根据上述建议手动修复</div>`\r\n }\r\n </div>\r\n </div>\r\n `,\r\n )\r\n .join(\"\");\r\n\r\n const html = `\r\n<!DOCTYPE html>\r\n<html lang=\"zh-CN\">\r\n<head>\r\n <meta charset=\"UTF-8\">\r\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n <title>AI 诊断报告 - ${report.totalErrors} 个错误</title>\r\n <style>\r\n * { margin: 0; padding: 0; box-sizing: border-box; }\r\n body {\r\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\r\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\r\n padding: 20px;\r\n min-height: 100vh;\r\n }\r\n .container {\r\n max-width: 1000px;\r\n margin: 0 auto;\r\n background: white;\r\n border-radius: 12px;\r\n box-shadow: 0 8px 32px rgba(0,0,0,0.2);\r\n overflow: hidden;\r\n }\r\n .header {\r\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\r\n color: white;\r\n padding: 30px;\r\n text-align: center;\r\n }\r\n .header h1 {\r\n font-size: 32px;\r\n margin-bottom: 10px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 10px;\r\n }\r\n .header .time {\r\n font-size: 14px;\r\n opacity: 0.9;\r\n }\r\n .header .error-count {\r\n font-size: 18px;\r\n margin-top: 10px;\r\n background: rgba(255,255,255,0.2);\r\n padding: 8px 16px;\r\n border-radius: 20px;\r\n display: inline-block;\r\n }\r\n .content {\r\n padding: 30px;\r\n }\r\n .error-item {\r\n margin-bottom: 40px;\r\n padding-bottom: 40px;\r\n border-bottom: 2px dashed #e2e8f0;\r\n }\r\n .error-item:last-child {\r\n border-bottom: none;\r\n margin-bottom: 0;\r\n padding-bottom: 0;\r\n }\r\n .error-number {\r\n font-size: 16px;\r\n font-weight: bold;\r\n color: #667eea;\r\n margin-bottom: 15px;\r\n padding: 8px 16px;\r\n background: #f0f9ff;\r\n border-radius: 8px;\r\n display: inline-block;\r\n }\r\n .section {\r\n margin-bottom: 20px;\r\n }\r\n .section-title {\r\n font-size: 18px;\r\n font-weight: bold;\r\n color: #333;\r\n margin-bottom: 12px;\r\n padding-bottom: 8px;\r\n border-bottom: 2px solid #667eea;\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n }\r\n .error-box {\r\n background: #fff5f5;\r\n border-left: 4px solid #f56565;\r\n padding: 20px;\r\n border-radius: 8px;\r\n margin-bottom: 20px;\r\n }\r\n .error-type {\r\n display: inline-block;\r\n background: #f56565;\r\n color: white;\r\n padding: 4px 12px;\r\n border-radius: 12px;\r\n font-size: 12px;\r\n font-weight: bold;\r\n margin-bottom: 10px;\r\n }\r\n .error-message {\r\n font-size: 16px;\r\n color: #c53030;\r\n font-weight: 500;\r\n margin-bottom: 10px;\r\n line-height: 1.6;\r\n }\r\n .error-file {\r\n font-size: 14px;\r\n color: #666;\r\n font-family: 'Courier New', monospace;\r\n background: #f7fafc;\r\n padding: 8px 12px;\r\n border-radius: 4px;\r\n display: inline-block;\r\n }\r\n .analysis-box {\r\n background: #f0f9ff;\r\n border-left: 4px solid #3b82f6;\r\n padding: 20px;\r\n border-radius: 8px;\r\n line-height: 1.8;\r\n color: #1e40af;\r\n }\r\n .suggestion-box {\r\n background: #f0fdf4;\r\n border-left: 4px solid #10b981;\r\n padding: 20px;\r\n border-radius: 8px;\r\n line-height: 1.8;\r\n color: #065f46;\r\n }\r\n .suggestion-box pre {\r\n background: #1e293b;\r\n color: #e2e8f0;\r\n padding: 15px;\r\n border-radius: 6px;\r\n overflow-x: auto;\r\n margin: 10px 0;\r\n font-size: 14px;\r\n line-height: 1.5;\r\n }\r\n .fixed-badge {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 6px;\r\n background: #10b981;\r\n color: white;\r\n padding: 8px 16px;\r\n border-radius: 20px;\r\n font-size: 14px;\r\n font-weight: bold;\r\n }\r\n .not-fixed-badge {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 6px;\r\n background: #f59e0b;\r\n color: white;\r\n padding: 8px 16px;\r\n border-radius: 20px;\r\n font-size: 14px;\r\n font-weight: bold;\r\n }\r\n .footer {\r\n background: #f7fafc;\r\n padding: 20px;\r\n text-align: center;\r\n color: #718096;\r\n font-size: 14px;\r\n border-top: 1px solid #e2e8f0;\r\n }\r\n .stack-trace {\r\n background: #1e293b;\r\n color: #e2e8f0;\r\n padding: 15px;\r\n border-radius: 6px;\r\n overflow-x: auto;\r\n font-family: 'Courier New', monospace;\r\n font-size: 12px;\r\n line-height: 1.5;\r\n margin-top: 10px;\r\n max-height: 300px;\r\n overflow-y: auto;\r\n }\r\n </style>\r\n</head>\r\n<body>\r\n <div class=\"container\">\r\n <div class=\"header\">\r\n <h1>🤖 AI 诊断报告</h1>\r\n <div class=\"time\">生成时间: ${report.timestamp}</div>\r\n <div class=\"error-count\">共发现 ${report.totalErrors} 个错误</div>\r\n </div>\r\n\r\n <div class=\"content\">\r\n ${errorsHtml}\r\n </div>\r\n\r\n <div class=\"footer\">\r\n <p>AI Diagnostic Plugin v1.0.7</p>\r\n <p>Powered by LangGraph & OpenAI</p>\r\n </div>\r\n </div>\r\n</body>\r\n</html>\r\n `.trim();\r\n\r\n // 创建报告目录\r\n const reportsDir = path.resolve(process.cwd(), \"ai-reports\");\r\n if (!fs.existsSync(reportsDir)) {\r\n fs.mkdirSync(reportsDir, { recursive: true });\r\n }\r\n\r\n const reportPath = path.resolve(reportsDir, \"diagnostic-report.html\");\r\n fs.writeFileSync(reportPath, html, \"utf-8\");\r\n console.log(\r\n `\\n📄 诊断报告已生成: ${reportPath} (${report.totalErrors} 个错误)\\n`,\r\n );\r\n }\r\n\r\n /**\r\n * 生成多错误 Markdown 报告\r\n */\r\n static async generateMultiMarkdownReport(\r\n report: MultiDiagnosticReport,\r\n ): Promise<void> {\r\n const errorsMarkdown = report.errors\r\n .map(\r\n (error, index) => `\r\n## 错误 ${index + 1} / ${report.totalErrors}\r\n\r\n### ❌ 错误信息\r\n\r\n**类型**: \\`${error.error.type}\\` \r\n**文件**: \\`${error.error.file}\\` \r\n**消息**: \r\n\\`\\`\\`\r\n${error.error.message}\r\n\\`\\`\\`\r\n\r\n${\r\n error.error.stack\r\n ? `**堆栈跟踪**:\\n\\`\\`\\`\\n${error.error.stack}\\n\\`\\`\\`\\n`\r\n : \"\"\r\n}\r\n\r\n### 🔍 AI 分析\r\n\r\n${error.analysis}\r\n\r\n### 💡 修复建议\r\n\r\n${error.suggestion}\r\n\r\n### 🔧 修复状态\r\n\r\n${\r\n error.fixed\r\n ? `✅ **已自动修复**\\n\\n修复文件: \\`${error.fixedFilePath}\\``\r\n : `⚠️ **未自动修复**\\n\\n请根据上述建议手动修复`\r\n}\r\n\r\n---\r\n`,\r\n )\r\n .join(\"\\n\");\r\n\r\n const markdown = `# 🤖 AI 诊断报告\r\n\r\n**生成时间**: ${report.timestamp} \r\n**错误总数**: ${report.totalErrors}\r\n\r\n---\r\n\r\n${errorsMarkdown}\r\n\r\n*AI Diagnostic Plugin v1.0.7* \r\n*Powered by LangGraph & OpenAI*\r\n`;\r\n\r\n // 创建报告目录\r\n const reportsDir = path.resolve(process.cwd(), \"ai-reports\");\r\n if (!fs.existsSync(reportsDir)) {\r\n fs.mkdirSync(reportsDir, { recursive: true });\r\n }\r\n\r\n const reportPath = path.resolve(reportsDir, \"diagnostic-report.md\");\r\n fs.writeFileSync(reportPath, markdown, \"utf-8\");\r\n console.log(`📄 Markdown 报告已生成: ${reportPath}`);\r\n }\r\n\r\n /**\r\n * 生成多错误 JSON 报告\r\n */\r\n static async generateMultiJSONReport(\r\n report: MultiDiagnosticReport,\r\n ): Promise<void> {\r\n const jsonReport = {\r\n version: \"1.0.7\",\r\n timestamp: report.timestamp,\r\n totalErrors: report.totalErrors,\r\n errors: report.errors.map((error) => ({\r\n error: {\r\n type: error.error.type,\r\n message: error.error.message,\r\n file: error.error.file,\r\n stack: error.error.stack || null,\r\n },\r\n diagnosis: {\r\n analysis: error.analysis,\r\n suggestion: error.suggestion,\r\n },\r\n fix: {\r\n applied: error.fixed,\r\n filePath: error.fixedFilePath || null,\r\n },\r\n })),\r\n };\r\n\r\n // 创建报告目录\r\n const reportsDir = path.resolve(process.cwd(), \"ai-reports\");\r\n if (!fs.existsSync(reportsDir)) {\r\n fs.mkdirSync(reportsDir, { recursive: true });\r\n }\r\n\r\n const reportPath = path.resolve(reportsDir, \"diagnostic-report.json\");\r\n fs.writeFileSync(reportPath, JSON.stringify(jsonReport, null, 2), \"utf-8\");\r\n console.log(`📄 JSON 报告已生成: ${reportPath}`);\r\n }\r\n}\r\n"],"mappings":"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","names":["fs","path","error","error","path","fs","options"]}
|