Commit Graph

66 Commits

Author SHA1 Message Date
Eugene Mikhantyev
9f89437918 chore: apply Black formatting and add tests for get_wire_connections
- Apply Black formatting to wire_connectivity.py, kicad_interface.py,
  and tool_schemas.py (changed files only)
- Add python/tests/conftest.py with pcbnew/skip C-extension stubs
- Add python/tests/test_wire_connectivity.py with 29 unit tests covering
  schema validation, handler dispatch, parameter validation, and core
  logic (_to_iu, _parse_wires, _build_adjacency, _find_connected_wires,
  get_wire_connections)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 19:26:25 +00:00
Eugene Mikhantyev
f120034846 refactor: extract wire connectivity into module with KiCad-native IU matching
Move wire connectivity logic from _handle_get_wire_connections into
commands/wire_connectivity.py. Use KiCad's internal integer unit system
(10,000 IU/mm) with exact coordinate matching instead of tolerance-based
float comparison, mirroring how KiCad itself determines connectivity.

Key improvements:
- Exact integer matching for wire endpoints (O(1) dict lookup vs O(n) grid scan)
- Junction support for T-connections
- Multi-unit symbol support (removed incorrect processed_refs dedup)
- Single public API: get_wire_connections()

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 19:24:38 +00:00
Eugene Mikhantyev
4277a3d000 refactor: use pre-compiled adjacency list for BFS in get_wire_connections
Replace runtime spatial-index queries during BFS with a pre-compiled
adjacency list for O(1) edge traversal. Also fix potential UnboundLocalError
for `ref` in the pin-checking exception handler and simplify validation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 19:24:38 +00:00
Eugene Mikhantyev
b257bef89b fix: harden get_wire_connections against edge cases and improve performance
- Add +1 safety margin to grid_radius to handle banker's rounding at cell
  boundaries in the spatial index
- Move symbol property guards inside per-symbol try/except to prevent
  AttributeError from aborting all pin processing
- Replace O(n) connected_points scan for pin matching with spatial index
  lookup (_frontier_has_neighbour), consistent with flood-fill approach
- Wrap float(x)/float(y) conversion with clear user-facing error message

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 19:24:38 +00:00
Eugene Mikhantyev
ddbfc62a49 fix: address review issues in get_wire_connections
- Fix critical bug: use pin_data[0]/[1] instead of pin_data["x"]/["y"]
  (get_all_symbol_pins returns List[float], not dict)
- Use index-based wire tracking to avoid fragile float list equality
- Check all polyline points (not just endpoints) during flood-fill
- Add spatial index (0.05mm grid) to replace O(n²) frontier scan
- Skip already-processed refs to avoid redundant calls for multi-unit symbols
- Include wires_out in early return when schematic has no symbols
- Add get_wire_connections schema entry to tool_schemas.py

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 19:24:38 +00:00
Eugene Mikhantyev
6633cd59fd feat: add get_wire_connections tool for pin/wire lookup by schematic point
Given a single (x,y) coordinate on the schematic, flood-fills through all
connected wire segments and returns every component pin reachable on that net,
plus the full list of wire segments with their start/end coordinates.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 19:24:38 +00:00
Eugene Mikhantyev
c5a0bc495c style: apply Black formatting to kicad_interface.py
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 21:47:49 +00:00
Eugene Mikhantyev
59bd4c4acf style: apply Black formatting to changed files
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 21:37:05 +00:00
Eugene Mikhantyev
1ef4ce5cab refactor: remove find_unconnected_pins tool (redundant with run_erc)
KiCad's native ERC already checks for unconnected pins with better
accuracy (hierarchical sheets, bus connections, custom rules). Remove
the reimplemented version and its dead helper _parse_no_connects.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 21:36:50 +00:00
Eugene Mikhantyev
0ab7428b84 fix: address PR review issues for schematic analysis tools
Eliminate repeated file parsing by extracting _extract_lib_symbols helper
that walks already-parsed sexp_data once instead of re-reading the file
per symbol via PinLocator. Support diagonal wire overlap detection using
cross-product parallelism and 1D projection. Fix wire region inclusion to
use AABB intersection for pass-through wires. Normalize view region
coordinates. Clarify tolerance docstrings across Python, TS, and schema.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 21:36:50 +00:00
Eugene Mikhantyev
76ad44121c fix: rename check_wire_collisions to find_wires_crossing_symbols and detect pass-through wires
Wires that start at a component pin but continue through the body were
incorrectly suppressed as "valid connections." Now nudges the pin endpoint
toward the other end and re-tests intersection — if the shortened segment
still hits the bbox, the wire passes through and is flagged.

