copperhead 0.5.0 → 0.7.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 (74) hide show
  1. package/README.md +34 -1
  2. package/dist/agent/loop.js +130 -15
  3. package/dist/agent/loop.js.map +1 -1
  4. package/dist/agent/prompts.js +2 -1
  5. package/dist/agent/prompts.js.map +1 -1
  6. package/dist/agent/providers/claude-code.js +466 -0
  7. package/dist/agent/providers/claude-code.js.map +1 -0
  8. package/dist/agent/providers/openai.js +30 -10
  9. package/dist/agent/providers/openai.js.map +1 -1
  10. package/dist/agent/recovery.js +148 -0
  11. package/dist/agent/recovery.js.map +1 -0
  12. package/dist/agent/render.js +17 -2
  13. package/dist/agent/render.js.map +1 -1
  14. package/dist/agent/response-cache.js +81 -0
  15. package/dist/agent/response-cache.js.map +1 -0
  16. package/dist/agent/tools.js +61 -4
  17. package/dist/agent/tools.js.map +1 -1
  18. package/dist/agent/transcript.js.map +1 -1
  19. package/dist/cli.js +47 -2
  20. package/dist/cli.js.map +1 -1
  21. package/dist/commands/create.js +486 -35
  22. package/dist/commands/create.js.map +1 -1
  23. package/dist/commands/export.js +90 -0
  24. package/dist/commands/export.js.map +1 -0
  25. package/dist/config.js +33 -6
  26. package/dist/config.js.map +1 -1
  27. package/dist/kicad/bom-export.js +240 -0
  28. package/dist/kicad/bom-export.js.map +1 -0
  29. package/dist/kicad/bootstrap.js +166 -0
  30. package/dist/kicad/bootstrap.js.map +1 -0
  31. package/dist/kicad/fab.js +94 -0
  32. package/dist/kicad/fab.js.map +1 -0
  33. package/dist/kicad/spice.js +306 -0
  34. package/dist/kicad/spice.js.map +1 -0
  35. package/dist/kicad/symlib.js +228 -0
  36. package/dist/kicad/symlib.js.map +1 -0
  37. package/dist/memory/bom-table.js +232 -0
  38. package/dist/memory/bom-table.js.map +1 -0
  39. package/dist/memory/drift.js +33 -27
  40. package/dist/memory/drift.js.map +1 -1
  41. package/dist/util/git.js +37 -1
  42. package/dist/util/git.js.map +1 -1
  43. package/dist/util/preflight.js +37 -0
  44. package/dist/util/preflight.js.map +1 -1
  45. package/dist/util/retry.js +23 -0
  46. package/dist/util/retry.js.map +1 -1
  47. package/dist/util/tmp.js +119 -0
  48. package/dist/util/tmp.js.map +1 -0
  49. package/package.json +6 -2
  50. package/src/agent/loop.ts +148 -15
  51. package/src/agent/prompts.ts +2 -1
  52. package/src/agent/providers/claude-code.ts +550 -0
  53. package/src/agent/providers/openai.ts +33 -16
  54. package/src/agent/recovery.ts +162 -0
  55. package/src/agent/render.ts +28 -1
  56. package/src/agent/response-cache.ts +80 -0
  57. package/src/agent/tools.ts +62 -4
  58. package/src/agent/transcript.ts +1 -0
  59. package/src/agent/types.ts +18 -0
  60. package/src/cli.ts +52 -2
  61. package/src/commands/create.ts +543 -38
  62. package/src/commands/export.ts +117 -0
  63. package/src/config.ts +54 -6
  64. package/src/kicad/bom-export.ts +321 -0
  65. package/src/kicad/bootstrap.ts +181 -0
  66. package/src/kicad/fab.ts +121 -0
  67. package/src/kicad/spice.ts +399 -0
  68. package/src/kicad/symlib.ts +248 -0
  69. package/src/memory/bom-table.ts +249 -0
  70. package/src/memory/drift.ts +42 -32
  71. package/src/util/git.ts +37 -1
  72. package/src/util/preflight.ts +44 -0
  73. package/src/util/retry.ts +29 -0
  74. package/src/util/tmp.ts +113 -0
