style: revert Prettier formatting in TS files

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Eugene Mikhantyev
2026-03-29 12:28:30 +01:00
parent 7d53272cb1
commit 8b0ed30ee3
2 changed files with 370 additions and 484 deletions

View File

@@ -1,307 +1,308 @@
/** /**
* Tool Registry for KiCAD MCP Server * Tool Registry for KiCAD MCP Server
* *
* Centralizes all tool definitions and provides lookup/search functionality * Centralizes all tool definitions and provides lookup/search functionality
*/ */
import { z } from "zod"; import { z } from 'zod';
export interface ToolDefinition { export interface ToolDefinition {
name: string; name: string;
description: string; description: string;
inputSchema: z.ZodObject<any> | z.ZodType<any>; inputSchema: z.ZodObject<any> | z.ZodType<any>;
// Handler will be registered separately in the existing tool files // Handler will be registered separately in the existing tool files
} }
export interface ToolCategory { export interface ToolCategory {
name: string; name: string;
description: string; description: string;
tools: string[]; // Tool names in this category tools: string[]; // Tool names in this category
} }
/** /**
* Tool category definitions * Tool category definitions
* Each category groups related tools for better organization * Each category groups related tools for better organization
*/ */
export const toolCategories: ToolCategory[] = [ export const toolCategories: ToolCategory[] = [
{ {
name: "board", name: "board",
description: description: "Board configuration: layers, mounting holes, zones, visualization",
"Board configuration: layers, mounting holes, zones, visualization", tools: [
tools: [ "add_layer",
"add_layer", "set_active_layer",
"set_active_layer", "get_layer_list",
"get_layer_list", "add_mounting_hole",
"add_mounting_hole", "add_board_text",
"add_board_text", "add_zone",
"add_zone", "get_board_extents",
"get_board_extents", "get_board_2d_view",
"get_board_2d_view", "launch_kicad_ui"
"launch_kicad_ui", ]
], },
}, {
{ name: "component",
name: "component", description: "Advanced component operations: edit, delete, search, group, annotate",
description: tools: [
"Advanced component operations: edit, delete, search, group, annotate", "rotate_component",
tools: [ "delete_component",
"rotate_component", "edit_component",
"delete_component", "find_component",
"edit_component", "get_component_properties",
"find_component", "add_component_annotation",
"get_component_properties", "group_components",
"add_component_annotation", "replace_component"
"group_components", ]
"replace_component", },
], {
}, name: "export",
{ description: "File export for fabrication and documentation: Gerber, PDF, BOM, 3D models",
name: "export", tools: [
description: "export_gerber",
"File export for fabrication and documentation: Gerber, PDF, BOM, 3D models", "export_pdf",
tools: [ "export_svg",
"export_gerber", "export_3d",
"export_pdf", "export_bom",
"export_svg", "export_netlist",
"export_3d", "export_position_file",
"export_bom", "export_vrml"
"export_netlist", ]
"export_position_file", },
"export_vrml", {
], name: "drc",
}, description: "Design rule checking and electrical validation: DRC, net classes, clearances",
{ tools: [
name: "drc", "set_design_rules",
description: "get_design_rules",
"Design rule checking and electrical validation: DRC, net classes, clearances", "run_drc",
tools: [ "add_net_class",
"set_design_rules", "assign_net_to_class",
"get_design_rules", "set_layer_constraints",
"run_drc", "check_clearance",
"add_net_class", "get_drc_violations"
"assign_net_to_class", ]
"set_layer_constraints", },
"check_clearance", {
"get_drc_violations", name: "schematic",
], description: "Schematic operations: create, inspect, add/edit/delete components, wire connections, netlists, annotation",
}, tools: [
{ "create_schematic",
name: "schematic", "add_schematic_component",
description: "list_schematic_components",
"Schematic operations: create, inspect, add/edit/delete components, wire connections, netlists, annotation", "move_schematic_component",
tools: [ "rotate_schematic_component",
"create_schematic", "annotate_schematic",
"add_schematic_component", "add_schematic_wire",
"list_schematic_components", "delete_schematic_wire",
"move_schematic_component", "add_schematic_junction",
"rotate_schematic_component", "add_schematic_net_label",
"annotate_schematic", "delete_schematic_net_label",
"add_schematic_wire", "connect_to_net",
"delete_schematic_wire", "connect_passthrough",
"add_schematic_junction", "get_net_connections",
"add_schematic_net_label", "list_schematic_nets",
"delete_schematic_net_label", "list_schematic_wires",
"connect_to_net", "list_schematic_labels",
"connect_passthrough", "get_wire_connections",
"get_net_connections", "generate_netlist",
"list_schematic_nets", "sync_schematic_to_board",
"list_schematic_wires", "get_schematic_view",
"list_schematic_labels", "export_schematic_svg",
"get_wire_connections", "export_schematic_pdf"
"generate_netlist", ]
"sync_schematic_to_board", },
"get_schematic_view", {
"export_schematic_svg", name: "library",
"export_schematic_pdf", description: "Footprint library access: search, browse, get footprint information",
], tools: [
}, "list_libraries",
{ "search_footprints",
name: "library", "list_library_footprints",
description: "get_footprint_info"
"Footprint library access: search, browse, get footprint information", ]
tools: [ },
"list_libraries", {
"search_footprints", name: "routing",
"list_library_footprints", description: "Advanced routing operations: vias, copper pours",
"get_footprint_info", tools: [
], "add_via",
}, "add_copper_pour"
{ ]
name: "routing", },
description: "Advanced routing operations: vias, copper pours", {
tools: ["add_via", "add_copper_pour"], name: "autoroute",
}, description: "Freerouting autorouter: automatic PCB routing via Specctra DSN/SES",
{ tools: [
name: "autoroute", "autoroute",
description: "export_dsn",
"Freerouting autorouter: automatic PCB routing via Specctra DSN/SES", "import_ses",
tools: ["autoroute", "export_dsn", "import_ses", "check_freerouting"], "check_freerouting"
}, ]
]; }
];
/**
* Direct tools that are always visible (not routed) /**
* These are the most frequently used tools * Direct tools that are always visible (not routed)
*/ * These are the most frequently used tools
export const directToolNames = [ */
// Project lifecycle export const directToolNames = [
"create_project", // Project lifecycle
"open_project", "create_project",
"save_project", "open_project",
"snapshot_project", "save_project",
"get_project_info", "snapshot_project",
"get_project_info",
// Core PCB operations
"place_component", // Core PCB operations
"move_component", "place_component",
"add_net", "move_component",
"route_trace", "add_net",
"get_board_info", "route_trace",
"set_board_size", "get_board_info",
"set_board_size",
// Board setup
"add_board_outline", // Board setup
"add_board_outline",
// Schematic essentials (always visible so AI uses them correctly)
"add_schematic_component", // Schematic essentials (always visible so AI uses them correctly)
"list_schematic_components", "add_schematic_component",
"annotate_schematic", "list_schematic_components",
"connect_passthrough", "annotate_schematic",
"connect_to_net", "connect_passthrough",
"add_schematic_net_label", "connect_to_net",
"add_schematic_net_label",
// Schematic <-> PCB sync (F8 equivalent)
"sync_schematic_to_board", // Schematic <-> PCB sync (F8 equivalent)
"sync_schematic_to_board",
// UI management
"check_kicad_ui", // UI management
]; "check_kicad_ui"
];
// Build lookup maps at module load time
const categoryMap = new Map<string, ToolCategory>(); // Build lookup maps at module load time
const toolCategoryMap = new Map<string, string>(); const categoryMap = new Map<string, ToolCategory>();
const toolCategoryMap = new Map<string, string>();
export function initializeRegistry() {
// Build category map export function initializeRegistry() {
for (const category of toolCategories) { // Build category map
categoryMap.set(category.name, category); for (const category of toolCategories) {
categoryMap.set(category.name, category);
// Build tool -> category map
for (const toolName of category.tools) { // Build tool -> category map
toolCategoryMap.set(toolName, category.name); for (const toolName of category.tools) {
} toolCategoryMap.set(toolName, category.name);
} }
} }
}
/**
* Get a category by name /**
*/ * Get a category by name
export function getCategory(name: string): ToolCategory | undefined { */
return categoryMap.get(name); export function getCategory(name: string): ToolCategory | undefined {
} return categoryMap.get(name);
}
/**
* Get the category name for a tool /**
*/ * Get the category name for a tool
export function getToolCategory(toolName: string): string | undefined { */
return toolCategoryMap.get(toolName); export function getToolCategory(toolName: string): string | undefined {
} return toolCategoryMap.get(toolName);
}
/**
* Get all categories /**
*/ * Get all categories
export function getAllCategories(): ToolCategory[] { */
return toolCategories; export function getAllCategories(): ToolCategory[] {
} return toolCategories;
}
/**
* Get all routed tool names (excludes direct tools) /**
*/ * Get all routed tool names (excludes direct tools)
export function getRoutedToolNames(): string[] { */
const allRoutedTools: string[] = []; export function getRoutedToolNames(): string[] {
for (const category of toolCategories) { const allRoutedTools: string[] = [];
allRoutedTools.push(...category.tools); for (const category of toolCategories) {
} allRoutedTools.push(...category.tools);
return allRoutedTools; }
} return allRoutedTools;
}
/**
* Check if a tool is a direct tool /**
*/ * Check if a tool is a direct tool
export function isDirectTool(toolName: string): boolean { */
return directToolNames.includes(toolName); export function isDirectTool(toolName: string): boolean {
} return directToolNames.includes(toolName);
}
/**
* Check if a tool is a routed tool /**
*/ * Check if a tool is a routed tool
export function isRoutedTool(toolName: string): boolean { */
return toolCategoryMap.has(toolName); export function isRoutedTool(toolName: string): boolean {
} return toolCategoryMap.has(toolName);
}
/**
* Search for tools by keyword /**
* Searches tool names, descriptions, and category names * Search for tools by keyword
*/ * Searches tool names, descriptions, and category names
export interface SearchResult { */
category: string; export interface SearchResult {
tool: string; category: string;
description: string; tool: string;
} description: string;
}
export function searchTools(query: string): SearchResult[] {
const q = query.toLowerCase(); export function searchTools(query: string): SearchResult[] {
const matches: SearchResult[] = []; const q = query.toLowerCase();
const matches: SearchResult[] = [];
// Search direct tools first
for (const toolName of directToolNames) { // Search direct tools first
if (toolName.toLowerCase().includes(q)) { for (const toolName of directToolNames) {
matches.push({ if (toolName.toLowerCase().includes(q)) {
category: "direct", matches.push({
tool: toolName, category: "direct",
description: `${toolName} (direct tool — call directly, no execute_tool needed)`, tool: toolName,
}); description: `${toolName} (direct tool — call directly, no execute_tool needed)`
} });
} }
}
// Search routed tools by name and category
for (const category of toolCategories) { // Search routed tools by name and category
const categoryMatch = for (const category of toolCategories) {
category.name.toLowerCase().includes(q) || const categoryMatch =
category.description.toLowerCase().includes(q); category.name.toLowerCase().includes(q) ||
category.description.toLowerCase().includes(q);
for (const toolName of category.tools) {
if (toolName.toLowerCase().includes(q) || categoryMatch) { for (const toolName of category.tools) {
matches.push({ if (toolName.toLowerCase().includes(q) || categoryMatch) {
category: category.name, matches.push({
tool: toolName, category: category.name,
description: `${toolName} (${category.name})`, tool: toolName,
}); description: `${toolName} (${category.name})`
} });
} }
} }
}
return matches.slice(0, 20); // Limit results
} return matches.slice(0, 20); // Limit results
}
/**
* Get statistics about the tool registry /**
*/ * Get statistics about the tool registry
export function getRegistryStats() { */
const routedToolCount = getRoutedToolNames().length; export function getRegistryStats() {
const directToolCount = directToolNames.length; const routedToolCount = getRoutedToolNames().length;
const directToolCount = directToolNames.length;
return {
total_categories: toolCategories.length, return {
total_routed_tools: routedToolCount, total_categories: toolCategories.length,
total_direct_tools: directToolCount, total_routed_tools: routedToolCount,
total_tools: routedToolCount + directToolCount, total_direct_tools: directToolCount,
categories: toolCategories.map((c) => ({ total_tools: routedToolCount + directToolCount,
name: c.name, categories: toolCategories.map(c => ({
tool_count: c.tools.length, name: c.name,
})), tool_count: c.tools.length
}; }))
} };
}
// Initialize on module load
initializeRegistry(); // Initialize on module load
initializeRegistry();

