@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.
Files changed (49) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/LICENSE +190 -0
  3. package/NOTICE +4 -0
  4. package/README.md +156 -0
  5. package/dist/cli/commands.d.ts +23 -0
  6. package/dist/cli/commands.d.ts.map +1 -0
  7. package/dist/cli/commands.js +113 -0
  8. package/dist/cli/commands.js.map +1 -0
  9. package/dist/cli/prompts.d.ts +10 -0
  10. package/dist/cli/prompts.d.ts.map +1 -0
  11. package/dist/cli/prompts.js +25 -0
  12. package/dist/cli/prompts.js.map +1 -0
  13. package/dist/cli/shell.d.ts +15 -0
  14. package/dist/cli/shell.d.ts.map +1 -0
  15. package/dist/cli/shell.js +66 -0
  16. package/dist/cli/shell.js.map +1 -0
  17. package/dist/cli/updater.d.ts +50 -0
  18. package/dist/cli/updater.d.ts.map +1 -0
  19. package/dist/cli/updater.js +305 -0
  20. package/dist/cli/updater.js.map +1 -0
  21. package/dist/index.d.ts +15 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +62 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/server.d.ts +16 -0
  26. package/dist/server.d.ts.map +1 -0
  27. package/dist/server.js +175 -0
  28. package/dist/server.js.map +1 -0
  29. package/dist/service.d.ts +13 -0
  30. package/dist/service.d.ts.map +1 -0
  31. package/dist/service.js +1139 -0
  32. package/dist/service.js.map +1 -0
  33. package/dist/types.d.ts +128 -0
  34. package/dist/types.d.ts.map +1 -0
  35. package/dist/types.js +8 -0
  36. package/dist/types.js.map +1 -0
  37. package/dist/version.d.ts +10 -0
  38. package/dist/version.d.ts.map +1 -0
  39. package/dist/version.js +25 -0
  40. package/dist/version.js.map +1 -0
  41. package/dist/wasm-embed.d.ts +3 -0
  42. package/dist/wasm-embed.d.ts.map +1 -0
  43. package/dist/wasm-embed.js +5 -0
  44. package/dist/wasm-embed.js.map +1 -0
  45. package/dist/xml-utils.d.ts +41 -0
  46. package/dist/xml-utils.d.ts.map +1 -0
  47. package/dist/xml-utils.js +81 -0
  48. package/dist/xml-utils.js.map +1 -0
  49. 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":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,iBAAiB,EACjB,SAAS,EACT,UAAU,EACV,UAAU,EACV,UAAU,EACV,WAAW,GACZ,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AA4BlE;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,GAAY,EAAE;IACxC,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACnC,OAAO,UAAU,EAAE,QAAQ,CAAC,cAAc,CAAC,IAAI,KAAK,CAAC;AACvD,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,qBAAqB,GAAG,GAAW,EAAE;IACzC,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;IAClC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAE1B,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC1B,OAAO,GAAG,WAAW,mBAAmB,CAAC;IAC3C,CAAC;SAAM,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;QAChC,OAAO,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,WAAW,cAAc,CAAC,CAAC,CAAC,GAAG,WAAW,YAAY,CAAC;IACtF,CAAC;SAAM,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;QAChC,OAAO,GAAG,WAAW,kBAAkB,CAAC;IAC1C,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,yBAAyB,QAAQ,IAAI,IAAI,EAAE,CAAC,CAAC;AAC/D,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,YAAY,GAAG,CAAC,OAAe,EAAY,EAAE;IACjD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAC1C,OAAO,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;AACnE,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,eAAe,GAAG,CAAC,CAAS,EAAE,CAAS,EAAU,EAAE;IACvD,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;IAC/B,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;IAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IAEtD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAChC,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC5B,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC5B,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAClB,OAAO,IAAI,GAAG,IAAI,CAAC;QACrB,CAAC;IACH,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,kBAAkB,GAAG,KAAK,IAA4B,EAAE;IAC5D,MAAM,GAAG,GAAG,gCAAgC,WAAW,kBAAkB,CAAC;IAC1E,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAChC,OAAO,EAAE;YACP,MAAM,EAAE,gCAAgC;YACxC,YAAY,EAAE,GAAG,WAAW,IAAI,OAAO,EAAE;SAC1C;QACD,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC;KACpC,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC5B,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACvC,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,qBAAqB,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;IACjF,CAAC;IAED,OAAO,QAAQ,CAAC,IAAI,EAA4B,CAAC;AACnD,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,IAAgC,EAAE;IACnE,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,kBAAkB,EAAE,CAAC;QAC3C,MAAM,aAAa,GAAG,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACzD,MAAM,eAAe,GAAG,eAAe,CAAC,aAAa,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;QAEpE,IAAI,WAAW,GAAkB,IAAI,CAAC;QACtC,IAAI,eAAe,EAAE,CAAC;YACpB,MAAM,UAAU,GAAG,qBAAqB,EAAE,CAAC;YAC3C,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC;YAChE,IAAI,KAAK,EAAE,CAAC;gBACV,WAAW,GAAG,KAAK,CAAC,oBAAoB,CAAC;YAC3C,CAAC;QACH,CAAC;QAED,OAAO;YACL,eAAe;YACf,cAAc,EAAE,OAAO;YACvB,aAAa;YACb,WAAW;SACZ,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO;YACL,eAAe,EAAE,KAAK;YACtB,cAAc,EAAE,OAAO;YACvB,aAAa,EAAE,IAAI;YACnB,WAAW,EAAE,IAAI;YACjB,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;SAC9D,CAAC;IACJ,CAAC;AACH,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,YAAY,GAAG,KAAK,EAAE,GAAW,EAAE,QAAgB,EAAiB,EAAE;IAC1E,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAChC,OAAO,EAAE;YACP,YAAY,EAAE,GAAG,WAAW,IAAI,OAAO,EAAE;SAC1C;QACD,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC;KACpC,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,oBAAoB,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;IAChF,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;IACtC,CAAC;IAED,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;IACjD,MAAM,UAAU,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACnD,MAAM,UAAU,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IAE/C,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC1C,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC5B,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACjC,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC/B,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,GAAW,EAAE;IACnD,0EAA0E;IAC1E,kDAAkD;IAClD,IAAI,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1E,iDAAiD;QACjD,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACzB,CAAC;IACD,iCAAiC;IACjC,OAAO,OAAO,CAAC,QAAQ,CAAC;AAC1B,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,aAAa,GAAG,CAAC,WAAmB,EAAU,EAAE;IACpD,OAAO,GAAG,WAAW,WAAW,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;AAC/C,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,iBAAiB,GAAG,CAAC,WAAmB,EAAQ,EAAE;IACtD,MAAM,GAAG,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACjC,MAAM,IAAI,GAAG,QAAQ,CAAC,WAAW,CAAC,CAAC;IACnC,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;QAC/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC;gBACvC,IAAI,CAAC;oBACH,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC;gBAC9B,CAAC;gBAAC,MAAM,CAAC;oBACP,oCAAoC;gBACtC,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,+BAA+B;IACjC,CAAC;AACH,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,EAChC,WAAmB,EACnB,UAAkB,EACK,EAAE;IACzB,MAAM,WAAW,GAAG,wBAAwB,EAAE,CAAC;IAC/C,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,GAAG,WAAW,WAAW,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACvE,oFAAoF;IACpF,MAAM,UAAU,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC;IAE9C,sEAAsE;IACtE,iBAAiB,CAAC,WAAW,CAAC,CAAC;IAE/B,IAAI,CAAC;QACH,uCAAuC;QACvC,MAAM,YAAY,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;QAE1C,kBAAkB;QAClB,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;YACjC,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAC7B,CAAC;QAED,wBAAwB;QACxB,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YAC5B,UAAU,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;QACtC,CAAC;QAED,6BAA6B;QAC7B,UAAU,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;QAElC,2DAA2D;QAC3D,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC3B,IAAI,CAAC;gBACH,UAAU,CAAC,UAAU,CAAC,CAAC;YACzB,CAAC;YAAC,MAAM,CAAC;gBACP,sDAAsD;gBACtD,uDAAuD;YACzD,CAAC;QACH,CAAC;QAED,OAAO;YACL,OAAO,EAAE,IAAI;YACb,eAAe,EAAE,OAAO;YACxB,UAAU;SACX,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,4BAA4B;QAC5B,IAAI,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YACvD,IAAI,CAAC;gBACH,UAAU,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;YACtC,CAAC;YAAC,MAAM,CAAC;gBACP,wBAAwB;YAC1B,CAAC;QACH,CAAC;QAED,qBAAqB;QACrB,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzB,IAAI,CAAC;gBACH,UAAU,CAAC,QAAQ,CAAC,CAAC;YACvB,CAAC;YAAC,MAAM,CAAC;gBACP,wBAAwB;YAC1B,CAAC;QACH,CAAC;QAED,OAAO;YACL,OAAO,EAAE,KAAK;YACd,eAAe,EAAE,OAAO;YACxB,UAAU,EAAE,IAAI;YAChB,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;SAC9D,CAAC;IACJ,CAAC;AACH,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,GAAU,EAAE;IAChC,MAAM,QAAQ,GAAG,wBAAwB,EAAE,CAAC;IAC5C,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAEnC,wBAAwB;IACxB,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE;QAClC,KAAK,EAAE,SAAS;QAChB,QAAQ,EAAE,KAAK;KAChB,CAAC,CAAC;IAEH,qCAAqC;IACrC,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;QACxB,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;IAEH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;QACxB,OAAO,CAAC,KAAK,CAAC,oBAAoB,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;QACjD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,yDAAyD;IACzD,mDAAmD;IACnD,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;AACvD,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,IAAsB,EAAE;IACrD,6DAA6D;IAC7D,IAAI,YAAY,EAAE,EAAE,CAAC;QACnB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,cAAc,EAAE,CAAC;IAErC,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QAChB,0CAA0C;QAC1C,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,CAAC,KAAK,CAAC,eAAe,IAAI,CAAC,KAAK,CAAC,WAAW,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC;QACzE,OAAO,KAAK,CAAC;IACf,CAAC;IAED,+DAA+D;IAC/D,OAAO,CAAC,KAAK,CAAC,4BAA4B,OAAO,OAAO,KAAK,CAAC,aAAa,KAAK,CAAC,CAAC;IAElF,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC;IAE3E,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,OAAO,CAAC,KAAK,CAAC,6BAA6B,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;QAC3D,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,CAAC,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAC3D,OAAO,IAAI,CAAC;AACd,CAAC,CAAC"}