Renamed the tool from check_wire_collisions to find_wires_crossing_symbols
across all layers (Python, handler, schema, TypeScript) to clarify that it
finds wires crossing over component symbols, which is unacceptable in
schematics.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 21:36:50 +00:00
Eugene Mikhantyev
9141e33b70 fix: get_schematic_view_region SVG export and coordinate system
- Use a temp directory (not file) for kicad-cli svg output, which expects a directory path
- Clean up temp dir with shutil.rmtree instead of individual file unlinks
- Fix viewBox cropping: KiCad schematic SVGs use mm directly, not mils (removed erroneous 39.3701 multiplier)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 21:36:50 +00:00
Eugene Mikhantyev
764b8db3d3 feat: add schematic analysis tools (read-only)
Add five new read-only schematic analysis MCP tools:
- get_schematic_view_region: export cropped schematic region as PNG/SVG
- find_unconnected_pins: list pins with no wire/label/power connection
- find_overlapping_elements: detect duplicate symbols, stacked labels, collinear wire overlaps
- get_elements_in_region: list all symbols/wires/labels in a bounding box
- check_wire_collisions: detect wires passing through component bodies

Includes Python handler dispatch, tool schemas, TypeScript server bindings,
the schematic_analysis command module, and a full test suite (28 tests passing).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 21:36:50 +00:00
Jeff Laflamme
53a8b3ff3e Add Freerouting autoroute integration
4 new MCP tools: autoroute (full DSN→Freerouting→SES pipeline),
export_dsn, import_ses, check_freerouting. Requires Java 11+ and
freerouting.jar. Includes 21 test cases and README usage examples.
2026-03-20 11:33:37 +07:00
mixelpixx
5b380c0f17 Merge pull request #66 from Mehanik/feature/schematic-component-field-inspection
feat: schematic component field inspection and label repositioning
2026-03-16 21:33:51 -04:00
mixelpixx
fbbe5a408d Merge pull request #67 from Mehanik/fix/delete-schematic-component-multiline
fix: delete_schematic_component fails on multi-line KiCAD format
2026-03-16 20:14:44 -04:00
Eugene Mikhantyev
f562035f79 test: add schematic tools tests and apply black formatting
- Add python/tests/conftest.py with MagicMock stubs for pcbnew/skip
- Add python/tests/test_schematic_tools.py with 29 tests covering
  WireManager.delete_wire, WireManager.delete_label (unit + integration),
  and parameter validation for all 11 new _handle_* methods
