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