fix: address review issues in schematic tools

- Remove unused imports in move_schematic_component
- Add warning log when mirror attribute missing on rotate
- Move `import re` out of loop in annotate_schematic
- Include global_label in list_schematic_nets
- Fix SVG export to use directory for kicad-cli --output flag
- Return actual SVG data in get_schematic_view TS handler
- Add isError: true to all failure responses in new tools
- Add connect_passthrough to schematic category in registry
- Simplify power symbol filtering control flow in list_labels
- Fix indentation in list_schematic_labels power section

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Eugene Mikhantyev
2026-03-13 00:23:26 +00:00
parent 72e5320044
commit ffe51f0f16
3 changed files with 74 additions and 31 deletions

View File

@@ -1592,12 +1592,16 @@ class KiCADInterface:
if not schematic: if not schematic:
return {"success": False, "message": "Failed to load schematic"} return {"success": False, "message": "Failed to load schematic"}
# Get all net names from labels # Get all net names from labels and global labels
net_names = set() net_names = set()
if hasattr(schematic, "label"): if hasattr(schematic, "label"):
for label in schematic.label: for label in schematic.label:
if hasattr(label, "value"): if hasattr(label, "value"):
net_names.add(label.value) net_names.add(label.value)
if hasattr(schematic, "global_label"):
for label in schematic.global_label:
if hasattr(label, "value"):
net_names.add(label.value)
nets = [] nets = []
for net_name in sorted(net_names): for net_name in sorted(net_names):
@@ -1697,16 +1701,17 @@ class KiCADInterface:
if not hasattr(symbol.property, "Reference"): if not hasattr(symbol.property, "Reference"):
continue continue
ref = symbol.property.Reference.value ref = symbol.property.Reference.value
if ref.startswith("#PWR") or ref.startswith("_TEMPLATE"): if ref.startswith("_TEMPLATE"):
if ref.startswith("_TEMPLATE"): continue
continue if not ref.startswith("#PWR"):
value = symbol.property.Value.value if hasattr(symbol.property, "Value") else ref continue
pos = symbol.at.value if hasattr(symbol, "at") else [0, 0, 0] value = symbol.property.Value.value if hasattr(symbol.property, "Value") else ref
labels.append({ pos = symbol.at.value if hasattr(symbol, "at") else [0, 0, 0]
"name": value, labels.append({
"type": "power", "name": value,
"position": {"x": float(pos[0]), "y": float(pos[1])}, "type": "power",
}) "position": {"x": float(pos[0]), "y": float(pos[1])},
})
return {"success": True, "labels": labels, "count": len(labels)} return {"success": True, "labels": labels, "count": len(labels)}
@@ -1720,9 +1725,6 @@ class KiCADInterface:
"""Move a schematic component to a new position""" """Move a schematic component to a new position"""
logger.info("Moving schematic component") logger.info("Moving schematic component")
try: try:
from pathlib import Path
import re
schematic_path = params.get("schematicPath") schematic_path = params.get("schematicPath")
reference = params.get("reference") reference = params.get("reference")
position = params.get("position", {}) position = params.get("position", {})
@@ -1793,8 +1795,15 @@ class KiCADInterface:
symbol.at.value = pos symbol.at.value = pos
# Handle mirror if specified # Handle mirror if specified
if mirror and hasattr(symbol, "mirror"): if mirror:
symbol.mirror.value = mirror if hasattr(symbol, "mirror"):
symbol.mirror.value = mirror
else:
logger.warning(
f"Mirror '{mirror}' requested for {reference}, "
f"but symbol does not have a 'mirror' attribute; "
f"mirror not applied"
)
SchematicManager.save_schematic(schematic, schematic_path) SchematicManager.save_schematic(schematic, schematic_path)
return {"success": True, "reference": reference, "angle": angle} return {"success": True, "reference": reference, "angle": angle}
@@ -1811,6 +1820,8 @@ class KiCADInterface:
"""Annotate unannotated components in schematic (R? -> R1, R2, ...)""" """Annotate unannotated components in schematic (R? -> R1, R2, ...)"""
logger.info("Annotating schematic") logger.info("Annotating schematic")
try: try:
import re
schematic_path = params.get("schematicPath") schematic_path = params.get("schematicPath")
if not schematic_path: if not schematic_path:
return {"success": False, "message": "schematicPath is required"} return {"success": False, "message": "schematicPath is required"}
@@ -1831,7 +1842,6 @@ class KiCADInterface:
continue continue
# Split reference into prefix and number # Split reference into prefix and number
import re
match = re.match(r'^([A-Za-z_]+)(\d+)$', ref) match = re.match(r'^([A-Za-z_]+)(\d+)$', ref)
if match: if match:
prefix = match.group(1) prefix = match.group(1)
@@ -1990,6 +2000,8 @@ class KiCADInterface:
"""Export schematic to SVG using kicad-cli""" """Export schematic to SVG using kicad-cli"""
logger.info("Exporting schematic SVG") logger.info("Exporting schematic SVG")
import subprocess import subprocess
import glob
import shutil
try: try:
schematic_path = params.get("schematicPath") schematic_path = params.get("schematicPath")
@@ -2001,18 +2013,37 @@ class KiCADInterface:
if not os.path.exists(schematic_path): if not os.path.exists(schematic_path):
return {"success": False, "message": f"Schematic not found: {schematic_path}"} return {"success": False, "message": f"Schematic not found: {schematic_path}"}
cmd = ["kicad-cli", "sch", "export", "svg", schematic_path, "-o", output_path] # kicad-cli's --output flag for SVG export expects a directory, not a file path.
# The output file is auto-named based on the schematic name.
output_dir = os.path.dirname(output_path)
if not output_dir:
output_dir = "."
os.makedirs(output_dir, exist_ok=True)
cmd = ["kicad-cli", "sch", "export", "svg", schematic_path, "-o", output_dir]
if params.get("blackAndWhite"): if params.get("blackAndWhite"):
cmd.append("--black-and-white") cmd.append("--black-and-white")
result = subprocess.run(cmd, capture_output=True, text=True, timeout=60) result = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
if result.returncode == 0: if result.returncode != 0:
return {"success": True, "file": {"path": output_path}}
else:
return {"success": False, "message": f"kicad-cli failed: {result.stderr}"} return {"success": False, "message": f"kicad-cli failed: {result.stderr}"}
# kicad-cli names the file after the schematic, so find the generated SVG
svg_files = glob.glob(os.path.join(output_dir, "*.svg"))
if not svg_files:
return {"success": False, "message": "No SVG file produced by kicad-cli"}
generated_svg = svg_files[0]
# Move/rename to the user-specified output path if it differs
if os.path.abspath(generated_svg) != os.path.abspath(output_path):
shutil.move(generated_svg, output_path)
return {"success": True, "file": {"path": output_path}}
except FileNotFoundError: except FileNotFoundError:
return {"success": False, "message": "kicad-cli not found in PATH"} return {"success": False, "message": "kicad-cli not found in PATH"}
except Exception as e: except Exception as e:

