Update code

This commit is contained in:
User
2026-03-12 12:47:56 +08:00
parent 92e7fc5bda
commit 9dab61345c
9383 changed files with 1463454 additions and 1 deletions

2
dev-assistant-mcp/dist/index.d.ts vendored Normal file
View File

@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=index.d.ts.map

1
dev-assistant-mcp/dist/index.d.ts.map vendored Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}

183
dev-assistant-mcp/dist/index.js vendored Normal file
View File

@@ -0,0 +1,183 @@
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
// ===== 分析工具 =====
import { codeReviewTool, executeCodeReview } from "./tools/codeReview.js";
import { codeWriteTool, executeCodeWrite } from "./tools/codeWrite.js";
import { codeDebugTool, executeCodeDebug } from "./tools/codeDebug.js";
import { docWriteTool, executeDocWrite } from "./tools/docWrite.js";
// ===== 本地执行工具(自动化闭环核心) =====
import { execCommandTool, executeExecCommand } from "./tools/execCommand.js";
import { lintCheckTool, executeLintCheck } from "./tools/lintCheck.js";
import { autoFixTool, executeAutoFix } from "./tools/autoFix.js";
import { runTestsTool, executeRunTests } from "./tools/runTests.js";
import { buildProjectTool, executeBuildProject } from "./tools/buildProject.js";
import { projectScanTool, executeProjectScan } from "./tools/projectScan.js";
import { readFileTool, executeReadFile, writeFileTool, executeWriteFile, patchFileTool, executePatchFile, } from "./tools/fileOps.js";
// ===== 高级工具(极致版) =====
import { gitOpsTool, executeGitOps } from "./tools/gitOps.js";
import { depManageTool, executeDepManage } from "./tools/depManage.js";
import { searchCodeTool, executeSearchCode } from "./tools/searchCode.js";
import { devServerTool, executeDevServer } from "./tools/devServer.js";
import { envCheckTool, executeEnvCheck } from "./tools/envCheck.js";
import { workflowTool, executeWorkflow } from "./tools/workflow.js";
// ===== 资源 =====
import { codingStandardsResource, getCodingStandards, } from "./resources/codingStandards.js";
import { debugGuideResource, getDebugGuide } from "./resources/debugGuide.js";
import { docTemplatesResource, getDocTemplates, } from "./resources/docTemplates.js";
// ========== MCP Server ==========
const server = new Server({ name: "dev-assistant", version: "2.0.0" }, { capabilities: { tools: {}, resources: {} } });
// ========== 注册工具列表 ==========
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
// 分析工具
codeReviewTool, codeWriteTool, codeDebugTool, docWriteTool,
// 本地执行工具(自动化闭环核心)
execCommandTool, lintCheckTool, autoFixTool, runTestsTool,
buildProjectTool, projectScanTool,
readFileTool, writeFileTool, patchFileTool,
// 高级工具(极致版)
gitOpsTool, depManageTool, searchCodeTool,
devServerTool, envCheckTool, workflowTool,
],
}));
// ========== 工具执行 ==========
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
let result;
switch (name) {
// 分析工具
case "code_review":
result = await executeCodeReview(args);
break;
case "code_write":
result = await executeCodeWrite(args);
break;
case "code_debug":
result = await executeCodeDebug(args);
break;
case "doc_write":
result = await executeDocWrite(args);
break;
// 本地执行工具
case "exec_command":
result = await executeExecCommand(args);
break;
case "lint_check":
result = await executeLintCheck(args);
break;
case "auto_fix":
result = await executeAutoFix(args);
break;
case "run_tests":
result = await executeRunTests(args);
break;
case "build_project":
result = await executeBuildProject(args);
break;
case "project_scan":
result = await executeProjectScan(args);
break;
// 文件操作
case "read_local_file":
result = await executeReadFile(args);
break;
case "write_local_file":
result = await executeWriteFile(args);
break;
case "patch_file":
result = await executePatchFile(args);
break;
// 高级工具
case "git_ops":
result = await executeGitOps(args);
break;
case "dep_manage":
result = await executeDepManage(args);
break;
case "search_code":
result = await executeSearchCode(args);
break;
case "dev_server":
result = await executeDevServer(args);
break;
case "env_check":
result = await executeEnvCheck(args);
break;
case "workflow":
result = await executeWorkflow(args);
break;
default:
return {
content: [{ type: "text", text: `未知工具: ${name}` }],
isError: true,
};
}
return { content: [{ type: "text", text: result }] };
}
catch (error) {
return {
content: [
{
type: "text",
text: `执行出错: ${error.message}`,
},
],
isError: true,
};
}
});
// ========== 注册资源列表 ==========
server.setRequestHandler(ListResourcesRequestSchema, async () => ({
resources: [codingStandardsResource, debugGuideResource, docTemplatesResource],
}));
// ========== 资源读取 ==========
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
const { uri } = request.params;
switch (uri) {
case codingStandardsResource.uri:
return {
contents: [
{
uri,
mimeType: "text/markdown",
text: getCodingStandards(),
},
],
};
case debugGuideResource.uri:
return {
contents: [
{
uri,
mimeType: "text/markdown",
text: getDebugGuide(),
},
],
};
case docTemplatesResource.uri:
return {
contents: [
{
uri,
mimeType: "text/markdown",
text: getDocTemplates(),
},
],
};
default:
throw new Error(`未知资源: ${uri}`);
}
});
// ========== 启动 ==========
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Dev Assistant MCP Server v2.0.0 (19 tools) running on stdio");
}
main().catch((err) => {
console.error("Fatal:", err);
process.exit(1);
});
//# sourceMappingURL=index.js.map

1
dev-assistant-mcp/dist/index.js.map vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,8 @@
export declare const codingStandardsResource: {
uri: string;
name: string;
description: string;
mimeType: string;
};
export declare function getCodingStandards(): string;
//# sourceMappingURL=codingStandards.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"codingStandards.d.ts","sourceRoot":"","sources":["../../src/resources/codingStandards.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,uBAAuB;;;;;CAKnC,CAAC;AAEF,wBAAgB,kBAAkB,IAAI,MAAM,CA2B3C"}

View File

@@ -0,0 +1,35 @@
export const codingStandardsResource = {
uri: "devassistant://resources/coding-standards",
name: "编码规范",
description: "各主流语言的编码最佳实践和规范",
mimeType: "text/markdown",
};
export function getCodingStandards() {
return `# 编码规范速查
## TypeScript / JavaScript
- 使用 \`const\` 优先,\`let\` 次之,禁用 \`var\`
- 函数和变量使用 camelCase类和接口使用 PascalCase
- 优先使用 \`async/await\` 而非回调和 \`.then()\`
- 使用严格类型,避免 \`any\`
- 错误处理:始终 catch 异步操作的异常
- 单个函数不超过 50 行,单个文件不超过 300 行
## Python
- 遵循 PEP 8 规范
- 函数和变量使用 snake_case类使用 PascalCase
- 使用 type hints 标注参数和返回值
- 使用 f-string 格式化字符串
- 使用 \`with\` 语句管理资源
- 使用 \`pathlib\` 替代 \`os.path\`
## 通用原则
- **DRY** — Don't Repeat Yourself消除重复代码
- **KISS** — Keep It Simple, Stupid保持简单
- **单一职责** — 每个函数/类只做一件事
- **提前返回** — 用 guard clause 减少嵌套
- **有意义的命名** — 变量名应表达意图,不用缩写
- **最小暴露** — 只暴露必要的公开接口
`;
}
//# sourceMappingURL=codingStandards.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"codingStandards.js","sourceRoot":"","sources":["../../src/resources/codingStandards.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,GAAG,EAAE,2CAA2C;IAChD,IAAI,EAAE,MAAM;IACZ,WAAW,EAAE,iBAAiB;IAC9B,QAAQ,EAAE,eAAe;CAC1B,CAAC;AAEF,MAAM,UAAU,kBAAkB;IAChC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;CAyBR,CAAC;AACF,CAAC"}

View File

@@ -0,0 +1,8 @@
export declare const debugGuideResource: {
uri: string;
name: string;
description: string;
mimeType: string;
};
export declare function getDebugGuide(): string;
//# sourceMappingURL=debugGuide.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"debugGuide.d.ts","sourceRoot":"","sources":["../../src/resources/debugGuide.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,kBAAkB;;;;;CAK9B,CAAC;AAEF,wBAAgB,aAAa,IAAI,MAAM,CA4CtC"}

View File

@@ -0,0 +1,52 @@
export const debugGuideResource = {
uri: "devassistant://resources/debug-guide",
name: "调试指南",
description: "常见错误模式和排查方法",
mimeType: "text/markdown",
};
export function getDebugGuide() {
return `# 调试指南
## 调试步骤
1. **复现问题** — 找到稳定的复现路径
2. **阅读错误信息** — 仔细看完整报错和堆栈
3. **缩小范围** — 二分法定位问题代码
4. **检查假设** — 用 console.log / print 验证变量值
5. **查看变更** — git diff 看最近改了什么
6. **搜索已知问题** — Google / StackOverflow / GitHub Issues
## 常见错误模式
### TypeError: Cannot read properties of undefined
- **原因**:访问了 null/undefined 的属性
- **排查**:检查调用链上哪个变量可能为空
- **修复**:使用可选链 \`?.\` 或提前判空
### ECONNREFUSED / ETIMEDOUT
- **原因**:网络连接被拒绝或超时
- **排查**:检查目标服务是否启动、端口是否正确、防火墙规则
- **修复**:确认服务地址和端口,添加重试机制
### Memory Leak
- **表现**:内存持续增长不释放
- **排查**:检查未清理的定时器、事件监听器、闭包引用
- **修复**:在组件销毁/函数退出时清理资源
### Race Condition
- **表现**:偶发的数据不一致
- **排查**:检查并发操作共享状态
- **修复**:加锁、使用原子操作、或重新设计数据流
### Import/Module Error
- **原因**:路径错误、循环依赖、导出方式不匹配
- **排查**检查文件路径、ESM vs CJS、default vs named export
- **修复**:修正导入路径和方式
## 调试工具
- **Node.js**: \`node --inspect\`, Chrome DevTools
- **Python**: \`pdb\`, \`ipdb\`, VS Code debugger
- **浏览器**: Chrome DevTools (Sources, Network, Console)
- **通用**: \`git bisect\` 定位引入 bug 的提交
`;
}
//# sourceMappingURL=debugGuide.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"debugGuide.js","sourceRoot":"","sources":["../../src/resources/debugGuide.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,GAAG,EAAE,sCAAsC;IAC3C,IAAI,EAAE,MAAM;IACZ,WAAW,EAAE,aAAa;IAC1B,QAAQ,EAAE,eAAe;CAC1B,CAAC;AAEF,MAAM,UAAU,aAAa;IAC3B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0CR,CAAC;AACF,CAAC"}

View File

@@ -0,0 +1,8 @@
export declare const docTemplatesResource: {
uri: string;
name: string;
description: string;
mimeType: string;
};
export declare function getDocTemplates(): string;
//# sourceMappingURL=docTemplates.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"docTemplates.d.ts","sourceRoot":"","sources":["../../src/resources/docTemplates.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,oBAAoB;;;;;CAKhC,CAAC;AAEF,wBAAgB,eAAe,IAAI,MAAM,CAiGxC"}

View File

@@ -0,0 +1,105 @@
export const docTemplatesResource = {
uri: "devassistant://resources/doc-templates",
name: "文档模板",
description: "README、API 文档、CHANGELOG 等标准模板",
mimeType: "text/markdown",
};
export function getDocTemplates() {
return `# 文档模板集合
---
## README.md 模板
\`\`\`markdown
# 项目名称
简短的项目描述(一句话)。
## 功能特性
- 特性 1
- 特性 2
## 快速开始
### 环境要求
- Node.js >= 18
### 安装
\\\`\\\`\\\`bash
npm install
\\\`\\\`\\\`
### 配置
复制 \`.env.example\`\`.env\`,填写配置。
### 运行
\\\`\\\`\\\`bash
npm start
\\\`\\\`\\\`
## 项目结构
\\\`\\\`\\\`
src/
├── index.ts # 入口
├── routes/ # 路由
├── services/ # 业务逻辑
└── utils/ # 工具函数
\\\`\\\`\\\`
## API 文档
见 [API.md](./API.md)
## License
MIT
\`\`\`
---
## API 文档模板
\`\`\`markdown
# API 文档
## Base URL
\\\`https://api.example.com/v1\\\`
## 认证
Header: \\\`Authorization: Bearer <token>\\\`
## 端点
### POST /endpoint
描述
**请求参数**
| 字段 | 类型 | 必填 | 描述 |
|------|------|------|------|
| name | string | 是 | 名称 |
**响应**
\\\`\\\`\\\`json
{ "code": 0, "data": {} }
\\\`\\\`\\\`
\`\`\`
---
## CHANGELOG 模板
\`\`\`markdown
# Changelog
## [1.0.0] - 2025-01-01
### Added
- 初始版本发布
- 功能 A
- 功能 B
### Fixed
- 修复问题 X
\`\`\`
`;
}
//# sourceMappingURL=docTemplates.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"docTemplates.js","sourceRoot":"","sources":["../../src/resources/docTemplates.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,GAAG,EAAE,wCAAwC;IAC7C,IAAI,EAAE,MAAM;IACZ,WAAW,EAAE,+BAA+B;IAC5C,QAAQ,EAAE,eAAe;CAC1B,CAAC;AAEF,MAAM,UAAU,eAAe;IAC7B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+FR,CAAC;AACF,CAAC"}

View File

