@huaqiu/dsh-hqsch 0.4.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +43 -0
- package/cordis.patch.yml +13 -0
- package/lib/index.d.mts +98 -0
- package/lib/index.mjs +159 -0
- package/package.json +40 -0
- package/skills/hqsch-scenario-b/AGENTS.md +209 -0
- package/skills/hqsch-scenario-b/CLAUDE.md +209 -0
- package/skills/hqsch-scenario-b/INSTALL.md +140 -0
- package/skills/hqsch-scenario-b/SKILL.md +107 -0
- package/skills/hqsch-scenario-b/SYSTEM-PROMPT.md +209 -0
- package/skills/hqsch-scenario-b/docs/circuit-pattern-layout.md +304 -0
- package/skills/hqsch-scenario-b/docs/editing-a-circuit.md +167 -0
- package/skills/hqsch-scenario-b/docs/part-search.md +244 -0
- package/skills/hqsch-scenario-b/docs/placement-conventions.md +714 -0
- package/skills/hqsch-scenario-b/docs/property-conventions.md +225 -0
- package/skills/hqsch-scenario-b/docs/quickstart.md +99 -0
- package/skills/hqsch-scenario-b/docs/reading-a-circuit.md +317 -0
- package/skills/hqsch-scenario-b/docs/rpc/canvas-auto-connect-objects-by-id.md +98 -0
- package/skills/hqsch-scenario-b/docs/rpc/canvas-delete-objects-by-ids.md +94 -0
- package/skills/hqsch-scenario-b/docs/rpc/canvas-find-object-by-property.md +101 -0
- package/skills/hqsch-scenario-b/docs/rpc/canvas-list-wire-segments.md +94 -0
- package/skills/hqsch-scenario-b/docs/rpc/canvas-mirror-objects-by-ids.md +96 -0
- package/skills/hqsch-scenario-b/docs/rpc/canvas-rotate-objects-by-ids.md +94 -0
- package/skills/hqsch-scenario-b/docs/rpc/canvas-set-object-property.md +99 -0
- package/skills/hqsch-scenario-b/docs/rpc/canvas-zoom-all.md +92 -0
- package/skills/hqsch-scenario-b/docs/rpc/find-find-object.md +96 -0
- package/skills/hqsch-scenario-b/docs/rpc/kernel-get-snapshot.md +104 -0
- package/skills/hqsch-scenario-b/docs/rpc/netlist-get-active-page-net-list.md +87 -0
- package/skills/hqsch-scenario-b/docs/rpc/netlist-get-port-pairing.md +34 -0
- package/skills/hqsch-scenario-b/docs/rpc/obj-place-place-pin-stub-wire-and-net-alias.md +114 -0
- package/skills/hqsch-scenario-b/docs/rpc/pattern-layout-apply-circuit-pattern.md +125 -0
- package/skills/hqsch-scenario-b/docs/rpc/pattern-layout-get-page-occupancy.md +100 -0
- package/skills/hqsch-scenario-b/docs/rpc/pattern-layout-list-circuit-patterns.md +97 -0
- package/skills/hqsch-scenario-b/docs/rpc/placement-list-part-libraries.md +94 -0
- package/skills/hqsch-scenario-b/docs/rpc/placement-list-symbol-libraries.md +94 -0
- package/skills/hqsch-scenario-b/docs/rpc/placement-place-kicad-symbol.md +105 -0
- package/skills/hqsch-scenario-b/docs/rpc/placement-place-part-from-library.md +106 -0
- package/skills/hqsch-scenario-b/docs/rpc/placement-place-symbol-from-library.md +108 -0
- package/skills/hqsch-scenario-b/docs/rpc/project-get-active-project.md +96 -0
- package/skills/hqsch-scenario-b/docs/rpc/project-list-open-projects.md +99 -0
- package/skills/hqsch-scenario-b/docs/rpc-availability.md +97 -0
- package/skills/hqsch-scenario-b/docs/rpc-index/canvas.md +81 -0
- package/skills/hqsch-scenario-b/docs/rpc-index/find.md +36 -0
- package/skills/hqsch-scenario-b/docs/rpc-index/kernel.md +36 -0
- package/skills/hqsch-scenario-b/docs/rpc-index/netlist.md +38 -0
- package/skills/hqsch-scenario-b/docs/rpc-index/obj-place.md +76 -0
- package/skills/hqsch-scenario-b/docs/rpc-index/pattern-layout.md +38 -0
- package/skills/hqsch-scenario-b/docs/rpc-index/placement.md +48 -0
- package/skills/hqsch-scenario-b/docs/rpc-index/project.md +47 -0
- package/skills/hqsch-scenario-b/docs/serialization.md +60 -0
- package/skills/hqsch-scenario-b/docs/skill-dependencies.md +93 -0
- package/skills/hqsch-scenario-b/skill.json +13 -0
- package/skills/hqsch-scenario-b/template/package.json +16 -0
- package/skills/hqsch-scenario-b/template/scripts/edit-property-by-ref.ts +44 -0
- package/skills/hqsch-scenario-b/template/scripts/fix-designators.ts +52 -0
- package/skills/hqsch-scenario-b/template/scripts/hello.ts +46 -0
- package/skills/hqsch-scenario-b/template/scripts/read-circuit.ts +357 -0
- package/skills/hqsch-scenario-b/template/scripts/replace-part-by-ref.ts +44 -0
- package/skills/hqsch-scenario-b/template/scripts/rewire-pin-by-ref.ts +42 -0
- package/skills/hqsch-scenario-b/template/tsconfig.json +11 -0
- package/src/config.ts +25 -0
- package/src/index.ts +186 -0
- package/src/paths.ts +48 -0
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
# Circuit Pattern Layout (HQSCH)
|
|
2
|
+
|
|
3
|
+
Parametric local-circuit layout. The agent identifies a recurring sub-circuit,
|
|
4
|
+
places the parts anywhere on the page (position may be rough), binds each part
|
|
5
|
+
to a **role**, and calls `ApplyCircuitPattern`. The engine then computes exact
|
|
6
|
+
positions / rotations from a LEFT_TO_RIGHT template, optionally adds GND/VCC,
|
|
7
|
+
routes intra-pattern nets as collinear stubs + rails, and returns one
|
|
8
|
+
`occupied_box` for later avoidance.
|
|
9
|
+
|
|
10
|
+
Coordinates are the same **external display** space as `Place*` RPCs: page
|
|
11
|
+
top-left origin, Y down. See [placement-conventions.md](placement-conventions.md).
|
|
12
|
+
|
|
13
|
+
> **After every `ApplyCircuitPattern`:** wire leftovers with the [routing mode gate](placement-conventions.md#routing-mode-gate-mandatory-before-every-net).
|
|
14
|
+
> **Measure first:** short → `autoConnect`; long / crowded → dual-end stub+NetAlias.
|
|
15
|
+
> Do **not** `autoConnect` far-apart modules without checking distance.
|
|
16
|
+
|
|
17
|
+
## When to use a pattern vs hand layout
|
|
18
|
+
|
|
19
|
+
| Use a pattern | Hand-layout instead |
|
|
20
|
+
| --- | --- |
|
|
21
|
+
| Decoupling / bypass caps on one power pin | One-off geometry that matches no catalog entry |
|
|
22
|
+
| Pull-up / pull-down cluster | Cross-module nets after patterns are applied |
|
|
23
|
+
| MCU reset (pull-up + cap + optional button) | Simple single-pin pull-up only (use `pull_resistor`) |
|
|
24
|
+
| I2C (master + slaves + SDA/SCL pull-ups) | Long-distance leftover nets (stub + NetAlias) |
|
|
25
|
+
| SPI (master + slaves, CS lanes) | Parts that must stay exactly where the user put them |
|
|
26
|
+
| Crystal + load caps (+ feedback R) | |
|
|
27
|
+
|
|
28
|
+
## Mixed-circuit decomposition
|
|
29
|
+
|
|
30
|
+
Most real sheets are **not** one catalog entry end-to-end. Before any hand
|
|
31
|
+
layout or `autoConnect` pass, **decompose** the design into subnets and classify
|
|
32
|
+
each subnet independently.
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
Whole design
|
|
36
|
+
├─ subnet A → matches catalog? → ApplyCircuitPattern
|
|
37
|
+
├─ subnet B → matches catalog? → ApplyCircuitPattern
|
|
38
|
+
└─ subnet C → no catalog match → hand layout (gate: short autoConnect, long stub+NetAlias)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Rules
|
|
42
|
+
|
|
43
|
+
1. **Per-subnet, not per-sheet.** If subnet A matches `pull_resistor`, apply it
|
|
44
|
+
even when subnet B (e.g. a termination resistor between two bus wires, pin
|
|
45
|
+
short, cross-module net alias) has no pattern.
|
|
46
|
+
2. **Do not skip a pattern because another part of the sheet is hand-only.**
|
|
47
|
+
Wrong: “this interface has no dedicated pattern → hand-layout everything
|
|
48
|
+
including obvious pull-ups.”
|
|
49
|
+
Right: apply `pull_resistor` / `decoupling_cap` / … for every matching
|
|
50
|
+
subnet; hand-layout only the leftovers.
|
|
51
|
+
3. **One `ApplyCircuitPattern` call = one catalog entry = one local cluster.**
|
|
52
|
+
Do not try to bind termination resistors, bus transceivers, and pull-ups
|
|
53
|
+
into a single apply unless the catalog explicitly defines that combined
|
|
54
|
+
pattern.
|
|
55
|
+
4. **Apply order:** pattern subnets first (each with its own anchor +
|
|
56
|
+
`occupied_box`), then hand leftovers. Re-read `get-page-occupancy` /
|
|
57
|
+
reserved boxes before the next apply.
|
|
58
|
+
5. **After apply:** do not re-hand-wire intra-pattern nets listed in
|
|
59
|
+
`response.connections`. Hand work is only for subnets that never entered a
|
|
60
|
+
pattern.
|
|
61
|
+
|
|
62
|
+
### Same part in multiple patterns
|
|
63
|
+
|
|
64
|
+
| Role kind | Moved by pattern? | Same part in multiple applies? |
|
|
65
|
+
| --- | --- | --- |
|
|
66
|
+
| `host`, `signal_host`, `master` | **No** (`movable=false`) | **Yes** — same IC in multiple applies **or** one apply with multiple `slotIndex` pairs (see [Pull resistor: multiple pins](#pull-resistor-multiple-pins)) |
|
|
67
|
+
| `cap`, `resistor`, `slave`, `xtal`, … | **Yes** | **No** — each physical part bound to **at most one** pattern |
|
|
68
|
+
|
|
69
|
+
**Forbidden:** bind the same **movable** part (e.g. one resistor) as `resistor`
|
|
70
|
+
in two different applies.
|
|
71
|
+
|
|
72
|
+
**Allowed:** the same MCU or transceiver as `signal_host` / `host` in several
|
|
73
|
+
applies, as long as each apply targets a **different pin or role terminal**
|
|
74
|
+
(e.g. pin A pull-up apply + pin B pull-down apply). When several pins share the
|
|
75
|
+
**same polarity and the same rail** (e.g. CC1 + CC2 both 5.1k→GND), prefer
|
|
76
|
+
**one apply with multiple slot pairs** instead of separate applies.
|
|
77
|
+
|
|
78
|
+
### Classifying ambiguous subnets
|
|
79
|
+
|
|
80
|
+
| Electrical shape | Typical pattern | Notes |
|
|
81
|
+
| --- | --- | --- |
|
|
82
|
+
| One signal pin → one R → VCC | `pull_resistor` `polarity=up` | Bind `signal_host` + `resistor`; optional `rail` or auto-place VCC |
|
|
83
|
+
| One signal pin → one R → GND | `pull_resistor` `polarity=down` | Same; optional `rail` = GND |
|
|
84
|
+
| One power pin → bulk (+ optional bypass) → GND | `decoupling_cap` | See bulk/bypass bind table below |
|
|
85
|
+
| Master + slaves + SDA/SCL pull-ups | `i2c_bus` | Prefer over separate pull_resistor applies for the I2C cluster |
|
|
86
|
+
| Master + slaves + SPI lanes | `spi_bus` | Apply with **`route_mode=NONE`** (layout only); AI routes each `connections[]` entry |
|
|
87
|
+
| MCU xin/xout + crystal + load caps | `crystal` | |
|
|
88
|
+
| MCU reset + pull-up + filter cap (+ button) | `reset_circuit` | Host stub+`reset_net`; internal autoconnect |
|
|
89
|
+
| R between **two signal pins** (termination, series) | **Hand** | Not `pull_resistor` (that pattern is signal → R → rail) |
|
|
90
|
+
| Two control pins shorted (e.g. RE + DE) | **Hand** | `autoConnect` + NetAlias |
|
|
91
|
+
| Net alias to off-page / MCU port | **Hand** | stub + `placeNetAliasAt` after patterns |
|
|
92
|
+
|
|
93
|
+
When the catalog grows, call `list-circuit-patterns` again — do not rely only on
|
|
94
|
+
the static table below.
|
|
95
|
+
|
|
96
|
+
## Catalog (call ListCircuitPatterns)
|
|
97
|
+
|
|
98
|
+
Always call `pattern-layout-list-circuit-patterns` first. The table below is a
|
|
99
|
+
shortcut; the RPC is the source of truth for roles / terminals / options.
|
|
100
|
+
|
|
101
|
+
| `pattern` | `id` | Required roles | Repeatable | Optional roles | Key options (defaults) |
|
|
102
|
+
| --- | --- | --- | --- | --- | --- |
|
|
103
|
+
| `CIRCUIT_PATTERN_DECOUPLING_CAP` | `decoupling_cap` | `host`(vcc), `cap[0]` bulk, optional `cap_bypass` or `cap[1]` | `cap` 1..8, `cap_bypass` 0..1 | `gnd`, `vcc` | `pitch=8`, `cap_gap=4`, `rail_offset=4`, `gnd_gap=4`, `power_net=VCC`, `power_symbol=VCC` |
|
|
104
|
+
| `CIRCUIT_PATTERN_PULL_RESISTOR` | `pull_resistor` | `signal_host`(sig), `resistor[]`(a/b) | both 1..8 | `rail` | `polarity=up\|down`, `pitch=6`, `lane_gap=4`, `rail_gap=4` |
|
|
105
|
+
| `CIRCUIT_PATTERN_I2C_BUS` | `i2c_bus` | `master`(sda/scl), `r_pullup_sda`, `r_pullup_scl` | `slave` 0..8 | `vcc` | `lane_gap=3`, `device_gap=10`, `pull_gap=4`, `pull_offset=4`, `sda_net=SDA`, `scl_net=SCL`, `lane_above=true` |
|
|
106
|
+
| `CIRCUIT_PATTERN_SPI_BUS` | `spi_bus` | `master`(sck/mosi/miso/cs), `slave[]` | `slave` 1..8 | — | `lane_gap=3`, `device_gap=10`, `share_cs=false`; **default `PATTERN_ROUTE_NONE`** — response `connections[]` lists pending nets (`note=pending AI routing`); agent chooses `autoConnect` vs dual-end `placePinStubWireAndNetAlias` per [placement-conventions.md](placement-conventions.md) |
|
|
107
|
+
| `CIRCUIT_PATTERN_CRYSTAL` | `crystal` | `host`(xin/xout), `xtal`(a/b), `cap_load_1`, `cap_load_2` | — | `r_feedback`, `gnd` | `cap_gap=4`, `xtal_offset=6`, `cap_spread=4` |
|
|
108
|
+
| `CIRCUIT_PATTERN_RESET_CIRCUIT` | `reset_circuit` | `host`(rst), `pull_up`(a/b), `filter_cap`(a/b) | — | `reset_sw`, `vcc`, `gnd` | `reset_net=RESET`, `pitch=6`, `branch_offset=4`, `branch_gap=4`, `sw_outward_gap=4`, `vcc_gap=4`, `gnd_gap=4`, `stub_length=3` |
|
|
109
|
+
|
|
110
|
+
`host` / `signal_host` are **not moved** (`movable=false`). Power symbols can be
|
|
111
|
+
bound (`power_mode=BOUND_ONLY`) or auto-created (`AUTO_PLACE`, default).
|
|
112
|
+
|
|
113
|
+
`anchor` is an external display point. Exact meaning is in
|
|
114
|
+
`descriptor.anchor_semantics` (typically the first device's bottom-left or the
|
|
115
|
+
leftmost cap).
|
|
116
|
+
|
|
117
|
+
`orientation` defaults to `LEFT_TO_RIGHT`. Other values are an affine transform
|
|
118
|
+
of the same template — do not rewrite roles.
|
|
119
|
+
|
|
120
|
+
### Decoupling cap: bulk + optional bypass
|
|
121
|
+
|
|
122
|
+
Typical LDO/MCU input pairs: **10µF bulk** + **100nF bypass** on the same power
|
|
123
|
+
pin. The engine places both caps **vertical**, **same pin-row height**, **parallel
|
|
124
|
+
along the host pin outward direction** (e.g. VIN on the right → both caps sit to
|
|
125
|
+
the right of the pin, spaced by `cap_gap`).
|
|
126
|
+
|
|
127
|
+
| Bind | When |
|
|
128
|
+
| --- | --- |
|
|
129
|
+
| `cap` slot 0 | Always — bulk / filter cap (e.g. 10µF) |
|
|
130
|
+
| `cap_bypass` | When the design includes an HF bypass (e.g. 100nF). **Omit the role entirely** when there is no bypass cap. |
|
|
131
|
+
| `cap` slot 1 | Legacy alias for bypass (same layout as `cap_bypass`) |
|
|
132
|
+
|
|
133
|
+
After `ApplyCircuitPattern`, read `response.message`:
|
|
134
|
+
|
|
135
|
+
- `ok; bulk+bypass caps parallel outward …` — bypass was bound and laid out
|
|
136
|
+
- `ok; bulk filter cap only …` — no bypass role bound
|
|
137
|
+
|
|
138
|
+
Do **not** hand-wire between bulk and bypass after apply; autoconnect covers
|
|
139
|
+
`host.vcc → cap[0].a`, `cap.a → rail` (every cap), and `cap.b → GND` — one wire
|
|
140
|
+
per pin. Never wire `host.vcc → each cap.a` or `host.vcc → rail` by hand: the
|
|
141
|
+
first duplicates the cap pin and the second has to detour around the cap bodies.
|
|
142
|
+
|
|
143
|
+
### Power rail: let the pattern place it
|
|
144
|
+
|
|
145
|
+
**Do not** hand-place `+5V` / `3V3` / `VCC` on a fixed page side before apply — the
|
|
146
|
+
host power pin may be on the opposite side (e.g. LDO VIN on the right). The engine
|
|
147
|
+
**auto-places the rail symbol above the cap cluster on the host pin outward side**
|
|
148
|
+
and autoconnects `host.vcc → cap[0].a` plus `cap.a → rail`.
|
|
149
|
+
|
|
150
|
+
| Option | Purpose |
|
|
151
|
+
| --- | --- |
|
|
152
|
+
| `power_net` | Net label on the auto rail (default `VCC`; use `+5V`, `3V3`, …) |
|
|
153
|
+
| `power_symbol` | Library symbol name (default `VCC`) |
|
|
154
|
+
|
|
155
|
+
Only bind optional role `vcc` when reusing an **existing** rail symbol; otherwise
|
|
156
|
+
**omit `vcc`** and let apply create one. Use `power_mode=BOUND_ONLY` with a bound
|
|
157
|
+
`gnd` if the design shares one ground symbol; rail is still auto-placed unless
|
|
158
|
+
`vcc` is bound.
|
|
159
|
+
|
|
160
|
+
### Pull resistor: multiple pins {#pull-resistor-multiple-pins}
|
|
161
|
+
|
|
162
|
+
Up to **8** `(signal_host, resistor)` pairs per apply — same `slotIndex` on both
|
|
163
|
+
roles, one shared `polarity`, optional bound `rail` (VCC/GND).
|
|
164
|
+
|
|
165
|
+
| Case | Do |
|
|
166
|
+
| --- | --- |
|
|
167
|
+
| N signal pins, same pull direction, same rail | **One apply**, slots `0..N−1`; bind `rail` when reusing an existing power symbol (`power_mode=BOUND_ONLY`) |
|
|
168
|
+
| Mixed pull-up + pull-down, or different rails | **Separate applies** |
|
|
169
|
+
| Bus with paired pull-ups (e.g. I2C) | Matching **bus pattern** (`i2c_bus`, …) — not N separate `pull_resistor` applies |
|
|
170
|
+
|
|
171
|
+
One apply merges a single rail connection; repeated applies with `AUTO_PLACE` may
|
|
172
|
+
duplicate GND/VCC and hit `AREA_OCCUPIED` near the first cluster.
|
|
173
|
+
|
|
174
|
+
**Layout:** each resistor offsets from its own `sig` pin (`pitch`), outward from
|
|
175
|
+
the host edge (left/right/top/bottom). Multiple pins on the same edge use
|
|
176
|
+
`lane_gap` to stagger outward; the engine also nudges if bodies still overlap.
|
|
177
|
+
|
|
178
|
+
After apply, hand-finish only `response.connections` entries with `routed=false`;
|
|
179
|
+
do not re-wire segments already routed.
|
|
180
|
+
|
|
181
|
+
### Reset circuit
|
|
182
|
+
|
|
183
|
+
Topology: **VCC → pull-up → reset net → (switch ∥ filter cap) → GND**. Layout extends
|
|
184
|
+
outward from the bound MCU `host.rst` pin, then stacks **pull-up → optional switch →
|
|
185
|
+
cap → GND** on one trunk column (avoids side loops). The reset button body is placed
|
|
186
|
+
**further outward** than the trunk (`sw_outward_gap`, default 4 grids) and clamped
|
|
187
|
+
clear of the host bbox so 4-pin switch pins do not overlap the MCU or trunk wires.
|
|
188
|
+
Optional `reset_sw` binds a momentary button to GND via the cap bottom node.
|
|
189
|
+
|
|
190
|
+
Debug log: `%TEMP%\pattern_layout.log` tags `[PL:reset]` and `[PL:stub]`.
|
|
191
|
+
|
|
192
|
+
| Wiring | Mechanism |
|
|
193
|
+
| --- | --- |
|
|
194
|
+
| Host reset pin | Engine places **short stub + net alias** (`reset_net`, default `RESET`) |
|
|
195
|
+
| Pull-up, cap, switch, rails | **autoconnect** inside the pattern |
|
|
196
|
+
| Host ↔ pull-up | autoconnect on `RESET` after host stub |
|
|
197
|
+
|
|
198
|
+
Bind `reset_sw` only when the design includes a reset button; omit the role for
|
|
199
|
+
cap-only RC debounce. Use `power_net` / bound `vcc` for the MCU rail name (`3V3`,
|
|
200
|
+
`VCC_3V3`, …). Do not hand-place a second stub on `host.rst` after apply.
|
|
201
|
+
|
|
202
|
+
### I2C / SPI bus: autoconnect + spacing
|
|
203
|
+
|
|
204
|
+
Both patterns use **pin-to-pin autoconnect** (no manual coordinate wires). Slaves
|
|
205
|
+
are spaced by **`device_gap` (default 10 grids)** measured between bus pin columns,
|
|
206
|
+
not just bbox edges — increase it if MCU and slave bodies look cramped.
|
|
207
|
+
|
|
208
|
+
**I2C** topology:
|
|
209
|
+
|
|
210
|
+
- Pull-ups sit **between master and slave** (not on master pin X — SCL/SDA often share the same column)
|
|
211
|
+
- `r_pullup_scl/sda` vertical, bottom pin above bus by `pull_offset`; `vcc_offset` lifts 3V3 further
|
|
212
|
+
- **Hub topology**: `master.scl/sda → r_pullup_*`, `slave.scl/sda → same r_pullup_*` (not slave→master)
|
|
213
|
+
- Slave Y auto-aligns when SDA/SCL pin order is inverted vs master (MPU6050 vs STM32)
|
|
214
|
+
|
|
215
|
+
**SPI** topology:
|
|
216
|
+
|
|
217
|
+
- `slave.sck/mosi/miso → master.sck/mosi/miso` (star at master)
|
|
218
|
+
- `master.cs → slave.cs` when `share_cs=false`; `slave.cs → master.cs` when shared
|
|
219
|
+
|
|
220
|
+
Debug log tags: `[PL:i2c]`, `[PL:spi]`, `[PL:connect]`, `[PL:route]` in
|
|
221
|
+
`%TEMP%\pattern_layout.log`. Do not hand-wire SDA/SCL/SCK after apply.
|
|
222
|
+
|
|
223
|
+
## Plan-then-apply
|
|
224
|
+
|
|
225
|
+
```
|
|
226
|
+
list-circuit-patterns
|
|
227
|
+
→ get-page-occupancy # page_box + existing bboxes
|
|
228
|
+
→ place parts (rough pos) # keep out of finished occupied_box areas
|
|
229
|
+
→ apply-circuit-pattern(plan_only=true, roles, anchor)
|
|
230
|
+
if AREA_OCCUPIED: pick another anchor from conflicting_object_ids
|
|
231
|
+
→ apply-circuit-pattern(plan_only=false, route_mode=NONE for spi_bus)
|
|
232
|
+
→ book-keep response.occupied_box
|
|
233
|
+
→ for each connections[] with routed=false OR cross-block leftovers:
|
|
234
|
+
run routing gate per net
|
|
235
|
+
short (≤300 ext, low crossings) → autoConnect
|
|
236
|
+
long / crowded → dual-end placePinStubWireAndNetAlias (same netName)
|
|
237
|
+
→ layout other leftovers (power rails: autoConnect if adjacent, stub+alias if far)
|
|
238
|
+
→ kernel-get-snapshot or netlist-get-active-page-net-list
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Rules:
|
|
242
|
+
|
|
243
|
+
- **`spi_bus`:** use `PATTERN_ROUTE_NONE` — pattern moves parts only; `connections[]`
|
|
244
|
+
lists SCK/MOSI/MISO/CS intents (`routed=false`, `note=pending AI routing`).
|
|
245
|
+
- `plan_only=true` never mutates the canvas. Use it to test anchors.
|
|
246
|
+
- `ignore_area_conflict=false` (default) returns `AREA_OCCUPIED` plus
|
|
247
|
+
`conflicting_object_ids` when the planned box hits existing parts.
|
|
248
|
+
- `PATTERN_STATUS_PARTIAL` means layout was kept but some wires failed. Do not
|
|
249
|
+
undo; finish those nets with PlaceWire / stub+alias.
|
|
250
|
+
- `PATTERN_STATUS_LAYOUT_FAILED` aborted the undo group — the page is unchanged.
|
|
251
|
+
- After a successful apply, treat `occupied_box` as reserved. Later placements
|
|
252
|
+
and later patterns must stay outside it (plus a small grid margin).
|
|
253
|
+
|
|
254
|
+
## Binding roles
|
|
255
|
+
|
|
256
|
+
```typescript
|
|
257
|
+
await client.patternLayout.applyCircuitPattern({
|
|
258
|
+
context: projectCtx,
|
|
259
|
+
pattern: CircuitPatternId.CIRCUIT_PATTERN_I2C_BUS,
|
|
260
|
+
anchor: { x: 400n, y: 300n },
|
|
261
|
+
orientation: PatternOrientation.PATTERN_ORIENT_LEFT_TO_RIGHT,
|
|
262
|
+
routeMode: PatternRouteMode.PATTERN_ROUTE_FULL,
|
|
263
|
+
powerMode: PatternPowerMode.PATTERN_POWER_AUTO_PLACE,
|
|
264
|
+
planOnly: false,
|
|
265
|
+
roles: [
|
|
266
|
+
{ role: "master", objectId: mcuId, slotIndex: 0, pins: [
|
|
267
|
+
{ terminal: "sda", pinNumber: "21" },
|
|
268
|
+
{ terminal: "scl", pinNumber: "22" },
|
|
269
|
+
]},
|
|
270
|
+
{ role: "slave", objectId: eepromId, slotIndex: 0, pins: [
|
|
271
|
+
{ terminal: "sda", pinName: "SDA" },
|
|
272
|
+
{ terminal: "scl", pinName: "SCL" },
|
|
273
|
+
]},
|
|
274
|
+
{ role: "r_pullup_sda", objectId: rSdaId, slotIndex: 0, pins: [] },
|
|
275
|
+
{ role: "r_pullup_scl", objectId: rSclId, slotIndex: 0, pins: [] },
|
|
276
|
+
],
|
|
277
|
+
options: { sda_net: "SDA", scl_net: "SCL", lane_gap: "3" },
|
|
278
|
+
});
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
Pin resolution order: `pin_number` (string, e.g. `"1"`, `"A5"`) → `pin_name` →
|
|
282
|
+
two-terminal default (a=`"1"`, b=`"2"`) → power/port symbols use `"0"`.
|
|
283
|
+
|
|
284
|
+
Type-C CC pins: bind with `pinNumber: "A5"` / `"B5"` or `pinName: "CC1"` /
|
|
285
|
+
`"CC2"` — never coerce alphanumeric numbers to `int`.
|
|
286
|
+
|
|
287
|
+
## Occupancy bookkeeping
|
|
288
|
+
|
|
289
|
+
`GetPageOccupancy` returns every part/symbol bbox (and wires if
|
|
290
|
+
`include_wires=true`) in external coordinates. Use it to:
|
|
291
|
+
|
|
292
|
+
1. Floorplan several patterns before placing anything.
|
|
293
|
+
2. Choose an `anchor` whose `typical_size` box is empty.
|
|
294
|
+
3. After apply, merge `occupied_box` into the agent's reserved-rect list.
|
|
295
|
+
|
|
296
|
+
Empty `area` (all zeros) means the whole page.
|
|
297
|
+
|
|
298
|
+
## Capability skill IDs
|
|
299
|
+
|
|
300
|
+
| Task | Skill |
|
|
301
|
+
| --- | --- |
|
|
302
|
+
| Catalog | `pattern-layout-list-circuit-patterns` |
|
|
303
|
+
| Occupancy | `pattern-layout-get-page-occupancy` |
|
|
304
|
+
| Dry-run / apply | `pattern-layout-apply-circuit-pattern` |
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# Editing a circuit (local / surgical changes)
|
|
2
|
+
|
|
3
|
+
Use this when the task is **modify part of an existing design**, not redraw the
|
|
4
|
+
whole page: change a value, rewire one pin, replace one part, rename a net label.
|
|
5
|
+
|
|
6
|
+
**Flow C** — see [SYSTEM-PROMPT.md](../SYSTEM-PROMPT.md) §流程 C.
|
|
7
|
+
|
|
8
|
+
## When to use Flow C vs A vs B
|
|
9
|
+
|
|
10
|
+
| User intent | Flow |
|
|
11
|
+
| --- | --- |
|
|
12
|
+
| Draw a new circuit from scratch | **A** — patterns + placement |
|
|
13
|
+
| "What does VR201 do?" / read-only | **B** — [reading-a-circuit.md](./reading-a-circuit.md) |
|
|
14
|
+
| Change C201 to 1 µF / move R5 net / swap U3 | **C** — this doc |
|
|
15
|
+
|
|
16
|
+
**Never** clear the page or redraw the whole schematic for a local edit.
|
|
17
|
+
|
|
18
|
+
## Fixed workflow (mandatory order)
|
|
19
|
+
|
|
20
|
+
```mermaid
|
|
21
|
+
flowchart TD
|
|
22
|
+
confirm[1. Confirm projectId]
|
|
23
|
+
snap[2. GetSnapshot locate targets]
|
|
24
|
+
scope[3. Define blast radius]
|
|
25
|
+
diff[4. Print diff ask user]
|
|
26
|
+
exec[5. Execute minimal RPCs]
|
|
27
|
+
verify[6. Snapshot + netList verify]
|
|
28
|
+
confirm --> snap --> scope --> diff --> exec --> verify
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### 1. Confirm project
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
const active = await client.project.getActiveProject({ context: editorCtx });
|
|
35
|
+
const projectId = active.project?.projectId;
|
|
36
|
+
console.log("projectId:", projectId); // print every run
|
|
37
|
+
const ctx = client.createProjectContext(projectId!);
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 2. Locate targets (snapshot + find)
|
|
41
|
+
|
|
42
|
+
| Need | Source |
|
|
43
|
+
| --- | --- |
|
|
44
|
+
| Topology / neighbors | `kernel.GetSnapshot` — see [reading-a-circuit.md](./reading-a-circuit.md) |
|
|
45
|
+
| Canvas object id for edit | `canvasObjectId` from snapshot **or** `FindObjectByProperty("Reference", ref)` → `objectIds[0]` |
|
|
46
|
+
| Property keys | [property-conventions.md](./property-conventions.md) — set designator with **`Part Reference`**, not `Reference` |
|
|
47
|
+
|
|
48
|
+
Run the read template for context before editing:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
REF=VR201 npx tsx scripts/read-circuit.ts
|
|
52
|
+
REF=C201 TRACE=1 npx tsx scripts/read-circuit.ts # optional series traversal
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The script prints **canvas 编辑 id** block for the designator → edit bridge.
|
|
56
|
+
|
|
57
|
+
### 3. Blast radius (修改集)
|
|
58
|
+
|
|
59
|
+
Before any write, list **only** what will change:
|
|
60
|
+
|
|
61
|
+
| Edit type | Typical blast radius |
|
|
62
|
+
| --- | --- |
|
|
63
|
+
| Change Value / Footprint | That object only |
|
|
64
|
+
| Rename designator | That object + verify find by new ref |
|
|
65
|
+
| Rewire one pin | That pin stub/alias **or** one `autoConnect`; avoid touching unrelated nets |
|
|
66
|
+
| Replace part | Old object + its wires (often delete old → place new → reconnect listed pins) |
|
|
67
|
+
| Bulk delete | **Forbidden** without explicit user confirmation |
|
|
68
|
+
|
|
69
|
+
Do **not** use `deleteObjectsByIds` on whole-page occupancy without user OK.
|
|
70
|
+
|
|
71
|
+
### 4. Print diff → user confirmation
|
|
72
|
+
|
|
73
|
+
**Mandatory** for Flow C (unless user explicitly said "just do it"):
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
计划修改:
|
|
77
|
+
- C201 Value: 0.1 µF → 1 µF (objectId=…)
|
|
78
|
+
- VR201 pin5 仍接 N0261718,不改
|
|
79
|
+
爆炸半径: 1 个对象,0 条 net 重布
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Wait for user confirmation before `SetObjectProperty` / delete / place.
|
|
83
|
+
|
|
84
|
+
Environment escape hatch: `CONFIRM=1` in script (document in script header).
|
|
85
|
+
|
|
86
|
+
### 5. Execute (minimal RPC set)
|
|
87
|
+
|
|
88
|
+
| Recipe | RPCs | Template script |
|
|
89
|
+
| --- | --- | --- |
|
|
90
|
+
| Edit property | `FindObjectByProperty` → `SetObjectProperty` | `scripts/edit-property-by-ref.ts` |
|
|
91
|
+
| Rewire pin | Snapshot pin + `autoConnectObjectsById` **or** `placePinStubWireAndNetAlias` | `scripts/rewire-pin-by-ref.ts` |
|
|
92
|
+
| Replace part | Snapshot pose → `deleteObjectsByIds` → `placeKicadSymbol` → reconnect | `scripts/replace-part-by-ref.ts` |
|
|
93
|
+
|
|
94
|
+
Common rules:
|
|
95
|
+
|
|
96
|
+
- `SetObjectProperty`: `op: 1` (OBJ_PROP_SET), `commitUndo: true`
|
|
97
|
+
- Power symbol wiring: pin **`0`** on VCC/GND side
|
|
98
|
+
- After delete: poll occupancy until ids gone ([circuit-pattern-layout.md](./circuit-pattern-layout.md) § delete settle)
|
|
99
|
+
- After place: poll until new ids appear before wiring
|
|
100
|
+
|
|
101
|
+
**Rewire reality check:** there is no dedicated "disconnect this pin only" RPC in
|
|
102
|
+
the skill toolbox. Practical options:
|
|
103
|
+
|
|
104
|
+
1. **Join existing net:** `autoConnectObjectsById` to a part already on the target net.
|
|
105
|
+
2. **Name a net at pin:** `placePinStubWireAndNetAlias` with target `netName` (routing gate in [placement-conventions.md](./placement-conventions.md)).
|
|
106
|
+
3. **True cut:** identify wire segments via `listWireSegments().wires` and delete only if user accepts risk — prefer (1)/(2) for surgical edits.
|
|
107
|
+
|
|
108
|
+
### 6. Dual-source verification
|
|
109
|
+
|
|
110
|
+
After writes:
|
|
111
|
+
|
|
112
|
+
1. **`GetSnapshot`** — target ref pin→net, no unexpected floating pins.
|
|
113
|
+
2. **`netList.getProjectNetList`** or `getActivePageNetList` — net membership for changed nets.
|
|
114
|
+
3. Re-run consistency checks from Flow B (e.g. `output_voltage` vs rail name).
|
|
115
|
+
4. Optional `zoomAll` when user wants visual check (Flow B default skips viewport changes).
|
|
116
|
+
|
|
117
|
+
## Safety rules (Flow C)
|
|
118
|
+
|
|
119
|
+
- **No** whole-page clear without confirmation.
|
|
120
|
+
- **No** Flow A pattern re-apply on existing design unless user asks to regenerate a subnet.
|
|
121
|
+
- **No** dependency on `GetConnectivity`, `selection.*`, `transaction.*` — see [rpc-availability.md](./rpc-availability.md).
|
|
122
|
+
- Prefer **one object / one net** per script; split large edits into reviewable steps.
|
|
123
|
+
- Report `projectId` and every `objectId` mutated in stdout.
|
|
124
|
+
|
|
125
|
+
## Recipe: edit property by REF
|
|
126
|
+
|
|
127
|
+
Env: `REF=C201` `PROP=Value` `NEW=1 µF` `CONFIRM=1`
|
|
128
|
+
|
|
129
|
+
See `template/scripts/edit-property-by-ref.ts`.
|
|
130
|
+
|
|
131
|
+
## Recipe: rewire pin by REF
|
|
132
|
+
|
|
133
|
+
Env: `REF=R201` `PIN=1` `TARGET_REF=U301` `TARGET_PIN=14` `CONFIRM=1`
|
|
134
|
+
|
|
135
|
+
Connects source pin to an existing part on the target net via `autoConnectObjectsById`.
|
|
136
|
+
For net-label-only targets, use `TARGET_NET=+3.3V` + stub/alias path in script comments.
|
|
137
|
+
|
|
138
|
+
See `template/scripts/rewire-pin-by-ref.ts`.
|
|
139
|
+
|
|
140
|
+
## Recipe: replace part by REF
|
|
141
|
+
|
|
142
|
+
Env: `OLD_REF=U3` `NEW_MPN=…` `CONFIRM=1`
|
|
143
|
+
|
|
144
|
+
1. Snapshot old position/rotation/mirrored + pin→net list.
|
|
145
|
+
2. User confirms diff (old deleted, new placed, N pins reconnected).
|
|
146
|
+
3. Delete old → place via part-search → reconnect pin-by-pin.
|
|
147
|
+
|
|
148
|
+
See `template/scripts/replace-part-by-ref.ts`.
|
|
149
|
+
|
|
150
|
+
## From understanding (B) to editing (C)
|
|
151
|
+
|
|
152
|
+
After Flow B / `read-circuit.ts`:
|
|
153
|
+
|
|
154
|
+
1. Copy `canvasObjectId` or `FindObject` id from output.
|
|
155
|
+
2. Use in Flow C script — **do not** guess ids from designator strings alone for wiring.
|
|
156
|
+
3. If `metadata.properties` was empty during read, still OK to edit Value/Footprint; do not invent MPN.
|
|
157
|
+
|
|
158
|
+
## Engine improvements (optional, not blocking)
|
|
159
|
+
|
|
160
|
+
Documented in [rpc-availability.md](./rpc-availability.md) § Skill-side workarounds:
|
|
161
|
+
|
|
162
|
+
- True `GetConnectivity` graph → replace client-side series BFS.
|
|
163
|
+
- Per-pin associated wire ids → safer disconnect.
|
|
164
|
+
- `FindNet` explicit unimplemented instead of silent false.
|
|
165
|
+
- Selection API for "edit this region".
|
|
166
|
+
|
|
167
|
+
Skill ships with snapshot BFS + find-by-property until engine catches up.
|