View File

@@ -97,6 +97,7 @@ export const toolCategories: ToolCategory[] = [
"add_schematic_net_label", "add_schematic_net_label",
"delete_schematic_net_label", "delete_schematic_net_label",
"connect_to_net", "connect_to_net",
"connect_passthrough",
"get_net_connections", "get_net_connections",
"list_schematic_nets", "list_schematic_nets",
"list_schematic_wires", "list_schematic_wires",

View File

@@ -491,6 +491,7 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
text: `Failed to list components: ${result.message || "Unknown error"}`, text: `Failed to list components: ${result.message || "Unknown error"}`,
}, },
], ],
isError: true,
}; };
}, },
); );
@@ -530,6 +531,7 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
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,
}; };
}, },
); );
@@ -567,6 +569,7 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
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,
}; };
}, },
); );
@@ -604,6 +607,7 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
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,
}; };
}, },
); );
@@ -645,6 +649,7 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
text: `Failed to move component: ${result.message || "Unknown error"}`, text: `Failed to move component: ${result.message || "Unknown error"}`,
}, },
], ],
isError: true,
}; };
}, },
); );
@@ -686,6 +691,7 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
text: `Failed to rotate component: ${result.message || "Unknown error"}`, text: `Failed to rotate component: ${result.message || "Unknown error"}`,
}, },
], ],
isError: true,
}; };
}, },
); );
@@ -727,6 +733,7 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
text: `Failed to annotate: ${result.message || "Unknown error"}`, text: `Failed to annotate: ${result.message || "Unknown error"}`,
}, },
], ],
isError: true,
}; };
}, },
); );
@@ -767,6 +774,7 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
text: `Failed to delete wire: ${result.message || "Unknown error"}`, text: `Failed to delete wire: ${result.message || "Unknown error"}`,
}, },
], ],
isError: true,
}; };
}, },
); );
@@ -806,6 +814,7 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
text: `Failed to delete label: ${result.message || "Unknown error"}`, text: `Failed to delete label: ${result.message || "Unknown error"}`,
}, },
], ],
isError: true,
}; };
}, },
); );
@@ -845,6 +854,7 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
text: `Failed to export SVG: ${result.message || "Unknown error"}`, text: `Failed to export SVG: ${result.message || "Unknown error"}`,
}, },
], ],
isError: true,
}; };
}, },
); );
@@ -884,6 +894,7 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
text: `Failed to export PDF: ${result.message || "Unknown error"}`, text: `Failed to export PDF: ${result.message || "Unknown error"}`,
}, },
], ],
isError: true,
}; };
}, },
); );
@@ -910,16 +921,15 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
const result = await callKicadScript("get_schematic_view", args); const result = await callKicadScript("get_schematic_view", args);
if (result.success) { if (result.success) {
if (result.format === "svg") { if (result.format === "svg") {
return { const parts: { type: "text"; text: string }[] = [];
content: [ if (result.message) {
{ parts.push({ type: "text", text: result.message });
type: "text", }
text: result.message parts.push({
? `SVG data returned (${result.message})` type: "text",
: `SVG schematic view (${result.imageData?.length || 0} chars)`, text: result.imageData || "",
}, });
], return { content: parts };
};
} }
// PNG — return as base64 image // PNG — return as base64 image
return { return {
@@ -939,6 +949,7 @@ Note: operates on .kicad_sch files only. To modify a PCB footprint use edit_comp
text: `Failed to get schematic view: ${result.message || "Unknown error"}`, text: `Failed to get schematic view: ${result.message || "Unknown error"}`,
}, },
], ],
isError: true,
}; };
}, },
); );