@@ -0,0 +1,28 @@
export declare const autoFixTool: {
name: string;
description: string;
inputSchema: {
type: "object";
properties: {
project_path: {
type: string;
description: string;
};
files: {
type: string;
description: string;
};
tools: {
type: string;
description: string;
};
};
required: string[];
};
};
export declare function executeAutoFix(args: {
project_path: string;
files?: string;
tools?: string;
}): Promise<string>;
//# sourceMappingURL=autoFix.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"autoFix.d.ts","sourceRoot":"","sources":["../../src/tools/autoFix.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;CAsBvB,CAAC;AAgBF,wBAAsB,cAAc,CAAC,IAAI,EAAE;IACzC,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CA0FlB"}

112
dev-assistant-mcp/dist/tools/autoFix.js vendored Normal file
View File

@@ -0,0 +1,112 @@
import { exec } from "child_process";
import { promisify } from "util";
import { existsSync } from "fs";
import { join } from "path";
const execAsync = promisify(exec);
export const autoFixTool = {
name: "auto_fix",
description: "自动修复代码问题。运行 Prettier 格式化、ESLint --fix 自动修复、以及其他自动修复工具。返回修复前后的变更摘要。",
inputSchema: {
type: "object",
properties: {
project_path: {
type: "string",
description: "项目根目录(绝对路径)",
},
files: {
type: "string",
description: "指定修复的文件或 glob可选默认修复整个项目",
},
tools: {
type: "string",
description: "指定修复工具逗号分隔可选prettier, eslint, autopep8。默认自动检测。",
},
},
required: ["project_path"],
},
};
async function runFix(cmd, cwd) {
try {
const { stdout, stderr } = await execAsync(cmd, {
cwd,
timeout: 30000,
maxBuffer: 1024 * 1024 * 5,
shell: process.platform === "win32" ? "powershell.exe" : "/bin/bash",
});
return { success: true, output: stdout || stderr || "✅ 修复完成" };
}
catch (error) {
return { success: false, output: error.stdout || error.stderr || error.message };
}
}
export async function executeAutoFix(args) {
const { project_path, files, tools } = args;
const hasFile = (name) => existsSync(join(project_path, name));
const fixResults = [];
// 先获取 git diff 作为修复前基线
let diffBefore = "";
try {
const { stdout } = await execAsync("git diff --stat", { cwd: project_path, timeout: 5000 });
diffBefore = stdout;
}
catch { }
const requestedTools = tools ? tools.split(",").map((t) => t.trim().toLowerCase()) : [];
const autoDetect = requestedTools.length === 0;
// Prettier
if (autoDetect ? (hasFile(".prettierrc") || hasFile(".prettierrc.json") || hasFile("prettier.config.js")) : requestedTools.includes("prettier")) {
const target = files || ".";
const result = await runFix(`npx prettier --write "${target}"`, project_path);
fixResults.push({ tool: "Prettier", ...result });
}
// ESLint --fix
if (autoDetect ? (hasFile(".eslintrc.js") || hasFile(".eslintrc.json") || hasFile("eslint.config.js") || hasFile("eslint.config.mjs")) : requestedTools.includes("eslint")) {
const target = files || "src/";
const result = await runFix(`npx eslint "${target}" --fix`, project_path);
fixResults.push({ tool: "ESLint --fix", ...result });
}
// Python autopep8
if (autoDetect ? (hasFile("requirements.txt") || hasFile("pyproject.toml")) : requestedTools.includes("autopep8")) {
const target = files || ".";
const result = await runFix(`python -m autopep8 --in-place --recursive "${target}"`, project_path);
if (!result.output.includes("No module named")) {
fixResults.push({ tool: "autopep8", ...result });
}
}
// 如果没有检测到工具配置,尝试 package.json 中的 format 脚本
if (fixResults.length === 0 && hasFile("package.json")) {
const result = await runFix("npm run format 2>&1 || npm run lint:fix 2>&1 || echo NO_FIX_SCRIPT", project_path);
if (!result.output.includes("NO_FIX_SCRIPT") && !result.output.includes("Missing script")) {
fixResults.push({ tool: "npm script (format/lint:fix)", ...result });
}
}
// 获取修复后的 diff
let diffAfter = "";
try {
const { stdout } = await execAsync("git diff --stat", { cwd: project_path, timeout: 5000 });
diffAfter = stdout;
}
catch { }
// 组装报告
const output = [
`# 自动修复报告`,
``,
`📂 项目: ${project_path}`,
``,
];
if (fixResults.length === 0) {
output.push("⚠️ 未检测到格式化/修复工具", "", "建议安装:", "- `npm install -D prettier` — 代码格式化", "- `npm install -D eslint` — 代码质量检查和自动修复", "- `pip install autopep8` — Python 代码格式化");
}
else {
for (const r of fixResults) {
output.push(`## ${r.success ? "✅" : "⚠️"} ${r.tool}`, "```", r.output.slice(0, 2000), "```", ``);
}
if (diffAfter && diffAfter !== diffBefore) {
output.push("## 变更摘要 (git diff --stat)", "```", diffAfter, "```");
}
else if (fixResults.some((r) => r.success)) {
output.push("📝 修复完成,代码已更新");
}
}
return output.join("\n");
}
//# sourceMappingURL=autoFix.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"autoFix.js","sourceRoot":"","sources":["../../src/tools/autoFix.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,23 @@
export declare const buildProjectTool: {
name: string;
description: string;
inputSchema: {
type: "object";
properties: {
project_path: {
type: string;
description: string;
};
command: {
type: string;
description: string;
};
};
required: string[];
};
};
export declare function executeBuildProject(args: {
project_path: string;
command?: string;
}): Promise<string>;
//# sourceMappingURL=buildProject.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"buildProject.d.ts","sourceRoot":"","sources":["../../src/tools/buildProject.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;CAkB5B,CAAC;AAsBF,wBAAsB,mBAAmB,CAAC,IAAI,EAAE;IAC9C,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GAAG,OAAO,CAAC,MAAM,CAAC,CA6FlB"}

View File

@@ -0,0 +1,115 @@
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

View File

