copperhead 0.9.0 → 0.10.0

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.
Files changed (90) hide show
  1. package/NOTICE +1 -1
  2. package/README.md +6 -6
  3. package/dist/agent/filetools.js +24 -1
  4. package/dist/agent/filetools.js.map +1 -1
  5. package/dist/agent/ledger.js +24 -0
  6. package/dist/agent/ledger.js.map +1 -1
  7. package/dist/agent/loop.js +29 -58
  8. package/dist/agent/loop.js.map +1 -1
  9. package/dist/agent/prompts.js +4 -3
  10. package/dist/agent/prompts.js.map +1 -1
  11. package/dist/agent/providers/tool-protocol.js +21 -0
  12. package/dist/agent/providers/tool-protocol.js.map +1 -1
  13. package/dist/agent/recovery.js +95 -1
  14. package/dist/agent/recovery.js.map +1 -1
  15. package/dist/agent/tools.js +185 -1
  16. package/dist/agent/tools.js.map +1 -1
  17. package/dist/agent/transcript.js +2 -0
  18. package/dist/agent/transcript.js.map +1 -1
  19. package/dist/cli.js +75 -0
  20. package/dist/cli.js.map +1 -1
  21. package/dist/commands/check.js +33 -1
  22. package/dist/commands/check.js.map +1 -1
  23. package/dist/commands/create.js +177 -25
  24. package/dist/commands/create.js.map +1 -1
  25. package/dist/commands/doctor.js +50 -3
  26. package/dist/commands/doctor.js.map +1 -1
  27. package/dist/config.js +1 -0
  28. package/dist/config.js.map +1 -1
  29. package/dist/kicad/bootstrap.js +24 -3
  30. package/dist/kicad/bootstrap.js.map +1 -1
  31. package/dist/kicad/dossier.js +207 -0
  32. package/dist/kicad/dossier.js.map +1 -0
  33. package/dist/kicad/draft/draft.js +132 -0
  34. package/dist/kicad/draft/draft.js.map +1 -0
  35. package/dist/kicad/draft/engine.js +2389 -0
  36. package/dist/kicad/draft/engine.js.map +1 -0
  37. package/dist/kicad/draft/ir.js +368 -0
  38. package/dist/kicad/draft/ir.js.map +1 -0
  39. package/dist/kicad/draft/symsource.js +490 -0
  40. package/dist/kicad/draft/symsource.js.map +1 -0
  41. package/dist/kicad/emit.js +181 -0
  42. package/dist/kicad/emit.js.map +1 -0
  43. package/dist/kicad/fab.js +13 -0
  44. package/dist/kicad/fab.js.map +1 -1
  45. package/dist/kicad/legibility.js +561 -0
  46. package/dist/kicad/legibility.js.map +1 -0
  47. package/dist/kicad/score.js +261 -0
  48. package/dist/kicad/score.js.map +1 -0
  49. package/dist/kicad/sexp.js +239 -6
  50. package/dist/kicad/sexp.js.map +1 -1
  51. package/dist/kicad/symlib.js +346 -16
  52. package/dist/kicad/symlib.js.map +1 -1
  53. package/dist/memory/bom-table.js +75 -39
  54. package/dist/memory/bom-table.js.map +1 -1
  55. package/dist/memory/scaffold.js +6 -0
  56. package/dist/memory/scaffold.js.map +1 -1
  57. package/dist/util/redact.js +6 -0
  58. package/dist/util/redact.js.map +1 -1
  59. package/package.json +9 -7
  60. package/src/agent/filetools.ts +26 -1
  61. package/src/agent/ledger.ts +24 -0
  62. package/src/agent/loop.ts +28 -61
  63. package/src/agent/prompts.ts +4 -3
  64. package/src/agent/providers/tool-protocol.ts +22 -0
  65. package/src/agent/recovery.ts +94 -1
  66. package/src/agent/tools.ts +189 -1
  67. package/src/agent/transcript.ts +6 -0
  68. package/src/cli.ts +71 -0
  69. package/src/commands/check.ts +51 -1
  70. package/src/commands/create.ts +179 -20
  71. package/src/commands/doctor.ts +51 -3
  72. package/src/config.ts +24 -0
  73. package/src/kicad/bootstrap.ts +24 -3
  74. package/src/kicad/dossier.ts +217 -0
  75. package/src/kicad/draft/draft.ts +171 -0
  76. package/src/kicad/draft/engine.ts +2466 -0
  77. package/src/kicad/draft/ir.ts +416 -0
  78. package/src/kicad/draft/symsource.ts +535 -0
  79. package/src/kicad/emit.ts +236 -0
  80. package/src/kicad/fab.ts +15 -0
  81. package/src/kicad/legibility.ts +646 -0
  82. package/src/kicad/score.ts +323 -0
  83. package/src/kicad/sexp.ts +315 -6
  84. package/src/kicad/symlib.ts +364 -18
  85. package/src/memory/bom-table.ts +85 -38
  86. package/src/memory/scaffold.ts +6 -0
  87. package/src/util/redact.ts +6 -0
  88. package/dist/memory/synap.js +0 -152
  89. package/dist/memory/synap.js.map +0 -1
  90. package/src/memory/synap.ts +0 -217
