Update code
This commit is contained in:
196
dev-assistant-mcp/dist/tools/projectScan.js
vendored
Normal file
196
dev-assistant-mcp/dist/tools/projectScan.js
vendored
Normal file
@@ -0,0 +1,196 @@
|
||||
import { existsSync, readFileSync, readdirSync, statSync } from "fs";
|
||||
import { join, extname } from "path";
|
||||
export const projectScanTool = {
|
||||
name: "project_scan",
|
||||
description: "扫描分析项目结构。返回项目类型、技术栈、文件结构、依赖列表、可用脚本、配置文件等全局信息,帮助快速理解项目。",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
project_path: {
|
||||
type: "string",
|
||||
description: "项目根目录(绝对路径)",
|
||||
},
|
||||
max_depth: {
|
||||
type: "number",
|
||||
description: "目录扫描最大深度(默认 3)",
|
||||
},
|
||||
},
|
||||
required: ["project_path"],
|
||||
},
|
||||
};
|
||||
function scanDir(dir, depth, maxDepth, prefix = "") {
|
||||
if (depth > maxDepth)
|
||||
return [];
|
||||
const lines = [];
|
||||
try {
|
||||
const entries = readdirSync(dir).filter((e) => !e.startsWith(".") && e !== "node_modules" && e !== "__pycache__" && e !== "dist" && e !== "build" && e !== ".git");
|
||||
for (const entry of entries.slice(0, 30)) { // 限制每层最多30项
|
||||
const fullPath = join(dir, entry);
|
||||
try {
|
||||
const stat = statSync(fullPath);
|
||||
if (stat.isDirectory()) {
|
||||
lines.push(`${prefix}📂 ${entry}/`);
|
||||
lines.push(...scanDir(fullPath, depth + 1, maxDepth, prefix + " "));
|
||||
}
|
||||
else {
|
||||
const size = stat.size;
|
||||
const sizeStr = size < 1024 ? `${size}B` : size < 1024 * 1024 ? `${(size / 1024).toFixed(0)}KB` : `${(size / 1024 / 1024).toFixed(1)}MB`;
|
||||
lines.push(`${prefix}📄 ${entry} (${sizeStr})`);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
if (entries.length > 30) {
|
||||
lines.push(`${prefix}... 还有 ${entries.length - 30} 个条目`);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
return lines;
|
||||
}
|
||||
function countFiles(dir, ext, depth = 0) {
|
||||
if (depth > 5)
|
||||
return 0;
|
||||
let count = 0;
|
||||
try {
|
||||
for (const entry of readdirSync(dir)) {
|
||||
if (entry.startsWith(".") || entry === "node_modules" || entry === "__pycache__" || entry === "dist")
|
||||
continue;
|
||||
const fullPath = join(dir, entry);
|
||||
try {
|
||||
const stat = statSync(fullPath);
|
||||
if (stat.isDirectory())
|
||||
count += countFiles(fullPath, ext, depth + 1);
|
||||
else if (extname(entry) === ext)
|
||||
count++;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
return count;
|
||||
}
|
||||
export async function executeProjectScan(args) {
|
||||
const { project_path, max_depth = 3 } = args;
|
||||
const hasFile = (name) => existsSync(join(project_path, name));
|
||||
const readJson = (name) => {
|
||||
try {
|
||||
return JSON.parse(readFileSync(join(project_path, name), "utf-8"));
|
||||
}
|
||||
catch {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
const output = [
|
||||
`# 项目分析报告`,
|
||||
``,
|
||||
`📂 路径: ${project_path}`,
|
||||
``,
|
||||
];
|
||||
// 项目类型和技术栈检测
|
||||
const techStack = [];
|
||||
const configs = [];
|
||||
if (hasFile("package.json"))
|
||||
techStack.push("Node.js");
|
||||
if (hasFile("tsconfig.json"))
|
||||
techStack.push("TypeScript");
|
||||
if (hasFile("next.config.js") || hasFile("next.config.mjs") || hasFile("next.config.ts"))
|
||||
techStack.push("Next.js");
|
||||
if (hasFile("vite.config.ts") || hasFile("vite.config.js"))
|
||||
techStack.push("Vite");
|
||||
if (hasFile("webpack.config.js"))
|
||||
techStack.push("Webpack");
|
||||
if (hasFile("requirements.txt") || hasFile("pyproject.toml"))
|
||||
techStack.push("Python");
|
||||
if (hasFile("Cargo.toml"))
|
||||
techStack.push("Rust");
|
||||
if (hasFile("go.mod"))
|
||||
techStack.push("Go");
|
||||
if (hasFile("pom.xml") || hasFile("build.gradle"))
|
||||
techStack.push("Java");
|
||||
if (hasFile("docker-compose.yml") || hasFile("Dockerfile"))
|
||||
techStack.push("Docker");
|
||||
if (hasFile(".eslintrc.js") || hasFile("eslint.config.js"))
|
||||
configs.push("ESLint");
|
||||
if (hasFile(".prettierrc") || hasFile(".prettierrc.json"))
|
||||
configs.push("Prettier");
|
||||
if (hasFile("jest.config.js") || hasFile("jest.config.ts"))
|
||||
configs.push("Jest");
|
||||
if (hasFile("vitest.config.ts"))
|
||||
configs.push("Vitest");
|
||||
if (hasFile(".env") || hasFile(".env.example"))
|
||||
configs.push(".env");
|
||||
output.push(`## 技术栈`, techStack.length > 0 ? techStack.join(" + ") : "未检测到", ``);
|
||||
if (configs.length > 0) {
|
||||
output.push(`## 工具配置`, configs.join(", "), ``);
|
||||
}
|
||||
// package.json 分析
|
||||
const pkg = readJson("package.json");
|
||||
if (pkg) {
|
||||
output.push(`## package.json`);
|
||||
if (pkg.name)
|
||||
output.push(`- **名称**: ${pkg.name}`);
|
||||
if (pkg.version)
|
||||
output.push(`- **版本**: ${pkg.version}`);
|
||||
if (pkg.description)
|
||||
output.push(`- **描述**: ${pkg.description}`);
|
||||
if (pkg.scripts && Object.keys(pkg.scripts).length > 0) {
|
||||
output.push(``, `### 可用脚本`);
|
||||
for (const [name, cmd] of Object.entries(pkg.scripts)) {
|
||||
output.push(`- \`npm run ${name}\` → ${cmd}`);
|
||||
}
|
||||
}
|
||||
if (pkg.dependencies) {
|
||||
const deps = Object.entries(pkg.dependencies);
|
||||
output.push(``, `### 依赖 (${deps.length})`);
|
||||
for (const [name, ver] of deps.slice(0, 20)) {
|
||||
output.push(`- ${name}: ${ver}`);
|
||||
}
|
||||
if (deps.length > 20)
|
||||
output.push(`... 还有 ${deps.length - 20} 个`);
|
||||
}
|
||||
if (pkg.devDependencies) {
|
||||
const devDeps = Object.entries(pkg.devDependencies);
|
||||
output.push(``, `### 开发依赖 (${devDeps.length})`);
|
||||
for (const [name, ver] of devDeps.slice(0, 15)) {
|
||||
output.push(`- ${name}: ${ver}`);
|
||||
}
|
||||
if (devDeps.length > 15)
|
||||
output.push(`... 还有 ${devDeps.length - 15} 个`);
|
||||
}
|
||||
output.push(``);
|
||||
}
|
||||
// Python 依赖
|
||||
if (hasFile("requirements.txt")) {
|
||||
try {
|
||||
const reqs = readFileSync(join(project_path, "requirements.txt"), "utf-8")
|
||||
.split("\n").filter((l) => l.trim() && !l.startsWith("#"));
|
||||
output.push(`## Python 依赖 (${reqs.length})`);
|
||||
for (const r of reqs.slice(0, 20))
|
||||
output.push(`- ${r.trim()}`);
|
||||
if (reqs.length > 20)
|
||||
output.push(`... 还有 ${reqs.length - 20} 个`);
|
||||
output.push(``);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
// 文件统计
|
||||
const fileCounts = {};
|
||||
for (const ext of [".ts", ".tsx", ".js", ".jsx", ".py", ".css", ".html", ".json", ".md"]) {
|
||||
const count = countFiles(project_path, ext);
|
||||
if (count > 0)
|
||||
fileCounts[ext] = count;
|
||||
}
|
||||
if (Object.keys(fileCounts).length > 0) {
|
||||
output.push(`## 文件统计`);
|
||||
for (const [ext, count] of Object.entries(fileCounts).sort((a, b) => b[1] - a[1])) {
|
||||
output.push(`- ${ext}: ${count} 个文件`);
|
||||
}
|
||||
output.push(``);
|
||||
}
|
||||
// 目录树
|
||||
output.push(`## 目录结构`);
|
||||
const tree = scanDir(project_path, 0, max_depth);
|
||||
output.push(...tree);
|
||||
return output.join("\n");
|
||||
}
|
||||
//# sourceMappingURL=projectScan.js.map
|
||||
Reference in New Issue
Block a user