style: apply Prettier formatting to TS/JS/JSON/MD files
Add Prettier as a dev dependency with .prettierrc.json config and .prettierignore. Hook added via mirrors-prettier in pre-commit config. All TypeScript, JSON, Markdown, and YAML files auto-formatted. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
112
src/server.ts
112
src/server.ts
@@ -54,18 +54,8 @@ function findPythonExecutable(scriptPath: string): string {
|
||||
|
||||
// Check for virtual environment
|
||||
const venvPaths = [
|
||||
join(
|
||||
projectRoot,
|
||||
"venv",
|
||||
isWindows ? "Scripts" : "bin",
|
||||
isWindows ? "python.exe" : "python",
|
||||
),
|
||||
join(
|
||||
projectRoot,
|
||||
".venv",
|
||||
isWindows ? "Scripts" : "bin",
|
||||
isWindows ? "python.exe" : "python",
|
||||
),
|
||||
join(projectRoot, "venv", isWindows ? "Scripts" : "bin", isWindows ? "python.exe" : "python"),
|
||||
join(projectRoot, ".venv", isWindows ? "Scripts" : "bin", isWindows ? "python.exe" : "python"),
|
||||
];
|
||||
|
||||
for (const venvPath of venvPaths) {
|
||||
@@ -77,9 +67,7 @@ function findPythonExecutable(scriptPath: string): string {
|
||||
|
||||
// Allow override via KICAD_PYTHON environment variable (any platform)
|
||||
if (process.env.KICAD_PYTHON) {
|
||||
logger.info(
|
||||
`Using KICAD_PYTHON environment variable: ${process.env.KICAD_PYTHON}`,
|
||||
);
|
||||
logger.info(`Using KICAD_PYTHON environment variable: ${process.env.KICAD_PYTHON}`);
|
||||
return process.env.KICAD_PYTHON;
|
||||
}
|
||||
|
||||
@@ -123,9 +111,7 @@ function findPythonExecutable(scriptPath: string): string {
|
||||
|
||||
for (const path of homebrewPaths) {
|
||||
if (existsSync(path)) {
|
||||
logger.info(
|
||||
`Found Homebrew Python at: ${path} (ensure pcbnew is importable)`,
|
||||
);
|
||||
logger.info(`Found Homebrew Python at: ${path} (ensure pcbnew is importable)`);
|
||||
return path;
|
||||
}
|
||||
}
|
||||
@@ -196,19 +182,14 @@ export class KiCADMcpServer {
|
||||
* @param kicadScriptPath Path to the Python KiCAD interface script
|
||||
* @param logLevel Log level for the server
|
||||
*/
|
||||
constructor(
|
||||
kicadScriptPath: string,
|
||||
logLevel: "error" | "warn" | "info" | "debug" = "info",
|
||||
) {
|
||||
constructor(kicadScriptPath: string, logLevel: "error" | "warn" | "info" | "debug" = "info") {
|
||||
// Set up the logger
|
||||
logger.setLogLevel(logLevel);
|
||||
|
||||
// Check if KiCAD script exists
|
||||
this.kicadScriptPath = kicadScriptPath;
|
||||
if (!existsSync(this.kicadScriptPath)) {
|
||||
throw new Error(
|
||||
`KiCAD interface script not found: ${this.kicadScriptPath}`,
|
||||
);
|
||||
throw new Error(`KiCAD interface script not found: ${this.kicadScriptPath}`);
|
||||
}
|
||||
|
||||
// Initialize the MCP server
|
||||
@@ -267,9 +248,7 @@ export class KiCADMcpServer {
|
||||
registerFootprintPrompts(this.server);
|
||||
|
||||
logger.info("All KiCAD tools, resources, and prompts registered");
|
||||
logger.info(
|
||||
"Router pattern enabled: 4 router tools + direct tools for discovery",
|
||||
);
|
||||
logger.info("Router pattern enabled: 4 router tools + direct tools for discovery");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -277,15 +256,12 @@ export class KiCADMcpServer {
|
||||
*/
|
||||
private async validatePrerequisites(pythonExe: string): Promise<boolean> {
|
||||
const isWindows = process.platform === "win32";
|
||||
const isLinux =
|
||||
process.platform !== "win32" && process.platform !== "darwin";
|
||||
const isLinux = process.platform !== "win32" && process.platform !== "darwin";
|
||||
const errors: string[] = [];
|
||||
|
||||
// Check if Python executable exists (for absolute paths) or is executable (for commands)
|
||||
const isAbsolutePath =
|
||||
pythonExe.startsWith("/") ||
|
||||
pythonExe.startsWith("C:") ||
|
||||
pythonExe.startsWith("\\");
|
||||
pythonExe.startsWith("/") || pythonExe.startsWith("C:") || pythonExe.startsWith("\\");
|
||||
|
||||
if (isAbsolutePath) {
|
||||
// Absolute path: use existsSync
|
||||
@@ -293,16 +269,10 @@ export class KiCADMcpServer {
|
||||
errors.push(`Python executable not found: ${pythonExe}`);
|
||||
|
||||
if (isWindows) {
|
||||
errors.push(
|
||||
"Windows: Install KiCAD 9.0+ from https://www.kicad.org/download/windows/",
|
||||
);
|
||||
errors.push(
|
||||
"Or run: .\\setup-windows.ps1 for automatic configuration",
|
||||
);
|
||||
errors.push("Windows: Install KiCAD 9.0+ from https://www.kicad.org/download/windows/");
|
||||
errors.push("Or run: .\\setup-windows.ps1 for automatic configuration");
|
||||
} else if (isLinux) {
|
||||
errors.push(
|
||||
"Linux: Install KiCAD 9.0+ or set KICAD_PYTHON environment variable",
|
||||
);
|
||||
errors.push("Linux: Install KiCAD 9.0+ or set KICAD_PYTHON environment variable");
|
||||
errors.push("Set KICAD_PYTHON to specify a custom Python path");
|
||||
}
|
||||
}
|
||||
@@ -334,20 +304,14 @@ export class KiCADMcpServer {
|
||||
} catch (error: any) {
|
||||
errors.push(`Python executable not found in PATH: ${pythonExe}`);
|
||||
errors.push(`Error: ${error.message}`);
|
||||
errors.push(
|
||||
"Set KICAD_PYTHON environment variable to specify full path",
|
||||
);
|
||||
errors.push("Set KICAD_PYTHON environment variable to specify full path");
|
||||
|
||||
if (isLinux) {
|
||||
errors.push("");
|
||||
errors.push("Linux troubleshooting:");
|
||||
errors.push("1. Check if python3 is installed: which python3");
|
||||
errors.push(
|
||||
"2. Install KiCAD: sudo apt install kicad (Ubuntu/Debian)",
|
||||
);
|
||||
errors.push(
|
||||
"3. Set KICAD_PYTHON=/usr/bin/python3 in your MCP config",
|
||||
);
|
||||
errors.push("2. Install KiCAD: sudo apt install kicad (Ubuntu/Debian)");
|
||||
errors.push("3. Set KICAD_PYTHON=/usr/bin/python3 in your MCP config");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -358,11 +322,7 @@ export class KiCADMcpServer {
|
||||
}
|
||||
|
||||
// Check if dist/index.js exists (if running from compiled code)
|
||||
const distPath = join(
|
||||
dirname(dirname(this.kicadScriptPath)),
|
||||
"dist",
|
||||
"index.js",
|
||||
);
|
||||
const distPath = join(dirname(dirname(this.kicadScriptPath)), "dist", "index.js");
|
||||
if (!existsSync(distPath)) {
|
||||
errors.push("Project not built. Run: npm run build");
|
||||
}
|
||||
@@ -458,9 +418,7 @@ export class KiCADMcpServer {
|
||||
logger.info("Starting KiCAD MCP server...");
|
||||
|
||||
// Start the Python process for KiCAD scripting
|
||||
logger.info(
|
||||
`Starting Python process with script: ${this.kicadScriptPath}`,
|
||||
);
|
||||
logger.info(`Starting Python process with script: ${this.kicadScriptPath}`);
|
||||
const pythonExe = findPythonExecutable(this.kicadScriptPath);
|
||||
|
||||
logger.info(`Using Python executable: ${pythonExe}`);
|
||||
@@ -468,25 +426,20 @@ export class KiCADMcpServer {
|
||||
// Validate prerequisites
|
||||
const isValid = await this.validatePrerequisites(pythonExe);
|
||||
if (!isValid) {
|
||||
throw new Error(
|
||||
"Prerequisites validation failed. See logs above for details.",
|
||||
);
|
||||
throw new Error("Prerequisites validation failed. See logs above for details.");
|
||||
}
|
||||
this.pythonProcess = spawn(pythonExe, [this.kicadScriptPath], {
|
||||
stdio: ["pipe", "pipe", "pipe"],
|
||||
env: {
|
||||
...process.env,
|
||||
PYTHONPATH:
|
||||
process.env.PYTHONPATH ||
|
||||
"C:/Program Files/KiCad/9.0/lib/python3/dist-packages",
|
||||
process.env.PYTHONPATH || "C:/Program Files/KiCad/9.0/lib/python3/dist-packages",
|
||||
},
|
||||
});
|
||||
|
||||
// Listen for process exit
|
||||
this.pythonProcess.on("exit", (code, signal) => {
|
||||
logger.warn(
|
||||
`Python process exited with code ${code} and signal ${signal}`,
|
||||
);
|
||||
logger.warn(`Python process exited with code ${code} and signal ${signal}`);
|
||||
this.pythonProcess = null;
|
||||
});
|
||||
|
||||
@@ -563,17 +516,10 @@ export class KiCADMcpServer {
|
||||
// Determine timeout based on command type
|
||||
// DRC and export operations need longer timeouts for large boards
|
||||
let commandTimeout = 30000; // Default 30 seconds
|
||||
const longRunningCommands = [
|
||||
"run_drc",
|
||||
"export_gerber",
|
||||
"export_pdf",
|
||||
"export_3d",
|
||||
];
|
||||
const longRunningCommands = ["run_drc", "export_gerber", "export_pdf", "export_3d"];
|
||||
if (longRunningCommands.includes(command)) {
|
||||
commandTimeout = 600000; // 10 minutes for long operations
|
||||
logger.info(
|
||||
`Using extended timeout (${commandTimeout / 1000}s) for command: ${command}`,
|
||||
);
|
||||
logger.info(`Using extended timeout (${commandTimeout / 1000}s) for command: ${command}`);
|
||||
}
|
||||
|
||||
// Add request to queue with timeout info
|
||||
@@ -678,12 +624,8 @@ export class KiCADMcpServer {
|
||||
// Set a timeout (use command-specific timeout or default)
|
||||
const timeoutDuration = request.timeout || 30000;
|
||||
const timeoutHandle = setTimeout(() => {
|
||||
logger.error(
|
||||
`Command timeout after ${timeoutDuration / 1000}s: ${request.command}`,
|
||||
);
|
||||
logger.error(
|
||||
`Buffer contents: ${this.responseBuffer.substring(0, 200)}...`,
|
||||
);
|
||||
logger.error(`Command timeout after ${timeoutDuration / 1000}s: ${request.command}`);
|
||||
logger.error(`Buffer contents: ${this.responseBuffer.substring(0, 200)}...`);
|
||||
|
||||
// Clear state
|
||||
this.responseBuffer = "";
|
||||
@@ -691,11 +633,7 @@ export class KiCADMcpServer {
|
||||
this.processingRequest = false;
|
||||
|
||||
// Reject the promise
|
||||
reject(
|
||||
new Error(
|
||||
`Command timeout after ${timeoutDuration / 1000}s: ${request.command}`,
|
||||
),
|
||||
);
|
||||
reject(new Error(`Command timeout after ${timeoutDuration / 1000}s: ${request.command}`));
|
||||
|
||||
// Process next request
|
||||
setTimeout(() => this.processNextRequest(), 0);
|
||||
|
||||
Reference in New Issue
Block a user