- Apply black formatting to component_schematic.py, wire_manager.py,
  and kicad_interface.py

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-15 22:48:24 +00:00
Eugene Mikhantyev
22a7561f5c style: apply Black formatting to changed files
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-15 22:33:50 +00:00
Eugene Mikhantyev
da359513bf fix: delete_schematic_component fails on multi-line KiCAD format
The handler used a line-by-line regex requiring (symbol and (lib_id on
the same line, but KiCAD's file writer places them on separate lines.
Replace with the content-string approach (already used by edit handler)
so \s+ matches across newlines. Add regression tests covering inline,
multi-line, and power symbol (#PWR) cases.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-15 21:36:39 +00:00
Eugene Mikhantyev
ccd817531a feat: add get_schematic_component tool and fieldPositions to edit_schematic_component
- New `get_schematic_component` MCP tool returns component position and
  all field values with their label (at x/y/angle) positions
- Extends `edit_schematic_component` with optional `fieldPositions` dict
  so callers can reposition Reference/Value/etc. labels in one call
- Adds 18 tests (6 unit, 12 integration) covering parsing, round-trips,
  and edge cases

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-15 15:37:52 +00:00
Eugene Mikhantyev
4dc351660c fix: apply sexpdata round-trip write to delete_schematic_net_label
delete_schematic_net_label was using kicad-skip's write() which silently
discards in-memory _elements mutations. Replaced with WireManager.delete_label()
that uses the same sexpdata round-trip approach already used by delete_schematic_wire.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 01:08:49 +00:00
Eugene Mikhantyev
9d9234abd0 fix: replace kicad-skip mutation with sexpdata in delete_schematic_wire
kicad-skip's write() serializes from original parsed data, silently
discarding in-memory _elements mutations. Switch to the same sexpdata
approach used by add_wire: parse, find matching wire, delete the entry,
write back. Also adds WireManager.delete_wire() static method.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 00:39:23 +00:00
Eugene Mikhantyev
2956b4fa9d fix: use _elements.remove() for kicad-skip collections lacking remove method
ElementCollection in kicad-skip doesn't implement remove(), causing
'WireCollection object has no attribute remove' errors. Access the
underlying _elements list directly for wire, label, and symbol deletion.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 00:27:17 +00:00
Eugene Mikhantyev
ffe51f0f16 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>
2026-03-13 00:23:26 +00:00
Eugene Mikhantyev
72e5320044 feat: add get_schematic_view tool for rasterized schematic images
Exports schematic to SVG via kicad-cli, then converts to PNG using
cairosvg (same approach as get_board_2d_view). Falls back gracefully
to SVG if cairosvg is not installed. Supports configurable output
size and format (png/svg).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 23:57:39 +00:00
Eugene Mikhantyev
b2a547e624 feat: add 11 missing schematic inspection & editing tools
Add all missing schematic operations identified in the gap analysis:

Inspection (P0/P2):
- list_schematic_components: enumerate all components with refs, values, pins
- list_schematic_nets: list all nets with their connections
- list_schematic_wires: list all wire geometry
- list_schematic_labels: list net labels, global labels, power flags

Editing (P0/P1):
- annotate_schematic: assign ref designators to unannotated components (R? → R1)
- move_schematic_component: reposition placed symbols
- rotate_schematic_component: rotate/mirror placed symbols
- delete_schematic_wire: remove wires by coordinates
- delete_schematic_net_label: remove labels by name/position

Export (P1):
- export_schematic_svg: schematic SVG export via kicad-cli
- export_schematic_pdf: enhanced with file path return & blackAndWhite support

Also registers list_schematic_components and annotate_schematic as
direct tools (always visible) since they're prerequisites for
reference-based workflows.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 23:52:11 +00:00
Tom
3d9497ebe5 fix: snapshot saves logs+prompt to logs/ subdir; routing via_x under start pad; router disabled 2026-03-11 11:20:05 +01:00
Tom
8e4e3176c2 fix: register sync_schematic_to_board + snapshot_project as MCP tools; auto-save board after SWIG mutations; boardPath reload in place_component; add_schematic_connection warns about connect_passthrough; via.GetWidth(F_Cu) for KiCAD 9.0 2026-03-07 11:27:41 +01:00
Tom
b6e1b8b7b1 fix: propagate board reload to project_commands after SVG logo import
save_project uses project_commands.board, which was NOT in the propagation
list after pcbnew.LoadBoard() in _handle_import_svg_logo. As a result,
save_project() wrote the old in-memory board (without logo gr_poly entries)
back to disk, erasing the logo every time.

Fix: call _update_command_handlers() after reload, which updates all
command handler board references including project_commands.
2026-03-07 01:50:03 +01:00
Tom
44c5e7f388 fix: unwrap nested params in add_board_outline (SWIG + IPC paths)
Claude sends {shape:'rectangle', params:{x,y,width,height,...}} but handlers
were reading params.get('width') on the outer dict → None → wrong board size.

outline.py: extract inner = params.get('params', params) at method start,
read all dimensions from inner dict.

kicad_interface.py (_ipc_add_board_outline): delegate 'rectangle' to SWIG
path (same as 'rounded_rectangle') so Claude's shape+dims call is handled
correctly. For polygon IPC path: also unwrap inner params for points/width.
2026-03-07 01:43:43 +01:00
Tom
b43c63edca feat: add snapshot_project tool for step checkpoints (resume from Step2 without full redo) 2026-03-06 20:42:42 +01:00
Tom
ae66001886 fix: reload board into pcbnew after SVG logo import (prevents logo loss on next Save) 2026-03-06 20:38:16 +01:00
Tom
8e92e144b3 fix: board outline 3 bugs (cornerRadius fallback, top-left origin default, IPC rounded_rect arc delegation) 2026-03-06 20:33:25 +01:00
Tom
ec39905702 feat: add sync_schematic_to_board + fix refill_zones subprocess isolation 2026-03-06 20:05:30 +01:00
Tom
93ae23dacc fix: prevent header corruption when sexpdata compacts schematic to single line
create_component_instance used line-based insertion which placed new
symbols BEFORE (kicad_sch ...) header when the file was written as
a single line by sexpdata.dumps(). Switch to rfind()-based string
insertion which is format-independent.

Also remove StreamHandler(sys.stdout) from logging — Python logs now
go only to file (~/.kicad-mcp/logs/kicad_interface.log) to avoid
polluting MCP stderr with INFO/DEBUG entries shown as [error].
2026-03-06 13:17:25 +01:00
Tom
410d02ad8b feat: add import_svg_logo tool — converts SVG to PCB silkscreen polygons 2026-03-06 12:41:11 +01:00
Tom
23946a211a feat: add run_erc tool for schematic electrical rules checking 2026-03-06 12:32:35 +01:00
Tom
11d7e49e74 feat: add connect_passthrough tool for FFC/ribbon cable pin-to-pin wiring 2026-03-06 12:25:25 +01:00
Tom
4c12096886 fix: redirect Python logging from stderr to stdout (prevents false [ERROR] labels in MCP log) 2026-03-06 11:49:31 +01:00
Tom
1d390f4fed fix: schematic pin connection reliability
- add_schematic_net_label: warn in description that coords must be exact pin endpoints; recommend connect_to_net instead
- connect_to_net: stub wire direction now follows pin angle (was hardcoded +X)
- pin_locator.py: add get_pin_angle() and _get_lib_id() helpers
- new tool: get_schematic_pin_locations(schematicPath, reference) → returns exact x/y of every pin endpoint, so Claude can place labels correctly
2026-03-06 11:29:52 +01:00
Roman PASSLER
2dd9de6a52 style: apply black formatting to changed files 2026-03-01 19:15:32 +01:00
Roman PASSLER
61356d42cb fix(schematic): rewrite component lookup to handle single-line files
The previous line-based parser (split("\n") + line-by-line regex)
failed when the MCP server itself generates .kicad_sch files as a
single line. The new implementation works directly on the raw content
string using parenthesis-depth matching to find symbol blocks,
making it independent of formatting/whitespace.
2026-03-01 18:43:20 +01:00
Tom
f0d738fff1 feat: add route_pad_to_pad tool
Convenience wrapper around route_trace that eliminates the need for
separate get_pad_position calls before routing.

- Accepts fromRef/fromPad/toRef/toPad instead of raw coordinates
- Automatically looks up pad positions from board footprints
- Auto-detects net from pad assignment (overridable via net param)
- Returns fromPad/toPad position info in response
- Saves ~2 tool calls (64+ calls for a full TMC2209 board) vs 3-step flow

Registered in: routing.py, kicad_interface.py (dispatch), routing.ts (MCP)
2026-03-01 15:03:52 +01:00
Tom
b33d6e22fd fix: project-local library resolution + copy_routing_pattern geometric fallback + TypeScript tool
- fix: DynamicSymbolLoader reads project sym-lib-table before global dirs
  add_schematic_component now finds symbols from project-local .kicad_sym files
  project_path derived automatically from schematic file path

- fix: place_component reloads FootprintLibraryManager with project_path
  new boardPath parameter passed to place_component tool (TypeScript + Python)
  _handle_place_component wrapper recreates LibraryManager per project

- fix: copy_routing_pattern geometric fallback when pads have no nets
  primary filter: net-based (when pads are assigned to nets)
  fallback: bounding box of source footprint pads +5mm tolerance
  filterMethod field in response indicates which mode was used

- feat: register copy_routing_pattern as MCP tool in routing.ts
  sourceRefs, targetRefs, includeVias, traceWidth parameters

Live tested: ESP32 + 2x TMC2209 in Test3 project
  13 traces U2 routed, copy_routing_pattern copied all 13 to U3
  offset Y+30mm correct, 26 total traces verified
2026-03-01 15:03:52 +01:00
Tom
914c4fa1e3 feat: add footprint + symbol creator tools
Footprint tools:
- create_footprint: generates .kicad_mod via f-string (SMD/THT, courtyard, silkscreen, fab)
- edit_footprint_pad: updates size/position/drill/shape in-place
- list_footprint_libraries: scans .pretty directories
- register_footprint_library: adds entry to fp-lib-table

Symbol tools:
- create_symbol: generates .kicad_sym with pins, rectangles, polylines
- delete_symbol: removes symbol from library
- list_symbols_in_library: lists all symbols in a .kicad_sym file
- register_symbol_library: adds entry to sym-lib-table

Also:
- Fix footprint format version: 20250114 (schematic) -> 20241229 (footprint)
- Two MCP prompts: create_footprint_guide + footprint_ipc_checklist

Live tested: TMC2209 footprint (19 pads), R_0603_Test, edit_footprint_pad,
TMC2209_Custom symbol with pins all confirmed in KiCAD 9
2026-02-28 22:42:27 +01:00
Tom
b1eb570183 fix: footprint param ignored, delete duplicates, add edit_schematic_component
Bug 1 - add_schematic_component: footprint parameter silently ignored
  The footprint value from MCP params was never passed through to
  DynamicSymbolLoader.add_component() / create_component_instance().
  Every placed symbol had an empty Footprint field regardless of input.
  Fix: added footprint: str='' to both functions, passed through all
  call sites, added footprint to schematic.ts tool schema.

Bug 2 - delete_schematic_component: only deleted first duplicate
  When a reference appeared multiple times (e.g. after a failed
  add attempt), only the first instance was removed due to break
  after first match. Fix: collect all matching blocks first, then
  delete back-to-front to preserve indices. Response now includes
  deleted_count.

New tool - edit_schematic_component
  Update footprint, value or reference of a placed symbol in-place.
  More efficient than delete+re-add: preserves position and UUID.
  Accepts: schematicPath, reference, footprint?, value?, newReference?

All 3 fixes verified by live tests on a real JLCPCB/KiCAD 9 project:
  - R_TEST1: footprint Resistor_SMD:R_0603_1608Metric written correctly
  - J1 duplicate: deleted_count=2 with single call
  - J2 edit: PinSocket footprint assigned in-place, no delete+add needed
  - PCB update (F8) confirmed: only components with footprint imported
2026-02-28 15:21:07 +01:00
Tom
1ba86f7769 feat: datasheet tools + fix missing delete_schematic_component
New tools - datasheet:
- get_datasheet_url: construct LCSC datasheet PDF URL + product page URL
  without any API key (URL schema: https://www.lcsc.com/datasheet/<C#>.pdf)
- enrich_datasheets: scan .kicad_sch, write LCSC datasheet URL into every
  symbol that has an LCSC property but an empty Datasheet field; supports
  dry_run=true for preview; text-based implementation (no skip writes)
  Implementation: python/commands/datasheet_manager.py

New tool - schematic:
- delete_schematic_component: remove a placed symbol from a .kicad_sch file
  by reference designator (e.g. R1, U3)

Bug fix - delete_schematic_component (two separate root causes):
1. No MCP tool named delete_schematic_component was registered at all.
   Any delete-symbol request fell through to the PCB-only delete_component
   tool which searches pcbnew.BOARD and always returned 'Component not found'
   for schematic symbols.
2. component_schematic.py::remove_component() still used skip for writes.
   PR #40 rewrote DynamicSymbolLoader (add path) to avoid skip-induced
   schematic corruption, but the delete path was not touched by that PR.

Fix: _handle_delete_schematic_component in kicad_interface.py uses direct
text manipulation with parenthesis-depth tracking (same technique as PR #40),
bypassing component_schematic.py entirely. Error message explicitly guides
users: 'use delete_component for PCB footprints'.

Files changed:
- python/commands/datasheet_manager.py (new)
- src/tools/datasheet.ts (new)
- python/kicad_interface.py: 3 new handlers + dispatch entries
- src/tools/schematic.ts: delete_schematic_component tool
- src/server.ts: registerDatasheetTools import + call
- src/tools/index.ts: export registerDatasheetTools
- CHANGELOG.md: document all above
2026-02-28 13:48:35 +01:00
Tom
76503b144c fix: generate_netlist schematic_path, PinLocator cache, server.ts Python detection
- connection_schematic.py: generate_netlist() now accepts schematic_path param,
  threaded through to get_net_connections() so PinLocator is actually invoked
  (previously only 1 connection per component was returned due to fallback break)
- kicad_interface.py: pass schematic_path to generate_netlist()
- pin_locator.py: add _schematic_cache to avoid loading Schematic() once per pin
  (was causing timeout: O(nets x components x pins) Schematic() calls)
- server.ts: remove fragile PYTHONPATH?.includes('KiCad') condition,
  always prefer KiCAD bundled Python on Windows when executable exists
- CHANGELOG.md: document fixes under v2.2.0-alpha
2026-02-28 01:23:36 +01:00
FlowSync0
a69d288251 fix: Rewrite DynamicSymbolLoader to prevent schematic file corruption (#40)
Fixes Issue #26 - add_schematic_component corrupts .kicad_sch files

Complete rewrite of DynamicSymbolLoader to use text manipulation instead of sexpdata:
- Preserves KiCAD file formatting perfectly
- Correctly handles KiCAD 9 symbol naming conventions (library prefix for top-level, no prefix for sub-symbols)
- Resolves parent-child symbol dependencies with (extends)
- Adds symbol caching for performance
- Simplifies component addition workflow

Tested on KiCAD 9.0.7 with R, C, LED, ESP32, and transistor components.
Compatible with recent Windows fixes (UUID generation, IPC, JLCPCB).

Co-authored-by: FlowSync0 <249798311+FlowSync0@users.noreply.github.com>
2026-02-26 11:02:10 -05:00
KiCAD MCP Bot
b9bd401b11 feat: Add routing replication commands for Issue #30 Phase 2
Implements advanced trace manipulation and routing pattern copying:
- Enhanced delete_trace with net-based bulk deletion and layer filtering
- Added modify_trace to change width, layer, or net by UUID/position
- Added copy_routing_pattern to replicate routing between component groups

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-19 19:24:59 -05:00