easyeda-mcp-pro 0.4.0 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. package/README.md +68 -24
  2. package/dist/bom-quality/adapter.d.ts +90 -0
  3. package/dist/bom-quality/adapter.js +295 -0
  4. package/dist/bom-quality/adapter.js.map +1 -0
  5. package/dist/bom-quality/index.d.ts +10 -0
  6. package/dist/bom-quality/index.js +9 -0
  7. package/dist/bom-quality/index.js.map +1 -0
  8. package/dist/bom-quality/quality.d.ts +28 -0
  9. package/dist/bom-quality/quality.js +179 -0
  10. package/dist/bom-quality/quality.js.map +1 -0
  11. package/dist/bom-quality/types.d.ts +94 -0
  12. package/dist/bom-quality/types.js +12 -0
  13. package/dist/bom-quality/types.js.map +1 -0
  14. package/dist/bridge/manager.d.ts +41 -0
  15. package/dist/bridge/manager.js +333 -51
  16. package/dist/bridge/manager.js.map +1 -1
  17. package/dist/bridge/protocol.d.ts +47 -1
  18. package/dist/bridge/protocol.js +42 -1
  19. package/dist/bridge/protocol.js.map +1 -1
  20. package/dist/bridge/types.d.ts +6 -0
  21. package/dist/bridge/types.js +6 -0
  22. package/dist/bridge/types.js.map +1 -1
  23. package/dist/catalog/errors.d.ts +49 -0
  24. package/dist/catalog/errors.js +60 -0
  25. package/dist/catalog/errors.js.map +1 -0
  26. package/dist/catalog/index.d.ts +15 -0
  27. package/dist/catalog/index.js +17 -0
  28. package/dist/catalog/index.js.map +1 -0
  29. package/dist/catalog/schema.d.ts +268 -0
  30. package/dist/catalog/schema.js +245 -0
  31. package/dist/catalog/schema.js.map +1 -0
  32. package/dist/catalog/starter.d.ts +159 -0
  33. package/dist/catalog/starter.js +579 -0
  34. package/dist/catalog/starter.js.map +1 -0
  35. package/dist/catalog/validation.d.ts +48 -0
  36. package/dist/catalog/validation.js +263 -0
  37. package/dist/catalog/validation.js.map +1 -0
  38. package/dist/circuit/circuit-ir.d.ts +460 -0
  39. package/dist/circuit/circuit-ir.js +292 -0
  40. package/dist/circuit/circuit-ir.js.map +1 -0
  41. package/dist/circuit/compiler.d.ts +55 -0
  42. package/dist/circuit/compiler.js +197 -0
  43. package/dist/circuit/compiler.js.map +1 -0
  44. package/dist/circuit/design-intent.d.ts +94 -0
  45. package/dist/circuit/design-intent.js +118 -0
  46. package/dist/circuit/design-intent.js.map +1 -0
  47. package/dist/circuit/errors.d.ts +50 -0
  48. package/dist/circuit/errors.js +61 -0
  49. package/dist/circuit/errors.js.map +1 -0
  50. package/dist/circuit/index.d.ts +17 -0
  51. package/dist/circuit/index.js +18 -0
  52. package/dist/circuit/index.js.map +1 -0
  53. package/dist/circuit/types.d.ts +186 -0
  54. package/dist/circuit/types.js +123 -0
  55. package/dist/circuit/types.js.map +1 -0
  56. package/dist/cli/auto-setup.d.ts +1 -8
  57. package/dist/cli/auto-setup.js +10 -178
  58. package/dist/cli/auto-setup.js.map +1 -1
  59. package/dist/cli/client-definitions.d.ts +34 -0
  60. package/dist/cli/client-definitions.js +194 -0
  61. package/dist/cli/client-definitions.js.map +1 -0
  62. package/dist/cli/local-setup.js +2 -2
  63. package/dist/cli/local-setup.js.map +1 -1
  64. package/dist/config/env.d.ts +6 -1
  65. package/dist/config/env.js +93 -5
  66. package/dist/config/env.js.map +1 -1
  67. package/dist/config/version.d.ts +1 -1
  68. package/dist/config/version.js +1 -1
  69. package/dist/export-manifest/errors.d.ts +55 -0
  70. package/dist/export-manifest/errors.js +69 -0
  71. package/dist/export-manifest/errors.js.map +1 -0
  72. package/dist/export-manifest/index.d.ts +10 -0
  73. package/dist/export-manifest/index.js +9 -0
  74. package/dist/export-manifest/index.js.map +1 -0
  75. package/dist/export-manifest/types.d.ts +170 -0
  76. package/dist/export-manifest/types.js +36 -0
  77. package/dist/export-manifest/types.js.map +1 -0
  78. package/dist/export-manifest/validation.d.ts +39 -0
  79. package/dist/export-manifest/validation.js +298 -0
  80. package/dist/export-manifest/validation.js.map +1 -0
  81. package/dist/index.js +7 -0
  82. package/dist/index.js.map +1 -1
  83. package/dist/net-validation/errors.d.ts +89 -0
  84. package/dist/net-validation/errors.js +69 -0
  85. package/dist/net-validation/errors.js.map +1 -0
  86. package/dist/net-validation/fixtures.d.ts +38 -0
  87. package/dist/net-validation/fixtures.js +215 -0
  88. package/dist/net-validation/fixtures.js.map +1 -0
  89. package/dist/net-validation/index.d.ts +10 -0
  90. package/dist/net-validation/index.js +9 -0
  91. package/dist/net-validation/index.js.map +1 -0
  92. package/dist/net-validation/schema.d.ts +118 -0
  93. package/dist/net-validation/schema.js +140 -0
  94. package/dist/net-validation/schema.js.map +1 -0
  95. package/dist/net-validation/validation.d.ts +45 -0
  96. package/dist/net-validation/validation.js +369 -0
  97. package/dist/net-validation/validation.js.map +1 -0
  98. package/dist/pcb-constraints/errors.d.ts +39 -0
  99. package/dist/pcb-constraints/errors.js +133 -0
  100. package/dist/pcb-constraints/errors.js.map +1 -0
  101. package/dist/pcb-constraints/index.d.ts +9 -0
  102. package/dist/pcb-constraints/index.js +9 -0
  103. package/dist/pcb-constraints/index.js.map +1 -0
  104. package/dist/pcb-constraints/types.d.ts +102 -0
  105. package/dist/pcb-constraints/types.js +7 -0
  106. package/dist/pcb-constraints/types.js.map +1 -0
  107. package/dist/pcb-constraints/validation.d.ts +70 -0
  108. package/dist/pcb-constraints/validation.js +309 -0
  109. package/dist/pcb-constraints/validation.js.map +1 -0
  110. package/dist/server/factory.js +2 -0
  111. package/dist/server/factory.js.map +1 -1
  112. package/dist/server/transports/http.d.ts +20 -1
  113. package/dist/server/transports/http.js +156 -34
  114. package/dist/server/transports/http.js.map +1 -1
  115. package/dist/storage/database.d.ts +25 -0
  116. package/dist/storage/database.js +126 -51
  117. package/dist/storage/database.js.map +1 -1
  118. package/dist/tools/{L0_diagnostics.d.ts → L0_diagnostics_api.d.ts} +2 -2
  119. package/dist/tools/L0_diagnostics_api.js +152 -0
  120. package/dist/tools/L0_diagnostics_api.js.map +1 -0
  121. package/dist/tools/L0_diagnostics_core.d.ts +6 -0
  122. package/dist/tools/{L0_diagnostics.js → L0_diagnostics_core.js} +50 -124
  123. package/dist/tools/L0_diagnostics_core.js.map +1 -0
  124. package/dist/tools/L1_board.js +20 -4
  125. package/dist/tools/L1_board.js.map +1 -1
  126. package/dist/tools/{L1_bom.d.ts → L1_bom_core.d.ts} +2 -2
  127. package/dist/tools/{L1_bom.js → L1_bom_core.js} +21 -101
  128. package/dist/tools/L1_bom_core.js.map +1 -0
  129. package/dist/tools/{L1_schematic.d.ts → L1_bom_sourcing.d.ts} +2 -2
  130. package/dist/tools/L1_bom_sourcing.js +265 -0
  131. package/dist/tools/L1_bom_sourcing.js.map +1 -0
  132. package/dist/tools/L1_drc_erc.js +15 -3
  133. package/dist/tools/L1_drc_erc.js.map +1 -1
  134. package/dist/tools/L1_export.js +20 -4
  135. package/dist/tools/L1_export.js.map +1 -1
  136. package/dist/tools/L1_pcb_constraints.d.ts +6 -0
  137. package/dist/tools/L1_pcb_constraints.js +234 -0
  138. package/dist/tools/L1_pcb_constraints.js.map +1 -0
  139. package/dist/tools/L1_pcb_write.js +26 -12
  140. package/dist/tools/L1_pcb_write.js.map +1 -1
  141. package/dist/tools/L1_schematic_read.d.ts +6 -0
  142. package/dist/tools/{L1_schematic.js → L1_schematic_read.js} +125 -194
  143. package/dist/tools/L1_schematic_read.js.map +1 -0
  144. package/dist/tools/L1_schematic_write.d.ts +6 -0
  145. package/dist/tools/L1_schematic_write.js +516 -0
  146. package/dist/tools/L1_schematic_write.js.map +1 -0
  147. package/dist/tools/register.js +15 -7
  148. package/dist/tools/register.js.map +1 -1
  149. package/dist/tools/registry.d.ts +41 -7
  150. package/dist/tools/registry.js +95 -25
  151. package/dist/tools/registry.js.map +1 -1
  152. package/dist/tools/types.d.ts +16 -0
  153. package/dist/utils/logger.d.ts +1 -1
  154. package/dist/utils/logger.js +1 -1
  155. package/dist/utils/logger.js.map +1 -1
  156. package/dist/vendors/base-http-client.d.ts +48 -0
  157. package/dist/vendors/base-http-client.js +75 -0
  158. package/dist/vendors/base-http-client.js.map +1 -0
  159. package/dist/vendors/digikey/client.js +10 -19
  160. package/dist/vendors/digikey/client.js.map +1 -1
  161. package/dist/vendors/jlcpcb/client.js +41 -70
  162. package/dist/vendors/jlcpcb/client.js.map +1 -1
  163. package/dist/vendors/lcsc/client.js +5 -18
  164. package/dist/vendors/lcsc/client.js.map +1 -1
  165. package/dist/vendors/mouser/client.js +4 -12
  166. package/dist/vendors/mouser/client.js.map +1 -1
  167. package/easyeda-bridge-extension.eext +0 -0
  168. package/package.json +11 -10
  169. package/dist/tools/L0_diagnostics.js.map +0 -1
  170. package/dist/tools/L1_bom.js.map +0 -1
  171. 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 | 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