@@ -0,0 +1,261 @@
1
+ import { readSheetGeometry } from './sexp.js';
2
+ import { checkLegibility } from './legibility.js';
3
+ const DEFAULT_WEIGHTS = {
4
+ 'wire-crossings': 10,
5
+ 'wire-bends': 5,
6
+ 'wire-length': 5,
7
+ 'label-to-wire-ratio': 5,
8
+ 'group-cohesion': 10,
9
+ 'flow-direction': 10,
10
+ utilization: 10,
11
+ 'axis-alignment': 10,
12
+ 'spacing-uniformity': 10,
13
+ 'straight-wire-ratio': 5,
14
+ 'label-alignment': 5,
15
+ 'whitespace-balance': 10,
16
+ 'pair-symmetry': 5,
17
+ };
18
+ /** Composite is capped this far below the Tier A floor when errors exist. */
19
+ const DEFAULT_FLOOR = 85;
20
+ const ERROR_CAP = 40;
21
+ /** Top-edge spread (mm) within which two group boxes count as the same row. */
22
+ const ROW_BAND = 12;
23
+ const PAPER = {
24
+ A5: { w: 210, h: 148 },
25
+ A4: { w: 297, h: 210 },
26
+ A3: { w: 420, h: 297 },
27
+ A2: { w: 594, h: 420 },
28
+ A1: { w: 841, h: 594 },
29
+ A0: { w: 1189, h: 841 },
30
+ };
31
+ const segLen = (s) => Math.hypot(s.x2 - s.x1, s.y2 - s.y1);
32
+ const isVert = (s) => s.x1 === s.x2;
33
+ function properCrossing(a, b) {
34
+ // orthogonal proper crossing (interiors intersect); shared endpoints are joins
35
+ const [v, h] = isVert(a) && !isVert(b) ? [a, b] : !isVert(a) && isVert(b) ? [b, a] : [null, null];
36
+ if (!v || !h)
37
+ return false;
38
+ const [hy, vx] = [h.y1, v.x1];
39
+ const [hx1, hx2] = [Math.min(h.x1, h.x2), Math.max(h.x1, h.x2)];
40
+ const [vy1, vy2] = [Math.min(v.y1, v.y2), Math.max(v.y1, v.y2)];
41
+ return vx > hx1 + 0.01 && vx < hx2 - 0.01 && hy > vy1 + 0.01 && hy < vy2 - 0.01;
42
+ }
43
+ export async function scoreSchematic(rootSch, opts = {}) {
44
+ const sheets = await readSheetGeometry(rootSch);
45
+ const legibility = await checkLegibility(rootSch, {
46
+ docsDir: opts.docsDir ?? null,
47
+ ...(opts.config ? { config: opts.config } : {}),
48
+ });
49
+ return scoreFromGeometry(sheets, legibility, opts.config);
50
+ }
51
+ export function scoreFromGeometry(sheets, legibility, config) {
52
+ const weights = { ...DEFAULT_WEIGHTS };
53
+ for (const [k, v] of Object.entries(config?.score?.weights ?? {})) {
54
+ if (k in weights && typeof v === 'number' && Number.isFinite(v) && v >= 0)
55
+ weights[k] = v;
56
+ }
57
+ // Sanitized like the weights above: a floor of 0 (or a non-number) would
58
+ // push the error cap `min(ERROR_CAP, floor - 1)` negative or NaN.
59
+ const rawFloor = config?.score?.floor;
60
+ const floor = typeof rawFloor === 'number' && Number.isFinite(rawFloor) && rawFloor >= 1 ? rawFloor : DEFAULT_FLOOR;
61
+ // ---- collect geometry across sheets ----
62
+ const segs = sheets.flatMap((s) => s.wires);
63
+ const labels = sheets.flatMap((s) => s.labels);
64
+ const realSyms = sheets.flatMap((s) => s.symbols.filter((y) => !y.isPower).map((y) => ({ ...y, sheet: s.sheetName })));
65
+ // wire crossings
66
+ let crossings = 0;
67
+ for (let i = 0; i < segs.length; i++) {
68
+ for (let j = i + 1; j < segs.length; j++)
69
+ if (properCrossing(segs[i], segs[j]))
70
+ crossings++;
71
+ }
72
+ // bends: points where exactly two segments of different orientation meet
73
+ const ends = new Map();
74
+ for (const s of segs) {
75
+ for (const [x, y] of [[s.x1, s.y1], [s.x2, s.y2]]) {
76
+ const k = `${x},${y}`;
77
+ ends.set(k, [...(ends.get(k) ?? []), s]);
78
+ }
79
+ }
80
+ let bends = 0;
81
+ for (const list of ends.values()) {
82
+ if (list.length === 2 && isVert(list[0]) !== isVert(list[1]))
83
+ bends++;
84
+ }
85
+ const totalLen = segs.reduce((s, w) => s + segLen(w), 0);
86
+ // group cohesion: same-name label pairs, mean anchor distance vs sheet diagonal
87
+ const byName = new Map();
88
+ for (const l of labels)
89
+ byName.set(l.name, [...(byName.get(l.name) ?? []), { x: l.x, y: l.y }]);
90
+ const paper = PAPER[sheets[0]?.paper.name ?? 'A4'] ?? PAPER.A4;
91
+ const diag = Math.hypot(paper.w, paper.h);
92
+ const pairDists = [];
93
+ for (const pts of byName.values()) {
94
+ for (let i = 0; i < pts.length; i++) {
95
+ for (let j = i + 1; j < pts.length; j++)
96
+ pairDists.push(Math.hypot(pts[i].x - pts[j].x, pts[i].y - pts[j].y));
97
+ }
98
+ }
99
+ const meanPair = pairDists.length ? pairDists.reduce((a, b) => a + b, 0) / pairDists.length : 0;
100
+ // flow-direction: cross-group label nets should connect adjacent groups in
101
+ // reading order; a hop across intervening groups reads as against-the-flow
102
+ // wiring
103
+ const rects = sheets.flatMap((s) => s.rectangles.map((r) => ({
104
+ minX: Math.min(r.x1, r.x2),
105
+ maxX: Math.max(r.x1, r.x2),
106
+ minY: Math.min(r.y1, r.y2),
107
+ maxY: Math.max(r.y1, r.y2),
108
+ })));
109
+ // Reading order is rows first, then left-to-right within a row. Ordering by
110
+ // minX alone was correct only while every group sat in one band; on a sheet
111
+ // whose groups wrap onto several rows it interleaves row 2 back into row 1
112
+ // and reports flow violations for a drawing that reads perfectly.
113
+ const byRow = [...rects].sort((a, b) => a.minY - b.minY || a.minX - b.minX);
114
+ const rows = [];
115
+ for (const r of byRow) {
116
+ const row = rows[rows.length - 1];
117
+ // Rows are separated by a group box height; members of one row share a top
118
+ // edge to within a symbol cell, so a generous band still cannot merge two.
119
+ if (row && r.minY - row[0].minY <= ROW_BAND)
120
+ row.push(r);
121
+ else
122
+ rows.push([r]);
123
+ }
124
+ const ordered = rows.flatMap((row) => [...row].sort((a, b) => a.minX - b.minX));
125
+ const groupIdx = (x, y) => ordered.findIndex((r) => x > r.minX && x < r.maxX && y > r.minY && y < r.maxY);
126
+ /** Which wrapped row a point falls in; -1 when it is in no group box. */
127
+ const rowIdx = (x, y) => rows.findIndex((row) => row.some((r) => x > r.minX && x < r.maxX && y > r.minY && y < r.maxY));
128
+ let crossNets = 0;
129
+ let flowViolations = 0;
130
+ for (const pts of byName.values()) {
131
+ const gs = [...new Set(pts.map((p) => groupIdx(p.x, p.y)).filter((g) => g >= 0))];
132
+ if (gs.length > 1) {
133
+ crossNets++;
134
+ if (Math.max(...gs) - Math.min(...gs) > 1)
135
+ flowViolations++;
136
+ }
137
+ }
138
+ // utilization + whitespace balance over the first sheet's usable frame
139
+ const items = [
140
+ ...realSyms.map((s) => ({ minX: s.at.x - 2, minY: s.at.y - 2, maxX: s.at.x + 2, maxY: s.at.y + 2 })),
141
+ ...rects,
142
+ ];
143
+ const content = items.length
144
+ ? items.reduce((a, b) => ({
145
+ minX: Math.min(a.minX, b.minX),
146
+ minY: Math.min(a.minY, b.minY),
147
+ maxX: Math.max(a.maxX, b.maxX),
148
+ maxY: Math.max(a.maxY, b.maxY),
149
+ }))
150
+ : null;
151
+ const usable = { minX: 10, minY: 10, maxX: paper.w - 10, maxY: paper.h - 10 - 30 };
152
+ const usableArea = (usable.maxX - usable.minX) * (usable.maxY - usable.minY);
153
+ const utilization = content
154
+ ? Math.min(1, ((content.maxX - content.minX) * (content.maxY - content.minY)) / usableArea)
155
+ : 0;
156
+ const centroidOff = content
157
+ ? Math.hypot((content.minX + content.maxX) / 2 - (usable.minX + usable.maxX) / 2, (content.minY + content.maxY) / 2 - (usable.minY + usable.maxY) / 2) / (diag / 2)
158
+ : 1;
159
+ // axis alignment: symbols sharing an origin axis with at least one other
160
+ const sharesAxis = (i) => realSyms.some((o, j) => j !== i && (Math.abs(o.at.x - realSyms[i].at.x) < 0.01 || Math.abs(o.at.y - realSyms[i].at.y) < 0.01));
161
+ const axisAligned = realSyms.length > 1 ? realSyms.filter((_, i) => sharesAxis(i)).length / realSyms.length : 1;
162
+ // spacing uniformity: variance of consecutive gaps within shared-x columns
163
+ const cols = new Map();
164
+ for (const s of realSyms) {
165
+ // Keyed by row as well as x: a column is a vertical run the eye reads as
166
+ // one stack. Once groups wrap, two symbols in different rows can share an x
167
+ // while sitting a whole row apart, and treating that jump as a "gap" pushes
168
+ // the coefficient of variation — and the score — off a cliff.
169
+ const k = `${s.sheet}:${Math.round(s.at.x * 100)}:${rowIdx(s.at.x, s.at.y)}`;
170
+ cols.set(k, [...(cols.get(k) ?? []), s.at.y]);
171
+ }
172
+ const gapCVs = [];
173
+ for (const ys of cols.values()) {
174
+ if (ys.length < 3)
175
+ continue;
176
+ ys.sort((a, b) => a - b);
177
+ const gaps = ys.slice(1).map((y, i) => y - ys[i]);
178
+ const mean = gaps.reduce((a, b) => a + b, 0) / gaps.length;
179
+ const sd = Math.sqrt(gaps.reduce((a, g) => a + (g - mean) ** 2, 0) / gaps.length);
180
+ gapCVs.push(mean > 0 ? sd / mean : 0);
181
+ }
182
+ const spacingUniformity = gapCVs.length ? Math.max(0, 1 - gapCVs.reduce((a, b) => a + b, 0) / gapCVs.length) : 1;
183
+ // pair symmetry: same-libId+value symbols in one group aligned on a shared axis
184
+ const pairKeys = new Map();
185
+ for (const s of realSyms) {
186
+ const g = groupIdx(s.at.x, s.at.y);
187
+ const k = `${g}:${s.libId}:${s.value}`;
188
+ pairKeys.set(k, [...(pairKeys.get(k) ?? []), { x: s.at.x, y: s.at.y }]);
189
+ }
190
+ let pairs = 0;
191
+ let symmetric = 0;
192
+ for (const pts of pairKeys.values()) {
193
+ if (pts.length < 2)
194
+ continue;
195
+ for (let i = 0; i < pts.length; i++) {
196
+ for (let j = i + 1; j < pts.length; j++) {
197
+ pairs++;
198
+ if (Math.abs(pts[i].x - pts[j].x) < 0.01 || Math.abs(pts[i].y - pts[j].y) < 0.01)
199
+ symmetric++;
200
+ }
201
+ }
202
+ }
203
+ const pairSymmetry = pairs ? symmetric / pairs : 1;
204
+ const horizLabels = labels.length
205
+ ? labels.filter((l) => Math.abs(l.rot % 180) !== 90).length / labels.length
206
+ : 1;
207
+ const straightRatio = segs.length ? Math.max(0, 1 - bends / segs.length) : 1;
208
+ const labelRatio = segs.length ? labels.length / segs.length : labels.length ? 1 : 0;
209
+ // ---- normalize to [0,1] goodness and compose ----
210
+ const raw = {
211
+ 'wire-crossings': { raw: crossings, score: 1 / (1 + crossings) },
212
+ 'wire-bends': { raw: bends, score: 1 / (1 + bends / 8) },
213
+ 'wire-length': { raw: totalLen, score: 1 / (1 + totalLen / (4 * diag)) },
214
+ 'label-to-wire-ratio': { raw: labelRatio, score: labelRatio <= 1.5 ? 1 : 1.5 / labelRatio },
215
+ 'group-cohesion': { raw: meanPair, score: pairDists.length ? Math.max(0, 1 - meanPair / diag) : 1 },
216
+ 'flow-direction': { raw: flowViolations, score: crossNets ? 1 - flowViolations / crossNets : 1 },
217
+ utilization: { raw: utilization, score: Math.min(1, utilization / 0.5) },
218
+ 'axis-alignment': { raw: axisAligned, score: axisAligned },
219
+ 'spacing-uniformity': { raw: spacingUniformity, score: spacingUniformity },
220
+ 'straight-wire-ratio': { raw: straightRatio, score: straightRatio },
221
+ 'label-alignment': { raw: horizLabels, score: horizLabels },
222
+ 'whitespace-balance': { raw: centroidOff, score: Math.max(0, 1 - centroidOff) },
223
+ 'pair-symmetry': { raw: pairSymmetry, score: pairSymmetry },
224
+ };
225
+ const totalWeight = Object.values(weights).reduce((a, b) => a + b, 0) || 1;
226
+ const metrics = Object.entries(raw).map(([name, m]) => ({
227
+ name,
228
+ raw: m.raw,
229
+ score: m.score,
230
+ weight: weights[name],
231
+ contribution: (100 * weights[name] * m.score) / totalWeight,
232
+ }));
233
+ let composite = metrics.reduce((a, m) => a + m.contribution, 0);
234
+ let cap = null;
235
+ if (legibility.counts.error > 0) {
236
+ const capValue = Math.min(ERROR_CAP, floor - 1);
237
+ if (composite > capValue) {
238
+ cap = {
239
+ appliedAt: capValue,
240
+ reason: `${legibility.counts.error} error-severity legibility finding(s) cap the composite below the known-good floor (${floor})`,
241
+ };
242
+ composite = capValue;
243
+ }
244
+ }
245
+ return {
246
+ composite: Math.round(composite * 100) / 100,
247
+ metrics,
248
+ cap,
249
+ legibility: legibility.counts,
250
+ };
251
+ }
252
+ export function formatScore(report) {
253
+ const lines = [`score: ${report.composite}/100`];
254
+ if (report.cap)
255
+ lines.push(` cap: ${report.cap.appliedAt} — ${report.cap.reason}`);
256
+ for (const m of report.metrics) {
257
+ lines.push(` ${m.name}: raw ${Math.round(m.raw * 10000) / 10000}, score ${Math.round(m.score * 1000) / 1000}, weight ${m.weight}, contributes ${Math.round(m.contribution * 100) / 100}`);
258
+ }
259
+ return lines.join('\n');
260
+ }
261
+ //# sourceMappingURL=score.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"score.js","sourceRoot":"","sources":["../../src/kicad/score.ts"],"names":[],"mappings":"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"}
@@ -14,7 +14,11 @@ export function parseSexp(text) {
14
14
  let s = '';
15
15
  while (j < text.length && text[j] !== '"') {
16
16
  if (text[j] === '\\' && j + 1 < text.length) {
17
- s += text[j + 1];
17
+ // KiCad writes multi-line text as `\n` (and tabs as `\t`) inside the
18
+ // quoted atom; mapping the escape to the literal letter would give
19
+ // the legibility width model a one-line `line1nline2` string.
20
+ const e = text[j + 1];
21
+ s += e === 'n' ? '\n' : e === 't' ? '\t' : e;
18
22
  j += 2;
19
23
  }
20
24
  else {
@@ -98,7 +102,10 @@ async function loadSheets(rootSch) {
98
102
  await load(rootSch, '/');
99
103
  return out;
100
104
  }
101
- /** Pin definitions per lib symbol name, in symbol coordinates. */
105
+ /** Pin definitions per lib symbol name, in symbol coordinates. Each pin
106
+ * carries the unit of the `_<unit>_<style>` child it was defined in (0 for
107
+ * the common unit); de Morgan alternates (style ≥ 2) are skipped so a pin is
108
+ * recorded once. */
102
109
  function libPinDefs(root) {
103
110
  const map = new Map();
104
111
  const libs = child(root, 'lib_symbols');
@@ -109,9 +116,17 @@ function libPinDefs(root) {
109
116
  if (!name)
110
117
  continue;
111
118
  const pins = [];
112
- const walk = (n) => {
119
+ const walk = (n, unit) => {
113
120
  if (!isList(n))
114
121
  return;
122
+ if (tag(n) === 'symbol') {
123
+ const m = /_(\d+)_(\d+)$/.exec(atomAt(n, 1) ?? '');
124
+ if (m) {
125
+ if (Number(m[2]) >= 2)
126
+ return; // de Morgan alternate body style
127
+ unit = Number(m[1]);
128
+ }
129
+ }
115
130
  if (tag(n) === 'pin') {
116
131
  const at = child(n, 'at');
117
132
  const num = atomAt(child(n, 'number'), 1);
@@ -122,17 +137,26 @@ function libPinDefs(root) {
122
137
  name: pinName ?? '~',
123
138
  x: parseFloat(atomAt(at, 1) ?? '0'),
124
139
  y: parseFloat(atomAt(at, 2) ?? '0'),
140
+ unit,
125
141
  });
126
142
  }
127
143
  }
128
144
  for (const c of n)
129
- walk(c);
145
+ walk(c, unit);
130
146
  };
131
- walk(sym);
147
+ walk(sym, 0);
132
148
  map.set(name, pins);
133
149
  }
134
150
  return map;
135
151
  }
152
+ /** The pins a PLACED instance actually shows: its own unit's plus the common
153
+ * unit's. A single-unit symbol keeps every pin (they are all unit ≤ 1). */
154
+ export function pinsOfUnit(defs, unit) {
155
+ const multi = defs.some((p) => p.unit >= 2);
156
+ if (!multi)
157
+ return defs;
158
+ return defs.filter((p) => p.unit === 0 || p.unit === unit);
159
+ }
136
160
  /** Symbol-space → schematic-space transform (schematic Y grows downward). */
137
161
  export function pinAbsolute(symAt, mirror, pin) {
138
162
  let px = pin.x;
@@ -189,6 +213,7 @@ function symbolsOf(sheet) {
189
213
  rot: parseFloat(atomAt(at, 3) ?? '0'),
190
214
  },
191
215
  uuid: atomAt(child(s, 'uuid'), 1) ?? '',
216
+ unit: parseInt(atomAt(child(s, 'unit'), 1) ?? '1', 10) || 1,
192
217
  },
193
218
  });
