@intelligentelectron/pcb-lens 0.0.1
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/CHANGELOG.md +26 -0
- package/LICENSE +190 -0
- package/NOTICE +4 -0
- package/README.md +156 -0
- package/dist/cli/commands.d.ts +23 -0
- package/dist/cli/commands.d.ts.map +1 -0
- package/dist/cli/commands.js +113 -0
- package/dist/cli/commands.js.map +1 -0
- package/dist/cli/prompts.d.ts +10 -0
- package/dist/cli/prompts.d.ts.map +1 -0
- package/dist/cli/prompts.js +25 -0
- package/dist/cli/prompts.js.map +1 -0
- package/dist/cli/shell.d.ts +15 -0
- package/dist/cli/shell.d.ts.map +1 -0
- package/dist/cli/shell.js +66 -0
- package/dist/cli/shell.js.map +1 -0
- package/dist/cli/updater.d.ts +50 -0
- package/dist/cli/updater.d.ts.map +1 -0
- package/dist/cli/updater.js +305 -0
- package/dist/cli/updater.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +62 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +16 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +175 -0
- package/dist/server.js.map +1 -0
- package/dist/service.d.ts +13 -0
- package/dist/service.d.ts.map +1 -0
- package/dist/service.js +1139 -0
- package/dist/service.js.map +1 -0
- package/dist/types.d.ts +128 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/dist/version.d.ts +10 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +25 -0
- package/dist/version.js.map +1 -0
- package/dist/wasm-embed.d.ts +3 -0
- package/dist/wasm-embed.d.ts.map +1 -0
- package/dist/wasm-embed.js +5 -0
- package/dist/wasm-embed.js.map +1 -0
- package/dist/xml-utils.d.ts +41 -0
- package/dist/xml-utils.d.ts.map +1 -0
- package/dist/xml-utils.js +81 -0
- package/dist/xml-utils.js.map +1 -0
- package/package.json +78 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-updater for pcb-lens server.
|
|
3
|
+
*
|
|
4
|
+
* Checks GitHub Releases for newer versions and self-updates on startup.
|
|
5
|
+
* Can be disabled via --no-update CLI flag.
|
|
6
|
+
*/
|
|
7
|
+
/** Result of an update check. */
|
|
8
|
+
export interface UpdateCheckResult {
|
|
9
|
+
updateAvailable: boolean;
|
|
10
|
+
currentVersion: string;
|
|
11
|
+
latestVersion: string | null;
|
|
12
|
+
downloadUrl: string | null;
|
|
13
|
+
error?: string;
|
|
14
|
+
}
|
|
15
|
+
/** Result of an update operation. */
|
|
16
|
+
export interface UpdateResult {
|
|
17
|
+
success: boolean;
|
|
18
|
+
previousVersion: string;
|
|
19
|
+
newVersion: string | null;
|
|
20
|
+
error?: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Detect if running as an npm global install or via npx.
|
|
24
|
+
* npm installs run from node_modules, not as compiled binaries.
|
|
25
|
+
*/
|
|
26
|
+
export declare const isNpmInstall: () => boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Check if an update is available.
|
|
29
|
+
*/
|
|
30
|
+
export declare const checkForUpdate: () => Promise<UpdateCheckResult>;
|
|
31
|
+
/**
|
|
32
|
+
* Get the path to the current executable.
|
|
33
|
+
*/
|
|
34
|
+
export declare const getCurrentExecutablePath: () => string;
|
|
35
|
+
/**
|
|
36
|
+
* Perform the update by downloading and replacing the current binary.
|
|
37
|
+
*/
|
|
38
|
+
export declare const performUpdate: (downloadUrl: string, newVersion: string) => Promise<UpdateResult>;
|
|
39
|
+
/**
|
|
40
|
+
* Re-execute the current process with the same arguments.
|
|
41
|
+
*/
|
|
42
|
+
export declare const reexec: () => never;
|
|
43
|
+
/**
|
|
44
|
+
* Check for updates and apply if available.
|
|
45
|
+
* This is the main entry point for auto-updates on startup.
|
|
46
|
+
*
|
|
47
|
+
* @returns true if an update was applied and process should restart
|
|
48
|
+
*/
|
|
49
|
+
export declare const autoUpdate: () => Promise<boolean>;
|
|
50
|
+
//# sourceMappingURL=updater.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"updater.d.ts","sourceRoot":"","sources":["../../src/cli/updater.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAwBH,iCAAiC;AACjC,MAAM,WAAW,iBAAiB;IAChC,eAAe,EAAE,OAAO,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qCAAqC;AACrC,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,eAAO,MAAM,YAAY,QAAO,OAG/B,CAAC;AAwEF;;GAEG;AACH,eAAO,MAAM,cAAc,QAAa,OAAO,CAAC,iBAAiB,CA8BhE,CAAC;AAiCF;;GAEG;AACH,eAAO,MAAM,wBAAwB,QAAO,MAS3C,CAAC;AAkCF;;GAEG;AACH,eAAO,MAAM,aAAa,GACxB,aAAa,MAAM,EACnB,YAAY,MAAM,KACjB,OAAO,CAAC,YAAY,CAmEtB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,MAAM,QAAO,KAuBzB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,UAAU,QAAa,OAAO,CAAC,OAAO,CA6BlD,CAAC"}
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-updater for pcb-lens server.
|
|
3
|
+
*
|
|
4
|
+
* Checks GitHub Releases for newer versions and self-updates on startup.
|
|
5
|
+
* Can be disabled via --no-update CLI flag.
|
|
6
|
+
*/
|
|
7
|
+
import { createWriteStream, chmodSync, renameSync, unlinkSync, existsSync, readdirSync, } from "node:fs";
|
|
8
|
+
import { tmpdir } from "node:os";
|
|
9
|
+
import { join, dirname, basename } from "node:path";
|
|
10
|
+
import { spawn } from "node:child_process";
|
|
11
|
+
import { VERSION, GITHUB_REPO, BINARY_NAME } from "../version.js";
|
|
12
|
+
/**
|
|
13
|
+
* Detect if running as an npm global install or via npx.
|
|
14
|
+
* npm installs run from node_modules, not as compiled binaries.
|
|
15
|
+
*/
|
|
16
|
+
export const isNpmInstall = () => {
|
|
17
|
+
const scriptPath = process.argv[1];
|
|
18
|
+
return scriptPath?.includes("node_modules") ?? false;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Get the platform-specific binary name.
|
|
22
|
+
*/
|
|
23
|
+
const getPlatformBinaryName = () => {
|
|
24
|
+
const platform = process.platform;
|
|
25
|
+
const arch = process.arch;
|
|
26
|
+
if (platform === "darwin") {
|
|
27
|
+
return `${BINARY_NAME}-darwin-universal`;
|
|
28
|
+
}
|
|
29
|
+
else if (platform === "linux") {
|
|
30
|
+
return arch === "arm64" ? `${BINARY_NAME}-linux-arm64` : `${BINARY_NAME}-linux-x64`;
|
|
31
|
+
}
|
|
32
|
+
else if (platform === "win32") {
|
|
33
|
+
return `${BINARY_NAME}-windows-x64.exe`;
|
|
34
|
+
}
|
|
35
|
+
throw new Error(`Unsupported platform: ${platform}-${arch}`);
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Parse a version string into comparable parts.
|
|
39
|
+
*/
|
|
40
|
+
const parseVersion = (version) => {
|
|
41
|
+
const cleaned = version.replace(/^v/, "");
|
|
42
|
+
return cleaned.split(".").map((part) => parseInt(part, 10) || 0);
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Compare two version strings. Returns:
|
|
46
|
+
* - Negative if a < b
|
|
47
|
+
* - Zero if a === b
|
|
48
|
+
* - Positive if a > b
|
|
49
|
+
*/
|
|
50
|
+
const compareVersions = (a, b) => {
|
|
51
|
+
const partsA = parseVersion(a);
|
|
52
|
+
const partsB = parseVersion(b);
|
|
53
|
+
const maxLen = Math.max(partsA.length, partsB.length);
|
|
54
|
+
for (let i = 0; i < maxLen; i++) {
|
|
55
|
+
const numA = partsA[i] || 0;
|
|
56
|
+
const numB = partsB[i] || 0;
|
|
57
|
+
if (numA !== numB) {
|
|
58
|
+
return numA - numB;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return 0;
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Fetch the latest release from GitHub.
|
|
65
|
+
*/
|
|
66
|
+
const fetchLatestRelease = async () => {
|
|
67
|
+
const url = `https://api.github.com/repos/${GITHUB_REPO}/releases/latest`;
|
|
68
|
+
const response = await fetch(url, {
|
|
69
|
+
headers: {
|
|
70
|
+
Accept: "application/vnd.github.v3+json",
|
|
71
|
+
"User-Agent": `${BINARY_NAME}/${VERSION}`,
|
|
72
|
+
},
|
|
73
|
+
signal: AbortSignal.timeout(10_000),
|
|
74
|
+
});
|
|
75
|
+
if (!response.ok) {
|
|
76
|
+
if (response.status === 404) {
|
|
77
|
+
throw new Error("No releases found");
|
|
78
|
+
}
|
|
79
|
+
throw new Error(`GitHub API error: ${response.status} ${response.statusText}`);
|
|
80
|
+
}
|
|
81
|
+
return response.json();
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* Check if an update is available.
|
|
85
|
+
*/
|
|
86
|
+
export const checkForUpdate = async () => {
|
|
87
|
+
try {
|
|
88
|
+
const release = await fetchLatestRelease();
|
|
89
|
+
const latestVersion = release.tag_name.replace(/^v/, "");
|
|
90
|
+
const updateAvailable = compareVersions(latestVersion, VERSION) > 0;
|
|
91
|
+
let downloadUrl = null;
|
|
92
|
+
if (updateAvailable) {
|
|
93
|
+
const binaryName = getPlatformBinaryName();
|
|
94
|
+
const asset = release.assets.find((a) => a.name === binaryName);
|
|
95
|
+
if (asset) {
|
|
96
|
+
downloadUrl = asset.browser_download_url;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
updateAvailable,
|
|
101
|
+
currentVersion: VERSION,
|
|
102
|
+
latestVersion,
|
|
103
|
+
downloadUrl,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
return {
|
|
108
|
+
updateAvailable: false,
|
|
109
|
+
currentVersion: VERSION,
|
|
110
|
+
latestVersion: null,
|
|
111
|
+
downloadUrl: null,
|
|
112
|
+
error: error instanceof Error ? error.message : String(error),
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* Download a file from a URL to a local path.
|
|
118
|
+
*/
|
|
119
|
+
const downloadFile = async (url, destPath) => {
|
|
120
|
+
const response = await fetch(url, {
|
|
121
|
+
headers: {
|
|
122
|
+
"User-Agent": `${BINARY_NAME}/${VERSION}`,
|
|
123
|
+
},
|
|
124
|
+
signal: AbortSignal.timeout(60_000),
|
|
125
|
+
});
|
|
126
|
+
if (!response.ok) {
|
|
127
|
+
throw new Error(`Download failed: ${response.status} ${response.statusText}`);
|
|
128
|
+
}
|
|
129
|
+
if (!response.body) {
|
|
130
|
+
throw new Error("No response body");
|
|
131
|
+
}
|
|
132
|
+
const { Readable } = await import("node:stream");
|
|
133
|
+
const nodeStream = Readable.fromWeb(response.body);
|
|
134
|
+
const fileStream = createWriteStream(destPath);
|
|
135
|
+
await new Promise((resolve, reject) => {
|
|
136
|
+
nodeStream.pipe(fileStream);
|
|
137
|
+
fileStream.on("finish", resolve);
|
|
138
|
+
fileStream.on("error", reject);
|
|
139
|
+
nodeStream.on("error", reject);
|
|
140
|
+
});
|
|
141
|
+
};
|
|
142
|
+
/**
|
|
143
|
+
* Get the path to the current executable.
|
|
144
|
+
*/
|
|
145
|
+
export const getCurrentExecutablePath = () => {
|
|
146
|
+
// For Bun-compiled binaries, process.execPath points to the binary itself
|
|
147
|
+
// For Node.js, process.argv[1] is the script path
|
|
148
|
+
if (process.execPath.includes("node") || process.execPath.includes("bun")) {
|
|
149
|
+
// Running via node/bun interpreter - use argv[1]
|
|
150
|
+
return process.argv[1];
|
|
151
|
+
}
|
|
152
|
+
// Compiled binary - use execPath
|
|
153
|
+
return process.execPath;
|
|
154
|
+
};
|
|
155
|
+
/**
|
|
156
|
+
* Generate a unique backup path with timestamp to avoid conflicts with locked files.
|
|
157
|
+
* On Windows, previous backup files may still be locked by the old process.
|
|
158
|
+
*/
|
|
159
|
+
const getBackupPath = (currentPath) => {
|
|
160
|
+
return `${currentPath}.backup.${Date.now()}`;
|
|
161
|
+
};
|
|
162
|
+
/**
|
|
163
|
+
* Clean up old backup files from previous updates (best effort).
|
|
164
|
+
* On Windows, backup files may remain if the old process was still running.
|
|
165
|
+
* This is non-fatal - if files are locked, they'll be cleaned up next time.
|
|
166
|
+
*/
|
|
167
|
+
const cleanupOldBackups = (currentPath) => {
|
|
168
|
+
const dir = dirname(currentPath);
|
|
169
|
+
const base = basename(currentPath);
|
|
170
|
+
try {
|
|
171
|
+
const files = readdirSync(dir);
|
|
172
|
+
for (const file of files) {
|
|
173
|
+
if (file.startsWith(`${base}.backup.`)) {
|
|
174
|
+
try {
|
|
175
|
+
unlinkSync(join(dir, file));
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
// Ignore - file may still be locked
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
// Ignore directory read errors
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
/**
|
|
188
|
+
* Perform the update by downloading and replacing the current binary.
|
|
189
|
+
*/
|
|
190
|
+
export const performUpdate = async (downloadUrl, newVersion) => {
|
|
191
|
+
const currentPath = getCurrentExecutablePath();
|
|
192
|
+
const tempPath = join(tmpdir(), `${BINARY_NAME}-update-${Date.now()}`);
|
|
193
|
+
// Use timestamped backup to avoid conflicts with locked files from previous updates
|
|
194
|
+
const backupPath = getBackupPath(currentPath);
|
|
195
|
+
// Clean up old backups from previous updates (best effort, non-fatal)
|
|
196
|
+
cleanupOldBackups(currentPath);
|
|
197
|
+
try {
|
|
198
|
+
// Download new binary to temp location
|
|
199
|
+
await downloadFile(downloadUrl, tempPath);
|
|
200
|
+
// Make executable
|
|
201
|
+
if (process.platform !== "win32") {
|
|
202
|
+
chmodSync(tempPath, 0o755);
|
|
203
|
+
}
|
|
204
|
+
// Backup current binary
|
|
205
|
+
if (existsSync(currentPath)) {
|
|
206
|
+
renameSync(currentPath, backupPath);
|
|
207
|
+
}
|
|
208
|
+
// Move new binary into place
|
|
209
|
+
renameSync(tempPath, currentPath);
|
|
210
|
+
// Remove backup (non-fatal on Windows due to file locking)
|
|
211
|
+
if (existsSync(backupPath)) {
|
|
212
|
+
try {
|
|
213
|
+
unlinkSync(backupPath);
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
// On Windows, the old executable may still be locked.
|
|
217
|
+
// This is fine - it will be cleaned up on next update.
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return {
|
|
221
|
+
success: true,
|
|
222
|
+
previousVersion: VERSION,
|
|
223
|
+
newVersion,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
catch (error) {
|
|
227
|
+
// Attempt to restore backup
|
|
228
|
+
if (existsSync(backupPath) && !existsSync(currentPath)) {
|
|
229
|
+
try {
|
|
230
|
+
renameSync(backupPath, currentPath);
|
|
231
|
+
}
|
|
232
|
+
catch {
|
|
233
|
+
// Ignore restore errors
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
// Clean up temp file
|
|
237
|
+
if (existsSync(tempPath)) {
|
|
238
|
+
try {
|
|
239
|
+
unlinkSync(tempPath);
|
|
240
|
+
}
|
|
241
|
+
catch {
|
|
242
|
+
// Ignore cleanup errors
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return {
|
|
246
|
+
success: false,
|
|
247
|
+
previousVersion: VERSION,
|
|
248
|
+
newVersion: null,
|
|
249
|
+
error: error instanceof Error ? error.message : String(error),
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
/**
|
|
254
|
+
* Re-execute the current process with the same arguments.
|
|
255
|
+
*/
|
|
256
|
+
export const reexec = () => {
|
|
257
|
+
const execPath = getCurrentExecutablePath();
|
|
258
|
+
const args = process.argv.slice(2);
|
|
259
|
+
// Spawn the new process
|
|
260
|
+
const child = spawn(execPath, args, {
|
|
261
|
+
stdio: "inherit",
|
|
262
|
+
detached: false,
|
|
263
|
+
});
|
|
264
|
+
// Exit this process when child exits
|
|
265
|
+
child.on("exit", (code) => {
|
|
266
|
+
process.exit(code ?? 0);
|
|
267
|
+
});
|
|
268
|
+
child.on("error", (err) => {
|
|
269
|
+
console.error("Failed to restart:", err.message);
|
|
270
|
+
process.exit(1);
|
|
271
|
+
});
|
|
272
|
+
// This line is reached but we've set up handlers to exit
|
|
273
|
+
// TypeScript needs the never return type satisfied
|
|
274
|
+
throw new Error("Process should have been replaced");
|
|
275
|
+
};
|
|
276
|
+
/**
|
|
277
|
+
* Check for updates and apply if available.
|
|
278
|
+
* This is the main entry point for auto-updates on startup.
|
|
279
|
+
*
|
|
280
|
+
* @returns true if an update was applied and process should restart
|
|
281
|
+
*/
|
|
282
|
+
export const autoUpdate = async () => {
|
|
283
|
+
// Skip auto-update for npm installs - use npm update instead
|
|
284
|
+
if (isNpmInstall()) {
|
|
285
|
+
return false;
|
|
286
|
+
}
|
|
287
|
+
const check = await checkForUpdate();
|
|
288
|
+
if (check.error) {
|
|
289
|
+
// Silently continue if update check fails
|
|
290
|
+
return false;
|
|
291
|
+
}
|
|
292
|
+
if (!check.updateAvailable || !check.downloadUrl || !check.latestVersion) {
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
// Log update to stderr (MCP uses stdio, so stdout is reserved)
|
|
296
|
+
console.error(`[pcb-lens] Updating from ${VERSION} to ${check.latestVersion}...`);
|
|
297
|
+
const result = await performUpdate(check.downloadUrl, check.latestVersion);
|
|
298
|
+
if (!result.success) {
|
|
299
|
+
console.error(`[pcb-lens] Update failed: ${result.error}`);
|
|
300
|
+
return false;
|
|
301
|
+
}
|
|
302
|
+
console.error(`[pcb-lens] Update complete. Restarting...`);
|
|
303
|
+
return true;
|
|
304
|
+
};
|
|
305
|
+
//# sourceMappingURL=updater.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"updater.js","sourceRoot":"","sources":["../../src/cli/updater.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* PCB Lens MCP Server Entry Point
|
|
4
|
+
*
|
|
5
|
+
* Run with: npx tsx src/index.ts
|
|
6
|
+
* Or after build: node dist/index.js
|
|
7
|
+
*
|
|
8
|
+
* CLI flags:
|
|
9
|
+
* --version, -v Print version and exit
|
|
10
|
+
* --help, -h Show help
|
|
11
|
+
* --update Check for and install updates
|
|
12
|
+
* --uninstall Remove binary and PATH entries
|
|
13
|
+
*/
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;GAWG"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* PCB Lens MCP Server Entry Point
|
|
4
|
+
*
|
|
5
|
+
* Run with: npx tsx src/index.ts
|
|
6
|
+
* Or after build: node dist/index.js
|
|
7
|
+
*
|
|
8
|
+
* CLI flags:
|
|
9
|
+
* --version, -v Print version and exit
|
|
10
|
+
* --help, -h Show help
|
|
11
|
+
* --update Check for and install updates
|
|
12
|
+
* --uninstall Remove binary and PATH entries
|
|
13
|
+
*/
|
|
14
|
+
import { printVersion, printHelp, handleUpdateCommand, handleUninstallCommand, } from "./cli/commands.js";
|
|
15
|
+
import { autoUpdate, reexec } from "./cli/updater.js";
|
|
16
|
+
import { runServer } from "./server.js";
|
|
17
|
+
const main = async () => {
|
|
18
|
+
const args = process.argv.slice(2);
|
|
19
|
+
// Handle --version / -v
|
|
20
|
+
if (args.includes("--version") || args.includes("-v")) {
|
|
21
|
+
printVersion();
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
// Handle --help / -h
|
|
25
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
26
|
+
printHelp();
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
// Handle --update
|
|
30
|
+
if (args.includes("--update")) {
|
|
31
|
+
await handleUpdateCommand();
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
// Handle --uninstall
|
|
35
|
+
if (args.includes("--uninstall")) {
|
|
36
|
+
await handleUninstallCommand();
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
// If running in a TTY (interactive terminal), show help instead of starting server
|
|
40
|
+
if (process.stdin.isTTY) {
|
|
41
|
+
console.log("This is an MCP server that communicates via stdio.");
|
|
42
|
+
console.log("It should be run by an MCP client (e.g., Claude Desktop), not directly.\n");
|
|
43
|
+
console.log("For setup instructions, see:");
|
|
44
|
+
console.log(" https://github.com/IntelligentElectron/pcb-lens?tab=readme-ov-file#connect-the-mcp-with-your-favorite-ai-tool\n");
|
|
45
|
+
console.log("Run with --help for available options.");
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
// Auto-update on startup (unless --no-update flag is present)
|
|
49
|
+
if (!args.includes("--no-update")) {
|
|
50
|
+
const updated = await autoUpdate();
|
|
51
|
+
if (updated) {
|
|
52
|
+
// Re-execute with the new binary
|
|
53
|
+
reexec();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
await runServer();
|
|
57
|
+
};
|
|
58
|
+
main().catch((error) => {
|
|
59
|
+
console.error("Server error:", error);
|
|
60
|
+
process.exit(1);
|
|
61
|
+
});
|
|
62
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;GAWG;AAEH,OAAO,EACL,YAAY,EACZ,SAAS,EACT,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,MAAM,IAAI,GAAG,KAAK,IAAmB,EAAE;IACrC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAEnC,wBAAwB;IACxB,IAAI,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACtD,YAAY,EAAE,CAAC;QACf,OAAO;IACT,CAAC;IAED,qBAAqB;IACrB,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACnD,SAAS,EAAE,CAAC;QACZ,OAAO;IACT,CAAC;IAED,kBAAkB;IAClB,IAAI,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QAC9B,MAAM,mBAAmB,EAAE,CAAC;QAC5B,OAAO;IACT,CAAC;IAED,qBAAqB;IACrB,IAAI,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;QACjC,MAAM,sBAAsB,EAAE,CAAC;QAC/B,OAAO;IACT,CAAC;IAED,mFAAmF;IACnF,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACxB,OAAO,CAAC,GAAG,CAAC,oDAAoD,CAAC,CAAC;QAClE,OAAO,CAAC,GAAG,CAAC,2EAA2E,CAAC,CAAC;QACzF,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;QAC5C,OAAO,CAAC,GAAG,CACT,mHAAmH,CACpH,CAAC;QACF,OAAO,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAC;QACtD,OAAO;IACT,CAAC;IAED,8DAA8D;IAC9D,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;QAClC,MAAM,OAAO,GAAG,MAAM,UAAU,EAAE,CAAC;QACnC,IAAI,OAAO,EAAE,CAAC;YACZ,iCAAiC;YACjC,MAAM,EAAE,CAAC;QACX,CAAC;IACH,CAAC;IAED,MAAM,SAAS,EAAE,CAAC;AACpB,CAAC,CAAC;AAEF,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC;IACtC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PCB Lens MCP Server
|
|
3
|
+
*
|
|
4
|
+
* Model Context Protocol server for querying IPC-2581 PCB layout files.
|
|
5
|
+
* Supports any EDA tool that exports IPC-2581 XML.
|
|
6
|
+
*/
|
|
7
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
8
|
+
/**
|
|
9
|
+
* Create and configure the MCP server.
|
|
10
|
+
*/
|
|
11
|
+
export declare const createServer: () => McpServer;
|
|
12
|
+
/**
|
|
13
|
+
* Run the MCP server with stdio transport.
|
|
14
|
+
*/
|
|
15
|
+
export declare const runServer: () => Promise<void>;
|
|
16
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA6GpE;;GAEG;AACH,eAAO,MAAM,YAAY,QAAO,SA+F/B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,SAAS,QAAa,OAAO,CAAC,IAAI,CAI9C,CAAC"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PCB Lens MCP Server
|
|
3
|
+
*
|
|
4
|
+
* Model Context Protocol server for querying IPC-2581 PCB layout files.
|
|
5
|
+
* Supports any EDA tool that exports IPC-2581 XML.
|
|
6
|
+
*/
|
|
7
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
8
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
9
|
+
import { Resvg, initWasm } from "@resvg/resvg-wasm";
|
|
10
|
+
import { readFile } from "node:fs/promises";
|
|
11
|
+
import { fileURLToPath } from "node:url";
|
|
12
|
+
import { z } from "zod";
|
|
13
|
+
import { VERSION } from "./version.js";
|
|
14
|
+
import { getDesignOverview, queryComponents, queryNet, renderNet } from "./service.js";
|
|
15
|
+
import { isErrorResult } from "./types.js";
|
|
16
|
+
// =============================================================================
|
|
17
|
+
// Server Instructions
|
|
18
|
+
// =============================================================================
|
|
19
|
+
const SERVER_INSTRUCTIONS = `
|
|
20
|
+
# PCB Lens MCP Server
|
|
21
|
+
|
|
22
|
+
This server provides tools to query IPC-2581 PCB layout files for physical design review.
|
|
23
|
+
Supports IPC-2581 XML files (RevA, RevB, RevC) exported from any compliant EDA tool.
|
|
24
|
+
|
|
25
|
+
## Workflow Guidance
|
|
26
|
+
|
|
27
|
+
1. Use \`get_design_overview\` first to understand the design structure, layer stackup, and size
|
|
28
|
+
2. Use \`query_components\` to find component placements by refdes pattern (regex)
|
|
29
|
+
3. Use \`query_net\` to trace a net's routing, trace widths, vias, and connected pins
|
|
30
|
+
4. Use \`render_net\` to visualize a net's routing geometry as SVG
|
|
31
|
+
|
|
32
|
+
## Tool Usage Tips
|
|
33
|
+
|
|
34
|
+
- All tools accept an IPC-2581 XML file path as the first argument
|
|
35
|
+
- Component refdes patterns use regex (e.g., "^U\\\\d+" for all ICs, "^C1$" for exact match)
|
|
36
|
+
- Net name patterns use regex (e.g., "DDR_D0", "^VCC", "CLK")
|
|
37
|
+
- All physical values (coordinates, trace widths) are normalized to microns regardless of the source file's native unit
|
|
38
|
+
- Rotation is in degrees counterclockwise
|
|
39
|
+
|
|
40
|
+
## Error Handling
|
|
41
|
+
|
|
42
|
+
Results with an \`error\` field indicate a problem:
|
|
43
|
+
- File not found: Check the file path
|
|
44
|
+
- No matches: Try a broader regex pattern
|
|
45
|
+
- Invalid regex: Check pattern syntax
|
|
46
|
+
`.trim();
|
|
47
|
+
// =============================================================================
|
|
48
|
+
// Helper Functions
|
|
49
|
+
// =============================================================================
|
|
50
|
+
/**
|
|
51
|
+
* Format a result as MCP tool response content.
|
|
52
|
+
*/
|
|
53
|
+
const formatResult = (result) => ({
|
|
54
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
55
|
+
});
|
|
56
|
+
let wasmInitialized = false;
|
|
57
|
+
const resolveWasmBuffer = async () => {
|
|
58
|
+
if (typeof BUILD_VERSION !== "undefined") {
|
|
59
|
+
const { default: wasmPath } = await import("./wasm-embed.js");
|
|
60
|
+
return readFile(wasmPath);
|
|
61
|
+
}
|
|
62
|
+
const wasmUrl = import.meta.resolve("@resvg/resvg-wasm/index_bg.wasm");
|
|
63
|
+
return readFile(fileURLToPath(wasmUrl));
|
|
64
|
+
};
|
|
65
|
+
const ensureWasmInitialized = async () => {
|
|
66
|
+
if (wasmInitialized)
|
|
67
|
+
return;
|
|
68
|
+
await initWasm(await resolveWasmBuffer());
|
|
69
|
+
wasmInitialized = true;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* Render SVG to PNG using resvg-wasm, return as MCP image content + stats text.
|
|
73
|
+
*/
|
|
74
|
+
const formatRenderResult = async (result) => {
|
|
75
|
+
await ensureWasmInitialized();
|
|
76
|
+
const resvg = new Resvg(result.svg, { fitTo: { mode: "width", value: 1200 } });
|
|
77
|
+
const png = resvg.render().asPng();
|
|
78
|
+
return {
|
|
79
|
+
content: [
|
|
80
|
+
{
|
|
81
|
+
type: "image",
|
|
82
|
+
data: Buffer.from(png).toString("base64"),
|
|
83
|
+
mimeType: "image/png",
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
type: "text",
|
|
87
|
+
text: JSON.stringify({ netName: result.netName, units: result.units, stats: result.stats }, null, 2),
|
|
88
|
+
},
|
|
89
|
+
],
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
// =============================================================================
|
|
93
|
+
// Server Setup
|
|
94
|
+
// =============================================================================
|
|
95
|
+
/**
|
|
96
|
+
* Create and configure the MCP server.
|
|
97
|
+
*/
|
|
98
|
+
export const createServer = () => {
|
|
99
|
+
const server = new McpServer({
|
|
100
|
+
name: "pcb-lens-mcp-server",
|
|
101
|
+
version: VERSION,
|
|
102
|
+
}, {
|
|
103
|
+
capabilities: {
|
|
104
|
+
tools: {},
|
|
105
|
+
},
|
|
106
|
+
instructions: SERVER_INSTRUCTIONS,
|
|
107
|
+
});
|
|
108
|
+
// -------------------------------------------------------------------------
|
|
109
|
+
// Tool: get_design_overview
|
|
110
|
+
// -------------------------------------------------------------------------
|
|
111
|
+
server.registerTool("get_design_overview", {
|
|
112
|
+
description: "Get an overview of an IPC-2581 PCB design file: metadata, layer stackup, component/net counts, and section sizes",
|
|
113
|
+
inputSchema: {
|
|
114
|
+
file: z.string().describe("Path to IPC-2581 XML file"),
|
|
115
|
+
},
|
|
116
|
+
}, async ({ file }) => {
|
|
117
|
+
const result = await getDesignOverview(file);
|
|
118
|
+
return formatResult(result);
|
|
119
|
+
});
|
|
120
|
+
// -------------------------------------------------------------------------
|
|
121
|
+
// Tool: query_components
|
|
122
|
+
// -------------------------------------------------------------------------
|
|
123
|
+
server.registerTool("query_components", {
|
|
124
|
+
description: "Find components by refdes pattern in an IPC-2581 file. Returns placement coordinates, rotation, layer, package, and BOM data.",
|
|
125
|
+
inputSchema: {
|
|
126
|
+
file: z.string().describe("Path to IPC-2581 XML file"),
|
|
127
|
+
pattern: z
|
|
128
|
+
.string()
|
|
129
|
+
.describe("Regex pattern for component refdes (e.g., '^U1$', '^C\\\\d+', 'R10[0-9]')"),
|
|
130
|
+
},
|
|
131
|
+
}, async ({ file, pattern }) => {
|
|
132
|
+
const result = await queryComponents(file, pattern);
|
|
133
|
+
return formatResult(result);
|
|
134
|
+
});
|
|
135
|
+
// -------------------------------------------------------------------------
|
|
136
|
+
// Tool: query_net
|
|
137
|
+
// -------------------------------------------------------------------------
|
|
138
|
+
server.registerTool("query_net", {
|
|
139
|
+
description: "Query a net by name pattern in an IPC-2581 file. Returns connected pins, routing per layer (trace widths, segment counts), and via information.",
|
|
140
|
+
inputSchema: {
|
|
141
|
+
file: z.string().describe("Path to IPC-2581 XML file"),
|
|
142
|
+
pattern: z
|
|
143
|
+
.string()
|
|
144
|
+
.describe("Regex pattern for net name (e.g., '^DDR_D0$', 'CLK', '^VCC_3V3$')"),
|
|
145
|
+
},
|
|
146
|
+
}, async ({ file, pattern }) => {
|
|
147
|
+
const result = await queryNet(file, pattern);
|
|
148
|
+
return formatResult(result);
|
|
149
|
+
});
|
|
150
|
+
// -------------------------------------------------------------------------
|
|
151
|
+
// Tool: render_net
|
|
152
|
+
// -------------------------------------------------------------------------
|
|
153
|
+
server.registerTool("render_net", {
|
|
154
|
+
description: "Render a net's routing geometry as SVG from an IPC-2581 file. Returns an SVG showing board outline, trace paths by layer, exact SMD pad shapes, via annular rings, and pin labels.",
|
|
155
|
+
inputSchema: {
|
|
156
|
+
file: z.string().describe("Path to IPC-2581 XML file"),
|
|
157
|
+
pattern: z.string().describe("Regex pattern for net name (e.g., '^VDD_3V3B$', 'CLK')"),
|
|
158
|
+
},
|
|
159
|
+
}, async ({ file, pattern }) => {
|
|
160
|
+
const result = await renderNet(file, pattern);
|
|
161
|
+
if (isErrorResult(result))
|
|
162
|
+
return formatResult(result);
|
|
163
|
+
return await formatRenderResult(result);
|
|
164
|
+
});
|
|
165
|
+
return server;
|
|
166
|
+
};
|
|
167
|
+
/**
|
|
168
|
+
* Run the MCP server with stdio transport.
|
|
169
|
+
*/
|
|
170
|
+
export const runServer = async () => {
|
|
171
|
+
const server = createServer();
|
|
172
|
+
const transport = new StdioServerTransport();
|
|
173
|
+
await server.connect(transport);
|
|
174
|
+
};
|
|
175
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|