- | `TRANSPORT` | `stdio` | Server transport: `stdio` (default) or `http` |
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 | Default | Description |
378
- | --------------------- | ------------------- | -------------------------------- |
379
- | `BRIDGE_HOST` | `127.0.0.1` | Bridge WebSocket host |
380
- | `BRIDGE_PORT` | `18601` | Primary bridge port |
381
- | `BRIDGE_PORT_SCAN` | `18601,49620-49629` | Port scan spec (comma/range) |
382
- | `BRIDGE_TIMEOUT_MS` | `15000` | Bridge call timeout (ms) |
383
- | `BRIDGE_HEARTBEAT_MS` | `10000` | Heartbeat interval (ms) |
384
- | `BRIDGE_TOKEN` | `''` | Session token for extension auth |
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 | Default | Description |
389
- | ---------- | ------------------ | ------------------------------------------- |
390
- | `DATA_DIR` | `.easyeda-mcp-pro` | Data directory (cache, database, artifacts) |
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 | Default | Description |
406
- | ------------- | ------- | ----------------------------------------------- |
407
- | `AI_PROVIDER` | `none` | `anthropic`, `openai`, `openrouter`, or `local` |
408
- | `AI_MODEL` | `''` | Model name |
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
- # Code quality
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**: Optional Bearer token validation via JWKS endpoint for HTTP transport
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>;