194
219
  }
@@ -244,6 +269,211 @@ export async function listNets(rootSch) {
244
269
  }
245
270
  return [...names].sort();
246
271
  }
272
+ const num = (n, idx, fallback = 0) => {
273
+ const v = atomAt(n, idx);
274
+ return v === undefined ? fallback : parseFloat(v);
275
+ };
276
+ function effectsOf(node) {
277
+ const effects = child(node, 'effects');
278
+ const font = effects ? child(effects, 'font') : undefined;
279
+ const size = font ? child(font, 'size') : undefined;
280
+ // hidden: legacy bare `hide` atom, or v9 `(hide yes)`
281
+ const hideNode = effects ? child(effects, 'hide') : undefined;
282
+ const hidden = (effects?.some((c) => c === 'hide') ?? false) || (hideNode !== undefined && atomAt(hideNode, 1) !== 'no');
283
+ return { height: size ? num(size, 1, 1.27) : 1.27, hidden };
284
+ }
285
+ function libBodyBounds(root) {
286
+ const map = new Map();
287
+ const libs = child(root, 'lib_symbols');
288
+ if (!libs)
289
+ return map;
290
+ for (const sym of children(libs, 'symbol')) {
291
+ const name = atomAt(sym, 1);
292
+ if (!name)
293
+ continue;
294
+ /** Union across the whole symbol under `name`, per-unit union (common
295
+ * graphics included) under `name#<unit>` — a placed unit of a multi-unit
296
+ * symbol draws only its own unit's graphics, so measuring it with the
297
+ * package union would size every instance like the whole gate pack. */
298
+ const perUnit = new Map();
299
+ let b = null;
300
+ const grow = (prev, x, y) => {
301
+ if (!prev)
302
+ return { minX: x, minY: y, maxX: x, maxY: y };
303
+ prev.minX = Math.min(prev.minX, x);
304
+ prev.minY = Math.min(prev.minY, y);
305
+ prev.maxX = Math.max(prev.maxX, x);
306
+ prev.maxY = Math.max(prev.maxY, y);
307
+ return prev;
308
+ };
309
+ const walk = (n, unit) => {
310
+ if (!isList(n))
311
+ return;
312
+ const t = tag(n);
313
+ if (t === 'symbol') {
314
+ const m = /_(\d+)_(\d+)$/.exec(atomAt(n, 1) ?? '');
315
+ if (m) {
316
+ if (Number(m[2]) >= 2)
317
+ return; // de Morgan alternate body style
318
+ unit = Number(m[1]);
319
+ }
320
+ }
321
+ const extend = (x, y) => {
322
+ b = grow(b, x, y);
323
+ if (unit !== null)
324
+ perUnit.set(unit, grow(perUnit.get(unit) ?? null, x, y));
325
+ };
326
+ if (t === 'rectangle') {
327
+ const s = child(n, 'start');
328
+ const e = child(n, 'end');
329
+ extend(num(s, 1), num(s, 2));
330
+ extend(num(e, 1), num(e, 2));
331
+ }
332
+ else if (t === 'circle') {
333
+ const c = child(n, 'center');
334
+ const r = num(child(n, 'radius'), 1);
335
+ extend(num(c, 1) - r, num(c, 2) - r);
336
+ extend(num(c, 1) + r, num(c, 2) + r);
337
+ }
338
+ else if (t === 'arc') {
339
+ for (const part of ['start', 'mid', 'end']) {
340
+ const p = child(n, part);
341
+ if (p)
342
+ extend(num(p, 1), num(p, 2));
343
+ }
344
+ }
345
+ else if (t === 'polyline') {
346
+ for (const xy of children(child(n, 'pts') ?? [], 'xy'))
347
+ extend(num(xy, 1), num(xy, 2));
348
+ }
349
+ // pin/text graphics are deliberately excluded from the body box (design C2)
350
+ if (t !== 'pin' && t !== 'text')
351
+ for (const c of n)
352
+ walk(c, unit);
353
+ };
354
+ walk(sym, null);
355
+ map.set(name, b);
356
+ const common = perUnit.get(0) ?? null;
357
+ for (const [unit, ub] of perUnit) {
358
+ if (unit === 0)
359
+ continue;
360
+ const merged = ub && common
361
+ ? {
362
+ minX: Math.min(ub.minX, common.minX),
363
+ minY: Math.min(ub.minY, common.minY),
364
+ maxX: Math.max(ub.maxX, common.maxX),
365
+ maxY: Math.max(ub.maxY, common.maxY),
366
+ }
367
+ : (ub ?? (common ? { ...common } : null));
368
+ map.set(`${name}#${unit}`, merged);
369
+ }
370
+ }
371
+ return map;
372
+ }
373
+ function textItemsOf(sym) {
374
+ const out = [];
375
+ for (const p of children(sym, 'property')) {
376
+ const key = atomAt(p, 1);
377
+ if (key !== 'Reference' && key !== 'Value')
378
+ continue;
379
+ const at = child(p, 'at');
380
+ const fx = effectsOf(p);
381
+ out.push({
382
+ text: atomAt(p, 2) ?? '',
383
+ x: num(at, 1),
384
+ y: num(at, 2),
385
+ rot: num(at, 3),
386
+ height: fx.height,
387
+ hidden: fx.hidden,
388
+ });
389
+ }
390
+ return out;
391
+ }
392
+ /**
393
+ * Everything the legibility checker needs to see per sheet, extracted read-only.
394
+ * Never serializes and never mutates the file.
395
+ */
396
+ export async function readSheetGeometry(rootSch) {
397
+ const sheets = await loadSheets(rootSch);
398
+ const powerSyms = collectPowerSymbols(sheets);
399
+ return sheets.map((sheet) => {
400
+ const paperNode = child(sheet.root, 'paper');
401
+ const paperName = atomAt(paperNode, 1) ?? null;
402
+ const portrait = paperNode?.includes('portrait') ?? false;
403
+ const explicitW = num(paperNode, 2, NaN);
404
+ const explicitH = num(paperNode, 3, NaN);
405
+ const tb = child(sheet.root, 'title_block');
406
+ const tbField = (name) => (tb ? (atomAt(child(tb, name), 1) ?? '') : '');
407
+ const wires = [];
408
+ for (const w of children(sheet.root, 'wire')) {
409
+ const pts = children(child(w, 'pts') ?? [], 'xy');
410
+ for (let i = 1; i < pts.length; i++) {
411
+ wires.push({ x1: num(pts[i - 1], 1), y1: num(pts[i - 1], 2), x2: num(pts[i], 1), y2: num(pts[i], 2) });
412
+ }
413
+ }
414
+ const labels = [];
415
+ for (const kind of ['label', 'global_label', 'hierarchical_label']) {
416
+ for (const l of children(sheet.root, kind)) {
417
+ const at = child(l, 'at');
418
+ const effects = child(l, 'effects');
419
+ const justify = effects ? child(effects, 'justify') : undefined;
420
+ labels.push({
421
+ name: atomAt(l, 1) ?? '',
422
+ kind,
423
+ x: num(at, 1),
424
+ y: num(at, 2),
425
+ rot: num(at, 3),
426
+ height: effectsOf(l).height,
427
+ justify: justify?.some((c) => c === 'right') ? 'right' : justify?.some((c) => c === 'left') ? 'left' : null,
428
+ });
429
+ }
430
+ }
431
+ const texts = children(sheet.root, 'text').map((t) => {
432
+ const at = child(t, 'at');
433
+ const fx = effectsOf(t);
434
+ return { text: atomAt(t, 1) ?? '', x: num(at, 1), y: num(at, 2), rot: num(at, 3), height: fx.height, hidden: fx.hidden };
435
+ });
436
+ const rectangles = children(sheet.root, 'rectangle').map((r) => {
437
+ const s = child(r, 'start');
438
+ const e = child(r, 'end');
439
+ const stroke = child(r, 'stroke');
440
+ return {
441
+ x1: num(s, 1),
442
+ y1: num(s, 2),
443
+ x2: num(e, 1),
444
+ y2: num(e, 2),
445
+ strokeType: atomAt(child(stroke ?? [], 'type'), 1) ?? 'default',
446
+ };
447
+ });
448
+ return {
449
+ filePath: sheet.filePath,
450
+ sheetName: sheet.sheetName,
451
+ paper: {
452
+ name: paperName,
453
+ width: Number.isNaN(explicitW) ? null : explicitW,
454
+ height: Number.isNaN(explicitH) ? null : explicitH,
455
+ portrait,
456
+ },
457
+ titleBlock: tb ? { title: tbField('title'), date: tbField('date'), rev: tbField('rev') } : null,
458
+ symbols: symbolsOf(sheet).map(({ sym, mirror, node }) => ({
459
+ ref: sym.ref,
460
+ libId: sym.libId,
461
+ value: sym.value,
462
+ at: sym.at,
463
+ mirror,
464
+ isPower: isPowerSymbol(sym.libId, powerSyms),
465
+ unit: sym.unit,
466
+ props: textItemsOf(node),
467
+ })),
468
+ wires,
469
+ labels,
470
+ texts,
471
+ rectangles,
472
+ libBounds: libBodyBounds(sheet.root),
473
+ libPins: libPinDefs(sheet.root),
474
+ };
475
+ });
476
+ }
247
477
  /**
248
478
  * Geometric connectivity per sheet: pins, labels, and wire endpoints that share
249
479
  * coordinates (or are joined by wires) form a group; a group's net name comes
@@ -280,7 +510,10 @@ export async function pinNets(rootSch) {
280
510
  }
281
511
  const symPins = [];
282
512
  for (const { sym, mirror } of symbolsOf(sheet)) {
283
- const defs = pinDefs.get(sym.libId) ?? [];
513
+ // a placed unit of a multi-unit symbol shows only its own unit's pins;
514
+ // resolving the whole package at each instance would invent phantom
515
+ // connection points at every other unit's coordinates
516
+ const defs = pinsOfUnit(pinDefs.get(sym.libId) ?? [], sym.unit);
284
517
  for (const pin of defs) {
285
518
  const abs = pinAbsolute(sym.at, mirror, pin);
286
519
  const k = key(abs.x, abs.y);