copperhead 0.10.0 → 0.11.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.
- package/README.md +41 -2
- package/dist/agent/context.js +2 -0
- package/dist/agent/context.js.map +1 -0
- package/dist/agent/dock-renderer.js +2 -2
- package/dist/agent/dock-renderer.js.map +1 -1
- package/dist/agent/envelope.js +105 -0
- package/dist/agent/envelope.js.map +1 -0
- package/dist/agent/loop.js +34 -14
- package/dist/agent/loop.js.map +1 -1
- package/dist/agent/providers/claude-code.js +17 -1
- package/dist/agent/providers/claude-code.js.map +1 -1
- package/dist/agent/providers/codex.js +84 -39
- package/dist/agent/providers/codex.js.map +1 -1
- package/dist/agent/recovery.js +91 -14
- package/dist/agent/recovery.js.map +1 -1
- package/dist/agent/registry.js +49 -0
- package/dist/agent/registry.js.map +1 -0
- package/dist/agent/render.js +2 -2
- package/dist/agent/render.js.map +1 -1
- package/dist/agent/theme.js +10 -5
- package/dist/agent/theme.js.map +1 -1
- package/dist/agent/tools.js +99 -769
- package/dist/agent/tools.js.map +1 -1
- package/dist/capabilities/define.js +35 -0
- package/dist/capabilities/define.js.map +1 -0
- package/dist/capabilities/handlers.js +744 -0
- package/dist/capabilities/handlers.js.map +1 -0
- package/dist/capabilities/helpers.js +39 -0
- package/dist/capabilities/helpers.js.map +1 -0
- package/dist/capabilities/index.js +50 -0
- package/dist/capabilities/index.js.map +1 -0
- package/dist/capabilities/skills/generate-report.js +23 -0
- package/dist/capabilities/skills/generate-report.js.map +1 -0
- package/dist/cli.js +84 -1
- package/dist/cli.js.map +1 -1
- package/dist/commands/create.js +5 -2
- package/dist/commands/create.js.map +1 -1
- package/dist/commands/doctor.js +33 -3
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/skill.js +109 -0
- package/dist/commands/skill.js.map +1 -0
- package/dist/commands/sync.js +3 -1
- package/dist/commands/sync.js.map +1 -1
- package/dist/config.js +18 -6
- package/dist/config.js.map +1 -1
- package/dist/kicad/cli.js +106 -18
- package/dist/kicad/cli.js.map +1 -1
- package/dist/kicad/draft/draft.js +3 -0
- package/dist/kicad/draft/draft.js.map +1 -1
- package/dist/kicad/draft/engine.js +3139 -218
- package/dist/kicad/draft/engine.js.map +1 -1
- package/dist/kicad/draft/symsource.js +24 -10
- package/dist/kicad/draft/symsource.js.map +1 -1
- package/dist/kicad/emit.js +45 -6
- package/dist/kicad/emit.js.map +1 -1
- package/dist/kicad/legibility.js +51 -4
- package/dist/kicad/legibility.js.map +1 -1
- package/dist/kicad/score.js +173 -3
- package/dist/kicad/score.js.map +1 -1
- package/dist/kicad/sexp.js +32 -6
- package/dist/kicad/sexp.js.map +1 -1
- package/dist/mcp/server.js +485 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/memory/scaffold.js +8 -1
- package/dist/memory/scaffold.js.map +1 -1
- package/package.json +5 -2
- package/src/agent/context.ts +35 -0
- package/src/agent/dock-renderer.ts +3 -2
- package/src/agent/envelope.ts +124 -0
- package/src/agent/loop.ts +45 -17
- package/src/agent/providers/claude-code.ts +22 -1
- package/src/agent/providers/codex.ts +91 -42
- package/src/agent/recovery.ts +89 -12
- package/src/agent/registry.ts +58 -0
- package/src/agent/render.ts +4 -3
- package/src/agent/theme.ts +15 -5
- package/src/agent/tools.ts +124 -816
- package/src/agent/types.ts +10 -5
- package/src/capabilities/define.ts +88 -0
- package/src/capabilities/handlers.ts +769 -0
- package/src/capabilities/helpers.ts +37 -0
- package/src/capabilities/index.ts +53 -0
- package/src/capabilities/skills/generate-report.ts +25 -0
- package/src/cli.ts +84 -1
- package/src/commands/create.ts +5 -2
- package/src/commands/doctor.ts +34 -3
- package/src/commands/skill.ts +127 -0
- package/src/commands/sync.ts +5 -3
- package/src/config.ts +32 -8
- package/src/kicad/cli.ts +129 -18
- package/src/kicad/draft/draft.ts +2 -0
- package/src/kicad/draft/engine.ts +3034 -226
- package/src/kicad/draft/symsource.ts +24 -10
- package/src/kicad/emit.ts +71 -7
- package/src/kicad/legibility.ts +55 -6
- package/src/kicad/score.ts +187 -8
- package/src/kicad/sexp.ts +37 -6
- package/src/mcp/server.ts +560 -0
- package/src/memory/scaffold.ts +8 -1
package/src/kicad/cli.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { execa, ExecaError } from 'execa';
|
|
2
|
-
import { existsSync } from 'node:fs';
|
|
2
|
+
import { existsSync, readdirSync } from 'node:fs';
|
|
3
3
|
import { mkdtemp, readFile, rm } from 'node:fs/promises';
|
|
4
4
|
import { tmpdir } from 'node:os';
|
|
5
5
|
import path from 'node:path';
|
|
@@ -7,14 +7,29 @@ import { normalizeReport, type CheckReport } from './report.js';
|
|
|
7
7
|
import { PreflightError, isNotFoundError } from '../util/preflight.js';
|
|
8
8
|
|
|
9
9
|
export class KicadCliMissingError extends PreflightError {
|
|
10
|
-
constructor() {
|
|
10
|
+
constructor(platform = process.platform) {
|
|
11
|
+
const isWin = platform === 'win32';
|
|
12
|
+
const isMac = platform === 'darwin';
|
|
13
|
+
|
|
14
|
+
const locationHint = isWin
|
|
15
|
+
? 'ensure kicad-cli.exe is on PATH (typically in C:\\Program Files\\KiCad\\<version>\\bin)'
|
|
16
|
+
: isMac
|
|
17
|
+
? 'ensure the kicad-cli binary is on PATH (on macOS it ships inside KiCad.app/Contents/MacOS)'
|
|
18
|
+
: 'ensure the kicad-cli binary is on PATH (typically /usr/bin/kicad-cli)';
|
|
19
|
+
|
|
20
|
+
const envHint = isWin
|
|
21
|
+
? 'or set COPPERHEAD_KICAD_CLI="C:\\Program Files\\KiCad\\10.0\\bin\\kicad-cli.exe"'
|
|
22
|
+
: isMac
|
|
23
|
+
? 'or set COPPERHEAD_KICAD_CLI=/Applications/KiCad/KiCad.app/Contents/MacOS/kicad-cli'
|
|
24
|
+
: 'or set COPPERHEAD_KICAD_CLI=/usr/bin/kicad-cli';
|
|
25
|
+
|
|
11
26
|
super(
|
|
12
27
|
'kicad-cli not found on PATH',
|
|
13
28
|
'copperhead verifies every mutation with kicad-cli ERC/DRC; without it no edit can be checked, so no run can start',
|
|
14
29
|
[
|
|
15
30
|
'install KiCad ≥ 8: https://www.kicad.org/download/',
|
|
16
|
-
|
|
17
|
-
|
|
31
|
+
locationHint,
|
|
32
|
+
envHint,
|
|
18
33
|
'confirm with "kicad-cli version", then rerun',
|
|
19
34
|
],
|
|
20
35
|
);
|
|
@@ -28,15 +43,32 @@ export class KicadCliMissingError extends PreflightError {
|
|
|
28
43
|
* seen and rejected, so telling the user to set it would be nonsense.
|
|
29
44
|
*/
|
|
30
45
|
export class KicadCliBadOverrideError extends PreflightError {
|
|
31
|
-
constructor(configured: string) {
|
|
46
|
+
constructor(configured: string, platform = process.platform) {
|
|
47
|
+
const isWin = platform === 'win32';
|
|
48
|
+
const isMac = platform === 'darwin';
|
|
49
|
+
|
|
50
|
+
const checkHint = isWin
|
|
51
|
+
? `check the path in PowerShell: Test-Path "${configured}"`
|
|
52
|
+
: `check the path: ls -l "${configured}"`;
|
|
53
|
+
|
|
54
|
+
const locationHint = isWin
|
|
55
|
+
? 'on Windows the binary typically lives at C:\\Program Files\\KiCad\\<version>\\bin\\kicad-cli.exe'
|
|
56
|
+
: isMac
|
|
57
|
+
? 'on macOS the binary lives at /Applications/KiCad/KiCad.app/Contents/MacOS/kicad-cli'
|
|
58
|
+
: 'on Linux the binary typically lives at /usr/bin/kicad-cli';
|
|
59
|
+
|
|
60
|
+
const confirmHint = isWin
|
|
61
|
+
? 'confirm with "& $env:COPPERHEAD_KICAD_CLI version", then rerun'
|
|
62
|
+
: 'confirm with "$COPPERHEAD_KICAD_CLI" version, then rerun';
|
|
63
|
+
|
|
32
64
|
super(
|
|
33
65
|
`COPPERHEAD_KICAD_CLI points to a path that does not exist: ${configured}`,
|
|
34
66
|
'the override wins over PATH, so falling back silently would run a different binary than the one you named and make the failure impossible to diagnose',
|
|
35
67
|
[
|
|
36
|
-
|
|
37
|
-
|
|
68
|
+
checkHint,
|
|
69
|
+
locationHint,
|
|
38
70
|
'or unset COPPERHEAD_KICAD_CLI to fall back to PATH',
|
|
39
|
-
|
|
71
|
+
confirmHint,
|
|
40
72
|
],
|
|
41
73
|
);
|
|
42
74
|
this.name = 'KicadCliBadOverrideError';
|
|
@@ -44,20 +76,89 @@ export class KicadCliBadOverrideError extends PreflightError {
|
|
|
44
76
|
}
|
|
45
77
|
|
|
46
78
|
/** Well-known install locations when `kicad-cli` is not on PATH (macOS app bundle). */
|
|
47
|
-
const
|
|
79
|
+
const MACOS_FALLBACK_BINARIES = [
|
|
48
80
|
'/Applications/KiCad/KiCad.app/Contents/MacOS/kicad-cli',
|
|
49
81
|
'/Applications/KiCad-10.0/KiCad.app/Contents/MacOS/kicad-cli',
|
|
50
82
|
'/Applications/KiCad-9.0/KiCad.app/Contents/MacOS/kicad-cli',
|
|
51
83
|
'/Applications/KiCad-8.0/KiCad.app/Contents/MacOS/kicad-cli',
|
|
52
84
|
];
|
|
53
85
|
|
|
54
|
-
|
|
86
|
+
/**
|
|
87
|
+
* Minimum KiCad major version accepted for ERC/DRC and candidate discovery.
|
|
88
|
+
* Re-used by doctor.ts to ensure CLI discovery and environment preflight
|
|
89
|
+
* enforce the same version floor.
|
|
90
|
+
*/
|
|
91
|
+
export const MIN_KICAD_MAJOR = 8;
|
|
92
|
+
|
|
93
|
+
const DEFAULT_WIN_ROOTS = [
|
|
94
|
+
process.env.ProgramFiles ? path.join(process.env.ProgramFiles, 'KiCad') : 'C:/Program Files/KiCad',
|
|
95
|
+
'C:/Program Files/KiCad',
|
|
96
|
+
'C:/Program Files (x86)/KiCad',
|
|
97
|
+
];
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Return default fallback candidate paths for macOS and Windows standard KiCad installations.
|
|
101
|
+
* On Windows, version-numbered directories (e.g. 10.0, 9.0, 8.0) under the KiCad root
|
|
102
|
+
* are probed in descending numerical order, mirroring symlib.ts.
|
|
103
|
+
*/
|
|
104
|
+
export function defaultFallbackBinaries(winRoots: readonly string[] = DEFAULT_WIN_ROOTS): string[] {
|
|
105
|
+
const candidates: string[] = [...MACOS_FALLBACK_BINARIES];
|
|
106
|
+
const seenRoots = new Set<string>();
|
|
107
|
+
|
|
108
|
+
for (const winRoot of winRoots) {
|
|
109
|
+
const normalized = path.normalize(winRoot).toLowerCase();
|
|
110
|
+
if (seenRoots.has(normalized)) continue;
|
|
111
|
+
seenRoots.add(normalized);
|
|
112
|
+
|
|
113
|
+
if (!existsSync(winRoot)) continue;
|
|
114
|
+
try {
|
|
115
|
+
const entries = readdirSync(winRoot, { withFileTypes: true });
|
|
116
|
+
const versions = entries
|
|
117
|
+
.filter((e) => e.isDirectory())
|
|
118
|
+
.map((e) => e.name)
|
|
119
|
+
// Only include versions that meet the minimum supported KiCad major.
|
|
120
|
+
// This prevents a stale KiCad 7.x install from silently becoming the
|
|
121
|
+
// ERC/DRC binary while doctor correctly reports FAIL for it.
|
|
122
|
+
.filter((name) => {
|
|
123
|
+
const major = Number(name.split('.')[0]);
|
|
124
|
+
return Number.isFinite(major) && major >= MIN_KICAD_MAJOR;
|
|
125
|
+
})
|
|
126
|
+
.sort((a, b) => b.localeCompare(a, undefined, { numeric: true }));
|
|
127
|
+
|
|
128
|
+
for (const version of versions) {
|
|
129
|
+
candidates.push(
|
|
130
|
+
path.join(winRoot, version, 'bin', 'kicad-cli.exe'),
|
|
131
|
+
path.join(winRoot, version, 'bin', 'kicad-cli.cmd'),
|
|
132
|
+
path.join(winRoot, version, 'bin', 'kicad-cli.bat'),
|
|
133
|
+
path.join(winRoot, version, 'bin', 'kicad-cli'),
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
} catch {
|
|
137
|
+
// not readable / not a directory; versioned candidates unavailable, but
|
|
138
|
+
// the unversioned bin/ fallback below is still worth probing.
|
|
139
|
+
}
|
|
140
|
+
// Unversioned fallback: pushed unconditionally so a readdirSync failure
|
|
141
|
+
// (e.g. ENOTDIR) on the root itself doesn't also suppress this probe.
|
|
142
|
+
candidates.push(
|
|
143
|
+
path.join(winRoot, 'bin', 'kicad-cli.exe'),
|
|
144
|
+
path.join(winRoot, 'bin', 'kicad-cli.cmd'),
|
|
145
|
+
path.join(winRoot, 'bin', 'kicad-cli.bat'),
|
|
146
|
+
path.join(winRoot, 'bin', 'kicad-cli'),
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return candidates;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
let fallbackBinariesOverride: readonly string[] | null = null;
|
|
154
|
+
let fallbackWinRootsOverride: readonly string[] | null = null;
|
|
55
155
|
|
|
56
156
|
let cachedBinary: string | null | undefined;
|
|
57
157
|
|
|
58
158
|
/**
|
|
59
159
|
* Resolve the kicad-cli executable: `COPPERHEAD_KICAD_CLI` > PATH name
|
|
60
|
-
* (`kicad-cli`). On PATH miss, `runKicad` falls back to macOS KiCad.app paths
|
|
160
|
+
* (`kicad-cli`). On PATH miss, `runKicad` falls back to macOS KiCad.app paths
|
|
161
|
+
* and Windows standard installation paths.
|
|
61
162
|
*/
|
|
62
163
|
export function resolveKicadCli(): string {
|
|
63
164
|
if (cachedBinary !== undefined) {
|
|
@@ -88,7 +189,7 @@ function envOverride(): string | null {
|
|
|
88
189
|
}
|
|
89
190
|
|
|
90
191
|
/**
|
|
91
|
-
* After ENOENT on PATH, retry with
|
|
192
|
+
* After ENOENT on PATH, retry with known install paths (macOS app bundles, Windows standard paths).
|
|
92
193
|
*
|
|
93
194
|
* Deliberately does not re-read `COPPERHEAD_KICAD_CLI`: this is reached only
|
|
94
195
|
* when resolveKicadCli() cached the bare PATH name, which in turn happens only
|
|
@@ -96,7 +197,9 @@ function envOverride(): string | null {
|
|
|
96
197
|
* override re-check here could never fire.
|
|
97
198
|
*/
|
|
98
199
|
function fallbackAfterMissing(): string {
|
|
99
|
-
|
|
200
|
+
const candidates =
|
|
201
|
+
fallbackBinariesOverride ?? defaultFallbackBinaries(fallbackWinRootsOverride ?? undefined);
|
|
202
|
+
for (const candidate of candidates) {
|
|
100
203
|
if (existsSync(candidate)) {
|
|
101
204
|
cachedBinary = candidate;
|
|
102
205
|
return candidate;
|
|
@@ -133,13 +236,21 @@ export function resetKicadCliCache(): void {
|
|
|
133
236
|
}
|
|
134
237
|
|
|
135
238
|
/**
|
|
136
|
-
* Test helper: point the app-bundle probe at fixture paths, or call with no
|
|
137
|
-
* argument to restore the
|
|
138
|
-
* exercisable on a macOS host that happens to have KiCad installed, which
|
|
139
|
-
* makes the outcome depend on the developer's machine.
|
|
239
|
+
* Test helper: point the app-bundle / binary probe at fixture paths, or call with no
|
|
240
|
+
* argument to restore the default dynamic list.
|
|
140
241
|
*/
|
|
141
242
|
export function setKicadFallbackBinaries(paths?: readonly string[]): void {
|
|
142
|
-
|
|
243
|
+
fallbackBinariesOverride = paths ?? null;
|
|
244
|
+
fallbackWinRootsOverride = null;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Test helper: point the Windows installation discovery probe at fixture roots, or call
|
|
249
|
+
* with no argument to restore the default search roots.
|
|
250
|
+
*/
|
|
251
|
+
export function setKicadFallbackWinRoots(roots?: readonly string[]): void {
|
|
252
|
+
fallbackWinRootsOverride = roots ?? null;
|
|
253
|
+
fallbackBinariesOverride = null;
|
|
143
254
|
}
|
|
144
255
|
|
|
145
256
|
export async function kicadCliVersion(): Promise<string> {
|
package/src/kicad/draft/draft.ts
CHANGED
|
@@ -166,6 +166,8 @@ export function formatSchematicDraftReport(report: SchematicDraftReport): string
|
|
|
166
166
|
` net classes: ${report.netClasses.map((n) => `${n.name}=${n.class}${mark(n)}`).join(', ')}${legend.length ? ` (${legend.join(', ')})` : ''}`,
|
|
167
167
|
);
|
|
168
168
|
if (report.pwrFlags.length) lines.push(` PWR_FLAG synthesized on: ${report.pwrFlags.join(', ')}`);
|
|
169
|
+
const sf = report.sheetFit as SchematicDraftReport['sheetFit'] | undefined;
|
|
170
|
+
if (sf) lines.push(` sheet fit: ${sf.paper}, ink ${Math.round(sf.inkUtilization * 100)}% of the usable frame, compaction ${sf.compaction}`);
|
|
169
171
|
for (const n of report.notes) lines.push(` note: ${n}`);
|
|
170
172
|
return lines.join('\n');
|
|
171
173
|
}
|