115 lines
4.4 KiB
JavaScript
115 lines
4.4 KiB
JavaScript
import { exec } from "child_process";
|
||
import { promisify } from "util";
|
||
import { existsSync, readFileSync } from "fs";
|
||
import { join } from "path";
|
||
const execAsync = promisify(exec);
|
||
export const buildProjectTool = {
|
||
name: "build_project",
|
||
description: "构建项目。自动检测构建方式(npm run build、tsc、vite build、webpack 等),执行构建并返回结果。如果构建失败,返回错误详情供自动修复。",
|
||
inputSchema: {
|
||
type: "object",
|
||
properties: {
|
||
project_path: {
|
||
type: "string",
|
||
description: "项目根目录(绝对路径)",
|
||
},
|
||
command: {
|
||
type: "string",
|
||
description: "自定义构建命令(可选,默认自动检测)",
|
||
},
|
||
},
|
||
required: ["project_path"],
|
||
},
|
||
};
|
||
async function runBuild(cmd, cwd) {
|
||
const start = Date.now();
|
||
try {
|
||
const { stdout, stderr } = await execAsync(cmd, {
|
||
cwd,
|
||
timeout: 300000, // 5分钟
|
||
maxBuffer: 1024 * 1024 * 10,
|
||
shell: process.platform === "win32" ? "powershell.exe" : "/bin/bash",
|
||
});
|
||
return { stdout, stderr, code: 0, duration: Date.now() - start };
|
||
}
|
||
catch (error) {
|
||
return {
|
||
stdout: error.stdout || "",
|
||
stderr: error.stderr || "",
|
||
code: error.code ?? 1,
|
||
duration: Date.now() - start,
|
||
};
|
||
}
|
||
}
|
||
export async function executeBuildProject(args) {
|
||
const { project_path, command } = args;
|
||
const hasFile = (name) => existsSync(join(project_path, name));
|
||
let buildCmd = command || "";
|
||
let buildTool = "自定义";
|
||
if (!buildCmd) {
|
||
// 自动检测构建方式
|
||
if (hasFile("package.json")) {
|
||
try {
|
||
const pkg = JSON.parse(readFileSync(join(project_path, "package.json"), "utf-8"));
|
||
if (pkg.scripts?.build) {
|
||
buildCmd = "npm run build";
|
||
buildTool = `npm (${pkg.scripts.build})`;
|
||
}
|
||
else if (hasFile("tsconfig.json")) {
|
||
buildCmd = "npx tsc";
|
||
buildTool = "TypeScript (tsc)";
|
||
}
|
||
}
|
||
catch { }
|
||
}
|
||
else if (hasFile("Makefile")) {
|
||
buildCmd = "make";
|
||
buildTool = "Make";
|
||
}
|
||
else if (hasFile("setup.py") || hasFile("pyproject.toml")) {
|
||
buildCmd = "python -m build 2>&1 || python setup.py build 2>&1";
|
||
buildTool = "Python";
|
||
}
|
||
}
|
||
if (!buildCmd) {
|
||
return `# 构建结果\n\n⚠️ 未检测到构建配置\n项目路径: ${project_path}\n\n建议手动指定 command 参数`;
|
||
}
|
||
// 检查依赖是否安装
|
||
if (hasFile("package.json") && !hasFile("node_modules")) {
|
||
const installResult = await runBuild("npm install", project_path);
|
||
if (installResult.code !== 0) {
|
||
return `# 构建失败\n\n❌ 依赖安装失败 (npm install)\n\n\`\`\`\n${installResult.stderr || installResult.stdout}\n\`\`\``;
|
||
}
|
||
}
|
||
const result = await runBuild(buildCmd, project_path);
|
||
const fullOutput = (result.stdout + "\n" + result.stderr).trim();
|
||
// 提取错误信息
|
||
const errors = [];
|
||
const lines = fullOutput.split("\n");
|
||
for (const line of lines) {
|
||
if (/error\s+TS\d+/i.test(line) || /Error:/i.test(line) || /ERROR/i.test(line) || /Failed/i.test(line)) {
|
||
errors.push(line.trim());
|
||
}
|
||
}
|
||
const output = [
|
||
`# 构建报告`,
|
||
``,
|
||
`📂 项目: ${project_path}`,
|
||
`🔧 工具: ${buildTool}`,
|
||
`⏱️ 耗时: ${(result.duration / 1000).toFixed(1)}s`,
|
||
`${result.code === 0 ? "✅ **构建成功**" : "❌ **构建失败**"}`,
|
||
``,
|
||
`## 命令`,
|
||
`\`${buildCmd}\``,
|
||
``,
|
||
];
|
||
if (errors.length > 0 && result.code !== 0) {
|
||
output.push(`## 错误摘要(${errors.length} 项)`, ...errors.slice(0, 20).map((e) => `- ${e}`), errors.length > 20 ? `\n... 还有 ${errors.length - 20} 项错误` : "", ``);
|
||
}
|
||
output.push(`## 完整输出`, "```", fullOutput.slice(0, 5000), "```");
|
||
if (result.code !== 0) {
|
||
output.push(``, `## 自动修复建议`, `1. 使用 code_debug 分析上方错误`, `2. 修复代码后重新运行 build_project`, `3. 或使用 lint_check 先检查代码质量`);
|
||
}
|
||
return output.join("\n");
|
||
}
|
||
//# sourceMappingURL=buildProject.js.map
|