@@ -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"}
@@ -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":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEvF,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,gFAAgF;AAChF,sBAAsB;AACtB,gFAAgF;AAEhF,MAAM,mBAAmB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2B3B,CAAC,IAAI,EAAE,CAAC;AAET,gFAAgF;AAChF,mBAAmB;AACnB,gFAAgF;AAEhF;;GAEG;AACH,MAAM,YAAY,GAAG,CAAC,MAAe,EAAiD,EAAE,CAAC,CAAC;IACxF,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;CACnE,CAAC,CAAC;AAIH,IAAI,eAAe,GAAG,KAAK,CAAC;AAE5B,MAAM,iBAAiB,GAAG,KAAK,IAAqB,EAAE;IACpD,IAAI,OAAO,aAAa,KAAK,WAAW,EAAE,CAAC;QACzC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,iBAAiB,CAAC,CAAC;QAC9D,OAAO,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC5B,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,iCAAiC,CAAC,CAAC;IACvE,OAAO,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC;AAC1C,CAAC,CAAC;AAEF,MAAM,qBAAqB,GAAG,KAAK,IAAmB,EAAE;IACtD,IAAI,eAAe;QAAE,OAAO;IAC5B,MAAM,QAAQ,CAAC,MAAM,iBAAiB,EAAE,CAAC,CAAC;IAC1C,eAAe,GAAG,IAAI,CAAC;AACzB,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,kBAAkB,GAAG,KAAK,EAC9B,MAAuB,EAGtB,EAAE;IACH,MAAM,qBAAqB,EAAE,CAAC;IAC9B,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;IAC/E,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC;IAEnC,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,OAAO;gBACb,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;gBACzC,QAAQ,EAAE,WAAW;aACtB;YACD;gBACE,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAClB,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,EACrE,IAAI,EACJ,CAAC,CACF;aACF;SACF;KACF,CAAC;AACJ,CAAC,CAAC;AAEF,gFAAgF;AAChF,eAAe;AACf,gFAAgF;AAEhF;;GAEG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,GAAc,EAAE;IAC1C,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B;QACE,IAAI,EAAE,qBAAqB;QAC3B,OAAO,EAAE,OAAO;KACjB,EACD;QACE,YAAY,EAAE;YACZ,KAAK,EAAE,EAAE;SACV;QACD,YAAY,EAAE,mBAAmB;KAClC,CACF,CAAC;IAEF,4EAA4E;IAC5E,4BAA4B;IAC5B,4EAA4E;IAC5E,MAAM,CAAC,YAAY,CACjB,qBAAqB,EACrB;QACE,WAAW,EACT,kHAAkH;QACpH,WAAW,EAAE;YACX,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,2BAA2B,CAAC;SACvD;KACF,EACD,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;QACjB,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,IAAI,CAAC,CAAC;QAC7C,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC;IAC9B,CAAC,CACF,CAAC;IAEF,4EAA4E;IAC5E,yBAAyB;IACzB,4EAA4E;IAC5E,MAAM,CAAC,YAAY,CACjB,kBAAkB,EAClB;QACE,WAAW,EACT,+HAA+H;QACjI,WAAW,EAAE;YACX,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,2BAA2B,CAAC;YACtD,OAAO,EAAE,CAAC;iBACP,MAAM,EAAE;iBACR,QAAQ,CAAC,2EAA2E,CAAC;SACzF;KACF,EACD,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE;QAC1B,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACpD,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC;IAC9B,CAAC,CACF,CAAC;IAEF,4EAA4E;IAC5E,kBAAkB;IAClB,4EAA4E;IAC5E,MAAM,CAAC,YAAY,CACjB,WAAW,EACX;QACE,WAAW,EACT,iJAAiJ;QACnJ,WAAW,EAAE;YACX,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,2BAA2B,CAAC;YACtD,OAAO,EAAE,CAAC;iBACP,MAAM,EAAE;iBACR,QAAQ,CAAC,mEAAmE,CAAC;SACjF;KACF,EACD,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE;QAC1B,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC7C,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC;IAC9B,CAAC,CACF,CAAC;IAEF,4EAA4E;IAC5E,mBAAmB;IACnB,4EAA4E;IAC5E,MAAM,CAAC,YAAY,CACjB,YAAY,EACZ;QACE,WAAW,EACT,oLAAoL;QACtL,WAAW,EAAE;YACX,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,2BAA2B,CAAC;YACtD,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,wDAAwD,CAAC;SACvF;KACF,EACD,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE;QAC1B,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC9C,IAAI,aAAa,CAAC,MAAM,CAAC;YAAE,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC;QACvD,OAAO,MAAM,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAC1C,CAAC,CACF,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,KAAK,IAAmB,EAAE;IACjD,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;IAC9B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC,CAAC"}