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

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