easyeda-mcp-pro 0.4.0 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +68 -24
- package/dist/bom-quality/adapter.d.ts +90 -0
- package/dist/bom-quality/adapter.js +295 -0
- package/dist/bom-quality/adapter.js.map +1 -0
- package/dist/bom-quality/index.d.ts +10 -0
- package/dist/bom-quality/index.js +9 -0
- package/dist/bom-quality/index.js.map +1 -0
- package/dist/bom-quality/quality.d.ts +28 -0
- package/dist/bom-quality/quality.js +179 -0
- package/dist/bom-quality/quality.js.map +1 -0
- package/dist/bom-quality/types.d.ts +94 -0
- package/dist/bom-quality/types.js +12 -0
- package/dist/bom-quality/types.js.map +1 -0
- package/dist/bridge/manager.d.ts +41 -0
- package/dist/bridge/manager.js +333 -51
- package/dist/bridge/manager.js.map +1 -1
- package/dist/bridge/protocol.d.ts +47 -1
- package/dist/bridge/protocol.js +42 -1
- package/dist/bridge/protocol.js.map +1 -1
- package/dist/bridge/types.d.ts +6 -0
- package/dist/bridge/types.js +6 -0
- package/dist/bridge/types.js.map +1 -1
- package/dist/catalog/errors.d.ts +49 -0
- package/dist/catalog/errors.js +60 -0
- package/dist/catalog/errors.js.map +1 -0
- package/dist/catalog/index.d.ts +15 -0
- package/dist/catalog/index.js +17 -0
- package/dist/catalog/index.js.map +1 -0
- package/dist/catalog/schema.d.ts +268 -0
- package/dist/catalog/schema.js +245 -0
- package/dist/catalog/schema.js.map +1 -0
- package/dist/catalog/starter.d.ts +159 -0
- package/dist/catalog/starter.js +579 -0
- package/dist/catalog/starter.js.map +1 -0
- package/dist/catalog/validation.d.ts +48 -0
- package/dist/catalog/validation.js +263 -0
- package/dist/catalog/validation.js.map +1 -0
- package/dist/circuit/circuit-ir.d.ts +460 -0
- package/dist/circuit/circuit-ir.js +292 -0
- package/dist/circuit/circuit-ir.js.map +1 -0
- package/dist/circuit/compiler.d.ts +55 -0
- package/dist/circuit/compiler.js +197 -0
- package/dist/circuit/compiler.js.map +1 -0
- package/dist/circuit/design-intent.d.ts +94 -0
- package/dist/circuit/design-intent.js +118 -0
- package/dist/circuit/design-intent.js.map +1 -0
- package/dist/circuit/errors.d.ts +50 -0
- package/dist/circuit/errors.js +61 -0
- package/dist/circuit/errors.js.map +1 -0
- package/dist/circuit/index.d.ts +17 -0
- package/dist/circuit/index.js +18 -0
- package/dist/circuit/index.js.map +1 -0
- package/dist/circuit/types.d.ts +186 -0
- package/dist/circuit/types.js +123 -0
- package/dist/circuit/types.js.map +1 -0
- package/dist/cli/auto-setup.d.ts +1 -8
- package/dist/cli/auto-setup.js +10 -178
- package/dist/cli/auto-setup.js.map +1 -1
- package/dist/cli/client-definitions.d.ts +34 -0
- package/dist/cli/client-definitions.js +194 -0
- package/dist/cli/client-definitions.js.map +1 -0
- package/dist/cli/local-setup.js +2 -2
- package/dist/cli/local-setup.js.map +1 -1
- package/dist/config/env.d.ts +6 -1
- package/dist/config/env.js +93 -5
- package/dist/config/env.js.map +1 -1
- package/dist/config/version.d.ts +1 -1
- package/dist/config/version.js +1 -1
- package/dist/export-manifest/errors.d.ts +55 -0
- package/dist/export-manifest/errors.js +69 -0
- package/dist/export-manifest/errors.js.map +1 -0
- package/dist/export-manifest/index.d.ts +10 -0
- package/dist/export-manifest/index.js +9 -0
- package/dist/export-manifest/index.js.map +1 -0
- package/dist/export-manifest/types.d.ts +170 -0
- package/dist/export-manifest/types.js +36 -0
- package/dist/export-manifest/types.js.map +1 -0
- package/dist/export-manifest/validation.d.ts +39 -0
- package/dist/export-manifest/validation.js +298 -0
- package/dist/export-manifest/validation.js.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/net-validation/errors.d.ts +89 -0
- package/dist/net-validation/errors.js +69 -0
- package/dist/net-validation/errors.js.map +1 -0
- package/dist/net-validation/fixtures.d.ts +38 -0
- package/dist/net-validation/fixtures.js +215 -0
- package/dist/net-validation/fixtures.js.map +1 -0
- package/dist/net-validation/index.d.ts +10 -0
- package/dist/net-validation/index.js +9 -0
- package/dist/net-validation/index.js.map +1 -0
- package/dist/net-validation/schema.d.ts +118 -0
- package/dist/net-validation/schema.js +140 -0
- package/dist/net-validation/schema.js.map +1 -0
- package/dist/net-validation/validation.d.ts +45 -0
- package/dist/net-validation/validation.js +369 -0
- package/dist/net-validation/validation.js.map +1 -0
- package/dist/pcb-constraints/errors.d.ts +39 -0
- package/dist/pcb-constraints/errors.js +133 -0
- package/dist/pcb-constraints/errors.js.map +1 -0
- package/dist/pcb-constraints/index.d.ts +9 -0
- package/dist/pcb-constraints/index.js +9 -0
- package/dist/pcb-constraints/index.js.map +1 -0
- package/dist/pcb-constraints/types.d.ts +102 -0
- package/dist/pcb-constraints/types.js +7 -0
- package/dist/pcb-constraints/types.js.map +1 -0
- package/dist/pcb-constraints/validation.d.ts +70 -0
- package/dist/pcb-constraints/validation.js +309 -0
- package/dist/pcb-constraints/validation.js.map +1 -0
- package/dist/server/factory.js +2 -0
- package/dist/server/factory.js.map +1 -1
- package/dist/server/transports/http.d.ts +20 -1
- package/dist/server/transports/http.js +156 -34
- package/dist/server/transports/http.js.map +1 -1
- package/dist/storage/database.d.ts +25 -0
- package/dist/storage/database.js +126 -51
- package/dist/storage/database.js.map +1 -1
- package/dist/tools/{L0_diagnostics.d.ts → L0_diagnostics_api.d.ts} +2 -2
- package/dist/tools/L0_diagnostics_api.js +152 -0
- package/dist/tools/L0_diagnostics_api.js.map +1 -0
- package/dist/tools/L0_diagnostics_core.d.ts +6 -0
- package/dist/tools/{L0_diagnostics.js → L0_diagnostics_core.js} +50 -124
- package/dist/tools/L0_diagnostics_core.js.map +1 -0
- package/dist/tools/L1_board.js +20 -4
- package/dist/tools/L1_board.js.map +1 -1
- package/dist/tools/{L1_bom.d.ts → L1_bom_core.d.ts} +2 -2
- package/dist/tools/{L1_bom.js → L1_bom_core.js} +21 -101
- package/dist/tools/L1_bom_core.js.map +1 -0
- package/dist/tools/{L1_schematic.d.ts → L1_bom_sourcing.d.ts} +2 -2
- package/dist/tools/L1_bom_sourcing.js +265 -0
- package/dist/tools/L1_bom_sourcing.js.map +1 -0
- package/dist/tools/L1_drc_erc.js +15 -3
- package/dist/tools/L1_drc_erc.js.map +1 -1
- package/dist/tools/L1_export.js +20 -4
- package/dist/tools/L1_export.js.map +1 -1
- package/dist/tools/L1_pcb_constraints.d.ts +6 -0
- package/dist/tools/L1_pcb_constraints.js +234 -0
- package/dist/tools/L1_pcb_constraints.js.map +1 -0
- package/dist/tools/L1_pcb_write.js +26 -12
- package/dist/tools/L1_pcb_write.js.map +1 -1
- package/dist/tools/L1_schematic_read.d.ts +6 -0
- package/dist/tools/{L1_schematic.js → L1_schematic_read.js} +125 -194
- package/dist/tools/L1_schematic_read.js.map +1 -0
- package/dist/tools/L1_schematic_write.d.ts +6 -0
- package/dist/tools/L1_schematic_write.js +516 -0
- package/dist/tools/L1_schematic_write.js.map +1 -0
- package/dist/tools/register.js +15 -7
- package/dist/tools/register.js.map +1 -1
- package/dist/tools/registry.d.ts +41 -7
- package/dist/tools/registry.js +95 -25
- package/dist/tools/registry.js.map +1 -1
- package/dist/tools/types.d.ts +16 -0
- package/dist/utils/logger.d.ts +1 -1
- package/dist/utils/logger.js +1 -1
- package/dist/utils/logger.js.map +1 -1
- package/dist/vendors/base-http-client.d.ts +48 -0
- package/dist/vendors/base-http-client.js +75 -0
- package/dist/vendors/base-http-client.js.map +1 -0
- package/dist/vendors/digikey/client.js +10 -19
- package/dist/vendors/digikey/client.js.map +1 -1
- package/dist/vendors/jlcpcb/client.js +41 -70
- package/dist/vendors/jlcpcb/client.js.map +1 -1
- package/dist/vendors/lcsc/client.js +5 -18
- package/dist/vendors/lcsc/client.js.map +1 -1
- package/dist/vendors/mouser/client.js +4 -12
- package/dist/vendors/mouser/client.js.map +1 -1
- package/easyeda-bridge-extension.eext +0 -0
- package/package.json +11 -10
- package/dist/tools/L0_diagnostics.js.map +0 -1
- package/dist/tools/L1_bom.js.map +0 -1
- package/dist/tools/L1_schematic.js.map +0 -1
package/README.md
CHANGED
|
@@ -365,29 +365,36 @@ Copy `.env.example` to `.env` and edit. All variables have safe defaults — onl
|
|
|
365
365
|
|
|
366
366
|
### Essential
|
|
367
367
|
|
|
368
|
-
| Variable
|
|
369
|
-
|
|
|
370
|
-
| `NODE_ENV`
|
|
371
|
-
| `LOG_LEVEL`
|
|
372
|
-
| `TOOL_PROFILE`
|
|
373
|
-
| `
|
|
368
|
+
| Variable | Default | Description |
|
|
369
|
+
| ---------------------- | ------------- | ---------------------------------------------------------------------------- |
|
|
370
|
+
| `NODE_ENV` | `development` | Set to `production` in production |
|
|
371
|
+
| `LOG_LEVEL` | `info` | Pino log level: `trace`, `debug`, `info`, `warn`, `error`, `fatal`, `silent` |
|
|
372
|
+
| `TOOL_PROFILE` | `core` | Tool set: `core`, `pro`, `full`, `dev`, `experimental` |
|
|
373
|
+
| `MCP_PROTOCOL_VERSION` | `2025-11-25` | MCP protocol version string |
|
|
374
|
+
| `TRANSPORT` | `stdio` | Server transport: `stdio` (default) or `http` |
|
|
374
375
|
|
|
375
376
|
### Bridge (EasyEDA Pro connection)
|
|
376
377
|
|
|
377
|
-
| Variable
|
|
378
|
-
|
|
|
379
|
-
| `BRIDGE_HOST`
|
|
380
|
-
| `BRIDGE_PORT`
|
|
381
|
-
| `BRIDGE_PORT_SCAN`
|
|
382
|
-
| `BRIDGE_TIMEOUT_MS`
|
|
383
|
-
| `BRIDGE_HEARTBEAT_MS`
|
|
384
|
-
| `
|
|
378
|
+
| Variable | Default | Description |
|
|
379
|
+
| ------------------------------- | ------------- | ----------------------------------------- |
|
|
380
|
+
| `BRIDGE_HOST` | `127.0.0.1` | Bridge WebSocket host |
|
|
381
|
+
| `BRIDGE_PORT` | `49620` | Primary bridge port |
|
|
382
|
+
| `BRIDGE_PORT_SCAN` | `49620-49629` | Port scan spec (comma/range) |
|
|
383
|
+
| `BRIDGE_TIMEOUT_MS` | `15000` | Bridge call timeout (ms) |
|
|
384
|
+
| `BRIDGE_HEARTBEAT_MS` | `10000` | Heartbeat interval (ms) |
|
|
385
|
+
| `BRIDGE_RECONNECT_MAX_ATTEMPTS` | `0` | Max reconnect attempts (`0` = infinite) |
|
|
386
|
+
| `BRIDGE_WAIT_FOR_EDA_MS` | `30000` | Wait for EasyEDA Pro on startup (ms) |
|
|
387
|
+
| `BRIDGE_MAX_PAYLOAD_SIZE` | `1048576` | Max bridge payload (bytes, default 1 MiB) |
|
|
388
|
+
| `BRIDGE_TOKEN` | `''` | Session token for extension auth |
|
|
385
389
|
|
|
386
390
|
### Storage
|
|
387
391
|
|
|
388
|
-
| Variable
|
|
389
|
-
|
|
|
390
|
-
| `DATA_DIR`
|
|
392
|
+
| Variable | Default | Description |
|
|
393
|
+
| -------------- | ----------------------------------------- | ------------------------------------------- |
|
|
394
|
+
| `DATA_DIR` | `.easyeda-mcp-pro` | Data directory (cache, database, artifacts) |
|
|
395
|
+
| `SQLITE_PATH` | `.easyeda-mcp-pro/easyeda-mcp-pro.sqlite` | SQLite database path |
|
|
396
|
+
| `ARTIFACT_DIR` | `.easyeda-mcp-pro/artifacts` | Artifact export directory |
|
|
397
|
+
| `CACHE_DIR` | `.easyeda-mcp-pro/cache` | Cache directory |
|
|
391
398
|
|
|
392
399
|
### Supplier integration
|
|
393
400
|
|
|
@@ -402,10 +409,14 @@ Enable suppliers by setting their credentials. All suppliers are disabled by def
|
|
|
402
409
|
|
|
403
410
|
Configure an AI provider for LLM-assisted design review:
|
|
404
411
|
|
|
405
|
-
| Variable
|
|
406
|
-
|
|
|
407
|
-
| `AI_PROVIDER`
|
|
408
|
-
| `AI_MODEL`
|
|
412
|
+
| Variable | Default | Description |
|
|
413
|
+
| --------------------------- | ------- | ----------------------------------------------- |
|
|
414
|
+
| `AI_PROVIDER` | `none` | `anthropic`, `openai`, `openrouter`, or `local` |
|
|
415
|
+
| `AI_MODEL` | `''` | Model name (e.g., `claude-sonnet-4-20250514`) |
|
|
416
|
+
| `AI_API_KEY` | `''` | AI provider API key |
|
|
417
|
+
| `AI_MAX_TOKENS` | `8000` | Max tokens per AI response |
|
|
418
|
+
| `AI_TIMEOUT_MS` | `60000` | AI request timeout in ms |
|
|
419
|
+
| `AI_ALLOW_DESIGN_MUTATIONS` | `false` | Allow AI to modify schematic/board designs |
|
|
409
420
|
|
|
410
421
|
### HTTP transport
|
|
411
422
|
|
|
@@ -415,6 +426,7 @@ When using `TRANSPORT=http`:
|
|
|
415
426
|
| --------------------- | ----------- | ----------------------------------------- |
|
|
416
427
|
| `HTTP_HOST` | `127.0.0.1` | Bind address (use `0.0.0.0` with caution) |
|
|
417
428
|
| `HTTP_PORT` | `3000` | Port |
|
|
429
|
+
| `HTTP_AUTH_DISABLED` | `false` | Disable HTTP transport authentication |
|
|
418
430
|
| `HTTP_RATE_LIMIT_MAX` | `100` | Max requests per minute per IP |
|
|
419
431
|
| `CORS_ORIGIN` | `''` | Allowed CORS origin |
|
|
420
432
|
|
|
@@ -577,20 +589,34 @@ Installation: Open EasyEDA Pro → **Settings** → **Extensions** → **Extensi
|
|
|
577
589
|
|
|
578
590
|
## Development
|
|
579
591
|
|
|
592
|
+
### Prerequisites
|
|
593
|
+
|
|
594
|
+
- **Node.js** >=24 <27
|
|
595
|
+
- **pnpm** >=11
|
|
596
|
+
- **Go Task** (optional, for Taskfile commands)
|
|
597
|
+
|
|
598
|
+
### Quick Start
|
|
599
|
+
|
|
580
600
|
```bash
|
|
581
601
|
# Setup
|
|
582
602
|
pnpm install
|
|
583
603
|
cp .env.example .env
|
|
584
604
|
|
|
585
|
-
#
|
|
605
|
+
# All quality gates (lint + format + typecheck + test + build)
|
|
606
|
+
task verify
|
|
607
|
+
|
|
608
|
+
# Or use pnpm directly:
|
|
586
609
|
pnpm format:check # Prettier
|
|
587
610
|
pnpm typecheck # TypeScript
|
|
588
611
|
pnpm lint # ESLint
|
|
589
612
|
|
|
590
613
|
# Test
|
|
591
|
-
pnpm test # Vitest (120 tests across 18 files)
|
|
614
|
+
pnpm test # Vitest (120+ tests across 18+ files)
|
|
592
615
|
pnpm test:coverage # With coverage report
|
|
593
616
|
|
|
617
|
+
# Golden E2E fixture smoke tests are included in `pnpm test`
|
|
618
|
+
# See docs/golden-fixtures.md for fixture architecture
|
|
619
|
+
|
|
594
620
|
# Build & run
|
|
595
621
|
pnpm build # tsc -> dist/
|
|
596
622
|
pnpm build:extension # Bundle EasyEDA Pro extension
|
|
@@ -602,6 +628,22 @@ pnpm start # Run compiled build
|
|
|
602
628
|
pnpm inspector
|
|
603
629
|
```
|
|
604
630
|
|
|
631
|
+
### Available Taskfile Commands
|
|
632
|
+
|
|
633
|
+
This project includes a `Taskfile.yml` with the following commands:
|
|
634
|
+
|
|
635
|
+
| Command | Description |
|
|
636
|
+
| ---------------- | ------------------------------- |
|
|
637
|
+
| `task install` | Install dependencies |
|
|
638
|
+
| `task lint` | Run ESLint |
|
|
639
|
+
| `task format` | Check formatting with Prettier |
|
|
640
|
+
| `task typecheck` | Run TypeScript type checking |
|
|
641
|
+
| `task test` | Run tests |
|
|
642
|
+
| `task build` | Build the project |
|
|
643
|
+
| `task verify` | Run all quality gates (CI gate) |
|
|
644
|
+
|
|
645
|
+
Install [Go Task](https://taskfile.dev/installation/) to use these commands.
|
|
646
|
+
|
|
605
647
|
### Project structure
|
|
606
648
|
|
|
607
649
|
```
|
|
@@ -631,8 +673,10 @@ easyeda-bridge-extension/ # EasyEDA Pro bridge extension workspace package
|
|
|
631
673
|
|
|
632
674
|
## Security
|
|
633
675
|
|
|
676
|
+
See [Security Architecture & Threat Model](docs/security-architecture.md) for the complete security reference, including deployment modes, authentication, tool safety controls, secrets management, safe defaults, supplier API security, threat scenarios, and deployment checklists.
|
|
677
|
+
|
|
634
678
|
- **Production safety**: Validates config at startup — rejects non-loopback HTTP without OAuth, blocks dangerous features in production
|
|
635
|
-
- **OAuth/JWKS**:
|
|
679
|
+
- **OAuth/JWKS**: Bearer token validation via JWKS endpoint for HTTP transport (see [OAuth section](docs/security-architecture.md#21-oauth-20--openid-connect-http-transport))
|
|
636
680
|
- **Rate limiting**: Per-IP sliding window rate limiter on HTTP transport (default 100 req/min)
|
|
637
681
|
- **Path traversal protection**: All file export paths validated against `ARTIFACT_DIR`
|
|
638
682
|
- **Secret redaction**: API keys, tokens, passwords are redacted from logs and diagnostic output
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BOM quality — supplier adapter layer.
|
|
3
|
+
*
|
|
4
|
+
* Provides a common {@link SupplierAdapter} interface over each vendor
|
|
5
|
+
* client so quality checks can query any configured supplier uniformly.
|
|
6
|
+
*
|
|
7
|
+
* Each adapter:
|
|
8
|
+
* - normalises part data into {@link SupplierQueryResult}
|
|
9
|
+
* - records a query timestamp for provenance
|
|
10
|
+
* - wraps transient errors with an exponential-backoff retry
|
|
11
|
+
*
|
|
12
|
+
* @module
|
|
13
|
+
*/
|
|
14
|
+
import { type LcscClient } from '../vendors/lcsc/client.js';
|
|
15
|
+
import { type MouserClient } from '../vendors/mouser/client.js';
|
|
16
|
+
import { type DigiKeyClient } from '../vendors/digikey/client.js';
|
|
17
|
+
import type { SupplierKind, SupplierQueryResult } from './types.js';
|
|
18
|
+
export interface SupplierAdapter {
|
|
19
|
+
/** Short supplier key (e.g. 'lcsc', 'mouser'). */
|
|
20
|
+
readonly kind: SupplierKind;
|
|
21
|
+
/** Human-readable supplier name. */
|
|
22
|
+
readonly displayName: string;
|
|
23
|
+
/** Whether this supplier is configured and available. */
|
|
24
|
+
isAvailable(): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Query a part by LCSC code or manufacturer part number.
|
|
27
|
+
* Returns `null` when the part is not found (not an error).
|
|
28
|
+
*/
|
|
29
|
+
queryPart(identifier: {
|
|
30
|
+
lcsc?: string;
|
|
31
|
+
mpn?: string;
|
|
32
|
+
}): Promise<SupplierQueryResult | null>;
|
|
33
|
+
}
|
|
34
|
+
export declare class LcscAdapter implements SupplierAdapter {
|
|
35
|
+
readonly kind: SupplierKind;
|
|
36
|
+
readonly displayName = "LCSC";
|
|
37
|
+
private client;
|
|
38
|
+
private logger;
|
|
39
|
+
constructor(client: LcscClient | null);
|
|
40
|
+
isAvailable(): boolean;
|
|
41
|
+
private buildFoundResult;
|
|
42
|
+
queryPart(identifier: {
|
|
43
|
+
lcsc?: string;
|
|
44
|
+
mpn?: string;
|
|
45
|
+
}): Promise<SupplierQueryResult | null>;
|
|
46
|
+
}
|
|
47
|
+
export declare class MouserAdapter implements SupplierAdapter {
|
|
48
|
+
readonly kind: SupplierKind;
|
|
49
|
+
readonly displayName = "Mouser";
|
|
50
|
+
private client;
|
|
51
|
+
private logger;
|
|
52
|
+
constructor(client: MouserClient | null);
|
|
53
|
+
isAvailable(): boolean;
|
|
54
|
+
private buildFoundResult;
|
|
55
|
+
queryPart(identifier: {
|
|
56
|
+
lcsc?: string;
|
|
57
|
+
mpn?: string;
|
|
58
|
+
}): Promise<SupplierQueryResult | null>;
|
|
59
|
+
}
|
|
60
|
+
export declare class DigiKeyAdapter implements SupplierAdapter {
|
|
61
|
+
readonly kind: SupplierKind;
|
|
62
|
+
readonly displayName = "DigiKey";
|
|
63
|
+
private client;
|
|
64
|
+
private logger;
|
|
65
|
+
constructor(client: DigiKeyClient | null);
|
|
66
|
+
isAvailable(): boolean;
|
|
67
|
+
private buildFoundResult;
|
|
68
|
+
queryPart(identifier: {
|
|
69
|
+
lcsc?: string;
|
|
70
|
+
mpn?: string;
|
|
71
|
+
}): Promise<SupplierQueryResult | null>;
|
|
72
|
+
}
|
|
73
|
+
export interface AdapterMap {
|
|
74
|
+
lcsc: LcscAdapter;
|
|
75
|
+
mouser: MouserAdapter;
|
|
76
|
+
digikey: DigiKeyAdapter;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Build the adapter map from a ToolContext vendors object.
|
|
80
|
+
* Each adapter wraps the corresponding vendor client (or null if disabled).
|
|
81
|
+
*/
|
|
82
|
+
export declare function createAdapters(vendors: {
|
|
83
|
+
lcsc: LcscClient | null;
|
|
84
|
+
mouser: MouserClient | null;
|
|
85
|
+
digikey: DigiKeyClient | null;
|
|
86
|
+
}): AdapterMap;
|
|
87
|
+
/**
|
|
88
|
+
* Return the subset of adapters that are currently configured / available.
|
|
89
|
+
*/
|
|
90
|
+
export declare function availableAdapters(adapters: AdapterMap): SupplierAdapter[];
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BOM quality — supplier adapter layer.
|
|
3
|
+
*
|
|
4
|
+
* Provides a common {@link SupplierAdapter} interface over each vendor
|
|
5
|
+
* client so quality checks can query any configured supplier uniformly.
|
|
6
|
+
*
|
|
7
|
+
* Each adapter:
|
|
8
|
+
* - normalises part data into {@link SupplierQueryResult}
|
|
9
|
+
* - records a query timestamp for provenance
|
|
10
|
+
* - wraps transient errors with an exponential-backoff retry
|
|
11
|
+
*
|
|
12
|
+
* @module
|
|
13
|
+
*/
|
|
14
|
+
import { EasyEdaMcpError } from '../schemas/common.js';
|
|
15
|
+
import { getLogger } from '../utils/logger.js';
|
|
16
|
+
// ── Retry helper ───────────────────────────────────────────────────────────
|
|
17
|
+
const RETRY_BASE_MS = 200;
|
|
18
|
+
const RETRY_MAX_MS = 2_000;
|
|
19
|
+
const RETRY_ATTEMPTS = 2;
|
|
20
|
+
async function withRetry(label, fn, logger, attempts = RETRY_ATTEMPTS) {
|
|
21
|
+
let lastError;
|
|
22
|
+
for (let i = 0; i <= attempts; i++) {
|
|
23
|
+
try {
|
|
24
|
+
return await fn(i);
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
lastError = err;
|
|
28
|
+
// Only retry on retryable errors (rate limits, 5xx)
|
|
29
|
+
const retryable = err instanceof EasyEdaMcpError ? err.retryable === true : true; // unknown errors are not retried
|
|
30
|
+
if (!retryable || i === attempts) {
|
|
31
|
+
throw err;
|
|
32
|
+
}
|
|
33
|
+
const delay = Math.min(RETRY_BASE_MS * 2 ** i, RETRY_MAX_MS);
|
|
34
|
+
logger.debug({ delay, attempt: i + 1, label }, 'retrying supplier query');
|
|
35
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
throw lastError;
|
|
39
|
+
}
|
|
40
|
+
function toLifecycle(raw) {
|
|
41
|
+
if (typeof raw === 'boolean')
|
|
42
|
+
return raw ? 'discontinued' : 'active';
|
|
43
|
+
if (typeof raw === 'string') {
|
|
44
|
+
const lc = raw.toLowerCase();
|
|
45
|
+
if (lc === 'active' || lc === 'production')
|
|
46
|
+
return 'active';
|
|
47
|
+
if (lc.includes('discon') || lc.includes('obsolete') || lc === 'eol')
|
|
48
|
+
return 'discontinued';
|
|
49
|
+
}
|
|
50
|
+
return 'unknown';
|
|
51
|
+
}
|
|
52
|
+
// ── LCSC adapter ───────────────────────────────────────────────────────────
|
|
53
|
+
export class LcscAdapter {
|
|
54
|
+
kind = 'lcsc';
|
|
55
|
+
displayName = 'LCSC';
|
|
56
|
+
client;
|
|
57
|
+
logger;
|
|
58
|
+
constructor(client) {
|
|
59
|
+
this.client = client;
|
|
60
|
+
this.logger = getLogger();
|
|
61
|
+
}
|
|
62
|
+
isAvailable() {
|
|
63
|
+
return this.client !== null;
|
|
64
|
+
}
|
|
65
|
+
buildFoundResult(detail, now) {
|
|
66
|
+
const unitPrice = detail.priceBreaks?.[0]?.unitPrice ??
|
|
67
|
+
(typeof detail.price === 'number'
|
|
68
|
+
? detail.price
|
|
69
|
+
: typeof detail.price === 'string'
|
|
70
|
+
? parseFloat(detail.price)
|
|
71
|
+
: undefined);
|
|
72
|
+
return {
|
|
73
|
+
supplier: 'lcsc',
|
|
74
|
+
found: true,
|
|
75
|
+
lcsc: detail.lcsc,
|
|
76
|
+
mpn: detail.manufacturer || undefined,
|
|
77
|
+
manufacturer: detail.manufacturer || undefined,
|
|
78
|
+
description: detail.description || undefined,
|
|
79
|
+
lifecycle: detail.discontinued ? 'discontinued' : 'active',
|
|
80
|
+
stock: detail.stockCount ?? detail.stock ?? 0,
|
|
81
|
+
unitPrice,
|
|
82
|
+
currency: 'USD',
|
|
83
|
+
leadTimeDays: detail.leadTime,
|
|
84
|
+
queriedAt: now,
|
|
85
|
+
confidence: 'high',
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
async queryPart(identifier) {
|
|
89
|
+
const client = this.client;
|
|
90
|
+
if (!client)
|
|
91
|
+
return null;
|
|
92
|
+
if (!identifier.lcsc && !identifier.mpn)
|
|
93
|
+
return null;
|
|
94
|
+
const lcscCode = identifier.lcsc;
|
|
95
|
+
if (!lcscCode)
|
|
96
|
+
return null; // LCSC requires an LCSC code
|
|
97
|
+
const now = new Date().toISOString();
|
|
98
|
+
try {
|
|
99
|
+
const detail = await withRetry(`lcsc.getPartDetail(${lcscCode})`, () => client.getPartDetail(lcscCode), this.logger);
|
|
100
|
+
if (!detail) {
|
|
101
|
+
return {
|
|
102
|
+
supplier: 'lcsc',
|
|
103
|
+
found: false,
|
|
104
|
+
lifecycle: 'unknown',
|
|
105
|
+
stock: 0,
|
|
106
|
+
queriedAt: now,
|
|
107
|
+
confidence: 'medium',
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
return this.buildFoundResult(detail, now);
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
this.logger.warn({ err, lcscCode }, 'lcsc adapter query failed');
|
|
114
|
+
// Return an "unavailable" result rather than throwing
|
|
115
|
+
return {
|
|
116
|
+
supplier: 'lcsc',
|
|
117
|
+
found: false,
|
|
118
|
+
lifecycle: 'unknown',
|
|
119
|
+
stock: 0,
|
|
120
|
+
queriedAt: now,
|
|
121
|
+
confidence: 'low',
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// ── Mouser adapter ─────────────────────────────────────────────────────────
|
|
127
|
+
export class MouserAdapter {
|
|
128
|
+
kind = 'mouser';
|
|
129
|
+
displayName = 'Mouser';
|
|
130
|
+
client;
|
|
131
|
+
logger;
|
|
132
|
+
constructor(client) {
|
|
133
|
+
this.client = client;
|
|
134
|
+
this.logger = getLogger();
|
|
135
|
+
}
|
|
136
|
+
isAvailable() {
|
|
137
|
+
return this.client !== null;
|
|
138
|
+
}
|
|
139
|
+
buildFoundResult(part, now) {
|
|
140
|
+
return {
|
|
141
|
+
supplier: 'mouser',
|
|
142
|
+
found: true,
|
|
143
|
+
mpn: part.manufacturer || undefined,
|
|
144
|
+
manufacturer: part.manufacturer || undefined,
|
|
145
|
+
description: part.description || undefined,
|
|
146
|
+
lifecycle: 'active',
|
|
147
|
+
stock: part.availability ?? 0,
|
|
148
|
+
unitPrice: part.priceBreaks?.[0]?.price,
|
|
149
|
+
currency: 'USD',
|
|
150
|
+
leadTimeDays: part.leadTime ? parseInt(part.leadTime, 10) || undefined : undefined,
|
|
151
|
+
queriedAt: now,
|
|
152
|
+
confidence: 'high',
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
async queryPart(identifier) {
|
|
156
|
+
const client = this.client;
|
|
157
|
+
if (!client)
|
|
158
|
+
return null;
|
|
159
|
+
const mpn = identifier.mpn;
|
|
160
|
+
if (!mpn)
|
|
161
|
+
return null; // Mouser requires an MPN
|
|
162
|
+
const now = new Date().toISOString();
|
|
163
|
+
try {
|
|
164
|
+
const results = await withRetry(`mouser.searchByPartNumber(${mpn})`, () => client.searchByPartNumber(mpn), this.logger);
|
|
165
|
+
if (!results || results.length === 0) {
|
|
166
|
+
return {
|
|
167
|
+
supplier: 'mouser',
|
|
168
|
+
found: false,
|
|
169
|
+
lifecycle: 'unknown',
|
|
170
|
+
stock: 0,
|
|
171
|
+
queriedAt: now,
|
|
172
|
+
confidence: 'medium',
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
const part = results[0];
|
|
176
|
+
if (!part) {
|
|
177
|
+
return {
|
|
178
|
+
supplier: 'mouser',
|
|
179
|
+
found: false,
|
|
180
|
+
lifecycle: 'unknown',
|
|
181
|
+
stock: 0,
|
|
182
|
+
queriedAt: now,
|
|
183
|
+
confidence: 'medium',
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
return this.buildFoundResult(part, now);
|
|
187
|
+
}
|
|
188
|
+
catch (err) {
|
|
189
|
+
this.logger.warn({ err, mpn }, 'mouser adapter query failed');
|
|
190
|
+
return {
|
|
191
|
+
supplier: 'mouser',
|
|
192
|
+
found: false,
|
|
193
|
+
lifecycle: 'unknown',
|
|
194
|
+
stock: 0,
|
|
195
|
+
queriedAt: now,
|
|
196
|
+
confidence: 'low',
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
// ── DigiKey adapter ────────────────────────────────────────────────────────
|
|
202
|
+
export class DigiKeyAdapter {
|
|
203
|
+
kind = 'digikey';
|
|
204
|
+
displayName = 'DigiKey';
|
|
205
|
+
client;
|
|
206
|
+
logger;
|
|
207
|
+
constructor(client) {
|
|
208
|
+
this.client = client;
|
|
209
|
+
this.logger = getLogger();
|
|
210
|
+
}
|
|
211
|
+
isAvailable() {
|
|
212
|
+
return this.client !== null;
|
|
213
|
+
}
|
|
214
|
+
buildFoundResult(part, mpn, now) {
|
|
215
|
+
return {
|
|
216
|
+
supplier: 'digikey',
|
|
217
|
+
found: true,
|
|
218
|
+
mpn: part.manufacturerPartNumber || undefined,
|
|
219
|
+
manufacturer: part.manufacturer || undefined,
|
|
220
|
+
description: part.description || undefined,
|
|
221
|
+
lifecycle: toLifecycle(part.rohsStatus), // RoHS active is a loose proxy
|
|
222
|
+
stock: part.quantityAvailable ?? 0,
|
|
223
|
+
unitPrice: part.unitPrice || undefined,
|
|
224
|
+
currency: 'USD',
|
|
225
|
+
queriedAt: now,
|
|
226
|
+
confidence: part.manufacturerPartNumber?.toLowerCase() === mpn.toLowerCase() ? 'high' : 'medium',
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
async queryPart(identifier) {
|
|
230
|
+
const client = this.client;
|
|
231
|
+
if (!client)
|
|
232
|
+
return null;
|
|
233
|
+
const mpn = identifier.mpn;
|
|
234
|
+
if (!mpn)
|
|
235
|
+
return null; // DigiKey requires MPN or keyword
|
|
236
|
+
const now = new Date().toISOString();
|
|
237
|
+
try {
|
|
238
|
+
// Use keyword search as a proxy — DigiKey doesn't expose a
|
|
239
|
+
// direct MPN-lookup endpoint in the current client.
|
|
240
|
+
const results = await withRetry(`digikey.searchByKeyword(${mpn})`, () => client.searchByKeyword(mpn), this.logger);
|
|
241
|
+
if (!results || results.length === 0) {
|
|
242
|
+
return {
|
|
243
|
+
supplier: 'digikey',
|
|
244
|
+
found: false,
|
|
245
|
+
lifecycle: 'unknown',
|
|
246
|
+
stock: 0,
|
|
247
|
+
queriedAt: now,
|
|
248
|
+
confidence: 'medium',
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
// Take the first result — keyword search returns best match first
|
|
252
|
+
const part = results[0];
|
|
253
|
+
if (!part) {
|
|
254
|
+
return {
|
|
255
|
+
supplier: 'digikey',
|
|
256
|
+
found: false,
|
|
257
|
+
lifecycle: 'unknown',
|
|
258
|
+
stock: 0,
|
|
259
|
+
queriedAt: now,
|
|
260
|
+
confidence: 'medium',
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
return this.buildFoundResult(part, mpn, now);
|
|
264
|
+
}
|
|
265
|
+
catch (err) {
|
|
266
|
+
this.logger.warn({ err, mpn }, 'digikey adapter query failed');
|
|
267
|
+
return {
|
|
268
|
+
supplier: 'digikey',
|
|
269
|
+
found: false,
|
|
270
|
+
lifecycle: 'unknown',
|
|
271
|
+
stock: 0,
|
|
272
|
+
queriedAt: now,
|
|
273
|
+
confidence: 'low',
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Build the adapter map from a ToolContext vendors object.
|
|
280
|
+
* Each adapter wraps the corresponding vendor client (or null if disabled).
|
|
281
|
+
*/
|
|
282
|
+
export function createAdapters(vendors) {
|
|
283
|
+
return {
|
|
284
|
+
lcsc: new LcscAdapter(vendors.lcsc),
|
|
285
|
+
mouser: new MouserAdapter(vendors.mouser),
|
|
286
|
+
digikey: new DigiKeyAdapter(vendors.digikey),
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Return the subset of adapters that are currently configured / available.
|
|
291
|
+
*/
|
|
292
|
+
export function availableAdapters(adapters) {
|
|
293
|
+
return Object.values(adapters).filter((a) => a.isAvailable());
|
|
294
|
+
}
|
|
295
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../src/bom-quality/adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BOM quality — public API barrel.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
export type { SupplierKind, PartLifecycle, BomEntry, SupplierQueryResult, BomQualityIssueType, BomQualityIssue, BomQualityReport, BomQualityConfig, } from './types.js';
|
|
7
|
+
export { DEFAULT_BOM_QUALITY_CONFIG } from './types.js';
|
|
8
|
+
export type { SupplierAdapter, AdapterMap } from './adapter.js';
|
|
9
|
+
export { LcscAdapter, MouserAdapter, DigiKeyAdapter, createAdapters, availableAdapters, } from './adapter.js';
|
|
10
|
+
export { generateBomQualityReport } from './quality.js';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BOM quality — public API barrel.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
export { DEFAULT_BOM_QUALITY_CONFIG } from './types.js';
|
|
7
|
+
export { LcscAdapter, MouserAdapter, DigiKeyAdapter, createAdapters, availableAdapters, } from './adapter.js';
|
|
8
|
+
export { generateBomQualityReport } from './quality.js';
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/bom-quality/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAaH,OAAO,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAC;AAGxD,OAAO,EACL,WAAW,EACX,aAAa,EACb,cAAc,EACd,cAAc,EACd,iBAAiB,GAClB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BOM quality — report generation.
|
|
3
|
+
*
|
|
4
|
+
* Analyses BOM entries against supplier data to surface issues:
|
|
5
|
+
* 1. **Unavailable** — part not found or discontinued at any supplier.
|
|
6
|
+
* 2. **Single-source** — part found at exactly one supplier.
|
|
7
|
+
* 3. **Missing MPN** — no manufacturer part number.
|
|
8
|
+
* 4. **Missing footprint** — no package / footprint.
|
|
9
|
+
* 5. **Low stock** — stock below threshold at every supplier.
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
import type { BomEntry, BomQualityReport, BomQualityConfig } from './types.js';
|
|
14
|
+
import type { AdapterMap } from './adapter.js';
|
|
15
|
+
/**
|
|
16
|
+
* Generate a BOM quality report for the given entries.
|
|
17
|
+
*
|
|
18
|
+
* For each entry the function:
|
|
19
|
+
* 1. Queries every available supplier that can handle the entry.
|
|
20
|
+
* 2. Collects supplier results (with error resilience).
|
|
21
|
+
* 3. Runs the five quality checks.
|
|
22
|
+
* 4. Returns a structured report with a summary.
|
|
23
|
+
*
|
|
24
|
+
* Supplier failures are caught gracefully — the report always succeeds
|
|
25
|
+
* (non-null), with `hasSupplierErrors` set to `true` and any affected
|
|
26
|
+
* entries marked via their issues.
|
|
27
|
+
*/
|
|
28
|
+
export declare function generateBomQualityReport(bomId: string, entries: BomEntry[], adapters: AdapterMap, config?: BomQualityConfig): Promise<BomQualityReport>;
|