@@ -0,0 +1 @@
{"version":3,"file":"buildProject.js","sourceRoot":"","sources":["../../src/tools/buildProject.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,33 @@
export declare const codeDebugTool: {
name: string;
description: string;
inputSchema: {
type: "object";
properties: {
code: {
type: string;
description: string;
};
error_message: {
type: string;
description: string;
};
language: {
type: string;
description: string;
};
expected_behavior: {
type: string;
description: string;
};
};
required: string[];
};
};
export declare function executeCodeDebug(args: {
code: string;
error_message: string;
language: string;
expected_behavior?: string;
}): Promise<string>;
//# sourceMappingURL=codeDebug.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"codeDebug.d.ts","sourceRoot":"","sources":["../../src/tools/codeDebug.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;CA0BzB,CAAC;AAwHF,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,GAAG,OAAO,CAAC,MAAM,CAAC,CAkElB"}

View File

@@ -0,0 +1,176 @@
export const codeDebugTool = {
name: "code_debug",
description: "分析代码错误,返回结构化的调试信息:错误分类、常见原因、排查步骤和修复模式。",
inputSchema: {
type: "object",
properties: {
code: {
type: "string",
description: "有问题的代码",
},
error_message: {
type: "string",
description: "错误信息或堆栈跟踪",
},
language: {
type: "string",
description: "编程语言",
},
expected_behavior: {
type: "string",
description: "期望的正确行为(可选)",
},
},
required: ["code", "error_message", "language"],
},
};
const errorPatterns = [
{
pattern: /TypeError.*(?:undefined|null|is not a function|Cannot read prop)/i,
category: "类型错误 (TypeError)",
commonCauses: [
"访问了 undefined/null 的属性",
"函数调用目标不是函数",
"异步操作返回值未正确 await",
"解构赋值时对象为空",
],
fixStrategies: [
"使用可选链 ?. 和空值合并 ??",
"添加前置空值检查",
"确认异步操作是否正确 await",
"检查 import 路径和导出方式是否匹配",
],
},
{
pattern: /ReferenceError.*is not defined/i,
category: "引用错误 (ReferenceError)",
commonCauses: [
"变量/函数未声明就使用",
"拼写错误",
"作用域问题(块级作用域、闭包)",
"缺少 import 语句",
],
fixStrategies: [
"检查变量名拼写",
"确认 import/require 语句",
"检查变量声明的作用域",
],
},
{
pattern: /SyntaxError/i,
category: "语法错误 (SyntaxError)",
commonCauses: [
"括号/引号不匹配",
"缺少分号或逗号",
"关键字拼写错误",
"ESM/CJS 混用",
],
fixStrategies: [
"检查报错行及前几行的括号/引号匹配",
"确认模块系统一致性import vs require",
"使用格式化工具自动修复",
],
},
{
pattern: /ECONNREFUSED|ETIMEDOUT|ENOTFOUND|fetch failed|network/i,
category: "网络错误",
commonCauses: [
"目标服务未启动",
"URL/端口配置错误",
"DNS 解析失败",
"防火墙/代理阻断",
"SSL 证书问题",
],
fixStrategies: [
"确认目标服务运行状态和端口",
"检查 URL 配置(协议、域名、端口)",
"添加重试机制和超时控制",
"检查网络连通性",
],
},
{
pattern: /ENOENT|no such file|Module not found|Cannot find module/i,
category: "文件/模块未找到",
commonCauses: [
"文件路径错误",
"依赖未安装(缺少 npm install",
"相对路径 vs 绝对路径搞混",
"文件扩展名不匹配",
],
fixStrategies: [
"检查文件路径和大小写",
"运行 npm install 安装依赖",
"检查 tsconfig/webpack 的路径别名配置",
"确认文件扩展名(.js/.ts/.mjs",
],
},
{
pattern: /Permission denied|EACCES|403|401|Unauthorized/i,
category: "权限错误",
commonCauses: [
"文件权限不足",
"API 认证失败Token 过期/错误)",
"CORS 跨域限制",
],
fixStrategies: [
"检查文件/目录权限chmod",
"检查 API Key / Token 是否有效",
"配置正确的 CORS 头",
],
},
{
pattern: /out of memory|heap|stack overflow|Maximum call stack/i,
category: "内存/栈溢出",
commonCauses: [
"无限递归",
"处理超大数据集未分页",
"内存泄漏(未清理的引用)",
],
fixStrategies: [
"检查递归终止条件",
"对大数据使用流式处理或分页",
"使用 --max-old-space-size 调整堆内存",
"排查事件监听器和定时器泄漏",
],
},
];
export async function executeCodeDebug(args) {
const { code, error_message, language, expected_behavior } = args;
// 匹配错误模式
const matched = errorPatterns.filter((ep) => ep.pattern.test(error_message));
const categories = matched.length > 0 ? matched : [{
category: "未分类错误",
commonCauses: ["请仔细阅读完整错误信息和堆栈"],
fixStrategies: ["根据错误信息定位问题代码行", "添加日志逐步排查"],
}];
// 从堆栈中提取行号
const lineRefs = [];
const lineRegex = /(?:at\s+.+?|File\s+.+?):(\d+)(?::(\d+))?/g;
let match;
while ((match = lineRegex.exec(error_message)) !== null) {
lineRefs.push(`${match[1]}${match[2] ? `:${match[2]}` : ""}`);
}
const output = [
`# 调试分析报告`,
``,
`**语言**: ${language}`,
``,
`## 错误信息`,
"```",
error_message,
"```",
``,
];
if (lineRefs.length > 0) {
output.push(`## 堆栈中的关键位置`, ...lineRefs.map((l) => `- ${l}`), ``);
}
for (const cat of categories) {
output.push(`## 错误类型: ${cat.category}`, ``, `### 常见原因`, ...cat.commonCauses.map((c) => `- ${c}`), ``, `### 修复策略`, ...cat.fixStrategies.map((s) => `- ${s}`), ``);
}
if (expected_behavior) {
output.push(`## 期望行为`, expected_behavior, ``);
}
output.push(`## 问题代码`, "```" + language, code, "```", ``, `## 排查步骤`, `1. 根据以上错误分类和常见原因,定位问题代码行`, `2. 在可疑位置添加日志输出,验证变量值`, `3. 根据修复策略实施修改`, `4. 编写测试用例确认修复有效`);
return output.join("\n");
}
//# sourceMappingURL=codeDebug.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"codeDebug.js","sourceRoot":"","sources":["../../src/tools/codeDebug.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,29 @@
export declare const codeReviewTool: {
name: string;
description: string;
inputSchema: {
type: "object";
properties: {
code: {
type: string;
description: string;
};
language: {
type: string;
description: string;
};
focus: {
type: string;
description: string;
enum: string[];
};
};
required: string[];
};
};
export declare function executeCodeReview(args: {
code: string;
language: string;
focus?: string;
}): Promise<string>;
//# sourceMappingURL=codeReview.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"codeReview.d.ts","sourceRoot":"","sources":["../../src/tools/codeReview.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;CAwB1B,CAAC;AA6BF,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAyGlB"}

View File

@@ -0,0 +1,159 @@
export const codeReviewTool = {
name: "code_review",
description: "审查代码质量。根据审查重点返回结构化的检查清单和分析结果,涵盖 bug、安全、性能、风格等维度。",
inputSchema: {
type: "object",
properties: {
code: {
type: "string",
description: "要审查的代码",
},
language: {
type: "string",
description: "编程语言(如 typescript, python, java 等)",
},
focus: {
type: "string",
description: "审查重点可选security=安全性, performance=性能, style=代码风格, all=全面审查",
enum: ["security", "performance", "style", "all"],
},
},
required: ["code", "language"],
},
};
const reviewChecklists = {
security: [
"检查是否存在 SQL 注入、XSS、CSRF 等注入攻击风险",
"检查是否硬编码了密钥、密码、Token 等敏感信息",
"检查用户输入是否经过验证和清洗",
"检查权限控制是否完善,是否有越权风险",
"检查是否使用了不安全的加密算法或随机数生成",
"检查第三方依赖是否有已知安全漏洞",
],
performance: [
"检查是否存在不必要的循环嵌套或 O(n²) 以上复杂度",
"检查是否有内存泄漏(未清理的定时器、事件监听、闭包)",
"检查是否有不必要的重复计算,是否需要缓存/记忆化",
"检查异步操作是否可以并行化Promise.all",
"检查是否有阻塞主线程的同步操作",
"检查数据库查询是否有 N+1 问题",
],
style: [
"检查命名是否清晰表达意图(变量、函数、类)",
"检查函数长度是否超过 50 行,是否需要拆分",
"检查嵌套层级是否过深(>3 层),是否可用 guard clause",
"检查是否有重复代码DRY 原则)",
"检查注释是否准确且必要,而非冗余",
"检查是否遵循语言社区的标准代码风格",
],
};
export async function executeCodeReview(args) {
const { code, language, focus = "all" } = args;
const lines = code.split("\n");
const lineCount = lines.length;
// 基础代码统计
const stats = {
totalLines: lineCount,
blankLines: lines.filter((l) => l.trim() === "").length,
commentLines: lines.filter((l) => {
const t = l.trim();
return t.startsWith("//") || t.startsWith("#") || t.startsWith("/*") || t.startsWith("*");
}).length,
codeLines: 0,
maxLineLength: Math.max(...lines.map((l) => l.length)),
maxNestingDepth: 0,
};
stats.codeLines = stats.totalLines - stats.blankLines - stats.commentLines;
// 计算最大嵌套深度
let depth = 0;
for (const line of lines) {
const opens = (line.match(/{/g) || []).length;
const closes = (line.match(/}/g) || []).length;
depth += opens - closes;
if (depth > stats.maxNestingDepth)
stats.maxNestingDepth = depth;
}
// 检测潜在问题
const issues = [];
// 通用检查
if (stats.maxLineLength > 120)
issues.push(`⚠️ 存在超长行(最长 ${stats.maxLineLength} 字符),建议不超过 120`);
if (stats.maxNestingDepth > 4)
issues.push(`⚠️ 嵌套层级过深(${stats.maxNestingDepth} 层),建议重构`);
if (stats.codeLines > 300)
issues.push(`⚠️ 文件过长(${stats.codeLines} 行代码),建议拆分`);
if (stats.commentLines === 0 && stats.codeLines > 30)
issues.push("🔵 缺少注释,建议为关键逻辑添加说明");
// 安全检查
if (focus === "security" || focus === "all") {
if (/eval\s*\(/.test(code))
issues.push("🔴 使用了 eval(),存在代码注入风险");
if (/innerHTML\s*=/.test(code))
issues.push("🔴 使用了 innerHTML存在 XSS 风险");
if (/(password|secret|api_?key|token)\s*=\s*["'][^"']+["']/i.test(code))
issues.push("🔴 可能硬编码了敏感信息");
if (/\bhttp:\/\//.test(code))
issues.push("🟡 使用了 HTTP 而非 HTTPS");
if (/exec\s*\(|spawn\s*\(/.test(code) && !/sanitize|escape|validate/.test(code))
issues.push("🟡 执行了外部命令,确认输入已清洗");
}
// 性能检查
if (focus === "performance" || focus === "all") {
if (/for\s*\(.*for\s*\(/s.test(code))
issues.push("🟡 存在嵌套循环,注意时间复杂度");
if (/setTimeout|setInterval/.test(code) && !/clearTimeout|clearInterval/.test(code))
issues.push("<22> 设置了定时器但未见清理,可能内存泄漏");
if (/\.forEach\(.*await/.test(code))
issues.push("🟡 在 forEach 中使用 await不会等待完成建议用 for...of");
if (/new RegExp\(/.test(code) && /for|while|map|forEach/.test(code))
issues.push("🔵 循环中创建正则表达式,建议提取到循环外");
}
// 风格检查
if (focus === "style" || focus === "all") {
if (/var\s+/.test(code) && (language === "typescript" || language === "javascript"))
issues.push("🔵 使用了 var建议改用 const/let");
if (/console\.log/.test(code))
issues.push("🔵 包含 console.log确认是否需要在生产环境移除");
if (/any/.test(code) && language === "typescript")
issues.push("🔵 使用了 any 类型,建议使用具体类型");
if (/TODO|FIXME|HACK|XXX/.test(code))
issues.push("🔵 存在 TODO/FIXME 标记,建议处理");
}
// 获取对应的检查清单
let checklist;
if (focus === "all") {
checklist = [
...reviewChecklists.security,
...reviewChecklists.performance,
...reviewChecklists.style,
];
}
else {
checklist = reviewChecklists[focus] || reviewChecklists.style;
}
// 组装结果
const output = [
`# 代码审查报告`,
``,
`**语言**: ${language} | **审查重点**: ${focus}`,
``,
`## 代码统计`,
`- 总行数: ${stats.totalLines}(代码 ${stats.codeLines} / 注释 ${stats.commentLines} / 空行 ${stats.blankLines}`,
`- 最长行: ${stats.maxLineLength} 字符`,
`- 最大嵌套深度: ${stats.maxNestingDepth}`,
``,
`## 自动检测到的问题(${issues.length} 项)`,
issues.length > 0 ? issues.map((i) => `- ${i}`).join("\n") : "- ✅ 未检测到明显问题",
``,
`## 人工审查清单`,
`请逐项检查以下内容:`,
...checklist.map((item, idx) => `${idx + 1}. ${item}`),
``,
`## 待审查代码`,
"```" + language,
code,
"```",
];
return output.join("\n");
}
//# sourceMappingURL=codeReview.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,33 @@
export declare const codeWriteTool: {
name: string;
description: string;
inputSchema: {
type: "object";
properties: {
requirement: {
type: string;
description: string;
};
language: {
type: string;
description: string;
};
framework: {
type: string;
description: string;
};
context: {
type: string;
description: string;
};
};
required: string[];
};
};
export declare function executeCodeWrite(args: {
requirement: string;
language: string;
framework?: string;
context?: string;
}): Promise<string>;
//# sourceMappingURL=codeWrite.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"codeWrite.d.ts","sourceRoot":"","sources":["../../src/tools/codeWrite.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;CA0BzB,CAAC;AA4GF,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GAAG,OAAO,CAAC,MAAM,CAAC,CA4DlB"}

View File

@@ -0,0 +1,162 @@
export const codeWriteTool = {
name: "code_write",
description: "根据需求描述生成代码编写指引。返回结构化的需求分析、技术方案、代码骨架和最佳实践建议。",
inputSchema: {
type: "object",
properties: {
requirement: {
type: "string",
description: "功能需求描述",
},
language: {
type: "string",
description: "编程语言(如 typescript, python, java 等)",
},
framework: {
type: "string",
description: "框架(可选,如 react, express, fastapi 等)",
},
context: {
type: "string",
description: "额外上下文(可选,如现有代码片段、接口定义等)",
},
},
required: ["requirement", "language"],
},
};
const languageBestPractices = {
typescript: [
"使用严格类型,避免 any",
"用 interface/type 定义数据结构",
"async/await 处理异步",
"使用 const 优先,必要时 let",
"错误处理使用 try-catch + 自定义 Error 类",
],
javascript: [
"使用 const/let禁用 var",
"使用 JSDoc 注释函数签名",
"async/await 处理异步",
"使用解构赋值简化代码",
"模块化:每个文件单一职责",
],
python: [
"遵循 PEP 8 风格规范",
"使用 type hints 标注类型",
"使用 dataclass/Pydantic 定义数据模型",
"用 with 语句管理资源",
"异常处理:捕获具体异常而非 Exception",
],
java: [
"遵循 Java 命名约定",
"使用 Optional 避免 NullPointerException",
"用 Stream API 处理集合",
"接口优先于实现",
"使用 Lombok 减少样板代码",
],
};
const frameworkTemplates = {
react: `// React 组件骨架
import React, { useState, useEffect } from 'react';
interface Props {
// TODO: 定义 props
}
export function ComponentName({ }: Props) {
const [state, setState] = useState();
useEffect(() => {
// TODO: 副作用逻辑
}, []);
return (
<div>
{/* TODO: JSX 结构 */}
</div>
);
}`,
express: `// Express 路由骨架
import express from 'express';
const router = express.Router();
router.get('/', async (req, res) => {
try {
// TODO: 业务逻辑
res.json({ success: true, data: {} });
} catch (error) {
res.status(500).json({ success: false, message: error.message });
}
});
export default router;`,
fastapi: `# FastAPI 路由骨架
from fastapi import APIRouter, HTTPException
from pydantic import BaseModel
router = APIRouter()
class RequestModel(BaseModel):
# TODO: 定义请求模型
pass
class ResponseModel(BaseModel):
success: bool
data: dict = {}
@router.get("/", response_model=ResponseModel)
async def handler():
try:
# TODO: 业务逻辑
return ResponseModel(success=True, data={})
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))`,
vue: `<!-- Vue 组件骨架 -->
<template>
<div>
<!-- TODO: 模板结构 -->
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
// TODO: 定义响应式状态
const state = ref();
onMounted(() => {
// TODO: 初始化逻辑
});
</script>`,
};
export async function executeCodeWrite(args) {
const { requirement, language, framework, context } = args;
const practices = languageBestPractices[language.toLowerCase()] || [
"遵循语言社区标准",
"添加类型标注",
"做好错误处理",
"保持函数单一职责",
];
const output = [
`# 代码编写指引`,
``,
`## 需求`,
requirement,
``,
`## 技术规格`,
`- **语言**: ${language}`,
];
if (framework) {
output.push(`- **框架**: ${framework}`);
}
output.push(``, `## ${language} 最佳实践`, ...practices.map((p) => `- ${p}`), ``);
if (framework && frameworkTemplates[framework.toLowerCase()]) {
output.push(`## 代码骨架模板`, "```" + language, frameworkTemplates[framework.toLowerCase()], "```", ``);
}
output.push(`## 编写要求`, `1. 代码必须完整可运行,包含所有必要的 import`, `2. 遵循 ${language} 最佳实践和命名规范`, `3. 关键逻辑添加简洁注释`, `4. 包含必要的错误处理和边界检查`, `5. 函数保持单一职责,不超过 50 行`, ``);
if (context) {
output.push(`## 参考上下文`, "```", context, "```", ``);
}
output.push(`## 请根据以上指引生成完整代码`);
return output.join("\n");
}
//# sourceMappingURL=codeWrite.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"codeWrite.js","sourceRoot":"","sources":["../../src/tools/codeWrite.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,34 @@
export declare const depManageTool: {
name: string;
description: string;
inputSchema: {
type: "object";
properties: {
project_path: {
type: string;
description: string;
};
action: {
type: string;
description: string;
enum: string[];
};
packages: {
type: string;
description: string;
};
dev: {
type: string;
description: string;
};
};
required: string[];
};
};
export declare function executeDepManage(args: {
project_path: string;
action: string;
packages?: string;
dev?: boolean;
}): Promise<string>;
//# sourceMappingURL=depManage.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"depManage.d.ts","sourceRoot":"","sources":["../../src/tools/depManage.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BzB,CAAC;AAeF,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf,GAAG,OAAO,CAAC,MAAM,CAAC,CAgIlB"}

View File

@@ -0,0 +1,175 @@
import { exec } from "child_process";
import { promisify } from "util";
import { existsSync } from "fs";
import { join } from "path";
const execAsync = promisify(exec);
export const depManageTool = {
name: "dep_manage",
description: "依赖管理。安装/更新/删除依赖、检查过时包、安全漏洞审计、分析 bundle 大小。支持 npm 和 pip。",
inputSchema: {
type: "object",
properties: {
project_path: {
type: "string",
description: "项目根目录(绝对路径)",
},
action: {
type: "string",
description: "操作类型",
enum: ["install", "add", "remove", "update", "outdated", "audit", "list", "why"],
},
packages: {
type: "string",
description: "包名多个用空格分隔add/remove/why 时必填",
},
dev: {
type: "boolean",
description: "是否为开发依赖(默认 false",
},
},
required: ["project_path", "action"],
},
};
async function run(cmd, cwd, timeout = 120000) {
try {
const { stdout, stderr } = await execAsync(cmd, {
cwd, timeout,
maxBuffer: 1024 * 1024 * 10,
shell: process.platform === "win32" ? "powershell.exe" : "/bin/bash",
});
return { stdout, stderr, code: 0 };
}
catch (error) {
return { stdout: error.stdout || "", stderr: error.stderr || "", code: error.code ?? 1 };
}
}
export async function executeDepManage(args) {
const { project_path, action, packages, dev = false } = args;
const hasFile = (name) => existsSync(join(project_path, name));
const isNode = hasFile("package.json");
const isPython = hasFile("requirements.txt") || hasFile("pyproject.toml");
if (!isNode && !isPython) {
return "❌ 未检测到 package.json 或 requirements.txt";
}
let cmd = "";
let title = "";
if (isNode) {
switch (action) {
case "install":
cmd = "npm install";
title = "npm install";
break;
case "add":
if (!packages)
return "❌ add 需要 packages 参数";
cmd = `npm install ${packages}${dev ? " --save-dev" : ""}`;
title = `npm install ${packages}${dev ? " (dev)" : ""}`;
break;
case "remove":
if (!packages)
return "❌ remove 需要 packages 参数";
cmd = `npm uninstall ${packages}`;
title = `npm uninstall ${packages}`;
break;
case "update":
cmd = packages ? `npm update ${packages}` : "npm update";
title = `npm update${packages ? ` ${packages}` : ""}`;
break;
case "outdated":
cmd = "npm outdated --long 2>&1 || true";
title = "npm outdated过时依赖检查";
break;
case "audit":
cmd = "npm audit 2>&1 || true";
title = "npm audit安全漏洞审计";
break;
case "list":
cmd = "npm list --depth=0 2>&1";
title = "npm list已安装依赖";
break;
case "why":
if (!packages)
return "❌ why 需要 packages 参数";
cmd = `npm why ${packages} 2>&1`;
title = `npm why ${packages}`;
break;
}
}
else if (isPython) {
switch (action) {
case "install":
cmd = hasFile("requirements.txt") ? "pip install -r requirements.txt" : "pip install -e .";
title = "pip install";
break;
case "add":
if (!packages)
return "❌ add 需要 packages 参数";
cmd = `pip install ${packages}`;
title = `pip install ${packages}`;
break;
case "remove":
if (!packages)
return "❌ remove 需要 packages 参数";
cmd = `pip uninstall -y ${packages}`;
title = `pip uninstall ${packages}`;
break;
case "update":
cmd = packages ? `pip install --upgrade ${packages}` : "pip install --upgrade -r requirements.txt";
title = `pip upgrade${packages ? ` ${packages}` : ""}`;
break;
case "outdated":
cmd = "pip list --outdated 2>&1";
title = "pip outdated";
break;
case "audit":
cmd = "pip-audit 2>&1 || pip check 2>&1";
title = "pip audit / check";
break;
case "list":
cmd = "pip list 2>&1";
title = "pip list";
break;
case "why":
if (!packages)
return "❌ why 需要 packages 参数";
cmd = `pip show ${packages} 2>&1`;
title = `pip show ${packages}`;
break;
}
}
if (!cmd)
return `❌ 未知操作: ${action}`;
const result = await run(cmd, project_path);
const fullOutput = [result.stdout, result.stderr].filter(Boolean).join("\n").trim();
const icon = result.code === 0 ? "✅" : "⚠️";
const output = [
`# ${icon} ${title}`,
``,
`📂 ${project_path}`,
`📦 ${isNode ? "npm" : "pip"}`,
``,
"```",
fullOutput.slice(0, 6000) || "(无输出)",
"```",
];
// audit 额外解析
if (action === "audit" && isNode) {
const criticalMatch = fullOutput.match(/(\d+)\s+(critical|high)/gi);
if (criticalMatch && criticalMatch.length > 0) {
output.push(``, `⚠️ **发现高危漏洞!** 建议运行 \`npm audit fix\`\`npm audit fix --force\``);
}
else if (result.code === 0) {
output.push(``, `✅ 未发现已知安全漏洞`);
}
}
// outdated 额外解析
if (action === "outdated" && fullOutput.trim()) {
const lines = fullOutput.trim().split("\n").filter((l) => l.trim());
if (lines.length > 1) {
output.push(``, `📊 发现 ${lines.length - 1} 个可更新的包`);
output.push(`💡 运行 \`dep_manage action=update\` 更新所有包`);
}
}
return output.join("\n");
}
//# sourceMappingURL=depManage.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,39 @@
export declare const devServerTool: {
name: string;
description: string;
inputSchema: {
type: "object";
properties: {
project_path: {
type: string;
description: string;
};
action: {
type: string;
description: string;
enum: string[];
};
command: {
type: string;
description: string;
};
name: {
type: string;
description: string;
};
tail: {
type: string;
description: string;
};
};
required: string[];
};
};
export declare function executeDevServer(args: {
project_path?: string;
action: string;
command?: string;
name?: string;
tail?: number;
}): Promise<string>;
//# sourceMappingURL=devServer.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"devServer.d.ts","sourceRoot":"","sources":["../../src/tools/devServer.ts"],"names":[],"mappings":"AAgBA,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+BzB,CAAC;AAkCF,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,GAAG,OAAO,CAAC,MAAM,CAAC,CAuLlB"}

View File

@@ -0,0 +1,229 @@
import { exec, spawn } from "child_process";
import { promisify } from "util";
import { existsSync, readFileSync } from "fs";
import { join } from "path";
const execAsync = promisify(exec);
// 进程管理器 - 跟踪所有启动的开发服务器
const managedProcesses = new Map();
export const devServerTool = {
name: "dev_server",
description: "开发服务器管理。启动/停止/重启开发服务器,查看运行状态和实时日志。支持自动检测项目的 dev 命令。",
inputSchema: {
type: "object",
properties: {
project_path: {
type: "string",
description: "项目根目录(绝对路径)",
},
action: {
type: "string",
description: "操作类型",
enum: ["start", "stop", "restart", "status", "logs", "list"],
},
command: {
type: "string",
description: "自定义启动命令(可选,默认自动检测 npm run dev 等)",
},
name: {
type: "string",
description: "服务器名称/标识(可选,默认使用目录名)",
},
tail: {
type: "number",
description: "显示最近几行日志(默认 30",
},
},
required: ["action"],
},
};
function getServerName(projectPath, name) {
if (name)
return name;
if (projectPath)
return projectPath.split(/[/\\]/).pop() || "server";
return "default";
}
function detectDevCommand(projectPath) {
const pkgPath = join(projectPath, "package.json");
if (existsSync(pkgPath)) {
try {
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
const scripts = pkg.scripts || {};
// 按优先级检测
for (const name of ["dev", "start:dev", "serve", "start"]) {
if (scripts[name])
return `npm run ${name}`;
}
}
catch { }
}
if (existsSync(join(projectPath, "manage.py"))) {
return "python manage.py runserver";
}
if (existsSync(join(projectPath, "main.py"))) {
return "python main.py";
}
if (existsSync(join(projectPath, "app.py"))) {
return "python app.py";
}
return null;
}
export async function executeDevServer(args) {
const { project_path, action, command, name, tail = 30 } = args;
switch (action) {
case "list": {
if (managedProcesses.size === 0) {
return "# 开发服务器\n\n_没有正在运行的服务器_";
}
const output = ["# 运行中的开发服务器", ""];
for (const [key, info] of managedProcesses) {
const running = !info.process.killed && info.process.exitCode === null;
const uptime = Math.round((Date.now() - info.startTime) / 1000);
output.push(`## ${running ? "🟢" : "🔴"} ${key}`, `- 命令: \`${info.command}\``, `- 目录: ${info.cwd}`, `- PID: ${info.process.pid}`, `- 运行时间: ${uptime}s`, `- 状态: ${running ? "运行中" : "已停止"}`, ``);
}
return output.join("\n");
}
case "start": {
if (!project_path)
return "❌ start 需要 project_path 参数";
const serverName = getServerName(project_path, name);
const existing = managedProcesses.get(serverName);
if (existing && !existing.process.killed && existing.process.exitCode === null) {
return `⚠️ 服务器 "${serverName}" 已在运行中 (PID: ${existing.process.pid})\n\n使用 action=restart 重启,或 action=stop 先停止`;
}
const startCmd = command || detectDevCommand(project_path);
if (!startCmd) {
return `❌ 未检测到启动命令,请手动指定 command 参数\n\n常见命令:\n- npm run dev\n- npm start\n- python app.py`;
}
// 解析命令
const isWin = process.platform === "win32";
const child = spawn(isWin ? "cmd" : "sh", [isWin ? "/c" : "-c", startCmd], {
cwd: project_path,
stdio: ["ignore", "pipe", "pipe"],
detached: false,
});
const logs = [];
const maxLogs = 200;
const addLog = (data, stream) => {
const lines = data.toString().split("\n").filter(Boolean);
for (const line of lines) {
logs.push(`[${stream}] ${line}`);
if (logs.length > maxLogs)
logs.shift();
}
};
child.stdout?.on("data", (data) => addLog(data, "out"));
child.stderr?.on("data", (data) => addLog(data, "err"));
managedProcesses.set(serverName, {
process: child,
command: startCmd,
cwd: project_path,
startTime: Date.now(),
logs,
});
// 等待一会检查是否立即崩溃
await new Promise((r) => setTimeout(r, 2000));
const crashed = child.exitCode !== null;
if (crashed) {
const output = logs.join("\n");
managedProcesses.delete(serverName);
return `# ❌ 服务器启动失败\n\n命令: \`${startCmd}\`\n退出码: ${child.exitCode}\n\n\`\`\`\n${output.slice(0, 3000)}\n\`\`\``;
}
return [
`# ✅ 服务器已启动`,
``,
`- 名称: ${serverName}`,
`- 命令: \`${startCmd}\``,
`- PID: ${child.pid}`,
`- 目录: ${project_path}`,
``,
`最近日志:`,
"```",
logs.slice(-10).join("\n") || "(等待输出...)",
"```",
``,
`💡 使用 \`dev_server action=logs\` 查看实时日志`,
].join("\n");
}
case "stop": {
const serverName = getServerName(project_path, name);
const info = managedProcesses.get(serverName);
if (!info) {
return `❌ 未找到服务器 "${serverName}"\n\n使用 action=list 查看所有运行中的服务器`;
}
const pid = info.process.pid;
try {
// Windows 需要 taskkill 杀进程树
if (process.platform === "win32" && pid) {
await execAsync(`taskkill /PID ${pid} /T /F`).catch(() => { });
}
else {
info.process.kill("SIGTERM");
}
}
catch { }
managedProcesses.delete(serverName);
return `# ✅ 服务器已停止\n\n- 名称: ${serverName}\n- PID: ${pid}`;
}
case "restart": {
const serverName = getServerName(project_path, name);
const info = managedProcesses.get(serverName);
if (info) {
try {
if (process.platform === "win32" && info.process.pid) {
await execAsync(`taskkill /PID ${info.process.pid} /T /F`).catch(() => { });
}
else {
info.process.kill("SIGTERM");
}
}
catch { }
managedProcesses.delete(serverName);
await new Promise((r) => setTimeout(r, 1000));
}
// 重新启动
return executeDevServer({
project_path: info?.cwd || project_path,
action: "start",
command: command || info?.command,
name: serverName,
});
}
case "status": {
const serverName = getServerName(project_path, name);
const info = managedProcesses.get(serverName);
if (!info) {
return `❌ 未找到服务器 "${serverName}"`;
}
const running = !info.process.killed && info.process.exitCode === null;
const uptime = Math.round((Date.now() - info.startTime) / 1000);
return [
`# ${running ? "🟢" : "🔴"} ${serverName}`,
``,
`- 状态: ${running ? "运行中" : `已停止 (退出码: ${info.process.exitCode})`}`,
`- 命令: \`${info.command}\``,
`- PID: ${info.process.pid}`,
`- 运行时间: ${uptime}s`,
`- 目录: ${info.cwd}`,
].join("\n");
}
case "logs": {
const serverName = getServerName(project_path, name);
const info = managedProcesses.get(serverName);
if (!info) {
return `❌ 未找到服务器 "${serverName}"`;
}
const recentLogs = info.logs.slice(-tail);
return [
`# 📋 ${serverName} 日志(最近 ${tail} 行)`,
``,
"```",
recentLogs.join("\n") || "(无日志)",
"```",
].join("\n");
}
default:
return `❌ 未知操作: ${action}`;
}
}
//# sourceMappingURL=devServer.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,39 @@
export declare const docWriteTool: {
name: string;
description: string;
inputSchema: {
type: "object";
properties: {
code: {
type: string;
description: string;
};
doc_type: {
type: string;
description: string;
enum: string[];
};
language: {
type: string;
description: string;
};
project_name: {
type: string;
description: string;
};
extra_info: {
type: string;
description: string;
};
};
required: string[];
};
};
export declare function executeDocWrite(args: {
code: string;
doc_type: string;
language: string;
project_name?: string;
extra_info?: string;
}): Promise<string>;
//# sourceMappingURL=docWrite.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"docWrite.d.ts","sourceRoot":"","sources":["../../src/tools/docWrite.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+BxB,CAAC;AA8FF,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,GAAG,OAAO,CAAC,MAAM,CAAC,CA6ElB"}

167
dev-assistant-mcp/dist/tools/docWrite.js vendored Normal file
View File

@@ -0,0 +1,167 @@
export const docWriteTool = {
name: "doc_write",
description: "为代码生成文档指引。分析代码结构,提取函数/类/接口信息,返回结构化的文档框架和编写指引。",
inputSchema: {
type: "object",
properties: {
code: {
type: "string",
description: "需要生成文档的代码",
},
doc_type: {
type: "string",
description: "文档类型",
enum: ["readme", "api", "inline", "changelog", "jsdoc"],
},
language: {
type: "string",
description: "编程语言",
},
project_name: {
type: "string",
description: "项目名称(可选,用于 README",
},
extra_info: {
type: "string",
description: "额外信息(可选,如版本号、变更内容等)",
},
},
required: ["code", "doc_type", "language"],
},
};
function extractSymbols(code, language) {
const symbols = [];
const lines = code.split("\n");
for (let i = 0; i < lines.length; i++) {
const line = lines[i].trim();
const lineNum = i + 1;
// 函数
let m;
if ((m = line.match(/(?:export\s+)?(?:async\s+)?function\s+(\w+)\s*\(([^)]*)\)/))) {
symbols.push({ type: "function", name: m[1], line: lineNum, signature: m[0] });
}
// 箭头函数 / const 赋值
else if ((m = line.match(/(?:export\s+)?(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s+)?\(?([^)]*)\)?\s*=>/))) {
symbols.push({ type: "function", name: m[1], line: lineNum, signature: m[0] });
}
// 类
else if ((m = line.match(/(?:export\s+)?class\s+(\w+)/))) {
symbols.push({ type: "class", name: m[1], line: lineNum });
}
// 接口 (TS)
else if ((m = line.match(/(?:export\s+)?interface\s+(\w+)/))) {
symbols.push({ type: "interface", name: m[1], line: lineNum });
}
// 路由 (Express/FastAPI)
else if ((m = line.match(/(?:router|app)\.(get|post|put|delete|patch)\s*\(\s*['"]([^'"]+)['"]/))) {
symbols.push({ type: "route", name: `${m[1].toUpperCase()} ${m[2]}`, line: lineNum });
}
// Python 函数
else if ((m = line.match(/(?:async\s+)?def\s+(\w+)\s*\(([^)]*)\)/))) {
symbols.push({ type: "function", name: m[1], line: lineNum, signature: m[0] });
}
// Python 类
else if ((m = line.match(/class\s+(\w+)(?:\(([^)]*)\))?:/))) {
symbols.push({ type: "class", name: m[1], line: lineNum });
}
// export default
else if ((m = line.match(/export\s+default\s+(\w+)/))) {
symbols.push({ type: "export", name: m[1], line: lineNum });
}
}
return symbols;
}
const docTypeInstructions = {
readme: `请生成 README.md包含以下章节
# 项目名称
## 简介(一句话描述)
## 功能特性
## 快速开始(安装、配置、运行)
## API / 使用说明
## 项目结构
## License`,
api: `请生成 API 文档,每个端点/函数包含:
- 描述
- 请求方法和路径(如适用)
- 参数(名称、类型、是否必填、描述)
- 返回值(类型、描述)
- 示例代码
- 错误码(如适用)`,
inline: `请为代码添加内联注释:
- 每个函数/方法添加文档注释JSDoc / docstring
- 关键逻辑添加简洁的解释性注释
- 不要过度注释显而易见的代码
- 返回带注释的完整代码`,
changelog: `请生成 CHANGELOG.md遵循 Keep a Changelog 格式:
## [版本号] - 日期
### Added新增
### Changed变更
### Fixed修复
### Removed移除`,
jsdoc: `请为所有函数/类/接口生成文档注释:
- @param 参数(类型、描述)
- @returns 返回值(类型、描述)
- @throws 可能的异常
- @example 使用示例
- 返回带完整文档注释的代码`,
};
export async function executeDocWrite(args) {
const { code, doc_type, language, project_name, extra_info } = args;
const symbols = extractSymbols(code, language);
const lines = code.split("\n");
const output = [
`# 文档生成指引`,
``,
`**文档类型**: ${doc_type} | **语言**: ${language}${project_name ? ` | **项目**: ${project_name}` : ""}`,
``,
];
// 代码结构分析
output.push(`## 代码结构分析`, ``);
const functions = symbols.filter((s) => s.type === "function");
const classes = symbols.filter((s) => s.type === "class");
const interfaces = symbols.filter((s) => s.type === "interface");
const routes = symbols.filter((s) => s.type === "route");
if (functions.length > 0) {
output.push(`### 函数 (${functions.length})`);
for (const f of functions) {
output.push(`- **${f.name}** (行 ${f.line})${f.signature ? `: \`${f.signature}\`` : ""}`);
}
output.push(``);
}
if (classes.length > 0) {
output.push(`### 类 (${classes.length})`);
for (const c of classes) {
output.push(`- **${c.name}** (行 ${c.line})`);
}
output.push(``);
}
if (interfaces.length > 0) {
output.push(`### 接口 (${interfaces.length})`);
for (const i of interfaces) {
output.push(`- **${i.name}** (行 ${i.line})`);
}
output.push(``);
}
if (routes.length > 0) {
output.push(`### API 路由 (${routes.length})`);
for (const r of routes) {
output.push(`- **${r.name}** (行 ${r.line})`);
}
output.push(``);
}
if (symbols.length === 0) {
output.push(`_未检测到标准的函数/类/接口/路由定义_`, ``);
}
// 统计
output.push(`### 文件统计`, `- 总行数: ${lines.length}`, `- 代码符号: ${symbols.length}`, ``);
// 文档编写指引
const instruction = docTypeInstructions[doc_type] || docTypeInstructions.readme;
output.push(`## 文档编写指引`, ``, instruction, ``);
if (extra_info) {
output.push(`## 补充信息`, extra_info, ``);
}
// 附上源代码
output.push(`## 源代码`, "```" + language, code, "```");
return output.join("\n");
}
//# sourceMappingURL=docWrite.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,23 @@
export declare const envCheckTool: {
name: string;
description: string;
inputSchema: {
type: "object";
properties: {
checks: {
type: string;
description: string;
};
ports: {
type: string;
description: string;
};
};
required: never[];
};
};
export declare function executeEnvCheck(args: {
checks?: string;
ports?: string;
}): Promise<string>;
//# sourceMappingURL=envCheck.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"envCheck.d.ts","sourceRoot":"","sources":["../../src/tools/envCheck.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;CAkBxB,CAAC;AAmCF,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAmJlB"}

131
dev-assistant-mcp/dist/tools/envCheck.js vendored Normal file
View File

@@ -0,0 +1,131 @@
import { exec } from "child_process";
import { promisify } from "util";
import { platform, totalmem, freemem, cpus, hostname, userInfo } from "os";
const execAsync = promisify(exec);
export const envCheckTool = {
name: "env_check",
description: "环境检测。检查 Node.js、Python、Git 等工具版本检测端口占用查看系统资源CPU/内存/磁盘),验证开发环境是否就绪。",
inputSchema: {
type: "object",
properties: {
checks: {
type: "string",
description: "要检查的项目逗号分隔可选all, node, python, git, ports, system, docker。默认 all。",
},
ports: {
type: "string",
description: "要检测的端口号,逗号分隔(如 3000,8080,5173",
},
},
required: [],
},
};
async function getVersion(cmd) {
try {
const { stdout } = await execAsync(cmd, { timeout: 5000 });
return stdout.trim().split("\n")[0];
}
catch {
return "❌ 未安装";
}
}
async function checkPort(port) {
try {
const cmd = process.platform === "win32"
? `netstat -ano | findstr :${port}`
: `lsof -i :${port} 2>/dev/null || ss -tlnp | grep :${port}`;
const { stdout } = await execAsync(cmd, { timeout: 5000 });
return stdout.trim().length > 0;
}
catch {
return false;
}
}
async function getDiskSpace() {
try {
const cmd = process.platform === "win32"
? 'powershell -command "Get-PSDrive -PSProvider FileSystem | Select-Object Name, @{N=\'Used(GB)\';E={[math]::Round($_.Used/1GB,1)}}, @{N=\'Free(GB)\';E={[math]::Round($_.Free/1GB,1)}} | Format-Table -AutoSize"'
: "df -h / /home 2>/dev/null";
const { stdout } = await execAsync(cmd, { timeout: 10000 });
return stdout.trim();
}
catch {
return "无法获取";
}
}
export async function executeEnvCheck(args) {
const { checks = "all", ports } = args;
const checkList = checks.split(",").map((c) => c.trim().toLowerCase());
const doAll = checkList.includes("all");
const output = [
`# 环境检测报告`,
``,
`🖥️ ${hostname()} | ${platform()} | ${userInfo().username}`,
`📅 ${new Date().toLocaleString("zh-CN")}`,
``,
];
// 系统资源
if (doAll || checkList.includes("system")) {
const totalMem = (totalmem() / 1024 / 1024 / 1024).toFixed(1);
const freeMem = (freemem() / 1024 / 1024 / 1024).toFixed(1);
const usedMem = ((totalmem() - freemem()) / 1024 / 1024 / 1024).toFixed(1);
const memPercent = ((1 - freemem() / totalmem()) * 100).toFixed(0);
const cpuInfo = cpus();
const cpuModel = cpuInfo[0]?.model || "未知";
output.push(`## 💻 系统资源`, ``, `| 项目 | 值 |`, `|------|------|`, `| CPU | ${cpuModel} |`, `| 核心数 | ${cpuInfo.length} |`, `| 内存 | ${usedMem} / ${totalMem} GB (${memPercent}%) |`, `| 空闲内存 | ${freeMem} GB |`, ``);
const disk = await getDiskSpace();
if (disk !== "无法获取") {
output.push(`### 磁盘空间`, "```", disk, "```", ``);
}
}
// Node.js
if (doAll || checkList.includes("node")) {
const [nodeVer, npmVer, npxVer, yarnVer, pnpmVer] = await Promise.all([
getVersion("node --version"),
getVersion("npm --version"),
getVersion("npx --version"),
getVersion("yarn --version"),
getVersion("pnpm --version"),
]);
output.push(`## 📦 Node.js 生态`, ``, `| 工具 | 版本 |`, `|------|------|`, `| Node.js | ${nodeVer} |`, `| npm | ${npmVer} |`, `| npx | ${npxVer} |`, `| yarn | ${yarnVer} |`, `| pnpm | ${pnpmVer} |`, ``);
}
// Python
if (doAll || checkList.includes("python")) {
const [pyVer, py3Ver, pipVer] = await Promise.all([
getVersion("python --version"),
getVersion("python3 --version"),
getVersion("pip --version"),
]);
output.push(`## 🐍 Python 生态`, ``, `| 工具 | 版本 |`, `|------|------|`, `| Python | ${pyVer} |`, `| Python3 | ${py3Ver} |`, `| pip | ${pipVer} |`, ``);
}
// Git
if (doAll || checkList.includes("git")) {
const gitVer = await getVersion("git --version");
const gitUser = await getVersion("git config --global user.name");
const gitEmail = await getVersion("git config --global user.email");
output.push(`## 🔧 Git`, ``, `| 项目 | 值 |`, `|------|------|`, `| 版本 | ${gitVer} |`, `| 用户名 | ${gitUser} |`, `| 邮箱 | ${gitEmail} |`, ``);
}
// Docker
if (doAll || checkList.includes("docker")) {
const [dockerVer, composeVer] = await Promise.all([
getVersion("docker --version"),
getVersion("docker compose version 2>&1 || docker-compose --version 2>&1"),
]);
output.push(`## 🐳 Docker`, ``, `| 工具 | 版本 |`, `|------|------|`, `| Docker | ${dockerVer} |`, `| Compose | ${composeVer} |`, ``);
}
// 端口检测
if (doAll || checkList.includes("ports") || ports) {
const portsToCheck = ports
? ports.split(",").map((p) => parseInt(p.trim())).filter(Boolean)
: [3000, 3001, 5173, 5174, 8080, 8081, 4000, 4173, 5000, 5500];
const portResults = await Promise.all(portsToCheck.map(async (port) => ({
port,
occupied: await checkPort(port),
})));
output.push(`## 🔌 端口状态`, ``, `| 端口 | 状态 |`, `|------|------|`, ...portResults.map((r) => `| ${r.port} | ${r.occupied ? "🔴 已占用" : "🟢 空闲"} |`), ``);
}
// 总结
output.push(`---`, `_检测完成_`);
return output.join("\n");
}
//# sourceMappingURL=envCheck.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,28 @@
export declare const execCommandTool: {
name: string;
description: string;
inputSchema: {
type: "object";
properties: {
command: {
type: string;
description: string;
};
cwd: {
type: string;
description: string;
};
timeout: {
type: string;
description: string;
};
};
required: string[];
};
};
export declare function executeExecCommand(args: {
command: string;
cwd?: string;
timeout?: number;
}): Promise<string>;
//# sourceMappingURL=execCommand.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"execCommand.d.ts","sourceRoot":"","sources":["../../src/tools/execCommand.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;CAsB3B,CAAC;AAEF,wBAAsB,kBAAkB,CAAC,IAAI,EAAE;IAC7C,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GAAG,OAAO,CAAC,MAAM,CAAC,CAiClB"}

View File

@@ -0,0 +1,62 @@
import { exec } from "child_process";
import { promisify } from "util";
const execAsync = promisify(exec);
export const execCommandTool = {
name: "exec_command",
description: "在本地电脑上执行 Shell 命令。用于运行编译、测试、构建、安装依赖等任何命令。返回 stdout、stderr 和退出码。",
inputSchema: {
type: "object",
properties: {
command: {
type: "string",
description: "要执行的命令(如 npm install, tsc --noEmit, python script.py",
},
cwd: {
type: "string",
description: "工作目录(绝对路径)",
},
timeout: {
type: "number",
description: "超时时间(毫秒),默认 60000",
},
},
required: ["command"],
},
};
export async function executeExecCommand(args) {
const { command, cwd, timeout = 60000 } = args;
const workDir = cwd || process.cwd();
try {
const { stdout, stderr } = await execAsync(command, {
cwd: workDir,
timeout,
maxBuffer: 1024 * 1024 * 10, // 10MB
shell: process.platform === "win32" ? "powershell.exe" : "/bin/bash",
});
const output = [
`$ ${command}`,
`📂 ${workDir}`,
`✅ 退出码: 0`,
];
if (stdout.trim())
output.push(`\n--- stdout ---\n${stdout.trim()}`);
if (stderr.trim())
output.push(`\n--- stderr ---\n${stderr.trim()}`);
return output.join("\n");
}
catch (error) {
const output = [
`$ ${command}`,
`📂 ${workDir}`,
`❌ 退出码: ${error.code ?? "unknown"}`,
];
if (error.stdout?.trim())
output.push(`\n--- stdout ---\n${error.stdout.trim()}`);
if (error.stderr?.trim())
output.push(`\n--- stderr ---\n${error.stderr.trim()}`);
if (error.killed)
output.push(`\n⏰ 命令超时(${timeout}ms被终止`);
return output.join("\n");
}
}
//# sourceMappingURL=execCommand.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"execCommand.js","sourceRoot":"","sources":["../../src/tools/execCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAS,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAEjC,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;AAElC,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,IAAI,EAAE,cAAc;IACpB,WAAW,EACT,iEAAiE;IACnE,WAAW,EAAE;QACX,IAAI,EAAE,QAAiB;QACvB,UAAU,EAAE;YACV,OAAO,EAAE;gBACP,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,uDAAuD;aACrE;YACD,GAAG,EAAE;gBACH,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,YAAY;aAC1B;YACD,OAAO,EAAE;gBACP,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,mBAAmB;aACjC;SACF;QACD,QAAQ,EAAE,CAAC,SAAS,CAAC;KACtB;CACF,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,IAIxC;IACC,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,GAAG,KAAK,EAAE,GAAG,IAAI,CAAC;IAC/C,MAAM,OAAO,GAAG,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAErC,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,OAAO,EAAE;YAClD,GAAG,EAAE,OAAO;YACZ,OAAO;YACP,SAAS,EAAE,IAAI,GAAG,IAAI,GAAG,EAAE,EAAE,OAAO;YACpC,KAAK,EAAE,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,WAAW;SACrE,CAAC,CAAC;QAEH,MAAM,MAAM,GAAa;YACvB,KAAK,OAAO,EAAE;YACd,MAAM,OAAO,EAAE;YACf,UAAU;SACX,CAAC;QACF,IAAI,MAAM,CAAC,IAAI,EAAE;YAAE,MAAM,CAAC,IAAI,CAAC,qBAAqB,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACrE,IAAI,MAAM,CAAC,IAAI,EAAE;YAAE,MAAM,CAAC,IAAI,CAAC,qBAAqB,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAErE,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC3B,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,MAAM,MAAM,GAAa;YACvB,KAAK,OAAO,EAAE;YACd,MAAM,OAAO,EAAE;YACf,UAAU,KAAK,CAAC,IAAI,IAAI,SAAS,EAAE;SACpC,CAAC;QACF,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,EAAE;YAAE,MAAM,CAAC,IAAI,CAAC,qBAAqB,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAClF,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,EAAE;YAAE,MAAM,CAAC,IAAI,CAAC,qBAAqB,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAClF,IAAI,KAAK,CAAC,MAAM;YAAE,MAAM,CAAC,IAAI,CAAC,YAAY,OAAO,QAAQ,CAAC,CAAC;QAE3D,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC3B,CAAC;AACH,CAAC"}

View File

@@ -0,0 +1,87 @@
export declare const readFileTool: {
name: string;
description: string;
inputSchema: {
type: "object";
properties: {
path: {
type: string;
description: string;
};
start_line: {
type: string;
description: string;
};
end_line: {
type: string;
description: string;
};
};
required: string[];
};
};
export declare const writeFileTool: {
name: string;
description: string;
inputSchema: {
type: "object";
properties: {
path: {
type: string;
description: string;
};
content: {
type: string;
description: string;
};
create_dirs: {
type: string;
description: string;
};
};
required: string[];
};
};
export declare const patchFileTool: {
name: string;
description: string;
inputSchema: {
type: "object";
properties: {
path: {
type: string;
description: string;
};
old_text: {
type: string;
description: string;
};
new_text: {
type: string;
description: string;
};
replace_all: {
type: string;
description: string;
};
};
required: string[];
};
};
export declare function executeReadFile(args: {
path: string;
start_line?: number;
end_line?: number;
}): Promise<string>;
export declare function executeWriteFile(args: {
path: string;
content: string;
create_dirs?: boolean;
}): Promise<string>;
export declare function executePatchFile(args: {
path: string;
old_text: string;
new_text: string;
replace_all?: boolean;
}): Promise<string>;
//# sourceMappingURL=fileOps.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"fileOps.d.ts","sourceRoot":"","sources":["../../src/tools/fileOps.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;CAsBxB,CAAC;AAEF,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;CAsBzB,CAAC;AAEF,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;CA0BzB,CAAC;AAEF,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,MAAM,CAAC,CA0BlB;AAED,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,GAAG,OAAO,CAAC,MAAM,CAAC,CAwBlB;AAED,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,GAAG,OAAO,CAAC,MAAM,CAAC,CA4ClB"}

159
dev-assistant-mcp/dist/tools/fileOps.js vendored Normal file
View File

@@ -0,0 +1,159 @@
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
import { dirname, extname } from "path";
export const readFileTool = {
name: "read_local_file",
description: "读取本地文件内容。支持任意文本文件,返回带行号的内容。",
inputSchema: {
type: "object",
properties: {
path: {
type: "string",
description: "文件绝对路径",
},
start_line: {
type: "number",
description: "起始行号(可选,从 1 开始)",
},
end_line: {
type: "number",
description: "结束行号(可选)",
},
},
required: ["path"],
},
};
export const writeFileTool = {
name: "write_local_file",
description: "写入内容到本地文件。如果文件不存在会自动创建(含父目录)。支持完整写入或按行替换。",
inputSchema: {
type: "object",
properties: {
path: {
type: "string",
description: "文件绝对路径",
},
content: {
type: "string",
description: "要写入的完整文件内容",
},
create_dirs: {
type: "boolean",
description: "是否自动创建父目录(默认 true",
},
},
required: ["path", "content"],
},
};
export const patchFileTool = {
name: "patch_file",
description: "精确修改本地文件。查找指定文本并替换为新文本,支持多次替换。适合自动纠错和代码修改。",
inputSchema: {
type: "object",
properties: {
path: {
type: "string",
description: "文件绝对路径",
},
old_text: {
type: "string",
description: "要查找并替换的原文本(必须精确匹配)",
},
new_text: {
type: "string",
description: "替换后的新文本",
},
replace_all: {
type: "boolean",
description: "是否替换所有匹配项(默认 false只替换第一个",
},
},
required: ["path", "old_text", "new_text"],
},
};
export async function executeReadFile(args) {
const { path: filePath, start_line, end_line } = args;
if (!existsSync(filePath)) {
return `❌ 文件不存在: ${filePath}`;
}
try {
const content = readFileSync(filePath, "utf-8");
const lines = content.split("\n");
const start = (start_line || 1) - 1;
const end = end_line || lines.length;
const selected = lines.slice(start, end);
const numbered = selected.map((line, i) => `${String(start + i + 1).padStart(4)} | ${line}`).join("\n");
return [
`📄 ${filePath}`,
`行数: ${lines.length} | 显示: ${start + 1}-${Math.min(end, lines.length)}`,
`类型: ${extname(filePath) || "unknown"}`,
``,
numbered,
].join("\n");
}
catch (error) {
return `❌ 读取失败: ${error.message}`;
}
}
export async function executeWriteFile(args) {
const { path: filePath, content, create_dirs = true } = args;
try {
if (create_dirs) {
const dir = dirname(filePath);
if (!existsSync(dir)) {
mkdirSync(dir, { recursive: true });
}
}
const existed = existsSync(filePath);
const oldLines = existed ? readFileSync(filePath, "utf-8").split("\n").length : 0;
writeFileSync(filePath, content, "utf-8");
const newLines = content.split("\n").length;
return [
`✅ 文件已${existed ? "更新" : "创建"}: ${filePath}`,
existed ? `行数变化: ${oldLines}${newLines}` : `行数: ${newLines}`,
].join("\n");
}
catch (error) {
return `❌ 写入失败: ${error.message}`;
}
}
export async function executePatchFile(args) {
const { path: filePath, old_text, new_text, replace_all = false } = args;
if (!existsSync(filePath)) {
return `❌ 文件不存在: ${filePath}`;
}
try {
const content = readFileSync(filePath, "utf-8");
if (!content.includes(old_text)) {
return `❌ 未找到匹配文本。\n\n搜索内容:\n\`\`\`\n${old_text.slice(0, 200)}\n\`\`\`\n\n提示: old_text 必须精确匹配文件中的内容(包括空格和换行)`;
}
const occurrences = content.split(old_text).length - 1;
let newContent;
if (replace_all) {
newContent = content.split(old_text).join(new_text);
}
else {
const idx = content.indexOf(old_text);
newContent = content.substring(0, idx) + new_text + content.substring(idx + old_text.length);
}
writeFileSync(filePath, newContent, "utf-8");
const replacedCount = replace_all ? occurrences : 1;
return [
`✅ 文件已修改: ${filePath}`,
`替换: ${replacedCount}${occurrences > 1 && !replace_all ? `(共找到 ${occurrences} 处匹配,仅替换第 1 处)` : ""}`,
``,
`--- 旧代码 ---`,
"```",
old_text.slice(0, 500),
"```",
``,
`+++ 新代码 +++`,
"```",
new_text.slice(0, 500),
"```",
].join("\n");
}
catch (error) {
return `❌ 修改失败: ${error.message}`;
}
}
//# sourceMappingURL=fileOps.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"fileOps.js","sourceRoot":"","sources":["../../src/tools/fileOps.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,39 @@
export declare const gitOpsTool: {
name: string;
description: string;
inputSchema: {
type: "object";
properties: {
project_path: {
type: string;
description: string;
};
action: {
type: string;
description: string;
enum: string[];
};
message: {
type: string;
description: string;
};
target: {
type: string;
description: string;
};
count: {
type: string;
description: string;
};
};
required: string[];
};
};
export declare function executeGitOps(args: {
project_path: string;
action: string;
message?: string;
target?: string;
count?: number;
}): Promise<string>;
//# sourceMappingURL=gitOps.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"gitOps.d.ts","sourceRoot":"","sources":["../../src/tools/gitOps.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmCtB,CAAC;AAeF,wBAAsB,aAAa,CAAC,IAAI,EAAE;IACxC,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAwIlB"}

169
dev-assistant-mcp/dist/tools/gitOps.js vendored Normal file
View File

@@ -0,0 +1,169 @@
import { exec } from "child_process";
import { promisify } from "util";
const execAsync = promisify(exec);
export const gitOpsTool = {
name: "git_ops",
description: "Git 全套操作。支持 status、diff、add、commit、push、pull、log、branch、checkout、stash、reset 等所有常用 Git 命令。自动解析输出为结构化报告。",
inputSchema: {
type: "object",
properties: {
project_path: {
type: "string",
description: "项目根目录(绝对路径)",
},
action: {
type: "string",
description: "Git 操作",
enum: [
"status", "diff", "diff_staged", "add", "add_all", "commit",
"push", "pull", "log", "branch", "branch_create", "checkout",
"stash", "stash_pop", "reset_soft", "reset_hard", "remote", "init",
],
},
message: {
type: "string",
description: "commit 消息commit 时必填)",
},
target: {
type: "string",
description: "目标参数(文件路径/分支名/commit hash 等)",
},
count: {
type: "number",
description: "log 显示条数(默认 10",
},
},
required: ["project_path", "action"],
},
};
async function git(args, cwd) {
try {
const { stdout, stderr } = await execAsync(`git ${args}`, {
cwd,
timeout: 30000,
maxBuffer: 1024 * 1024 * 5,
});
return { stdout, stderr, code: 0 };
}
catch (error) {
return { stdout: error.stdout || "", stderr: error.stderr || "", code: error.code ?? 1 };
}
}
export async function executeGitOps(args) {
const { project_path, action, message, target, count = 10 } = args;
let result;
let title = "";
switch (action) {
case "status":
title = "Git Status";
result = await git("status --short --branch", project_path);
if (result.code === 0) {
const lines = result.stdout.trim().split("\n");
const branch = lines[0] || "";
const changes = lines.slice(1);
const staged = changes.filter((l) => /^[MADRC]/.test(l));
const unstaged = changes.filter((l) => /^.[MADRC]/.test(l));
const untracked = changes.filter((l) => l.startsWith("??"));
return [
`# ${title}`, `📂 ${project_path}`, `🌿 ${branch}`, ``,
`| 状态 | 数量 |`, `|------|------|`,
`| ✅ 已暂存 | ${staged.length} |`,
`| 📝 已修改 | ${unstaged.length} |`,
`| ❓ 未跟踪 | ${untracked.length} |`, ``,
changes.length > 0 ? "```\n" + result.stdout.trim() + "\n```" : "✨ 工作区干净",
].join("\n");
}
break;
case "diff":
title = "Git Diff (工作区)";
result = await git(`diff ${target ? `-- "${target}"` : ""} --stat`, project_path);
if (result.stdout.trim()) {
const detail = await git(`diff ${target ? `-- "${target}"` : ""} --no-color`, project_path);
return `# ${title}\n\n## 摘要\n\`\`\`\n${result.stdout.trim()}\n\`\`\`\n\n## 详细\n\`\`\`diff\n${detail.stdout.slice(0, 8000)}\n\`\`\``;
}
return `# ${title}\n\n✨ 无差异`;
case "diff_staged":
title = "Git Diff (暂存区)";
result = await git("diff --cached --stat", project_path);
if (result.stdout.trim()) {
const detail = await git("diff --cached --no-color", project_path);
return `# ${title}\n\n## 摘要\n\`\`\`\n${result.stdout.trim()}\n\`\`\`\n\n## 详细\n\`\`\`diff\n${detail.stdout.slice(0, 8000)}\n\`\`\``;
}
return `# ${title}\n\n✨ 暂存区无内容`;
case "add":
title = "Git Add";
result = await git(`add "${target || "."}"`, project_path);
break;
case "add_all":
title = "Git Add All";
result = await git("add -A", project_path);
break;
case "commit":
if (!message)
return "❌ commit 需要提供 message 参数";
title = "Git Commit";
result = await git(`commit -m "${message.replace(/"/g, '\\"')}"`, project_path);
break;
case "push":
title = "Git Push";
result = await git(`push ${target || ""}`, project_path);
break;
case "pull":
title = "Git Pull";
result = await git(`pull ${target || ""}`, project_path);
break;
case "log":
title = "Git Log";
result = await git(`log --oneline --graph --decorate -n ${count}`, project_path);
if (result.code === 0) {
return `# ${title} (最近 ${count} 条)\n\n\`\`\`\n${result.stdout.trim()}\n\`\`\``;
}
break;
case "branch":
title = "Git Branch";
result = await git("branch -a -v", project_path);
break;
case "branch_create":
if (!target)
return "❌ 创建分支需要提供 target分支名";
title = `Git Branch Create: ${target}`;
result = await git(`checkout -b "${target}"`, project_path);
break;
case "checkout":
if (!target)
return "❌ checkout 需要提供 target分支名或文件";
title = `Git Checkout: ${target}`;
result = await git(`checkout "${target}"`, project_path);
break;
case "stash":
title = "Git Stash";
result = await git(`stash${message ? ` push -m "${message}"` : ""}`, project_path);
break;
case "stash_pop":
title = "Git Stash Pop";
result = await git("stash pop", project_path);
break;
case "reset_soft":
title = "Git Reset (soft)";
result = await git(`reset --soft ${target || "HEAD~1"}`, project_path);
break;
case "reset_hard":
title = "Git Reset (hard) ⚠️";
result = await git(`reset --hard ${target || "HEAD"}`, project_path);
break;
case "remote":
title = "Git Remote";
result = await git("remote -v", project_path);
break;
case "init":
title = "Git Init";
result = await git("init", project_path);
break;
default:
return `❌ 未知 Git 操作: ${action}`;
}
const output = [result.stdout, result.stderr].filter(Boolean).join("\n").trim();
const icon = result.code === 0 ? "✅" : "❌";
return `# ${icon} ${title}\n\n📂 ${project_path}\n\n\`\`\`\n${output || "(无输出)"}\n\`\`\``;
}
//# sourceMappingURL=gitOps.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,28 @@
export declare const lintCheckTool: {
name: string;
description: string;
inputSchema: {
type: "object";
properties: {
project_path: {
type: string;
description: string;
};
fix: {
type: string;
description: string;
};
files: {
type: string;
description: string;
};
};
required: string[];
};
};
export declare function executeLintCheck(args: {
project_path: string;
fix?: boolean;
files?: string;
}): Promise<string>;
//# sourceMappingURL=lintCheck.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"lintCheck.d.ts","sourceRoot":"","sources":["../../src/tools/lintCheck.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;CAsBzB,CAAC;AA4BF,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,YAAY,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAuGlB"}

View File

@@ -0,0 +1,133 @@
import { exec } from "child_process";
import { promisify } from "util";
import { existsSync } from "fs";
import { join } from "path";
const execAsync = promisify(exec);
export const lintCheckTool = {
name: "lint_check",
description: "对项目执行代码检查。自动检测项目类型并运行对应的 lint 工具ESLint、TypeScript 编译检查、Pylint 等),返回结构化的错误列表。",
inputSchema: {
type: "object",
properties: {
project_path: {
type: "string",
description: "项目根目录(绝对路径)",
},
fix: {
type: "boolean",
description: "是否自动修复可修复的问题(默认 false",
},
files: {
type: "string",
description: "指定检查的文件或 glob可选默认检查整个项目",
},
},
required: ["project_path"],
},
};
async function runCommand(cmd, cwd, timeout = 30000) {
try {
const { stdout, stderr } = await execAsync(cmd, {
cwd,
timeout,
maxBuffer: 1024 * 1024 * 5,
shell: process.platform === "win32" ? "powershell.exe" : "/bin/bash",
});
return { stdout, stderr, code: 0 };
}
catch (error) {
return {
stdout: error.stdout || "",
stderr: error.stderr || "",
code: error.code ?? 1,
};
}
}
export async function executeLintCheck(args) {
const { project_path, fix = false, files } = args;
const results = [];
const hasFile = (name) => existsSync(join(project_path, name));
const hasNodeModules = hasFile("node_modules");
// TypeScript 编译检查
if (hasFile("tsconfig.json")) {
const result = await runCommand("npx tsc --noEmit --pretty", project_path);
const errorCount = (result.stdout.match(/error TS/g) || []).length;
results.push({
tool: "TypeScript (tsc --noEmit)",
success: result.code === 0,
errorCount,
warningCount: 0,
output: result.stdout || result.stderr || "(无输出)",
});
}
// ESLint
if (hasFile(".eslintrc.js") || hasFile(".eslintrc.json") || hasFile(".eslintrc.yml") || hasFile("eslint.config.js") || hasFile("eslint.config.mjs")) {
const target = files || "src/";
const fixFlag = fix ? " --fix" : "";
const result = await runCommand(`npx eslint ${target}${fixFlag} --format stylish`, project_path);
const errorMatch = result.stdout.match(/(\d+) errors?/);
const warnMatch = result.stdout.match(/(\d+) warnings?/);
results.push({
tool: `ESLint${fix ? " (--fix)" : ""}`,
success: result.code === 0,
errorCount: errorMatch ? parseInt(errorMatch[1]) : 0,
warningCount: warnMatch ? parseInt(warnMatch[1]) : 0,
output: result.stdout || result.stderr || "✅ 无问题",
});
}
// Python: pylint / flake8
if (hasFile("requirements.txt") || hasFile("setup.py") || hasFile("pyproject.toml")) {
const target = files || ".";
// 优先 flake8
const result = await runCommand(`python -m flake8 ${target} --max-line-length=120 --count`, project_path);
if (result.code !== 127) { // 127 = command not found
const lines = result.stdout.trim().split("\n").filter(Boolean);
results.push({
tool: "Flake8",
success: result.code === 0,
errorCount: lines.length,
warningCount: 0,
output: result.stdout || result.stderr || "✅ 无问题",
});
}
}
// 如果什么检查工具都没找到
if (results.length === 0) {
// 尝试通用的 package.json lint 脚本
if (hasFile("package.json")) {
const result = await runCommand("npm run lint 2>&1 || echo LINT_SCRIPT_NOT_FOUND", project_path);
if (!result.stdout.includes("LINT_SCRIPT_NOT_FOUND") && !result.stdout.includes("Missing script")) {
results.push({
tool: "npm run lint",
success: result.code === 0,
errorCount: result.code === 0 ? 0 : 1,
warningCount: 0,
output: result.stdout || result.stderr,
});
}
}
}
if (results.length === 0) {
return `# Lint 检查结果\n\n⚠️ 未检测到 lint 工具配置ESLint、tsconfig、pylint 等)\n项目路径: ${project_path}\n\n建议:\n- TypeScript 项目:添加 tsconfig.json\n- JS 项目npm init @eslint/config\n- Python 项目pip install flake8`;
}
// 组装报告
const totalErrors = results.reduce((sum, r) => sum + r.errorCount, 0);
const totalWarnings = results.reduce((sum, r) => sum + r.warningCount, 0);
const allPassed = results.every((r) => r.success);
const output = [
`# Lint 检查报告`,
``,
`📂 项目: ${project_path}`,
`${allPassed ? "✅ 全部通过" : "❌ 发现问题"} | 错误: ${totalErrors} | 警告: ${totalWarnings}`,
``,
];
for (const r of results) {
output.push(`## ${r.success ? "✅" : "❌"} ${r.tool}`, `错误: ${r.errorCount} | 警告: ${r.warningCount}`, "```", r.output.slice(0, 3000), // 限制输出长度
"```", ``);
}
if (!allPassed && !fix) {
output.push(`💡 提示: 可以设置 fix=true 自动修复可修复的问题`);
}
return output.join("\n");
}
//# sourceMappingURL=lintCheck.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,23 @@
export declare const projectScanTool: {
name: string;
description: string;
inputSchema: {
type: "object";
properties: {
project_path: {
type: string;
description: string;
};
max_depth: {
type: string;
description: string;
};
};
required: string[];
};
};
export declare function executeProjectScan(args: {
project_path: string;
max_depth?: number;
}): Promise<string>;
//# sourceMappingURL=projectScan.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"projectScan.d.ts","sourceRoot":"","sources":["../../src/tools/projectScan.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;CAkB3B,CAAC;AAmDF,wBAAsB,kBAAkB,CAAC,IAAI,EAAE;IAC7C,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,MAAM,CAAC,CA4GlB"}

View 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

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,28 @@
export declare const runTestsTool: {
name: string;
description: string;
inputSchema: {
type: "object";
properties: {
project_path: {
type: string;
description: string;
};
test_file: {
type: string;
description: string;
};
test_name: {
type: string;
description: string;
};
};
required: string[];
};
};
export declare function executeRunTests(args: {
project_path: string;
test_file?: string;
test_name?: string;
}): Promise<string>;
//# sourceMappingURL=runTests.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"runTests.d.ts","sourceRoot":"","sources":["../../src/tools/runTests.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;CAsBxB,CAAC;AAoBF,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAC1C,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,MAAM,CAAC,CAiGlB"}

137
dev-assistant-mcp/dist/tools/runTests.js vendored Normal file
View File

@@ -0,0 +1,137 @@
import { exec } from "child_process";
import { promisify } from "util";
import { existsSync } from "fs";
import { join } from "path";
const execAsync = promisify(exec);
export const runTestsTool = {
name: "run_tests",
description: "运行项目测试。自动检测测试框架Jest、Mocha、Pytest 等),执行测试并返回结构化的结果(通过/失败/跳过数量及失败详情)。",
inputSchema: {
type: "object",
properties: {
project_path: {
type: "string",
description: "项目根目录(绝对路径)",
},
test_file: {
type: "string",
description: "指定测试文件(可选,默认运行全部测试)",
},
test_name: {
type: "string",
description: "指定测试名称或模式(可选)",
},
},
required: ["project_path"],
},
};
async function runCommand(cmd, cwd) {
try {
const { stdout, stderr } = await execAsync(cmd, {
cwd,
timeout: 120000,
maxBuffer: 1024 * 1024 * 10,
shell: process.platform === "win32" ? "powershell.exe" : "/bin/bash",
});
return { stdout, stderr, code: 0 };
}
catch (error) {
return {
stdout: error.stdout || "",
stderr: error.stderr || "",
code: error.code ?? 1,
};
}
}
export async function executeRunTests(args) {
const { project_path, test_file, test_name } = args;
const hasFile = (name) => existsSync(join(project_path, name));
let testCmd = "";
let framework = "";
// 检测测试框架
if (hasFile("jest.config.js") || hasFile("jest.config.ts") || hasFile("jest.config.mjs")) {
framework = "Jest";
testCmd = "npx jest --verbose --no-coverage";
if (test_file)
testCmd += ` "${test_file}"`;
if (test_name)
testCmd += ` -t "${test_name}"`;
}
else if (hasFile("vitest.config.ts") || hasFile("vitest.config.js")) {
framework = "Vitest";
testCmd = "npx vitest run --reporter verbose";
if (test_file)
testCmd += ` "${test_file}"`;
}
else if (hasFile("pytest.ini") || hasFile("pyproject.toml") || hasFile("setup.cfg")) {
framework = "Pytest";
testCmd = "python -m pytest -v";
if (test_file)
testCmd += ` "${test_file}"`;
if (test_name)
testCmd += ` -k "${test_name}"`;
}
else if (hasFile("package.json")) {
// 尝试 package.json 中的 test 脚本
framework = "npm test";
testCmd = "npm test 2>&1";
}
else if (hasFile("requirements.txt")) {
framework = "Pytest (default)";
testCmd = "python -m pytest -v";
if (test_file)
testCmd += ` "${test_file}"`;
}
if (!testCmd) {
return `# 测试结果\n\n⚠️ 未检测到测试框架\n项目路径: ${project_path}\n\n建议:\n- JS/TS: npm install -D jest 或 vitest\n- Python: pip install pytest`;
}
const result = await runCommand(testCmd, project_path);
const fullOutput = (result.stdout + "\n" + result.stderr).trim();
// 解析测试结果
let passed = 0, failed = 0, skipped = 0;
// Jest / Vitest 格式
const jestMatch = fullOutput.match(/Tests:\s+(?:(\d+) failed,?\s*)?(?:(\d+) skipped,?\s*)?(?:(\d+) passed)?/);
if (jestMatch) {
failed = parseInt(jestMatch[1] || "0");
skipped = parseInt(jestMatch[2] || "0");
passed = parseInt(jestMatch[3] || "0");
}
// Pytest 格式
const pytestMatch = fullOutput.match(/(\d+) passed(?:.*?(\d+) failed)?(?:.*?(\d+) skipped)?/);
if (pytestMatch) {
passed = parseInt(pytestMatch[1] || "0");
failed = parseInt(pytestMatch[2] || "0");
skipped = parseInt(pytestMatch[3] || "0");
}
const total = passed + failed + skipped;
const allPassed = failed === 0 && result.code === 0;
const output = [
`# 测试报告`,
``,
`📂 项目: ${project_path}`,
`🔧 框架: ${framework}`,
``,
`## 结果`,
allPassed ? "✅ **全部通过**" : "❌ **存在失败**",
``,
`| 状态 | 数量 |`,
`|------|------|`,
`| ✅ 通过 | ${passed} |`,
`| ❌ 失败 | ${failed} |`,
`| ⏭️ 跳过 | ${skipped} |`,
`| 📊 总计 | ${total} |`,
``,
`## 命令`,
`\`${testCmd}\``,
``,
`## 完整输出`,
"```",
fullOutput.slice(0, 5000),
"```",
];
if (failed > 0) {
output.push(``, `## 建议`, `1. 查看上方失败的测试用例详情`, `2. 使用 code_debug 工具分析失败原因`, `3. 修复后重新运行 run_tests 验证`);
}
return output.join("\n");
}
//# sourceMappingURL=runTests.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"runTests.js","sourceRoot":"","sources":["../../src/tools/runTests.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,44 @@
export declare const searchCodeTool: {
name: string;
description: string;
inputSchema: {
type: "object";
properties: {
project_path: {
type: string;
description: string;
};
query: {
type: string;
description: string;
};
mode: {
type: string;
description: string;
enum: string[];
};
includes: {
type: string;
description: string;
};
case_sensitive: {
type: string;
description: string;
};
max_results: {
type: string;
description: string;
};
};
required: string[];
};
};
export declare function executeSearchCode(args: {
project_path: string;
query: string;
mode?: string;
includes?: string;
case_sensitive?: boolean;
max_results?: number;
}): Promise<string>;
//# sourceMappingURL=searchCode.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"searchCode.d.ts","sourceRoot":"","sources":["../../src/tools/searchCode.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmC1B,CAAC;AAiGF,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAC5C,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GAAG,OAAO,CAAC,MAAM,CAAC,CA2DlB"}

View File

@@ -0,0 +1,176 @@
import { exec } from "child_process";
import { promisify } from "util";
import { readdirSync, readFileSync, statSync } from "fs";
import { join, extname, relative } from "path";
const execAsync = promisify(exec);
export const searchCodeTool = {
name: "search_code",
description: "在项目中搜索代码。支持正则表达式、文本搜索、文件名搜索。返回匹配的文件、行号和上下文。类似 grep/ripgrep。",
inputSchema: {
type: "object",
properties: {
project_path: {
type: "string",
description: "项目根目录(绝对路径)",
},
query: {
type: "string",
description: "搜索内容(支持正则表达式)",
},
mode: {
type: "string",
description: "搜索模式content=代码内容默认、filename=文件名、symbol=函数/类名",
enum: ["content", "filename", "symbol"],
},
includes: {
type: "string",
description: "文件过滤 glob如 *.ts, *.py",
},
case_sensitive: {
type: "boolean",
description: "是否区分大小写(默认 false",
},
max_results: {
type: "number",
description: "最大结果数(默认 50",
},
},
required: ["project_path", "query"],
},
};
const SKIP_DIRS = new Set([
"node_modules", ".git", "__pycache__", "dist", "build", ".next",
".nuxt", "coverage", ".cache", ".tsbuildinfo", "vendor",
]);
const TEXT_EXTS = new Set([
".ts", ".tsx", ".js", ".jsx", ".py", ".java", ".go", ".rs", ".c", ".cpp", ".h",
".css", ".scss", ".less", ".html", ".vue", ".svelte", ".json", ".yaml", ".yml",
".toml", ".md", ".txt", ".sh", ".bat", ".ps1", ".sql", ".graphql", ".prisma",
".env", ".gitignore", ".eslintrc", ".prettierrc",
]);
function searchInDir(dir, rootDir, regex, mode, includeExt, results, maxResults, depth = 0) {
if (depth > 10 || results.length >= maxResults)
return;
try {
const entries = readdirSync(dir);
for (const entry of entries) {
if (results.length >= maxResults)
break;
if (SKIP_DIRS.has(entry) || entry.startsWith("."))
continue;
const fullPath = join(dir, entry);
try {
const stat = statSync(fullPath);
if (stat.isDirectory()) {
searchInDir(fullPath, rootDir, regex, mode, includeExt, results, maxResults, depth + 1);
}
else if (stat.isFile()) {
const ext = extname(entry).toLowerCase();
// 文件名搜索
if (mode === "filename") {
if (regex.test(entry)) {
results.push({ file: relative(rootDir, fullPath), line: 0, content: entry });
}
continue;
}
// 内容搜索 - 只搜索文本文件
if (!TEXT_EXTS.has(ext) && ext !== "")
continue;
if (includeExt && !entry.endsWith(includeExt.replace("*", "")))
continue;
if (stat.size > 1024 * 512)
continue; // 跳过 >512KB 的文件
const content = readFileSync(fullPath, "utf-8");
const lines = content.split("\n");
for (let i = 0; i < lines.length; i++) {
if (results.length >= maxResults)
break;
if (mode === "symbol") {
// 只匹配函数/类/接口定义
const line = lines[i];
if (/(?:function|class|interface|def|const|let|var|export)\s/.test(line) && regex.test(line)) {
results.push({
file: relative(rootDir, fullPath),
line: i + 1,
content: line.trim(),
context_before: i > 0 ? lines[i - 1].trim() : undefined,
context_after: i < lines.length - 1 ? lines[i + 1].trim() : undefined,
});
}
}
else {
if (regex.test(lines[i])) {
results.push({
file: relative(rootDir, fullPath),
line: i + 1,
content: lines[i].trim(),
context_before: i > 0 ? lines[i - 1].trim() : undefined,
context_after: i < lines.length - 1 ? lines[i + 1].trim() : undefined,
});
}
}
}
}
}
catch { }
}
}
catch { }
}
export async function executeSearchCode(args) {
const { project_path, query, mode = "content", includes, case_sensitive = false, max_results = 50 } = args;
const flags = case_sensitive ? "" : "i";
let regex;
try {
regex = new RegExp(query, flags);
}
catch {
regex = new RegExp(query.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), flags);
}
const results = [];
const includeExt = includes ? includes.replace("*", "") : null;
searchInDir(project_path, project_path, regex, mode, includeExt, results, max_results);
if (results.length === 0) {
return `# 搜索结果\n\n🔍 "${query}" (${mode})\n📂 ${project_path}\n\n_未找到匹配结果_`;
}
// 按文件分组
const grouped = {};
for (const r of results) {
(grouped[r.file] || (grouped[r.file] = [])).push(r);
}
const fileCount = Object.keys(grouped).length;
const output = [
`# 搜索结果`,
``,
`🔍 "${query}" | 模式: ${mode}${includes ? ` | 过滤: ${includes}` : ""}`,
`📂 ${project_path}`,
`📊 ${results.length} 个匹配,${fileCount} 个文件`,
``,
];
for (const [file, matches] of Object.entries(grouped)) {
output.push(`## 📄 ${file} (${matches.length} 处)`);
for (const m of matches) {
if (mode === "filename") {
output.push(`- ${m.content}`);
}
else {
output.push(`**行 ${m.line}:**`);
if (m.context_before)
output.push(`\`\`\`\n ${m.context_before}`);
else
output.push("```");
output.push(`${m.content}`);
if (m.context_after)
output.push(` ${m.context_after}\n\`\`\``);
else
output.push("```");
}
}
output.push(``);
}
if (results.length >= max_results) {
output.push(`\n⚠️ 结果已截断(最大 ${max_results} 条),可增大 max_results 或缩小搜索范围`);
}
return output.join("\n");
}
//# sourceMappingURL=searchCode.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,34 @@
export declare const workflowTool: {
name: string;
description: string;
inputSchema: {
type: "object";
properties: {
project_path: {
type: string;
description: string;
};
preset: {
type: string;
description: string;
enum: string[];
};
steps: {
type: string;
description: string;
};
stop_on_error: {
type: string;
description: string;
};
};
required: string[];
};
};
export declare function executeWorkflow(args: {
project_path: string;
preset?: string;
steps?: string;
stop_on_error?: boolean;
}): Promise<string>;
//# sourceMappingURL=workflow.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"workflow.d.ts","sourceRoot":"","sources":["../../src/tools/workflow.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;CAkCxB,CAAC;AA+DF,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAC1C,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,GAAG,OAAO,CAAC,MAAM,CAAC,CAkIlB"}

180
dev-assistant-mcp/dist/tools/workflow.js vendored Normal file
View File

@@ -0,0 +1,180 @@
import { executeProjectScan } from "./projectScan.js";
import { executeLintCheck } from "./lintCheck.js";
import { executeAutoFix } from "./autoFix.js";
import { executeBuildProject } from "./buildProject.js";
import { executeRunTests } from "./runTests.js";
import { executeGitOps } from "./gitOps.js";
import { executeDepManage } from "./depManage.js";
export const workflowTool = {
name: "workflow",
description: "自动化工作流编排。串联多个工具形成流水线一键执行完整开发流程。内置多种预设流程全量检查、CI 模拟、项目初始化等),也支持自定义步骤。",
inputSchema: {
type: "object",
properties: {
project_path: {
type: "string",
description: "项目根目录(绝对路径)",
},
preset: {
type: "string",
description: "预设工作流",
enum: [
"full_check", // 全量检查scan → lint → build → test
"fix_and_verify", // 修复验证auto_fix → lint → build → test
"pre_commit", // 提交前检查lint → build → test → git status
"ci_simulate", // CI 模拟install → lint → build → test → audit
"quick_scan", // 快速扫描scan → lint
"deploy_prep", // 部署准备lint → build → test → git status
],
},
steps: {
type: "string",
description: "自定义步骤,逗号分隔(如 scan,lint,fix,build,test,git_status,audit。与 preset 二选一。",
},
stop_on_error: {
type: "boolean",
description: "遇到错误是否停止(默认 true",
},
},
required: ["project_path"],
},
};
const STEP_MAP = {
scan: {
name: "📋 项目扫描",
fn: (p) => executeProjectScan({ project_path: p }),
},
lint: {
name: "🔍 代码检查",
fn: (p) => executeLintCheck({ project_path: p }),
},
fix: {
name: "🔧 自动修复",
fn: (p) => executeAutoFix({ project_path: p }),
},
build: {
name: "🏗️ 构建项目",
fn: (p) => executeBuildProject({ project_path: p }),
},
test: {
name: "🧪 运行测试",
fn: (p) => executeRunTests({ project_path: p }),
},
git_status: {
name: "📊 Git 状态",
fn: (p) => executeGitOps({ project_path: p, action: "status" }),
},
git_diff: {
name: "📝 Git Diff",
fn: (p) => executeGitOps({ project_path: p, action: "diff" }),
},
audit: {
name: "🛡️ 安全审计",
fn: (p) => executeDepManage({ project_path: p, action: "audit" }),
},
outdated: {
name: "📦 过时依赖检查",
fn: (p) => executeDepManage({ project_path: p, action: "outdated" }),
},
install: {
name: "📥 安装依赖",
fn: (p) => executeDepManage({ project_path: p, action: "install" }),
},
};
const PRESETS = {
full_check: ["scan", "lint", "build", "test"],
fix_and_verify: ["fix", "lint", "build", "test"],
pre_commit: ["lint", "build", "test", "git_status"],
ci_simulate: ["install", "lint", "build", "test", "audit"],
quick_scan: ["scan", "lint"],
deploy_prep: ["lint", "build", "test", "git_status"],
};
export async function executeWorkflow(args) {
const { project_path, preset, steps, stop_on_error = true } = args;
// 确定步骤列表
let stepKeys;
let workflowName;
if (steps) {
stepKeys = steps.split(",").map((s) => s.trim());
workflowName = "自定义工作流";
}
else if (preset && PRESETS[preset]) {
stepKeys = PRESETS[preset];
workflowName = `预设: ${preset}`;
}
else {
// 默认全量检查
stepKeys = PRESETS.full_check;
workflowName = "预设: full_check全量检查";
}
// 验证步骤
const invalidSteps = stepKeys.filter((k) => !STEP_MAP[k]);
if (invalidSteps.length > 0) {
return `❌ 未知步骤: ${invalidSteps.join(", ")}\n\n可用步骤: ${Object.keys(STEP_MAP).join(", ")}`;
}
const totalSteps = stepKeys.length;
const startTime = Date.now();
const results = [];
const output = [
`# 🚀 工作流执行`,
``,
`📂 ${project_path}`,
`📋 ${workflowName}`,
`📊 共 ${totalSteps} 个步骤`,
`${stop_on_error ? "⛔ 遇错停止" : "⏭️ 遇错继续"}`,
``,
`---`,
``,
];
let hasError = false;
for (let i = 0; i < stepKeys.length; i++) {
const key = stepKeys[i];
const step = STEP_MAP[key];
output.push(`## [${i + 1}/${totalSteps}] ${step.name}`);
const stepStart = Date.now();
try {
const result = await step.fn(project_path);
const duration = Date.now() - stepStart;
// 判断步骤是否成功(检查输出中的错误标志)
const isError = result.includes("❌") && !result.includes("✅");
const stepSuccess = !isError;
results.push({
name: step.name,
success: stepSuccess,
duration,
output: result,
});
output.push(`${stepSuccess ? "✅ 通过" : "❌ 失败"} (${(duration / 1000).toFixed(1)}s)`, ``, `<details>`, `<summary>查看详情</summary>`, ``, result.slice(0, 3000), ``, `</details>`, ``);
if (!stepSuccess) {
hasError = true;
if (stop_on_error) {
output.push(`\n⛔ **遇到错误,工作流停止。** 后续步骤: ${stepKeys.slice(i + 1).join(" → ")}`);
break;
}
}
}
catch (error) {
const duration = Date.now() - stepStart;
results.push({ name: step.name, success: false, duration, output: error.message });
output.push(`❌ 异常 (${(duration / 1000).toFixed(1)}s): ${error.message}`, ``);
hasError = true;
if (stop_on_error) {
output.push(`\n⛔ **工作流中断**`);
break;
}
}
}
// 总结报告
const totalDuration = Date.now() - startTime;
const passed = results.filter((r) => r.success).length;
const failed = results.filter((r) => !r.success).length;
output.push(``, `---`, ``, `# 📊 工作流总结`, ``, `| 项目 | 值 |`, `|------|------|`, `| 总耗时 | ${(totalDuration / 1000).toFixed(1)}s |`, `| 已执行 | ${results.length}/${totalSteps} |`, `| ✅ 通过 | ${passed} |`, `| ❌ 失败 | ${failed} |`, `| 最终结果 | ${hasError ? "❌ 有问题需要处理" : "✅ 全部通过"} |`, ``);
if (hasError) {
output.push(`## 💡 建议`, `1. 查看失败步骤的详情`, `2. 使用 \`auto_fix\` 自动修复格式问题`, `3. 使用 \`code_debug\` 分析编译错误`, `4. 修复后运行 \`workflow preset=fix_and_verify\` 验证`);
}
else {
output.push(`✨ **所有检查通过,代码质量良好!**`);
}
return output.join("\n");
}
//# sourceMappingURL=workflow.js.map

File diff suppressed because one or more lines are too long