View File

@@ -161,37 +161,15 @@ preserves the component's position and UUID.
Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_component.`, Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_component.`,
{ {
schematicPath: z.string().describe("Path to the .kicad_sch file"), schematicPath: z.string().describe("Path to the .kicad_sch file"),
reference: z reference: z.string().describe("Current reference designator of the component (e.g. R1, U3)"),
.string() footprint: z.string().optional().describe("New KiCAD footprint string (e.g. Resistor_SMD:R_0603_1608Metric)"),
.describe( value: z.string().optional().describe("New value string (e.g. 10k, 100nF)"),
"Current reference designator of the component (e.g. R1, U3)", newReference: z.string().optional().describe("Rename the reference designator (e.g. R1 → R10)"),
), fieldPositions: z.record(z.object({
footprint: z x: z.number(),
.string() y: z.number(),
.optional() angle: z.number().optional().default(0),
.describe( })).optional().describe("Reposition field labels: map of field name to {x, y, angle} (e.g. {\"Reference\": {\"x\": 12.5, \"y\": 17.0}})"),
"New KiCAD footprint string (e.g. Resistor_SMD:R_0603_1608Metric)",
),
value: z
.string()
.optional()
.describe("New value string (e.g. 10k, 100nF)"),
newReference: z
.string()
.optional()
.describe("Rename the reference designator (e.g. R1 → R10)"),
fieldPositions: z
.record(
z.object({
x: z.number(),
y: z.number(),
angle: z.number().optional().default(0),
}),
)
.optional()
.describe(
'Reposition field labels: map of field name to {x, y, angle} (e.g. {"Reference": {"x": 12.5, "y": 17.0}})',
),
}, },
async (args: { async (args: {
schematicPath: string; schematicPath: string;
@@ -232,9 +210,7 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
"Get full component info from a schematic: position, field values, and each field's label position (at x/y/angle). Use this to inspect or prepare repositioning of Reference/Value labels.", "Get full component info from a schematic: position, field values, and each field's label position (at x/y/angle). Use this to inspect or prepare repositioning of Reference/Value labels.",
{ {
schematicPath: z.string().describe("Path to the .kicad_sch file"), schematicPath: z.string().describe("Path to the .kicad_sch file"),
reference: z reference: z.string().describe("Component reference designator (e.g. R1, U1)"),
.string()
.describe("Component reference designator (e.g. R1, U1)"),
}, },
async (args: { schematicPath: string; reference: string }) => { async (args: { schematicPath: string; reference: string }) => {
const result = await callKicadScript("get_schematic_component", args); const result = await callKicadScript("get_schematic_component", args);
@@ -244,24 +220,20 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
: "unknown"; : "unknown";
const fieldLines = Object.entries(result.fields ?? {}).map( const fieldLines = Object.entries(result.fields ?? {}).map(
([name, f]: [string, any]) => ([name, f]: [string, any]) =>
` ${name}: "${f.value}" @ (${f.x}, ${f.y}, angle=${f.angle}°)`, ` ${name}: "${f.value}" @ (${f.x}, ${f.y}, angle=${f.angle}°)`
); );
return { return {
content: [ content: [{
{ type: "text",
type: "text", text: `Component ${result.reference} at ${pos}\nFields:\n${fieldLines.join("\n")}`,
text: `Component ${result.reference} at ${pos}\nFields:\n${fieldLines.join("\n")}`, }],
},
],
}; };
} }
return { return {
content: [ content: [{
{ type: "text",
type: "text", text: `Failed to get component: ${result.message || "Unknown error"}`,
text: `Failed to get component: ${result.message || "Unknown error"}`, }],
},
],
}; };
}, },
); );
@@ -608,14 +580,8 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
schematicPath: z.string().describe("Path to the .kicad_sch file"), schematicPath: z.string().describe("Path to the .kicad_sch file"),
filter: z filter: z
.object({ .object({
libId: z libId: z.string().optional().describe("Filter by library ID (e.g., 'Device:R')"),
.string() referencePrefix: z.string().optional().describe("Filter by reference prefix (e.g., 'R', 'C', 'U')"),
.optional()
.describe("Filter by library ID (e.g., 'Device:R')"),
referencePrefix: z
.string()
.optional()
.describe("Filter by reference prefix (e.g., 'R', 'C', 'U')"),
}) })
.optional() .optional()
.describe("Optional filters"), .describe("Optional filters"),
@@ -629,9 +595,7 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
const comps = result.components || []; const comps = result.components || [];
if (comps.length === 0) { if (comps.length === 0) {
return { return {
content: [ content: [{ type: "text", text: "No components found in schematic." }],
{ type: "text", text: "No components found in schematic." },
],
}; };
} }
const lines = comps.map( const lines = comps.map(
@@ -692,10 +656,7 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
} }
return { return {
content: [ content: [
{ { type: "text", text: `Failed to list nets: ${result.message || "Unknown error"}` },
type: "text",
text: `Failed to list nets: ${result.message || "Unknown error"}`,
},
], ],
isError: true, isError: true,
}; };
@@ -733,10 +694,7 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
} }
return { return {
content: [ content: [
{ { type: "text", text: `Failed to list wires: ${result.message || "Unknown error"}` },
type: "text",
text: `Failed to list wires: ${result.message || "Unknown error"}`,
},
], ],
isError: true, isError: true,
}; };
@@ -774,10 +732,7 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
} }
return { return {
content: [ content: [
{ { type: "text", text: `Failed to list labels: ${result.message || "Unknown error"}` },
type: "text",
text: `Failed to list labels: ${result.message || "Unknown error"}`,
},
], ],
isError: true, isError: true,
}; };
@@ -834,7 +789,10 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
schematicPath: z.string().describe("Path to the .kicad_sch file"), schematicPath: z.string().describe("Path to the .kicad_sch file"),
reference: z.string().describe("Reference designator (e.g., R1, U1)"), reference: z.string().describe("Reference designator (e.g., R1, U1)"),
angle: z.number().describe("Rotation angle in degrees (0, 90, 180, 270)"), angle: z.number().describe("Rotation angle in degrees (0, 90, 180, 270)"),
mirror: z.enum(["x", "y"]).optional().describe("Optional mirror axis"), mirror: z
.enum(["x", "y"])
.optional()
.describe("Optional mirror axis"),
}, },
async (args: { async (args: {
schematicPath: string; schematicPath: string;
@@ -1078,14 +1036,8 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
.enum(["png", "svg"]) .enum(["png", "svg"])
.optional() .optional()
.describe("Output format (default: png)"), .describe("Output format (default: png)"),
width: z width: z.number().optional().describe("Image width in pixels (default: 1200)"),
.number() height: z.number().optional().describe("Image height in pixels (default: 900)"),
.optional()
.describe("Image width in pixels (default: 1200)"),
height: z
.number()
.optional()
.describe("Image height in pixels (default: 900)"),
}, },
async (args: { async (args: {
schematicPath: string; schematicPath: string;
@@ -1255,35 +1207,19 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
"get_schematic_view_region", "get_schematic_view_region",
"Export a cropped region of the schematic as an image (PNG or SVG). Specify bounding box coordinates in schematic mm. Useful for zooming into a specific area to inspect wiring or layout.", "Export a cropped region of the schematic as an image (PNG or SVG). Specify bounding box coordinates in schematic mm. Useful for zooming into a specific area to inspect wiring or layout.",
{ {
schematicPath: z schematicPath: z.string().describe("Path to the .kicad_sch schematic file"),
.string()
.describe("Path to the .kicad_sch schematic file"),
x1: z.number().describe("Left X coordinate of the region in mm"), x1: z.number().describe("Left X coordinate of the region in mm"),
y1: z.number().describe("Top Y coordinate of the region in mm"), y1: z.number().describe("Top Y coordinate of the region in mm"),
x2: z.number().describe("Right X coordinate of the region in mm"), x2: z.number().describe("Right X coordinate of the region in mm"),
y2: z.number().describe("Bottom Y coordinate of the region in mm"), y2: z.number().describe("Bottom Y coordinate of the region in mm"),
format: z format: z.enum(["png", "svg"]).optional().describe("Output image format (default: png)"),
.enum(["png", "svg"]) width: z.number().optional().describe("Output image width in pixels (default: 800)"),
.optional() height: z.number().optional().describe("Output image height in pixels (default: 600)"),
.describe("Output image format (default: png)"),
width: z
.number()
.optional()
.describe("Output image width in pixels (default: 800)"),
height: z
.number()
.optional()
.describe("Output image height in pixels (default: 600)"),
}, },
async (args: { async (args: {
schematicPath: string; schematicPath: string;
x1: number; x1: number; y1: number; x2: number; y2: number;
y1: number; format?: string; width?: number; height?: number;
x2: number;
y2: number;
format?: string;
width?: number;
height?: number;
}) => { }) => {
const result = await callKicadScript("get_schematic_view_region", args); const result = await callKicadScript("get_schematic_view_region", args);
if (result.success && result.imageData) { if (result.success && result.imageData) {
@@ -1291,40 +1227,27 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
return { content: [{ type: "text", text: result.imageData }] }; return { content: [{ type: "text", text: result.imageData }] };
} }
return { return {
content: [ content: [{
{ type: "image",
type: "image", data: result.imageData,
data: result.imageData, mimeType: "image/png",
mimeType: "image/png", }],
},
],
}; };
} }
return { return {
content: [ content: [{ type: "text", text: `Failed: ${result.message || "Unknown error"}` }],
{
type: "text",
text: `Failed: ${result.message || "Unknown error"}`,
},
],
}; };
}, },
); );
// Find overlapping elements // Find overlapping elements
server.tool( server.tool(
"find_overlapping_elements", "find_overlapping_elements",
"Detect spatially overlapping symbols, wires, and labels in the schematic. Finds duplicate power symbols at the same position, collinear overlapping wires, and labels stacked on top of each other.", "Detect spatially overlapping symbols, wires, and labels in the schematic. Finds duplicate power symbols at the same position, collinear overlapping wires, and labels stacked on top of each other.",
{ {
schematicPath: z schematicPath: z.string().describe("Path to the .kicad_sch schematic file"),
.string() tolerance: z.number().optional().describe("Distance threshold in mm for label proximity and wire collinearity checks. Symbol overlap uses bounding-box intersection. (default: 0.5)"),
.describe("Path to the .kicad_sch schematic file"),
tolerance: z
.number()
.optional()
.describe(
"Distance threshold in mm for label proximity and wire collinearity checks. Symbol overlap uses bounding-box intersection. (default: 0.5)",
),
}, },
async (args: { schematicPath: string; tolerance?: number }) => { async (args: { schematicPath: string; tolerance?: number }) => {
const result = await callKicadScript("find_overlapping_elements", args); const result = await callKicadScript("find_overlapping_elements", args);
@@ -1336,36 +1259,25 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
if (syms.length) { if (syms.length) {
lines.push(`\nOverlapping symbols (${syms.length}):`); lines.push(`\nOverlapping symbols (${syms.length}):`);
syms.slice(0, 20).forEach((o: any) => { syms.slice(0, 20).forEach((o: any) => {
lines.push( lines.push(` ${o.element1.reference}${o.element2.reference} (${o.distance}mm) [${o.type}]`);
` ${o.element1.reference}${o.element2.reference} (${o.distance}mm) [${o.type}]`,
);
}); });
} }
if (lbls.length) { if (lbls.length) {
lines.push(`\nOverlapping labels (${lbls.length}):`); lines.push(`\nOverlapping labels (${lbls.length}):`);
lbls.slice(0, 20).forEach((o: any) => { lbls.slice(0, 20).forEach((o: any) => {
lines.push( lines.push(` "${o.element1.name}" ↔ "${o.element2.name}" (${o.distance}mm)`);
` "${o.element1.name}" ↔ "${o.element2.name}" (${o.distance}mm)`,
);
}); });
} }
if (wires.length) { if (wires.length) {
lines.push(`\nOverlapping wires (${wires.length}):`); lines.push(`\nOverlapping wires (${wires.length}):`);
wires.slice(0, 20).forEach((o: any) => { wires.slice(0, 20).forEach((o: any) => {
lines.push( lines.push(` wire @ (${o.wire1.start.x},${o.wire1.start.y})→(${o.wire1.end.x},${o.wire1.end.y}) overlaps with another`);
` wire @ (${o.wire1.start.x},${o.wire1.start.y})→(${o.wire1.end.x},${o.wire1.end.y}) overlaps with another`,
);
}); });
} }
return { content: [{ type: "text", text: lines.join("\n") }] }; return { content: [{ type: "text", text: lines.join("\n") }] };
} }
return { return {
content: [ content: [{ type: "text", text: `Failed: ${result.message || "Unknown error"}` }],
{
type: "text",
text: `Failed: ${result.message || "Unknown error"}`,
},
],
}; };
}, },
); );
@@ -1375,9 +1287,7 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
"get_elements_in_region", "get_elements_in_region",
"List all symbols, wires, and labels within a rectangular region of the schematic. Useful for understanding what is in a specific area before modifying it.", "List all symbols, wires, and labels within a rectangular region of the schematic. Useful for understanding what is in a specific area before modifying it.",
{ {
schematicPath: z schematicPath: z.string().describe("Path to the .kicad_sch schematic file"),
.string()
.describe("Path to the .kicad_sch schematic file"),
x1: z.number().describe("Left X coordinate of the region in mm"), x1: z.number().describe("Left X coordinate of the region in mm"),
y1: z.number().describe("Top Y coordinate of the region in mm"), y1: z.number().describe("Top Y coordinate of the region in mm"),
x2: z.number().describe("Right X coordinate of the region in mm"), x2: z.number().describe("Right X coordinate of the region in mm"),
@@ -1385,56 +1295,39 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
}, },
async (args: { async (args: {
schematicPath: string; schematicPath: string;
x1: number; x1: number; y1: number; x2: number; y2: number;
y1: number;
x2: number;
y2: number;
}) => { }) => {
const result = await callKicadScript("get_elements_in_region", args); const result = await callKicadScript("get_elements_in_region", args);
if (result.success) { if (result.success) {
const c = result.counts; const c = result.counts;
const lines = [ const lines = [`Region (${args.x1},${args.y1})→(${args.x2},${args.y2}): ${c.symbols} symbols, ${c.wires} wires, ${c.labels} labels`];
`Region (${args.x1},${args.y1})→(${args.x2},${args.y2}): ${c.symbols} symbols, ${c.wires} wires, ${c.labels} labels`,
];
const syms: any[] = result.symbols || []; const syms: any[] = result.symbols || [];
if (syms.length) { if (syms.length) {
lines.push("\nSymbols:"); lines.push("\nSymbols:");
syms.forEach((s: any) => { syms.forEach((s: any) => {
const pinCount = s.pins ? Object.keys(s.pins).length : 0; const pinCount = s.pins ? Object.keys(s.pins).length : 0;
lines.push( lines.push(` ${s.reference} (${s.libId}) @ (${s.position.x}, ${s.position.y}) [${pinCount} pins]`);
` ${s.reference} (${s.libId}) @ (${s.position.x}, ${s.position.y}) [${pinCount} pins]`,
);
}); });
} }
const wires: any[] = result.wires || []; const wires: any[] = result.wires || [];
if (wires.length) { if (wires.length) {
lines.push(`\nWires (${wires.length}):`); lines.push(`\nWires (${wires.length}):`);
wires.slice(0, 30).forEach((w: any) => { wires.slice(0, 30).forEach((w: any) => {
lines.push( lines.push(` (${w.start.x},${w.start.y}) → (${w.end.x},${w.end.y})`);
` (${w.start.x},${w.start.y}) → (${w.end.x},${w.end.y})`,
);
}); });
if (wires.length > 30) if (wires.length > 30) lines.push(` ... and ${wires.length - 30} more`);
lines.push(` ... and ${wires.length - 30} more`);
} }
const labels: any[] = result.labels || []; const labels: any[] = result.labels || [];
if (labels.length) { if (labels.length) {
lines.push(`\nLabels (${labels.length}):`); lines.push(`\nLabels (${labels.length}):`);
labels.forEach((l: any) => { labels.forEach((l: any) => {
lines.push( lines.push(` "${l.name}" [${l.type}] @ (${l.position.x}, ${l.position.y})`);
` "${l.name}" [${l.type}] @ (${l.position.x}, ${l.position.y})`,
);
}); });
} }
return { content: [{ type: "text", text: lines.join("\n") }] }; return { content: [{ type: "text", text: lines.join("\n") }] };
} }
return { return {
content: [ content: [{ type: "text", text: `Failed: ${result.message || "Unknown error"}` }],
{
type: "text",
text: `Failed: ${result.message || "Unknown error"}`,
},
],
}; };
}, },
); );
@@ -1444,9 +1337,7 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
"find_wires_crossing_symbols", "find_wires_crossing_symbols",
"Find all wires that cross over component symbol bodies. Wires passing over symbols are unacceptable in schematics — they indicate routing mistakes where a wire was drawn across a component instead of around it.", "Find all wires that cross over component symbol bodies. Wires passing over symbols are unacceptable in schematics — they indicate routing mistakes where a wire was drawn across a component instead of around it.",
{ {
schematicPath: z schematicPath: z.string().describe("Path to the .kicad_sch schematic file"),
.string()
.describe("Path to the .kicad_sch schematic file"),
}, },
async (args: { schematicPath: string }) => { async (args: { schematicPath: string }) => {
const result = await callKicadScript("find_wires_crossing_symbols", args); const result = await callKicadScript("find_wires_crossing_symbols", args);
@@ -1455,20 +1346,14 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
const lines = [`Found ${collisions.length} wire(s) crossing symbols:`]; const lines = [`Found ${collisions.length} wire(s) crossing symbols:`];
collisions.slice(0, 30).forEach((c: any, i: number) => { collisions.slice(0, 30).forEach((c: any, i: number) => {
lines.push( lines.push(
` ${i + 1}. Wire (${c.wire.start.x},${c.wire.start.y})→(${c.wire.end.x},${c.wire.end.y}) crosses ${c.component.reference} (${c.component.libId})`, ` ${i + 1}. Wire (${c.wire.start.x},${c.wire.start.y})→(${c.wire.end.x},${c.wire.end.y}) crosses ${c.component.reference} (${c.component.libId})`
); );
}); });
if (collisions.length > 30) if (collisions.length > 30) lines.push(` ... and ${collisions.length - 30} more`);
lines.push(` ... and ${collisions.length - 30} more`);
return { content: [{ type: "text", text: lines.join("\n") }] }; return { content: [{ type: "text", text: lines.join("\n") }] };
} }
return { return {
content: [ content: [{ type: "text", text: `Failed: ${result.message || "Unknown error"}` }],
{
type: "text",
text: `Failed: ${result.message || "Unknown error"}`,
},
],
}; };
}, },
); );