@@ -0,0 +1,166 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { writeFile } from 'node:fs/promises';
3
+ import { createHash } from 'node:crypto';
4
+ import path from 'node:path';
5
+ import { configPath, loadConfig } from '../config.js';
6
+ /**
7
+ * The create pipeline starts from a brief with no KiCad files, but the agent
8
+ * cannot create them: `write_file` refuses KiCad files and `edit_file` only
9
+ * edits existing ones. Without a project on disk the schematic stage can never
10
+ * satisfy its contract (config.schematic stays null), so the pipeline stalls
11
+ * indefinitely. This module scaffolds a minimal, kicad-cli-loadable empty
12
+ * project (schematic ERC-clean, board DRC-clean with a default outline) and
13
+ * wires it into .copperhead/config.json, giving the agent a file to populate.
14
+ */
15
+ /** Slug for the project filename, taken from the brief's first H1 (a leading
16
+ * "Brief:" label is dropped). Falls back to "board". */
17
+ export function projectSlug(brief) {
18
+ const m = brief.match(/^#\s+(.+?)\s*$/m);
19
+ const title = (m?.[1] ?? 'board').replace(/^brief\s*:\s*/i, '');
20
+ const slug = title
21
+ .toLowerCase()
22
+ .replace(/[^a-z0-9]+/g, '-')
23
+ .replace(/^-+|-+$/g, '');
24
+ return slug || 'board';
25
+ }
26
+ /** A stable, valid-shaped v4 UUID derived from a seed, so a given project
27
+ * bootstraps to the same UUIDs on every run (no Date/random — runs stay
28
+ * reproducible). */
29
+ function uuidFrom(seed) {
30
+ const h = createHash('sha256').update(seed).digest('hex');
31
+ return `${h.slice(0, 8)}-${h.slice(8, 12)}-4${h.slice(13, 16)}-8${h.slice(17, 20)}-${h.slice(20, 32)}`;
32
+ }
33
+ function emptySchematic(rootUuid) {
34
+ return `(kicad_sch
35
+ (version 20231120)
36
+ (generator "eeschema")
37
+ (generator_version "8.0")
38
+ (uuid "${rootUuid}")
39
+ (paper "A4")
40
+ (lib_symbols)
41
+ (sheet_instances
42
+ (path "/" (page "1"))
43
+ )
44
+ )
45
+ `;
46
+ }
47
+ function emptyBoard(outlineUuid) {
48
+ // A default 30x20mm outline on Edge.Cuts so the blank board is DRC-clean out
49
+ // of the gate; the layout stage resizes/replaces it with the real outline.
50
+ return `(kicad_pcb
51
+ (version 20240108)
52
+ (generator "pcbnew")
53
+ (generator_version "8.0")
54
+ (general
55
+ (thickness 1.6)
56
+ (legacy_teardrops no)
57
+ )
58
+ (paper "A4")
59
+ (layers
60
+ (0 "F.Cu" signal)
61
+ (31 "B.Cu" signal)
62
+ (32 "B.Adhes" user "B.Adhesive")
63
+ (33 "F.Adhes" user "F.Adhesive")
64
+ (34 "B.Paste" user)
65
+ (35 "F.Paste" user)
66
+ (36 "B.SilkS" user "B.Silkscreen")
67
+ (37 "F.SilkS" user "F.Silkscreen")
68
+ (38 "B.Mask" user)
69
+ (39 "F.Mask" user)
70
+ (40 "Dwgs.User" user "User.Drawings")
71
+ (41 "Cmts.User" user "User.Comments")
72
+ (42 "Eco1.User" user "User.Eco1")
73
+ (43 "Eco2.User" user "User.Eco2")
74
+ (44 "Edge.Cuts" user)
75
+ (45 "Margin" user)
76
+ (46 "B.CrtYd" user "B.Courtyard")
77
+ (47 "F.CrtYd" user "F.Courtyard")
78
+ (48 "B.Fab" user)
79
+ (49 "F.Fab" user)
80
+ )
81
+ (setup
82
+ (pad_to_mask_clearance 0)
83
+ (allow_soldermask_bridges_in_footprints no)
84
+ )
85
+ (net 0 "")
86
+ (gr_rect (start 100 100) (end 130 120)
87
+ (stroke (width 0.1) (type default))
88
+ (layer "Edge.Cuts")
89
+ (uuid "${outlineUuid}")
90
+ )
91
+ )
92
+ `;
93
+ }
94
+ function projectFile(slug, rootUuid) {
95
+ return (JSON.stringify({
96
+ board: { design_settings: { defaults: {}, rules: {} } },
97
+ erc: {
98
+ erc_exclusions: [],
99
+ meta: { version: 0 },
100
+ rule_severities: { footprint_link_issues: 'ignore', lib_symbol_issues: 'ignore' },
101
+ },
102
+ meta: { filename: `${slug}.kicad_pro`, version: 1 },
103
+ net_settings: {
104
+ classes: [
105
+ {
106
+ bus_width: 12,
107
+ clearance: 0.2,
108
+ diff_pair_gap: 0.25,
109
+ diff_pair_via_gap: 0.25,
110
+ diff_pair_width: 0.2,
111
+ line_style: 0,
112
+ microvia_diameter: 0.3,
113
+ microvia_drill: 0.1,
114
+ name: 'Default',
115
+ pcb_color: 'rgba(0, 0, 0, 0.000)',
116
+ schematic_color: 'rgba(0, 0, 0, 0.000)',
117
+ track_width: 0.25,
118
+ via_diameter: 0.6,
119
+ via_drill: 0.3,
120
+ wire_width: 6,
121
+ },
122
+ ],
123
+ meta: { version: 3 },
124
+ },
125
+ schematic: {
126
+ annotate_start_num: 0,
127
+ drawing: { default_line_thickness: 6.0, default_text_size: 50.0 },
128
+ legacy_lib_dir: '',
129
+ legacy_lib_list: [],
130
+ meta: { version: 1 },
131
+ },
132
+ sheets: [[rootUuid, 'Root']],
133
+ text_variables: {},
134
+ }, null, 2) + '\n');
135
+ }
136
+ async function persist(repoRoot, config) {
137
+ await writeFile(configPath(repoRoot), JSON.stringify(config, null, 2) + '\n', 'utf8');
138
+ }
139
+ /**
140
+ * Ensure a KiCad project exists and is wired into config. No-op (returns null)
141
+ * when config already points at a schematic on disk. If project files exist but
142
+ * config doesn't reference them, just wires config. Otherwise scaffolds an empty
143
+ * project. Returns the schematic's repo-relative path when it created or wired
144
+ * one, else null.
145
+ */
146
+ export async function bootstrapKicadProject(repoRoot, brief) {
147
+ const config = await loadConfig(repoRoot);
148
+ if (config.schematic && existsSync(path.join(repoRoot, config.schematic)))
149
+ return null;
150
+ const slug = projectSlug(brief);
151
+ const schRel = `${slug}.kicad_sch`;
152
+ const pcbRel = `${slug}.kicad_pcb`;
153
+ const proRel = `${slug}.kicad_pro`;
154
+ const schAbs = path.join(repoRoot, schRel);
155
+ if (!existsSync(schAbs)) {
156
+ const rootUuid = uuidFrom(slug);
157
+ await writeFile(schAbs, emptySchematic(rootUuid), 'utf8');
158
+ await writeFile(path.join(repoRoot, pcbRel), emptyBoard(uuidFrom(`${slug}:edge`)), 'utf8');
159
+ await writeFile(path.join(repoRoot, proRel), projectFile(slug, rootUuid), 'utf8');
160
+ }
161
+ config.schematic = schRel;
162
+ config.board = existsSync(path.join(repoRoot, pcbRel)) ? pcbRel : null;
163
+ await persist(repoRoot, config);
164
+ return schRel;
165
+ }
166
+ //# sourceMappingURL=bootstrap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../../src/kicad/bootstrap.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Fab release gate checks (OpenSpec: add-fab-release-gate).
3
+ * Documentation presence is pure over file contents: LLM-free, network-free.
4
+ */
5
+ export const DRAFT_QUALITY_HEADING = '## Draft quality';
6
+ /** Config marker: repos produced by `copperhead create` set `origin` to `"create"`. */
7
+ export const CREATE_ORIGIN = 'create';
8
+ /**
9
+ * True when `.copperhead/config.json` marks the repo as create-produced.
10
+ * Accepts the raw parsed object (or a loaded config that retained `origin`).
11
+ */
12
+ export function isCreateProducedRepo(config) {
13
+ if (config === null || typeof config !== 'object')
14
+ return false;
15
+ return config.origin === CREATE_ORIGIN;
16
+ }
17
+ /**
18
+ * Body of `## Draft quality` through the next `##` heading, or `null` if the
19
+ * heading is absent. HTML comments and whitespace alone do not count as filled
20
+ * (init scaffolds the empty heading + a placeholder comment).
21
+ */
22
+ export function draftQualitySection(layoutMd) {
23
+ const lines = layoutMd.split(/\r?\n/);
24
+ let start = -1;
25
+ for (let i = 0; i < lines.length; i++) {
26
+ if (lines[i].trim() === DRAFT_QUALITY_HEADING) {
27
+ start = i + 1;
28
+ break;
29
+ }
30
+ }
31
+ if (start < 0)
32
+ return null;
33
+ const body = [];
34
+ for (let i = start; i < lines.length; i++) {
35
+ const line = lines[i];
36
+ if (/^##\s/.test(line.trim()))
37
+ break;
38
+ body.push(line);
39
+ }
40
+ return body.join('\n');
41
+ }
42
+ export function isFilledDraftQuality(sectionBody) {
43
+ const withoutComments = sectionBody.replace(/<!--[\s\S]*?-->/g, '');
44
+ return withoutComments.trim().length > 0;
45
+ }
46
+ /**
47
+ * Documentation-presence check for `check --fab` (task 1.5):
48
+ * - LAYOUT.md must have a filled `## Draft quality` section
49
+ * - create-produced repos must also have DEVPLAN.md
50
+ *
51
+ * Failures use the drift-report voice: file as location, claim `"release-ready"`.
52
+ */
53
+ export function checkDocumentationPresence(input) {
54
+ const docs = (input.docsDir ?? 'docs').replace(/[/\\]+$/, '');
55
+ const violations = [];
56
+ const layoutLoc = `${docs}/LAYOUT.md`;
57
+ const claim = 'release-ready';
58
+ if (input.layoutMd === null) {
59
+ violations.push({
60
+ claim,
61
+ actual: 'LAYOUT.md missing',
62
+ location: layoutLoc,
63
+ });
64
+ }
65
+ else {
66
+ const section = draftQualitySection(input.layoutMd);
67
+ if (section === null) {
68
+ violations.push({
69
+ claim,
70
+ actual: `missing ${DRAFT_QUALITY_HEADING} section`,
71
+ location: layoutLoc,
72
+ });
73
+ }
74
+ else if (!isFilledDraftQuality(section)) {
75
+ violations.push({
76
+ claim,
77
+ actual: `${DRAFT_QUALITY_HEADING} section is empty`,
78
+ location: layoutLoc,
79
+ });
80
+ }
81
+ }
82
+ if (input.isCreateRepo && !input.devplanExists) {
83
+ violations.push({
84
+ claim,
85
+ actual: 'missing',
86
+ location: `${docs}/DEVPLAN.md`,
87
+ });
88
+ }
89
+ return {
90
+ status: violations.length === 0 ? 'pass' : 'fail',
91
+ violations,
92
+ };
93
+ }
94
+ //# sourceMappingURL=fab.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fab.js","sourceRoot":"","sources":["../../src/kicad/fab.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,306 @@
1
+ /**
2
+ * Parser and assertion compiler for the opt-in SPICE verification gate.
3
+ *
4
+ * This module is deliberately pure: it reads strings and produces data or
5
+ * ngspice deck fragments. Process execution belongs to the wrapper in task 1.1.
6
+ */
7
+ export class SimulationParseError extends Error {
8
+ line;
9
+ constructor(line, message) {
10
+ super(`line ${line}: ${message}`);
11
+ this.name = 'SimulationParseError';
12
+ this.line = line;
13
+ }
14
+ }
15
+ const ANALYSES = new Set(['op', 'dc', 'ac', 'tran']);
16
+ const SAFE_TARGET = /^[A-Za-z0-9_./:+-]+$/;
17
+ const SAFE_MEASURE_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
18
+ const SI_MULTIPLIERS = {
19
+ '': 1,
20
+ t: 1e12,
21
+ g: 1e9,
22
+ meg: 1e6,
23
+ k: 1e3,
24
+ m: 1e-3,
25
+ u: 1e-6,
26
+ n: 1e-9,
27
+ p: 1e-12,
28
+ f: 1e-15,
29
+ };
30
+ /** Parse a SPICE-style number while preserving the original safe literal. */
31
+ export function parseSpiceNumber(raw, line = 1) {
32
+ const token = raw.trim();
33
+ const match = /^([+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?)(meg|[tgkmunpf])?([a-z]*)$/i.exec(token);
34
+ if (!match) {
35
+ throw new SimulationParseError(line, `invalid SPICE number "${raw}"`);
36
+ }
37
+ const base = Number(match[1]);
38
+ const suffix = (match[2] ?? '').toLowerCase();
39
+ // The regex limits suffixes to keys in SI_MULTIPLIERS.
40
+ const multiplier = SI_MULTIPLIERS[suffix];
41
+ const value = base * multiplier;
42
+ if (!Number.isFinite(value)) {
43
+ throw new SimulationParseError(line, `SPICE number is out of range "${raw}"`);
44
+ }
45
+ return {
46
+ raw: token,
47
+ value,
48
+ unit: match[3] ?? '',
49
+ };
50
+ }
51
+ /** Parse one assertion from the closed grammar in the SPICE delta spec. */
52
+ export function parseSpiceAssertion(raw, line = 1) {
53
+ const text = raw.trim();
54
+ const measurableMatch = /^(V|I|corner)\(([^()\s]+)\)\s+(.+)$/i.exec(text);
55
+ if (!measurableMatch) {
56
+ throw new SimulationParseError(line, `invalid SPICE assertion "${raw}"`);
57
+ }
58
+ const target = measurableMatch[2];
59
+ if (!SAFE_TARGET.test(target)) {
60
+ throw new SimulationParseError(line, `invalid measurable target "${target}"`);
61
+ }
62
+ const measurableToken = measurableMatch[1].toLowerCase();
63
+ const measurable = measurableToken === 'v'
64
+ ? { kind: 'voltage', target }
65
+ : measurableToken === 'i'
66
+ ? { kind: 'current', target }
67
+ : { kind: 'corner', target };
68
+ const comparatorText = measurableMatch[3].trim();
69
+ const betweenMatch = /^between\s+(\S+)\s+and\s+(\S+)$/i.exec(comparatorText);
70
+ let comparator;
71
+ if (betweenMatch) {
72
+ const lower = parseSpiceNumber(betweenMatch[1], line);
73
+ const upper = parseSpiceNumber(betweenMatch[2], line);
74
+ if (lower.unit.toLowerCase() !== upper.unit.toLowerCase()) {
75
+ throw new SimulationParseError(line, 'between bounds use different units');
76
+ }
77
+ if (lower.value >= upper.value) {
78
+ throw new SimulationParseError(line, 'between lower bound must be less than upper bound');
79
+ }
80
+ comparator = { kind: 'between', lower, upper };
81
+ }
82
+ else {
83
+ const singleMatch = /^([<>])\s*(\S+)$/.exec(comparatorText);
84
+ if (!singleMatch) {
85
+ throw new SimulationParseError(line, `invalid comparator "${comparatorText}"`);
86
+ }
87
+ const bound = parseSpiceNumber(singleMatch[2], line);
88
+ comparator =
89
+ singleMatch[1] === '<'
90
+ ? { kind: 'less-than', bound }
91
+ : { kind: 'greater-than', bound };
92
+ }
93
+ return { raw: text, line, measurable, comparator };
94
+ }
95
+ /**
96
+ * Parse every `## Simulation` section from SUBSYSTEMS.md.
97
+ *
98
+ * Fields are line-oriented so errors can always identify the source line.
99
+ */
100
+ export function parseSimulationBlocks(markdown) {
101
+ const lines = markdown.split(/\r?\n/);
102
+ const blocks = [];
103
+ let openFence = null;
104
+ let inDocumentComment = false;
105
+ for (let index = 0; index < lines.length; index++) {
106
+ const line = lines[index].trim();
107
+ const fence = markdownFence(line);
108
+ if (openFence) {
109
+ if (fence)
110
+ openFence = toggleFence(openFence, fence);
111
+ continue;
112
+ }
113
+ if (inDocumentComment) {
114
+ if (line.includes('-->'))
115
+ inDocumentComment = false;
116
+ continue;
117
+ }
118
+ if (fence) {
119
+ openFence = fence;
120
+ continue;
121
+ }
122
+ if (line.startsWith('<!--')) {
123
+ if (!line.includes('-->'))
124
+ inDocumentComment = true;
125
+ continue;
126
+ }
127
+ if (!/^##\s+Simulation\s*$/i.test(line))
128
+ continue;
129
+ const headingLine = index + 1;
130
+ const body = [];
131
+ let cursor = index + 1;
132
+ let inComment = false;
133
+ let bodyFence = null;
134
+ for (; cursor < lines.length; cursor++) {
135
+ const text = lines[cursor];
136
+ const trimmed = text.trim();
137
+ const bodyFenceMarker = markdownFence(trimmed);
138
+ if (bodyFence) {
139
+ if (bodyFenceMarker)
140
+ bodyFence = toggleFence(bodyFence, bodyFenceMarker);
141
+ continue;
142
+ }
143
+ if (inComment) {
144
+ if (trimmed.includes('-->'))
145
+ inComment = false;
146
+ continue;
147
+ }
148
+ if (bodyFenceMarker) {
149
+ bodyFence = bodyFenceMarker;
150
+ continue;
151
+ }
152
+ if (/^#{1,6}\s+/.test(trimmed))
153
+ break;
154
+ if (trimmed.startsWith('<!--')) {
155
+ if (!trimmed.includes('-->'))
156
+ inComment = true;
157
+ continue;
158
+ }
159
+ if (trimmed.startsWith('.') || /^[A-Za-z]+\s*:/.test(trimmed)) {
160
+ body.push({ text: trimmed, line: cursor + 1 });
161
+ }
162
+ }
163
+ blocks.push(parseSimulationBlock(body, headingLine));
164
+ index = cursor - 1;
165
+ }
166
+ return blocks;
167
+ }
168
+ function markdownFence(line) {
169
+ return /^(`{3,}|~{3,})/.exec(line)?.[1] ?? null;
170
+ }
171
+ function toggleFence(openFence, marker) {
172
+ if (!openFence)
173
+ return marker;
174
+ if (marker[0] === openFence[0] && marker.length >= openFence.length)
175
+ return null;
176
+ return openFence;
177
+ }
178
+ function parseSimulationBlock(body, headingLine) {
179
+ let scope;
180
+ let analysis;
181
+ const sources = [];
182
+ const assertions = [];
183
+ for (const entry of body) {
184
+ if (entry.text.startsWith('.')) {
185
+ throw new SimulationParseError(entry.line, `raw ngspice statement "${entry.text.split(/\s/, 1)[0]}" is not allowed`);
186
+ }
187
+ const fieldMatch = /^([A-Za-z]+)\s*:\s*(.+)$/.exec(entry.text);
188
+ if (!fieldMatch) {
189
+ throw new SimulationParseError(entry.line, `expected "field: value", got "${entry.text}"`);
190
+ }
191
+ const field = fieldMatch[1].toLowerCase();
192
+ const value = fieldMatch[2].trim();
193
+ switch (field) {
194
+ case 'scope':
195
+ if (scope)
196
+ throw new SimulationParseError(entry.line, 'duplicate scope');
197
+ scope = parseScope(value, entry.line);
198
+ break;
199
+ case 'analysis': {
200
+ if (analysis)
201
+ throw new SimulationParseError(entry.line, 'duplicate analysis');
202
+ const candidate = value.toLowerCase();
203
+ if (!ANALYSES.has(candidate)) {
204
+ throw new SimulationParseError(entry.line, `unsupported analysis "${value}"`);
205
+ }
206
+ analysis = candidate;
207
+ break;
208
+ }
209
+ case 'source':
210
+ case 'sources':
211
+ sources.push(parseSource(value, entry.line));
212
+ break;
213
+ case 'assert':
214
+ assertions.push(parseSpiceAssertion(value, entry.line));
215
+ break;
216
+ default:
217
+ throw new SimulationParseError(entry.line, `unknown Simulation field "${field}"`);
218
+ }
219
+ }
220
+ if (!scope)
221
+ throw new SimulationParseError(headingLine, 'Simulation block is missing scope');
222
+ if (!analysis)
223
+ throw new SimulationParseError(headingLine, 'Simulation block is missing analysis');
224
+ if (assertions.length === 0) {
225
+ throw new SimulationParseError(headingLine, 'Simulation block needs at least one assertion');
226
+ }
227
+ return { line: headingLine, scope, analysis, sources, assertions };
228
+ }
229
+ function parseScope(raw, line) {
230
+ const match = /^(sheet|nets)(?:\s+(.*))?$/i.exec(raw);
231
+ if (!match) {
232
+ throw new SimulationParseError(line, 'scope must be "sheet <path>" or "nets <a>, <b>"');
233
+ }
234
+ const scopeValue = (match[2] ?? '').trim();
235
+ if (match[1].toLowerCase() === 'sheet') {
236
+ if (scopeValue.length === 0) {
237
+ throw new SimulationParseError(line, 'sheet scope is empty');
238
+ }
239
+ return { kind: 'sheet', sheet: scopeValue };
240
+ }
241
+ const netList = scopeValue.replace(/^\[(.*)\]$/, '$1');
242
+ const nets = netList
243
+ .split(',')
244
+ .map((net) => net.trim())
245
+ .filter((net) => net.length > 0);
246
+ if (nets.length === 0 || nets.some((net) => !SAFE_TARGET.test(net))) {
247
+ throw new SimulationParseError(line, 'net scope must contain comma-separated net names');
248
+ }
249
+ return { kind: 'nets', nets: [...new Set(nets)] };
250
+ }
251
+ function parseSource(raw, line) {
252
+ const match = /^([A-Za-z_][A-Za-z0-9_./:+-]*)\s*=\s*(\S+)$/.exec(raw);
253
+ if (!match) {
254
+ throw new SimulationParseError(line, 'source must be "<port>=<number>"');
255
+ }
256
+ return {
257
+ port: match[1],
258
+ value: parseSpiceNumber(match[2], line),
259
+ line,
260
+ };
261
+ }
262
+ /**
263
+ * Compile a parsed assertion to one value measure and one or two margin
264
+ * measures. Inclusive bounds pass at zero; strict bounds must be positive.
265
+ */
266
+ export function compileSpiceAssertion(assertion, analysis, name = `assertion_${assertion.line}`) {
267
+ if (!SAFE_MEASURE_NAME.test(name)) {
268
+ throw new SimulationParseError(assertion.line, `invalid measure name "${name}"`);
269
+ }
270
+ let valueLine;
271
+ if (assertion.measurable.kind === 'corner') {
272
+ if (analysis !== 'ac') {
273
+ throw new SimulationParseError(assertion.line, 'corner() requires an ac analysis');
274
+ }
275
+ valueLine = `.meas ac ${name}_value WHEN vdb(${assertion.measurable.target})=-3 FALL=1`;
276
+ }
277
+ else {
278
+ const expression = assertion.measurable.kind === 'voltage'
279
+ ? `v(${assertion.measurable.target})`
280
+ : `i(${assertion.measurable.target})`;
281
+ const operation = analysis === 'op' ? 'FIND' : 'AVG';
282
+ valueLine = `.meas ${analysis} ${name}_value ${operation} ${expression}`;
283
+ }
284
+ const valueName = `${name}_value`;
285
+ const marginExpressions = assertion.comparator.kind === 'between'
286
+ ? [
287
+ [`${name}_lower_margin`, `${valueName} - ${assertion.comparator.lower.raw}`],
288
+ [`${name}_upper_margin`, `${assertion.comparator.upper.raw} - ${valueName}`],
289
+ ]
290
+ : assertion.comparator.kind === 'less-than'
291
+ ? [[`${name}_margin`, `${assertion.comparator.bound.raw} - ${valueName}`]]
292
+ : [[`${name}_margin`, `${valueName} - ${assertion.comparator.bound.raw}`]];
293
+ const checks = marginExpressions.map(([checkName]) => ({
294
+ name: checkName,
295
+ pass: assertion.comparator.kind === 'between' ? 'nonnegative' : 'positive',
296
+ }));
297
+ const checkLines = marginExpressions.map(([checkName, expression]) => `.meas ${analysis} ${checkName} PARAM='${expression}'`);
298
+ const compiledLines = [valueLine, ...checkLines];
299
+ return {
300
+ valueName,
301
+ checks,
302
+ lines: compiledLines,
303
+ deck: compiledLines.join('\n'),
304
+ };
305
+ }
306
+ //# sourceMappingURL=spice.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spice.js","sourceRoot":"","sources":["../../src/kicad/spice.ts"],"names":[],"mappings":"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"}