@jlcpcb/mcp 0.2.0 → 0.3.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 +57 -0
- package/README.md +19 -29
- package/dist/index.js +865 -960
- package/package.json +2 -1
- package/src/index.ts +5 -1
- package/src/schemas.ts +14 -0
- package/src/services.ts +34 -0
- package/src/tools/batch.ts +123 -0
- package/src/tools/index.test.ts +13 -0
- package/src/tools/index.ts +36 -63
- package/src/tools/library-fix.ts +1 -18
- package/src/tools/library-update.ts +8 -27
- package/src/tools/library.ts +108 -149
- package/src/tools/search.ts +68 -10
- package/src/tools/details.ts +0 -66
- package/src/tools/easyeda.ts +0 -582
package/dist/index.js
CHANGED
|
@@ -1,32 +1,48 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { createRequire } from "node:module";
|
|
3
2
|
var __create = Object.create;
|
|
4
3
|
var __getProtoOf = Object.getPrototypeOf;
|
|
5
4
|
var __defProp = Object.defineProperty;
|
|
6
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
6
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
function __accessProp(key) {
|
|
8
|
+
return this[key];
|
|
9
|
+
}
|
|
10
|
+
var __toESMCache_node;
|
|
11
|
+
var __toESMCache_esm;
|
|
8
12
|
var __toESM = (mod, isNodeMode, target) => {
|
|
13
|
+
var canCache = mod != null && typeof mod === "object";
|
|
14
|
+
if (canCache) {
|
|
15
|
+
var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
|
|
16
|
+
var cached = cache.get(mod);
|
|
17
|
+
if (cached)
|
|
18
|
+
return cached;
|
|
19
|
+
}
|
|
9
20
|
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
10
21
|
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
11
22
|
for (let key of __getOwnPropNames(mod))
|
|
12
23
|
if (!__hasOwnProp.call(to, key))
|
|
13
24
|
__defProp(to, key, {
|
|
14
|
-
get: (
|
|
25
|
+
get: __accessProp.bind(mod, key),
|
|
15
26
|
enumerable: true
|
|
16
27
|
});
|
|
28
|
+
if (canCache)
|
|
29
|
+
cache.set(mod, to);
|
|
17
30
|
return to;
|
|
18
31
|
};
|
|
19
32
|
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
33
|
+
var __returnValue = (v) => v;
|
|
34
|
+
function __exportSetter(name, newValue) {
|
|
35
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
36
|
+
}
|
|
20
37
|
var __export = (target, all) => {
|
|
21
38
|
for (var name in all)
|
|
22
39
|
__defProp(target, name, {
|
|
23
40
|
get: all[name],
|
|
24
41
|
enumerable: true,
|
|
25
42
|
configurable: true,
|
|
26
|
-
set: (
|
|
43
|
+
set: __exportSetter.bind(all, name)
|
|
27
44
|
});
|
|
28
45
|
};
|
|
29
|
-
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
30
46
|
|
|
31
47
|
// ../../node_modules/@modelcontextprotocol/sdk/node_modules/ajv/dist/compile/codegen/code.js
|
|
32
48
|
var require_code = __commonJS((exports) => {
|
|
@@ -6278,7 +6294,7 @@ var require_formats = __commonJS((exports) => {
|
|
|
6278
6294
|
}
|
|
6279
6295
|
var TIME = /^(\d\d):(\d\d):(\d\d(?:\.\d+)?)(z|([+-])(\d\d)(?::?(\d\d))?)?$/i;
|
|
6280
6296
|
function getTime(strictTimeZone) {
|
|
6281
|
-
return function
|
|
6297
|
+
return function time3(str) {
|
|
6282
6298
|
const matches = TIME.exec(str);
|
|
6283
6299
|
if (!matches)
|
|
6284
6300
|
return false;
|
|
@@ -11947,6 +11963,9 @@ var require_dist = __commonJS((exports, module) => {
|
|
|
11947
11963
|
exports.default = formatsPlugin;
|
|
11948
11964
|
});
|
|
11949
11965
|
|
|
11966
|
+
// src/index.ts
|
|
11967
|
+
import { createRequire } from "module";
|
|
11968
|
+
|
|
11950
11969
|
// ../../node_modules/zod/v3/external.js
|
|
11951
11970
|
var exports_external = {};
|
|
11952
11971
|
__export(exports_external, {
|
|
@@ -21890,31 +21909,38 @@ class StdioServerTransport {
|
|
|
21890
21909
|
}
|
|
21891
21910
|
// ../core/dist/index.js
|
|
21892
21911
|
import { readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
21893
|
-
import { existsSync } from "fs";
|
|
21894
|
-
import { join as join2 } from "path";
|
|
21895
|
-
import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir2 } from "fs/promises";
|
|
21896
21912
|
import { existsSync as existsSync2 } from "fs";
|
|
21897
21913
|
import { join as join3 } from "path";
|
|
21898
|
-
import {
|
|
21914
|
+
import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir2 } from "fs/promises";
|
|
21915
|
+
import { existsSync as existsSync3 } from "fs";
|
|
21916
|
+
import { join as join4 } from "path";
|
|
21917
|
+
import { homedir as homedir2, platform as platform2 } from "os";
|
|
21899
21918
|
import { readdir, readFile, writeFile, mkdir, access, stat } from "fs/promises";
|
|
21900
21919
|
import { join, dirname, extname, basename } from "path";
|
|
21920
|
+
import { existsSync } from "fs";
|
|
21921
|
+
import { homedir, platform } from "os";
|
|
21922
|
+
import { join as join2 } from "path";
|
|
21901
21923
|
import { execSync } from "child_process";
|
|
21902
|
-
import { existsSync as
|
|
21903
|
-
import { readFile as readFile4, readdir as readdir2 } from "fs/promises";
|
|
21904
|
-
import { homedir as
|
|
21905
|
-
import { join as
|
|
21924
|
+
import { existsSync as existsSync4 } from "fs";
|
|
21925
|
+
import { readFile as readFile4, readdir as readdir2, unlink } from "fs/promises";
|
|
21926
|
+
import { homedir as homedir3, platform as platform3 } from "os";
|
|
21927
|
+
import { join as join5 } from "path";
|
|
21906
21928
|
import { createServer } from "http";
|
|
21907
21929
|
import { readFileSync } from "fs";
|
|
21908
|
-
import { join as
|
|
21930
|
+
import { join as join6, dirname as dirname3 } from "path";
|
|
21909
21931
|
import { fileURLToPath } from "url";
|
|
21910
21932
|
var __defProp2 = Object.defineProperty;
|
|
21933
|
+
var __returnValue2 = (v) => v;
|
|
21934
|
+
function __exportSetter2(name, newValue) {
|
|
21935
|
+
this[name] = __returnValue2.bind(null, newValue);
|
|
21936
|
+
}
|
|
21911
21937
|
var __export2 = (target, all) => {
|
|
21912
21938
|
for (var name in all)
|
|
21913
21939
|
__defProp2(target, name, {
|
|
21914
21940
|
get: all[name],
|
|
21915
21941
|
enumerable: true,
|
|
21916
21942
|
configurable: true,
|
|
21917
|
-
set: (
|
|
21943
|
+
set: __exportSetter2.bind(all, name)
|
|
21918
21944
|
});
|
|
21919
21945
|
};
|
|
21920
21946
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
@@ -21934,9 +21960,16 @@ function containsKeyword(text, keyword) {
|
|
|
21934
21960
|
return false;
|
|
21935
21961
|
}
|
|
21936
21962
|
function getLibraryCategory(prefix, category, description) {
|
|
21937
|
-
const
|
|
21938
|
-
if (
|
|
21939
|
-
|
|
21963
|
+
const cleanedPrefix = prefix.replace(/[^a-zA-Z0-9]/g, "").toUpperCase();
|
|
21964
|
+
if (cleanedPrefix.length >= 2) {
|
|
21965
|
+
const twoCharPrefix = cleanedPrefix.slice(0, 2);
|
|
21966
|
+
if (PREFIX_CATEGORY_MAP[twoCharPrefix]) {
|
|
21967
|
+
return PREFIX_CATEGORY_MAP[twoCharPrefix];
|
|
21968
|
+
}
|
|
21969
|
+
}
|
|
21970
|
+
const singleCharPrefix = cleanedPrefix.slice(0, 1);
|
|
21971
|
+
if (PREFIX_CATEGORY_MAP[singleCharPrefix]) {
|
|
21972
|
+
return PREFIX_CATEGORY_MAP[singleCharPrefix];
|
|
21940
21973
|
}
|
|
21941
21974
|
const searchText = [category || "", description || ""].join(" ");
|
|
21942
21975
|
if (searchText.trim()) {
|
|
@@ -22000,6 +22033,7 @@ var init_category_router = __esm(() => {
|
|
|
22000
22033
|
X: "Crystals",
|
|
22001
22034
|
J: "Connectors",
|
|
22002
22035
|
P: "Connectors",
|
|
22036
|
+
RJ: "Connectors",
|
|
22003
22037
|
K: "Misc",
|
|
22004
22038
|
F: "Misc"
|
|
22005
22039
|
};
|
|
@@ -22245,6 +22279,48 @@ var init_category_router = __esm(() => {
|
|
|
22245
22279
|
"ceramic resonator"
|
|
22246
22280
|
]
|
|
22247
22281
|
},
|
|
22282
|
+
{
|
|
22283
|
+
category: "Connectors",
|
|
22284
|
+
keywords: [
|
|
22285
|
+
"connector",
|
|
22286
|
+
"header",
|
|
22287
|
+
"socket",
|
|
22288
|
+
"terminal",
|
|
22289
|
+
"terminal block",
|
|
22290
|
+
"jack",
|
|
22291
|
+
"plug",
|
|
22292
|
+
"receptacle",
|
|
22293
|
+
"usb-c",
|
|
22294
|
+
"usb type-c",
|
|
22295
|
+
"micro usb",
|
|
22296
|
+
"mini usb",
|
|
22297
|
+
"usb-a",
|
|
22298
|
+
"usb-b",
|
|
22299
|
+
"hdmi connector",
|
|
22300
|
+
"rj45",
|
|
22301
|
+
"rj11",
|
|
22302
|
+
"barrel jack",
|
|
22303
|
+
"dc jack",
|
|
22304
|
+
"audio jack",
|
|
22305
|
+
"jst",
|
|
22306
|
+
"jst-xh",
|
|
22307
|
+
"jst-ph",
|
|
22308
|
+
"molex",
|
|
22309
|
+
"dupont",
|
|
22310
|
+
"pin header",
|
|
22311
|
+
"female header",
|
|
22312
|
+
"fpc",
|
|
22313
|
+
"ffc",
|
|
22314
|
+
"sim card",
|
|
22315
|
+
"sd card",
|
|
22316
|
+
"microsd",
|
|
22317
|
+
"pogo pin",
|
|
22318
|
+
"spring contact",
|
|
22319
|
+
"test point",
|
|
22320
|
+
"ethernet connector",
|
|
22321
|
+
"modular connector"
|
|
22322
|
+
]
|
|
22323
|
+
},
|
|
22248
22324
|
{
|
|
22249
22325
|
category: "Transistors",
|
|
22250
22326
|
keywords: [
|
|
@@ -22345,46 +22421,6 @@ var init_category_router = __esm(() => {
|
|
|
22345
22421
|
"chip resistor"
|
|
22346
22422
|
]
|
|
22347
22423
|
},
|
|
22348
|
-
{
|
|
22349
|
-
category: "Connectors",
|
|
22350
|
-
keywords: [
|
|
22351
|
-
"connector",
|
|
22352
|
-
"header",
|
|
22353
|
-
"socket",
|
|
22354
|
-
"terminal",
|
|
22355
|
-
"terminal block",
|
|
22356
|
-
"jack",
|
|
22357
|
-
"plug",
|
|
22358
|
-
"receptacle",
|
|
22359
|
-
"usb-c",
|
|
22360
|
-
"usb type-c",
|
|
22361
|
-
"micro usb",
|
|
22362
|
-
"mini usb",
|
|
22363
|
-
"usb-a",
|
|
22364
|
-
"usb-b",
|
|
22365
|
-
"hdmi connector",
|
|
22366
|
-
"rj45",
|
|
22367
|
-
"rj11",
|
|
22368
|
-
"barrel jack",
|
|
22369
|
-
"dc jack",
|
|
22370
|
-
"audio jack",
|
|
22371
|
-
"jst",
|
|
22372
|
-
"jst-xh",
|
|
22373
|
-
"jst-ph",
|
|
22374
|
-
"molex",
|
|
22375
|
-
"dupont",
|
|
22376
|
-
"pin header",
|
|
22377
|
-
"female header",
|
|
22378
|
-
"fpc",
|
|
22379
|
-
"ffc",
|
|
22380
|
-
"sim card",
|
|
22381
|
-
"sd card",
|
|
22382
|
-
"microsd",
|
|
22383
|
-
"pogo pin",
|
|
22384
|
-
"spring contact",
|
|
22385
|
-
"test point"
|
|
22386
|
-
]
|
|
22387
|
-
},
|
|
22388
22424
|
{
|
|
22389
22425
|
category: "ICs",
|
|
22390
22426
|
keywords: [
|
|
@@ -22478,9 +22514,9 @@ function addLibraryToTable(tableContent, libraryName, libraryPath, type, descrip
|
|
|
22478
22514
|
`;
|
|
22479
22515
|
}
|
|
22480
22516
|
async function ensureSymLibTable(projectDir, symbolLibPath, libraryName = DEFAULT_LIBRARY_NAME, description = DEFAULT_LIBRARY_DESCRIPTION) {
|
|
22481
|
-
const tablePath =
|
|
22517
|
+
const tablePath = join3(projectDir, "sym-lib-table");
|
|
22482
22518
|
const relativePath = symbolLibPath.startsWith(projectDir) ? "${KIPRJMOD}" + symbolLibPath.slice(projectDir.length) : symbolLibPath;
|
|
22483
|
-
if (!
|
|
22519
|
+
if (!existsSync2(tablePath)) {
|
|
22484
22520
|
const content = generateSymLibTable(relativePath, libraryName, description);
|
|
22485
22521
|
await writeFile2(tablePath, content, "utf-8");
|
|
22486
22522
|
return { created: true, modified: false, path: tablePath };
|
|
@@ -22494,9 +22530,9 @@ async function ensureSymLibTable(projectDir, symbolLibPath, libraryName = DEFAUL
|
|
|
22494
22530
|
return { created: false, modified: true, path: tablePath };
|
|
22495
22531
|
}
|
|
22496
22532
|
async function ensureFpLibTable(projectDir, footprintLibPath, libraryName = DEFAULT_LIBRARY_NAME, description = DEFAULT_LIBRARY_DESCRIPTION) {
|
|
22497
|
-
const tablePath =
|
|
22533
|
+
const tablePath = join3(projectDir, "fp-lib-table");
|
|
22498
22534
|
const relativePath = footprintLibPath.startsWith(projectDir) ? "${KIPRJMOD}" + footprintLibPath.slice(projectDir.length) : footprintLibPath;
|
|
22499
|
-
if (!
|
|
22535
|
+
if (!existsSync2(tablePath)) {
|
|
22500
22536
|
const content = generateFpLibTable(relativePath, libraryName, description);
|
|
22501
22537
|
await writeFile2(tablePath, content, "utf-8");
|
|
22502
22538
|
return { created: true, modified: false, path: tablePath };
|
|
@@ -22520,37 +22556,37 @@ __export2(exports_global_lib_table, {
|
|
|
22520
22556
|
ensureGlobalLibraryTables: () => ensureGlobalLibraryTables,
|
|
22521
22557
|
ensureGlobalEasyEDALibrary: () => ensureGlobalEasyEDALibrary
|
|
22522
22558
|
});
|
|
22523
|
-
function
|
|
22524
|
-
const home =
|
|
22525
|
-
const baseDir =
|
|
22559
|
+
function detectKicadVersion2() {
|
|
22560
|
+
const home = homedir2();
|
|
22561
|
+
const baseDir = join4(home, "Documents", "KiCad");
|
|
22526
22562
|
for (const version2 of KICAD_VERSIONS2) {
|
|
22527
|
-
if (
|
|
22563
|
+
if (existsSync3(join4(baseDir, version2))) {
|
|
22528
22564
|
return version2;
|
|
22529
22565
|
}
|
|
22530
22566
|
}
|
|
22531
22567
|
return "9.0";
|
|
22532
22568
|
}
|
|
22533
|
-
function
|
|
22534
|
-
const home =
|
|
22535
|
-
const plat =
|
|
22569
|
+
function getKicadConfigDir2(version2) {
|
|
22570
|
+
const home = homedir2();
|
|
22571
|
+
const plat = platform2();
|
|
22536
22572
|
if (plat === "darwin") {
|
|
22537
|
-
return
|
|
22573
|
+
return join4(home, "Library", "Preferences", "kicad", version2);
|
|
22538
22574
|
} else if (plat === "win32") {
|
|
22539
|
-
return
|
|
22575
|
+
return join4(process.env.APPDATA || join4(home, "AppData", "Roaming"), "kicad", version2);
|
|
22540
22576
|
} else {
|
|
22541
|
-
return
|
|
22577
|
+
return join4(home, ".config", "kicad", version2);
|
|
22542
22578
|
}
|
|
22543
22579
|
}
|
|
22544
22580
|
function get3rdPartyBaseDir(version2) {
|
|
22545
|
-
const home =
|
|
22546
|
-
const plat =
|
|
22581
|
+
const home = homedir2();
|
|
22582
|
+
const plat = platform2();
|
|
22547
22583
|
if (plat === "linux") {
|
|
22548
|
-
return
|
|
22584
|
+
return join4(home, ".local", "share", "kicad", version2, "3rdparty", LIBRARY_NAMESPACE);
|
|
22549
22585
|
}
|
|
22550
|
-
return
|
|
22586
|
+
return join4(home, "Documents", "KiCad", version2, "3rdparty", LIBRARY_NAMESPACE);
|
|
22551
22587
|
}
|
|
22552
22588
|
function getSymbolLibPath(category, version2) {
|
|
22553
|
-
return
|
|
22589
|
+
return join4(get3rdPartyBaseDir(version2), "symbols", getLibraryFilename(category));
|
|
22554
22590
|
}
|
|
22555
22591
|
function getSymbolLibUri(category) {
|
|
22556
22592
|
return `${KICAD_3RD_PARTY_VAR}/${LIBRARY_NAMESPACE}/symbols/${getLibraryFilename(category)}`;
|
|
@@ -22591,11 +22627,11 @@ function generateFpLibTable2() {
|
|
|
22591
22627
|
`;
|
|
22592
22628
|
}
|
|
22593
22629
|
async function ensureGlobalSymLibTable(version2) {
|
|
22594
|
-
const configDir =
|
|
22595
|
-
const tablePath =
|
|
22630
|
+
const configDir = getKicadConfigDir2(version2);
|
|
22631
|
+
const tablePath = join4(configDir, "sym-lib-table");
|
|
22596
22632
|
const categories = getAllCategories();
|
|
22597
22633
|
await mkdir2(configDir, { recursive: true });
|
|
22598
|
-
if (!
|
|
22634
|
+
if (!existsSync3(tablePath)) {
|
|
22599
22635
|
const content2 = generateSymLibTable2();
|
|
22600
22636
|
await writeFile3(tablePath, content2, "utf-8");
|
|
22601
22637
|
return {
|
|
@@ -22635,11 +22671,11 @@ async function ensureGlobalSymLibTable(version2) {
|
|
|
22635
22671
|
};
|
|
22636
22672
|
}
|
|
22637
22673
|
async function ensureGlobalFpLibTable(version2) {
|
|
22638
|
-
const configDir =
|
|
22639
|
-
const tablePath =
|
|
22674
|
+
const configDir = getKicadConfigDir2(version2);
|
|
22675
|
+
const tablePath = join4(configDir, "fp-lib-table");
|
|
22640
22676
|
const name = LIBRARY_PREFIX2;
|
|
22641
22677
|
await mkdir2(configDir, { recursive: true });
|
|
22642
|
-
if (!
|
|
22678
|
+
if (!existsSync3(tablePath)) {
|
|
22643
22679
|
const content2 = generateFpLibTable2();
|
|
22644
22680
|
await writeFile3(tablePath, content2, "utf-8");
|
|
22645
22681
|
return {
|
|
@@ -22673,13 +22709,13 @@ async function ensureGlobalFpLibTable(version2) {
|
|
|
22673
22709
|
}
|
|
22674
22710
|
async function ensureLibraryStubs(version2) {
|
|
22675
22711
|
const baseDir = get3rdPartyBaseDir(version2);
|
|
22676
|
-
const symbolsDir =
|
|
22677
|
-
const footprintsDir =
|
|
22678
|
-
const models3dDir =
|
|
22712
|
+
const symbolsDir = join4(baseDir, "symbols");
|
|
22713
|
+
const footprintsDir = join4(baseDir, "footprints", getFootprintDirName());
|
|
22714
|
+
const models3dDir = join4(baseDir, "3dmodels", get3DModelsDirName());
|
|
22679
22715
|
const directoriesCreated = [];
|
|
22680
22716
|
const symbolsCreated = [];
|
|
22681
22717
|
for (const dir of [symbolsDir, footprintsDir, models3dDir]) {
|
|
22682
|
-
if (!
|
|
22718
|
+
if (!existsSync3(dir)) {
|
|
22683
22719
|
await mkdir2(dir, { recursive: true });
|
|
22684
22720
|
directoriesCreated.push(dir);
|
|
22685
22721
|
}
|
|
@@ -22688,7 +22724,7 @@ async function ensureLibraryStubs(version2) {
|
|
|
22688
22724
|
const emptyContent = generateEmptySymbolLibrary();
|
|
22689
22725
|
for (const category of categories) {
|
|
22690
22726
|
const filePath = getSymbolLibPath(category, version2);
|
|
22691
|
-
if (!
|
|
22727
|
+
if (!existsSync3(filePath)) {
|
|
22692
22728
|
await writeFile3(filePath, emptyContent, "utf-8");
|
|
22693
22729
|
symbolsCreated.push(filePath);
|
|
22694
22730
|
}
|
|
@@ -22702,11 +22738,11 @@ function getEasyEDAFootprintLibUri() {
|
|
|
22702
22738
|
return `${KICAD_3RD_PARTY_VAR}/${LIBRARY_NAMESPACE}/footprints/${EASYEDA_FOOTPRINT_LIBRARY_NAME}`;
|
|
22703
22739
|
}
|
|
22704
22740
|
async function ensureGlobalEasyEDALibrary() {
|
|
22705
|
-
const version2 =
|
|
22706
|
-
const configDir =
|
|
22741
|
+
const version2 = detectKicadVersion2();
|
|
22742
|
+
const configDir = getKicadConfigDir2(version2);
|
|
22707
22743
|
await mkdir2(configDir, { recursive: true });
|
|
22708
|
-
const symTablePath =
|
|
22709
|
-
if (
|
|
22744
|
+
const symTablePath = join4(configDir, "sym-lib-table");
|
|
22745
|
+
if (existsSync3(symTablePath)) {
|
|
22710
22746
|
let content = await readFile3(symTablePath, "utf-8");
|
|
22711
22747
|
if (!libraryExistsInTable(content, EASYEDA_LIBRARY_NAME)) {
|
|
22712
22748
|
const uri = getEasyEDASymbolLibUri();
|
|
@@ -22722,8 +22758,8 @@ async function ensureGlobalEasyEDALibrary() {
|
|
|
22722
22758
|
`;
|
|
22723
22759
|
await writeFile3(symTablePath, content, "utf-8");
|
|
22724
22760
|
}
|
|
22725
|
-
const fpTablePath =
|
|
22726
|
-
if (
|
|
22761
|
+
const fpTablePath = join4(configDir, "fp-lib-table");
|
|
22762
|
+
if (existsSync3(fpTablePath)) {
|
|
22727
22763
|
let content = await readFile3(fpTablePath, "utf-8");
|
|
22728
22764
|
if (!libraryExistsInTable(content, EASYEDA_LIBRARY_NAME)) {
|
|
22729
22765
|
const uri = getEasyEDAFootprintLibUri();
|
|
@@ -22742,7 +22778,7 @@ async function ensureGlobalEasyEDALibrary() {
|
|
|
22742
22778
|
}
|
|
22743
22779
|
async function ensureGlobalLibraryTables() {
|
|
22744
22780
|
const errors22 = [];
|
|
22745
|
-
const version2 =
|
|
22781
|
+
const version2 = detectKicadVersion2();
|
|
22746
22782
|
let symLibTable = {
|
|
22747
22783
|
path: "",
|
|
22748
22784
|
created: false,
|
|
@@ -26770,6 +26806,9 @@ var coerce2 = {
|
|
|
26770
26806
|
};
|
|
26771
26807
|
var NEVER3 = INVALID2;
|
|
26772
26808
|
var LCSCPartNumberSchema = exports_external2.string().regex(/^C\d+$/, "Invalid LCSC part number format (expected C followed by digits)");
|
|
26809
|
+
var EasyEDAUuidSchema = exports_external2.string().regex(/^[a-f0-9]{32}$/i, "Invalid EasyEDA UUID (expected 32-character hex string)").transform((s) => s.toLowerCase());
|
|
26810
|
+
var ComponentIdSchema = exports_external2.union([LCSCPartNumberSchema, EasyEDAUuidSchema]);
|
|
26811
|
+
var SafePathSchema = exports_external2.string().min(1, "Path cannot be empty").refine((p) => !p.includes(".."), "Path traversal (..) not allowed").refine((p) => !p.includes("\x00"), "Null bytes not allowed in path");
|
|
26773
26812
|
var PackageSchema = exports_external2.string().min(1, "Package cannot be empty");
|
|
26774
26813
|
var PriceTierSchema = exports_external2.object({
|
|
26775
26814
|
quantity: exports_external2.number().positive(),
|
|
@@ -26845,6 +26884,9 @@ var KiCadPadShapeSchema = exports_external2.enum([
|
|
|
26845
26884
|
"roundrect",
|
|
26846
26885
|
"custom"
|
|
26847
26886
|
]);
|
|
26887
|
+
function isLcscId(id) {
|
|
26888
|
+
return LCSCPartNumberSchema.safeParse(id).success;
|
|
26889
|
+
}
|
|
26848
26890
|
async function ensureDir(path) {
|
|
26849
26891
|
await mkdir(path, { recursive: true });
|
|
26850
26892
|
}
|
|
@@ -26926,7 +26968,58 @@ var logger = new Logger({ prefix: "ai-eda" });
|
|
|
26926
26968
|
function createLogger(packageName) {
|
|
26927
26969
|
return logger.child(packageName);
|
|
26928
26970
|
}
|
|
26971
|
+
var KICAD_LAYERS = {
|
|
26972
|
+
F_CU: "F.Cu",
|
|
26973
|
+
B_CU: "B.Cu",
|
|
26974
|
+
IN1_CU: "In1.Cu",
|
|
26975
|
+
IN2_CU: "In2.Cu",
|
|
26976
|
+
IN3_CU: "In3.Cu",
|
|
26977
|
+
IN4_CU: "In4.Cu",
|
|
26978
|
+
F_ADHES: "F.Adhes",
|
|
26979
|
+
F_PASTE: "F.Paste",
|
|
26980
|
+
F_SILKS: "F.SilkS",
|
|
26981
|
+
F_MASK: "F.Mask",
|
|
26982
|
+
F_CRTYD: "F.CrtYd",
|
|
26983
|
+
F_FAB: "F.Fab",
|
|
26984
|
+
B_ADHES: "B.Adhes",
|
|
26985
|
+
B_PASTE: "B.Paste",
|
|
26986
|
+
B_SILKS: "B.SilkS",
|
|
26987
|
+
B_MASK: "B.Mask",
|
|
26988
|
+
B_CRTYD: "B.CrtYd",
|
|
26989
|
+
B_FAB: "B.Fab",
|
|
26990
|
+
EDGE_CUTS: "Edge.Cuts",
|
|
26991
|
+
MARGIN: "Margin",
|
|
26992
|
+
DWGS_USER: "Dwgs.User",
|
|
26993
|
+
CMTS_USER: "Cmts.User",
|
|
26994
|
+
ECO1_USER: "Eco1.User",
|
|
26995
|
+
ECO2_USER: "Eco2.User"
|
|
26996
|
+
};
|
|
26997
|
+
var KICAD_DEFAULTS = {
|
|
26998
|
+
TEXT_SIZE: 1.27,
|
|
26999
|
+
TEXT_THICKNESS: 0.15,
|
|
27000
|
+
WIRE_WIDTH: 0.25,
|
|
27001
|
+
GRID_SCHEMATIC: 2.54,
|
|
27002
|
+
GRID_PCB: 0.25,
|
|
27003
|
+
PIN_LENGTH: 1.27,
|
|
27004
|
+
PIN_NAME_OFFSET: 0
|
|
27005
|
+
};
|
|
27006
|
+
var KICAD_SYMBOL_VERSION = "20241209";
|
|
27007
|
+
var KICAD_FOOTPRINT_VERSION = "20241209";
|
|
27008
|
+
var KICAD_VERSIONS = ["9.0", "8.0"];
|
|
27009
|
+
function detectKicadVersion() {
|
|
27010
|
+
const home = homedir();
|
|
27011
|
+
const baseDir = join2(home, "Documents", "KiCad");
|
|
27012
|
+
for (const version2 of KICAD_VERSIONS) {
|
|
27013
|
+
if (existsSync(join2(baseDir, version2))) {
|
|
27014
|
+
return version2;
|
|
27015
|
+
}
|
|
27016
|
+
}
|
|
27017
|
+
return "9.0";
|
|
27018
|
+
}
|
|
26929
27019
|
var logger3 = createLogger("jlc-api");
|
|
27020
|
+
function stripTemperaturePrefix(description) {
|
|
27021
|
+
return description.replace(/^-?\d+℃~[+-]?\d+℃\s*/, "");
|
|
27022
|
+
}
|
|
26930
27023
|
var JLCPCB_SEARCH_API = "https://jlcpcb.com/api/overseas-pcb-order/v1/shoppingCart/smtGood/selectSmtComponentList/v2";
|
|
26931
27024
|
|
|
26932
27025
|
class JLCClient {
|
|
@@ -26972,7 +27065,7 @@ class JLCClient {
|
|
|
26972
27065
|
package: c.componentSpecificationEn || "",
|
|
26973
27066
|
price: c.componentPrices?.[0]?.productPrice,
|
|
26974
27067
|
stock: c.stockCount,
|
|
26975
|
-
description: c.describe,
|
|
27068
|
+
description: stripTemperaturePrefix(c.describe),
|
|
26976
27069
|
productUrl: c.lcscGoodsUrl,
|
|
26977
27070
|
datasheetPdf: c.dataManualUrl,
|
|
26978
27071
|
category: c.componentTypeEn,
|
|
@@ -27079,6 +27172,34 @@ function safeParseInt(value, defaultValue = 0) {
|
|
|
27079
27172
|
const parsed = parseInt(value, 10);
|
|
27080
27173
|
return isNaN(parsed) ? defaultValue : parsed;
|
|
27081
27174
|
}
|
|
27175
|
+
function parse3DModelNode(data) {
|
|
27176
|
+
try {
|
|
27177
|
+
const jsonStr = data.slice("SVGNODE~".length);
|
|
27178
|
+
const svgData = JSON.parse(jsonStr);
|
|
27179
|
+
const attrs = svgData?.attrs;
|
|
27180
|
+
if (!attrs?.uuid) {
|
|
27181
|
+
return;
|
|
27182
|
+
}
|
|
27183
|
+
const [translationX, translationY] = String(attrs.c_origin ?? "0,0").split(",").map((value) => safeParseFloat(value));
|
|
27184
|
+
const [rotationX, rotationY, rotationZ] = String(attrs.c_rotation ?? "0,0,0").split(",").map((value) => safeParseFloat(value));
|
|
27185
|
+
return {
|
|
27186
|
+
name: attrs.title || "3D Model",
|
|
27187
|
+
uuid: attrs.uuid,
|
|
27188
|
+
translation: {
|
|
27189
|
+
x: translationX,
|
|
27190
|
+
y: translationY,
|
|
27191
|
+
z: safeParseFloat(String(attrs.z ?? "0"))
|
|
27192
|
+
},
|
|
27193
|
+
rotation: {
|
|
27194
|
+
x: rotationX,
|
|
27195
|
+
y: rotationY,
|
|
27196
|
+
z: rotationZ
|
|
27197
|
+
}
|
|
27198
|
+
};
|
|
27199
|
+
} catch {
|
|
27200
|
+
return;
|
|
27201
|
+
}
|
|
27202
|
+
}
|
|
27082
27203
|
function parseSymbolPin(pinData) {
|
|
27083
27204
|
try {
|
|
27084
27205
|
const segments = pinData.split("^^");
|
|
@@ -27212,6 +27333,25 @@ function parseSymbolPath(data) {
|
|
|
27212
27333
|
return null;
|
|
27213
27334
|
}
|
|
27214
27335
|
}
|
|
27336
|
+
function parseSymbolText(data) {
|
|
27337
|
+
try {
|
|
27338
|
+
const f = data.split("~");
|
|
27339
|
+
const isPinPart = f[f.length - 1] === "pinpart" || f.some((field) => field === "pinpart");
|
|
27340
|
+
return {
|
|
27341
|
+
x: safeParseFloat(f[2]),
|
|
27342
|
+
y: safeParseFloat(f[3]),
|
|
27343
|
+
rotation: safeParseFloat(f[4]),
|
|
27344
|
+
color: f[5] || "#000000",
|
|
27345
|
+
fontSize: safeParseFloat(f[7], 7),
|
|
27346
|
+
textType: f[11] || "",
|
|
27347
|
+
text: f[12] || "",
|
|
27348
|
+
id: f[15] || f[13] || "",
|
|
27349
|
+
isPinPart
|
|
27350
|
+
};
|
|
27351
|
+
} catch {
|
|
27352
|
+
return null;
|
|
27353
|
+
}
|
|
27354
|
+
}
|
|
27215
27355
|
function parsePad(data) {
|
|
27216
27356
|
try {
|
|
27217
27357
|
const f = data.split("~");
|
|
@@ -27379,6 +27519,7 @@ function parseSymbolShapes(shapes) {
|
|
|
27379
27519
|
const polylines = [];
|
|
27380
27520
|
const polygons = [];
|
|
27381
27521
|
const paths = [];
|
|
27522
|
+
const texts = [];
|
|
27382
27523
|
for (const line of shapes) {
|
|
27383
27524
|
if (typeof line !== "string")
|
|
27384
27525
|
continue;
|
|
@@ -27432,10 +27573,15 @@ function parseSymbolShapes(shapes) {
|
|
|
27432
27573
|
paths.push(path);
|
|
27433
27574
|
break;
|
|
27434
27575
|
}
|
|
27435
|
-
case "T":
|
|
27576
|
+
case "T": {
|
|
27577
|
+
const text = parseSymbolText(line);
|
|
27578
|
+
if (text && text.text.trim())
|
|
27579
|
+
texts.push(text);
|
|
27436
27580
|
break;
|
|
27581
|
+
}
|
|
27437
27582
|
}
|
|
27438
27583
|
}
|
|
27584
|
+
associatePinNamesFromTexts(pins, texts);
|
|
27439
27585
|
return {
|
|
27440
27586
|
pins,
|
|
27441
27587
|
rectangles,
|
|
@@ -27444,8 +27590,29 @@ function parseSymbolShapes(shapes) {
|
|
|
27444
27590
|
arcs,
|
|
27445
27591
|
polylines,
|
|
27446
27592
|
polygons,
|
|
27447
|
-
paths
|
|
27448
|
-
|
|
27593
|
+
paths,
|
|
27594
|
+
texts
|
|
27595
|
+
};
|
|
27596
|
+
}
|
|
27597
|
+
function associatePinNamesFromTexts(pins, texts) {
|
|
27598
|
+
const pinpartTexts = texts.filter((t) => t.isPinPart && t.text.trim());
|
|
27599
|
+
for (const text of pinpartTexts) {
|
|
27600
|
+
const textContent = text.text.trim();
|
|
27601
|
+
const jMatch = textContent.match(/^J(\d+)(?:\/(.+))?$/i);
|
|
27602
|
+
if (jMatch) {
|
|
27603
|
+
const pinNum = jMatch[1];
|
|
27604
|
+
const pinFunction = jMatch[2] || textContent;
|
|
27605
|
+
const pin = pins.find((p) => p.number === pinNum);
|
|
27606
|
+
if (pin && (!pin.name || pin.name === pinNum)) {
|
|
27607
|
+
pin.name = pinFunction || textContent;
|
|
27608
|
+
}
|
|
27609
|
+
continue;
|
|
27610
|
+
}
|
|
27611
|
+
const numMatch = textContent.match(/^(\d+)$/);
|
|
27612
|
+
if (numMatch) {
|
|
27613
|
+
continue;
|
|
27614
|
+
}
|
|
27615
|
+
}
|
|
27449
27616
|
}
|
|
27450
27617
|
function parseFootprintShapes(shapes) {
|
|
27451
27618
|
const pads = [];
|
|
@@ -27512,16 +27679,10 @@ function parseFootprintShapes(shapes) {
|
|
|
27512
27679
|
break;
|
|
27513
27680
|
}
|
|
27514
27681
|
case "SVGNODE": {
|
|
27515
|
-
|
|
27516
|
-
|
|
27517
|
-
|
|
27518
|
-
|
|
27519
|
-
model3d = {
|
|
27520
|
-
name: svgData.attrs.title || "3D Model",
|
|
27521
|
-
uuid: svgData.attrs.uuid
|
|
27522
|
-
};
|
|
27523
|
-
}
|
|
27524
|
-
} catch {}
|
|
27682
|
+
const parsedModel3d = parse3DModelNode(line);
|
|
27683
|
+
if (parsedModel3d) {
|
|
27684
|
+
model3d = parsedModel3d;
|
|
27685
|
+
}
|
|
27525
27686
|
break;
|
|
27526
27687
|
}
|
|
27527
27688
|
case "SOLIDREGION": {
|
|
@@ -27633,6 +27794,7 @@ class EasyEDAClient {
|
|
|
27633
27794
|
polylines: symbolData.polylines,
|
|
27634
27795
|
polygons: symbolData.polygons,
|
|
27635
27796
|
paths: symbolData.paths,
|
|
27797
|
+
texts: symbolData.texts,
|
|
27636
27798
|
origin: symbolOrigin
|
|
27637
27799
|
},
|
|
27638
27800
|
footprint: {
|
|
@@ -27806,6 +27968,7 @@ class EasyEDACommunityClient {
|
|
|
27806
27968
|
polylines: symbolData.polylines,
|
|
27807
27969
|
polygons: symbolData.polygons,
|
|
27808
27970
|
paths: symbolData.paths,
|
|
27971
|
+
texts: symbolData.texts,
|
|
27809
27972
|
origin: symbolOrigin,
|
|
27810
27973
|
head: dataStr.head || {}
|
|
27811
27974
|
},
|
|
@@ -27832,14 +27995,14 @@ class EasyEDACommunityClient {
|
|
|
27832
27995
|
}
|
|
27833
27996
|
}
|
|
27834
27997
|
var easyedaCommunityClient = new EasyEDACommunityClient;
|
|
27835
|
-
function
|
|
27998
|
+
function isLcscId2(id) {
|
|
27836
27999
|
return /^C\d+$/.test(id);
|
|
27837
28000
|
}
|
|
27838
28001
|
function createComponentService() {
|
|
27839
28002
|
return {
|
|
27840
28003
|
async search(query, options = {}) {
|
|
27841
28004
|
const { source = "lcsc", limit = 20, inStock, basicOnly } = options;
|
|
27842
|
-
if (source === "easyeda-community") {
|
|
28005
|
+
if (source === "community" || source === "easyeda-community") {
|
|
27843
28006
|
const results = await easyedaCommunityClient.search({
|
|
27844
28007
|
query,
|
|
27845
28008
|
limit
|
|
@@ -27856,7 +28019,7 @@ function createComponentService() {
|
|
|
27856
28019
|
return jlcClient.search(query, { limit, inStock, basicOnly });
|
|
27857
28020
|
},
|
|
27858
28021
|
async fetch(id) {
|
|
27859
|
-
if (
|
|
28022
|
+
if (isLcscId2(id)) {
|
|
27860
28023
|
return easyedaClient.getComponentData(id);
|
|
27861
28024
|
}
|
|
27862
28025
|
return null;
|
|
@@ -27884,43 +28047,6 @@ function createComponentService() {
|
|
|
27884
28047
|
}
|
|
27885
28048
|
};
|
|
27886
28049
|
}
|
|
27887
|
-
var KICAD_LAYERS = {
|
|
27888
|
-
F_CU: "F.Cu",
|
|
27889
|
-
B_CU: "B.Cu",
|
|
27890
|
-
IN1_CU: "In1.Cu",
|
|
27891
|
-
IN2_CU: "In2.Cu",
|
|
27892
|
-
IN3_CU: "In3.Cu",
|
|
27893
|
-
IN4_CU: "In4.Cu",
|
|
27894
|
-
F_ADHES: "F.Adhes",
|
|
27895
|
-
F_PASTE: "F.Paste",
|
|
27896
|
-
F_SILKS: "F.SilkS",
|
|
27897
|
-
F_MASK: "F.Mask",
|
|
27898
|
-
F_CRTYD: "F.CrtYd",
|
|
27899
|
-
F_FAB: "F.Fab",
|
|
27900
|
-
B_ADHES: "B.Adhes",
|
|
27901
|
-
B_PASTE: "B.Paste",
|
|
27902
|
-
B_SILKS: "B.SilkS",
|
|
27903
|
-
B_MASK: "B.Mask",
|
|
27904
|
-
B_CRTYD: "B.CrtYd",
|
|
27905
|
-
B_FAB: "B.Fab",
|
|
27906
|
-
EDGE_CUTS: "Edge.Cuts",
|
|
27907
|
-
MARGIN: "Margin",
|
|
27908
|
-
DWGS_USER: "Dwgs.User",
|
|
27909
|
-
CMTS_USER: "Cmts.User",
|
|
27910
|
-
ECO1_USER: "Eco1.User",
|
|
27911
|
-
ECO2_USER: "Eco2.User"
|
|
27912
|
-
};
|
|
27913
|
-
var KICAD_DEFAULTS = {
|
|
27914
|
-
TEXT_SIZE: 1.27,
|
|
27915
|
-
TEXT_THICKNESS: 0.15,
|
|
27916
|
-
WIRE_WIDTH: 0.25,
|
|
27917
|
-
GRID_SCHEMATIC: 2.54,
|
|
27918
|
-
GRID_PCB: 0.25,
|
|
27919
|
-
PIN_LENGTH: 1.27,
|
|
27920
|
-
PIN_NAME_OFFSET: 0
|
|
27921
|
-
};
|
|
27922
|
-
var KICAD_SYMBOL_VERSION = "20241209";
|
|
27923
|
-
var KICAD_FOOTPRINT_VERSION = "20241209";
|
|
27924
28050
|
var PATTERNS = {
|
|
27925
28051
|
resistor: /(\d+(?:\.\d+)?)\s*([kKmMgGrR]?)\s*(?:ohm|Ohm|OHM|Ω|R)?/i,
|
|
27926
28052
|
capacitor: /(\d+(?:\.\d+)?)\s*([pnuμmM]?)[Ff]?\s*(?:[\/\s]*(\d+)\s*[Vv])?/i,
|
|
@@ -28330,6 +28456,29 @@ function parseSvgArcPath(path) {
|
|
|
28330
28456
|
return null;
|
|
28331
28457
|
}
|
|
28332
28458
|
}
|
|
28459
|
+
function interpolateArc(params, segmentsPerQuarter = 4) {
|
|
28460
|
+
const center = svgArcToCenter(params);
|
|
28461
|
+
if (!center) {
|
|
28462
|
+
return [{ x: params.x2, y: params.y2 }];
|
|
28463
|
+
}
|
|
28464
|
+
const { cx, cy, rx, ry, startAngle, deltaAngle } = center;
|
|
28465
|
+
const phiRad = params.phi * Math.PI / 180;
|
|
28466
|
+
const cosPhi = Math.cos(phiRad);
|
|
28467
|
+
const sinPhi = Math.sin(phiRad);
|
|
28468
|
+
const arcDegrees = Math.abs(deltaAngle) * (180 / Math.PI);
|
|
28469
|
+
const numSegments = Math.max(2, Math.ceil(arcDegrees / 90 * segmentsPerQuarter));
|
|
28470
|
+
const points = [];
|
|
28471
|
+
for (let i = 1;i <= numSegments; i++) {
|
|
28472
|
+
const t = i / numSegments;
|
|
28473
|
+
const angle = startAngle + deltaAngle * t;
|
|
28474
|
+
const px = rx * Math.cos(angle);
|
|
28475
|
+
const py = ry * Math.sin(angle);
|
|
28476
|
+
const x = cosPhi * px - sinPhi * py + cx;
|
|
28477
|
+
const y = sinPhi * px + cosPhi * py + cy;
|
|
28478
|
+
points.push({ x, y });
|
|
28479
|
+
}
|
|
28480
|
+
return points;
|
|
28481
|
+
}
|
|
28333
28482
|
var CATEGORY_TO_PREFIX = {
|
|
28334
28483
|
Resistors: "R",
|
|
28335
28484
|
Capacitors: "C",
|
|
@@ -28392,7 +28541,12 @@ class SymbolConverter {
|
|
|
28392
28541
|
return output;
|
|
28393
28542
|
}
|
|
28394
28543
|
hasRenderableShapes(symbol) {
|
|
28395
|
-
|
|
28544
|
+
const pinNamePattern = /^J\d+(?:\/|$)/i;
|
|
28545
|
+
const hasDecorativeText = (symbol.texts || []).some((t) => {
|
|
28546
|
+
const text = t.text.trim();
|
|
28547
|
+
return text && !pinNamePattern.test(text);
|
|
28548
|
+
});
|
|
28549
|
+
return symbol.rectangles.length > 0 || symbol.circles.length > 0 || symbol.ellipses.length > 0 || symbol.polylines.length > 0 || symbol.polygons.length > 0 || symbol.arcs.length > 0 || symbol.paths.length > 0 || hasDecorativeText;
|
|
28396
28550
|
}
|
|
28397
28551
|
generateFromShapes(component, name) {
|
|
28398
28552
|
const { info, symbol } = component;
|
|
@@ -28426,6 +28580,18 @@ class SymbolConverter {
|
|
|
28426
28580
|
if (pathOutput)
|
|
28427
28581
|
output += pathOutput;
|
|
28428
28582
|
}
|
|
28583
|
+
const pinNamePattern = /^J\d+(?:\/|$)/i;
|
|
28584
|
+
const decorativeTexts = (symbol.texts || []).filter((t) => {
|
|
28585
|
+
const text = t.text.trim();
|
|
28586
|
+
if (!text)
|
|
28587
|
+
return false;
|
|
28588
|
+
return !pinNamePattern.test(text);
|
|
28589
|
+
});
|
|
28590
|
+
for (const text of decorativeTexts) {
|
|
28591
|
+
const textOutput = this.convertText(text, origin);
|
|
28592
|
+
if (textOutput)
|
|
28593
|
+
output += textOutput;
|
|
28594
|
+
}
|
|
28429
28595
|
output += ` )
|
|
28430
28596
|
`;
|
|
28431
28597
|
output += ` (symbol "${name}_1_1"
|
|
@@ -28610,6 +28776,24 @@ class SymbolConverter {
|
|
|
28610
28776
|
`;
|
|
28611
28777
|
return output;
|
|
28612
28778
|
}
|
|
28779
|
+
convertText(text, origin) {
|
|
28780
|
+
if (!text.text || text.text.trim() === "")
|
|
28781
|
+
return null;
|
|
28782
|
+
const x = this.convertX(text.x, origin.x);
|
|
28783
|
+
const y = this.convertY(text.y, origin.y);
|
|
28784
|
+
const fontSize = roundTo(Math.max(text.fontSize * EE_TO_MM * 0.8, 0.5), 3);
|
|
28785
|
+
const rotation = (360 - text.rotation) % 360;
|
|
28786
|
+
const content = text.text.replace(/"/g, "'").replace(/\\/g, "");
|
|
28787
|
+
return ` (text "${content}"
|
|
28788
|
+
(at ${x} ${y} ${rotation})
|
|
28789
|
+
(effects
|
|
28790
|
+
(font
|
|
28791
|
+
(size ${fontSize} ${fontSize})
|
|
28792
|
+
)
|
|
28793
|
+
)
|
|
28794
|
+
)
|
|
28795
|
+
`;
|
|
28796
|
+
}
|
|
28613
28797
|
parseSvgPath(pathStr, origin) {
|
|
28614
28798
|
const points = [];
|
|
28615
28799
|
let firstPoint = null;
|
|
@@ -29606,6 +29790,9 @@ var KI_PAD_SHAPE = {
|
|
|
29606
29790
|
OVAL: "oval",
|
|
29607
29791
|
POLYGON: "custom"
|
|
29608
29792
|
};
|
|
29793
|
+
function normalize3DModelRotation(rotation) {
|
|
29794
|
+
return ((360 - rotation) % 360 + 360) % 360;
|
|
29795
|
+
}
|
|
29609
29796
|
function calculatePadCenter(pads) {
|
|
29610
29797
|
if (pads.length === 0) {
|
|
29611
29798
|
return { x: 0, y: 0 };
|
|
@@ -29734,7 +29921,7 @@ class FootprintConverter {
|
|
|
29734
29921
|
output += ` (embedded_fonts no)
|
|
29735
29922
|
`;
|
|
29736
29923
|
if (include3DModel && model3d && options.modelPath) {
|
|
29737
|
-
output += this.generate3DModel(options.modelPath);
|
|
29924
|
+
output += this.generate3DModel(options.modelPath, model3d, origin);
|
|
29738
29925
|
}
|
|
29739
29926
|
output += `)`;
|
|
29740
29927
|
return output;
|
|
@@ -29815,7 +30002,7 @@ class FootprintConverter {
|
|
|
29815
30002
|
return this.generatePad({ ...pad, shape: "RECT", points: "" }, origin);
|
|
29816
30003
|
}
|
|
29817
30004
|
let holeRadius = pad.holeRadius;
|
|
29818
|
-
if (holeRadius === 0 && pad.
|
|
30005
|
+
if (holeRadius === 0 && pad.layerId === 11 && pad.shape === "POLYGON") {
|
|
29819
30006
|
holeRadius = this.calculateDrillRadiusFromPolygon(points, pad.centerX, pad.centerY);
|
|
29820
30007
|
}
|
|
29821
30008
|
const isSmd = holeRadius === 0;
|
|
@@ -30157,12 +30344,26 @@ ${justify ? ` (justify ${justify})
|
|
|
30157
30344
|
break;
|
|
30158
30345
|
case "A":
|
|
30159
30346
|
if (args.length >= 7) {
|
|
30347
|
+
const arcParams = {
|
|
30348
|
+
x1: currentX,
|
|
30349
|
+
y1: currentY,
|
|
30350
|
+
rx: args[0],
|
|
30351
|
+
ry: args[1],
|
|
30352
|
+
phi: args[2],
|
|
30353
|
+
largeArc: args[3] === 1,
|
|
30354
|
+
sweep: args[4] === 1,
|
|
30355
|
+
x2: args[5],
|
|
30356
|
+
y2: args[6]
|
|
30357
|
+
};
|
|
30358
|
+
const arcPoints = interpolateArc(arcParams, 4);
|
|
30359
|
+
for (const pt of arcPoints) {
|
|
30360
|
+
points.push({
|
|
30361
|
+
x: convertX(pt.x, origin.x),
|
|
30362
|
+
y: convertY(pt.y, origin.y)
|
|
30363
|
+
});
|
|
30364
|
+
}
|
|
30160
30365
|
currentX = args[5];
|
|
30161
30366
|
currentY = args[6];
|
|
30162
|
-
points.push({
|
|
30163
|
-
x: convertX(currentX, origin.x),
|
|
30164
|
-
y: convertY(currentY, origin.y)
|
|
30165
|
-
});
|
|
30166
30367
|
}
|
|
30167
30368
|
break;
|
|
30168
30369
|
case "Z":
|
|
@@ -30309,16 +30510,22 @@ ${justify ? ` (justify ${justify})
|
|
|
30309
30510
|
}
|
|
30310
30511
|
return output;
|
|
30311
30512
|
}
|
|
30312
|
-
generate3DModel(modelPath) {
|
|
30513
|
+
generate3DModel(modelPath, model3d, origin) {
|
|
30514
|
+
const offsetX = roundTo(toMM(model3d.translation.x - origin.x), 3);
|
|
30515
|
+
const offsetY = roundTo(-toMM(model3d.translation.y - origin.y), 3);
|
|
30516
|
+
const offsetZ = roundTo(-toMM(model3d.translation.z), 3);
|
|
30517
|
+
const rotateX = normalize3DModelRotation(model3d.rotation.x);
|
|
30518
|
+
const rotateY = normalize3DModelRotation(model3d.rotation.y);
|
|
30519
|
+
const rotateZ = normalize3DModelRotation(model3d.rotation.z);
|
|
30313
30520
|
return ` (model "${modelPath}"
|
|
30314
30521
|
(offset
|
|
30315
|
-
(xyz
|
|
30522
|
+
(xyz ${offsetX} ${offsetY} ${offsetZ})
|
|
30316
30523
|
)
|
|
30317
30524
|
(scale
|
|
30318
30525
|
(xyz 1 1 1)
|
|
30319
30526
|
)
|
|
30320
30527
|
(rotate
|
|
30321
|
-
(xyz
|
|
30528
|
+
(xyz ${rotateX} ${rotateY} ${rotateZ})
|
|
30322
30529
|
)
|
|
30323
30530
|
)
|
|
30324
30531
|
`;
|
|
@@ -30336,7 +30543,6 @@ init_category_router();
|
|
|
30336
30543
|
var FOOTPRINT_LIBRARY_NAME = getFootprintDirName();
|
|
30337
30544
|
var MODELS_3D_NAME = get3DModelsDirName();
|
|
30338
30545
|
var LIBRARY_NAMESPACE2 = "jlc_mcp";
|
|
30339
|
-
var KICAD_VERSIONS3 = ["9.0", "8.0"];
|
|
30340
30546
|
var EASYEDA_LIBRARY_NAME2 = "EasyEDA";
|
|
30341
30547
|
var EASYEDA_SYMBOL_LIBRARY_NAME2 = "EasyEDA.kicad_sym";
|
|
30342
30548
|
var EASYEDA_FOOTPRINT_LIBRARY_NAME2 = "EasyEDA.pretty";
|
|
@@ -30345,58 +30551,48 @@ var EASYEDA_LOCAL_LIBRARY_NAME = "EasyEDA-local";
|
|
|
30345
30551
|
var EASYEDA_LOCAL_SYMBOL_LIBRARY_NAME = "EasyEDA-local.kicad_sym";
|
|
30346
30552
|
var EASYEDA_LOCAL_FOOTPRINT_LIBRARY_NAME = "EasyEDA-local.pretty";
|
|
30347
30553
|
var EASYEDA_LOCAL_LIBRARY_DESCRIPTION = "EasyEDA Community Component Library (Project-local)";
|
|
30348
|
-
function detectKicadVersion2() {
|
|
30349
|
-
const home = homedir2();
|
|
30350
|
-
const baseDir = join4(home, "Documents", "KiCad");
|
|
30351
|
-
for (const version2 of KICAD_VERSIONS3) {
|
|
30352
|
-
if (existsSync3(join4(baseDir, version2))) {
|
|
30353
|
-
return version2;
|
|
30354
|
-
}
|
|
30355
|
-
}
|
|
30356
|
-
return "9.0";
|
|
30357
|
-
}
|
|
30358
30554
|
function getGlobalLibraryPaths() {
|
|
30359
|
-
const home =
|
|
30360
|
-
const version2 =
|
|
30361
|
-
const plat =
|
|
30555
|
+
const home = homedir3();
|
|
30556
|
+
const version2 = detectKicadVersion();
|
|
30557
|
+
const plat = platform3();
|
|
30362
30558
|
let base;
|
|
30363
30559
|
if (plat === "linux") {
|
|
30364
|
-
base =
|
|
30560
|
+
base = join5(home, ".local", "share", "kicad", version2, "3rdparty", LIBRARY_NAMESPACE2);
|
|
30365
30561
|
} else {
|
|
30366
|
-
base =
|
|
30562
|
+
base = join5(home, "Documents", "KiCad", version2, "3rdparty", LIBRARY_NAMESPACE2);
|
|
30367
30563
|
}
|
|
30368
30564
|
return {
|
|
30369
30565
|
base,
|
|
30370
|
-
symbolsDir:
|
|
30371
|
-
footprintsDir:
|
|
30372
|
-
models3dDir:
|
|
30373
|
-
footprintDir:
|
|
30374
|
-
models3dFullDir:
|
|
30566
|
+
symbolsDir: join5(base, "symbols"),
|
|
30567
|
+
footprintsDir: join5(base, "footprints"),
|
|
30568
|
+
models3dDir: join5(base, "3dmodels"),
|
|
30569
|
+
footprintDir: join5(base, "footprints", FOOTPRINT_LIBRARY_NAME),
|
|
30570
|
+
models3dFullDir: join5(base, "3dmodels", MODELS_3D_NAME)
|
|
30375
30571
|
};
|
|
30376
30572
|
}
|
|
30377
30573
|
function getProjectLibraryPaths(projectPath) {
|
|
30378
|
-
const librariesDir =
|
|
30574
|
+
const librariesDir = join5(projectPath, "libraries");
|
|
30379
30575
|
return {
|
|
30380
30576
|
base: librariesDir,
|
|
30381
|
-
symbolsDir:
|
|
30382
|
-
footprintsDir:
|
|
30383
|
-
models3dDir:
|
|
30384
|
-
footprintDir:
|
|
30385
|
-
models3dFullDir:
|
|
30577
|
+
symbolsDir: join5(librariesDir, "symbols"),
|
|
30578
|
+
footprintsDir: join5(librariesDir, "footprints"),
|
|
30579
|
+
models3dDir: join5(librariesDir, "3dmodels"),
|
|
30580
|
+
footprintDir: join5(librariesDir, "footprints", FOOTPRINT_LIBRARY_NAME),
|
|
30581
|
+
models3dFullDir: join5(librariesDir, "3dmodels", MODELS_3D_NAME)
|
|
30386
30582
|
};
|
|
30387
30583
|
}
|
|
30388
|
-
function
|
|
30584
|
+
function isLcscId3(id) {
|
|
30389
30585
|
return /^C\d+$/.test(id);
|
|
30390
30586
|
}
|
|
30391
|
-
function
|
|
30392
|
-
const home =
|
|
30393
|
-
const plat =
|
|
30587
|
+
function getKicadConfigDir3(version2) {
|
|
30588
|
+
const home = homedir3();
|
|
30589
|
+
const plat = platform3();
|
|
30394
30590
|
if (plat === "darwin") {
|
|
30395
|
-
return
|
|
30591
|
+
return join5(home, "Library", "Preferences", "kicad", version2);
|
|
30396
30592
|
} else if (plat === "win32") {
|
|
30397
|
-
return
|
|
30593
|
+
return join5(process.env.APPDATA || join5(home, "AppData", "Roaming"), "kicad", version2);
|
|
30398
30594
|
} else {
|
|
30399
|
-
return
|
|
30595
|
+
return join5(home, ".config", "kicad", version2);
|
|
30400
30596
|
}
|
|
30401
30597
|
}
|
|
30402
30598
|
async function parseSymbolLibrary(filePath, libraryName, category, models3dDir) {
|
|
@@ -30422,8 +30618,8 @@ async function parseSymbolLibrary(filePath, libraryName, category, models3dDir)
|
|
|
30422
30618
|
const name = nameParts.length > 1 ? nameParts[1] : fullSymbolRef;
|
|
30423
30619
|
const fpMatch = symbolBlock.match(/\(property\s+"Footprint"\s+"([^"]+)"/);
|
|
30424
30620
|
const footprintRef = fpMatch ? fpMatch[1] : "";
|
|
30425
|
-
const model3dPath =
|
|
30426
|
-
const has3dModel =
|
|
30621
|
+
const model3dPath = join5(models3dDir, `${name}.step`);
|
|
30622
|
+
const has3dModel = existsSync4(model3dPath);
|
|
30427
30623
|
if (lcscId) {
|
|
30428
30624
|
components.push({
|
|
30429
30625
|
lcscId,
|
|
@@ -30439,6 +30635,42 @@ async function parseSymbolLibrary(filePath, libraryName, category, models3dDir)
|
|
|
30439
30635
|
} catch {}
|
|
30440
30636
|
return components;
|
|
30441
30637
|
}
|
|
30638
|
+
function removeSymbolFromLibrary(content, symbolName) {
|
|
30639
|
+
const lines = content.split(`
|
|
30640
|
+
`);
|
|
30641
|
+
const result = [];
|
|
30642
|
+
let depth = 0;
|
|
30643
|
+
let inTargetSymbol = false;
|
|
30644
|
+
let symbolStartDepth = 0;
|
|
30645
|
+
for (const line of lines) {
|
|
30646
|
+
const openCount = (line.match(/\(/g) || []).length;
|
|
30647
|
+
const closeCount = (line.match(/\)/g) || []).length;
|
|
30648
|
+
const symbolMatch = line.match(/^\s*\(symbol\s+"([^"]+)"/);
|
|
30649
|
+
if (symbolMatch && !inTargetSymbol) {
|
|
30650
|
+
const fullRef = symbolMatch[1];
|
|
30651
|
+
const nameOnly = fullRef.includes(":") ? fullRef.split(":")[1] : fullRef;
|
|
30652
|
+
if (nameOnly === symbolName || nameOnly.startsWith(`${symbolName}_`)) {
|
|
30653
|
+
inTargetSymbol = true;
|
|
30654
|
+
symbolStartDepth = depth;
|
|
30655
|
+
depth += openCount - closeCount;
|
|
30656
|
+
continue;
|
|
30657
|
+
}
|
|
30658
|
+
}
|
|
30659
|
+
if (inTargetSymbol) {
|
|
30660
|
+
depth += openCount - closeCount;
|
|
30661
|
+
if (depth <= symbolStartDepth) {
|
|
30662
|
+
inTargetSymbol = false;
|
|
30663
|
+
}
|
|
30664
|
+
continue;
|
|
30665
|
+
}
|
|
30666
|
+
depth += openCount - closeCount;
|
|
30667
|
+
result.push(line);
|
|
30668
|
+
}
|
|
30669
|
+
return result.join(`
|
|
30670
|
+
`).replace(/\n{3,}/g, `
|
|
30671
|
+
|
|
30672
|
+
`);
|
|
30673
|
+
}
|
|
30442
30674
|
function adaptCommunityComponent(component) {
|
|
30443
30675
|
const symbolHead = component.symbol.head;
|
|
30444
30676
|
const cPara = symbolHead?.c_para || {};
|
|
@@ -30461,6 +30693,7 @@ function adaptCommunityComponent(component) {
|
|
|
30461
30693
|
polylines: component.symbol.polylines,
|
|
30462
30694
|
polygons: component.symbol.polygons,
|
|
30463
30695
|
paths: component.symbol.paths,
|
|
30696
|
+
texts: component.symbol.texts || [],
|
|
30464
30697
|
origin: component.symbol.origin
|
|
30465
30698
|
},
|
|
30466
30699
|
footprint: {
|
|
@@ -30484,11 +30717,11 @@ function adaptCommunityComponent(component) {
|
|
|
30484
30717
|
function createLibraryService() {
|
|
30485
30718
|
return {
|
|
30486
30719
|
async install(id, options = {}) {
|
|
30487
|
-
const isCommunityComponent = !
|
|
30720
|
+
const isCommunityComponent = !isLcscId3(id);
|
|
30488
30721
|
const isGlobal = !options.projectPath;
|
|
30489
30722
|
const paths = isGlobal ? getGlobalLibraryPaths() : getProjectLibraryPaths(options.projectPath);
|
|
30490
30723
|
let component = null;
|
|
30491
|
-
if (
|
|
30724
|
+
if (isLcscId3(id)) {
|
|
30492
30725
|
component = await easyedaClient.getComponentData(id);
|
|
30493
30726
|
} else {
|
|
30494
30727
|
const communityComponent = await easyedaCommunityClient.getComponent(id);
|
|
@@ -30537,18 +30770,18 @@ function createLibraryService() {
|
|
|
30537
30770
|
let easyedaModelsDir;
|
|
30538
30771
|
if (isGlobal) {
|
|
30539
30772
|
symbolsDir = paths.symbolsDir;
|
|
30540
|
-
footprintDir =
|
|
30541
|
-
easyedaModelsDir =
|
|
30773
|
+
footprintDir = join5(paths.footprintsDir, fpLibDir);
|
|
30774
|
+
easyedaModelsDir = join5(paths.models3dDir, models3dDirName);
|
|
30542
30775
|
} else {
|
|
30543
|
-
const librariesDir =
|
|
30544
|
-
symbolsDir =
|
|
30545
|
-
footprintDir =
|
|
30546
|
-
easyedaModelsDir =
|
|
30776
|
+
const librariesDir = join5(options.projectPath, "libraries");
|
|
30777
|
+
symbolsDir = join5(librariesDir, "symbols");
|
|
30778
|
+
footprintDir = join5(librariesDir, "footprints", fpLibDir);
|
|
30779
|
+
easyedaModelsDir = join5(librariesDir, "3dmodels", models3dDirName);
|
|
30547
30780
|
}
|
|
30548
30781
|
models3dDir = easyedaModelsDir;
|
|
30549
30782
|
await ensureDir(symbolsDir);
|
|
30550
30783
|
await ensureDir(footprintDir);
|
|
30551
|
-
symbolFile =
|
|
30784
|
+
symbolFile = join5(symbolsDir, symLibFile);
|
|
30552
30785
|
symbolName = component.info.name.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
30553
30786
|
const include3d = options.include3d ?? true;
|
|
30554
30787
|
let modelRelativePath;
|
|
@@ -30557,7 +30790,7 @@ function createLibraryService() {
|
|
|
30557
30790
|
const model = await easyedaCommunityClient.get3DModel(component.model3d.uuid, "step");
|
|
30558
30791
|
if (model) {
|
|
30559
30792
|
const modelFilename = `${symbolName}.step`;
|
|
30560
|
-
modelPath =
|
|
30793
|
+
modelPath = join5(models3dDir, modelFilename);
|
|
30561
30794
|
await writeBinary(modelPath, model);
|
|
30562
30795
|
if (isGlobal) {
|
|
30563
30796
|
modelRelativePath = `\${KICAD9_3RD_PARTY}/${LIBRARY_NAMESPACE2}/3dmodels/${models3dDirName}/${modelFilename}`;
|
|
@@ -30571,7 +30804,7 @@ function createLibraryService() {
|
|
|
30571
30804
|
include3DModel: !!modelRelativePath,
|
|
30572
30805
|
modelPath: modelRelativePath
|
|
30573
30806
|
});
|
|
30574
|
-
footprintPath =
|
|
30807
|
+
footprintPath = join5(footprintDir, `${symbolName}.kicad_mod`);
|
|
30575
30808
|
footprintRef = `${libName}:${symbolName}`;
|
|
30576
30809
|
await writeText(footprintPath, footprint);
|
|
30577
30810
|
component.info.package = footprintRef;
|
|
@@ -30586,20 +30819,20 @@ function createLibraryService() {
|
|
|
30586
30819
|
} else {
|
|
30587
30820
|
category = getLibraryCategory(component.info.prefix, component.info.category, component.info.description);
|
|
30588
30821
|
const symbolLibraryFilename = getLibraryFilename(category);
|
|
30589
|
-
symbolFile =
|
|
30822
|
+
symbolFile = join5(paths.symbolsDir, symbolLibraryFilename);
|
|
30590
30823
|
footprintDir = paths.footprintDir;
|
|
30591
30824
|
models3dDir = paths.models3dFullDir;
|
|
30592
30825
|
await ensureDir(paths.symbolsDir);
|
|
30593
30826
|
await ensureDir(paths.footprintDir);
|
|
30594
30827
|
symbolName = symbolConverter.getSymbolName(component);
|
|
30595
|
-
const include3d = options.include3d ??
|
|
30828
|
+
const include3d = options.include3d ?? true;
|
|
30596
30829
|
let modelRelativePath;
|
|
30597
30830
|
if (include3d && component.model3d) {
|
|
30598
30831
|
await ensureDir(models3dDir);
|
|
30599
30832
|
const model = await easyedaClient.get3DModel(component.model3d.uuid, "step");
|
|
30600
30833
|
if (model) {
|
|
30601
30834
|
const modelFilename = `${symbolName}.step`;
|
|
30602
|
-
modelPath =
|
|
30835
|
+
modelPath = join5(models3dDir, modelFilename);
|
|
30603
30836
|
await writeBinary(modelPath, model);
|
|
30604
30837
|
modelRelativePath = `\${KICAD9_3RD_PARTY}/${LIBRARY_NAMESPACE2}/3dmodels/${MODELS_3D_NAME}/${modelFilename}`;
|
|
30605
30838
|
}
|
|
@@ -30611,7 +30844,7 @@ function createLibraryService() {
|
|
|
30611
30844
|
if (footprintResult.type === "reference") {
|
|
30612
30845
|
footprintRef = footprintResult.reference;
|
|
30613
30846
|
} else {
|
|
30614
|
-
footprintPath =
|
|
30847
|
+
footprintPath = join5(footprintDir, `${footprintResult.name}.kicad_mod`);
|
|
30615
30848
|
footprintRef = getFootprintReference(footprintResult.name);
|
|
30616
30849
|
await writeText(footprintPath, footprintResult.content);
|
|
30617
30850
|
}
|
|
@@ -30624,7 +30857,7 @@ function createLibraryService() {
|
|
|
30624
30857
|
}
|
|
30625
30858
|
let symbolContent;
|
|
30626
30859
|
let symbolAction;
|
|
30627
|
-
if (
|
|
30860
|
+
if (existsSync4(symbolFile)) {
|
|
30628
30861
|
const existingContent = await readFile4(symbolFile, "utf-8");
|
|
30629
30862
|
if (symbolConverter.symbolExistsInLibrary(existingContent, component.info.name)) {
|
|
30630
30863
|
if (options.force) {
|
|
@@ -30716,9 +30949,9 @@ function createLibraryService() {
|
|
|
30716
30949
|
if (options.category && options.category !== category)
|
|
30717
30950
|
continue;
|
|
30718
30951
|
const libraryFilename = getLibraryFilename(category);
|
|
30719
|
-
const libraryPath =
|
|
30952
|
+
const libraryPath = join5(paths.symbolsDir, libraryFilename);
|
|
30720
30953
|
const libraryName = `JLC-MCP-${category}`;
|
|
30721
|
-
if (
|
|
30954
|
+
if (existsSync4(libraryPath)) {
|
|
30722
30955
|
const components = await parseSymbolLibrary(libraryPath, libraryName, category, paths.models3dFullDir);
|
|
30723
30956
|
allComponents.push(...components);
|
|
30724
30957
|
}
|
|
@@ -30733,13 +30966,13 @@ function createLibraryService() {
|
|
|
30733
30966
|
await ensureGlobalLibraryTables2();
|
|
30734
30967
|
},
|
|
30735
30968
|
async getStatus() {
|
|
30736
|
-
const version2 =
|
|
30969
|
+
const version2 = detectKicadVersion();
|
|
30737
30970
|
const paths = getGlobalLibraryPaths();
|
|
30738
|
-
const configDir =
|
|
30739
|
-
const symLibTablePath =
|
|
30740
|
-
const fpLibTablePath =
|
|
30971
|
+
const configDir = getKicadConfigDir3(version2);
|
|
30972
|
+
const symLibTablePath = join5(configDir, "sym-lib-table");
|
|
30973
|
+
const fpLibTablePath = join5(configDir, "fp-lib-table");
|
|
30741
30974
|
let installed = false;
|
|
30742
|
-
if (
|
|
30975
|
+
if (existsSync4(paths.symbolsDir)) {
|
|
30743
30976
|
try {
|
|
30744
30977
|
const files = await readdir2(paths.symbolsDir);
|
|
30745
30978
|
installed = files.some((f) => f.endsWith(".kicad_sym"));
|
|
@@ -30748,7 +30981,7 @@ function createLibraryService() {
|
|
|
30748
30981
|
}
|
|
30749
30982
|
}
|
|
30750
30983
|
let linked = false;
|
|
30751
|
-
if (
|
|
30984
|
+
if (existsSync4(symLibTablePath)) {
|
|
30752
30985
|
try {
|
|
30753
30986
|
const content = await readFile4(symLibTablePath, "utf-8");
|
|
30754
30987
|
linked = content.includes("JLC-MCP");
|
|
@@ -30774,8 +31007,8 @@ function createLibraryService() {
|
|
|
30774
31007
|
},
|
|
30775
31008
|
async isEasyEDAInstalled(componentName) {
|
|
30776
31009
|
const paths = getGlobalLibraryPaths();
|
|
30777
|
-
const easyedaLibPath =
|
|
30778
|
-
if (!
|
|
31010
|
+
const easyedaLibPath = join5(paths.symbolsDir, EASYEDA_SYMBOL_LIBRARY_NAME2);
|
|
31011
|
+
if (!existsSync4(easyedaLibPath)) {
|
|
30779
31012
|
return false;
|
|
30780
31013
|
}
|
|
30781
31014
|
try {
|
|
@@ -30786,6 +31019,85 @@ function createLibraryService() {
|
|
|
30786
31019
|
} catch {
|
|
30787
31020
|
return false;
|
|
30788
31021
|
}
|
|
31022
|
+
},
|
|
31023
|
+
async regenerate(options = {}) {
|
|
31024
|
+
const include3d = options.include3d ?? true;
|
|
31025
|
+
const installed = await this.listInstalled({ projectPath: options.projectPath });
|
|
31026
|
+
const results = {
|
|
31027
|
+
total: installed.length,
|
|
31028
|
+
success: 0,
|
|
31029
|
+
failed: 0,
|
|
31030
|
+
components: []
|
|
31031
|
+
};
|
|
31032
|
+
for (let i = 0;i < installed.length; i++) {
|
|
31033
|
+
const component = installed[i];
|
|
31034
|
+
options.onProgress?.(i + 1, installed.length, component, "start");
|
|
31035
|
+
try {
|
|
31036
|
+
await this.install(component.lcscId, {
|
|
31037
|
+
projectPath: options.projectPath,
|
|
31038
|
+
include3d,
|
|
31039
|
+
force: true
|
|
31040
|
+
});
|
|
31041
|
+
results.success++;
|
|
31042
|
+
results.components.push({
|
|
31043
|
+
id: component.lcscId,
|
|
31044
|
+
name: component.name,
|
|
31045
|
+
status: "success"
|
|
31046
|
+
});
|
|
31047
|
+
options.onProgress?.(i + 1, installed.length, component, "success");
|
|
31048
|
+
} catch (error2) {
|
|
31049
|
+
const errorMessage = error2 instanceof Error ? error2.message : "Unknown error";
|
|
31050
|
+
results.failed++;
|
|
31051
|
+
results.components.push({
|
|
31052
|
+
id: component.lcscId,
|
|
31053
|
+
name: component.name,
|
|
31054
|
+
status: "failed",
|
|
31055
|
+
error: errorMessage
|
|
31056
|
+
});
|
|
31057
|
+
options.onProgress?.(i + 1, installed.length, component, "error", errorMessage);
|
|
31058
|
+
}
|
|
31059
|
+
}
|
|
31060
|
+
return results;
|
|
31061
|
+
},
|
|
31062
|
+
async remove(lcscId, options = {}) {
|
|
31063
|
+
const paths = options.projectPath ? getProjectLibraryPaths(options.projectPath) : getGlobalLibraryPaths();
|
|
31064
|
+
const installed = await this.listInstalled({ projectPath: options.projectPath });
|
|
31065
|
+
const component = installed.find((c) => c.lcscId === lcscId);
|
|
31066
|
+
if (!component) {
|
|
31067
|
+
throw new Error(`Component ${lcscId} not found in library`);
|
|
31068
|
+
}
|
|
31069
|
+
const result = {
|
|
31070
|
+
success: false,
|
|
31071
|
+
lcscId,
|
|
31072
|
+
symbolRemoved: false,
|
|
31073
|
+
footprintRemoved: false,
|
|
31074
|
+
model3dRemoved: false
|
|
31075
|
+
};
|
|
31076
|
+
const libraryFilename = getLibraryFilename(component.category);
|
|
31077
|
+
const symbolLibPath = join5(paths.symbolsDir, libraryFilename);
|
|
31078
|
+
if (existsSync4(symbolLibPath)) {
|
|
31079
|
+
const content = await readFile4(symbolLibPath, "utf-8");
|
|
31080
|
+
const newContent = removeSymbolFromLibrary(content, component.name);
|
|
31081
|
+
await writeText(symbolLibPath, newContent);
|
|
31082
|
+
result.symbolRemoved = true;
|
|
31083
|
+
}
|
|
31084
|
+
if (component.footprintRef?.startsWith("JLC-MCP:")) {
|
|
31085
|
+
const fpName = component.footprintRef.split(":")[1];
|
|
31086
|
+
const footprintPath = join5(paths.footprintDir, `${fpName}.kicad_mod`);
|
|
31087
|
+
if (existsSync4(footprintPath)) {
|
|
31088
|
+
await unlink(footprintPath);
|
|
31089
|
+
result.footprintRemoved = true;
|
|
31090
|
+
}
|
|
31091
|
+
}
|
|
31092
|
+
if (component.has3dModel) {
|
|
31093
|
+
const modelPath = join5(paths.models3dFullDir, `${component.name}.step`);
|
|
31094
|
+
if (existsSync4(modelPath)) {
|
|
31095
|
+
await unlink(modelPath);
|
|
31096
|
+
result.model3dRemoved = true;
|
|
31097
|
+
}
|
|
31098
|
+
}
|
|
31099
|
+
result.success = result.symbolRemoved;
|
|
31100
|
+
return result;
|
|
30789
31101
|
}
|
|
30790
31102
|
};
|
|
30791
31103
|
}
|
|
@@ -30801,16 +31113,16 @@ function getHtmlPage() {
|
|
|
30801
31113
|
return htmlCache;
|
|
30802
31114
|
try {
|
|
30803
31115
|
const possiblePaths = [
|
|
30804
|
-
|
|
30805
|
-
|
|
30806
|
-
|
|
30807
|
-
|
|
30808
|
-
|
|
30809
|
-
|
|
30810
|
-
|
|
30811
|
-
|
|
30812
|
-
|
|
30813
|
-
|
|
31116
|
+
join6(__dirname2, "assets/search.html"),
|
|
31117
|
+
join6(__dirname2, "../dist/assets/search.html"),
|
|
31118
|
+
join6(__dirname2, "../assets/search.html"),
|
|
31119
|
+
join6(__dirname2, "../assets/search-built.html"),
|
|
31120
|
+
join6(process.cwd(), "dist/assets/search.html"),
|
|
31121
|
+
join6(process.cwd(), "packages/core/dist/assets/search.html"),
|
|
31122
|
+
join6(__dirname2, "../../dist/assets/search.html"),
|
|
31123
|
+
join6(__dirname2, "../../../core/dist/assets/search.html"),
|
|
31124
|
+
join6(__dirname2, "../../../../packages/core/dist/assets/search.html"),
|
|
31125
|
+
join6(__dirname2, "../../node_modules/@jlcpcb/core/dist/assets/search.html")
|
|
30814
31126
|
];
|
|
30815
31127
|
for (const path of possiblePaths) {
|
|
30816
31128
|
try {
|
|
@@ -31001,17 +31313,51 @@ function startHttpServer(options = {}) {
|
|
|
31001
31313
|
});
|
|
31002
31314
|
return port;
|
|
31003
31315
|
}
|
|
31316
|
+
var EE_TO_MM3 = 10 * 0.0254;
|
|
31317
|
+
var EE_TO_MM4 = 10 * 0.0254;
|
|
31318
|
+
var EE_TO_MM5 = 10 * 0.0254;
|
|
31319
|
+
|
|
31320
|
+
// src/services.ts
|
|
31321
|
+
var componentService = null;
|
|
31322
|
+
var libraryService = null;
|
|
31323
|
+
function getComponentService() {
|
|
31324
|
+
if (!componentService) {
|
|
31325
|
+
componentService = createComponentService();
|
|
31326
|
+
}
|
|
31327
|
+
return componentService;
|
|
31328
|
+
}
|
|
31329
|
+
function getLibraryService() {
|
|
31330
|
+
if (!libraryService) {
|
|
31331
|
+
libraryService = createLibraryService();
|
|
31332
|
+
}
|
|
31333
|
+
return libraryService;
|
|
31334
|
+
}
|
|
31004
31335
|
|
|
31005
31336
|
// src/tools/search.ts
|
|
31006
|
-
var
|
|
31337
|
+
var componentSearchTool = {
|
|
31007
31338
|
name: "component_search",
|
|
31008
|
-
description:
|
|
31339
|
+
description: `Search for electronic components by keyword.
|
|
31340
|
+
|
|
31341
|
+
Sources:
|
|
31342
|
+
- "lcsc" (default): Search JLCPCB/LCSC official parts library. Returns components with LCSC IDs available for JLC assembly.
|
|
31343
|
+
- "community": Search EasyEDA community library for user-contributed parts (Arduino modules, XIAO, custom breakouts).
|
|
31344
|
+
|
|
31345
|
+
Returns full component details for selection including:
|
|
31346
|
+
- LCSC ID, manufacturer part number, manufacturer name
|
|
31347
|
+
- Description, package, datasheet URL
|
|
31348
|
+
- Price, stock, library type (basic/extended)
|
|
31349
|
+
- Key attributes (resistance, voltage, etc.)`,
|
|
31009
31350
|
inputSchema: {
|
|
31010
31351
|
type: "object",
|
|
31011
31352
|
properties: {
|
|
31012
31353
|
query: {
|
|
31013
31354
|
type: "string",
|
|
31014
|
-
description: 'Search query (e.g., "ESP32", "STM32F103", "0805 100nF")'
|
|
31355
|
+
description: 'Search query (e.g., "ESP32", "STM32F103", "0805 100nF", "XIAO RP2040")'
|
|
31356
|
+
},
|
|
31357
|
+
source: {
|
|
31358
|
+
type: "string",
|
|
31359
|
+
enum: ["lcsc", "community"],
|
|
31360
|
+
description: 'Search source: "lcsc" for official parts (default), "community" for EasyEDA user-contributed'
|
|
31015
31361
|
},
|
|
31016
31362
|
limit: {
|
|
31017
31363
|
type: "number",
|
|
@@ -31019,11 +31365,11 @@ var searchComponentsTool = {
|
|
|
31019
31365
|
},
|
|
31020
31366
|
in_stock: {
|
|
31021
31367
|
type: "boolean",
|
|
31022
|
-
description: "Only show in-stock items (default: false)"
|
|
31368
|
+
description: "Only show in-stock items (default: false, LCSC only)"
|
|
31023
31369
|
},
|
|
31024
31370
|
basic_only: {
|
|
31025
31371
|
type: "boolean",
|
|
31026
|
-
description: "Only show JLCPCB Basic Parts Library components (lower assembly cost,
|
|
31372
|
+
description: "Only show JLCPCB Basic Parts Library components (lower assembly cost, LCSC only)"
|
|
31027
31373
|
}
|
|
31028
31374
|
},
|
|
31029
31375
|
required: ["query"]
|
|
@@ -31031,112 +31377,64 @@ var searchComponentsTool = {
|
|
|
31031
31377
|
};
|
|
31032
31378
|
var SearchParamsSchema = exports_external.object({
|
|
31033
31379
|
query: exports_external.string().min(1),
|
|
31380
|
+
source: exports_external.enum(["lcsc", "community"]).default("lcsc"),
|
|
31034
31381
|
limit: exports_external.number().min(1).max(50).default(10),
|
|
31035
31382
|
in_stock: exports_external.boolean().optional(),
|
|
31036
31383
|
basic_only: exports_external.boolean().optional()
|
|
31037
31384
|
});
|
|
31038
|
-
async function
|
|
31385
|
+
async function handleComponentSearch(args) {
|
|
31039
31386
|
const params = SearchParamsSchema.parse(args);
|
|
31040
|
-
const results = await
|
|
31387
|
+
const results = await getComponentService().search(params.query, {
|
|
31388
|
+
source: params.source,
|
|
31041
31389
|
limit: params.limit,
|
|
31042
31390
|
inStock: params.in_stock,
|
|
31043
31391
|
basicOnly: params.basic_only
|
|
31044
31392
|
});
|
|
31045
|
-
|
|
31046
|
-
content: [{
|
|
31047
|
-
type: "text",
|
|
31048
|
-
text: JSON.stringify(results, null, 2)
|
|
31049
|
-
}]
|
|
31050
|
-
};
|
|
31051
|
-
}
|
|
31052
|
-
|
|
31053
|
-
// src/tools/details.ts
|
|
31054
|
-
var getComponentTool = {
|
|
31055
|
-
name: "component_get",
|
|
31056
|
-
description: "Get detailed component information by LCSC part number (e.g., C2040). LCSC is JLC PCB's preferred supplier - components with LCSC IDs are available for JLC assembly. Returns symbol pins, footprint pads, manufacturer info, datasheet URL, and 3D model reference.",
|
|
31057
|
-
inputSchema: {
|
|
31058
|
-
type: "object",
|
|
31059
|
-
properties: {
|
|
31060
|
-
lcsc_id: {
|
|
31061
|
-
type: "string",
|
|
31062
|
-
description: "LCSC part number (e.g., C2040, C14663)"
|
|
31063
|
-
}
|
|
31064
|
-
},
|
|
31065
|
-
required: ["lcsc_id"]
|
|
31066
|
-
}
|
|
31067
|
-
};
|
|
31068
|
-
var GetComponentParamsSchema = exports_external.object({
|
|
31069
|
-
lcsc_id: exports_external.string().regex(/^C\d+$/, "Invalid LCSC part number")
|
|
31070
|
-
});
|
|
31071
|
-
async function handleGetComponent(args) {
|
|
31072
|
-
const params = GetComponentParamsSchema.parse(args);
|
|
31073
|
-
const component = await easyedaClient.getComponentData(params.lcsc_id);
|
|
31074
|
-
if (!component) {
|
|
31393
|
+
if (results.length === 0) {
|
|
31075
31394
|
return {
|
|
31076
31395
|
content: [{
|
|
31077
31396
|
type: "text",
|
|
31078
|
-
text:
|
|
31079
|
-
|
|
31080
|
-
|
|
31397
|
+
text: JSON.stringify({
|
|
31398
|
+
success: true,
|
|
31399
|
+
query: params.query,
|
|
31400
|
+
source: params.source,
|
|
31401
|
+
count: 0,
|
|
31402
|
+
results: [],
|
|
31403
|
+
hint: params.source === "lcsc" ? 'Try searching with source: "community" for user-contributed parts' : 'Try searching with source: "lcsc" for official JLCPCB parts'
|
|
31404
|
+
})
|
|
31405
|
+
}]
|
|
31081
31406
|
};
|
|
31082
31407
|
}
|
|
31083
|
-
const
|
|
31084
|
-
|
|
31085
|
-
|
|
31086
|
-
|
|
31087
|
-
|
|
31088
|
-
|
|
31089
|
-
|
|
31090
|
-
|
|
31091
|
-
|
|
31092
|
-
|
|
31093
|
-
|
|
31094
|
-
|
|
31095
|
-
|
|
31096
|
-
model_3d_uuid: component.model3d?.uuid
|
|
31097
|
-
};
|
|
31408
|
+
const compactResults = results.map((r) => ({
|
|
31409
|
+
lcsc_id: r.lcscId,
|
|
31410
|
+
name: r.name,
|
|
31411
|
+
manufacturer: r.manufacturer,
|
|
31412
|
+
description: r.description,
|
|
31413
|
+
package: r.package,
|
|
31414
|
+
datasheet: r.datasheetPdf,
|
|
31415
|
+
stock: r.stock,
|
|
31416
|
+
price: r.price,
|
|
31417
|
+
library_type: r.libraryType,
|
|
31418
|
+
category: r.category,
|
|
31419
|
+
attributes: r.attributes
|
|
31420
|
+
}));
|
|
31098
31421
|
return {
|
|
31099
31422
|
content: [{
|
|
31100
31423
|
type: "text",
|
|
31101
|
-
text: JSON.stringify(
|
|
31424
|
+
text: JSON.stringify({
|
|
31425
|
+
success: true,
|
|
31426
|
+
query: params.query,
|
|
31427
|
+
source: params.source,
|
|
31428
|
+
count: results.length,
|
|
31429
|
+
results: compactResults
|
|
31430
|
+
})
|
|
31102
31431
|
}]
|
|
31103
31432
|
};
|
|
31104
31433
|
}
|
|
31105
|
-
|
|
31106
31434
|
// src/tools/library.ts
|
|
31107
|
-
var
|
|
31108
|
-
|
|
31109
|
-
|
|
31110
|
-
name: "library_get_symbol",
|
|
31111
|
-
description: "Get a KiCad-compatible symbol definition by LCSC part number. Returns the symbol in .kicad_sym format. LCSC is JLC PCB's preferred supplier for assembly.",
|
|
31112
|
-
inputSchema: {
|
|
31113
|
-
type: "object",
|
|
31114
|
-
properties: {
|
|
31115
|
-
lcsc_id: {
|
|
31116
|
-
type: "string",
|
|
31117
|
-
description: "LCSC part number (e.g., C2040)"
|
|
31118
|
-
}
|
|
31119
|
-
},
|
|
31120
|
-
required: ["lcsc_id"]
|
|
31121
|
-
}
|
|
31122
|
-
};
|
|
31123
|
-
var getFootprintKicadTool = {
|
|
31124
|
-
name: "library_get_footprint",
|
|
31125
|
-
description: "Get a KiCad-compatible footprint definition by LCSC part number. Returns the footprint in .kicad_mod format. LCSC is JLC PCB's preferred supplier for assembly.",
|
|
31126
|
-
inputSchema: {
|
|
31127
|
-
type: "object",
|
|
31128
|
-
properties: {
|
|
31129
|
-
lcsc_id: {
|
|
31130
|
-
type: "string",
|
|
31131
|
-
description: "LCSC part number (e.g., C2040)"
|
|
31132
|
-
}
|
|
31133
|
-
},
|
|
31134
|
-
required: ["lcsc_id"]
|
|
31135
|
-
}
|
|
31136
|
-
};
|
|
31137
|
-
var fetchLibraryTool = {
|
|
31138
|
-
name: "library_fetch",
|
|
31139
|
-
description: `Fetch a component and add it to KiCad libraries.
|
|
31435
|
+
var libraryInstallTool = {
|
|
31436
|
+
name: "library_install",
|
|
31437
|
+
description: `Install a component to KiCad libraries.
|
|
31140
31438
|
|
|
31141
31439
|
Accepts:
|
|
31142
31440
|
- LCSC part numbers (e.g., C2040) → global JLC-MCP libraries
|
|
@@ -31146,11 +31444,7 @@ LCSC components are routed to category-based global libraries:
|
|
|
31146
31444
|
- JLC-MCP-Resistors.kicad_sym, JLC-MCP-Capacitors.kicad_sym, JLC-MCP-ICs.kicad_sym, etc.
|
|
31147
31445
|
- Stored at ~/Documents/KiCad/{version}/3rdparty/jlc_mcp/
|
|
31148
31446
|
|
|
31149
|
-
|
|
31150
|
-
- <project>/libraries/symbols/EasyEDA.kicad_sym
|
|
31151
|
-
- <project>/libraries/footprints/EasyEDA.pretty/
|
|
31152
|
-
|
|
31153
|
-
Returns symbol_ref and footprint_ref for immediate use with add_schematic_component.`,
|
|
31447
|
+
Returns symbol_ref and footprint_ref for use with schematic placement.`,
|
|
31154
31448
|
inputSchema: {
|
|
31155
31449
|
type: "object",
|
|
31156
31450
|
properties: {
|
|
@@ -31164,89 +31458,47 @@ Returns symbol_ref and footprint_ref for immediate use with add_schematic_compon
|
|
|
31164
31458
|
},
|
|
31165
31459
|
include_3d: {
|
|
31166
31460
|
type: "boolean",
|
|
31167
|
-
description: "Include 3D model if available (default: false
|
|
31461
|
+
description: "Include 3D model if available (default: false)"
|
|
31462
|
+
},
|
|
31463
|
+
force: {
|
|
31464
|
+
type: "boolean",
|
|
31465
|
+
description: "Reinstall even if already exists (default: false)"
|
|
31168
31466
|
}
|
|
31169
31467
|
},
|
|
31170
31468
|
required: ["id"]
|
|
31171
31469
|
}
|
|
31172
31470
|
};
|
|
31173
|
-
var
|
|
31174
|
-
name: "
|
|
31175
|
-
description:
|
|
31471
|
+
var libraryGetComponentTool = {
|
|
31472
|
+
name: "library_get_component",
|
|
31473
|
+
description: `Get metadata for an installed component's symbol and footprint.
|
|
31474
|
+
|
|
31475
|
+
Returns symbol reference, footprint reference, file paths, and pin/pad counts.
|
|
31476
|
+
Does NOT return full file contents to minimize token usage.
|
|
31477
|
+
|
|
31478
|
+
Use this to verify installation or get references for schematic placement.`,
|
|
31176
31479
|
inputSchema: {
|
|
31177
31480
|
type: "object",
|
|
31178
31481
|
properties: {
|
|
31179
|
-
|
|
31180
|
-
type: "string",
|
|
31181
|
-
description: "3D model UUID from component_get result"
|
|
31182
|
-
},
|
|
31183
|
-
format: {
|
|
31482
|
+
id: {
|
|
31184
31483
|
type: "string",
|
|
31185
|
-
|
|
31186
|
-
description: 'Model format: "step" or "obj" (default: step)'
|
|
31484
|
+
description: "LCSC part number (e.g., C2040)"
|
|
31187
31485
|
}
|
|
31188
31486
|
},
|
|
31189
|
-
required: ["
|
|
31487
|
+
required: ["id"]
|
|
31190
31488
|
}
|
|
31191
31489
|
};
|
|
31192
|
-
var
|
|
31193
|
-
lcsc_id: exports_external.string().regex(/^C\d+$/, "Invalid LCSC part number")
|
|
31194
|
-
});
|
|
31195
|
-
var FetchLibraryParamsSchema = exports_external.object({
|
|
31490
|
+
var LibraryInstallParamsSchema = exports_external.object({
|
|
31196
31491
|
id: exports_external.string().min(1),
|
|
31197
|
-
project_path:
|
|
31198
|
-
include_3d: exports_external.boolean().optional()
|
|
31492
|
+
project_path: SafePathSchema.optional(),
|
|
31493
|
+
include_3d: exports_external.boolean().optional(),
|
|
31494
|
+
force: exports_external.boolean().optional()
|
|
31199
31495
|
});
|
|
31200
|
-
var
|
|
31201
|
-
|
|
31202
|
-
format: exports_external.enum(["step", "obj"]).default("step")
|
|
31496
|
+
var LibraryGetComponentParamsSchema = exports_external.object({
|
|
31497
|
+
id: LCSCPartNumberSchema
|
|
31203
31498
|
});
|
|
31204
|
-
async function
|
|
31205
|
-
const params =
|
|
31206
|
-
const
|
|
31207
|
-
if (!component) {
|
|
31208
|
-
return {
|
|
31209
|
-
content: [{
|
|
31210
|
-
type: "text",
|
|
31211
|
-
text: `Component ${params.lcsc_id} not found`
|
|
31212
|
-
}],
|
|
31213
|
-
isError: true
|
|
31214
|
-
};
|
|
31215
|
-
}
|
|
31216
|
-
const symbol = symbolConverter.convert(component);
|
|
31217
|
-
return {
|
|
31218
|
-
content: [{
|
|
31219
|
-
type: "text",
|
|
31220
|
-
text: symbol
|
|
31221
|
-
}]
|
|
31222
|
-
};
|
|
31223
|
-
}
|
|
31224
|
-
async function handleGetFootprintKicad(args) {
|
|
31225
|
-
const params = LibraryParamsSchema.parse(args);
|
|
31226
|
-
const component = await easyedaClient.getComponentData(params.lcsc_id);
|
|
31227
|
-
if (!component) {
|
|
31228
|
-
return {
|
|
31229
|
-
content: [{
|
|
31230
|
-
type: "text",
|
|
31231
|
-
text: `Component ${params.lcsc_id} not found`
|
|
31232
|
-
}],
|
|
31233
|
-
isError: true
|
|
31234
|
-
};
|
|
31235
|
-
}
|
|
31236
|
-
const footprint = footprintConverter.convert(component);
|
|
31237
|
-
return {
|
|
31238
|
-
content: [{
|
|
31239
|
-
type: "text",
|
|
31240
|
-
text: footprint
|
|
31241
|
-
}]
|
|
31242
|
-
};
|
|
31243
|
-
}
|
|
31244
|
-
function isLcscId3(id) {
|
|
31245
|
-
return /^C\d+$/.test(id);
|
|
31246
|
-
}
|
|
31247
|
-
async function handleFetchLibrary(args) {
|
|
31248
|
-
const params = FetchLibraryParamsSchema.parse(args);
|
|
31249
|
-
const isCommunityComponent = !isLcscId3(params.id);
|
|
31499
|
+
async function handleLibraryInstall(args) {
|
|
31500
|
+
const params = LibraryInstallParamsSchema.parse(args);
|
|
31501
|
+
const isCommunityComponent = !isLcscId(params.id);
|
|
31250
31502
|
if (isCommunityComponent && !params.project_path) {
|
|
31251
31503
|
return {
|
|
31252
31504
|
content: [{
|
|
@@ -31262,9 +31514,10 @@ async function handleFetchLibrary(args) {
|
|
|
31262
31514
|
};
|
|
31263
31515
|
}
|
|
31264
31516
|
try {
|
|
31265
|
-
const result = await
|
|
31517
|
+
const result = await getLibraryService().install(params.id, {
|
|
31266
31518
|
projectPath: params.project_path,
|
|
31267
|
-
include3d: params.include_3d
|
|
31519
|
+
include3d: params.include_3d,
|
|
31520
|
+
force: params.force
|
|
31268
31521
|
});
|
|
31269
31522
|
return {
|
|
31270
31523
|
content: [{
|
|
@@ -31272,22 +31525,23 @@ async function handleFetchLibrary(args) {
|
|
|
31272
31525
|
text: JSON.stringify({
|
|
31273
31526
|
success: true,
|
|
31274
31527
|
id: params.id,
|
|
31275
|
-
|
|
31276
|
-
storage_mode: result.storageMode,
|
|
31277
|
-
category: result.category,
|
|
31278
|
-
symbol_name: result.symbolName,
|
|
31528
|
+
installed: true,
|
|
31279
31529
|
symbol_ref: result.symbolRef,
|
|
31280
31530
|
footprint_ref: result.footprintRef,
|
|
31281
|
-
|
|
31282
|
-
datasheet: result.datasheet,
|
|
31531
|
+
category: result.category,
|
|
31283
31532
|
files: {
|
|
31284
31533
|
symbol_library: result.files.symbolLibrary,
|
|
31285
31534
|
footprint: result.files.footprint,
|
|
31286
31535
|
model_3d: result.files.model3d
|
|
31287
31536
|
},
|
|
31288
|
-
|
|
31289
|
-
|
|
31290
|
-
|
|
31537
|
+
validation: result.validationData ? {
|
|
31538
|
+
pin_pad_match: result.validationData.checks.pin_pad_count_match,
|
|
31539
|
+
pin_count: result.validationData.symbol.pin_count,
|
|
31540
|
+
pad_count: result.validationData.footprint.pad_count,
|
|
31541
|
+
has_power_pins: result.validationData.checks.has_power_pins,
|
|
31542
|
+
has_ground_pins: result.validationData.checks.has_ground_pins
|
|
31543
|
+
} : undefined
|
|
31544
|
+
})
|
|
31291
31545
|
}]
|
|
31292
31546
|
};
|
|
31293
31547
|
} catch (error2) {
|
|
@@ -31297,76 +31551,202 @@ async function handleFetchLibrary(args) {
|
|
|
31297
31551
|
text: JSON.stringify({
|
|
31298
31552
|
success: false,
|
|
31299
31553
|
error: error2 instanceof Error ? error2.message : "Unknown error",
|
|
31300
|
-
id: params.id
|
|
31301
|
-
source: isCommunityComponent ? "easyeda_community" : "lcsc"
|
|
31554
|
+
id: params.id
|
|
31302
31555
|
})
|
|
31303
31556
|
}],
|
|
31304
31557
|
isError: true
|
|
31305
31558
|
};
|
|
31306
31559
|
}
|
|
31307
31560
|
}
|
|
31308
|
-
async function
|
|
31309
|
-
const params =
|
|
31310
|
-
|
|
31311
|
-
|
|
31561
|
+
async function handleLibraryGetComponent(args) {
|
|
31562
|
+
const params = LibraryGetComponentParamsSchema.parse(args);
|
|
31563
|
+
try {
|
|
31564
|
+
const status = await getLibraryService().getStatus();
|
|
31565
|
+
if (!status.installed) {
|
|
31566
|
+
return {
|
|
31567
|
+
content: [{
|
|
31568
|
+
type: "text",
|
|
31569
|
+
text: JSON.stringify({
|
|
31570
|
+
success: false,
|
|
31571
|
+
error: "JLC-MCP libraries not installed. Run library_install first.",
|
|
31572
|
+
id: params.id
|
|
31573
|
+
})
|
|
31574
|
+
}],
|
|
31575
|
+
isError: true
|
|
31576
|
+
};
|
|
31577
|
+
}
|
|
31578
|
+
const installed = await getLibraryService().listInstalled();
|
|
31579
|
+
const component = installed.find((c) => c.lcscId === params.id);
|
|
31580
|
+
if (!component) {
|
|
31581
|
+
return {
|
|
31582
|
+
content: [{
|
|
31583
|
+
type: "text",
|
|
31584
|
+
text: JSON.stringify({
|
|
31585
|
+
success: false,
|
|
31586
|
+
error: `Component ${params.id} is not installed`,
|
|
31587
|
+
id: params.id,
|
|
31588
|
+
hint: "Use library_install to add this component first"
|
|
31589
|
+
})
|
|
31590
|
+
}],
|
|
31591
|
+
isError: true
|
|
31592
|
+
};
|
|
31593
|
+
}
|
|
31594
|
+
return {
|
|
31595
|
+
content: [{
|
|
31596
|
+
type: "text",
|
|
31597
|
+
text: JSON.stringify({
|
|
31598
|
+
success: true,
|
|
31599
|
+
id: params.id,
|
|
31600
|
+
installed: true,
|
|
31601
|
+
symbol_ref: component.symbolRef,
|
|
31602
|
+
footprint_ref: component.footprintRef,
|
|
31603
|
+
category: component.category,
|
|
31604
|
+
symbol_library: component.library,
|
|
31605
|
+
name: component.name,
|
|
31606
|
+
has_3d_model: component.has3dModel
|
|
31607
|
+
})
|
|
31608
|
+
}]
|
|
31609
|
+
};
|
|
31610
|
+
} catch (error2) {
|
|
31312
31611
|
return {
|
|
31313
31612
|
content: [{
|
|
31314
31613
|
type: "text",
|
|
31315
|
-
text:
|
|
31614
|
+
text: JSON.stringify({
|
|
31615
|
+
success: false,
|
|
31616
|
+
error: error2 instanceof Error ? error2.message : "Unknown error",
|
|
31617
|
+
id: params.id
|
|
31618
|
+
})
|
|
31316
31619
|
}],
|
|
31317
31620
|
isError: true
|
|
31318
31621
|
};
|
|
31319
31622
|
}
|
|
31623
|
+
}
|
|
31624
|
+
|
|
31625
|
+
// src/tools/batch.ts
|
|
31626
|
+
var libraryBatchInstallTool = {
|
|
31627
|
+
name: "library_batch_install",
|
|
31628
|
+
description: `Install multiple components to KiCad libraries in a single call.
|
|
31629
|
+
|
|
31630
|
+
Accepts up to 10 LCSC part numbers. Components are installed in parallel.
|
|
31631
|
+
Returns a summary of installed, skipped (already installed), and failed components.
|
|
31632
|
+
|
|
31633
|
+
Use this when you need to install a bill of materials or multiple components at once.`,
|
|
31634
|
+
inputSchema: {
|
|
31635
|
+
type: "object",
|
|
31636
|
+
properties: {
|
|
31637
|
+
ids: {
|
|
31638
|
+
type: "array",
|
|
31639
|
+
items: { type: "string" },
|
|
31640
|
+
maxItems: 10,
|
|
31641
|
+
description: 'Array of LCSC part numbers (e.g., ["C2040", "C5446", "C14663"])'
|
|
31642
|
+
},
|
|
31643
|
+
force: {
|
|
31644
|
+
type: "boolean",
|
|
31645
|
+
description: "Reinstall even if already exists (default: false)"
|
|
31646
|
+
},
|
|
31647
|
+
include_3d: {
|
|
31648
|
+
type: "boolean",
|
|
31649
|
+
description: "Include 3D models if available (default: false)"
|
|
31650
|
+
}
|
|
31651
|
+
},
|
|
31652
|
+
required: ["ids"]
|
|
31653
|
+
}
|
|
31654
|
+
};
|
|
31655
|
+
var BatchInstallParamsSchema = exports_external.object({
|
|
31656
|
+
ids: exports_external.array(LCSCPartNumberSchema).min(1).max(10),
|
|
31657
|
+
force: exports_external.boolean().optional(),
|
|
31658
|
+
include_3d: exports_external.boolean().optional()
|
|
31659
|
+
});
|
|
31660
|
+
async function handleLibraryBatchInstall(args) {
|
|
31661
|
+
const params = BatchInstallParamsSchema.parse(args);
|
|
31662
|
+
const results = [];
|
|
31663
|
+
let installed = 0;
|
|
31664
|
+
let skipped = 0;
|
|
31665
|
+
let failed = 0;
|
|
31666
|
+
const installPromises = params.ids.map(async (id) => {
|
|
31667
|
+
try {
|
|
31668
|
+
const result = await getLibraryService().install(id, {
|
|
31669
|
+
include3d: params.include_3d,
|
|
31670
|
+
force: params.force
|
|
31671
|
+
});
|
|
31672
|
+
if (result.symbolAction === "exists") {
|
|
31673
|
+
return {
|
|
31674
|
+
id,
|
|
31675
|
+
status: "skipped",
|
|
31676
|
+
symbol_ref: result.symbolRef,
|
|
31677
|
+
footprint_ref: result.footprintRef,
|
|
31678
|
+
reason: "already installed"
|
|
31679
|
+
};
|
|
31680
|
+
}
|
|
31681
|
+
return {
|
|
31682
|
+
id,
|
|
31683
|
+
status: "installed",
|
|
31684
|
+
symbol_ref: result.symbolRef,
|
|
31685
|
+
footprint_ref: result.footprintRef
|
|
31686
|
+
};
|
|
31687
|
+
} catch (error2) {
|
|
31688
|
+
return {
|
|
31689
|
+
id,
|
|
31690
|
+
status: "failed",
|
|
31691
|
+
error: error2 instanceof Error ? error2.message : "Unknown error"
|
|
31692
|
+
};
|
|
31693
|
+
}
|
|
31694
|
+
});
|
|
31695
|
+
const installResults = await Promise.all(installPromises);
|
|
31696
|
+
for (const result of installResults) {
|
|
31697
|
+
results.push(result);
|
|
31698
|
+
if (result.status === "installed")
|
|
31699
|
+
installed++;
|
|
31700
|
+
else if (result.status === "skipped")
|
|
31701
|
+
skipped++;
|
|
31702
|
+
else
|
|
31703
|
+
failed++;
|
|
31704
|
+
}
|
|
31320
31705
|
return {
|
|
31321
31706
|
content: [{
|
|
31322
31707
|
type: "text",
|
|
31323
|
-
text:
|
|
31324
|
-
|
|
31325
|
-
|
|
31326
|
-
|
|
31708
|
+
text: JSON.stringify({
|
|
31709
|
+
success: failed < params.ids.length,
|
|
31710
|
+
summary: {
|
|
31711
|
+
total: params.ids.length,
|
|
31712
|
+
installed,
|
|
31713
|
+
skipped,
|
|
31714
|
+
failed
|
|
31715
|
+
},
|
|
31716
|
+
results
|
|
31717
|
+
})
|
|
31327
31718
|
}]
|
|
31328
31719
|
};
|
|
31329
31720
|
}
|
|
31330
31721
|
|
|
31331
31722
|
// src/tools/library-update.ts
|
|
31332
|
-
import { existsSync as
|
|
31723
|
+
import { existsSync as existsSync5, readdirSync } from "fs";
|
|
31333
31724
|
import { readFile as readFile5 } from "fs/promises";
|
|
31334
|
-
import { homedir as
|
|
31335
|
-
import { join as
|
|
31336
|
-
var KICAD_VERSIONS = ["9.0", "8.0"];
|
|
31725
|
+
import { homedir as homedir4, platform as platform4 } from "os";
|
|
31726
|
+
import { join as join7 } from "path";
|
|
31337
31727
|
var LIBRARY_NAMESPACE3 = "jlc_mcp";
|
|
31338
|
-
function detectKicadVersion3() {
|
|
31339
|
-
const home = homedir3();
|
|
31340
|
-
const baseDir = join6(home, "Documents", "KiCad");
|
|
31341
|
-
for (const version2 of KICAD_VERSIONS) {
|
|
31342
|
-
if (existsSync4(join6(baseDir, version2))) {
|
|
31343
|
-
return version2;
|
|
31344
|
-
}
|
|
31345
|
-
}
|
|
31346
|
-
return "9.0";
|
|
31347
|
-
}
|
|
31348
31728
|
function getLibraryPaths(projectPath) {
|
|
31349
31729
|
if (projectPath) {
|
|
31350
|
-
const librariesDir =
|
|
31730
|
+
const librariesDir = join7(projectPath, "libraries");
|
|
31351
31731
|
return {
|
|
31352
|
-
symbolsDir:
|
|
31353
|
-
footprintDir:
|
|
31354
|
-
models3dDir:
|
|
31732
|
+
symbolsDir: join7(librariesDir, "symbols"),
|
|
31733
|
+
footprintDir: join7(librariesDir, "footprints", getFootprintDirName()),
|
|
31734
|
+
models3dDir: join7(librariesDir, "3dmodels", get3DModelsDirName())
|
|
31355
31735
|
};
|
|
31356
31736
|
}
|
|
31357
|
-
const home =
|
|
31358
|
-
const version2 =
|
|
31359
|
-
const plat =
|
|
31737
|
+
const home = homedir4();
|
|
31738
|
+
const version2 = detectKicadVersion();
|
|
31739
|
+
const plat = platform4();
|
|
31360
31740
|
let base;
|
|
31361
31741
|
if (plat === "linux") {
|
|
31362
|
-
base =
|
|
31742
|
+
base = join7(home, ".local", "share", "kicad", version2, "3rdparty", LIBRARY_NAMESPACE3);
|
|
31363
31743
|
} else {
|
|
31364
|
-
base =
|
|
31744
|
+
base = join7(home, "Documents", "KiCad", version2, "3rdparty", LIBRARY_NAMESPACE3);
|
|
31365
31745
|
}
|
|
31366
31746
|
return {
|
|
31367
|
-
symbolsDir:
|
|
31368
|
-
footprintDir:
|
|
31369
|
-
models3dDir:
|
|
31747
|
+
symbolsDir: join7(base, "symbols"),
|
|
31748
|
+
footprintDir: join7(base, "footprints", getFootprintDirName()),
|
|
31749
|
+
models3dDir: join7(base, "3dmodels", get3DModelsDirName())
|
|
31370
31750
|
};
|
|
31371
31751
|
}
|
|
31372
31752
|
function extractLcscIdsFromLibrary(content) {
|
|
@@ -31387,12 +31767,12 @@ function generateEmptyLibrary() {
|
|
|
31387
31767
|
`;
|
|
31388
31768
|
}
|
|
31389
31769
|
function findJlcLibraries(symbolsDir) {
|
|
31390
|
-
if (!
|
|
31770
|
+
if (!existsSync5(symbolsDir)) {
|
|
31391
31771
|
return [];
|
|
31392
31772
|
}
|
|
31393
31773
|
try {
|
|
31394
31774
|
const files = readdirSync(symbolsDir);
|
|
31395
|
-
return files.filter((f) => f.startsWith("JLC-MCP-") && f.endsWith(".kicad_sym")).map((f) =>
|
|
31775
|
+
return files.filter((f) => f.startsWith("JLC-MCP-") && f.endsWith(".kicad_sym")).map((f) => join7(symbolsDir, f));
|
|
31396
31776
|
} catch {
|
|
31397
31777
|
return [];
|
|
31398
31778
|
}
|
|
@@ -31459,7 +31839,7 @@ async function handleUpdateLibrary(args) {
|
|
|
31459
31839
|
libraries_to_create: allCategories.map((cat) => ({
|
|
31460
31840
|
category: cat,
|
|
31461
31841
|
filename: getLibraryFilename(cat),
|
|
31462
|
-
path:
|
|
31842
|
+
path: join7(paths.symbolsDir, getLibraryFilename(cat))
|
|
31463
31843
|
}))
|
|
31464
31844
|
}, null, 2)
|
|
31465
31845
|
}]
|
|
@@ -31472,7 +31852,7 @@ async function handleUpdateLibrary(args) {
|
|
|
31472
31852
|
const createdLibraries = [];
|
|
31473
31853
|
for (const category of allCategories) {
|
|
31474
31854
|
const filename = getLibraryFilename(category);
|
|
31475
|
-
const filepath =
|
|
31855
|
+
const filepath = join7(paths.symbolsDir, filename);
|
|
31476
31856
|
await writeText(filepath, emptyContent);
|
|
31477
31857
|
createdLibraries.push(filepath);
|
|
31478
31858
|
}
|
|
@@ -31549,7 +31929,7 @@ async function handleUpdateLibrary(args) {
|
|
|
31549
31929
|
if (!params.dry_run && footprintResult.type === "generated") {
|
|
31550
31930
|
await ensureDir(paths.footprintDir);
|
|
31551
31931
|
const footprintName = footprintResult.name + "_" + lcscId;
|
|
31552
|
-
const footprintPath =
|
|
31932
|
+
const footprintPath = join7(paths.footprintDir, `${footprintName}.kicad_mod`);
|
|
31553
31933
|
await writeText(footprintPath, footprintResult.content);
|
|
31554
31934
|
}
|
|
31555
31935
|
results.push({
|
|
@@ -31576,7 +31956,7 @@ async function handleUpdateLibrary(args) {
|
|
|
31576
31956
|
await ensureDir(paths.symbolsDir);
|
|
31577
31957
|
for (const [category, entries] of categorySymbols) {
|
|
31578
31958
|
const filename = getLibraryFilename(category);
|
|
31579
|
-
const filepath =
|
|
31959
|
+
const filepath = join7(paths.symbolsDir, filename);
|
|
31580
31960
|
const header = `(kicad_symbol_lib
|
|
31581
31961
|
(version 20241209)
|
|
31582
31962
|
(generator "jlc-mcp")
|
|
@@ -31604,53 +31984,41 @@ async function handleUpdateLibrary(args) {
|
|
|
31604
31984
|
success: true,
|
|
31605
31985
|
dry_run: params.dry_run,
|
|
31606
31986
|
summary: {
|
|
31607
|
-
|
|
31987
|
+
total: allLcscIds.size,
|
|
31608
31988
|
updated: successful.length,
|
|
31609
|
-
failed: failed.length
|
|
31610
|
-
libraries_generated: categorySymbols.size
|
|
31989
|
+
failed: failed.length
|
|
31611
31990
|
},
|
|
31612
31991
|
by_category: Object.fromEntries(byCategory),
|
|
31613
31992
|
footprint_stats: footprintStats,
|
|
31614
|
-
|
|
31615
|
-
failed_components: failed.map((f) => ({
|
|
31993
|
+
failed_sample: failed.slice(0, 5).map((f) => ({
|
|
31616
31994
|
lcsc_id: f.lcscId,
|
|
31617
31995
|
error: f.error
|
|
31618
|
-
}))
|
|
31619
|
-
|
|
31996
|
+
})),
|
|
31997
|
+
has_more_failures: failed.length > 5
|
|
31998
|
+
})
|
|
31620
31999
|
}]
|
|
31621
32000
|
};
|
|
31622
32001
|
}
|
|
31623
32002
|
|
|
31624
32003
|
// src/tools/library-fix.ts
|
|
31625
|
-
import { existsSync as
|
|
32004
|
+
import { existsSync as existsSync7 } from "fs";
|
|
31626
32005
|
import { readFile as readFile7 } from "fs/promises";
|
|
31627
|
-
import { homedir as
|
|
31628
|
-
import { join as
|
|
31629
|
-
var KICAD_VERSIONS4 = ["9.0", "8.0"];
|
|
31630
|
-
function detectKicadVersion5() {
|
|
31631
|
-
const home = homedir5();
|
|
31632
|
-
const baseDir = join8(home, "Documents", "KiCad");
|
|
31633
|
-
for (const version2 of KICAD_VERSIONS4) {
|
|
31634
|
-
if (existsSync6(join8(baseDir, version2))) {
|
|
31635
|
-
return version2;
|
|
31636
|
-
}
|
|
31637
|
-
}
|
|
31638
|
-
return "9.0";
|
|
31639
|
-
}
|
|
32006
|
+
import { homedir as homedir6 } from "os";
|
|
32007
|
+
import { join as join9 } from "path";
|
|
31640
32008
|
function getLibraryPaths2(projectPath) {
|
|
31641
32009
|
if (projectPath) {
|
|
31642
|
-
const librariesDir =
|
|
32010
|
+
const librariesDir = join9(projectPath, "libraries");
|
|
31643
32011
|
return {
|
|
31644
|
-
symbolsDir:
|
|
31645
|
-
footprintDir:
|
|
32012
|
+
symbolsDir: join9(librariesDir, "symbols"),
|
|
32013
|
+
footprintDir: join9(librariesDir, "footprints", getFootprintDirName())
|
|
31646
32014
|
};
|
|
31647
32015
|
}
|
|
31648
|
-
const home =
|
|
31649
|
-
const version2 =
|
|
31650
|
-
const base =
|
|
32016
|
+
const home = homedir6();
|
|
32017
|
+
const version2 = detectKicadVersion();
|
|
32018
|
+
const base = join9(home, "Documents", "KiCad", version2);
|
|
31651
32019
|
return {
|
|
31652
|
-
symbolsDir:
|
|
31653
|
-
footprintDir:
|
|
32020
|
+
symbolsDir: join9(base, "symbols"),
|
|
32021
|
+
footprintDir: join9(base, "footprints", getFootprintDirName())
|
|
31654
32022
|
};
|
|
31655
32023
|
}
|
|
31656
32024
|
var PinElectricalType = exports_external.enum([
|
|
@@ -31818,8 +32186,8 @@ async function handleFixLibrary(args) {
|
|
|
31818
32186
|
}
|
|
31819
32187
|
const category = getLibraryCategory(component.info.prefix, component.info.category, component.info.description);
|
|
31820
32188
|
const symbolLibraryFilename = getLibraryFilename(category);
|
|
31821
|
-
const symbolFile =
|
|
31822
|
-
if (!
|
|
32189
|
+
const symbolFile = join9(paths.symbolsDir, symbolLibraryFilename);
|
|
32190
|
+
if (!existsSync7(symbolFile) && !params.force) {
|
|
31823
32191
|
return {
|
|
31824
32192
|
content: [{
|
|
31825
32193
|
type: "text",
|
|
@@ -31833,7 +32201,7 @@ async function handleFixLibrary(args) {
|
|
|
31833
32201
|
isError: true
|
|
31834
32202
|
};
|
|
31835
32203
|
}
|
|
31836
|
-
if (
|
|
32204
|
+
if (existsSync7(symbolFile) && !params.force) {
|
|
31837
32205
|
const existingContent = await readFile7(symbolFile, "utf-8");
|
|
31838
32206
|
if (!symbolConverter.symbolExistsInLibrary(existingContent, component.info.name)) {
|
|
31839
32207
|
return {
|
|
@@ -31920,14 +32288,14 @@ async function handleFixLibrary(args) {
|
|
|
31920
32288
|
const footprintName = footprintResult.name + "_" + params.lcsc_id;
|
|
31921
32289
|
footprintRef = getFootprintReference2(footprintName);
|
|
31922
32290
|
await ensureDir(paths.footprintDir);
|
|
31923
|
-
const footprintPath =
|
|
32291
|
+
const footprintPath = join9(paths.footprintDir, `${footprintName}.kicad_mod`);
|
|
31924
32292
|
await writeText(footprintPath, footprintResult.content);
|
|
31925
32293
|
}
|
|
31926
32294
|
component.info.package = footprintRef;
|
|
31927
32295
|
await ensureDir(paths.symbolsDir);
|
|
31928
32296
|
let symbolContent;
|
|
31929
32297
|
let symbolAction;
|
|
31930
|
-
if (
|
|
32298
|
+
if (existsSync7(symbolFile)) {
|
|
31931
32299
|
const existingContent = await readFile7(symbolFile, "utf-8");
|
|
31932
32300
|
symbolContent = symbolConverter.replaceInLibrary(existingContent, component);
|
|
31933
32301
|
symbolAction = "replaced";
|
|
@@ -31956,494 +32324,31 @@ async function handleFixLibrary(args) {
|
|
|
31956
32324
|
};
|
|
31957
32325
|
}
|
|
31958
32326
|
|
|
31959
|
-
// src/tools/easyeda.ts
|
|
31960
|
-
import { join as join9 } from "path";
|
|
31961
|
-
import { execSync as execSync2 } from "child_process";
|
|
31962
|
-
import { tmpdir } from "os";
|
|
31963
|
-
var easyedaSearchTool = {
|
|
31964
|
-
name: "easyeda_search",
|
|
31965
|
-
description: "Search EasyEDA community library for user-contributed symbols and footprints. Use this for parts not in LCSC official library (e.g., XIAO, Arduino modules, custom breakouts). Returns results with UUIDs and optionally opens an HTML preview.",
|
|
31966
|
-
inputSchema: {
|
|
31967
|
-
type: "object",
|
|
31968
|
-
properties: {
|
|
31969
|
-
query: {
|
|
31970
|
-
type: "string",
|
|
31971
|
-
description: 'Search term (e.g., "XIAO RP2040", "ESP32-C3 module")'
|
|
31972
|
-
},
|
|
31973
|
-
source: {
|
|
31974
|
-
type: "string",
|
|
31975
|
-
enum: ["user", "lcsc", "easyeda", "all"],
|
|
31976
|
-
description: 'Filter by source. "user" for community-contributed (default)'
|
|
31977
|
-
},
|
|
31978
|
-
limit: {
|
|
31979
|
-
type: "number",
|
|
31980
|
-
description: "Max results to return (default: 20)"
|
|
31981
|
-
},
|
|
31982
|
-
open_preview: {
|
|
31983
|
-
type: "boolean",
|
|
31984
|
-
description: "Generate and open HTML preview in browser",
|
|
31985
|
-
default: true
|
|
31986
|
-
}
|
|
31987
|
-
},
|
|
31988
|
-
required: ["query"]
|
|
31989
|
-
}
|
|
31990
|
-
};
|
|
31991
|
-
var easyedaGet3DModelTool = {
|
|
31992
|
-
name: "easyeda_get_3d_model",
|
|
31993
|
-
description: "Download 3D model for an EasyEDA community component. Requires the model UUID from easyeda_get.",
|
|
31994
|
-
inputSchema: {
|
|
31995
|
-
type: "object",
|
|
31996
|
-
properties: {
|
|
31997
|
-
uuid: {
|
|
31998
|
-
type: "string",
|
|
31999
|
-
description: "3D model UUID from easyeda_get result"
|
|
32000
|
-
},
|
|
32001
|
-
format: {
|
|
32002
|
-
type: "string",
|
|
32003
|
-
enum: ["step", "obj"],
|
|
32004
|
-
description: 'Model format: "step" or "obj" (default: step)'
|
|
32005
|
-
}
|
|
32006
|
-
},
|
|
32007
|
-
required: ["uuid"]
|
|
32008
|
-
}
|
|
32009
|
-
};
|
|
32010
|
-
var EasyedaSearchParamsSchema = exports_external.object({
|
|
32011
|
-
query: exports_external.string().min(1),
|
|
32012
|
-
source: exports_external.enum(["user", "lcsc", "easyeda", "all"]).optional(),
|
|
32013
|
-
limit: exports_external.number().min(1).max(100).optional(),
|
|
32014
|
-
open_preview: exports_external.boolean().optional()
|
|
32015
|
-
});
|
|
32016
|
-
var EasyedaGet3DModelParamsSchema = exports_external.object({
|
|
32017
|
-
uuid: exports_external.string().min(1),
|
|
32018
|
-
format: exports_external.enum(["step", "obj"]).default("step")
|
|
32019
|
-
});
|
|
32020
|
-
async function handleEasyedaSearch(args) {
|
|
32021
|
-
const params = EasyedaSearchParamsSchema.parse(args);
|
|
32022
|
-
const openPreview = params.open_preview ?? true;
|
|
32023
|
-
const results = await easyedaCommunityClient.search({
|
|
32024
|
-
query: params.query,
|
|
32025
|
-
source: params.source,
|
|
32026
|
-
limit: params.limit || 20
|
|
32027
|
-
});
|
|
32028
|
-
if (results.length === 0) {
|
|
32029
|
-
return {
|
|
32030
|
-
content: [
|
|
32031
|
-
{
|
|
32032
|
-
type: "text",
|
|
32033
|
-
text: `No results found for "${params.query}"`
|
|
32034
|
-
}
|
|
32035
|
-
]
|
|
32036
|
-
};
|
|
32037
|
-
}
|
|
32038
|
-
let output = `Found ${results.length} results for "${params.query}":
|
|
32039
|
-
|
|
32040
|
-
`;
|
|
32041
|
-
output += `| # | Title | Package | Owner | UUID |
|
|
32042
|
-
`;
|
|
32043
|
-
output += `|---|-------|---------|-------|------|
|
|
32044
|
-
`;
|
|
32045
|
-
for (let i = 0;i < results.length; i++) {
|
|
32046
|
-
const r = results[i];
|
|
32047
|
-
output += `| ${i + 1} | ${r.title} | ${r.package} | ${r.owner.nickname || r.owner.username} | ${r.uuid} |
|
|
32048
|
-
`;
|
|
32049
|
-
}
|
|
32050
|
-
output += "\nUse `library_fetch` with the UUID to add component to global JLC-MCP libraries.";
|
|
32051
|
-
output += "\nUse `easyeda_fetch` with the UUID to add to project-local EasyEDA library.";
|
|
32052
|
-
if (openPreview) {
|
|
32053
|
-
const { filepath, browserOpened } = await generateHtmlPreview(params.query, results);
|
|
32054
|
-
if (browserOpened) {
|
|
32055
|
-
output += `
|
|
32056
|
-
|
|
32057
|
-
HTML preview opened in browser.`;
|
|
32058
|
-
} else {
|
|
32059
|
-
output += `
|
|
32060
|
-
|
|
32061
|
-
Could not open browser automatically.`;
|
|
32062
|
-
}
|
|
32063
|
-
output += `
|
|
32064
|
-
Preview file: ${filepath}`;
|
|
32065
|
-
}
|
|
32066
|
-
return {
|
|
32067
|
-
content: [
|
|
32068
|
-
{
|
|
32069
|
-
type: "text",
|
|
32070
|
-
text: output
|
|
32071
|
-
}
|
|
32072
|
-
]
|
|
32073
|
-
};
|
|
32074
|
-
}
|
|
32075
|
-
async function handleEasyedaGet3DModel(args) {
|
|
32076
|
-
const params = EasyedaGet3DModelParamsSchema.parse(args);
|
|
32077
|
-
const model = await easyedaCommunityClient.get3DModel(params.uuid, params.format);
|
|
32078
|
-
if (!model) {
|
|
32079
|
-
return {
|
|
32080
|
-
content: [
|
|
32081
|
-
{
|
|
32082
|
-
type: "text",
|
|
32083
|
-
text: `3D model ${params.uuid} not found`
|
|
32084
|
-
}
|
|
32085
|
-
],
|
|
32086
|
-
isError: true
|
|
32087
|
-
};
|
|
32088
|
-
}
|
|
32089
|
-
return {
|
|
32090
|
-
content: [
|
|
32091
|
-
{
|
|
32092
|
-
type: "text",
|
|
32093
|
-
text: `3D model downloaded (${model.length} bytes, ${params.format.toUpperCase()} format)
|
|
32094
|
-
|
|
32095
|
-
Base64 data:
|
|
32096
|
-
${model.toString("base64").slice(0, 500)}...`
|
|
32097
|
-
}
|
|
32098
|
-
]
|
|
32099
|
-
};
|
|
32100
|
-
}
|
|
32101
|
-
async function generateHtmlPreview(query, results) {
|
|
32102
|
-
const timestamp = Date.now();
|
|
32103
|
-
const filename = `easyeda-search-${timestamp}.html`;
|
|
32104
|
-
const filepath = join9(tmpdir(), filename);
|
|
32105
|
-
const noImageSvg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 150" style="background:#2a2a2a"><text x="100" y="75" text-anchor="middle" fill="#666" font-size="12">No Preview</text></svg>`;
|
|
32106
|
-
const noImageDataUri = `data:image/svg+xml,${encodeURIComponent(noImageSvg)}`;
|
|
32107
|
-
const cardsPromises = results.slice(0, 10).map(async (r) => {
|
|
32108
|
-
const symbolImageUrl = `https://image.easyeda.com/components/${r.uuid}.png`;
|
|
32109
|
-
let footprintSvg = "";
|
|
32110
|
-
try {
|
|
32111
|
-
const component = await easyedaCommunityClient.getComponent(r.uuid);
|
|
32112
|
-
if (component) {
|
|
32113
|
-
const rawData = component.rawData;
|
|
32114
|
-
const fpDataStr = rawData?.packageDetail?.dataStr || rawData?.dataStr;
|
|
32115
|
-
if (fpDataStr?.shape) {
|
|
32116
|
-
footprintSvg = generateFootprintSvg(fpDataStr);
|
|
32117
|
-
}
|
|
32118
|
-
}
|
|
32119
|
-
} catch {}
|
|
32120
|
-
const footprintDataUri = footprintSvg ? `data:image/svg+xml,${encodeURIComponent(footprintSvg)}` : noImageDataUri;
|
|
32121
|
-
return `
|
|
32122
|
-
<div class="card">
|
|
32123
|
-
<div class="images">
|
|
32124
|
-
<div class="image-box">
|
|
32125
|
-
<div class="image-label">Symbol</div>
|
|
32126
|
-
<img src="${symbolImageUrl}" alt="Symbol" onerror="this.src='${noImageDataUri}'">
|
|
32127
|
-
</div>
|
|
32128
|
-
<div class="image-box">
|
|
32129
|
-
<div class="image-label">Footprint</div>
|
|
32130
|
-
<img src="${footprintDataUri}" alt="Footprint">
|
|
32131
|
-
</div>
|
|
32132
|
-
</div>
|
|
32133
|
-
<h3>${escapeHtml(r.title)}</h3>
|
|
32134
|
-
<div class="meta">
|
|
32135
|
-
<div><strong>Package:</strong> ${escapeHtml(r.package || "N/A")}</div>
|
|
32136
|
-
<div><strong>Owner:</strong> ${escapeHtml(r.owner.nickname || r.owner.username)}</div>
|
|
32137
|
-
${r.manufacturer ? `<div><strong>Mfr:</strong> ${escapeHtml(r.manufacturer)}</div>` : ""}
|
|
32138
|
-
</div>
|
|
32139
|
-
<div class="uuid" onclick="navigator.clipboard.writeText('${r.uuid}'); this.classList.add('copied'); setTimeout(() => this.classList.remove('copied'), 1000);">
|
|
32140
|
-
${r.uuid}
|
|
32141
|
-
</div>
|
|
32142
|
-
</div>`;
|
|
32143
|
-
});
|
|
32144
|
-
const cards = (await Promise.all(cardsPromises)).join(`
|
|
32145
|
-
`);
|
|
32146
|
-
const html = `<!DOCTYPE html>
|
|
32147
|
-
<html lang="en">
|
|
32148
|
-
<head>
|
|
32149
|
-
<meta charset="UTF-8">
|
|
32150
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
32151
|
-
<title>EasyEDA Search: ${escapeHtml(query)}</title>
|
|
32152
|
-
<style>
|
|
32153
|
-
* { box-sizing: border-box; }
|
|
32154
|
-
body {
|
|
32155
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
32156
|
-
max-width: 1400px;
|
|
32157
|
-
margin: 0 auto;
|
|
32158
|
-
padding: 20px;
|
|
32159
|
-
background: #f9f9f9;
|
|
32160
|
-
color: #333;
|
|
32161
|
-
}
|
|
32162
|
-
h1 { margin-bottom: 8px; }
|
|
32163
|
-
.subtitle { color: #666; margin-bottom: 20px; }
|
|
32164
|
-
.grid {
|
|
32165
|
-
display: grid;
|
|
32166
|
-
grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
|
|
32167
|
-
gap: 16px;
|
|
32168
|
-
}
|
|
32169
|
-
.card {
|
|
32170
|
-
background: white;
|
|
32171
|
-
border: 1px solid #ddd;
|
|
32172
|
-
border-radius: 8px;
|
|
32173
|
-
padding: 16px;
|
|
32174
|
-
transition: box-shadow 0.2s;
|
|
32175
|
-
}
|
|
32176
|
-
.card:hover { box-shadow: 0 4px 12px rgba(0,0,0,0.1); }
|
|
32177
|
-
.card .images {
|
|
32178
|
-
display: flex;
|
|
32179
|
-
gap: 8px;
|
|
32180
|
-
margin-bottom: 12px;
|
|
32181
|
-
}
|
|
32182
|
-
.card .image-box {
|
|
32183
|
-
flex: 1;
|
|
32184
|
-
min-width: 0;
|
|
32185
|
-
}
|
|
32186
|
-
.card .image-label {
|
|
32187
|
-
font-size: 10px;
|
|
32188
|
-
color: #888;
|
|
32189
|
-
text-transform: uppercase;
|
|
32190
|
-
text-align: center;
|
|
32191
|
-
margin-bottom: 4px;
|
|
32192
|
-
}
|
|
32193
|
-
.card img {
|
|
32194
|
-
width: 100%;
|
|
32195
|
-
height: 120px;
|
|
32196
|
-
object-fit: contain;
|
|
32197
|
-
border-radius: 4px;
|
|
32198
|
-
border: 1px solid #eee;
|
|
32199
|
-
}
|
|
32200
|
-
.card h3 {
|
|
32201
|
-
margin: 0 0 8px;
|
|
32202
|
-
font-size: 15px;
|
|
32203
|
-
line-height: 1.3;
|
|
32204
|
-
overflow: hidden;
|
|
32205
|
-
text-overflow: ellipsis;
|
|
32206
|
-
white-space: nowrap;
|
|
32207
|
-
}
|
|
32208
|
-
.card .meta {
|
|
32209
|
-
color: #666;
|
|
32210
|
-
font-size: 12px;
|
|
32211
|
-
line-height: 1.6;
|
|
32212
|
-
}
|
|
32213
|
-
.card .meta div { margin-bottom: 2px; }
|
|
32214
|
-
.card .uuid {
|
|
32215
|
-
font-family: 'SF Mono', Monaco, 'Courier New', monospace;
|
|
32216
|
-
font-size: 10px;
|
|
32217
|
-
color: #888;
|
|
32218
|
-
background: #f5f5f5;
|
|
32219
|
-
padding: 6px 8px;
|
|
32220
|
-
border-radius: 4px;
|
|
32221
|
-
margin-top: 12px;
|
|
32222
|
-
cursor: pointer;
|
|
32223
|
-
word-break: break-all;
|
|
32224
|
-
transition: background 0.2s;
|
|
32225
|
-
}
|
|
32226
|
-
.card .uuid:hover { background: #e8e8e8; }
|
|
32227
|
-
.card .uuid.copied { background: #d4edda; color: #155724; }
|
|
32228
|
-
.instructions {
|
|
32229
|
-
background: #e8f4fd;
|
|
32230
|
-
border: 1px solid #b8daff;
|
|
32231
|
-
border-radius: 8px;
|
|
32232
|
-
padding: 16px;
|
|
32233
|
-
margin-bottom: 20px;
|
|
32234
|
-
font-size: 14px;
|
|
32235
|
-
}
|
|
32236
|
-
.instructions code {
|
|
32237
|
-
background: #fff;
|
|
32238
|
-
padding: 2px 6px;
|
|
32239
|
-
border-radius: 4px;
|
|
32240
|
-
font-family: 'SF Mono', Monaco, monospace;
|
|
32241
|
-
}
|
|
32242
|
-
</style>
|
|
32243
|
-
</head>
|
|
32244
|
-
<body>
|
|
32245
|
-
<h1>EasyEDA Search: "${escapeHtml(query)}"</h1>
|
|
32246
|
-
<p class="subtitle">Found ${results.length} results. Click UUID to copy to clipboard.</p>
|
|
32247
|
-
|
|
32248
|
-
<div class="instructions">
|
|
32249
|
-
<strong>How to use:</strong><br>
|
|
32250
|
-
1. Click on a UUID to copy it<br>
|
|
32251
|
-
2. Use <code>library_fetch</code> with the UUID to add to global JLC-MCP libraries<br>
|
|
32252
|
-
3. Or use <code>easyeda_fetch</code> for project-local EasyEDA library
|
|
32253
|
-
</div>
|
|
32254
|
-
|
|
32255
|
-
<div class="grid">
|
|
32256
|
-
${cards}
|
|
32257
|
-
</div>
|
|
32258
|
-
</body>
|
|
32259
|
-
</html>`;
|
|
32260
|
-
__require("fs").writeFileSync(filepath, html, "utf-8");
|
|
32261
|
-
const browserOpened = openInBrowser(filepath);
|
|
32262
|
-
return { filepath, browserOpened };
|
|
32263
|
-
}
|
|
32264
|
-
function openInBrowser(filepath) {
|
|
32265
|
-
const platform4 = process.platform;
|
|
32266
|
-
try {
|
|
32267
|
-
switch (platform4) {
|
|
32268
|
-
case "darwin":
|
|
32269
|
-
execSync2(`open "${filepath}"`, { stdio: "ignore" });
|
|
32270
|
-
return true;
|
|
32271
|
-
case "win32":
|
|
32272
|
-
execSync2(`start "" "${filepath}"`, { stdio: "ignore", shell: "cmd.exe" });
|
|
32273
|
-
return true;
|
|
32274
|
-
case "linux":
|
|
32275
|
-
default:
|
|
32276
|
-
execSync2(`xdg-open "${filepath}"`, { stdio: "ignore" });
|
|
32277
|
-
return true;
|
|
32278
|
-
}
|
|
32279
|
-
} catch {
|
|
32280
|
-
const fallbacks = ["xdg-open", "sensible-browser", "x-www-browser", "gnome-open"];
|
|
32281
|
-
for (const cmd of fallbacks) {
|
|
32282
|
-
try {
|
|
32283
|
-
execSync2(`${cmd} "${filepath}"`, { stdio: "ignore" });
|
|
32284
|
-
return true;
|
|
32285
|
-
} catch {}
|
|
32286
|
-
}
|
|
32287
|
-
return false;
|
|
32288
|
-
}
|
|
32289
|
-
}
|
|
32290
|
-
function escapeHtml(str) {
|
|
32291
|
-
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
32292
|
-
}
|
|
32293
|
-
function generateFootprintSvg(dataStr) {
|
|
32294
|
-
if (!dataStr.shape || dataStr.shape.length === 0) {
|
|
32295
|
-
return "";
|
|
32296
|
-
}
|
|
32297
|
-
const bbox = dataStr.BBox || { x: 0, y: 0, width: 100, height: 100 };
|
|
32298
|
-
const padding = 5;
|
|
32299
|
-
const viewBox = `${bbox.x - padding} ${bbox.y - padding} ${bbox.width + padding * 2} ${bbox.height + padding * 2}`;
|
|
32300
|
-
const regions = [];
|
|
32301
|
-
const tracks = [];
|
|
32302
|
-
const pads = [];
|
|
32303
|
-
const holes = [];
|
|
32304
|
-
const texts = [];
|
|
32305
|
-
for (const shape of dataStr.shape) {
|
|
32306
|
-
if (typeof shape !== "string")
|
|
32307
|
-
continue;
|
|
32308
|
-
if (shape.startsWith("SOLIDREGION~")) {
|
|
32309
|
-
const svg = renderSolidRegion(shape);
|
|
32310
|
-
if (svg)
|
|
32311
|
-
regions.push(svg);
|
|
32312
|
-
} else if (shape.startsWith("TRACK~")) {
|
|
32313
|
-
const svg = renderTrackShape(shape);
|
|
32314
|
-
if (svg)
|
|
32315
|
-
tracks.push(svg);
|
|
32316
|
-
} else if (shape.startsWith("PAD~")) {
|
|
32317
|
-
const result = renderPadShape(shape);
|
|
32318
|
-
if (result) {
|
|
32319
|
-
pads.push(result.pad);
|
|
32320
|
-
if (result.hole)
|
|
32321
|
-
holes.push(result.hole);
|
|
32322
|
-
}
|
|
32323
|
-
} else if (shape.startsWith("TEXT~")) {
|
|
32324
|
-
const svg = renderTextShape(shape);
|
|
32325
|
-
if (svg)
|
|
32326
|
-
texts.push(svg);
|
|
32327
|
-
}
|
|
32328
|
-
}
|
|
32329
|
-
const allElements = [...regions, ...tracks, ...pads, ...holes, ...texts];
|
|
32330
|
-
if (allElements.length === 0) {
|
|
32331
|
-
return "";
|
|
32332
|
-
}
|
|
32333
|
-
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="${viewBox}" style="background:#000000">
|
|
32334
|
-
<style>
|
|
32335
|
-
.pad { fill: #CC0000; stroke: none; }
|
|
32336
|
-
.pad-hole { fill: #666666; }
|
|
32337
|
-
.track { fill: none; stroke: #FFFF00; stroke-linecap: round; stroke-linejoin: round; }
|
|
32338
|
-
.region { fill: #CC0000; opacity: 0.6; }
|
|
32339
|
-
.text-path { fill: none; stroke: #FFFF00; stroke-width: 0.4; stroke-linecap: round; stroke-linejoin: round; }
|
|
32340
|
-
</style>
|
|
32341
|
-
${allElements.join(`
|
|
32342
|
-
`)}
|
|
32343
|
-
</svg>`;
|
|
32344
|
-
}
|
|
32345
|
-
function renderPadShape(padData) {
|
|
32346
|
-
const fields = padData.split("~");
|
|
32347
|
-
const shapeType = fields[1];
|
|
32348
|
-
const cx = parseFloat(fields[2]) || 0;
|
|
32349
|
-
const cy = parseFloat(fields[3]) || 0;
|
|
32350
|
-
if (shapeType === "POLYGON") {
|
|
32351
|
-
const holeDia2 = parseFloat(fields[9]) || 0;
|
|
32352
|
-
const pointsStr = fields[10] || "";
|
|
32353
|
-
if (!pointsStr)
|
|
32354
|
-
return null;
|
|
32355
|
-
const coords = pointsStr.split(" ").map(Number);
|
|
32356
|
-
if (coords.length < 4)
|
|
32357
|
-
return null;
|
|
32358
|
-
let pathD = `M ${coords[0]} ${coords[1]}`;
|
|
32359
|
-
for (let i = 2;i < coords.length; i += 2) {
|
|
32360
|
-
pathD += ` L ${coords[i]} ${coords[i + 1]}`;
|
|
32361
|
-
}
|
|
32362
|
-
pathD += " Z";
|
|
32363
|
-
return {
|
|
32364
|
-
pad: `<path class="pad" d="${pathD}"/>`,
|
|
32365
|
-
hole: holeDia2 > 0 ? `<circle class="pad-hole" cx="${cx}" cy="${cy}" r="${holeDia2}"/>` : null
|
|
32366
|
-
};
|
|
32367
|
-
}
|
|
32368
|
-
const width = parseFloat(fields[4]) || 0;
|
|
32369
|
-
const height = parseFloat(fields[5]) || 0;
|
|
32370
|
-
const holeDia = parseFloat(fields[9]) || 0;
|
|
32371
|
-
let padSvg = "";
|
|
32372
|
-
if (shapeType === "ELLIPSE" || shapeType === "OVAL" || shapeType === "ROUND") {
|
|
32373
|
-
const rx = width / 2;
|
|
32374
|
-
const ry = height / 2;
|
|
32375
|
-
padSvg = `<ellipse class="pad" cx="${cx}" cy="${cy}" rx="${rx}" ry="${ry}"/>`;
|
|
32376
|
-
} else {
|
|
32377
|
-
const rectX = cx - width / 2;
|
|
32378
|
-
const rectY = cy - height / 2;
|
|
32379
|
-
padSvg = `<rect class="pad" x="${rectX}" y="${rectY}" width="${width}" height="${height}"/>`;
|
|
32380
|
-
}
|
|
32381
|
-
return {
|
|
32382
|
-
pad: padSvg,
|
|
32383
|
-
hole: holeDia > 0 ? `<circle class="pad-hole" cx="${cx}" cy="${cy}" r="${holeDia}"/>` : null
|
|
32384
|
-
};
|
|
32385
|
-
}
|
|
32386
|
-
function renderTrackShape(trackData) {
|
|
32387
|
-
const fields = trackData.split("~");
|
|
32388
|
-
const strokeWidth = parseFloat(fields[1]) || 0.5;
|
|
32389
|
-
const pointsStr = fields[4] || "";
|
|
32390
|
-
if (!pointsStr)
|
|
32391
|
-
return null;
|
|
32392
|
-
const coords = pointsStr.split(" ").map(Number);
|
|
32393
|
-
if (coords.length < 4)
|
|
32394
|
-
return null;
|
|
32395
|
-
let pathD = `M ${coords[0]} ${coords[1]}`;
|
|
32396
|
-
for (let i = 2;i < coords.length; i += 2) {
|
|
32397
|
-
pathD += ` L ${coords[i]} ${coords[i + 1]}`;
|
|
32398
|
-
}
|
|
32399
|
-
return `<path class="track" d="${pathD}" stroke-width="${strokeWidth}"/>`;
|
|
32400
|
-
}
|
|
32401
|
-
function renderSolidRegion(regionData) {
|
|
32402
|
-
const fields = regionData.split("~");
|
|
32403
|
-
const pathD = fields[3] || "";
|
|
32404
|
-
if (!pathD || !pathD.startsWith("M"))
|
|
32405
|
-
return null;
|
|
32406
|
-
return `<path class="region" d="${pathD}"/>`;
|
|
32407
|
-
}
|
|
32408
|
-
function renderTextShape(textData) {
|
|
32409
|
-
const fields = textData.split("~");
|
|
32410
|
-
const svgPath = fields[11] || "";
|
|
32411
|
-
if (!svgPath || !svgPath.startsWith("M"))
|
|
32412
|
-
return null;
|
|
32413
|
-
return `<path class="text-path" d="${svgPath}"/>`;
|
|
32414
|
-
}
|
|
32415
|
-
|
|
32416
32327
|
// src/tools/index.ts
|
|
32417
32328
|
var tools = [
|
|
32418
|
-
|
|
32419
|
-
|
|
32420
|
-
|
|
32421
|
-
|
|
32422
|
-
fetchLibraryTool,
|
|
32329
|
+
componentSearchTool,
|
|
32330
|
+
libraryInstallTool,
|
|
32331
|
+
libraryBatchInstallTool,
|
|
32332
|
+
libraryGetComponentTool,
|
|
32423
32333
|
updateLibraryTool,
|
|
32424
|
-
fixLibraryTool
|
|
32425
|
-
get3DModelTool,
|
|
32426
|
-
easyedaSearchTool,
|
|
32427
|
-
easyedaGet3DModelTool
|
|
32334
|
+
fixLibraryTool
|
|
32428
32335
|
];
|
|
32429
32336
|
var toolHandlers = {
|
|
32430
|
-
|
|
32431
|
-
|
|
32432
|
-
|
|
32433
|
-
|
|
32434
|
-
|
|
32435
|
-
|
|
32436
|
-
library_fix: handleFixLibrary,
|
|
32437
|
-
library_get_3d_model: handleGet3DModel,
|
|
32438
|
-
easyeda_search: handleEasyedaSearch,
|
|
32439
|
-
easyeda_get_3d_model: handleEasyedaGet3DModel
|
|
32337
|
+
[componentSearchTool.name]: handleComponentSearch,
|
|
32338
|
+
[libraryInstallTool.name]: handleLibraryInstall,
|
|
32339
|
+
[libraryBatchInstallTool.name]: handleLibraryBatchInstall,
|
|
32340
|
+
[libraryGetComponentTool.name]: handleLibraryGetComponent,
|
|
32341
|
+
[updateLibraryTool.name]: handleUpdateLibrary,
|
|
32342
|
+
[fixLibraryTool.name]: handleFixLibrary
|
|
32440
32343
|
};
|
|
32441
32344
|
|
|
32442
32345
|
// src/index.ts
|
|
32346
|
+
var require2 = createRequire(import.meta.url);
|
|
32347
|
+
var { version: version2 } = require2("../package.json");
|
|
32443
32348
|
var logger2 = createLogger("jlc-mcp");
|
|
32444
32349
|
var server = new Server({
|
|
32445
32350
|
name: "jlc-mcp",
|
|
32446
|
-
version:
|
|
32351
|
+
version: version2
|
|
32447
32352
|
}, {
|
|
32448
32353
|
capabilities: {
|
|
32449
32354
|
tools: {}
|
|
@@ -32484,9 +32389,9 @@ async function main() {
|
|
|
32484
32389
|
});
|
|
32485
32390
|
process.exit(1);
|
|
32486
32391
|
}
|
|
32487
|
-
const { symLibTable, fpLibTable, libraryStubs, version:
|
|
32392
|
+
const { symLibTable, fpLibTable, libraryStubs, version: version3 } = registration;
|
|
32488
32393
|
if (symLibTable.created || symLibTable.modified || fpLibTable.created || fpLibTable.modified) {
|
|
32489
|
-
logger2.info(`JLC libraries registered in KiCad ${
|
|
32394
|
+
logger2.info(`JLC libraries registered in KiCad ${version3}`, {
|
|
32490
32395
|
symLibTable: symLibTable.created ? `created with ${symLibTable.entriesAdded} entries` : symLibTable.modified ? `added ${symLibTable.entriesAdded} entries` : "already configured",
|
|
32491
32396
|
fpLibTable: fpLibTable.created ? "created" : fpLibTable.modified ? "updated" : "already configured",
|
|
32492
32397
|
stubsCreated: libraryStubs.symbolsCreated.length + libraryStubs.directoriesCreated.length
|