driverge-mcp 0.0.0 → 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/README.md +275 -29
  2. package/dist/codegen/esp32.d.ts +11 -3
  3. package/dist/codegen/esp32.js +221 -10
  4. package/dist/codegen/esp32.js.map +1 -1
  5. package/dist/codegen/ident.d.ts +24 -2
  6. package/dist/codegen/ident.js +37 -4
  7. package/dist/codegen/ident.js.map +1 -1
  8. package/dist/codegen/index.d.ts +12 -7
  9. package/dist/codegen/index.js +17 -14
  10. package/dist/codegen/index.js.map +1 -1
  11. package/dist/codegen/lint.js +28 -8
  12. package/dist/codegen/lint.js.map +1 -1
  13. package/dist/codegen/portable-cpp.d.ts +8 -0
  14. package/dist/codegen/portable-cpp.js +281 -0
  15. package/dist/codegen/portable-cpp.js.map +1 -0
  16. package/dist/codegen/portable.d.ts +99 -3
  17. package/dist/codegen/portable.js +419 -99
  18. package/dist/codegen/portable.js.map +1 -1
  19. package/dist/codegen/stm32.d.ts +11 -3
  20. package/dist/codegen/stm32.js +156 -11
  21. package/dist/codegen/stm32.js.map +1 -1
  22. package/dist/codegen/types.d.ts +32 -0
  23. package/dist/codegen/types.js +27 -0
  24. package/dist/codegen/types.js.map +1 -1
  25. package/dist/mcp/cache.d.ts +15 -2
  26. package/dist/mcp/cache.js +32 -4
  27. package/dist/mcp/cache.js.map +1 -1
  28. package/dist/mcp/register.d.ts +17 -0
  29. package/dist/mcp/register.js +149 -21
  30. package/dist/mcp/register.js.map +1 -1
  31. package/dist/mcp/summary.js +8 -0
  32. package/dist/mcp/summary.js.map +1 -1
  33. package/dist/pdf/address.d.ts +4 -0
  34. package/dist/pdf/address.js +28 -0
  35. package/dist/pdf/address.js.map +1 -0
  36. package/dist/pdf/command.js +87 -14
  37. package/dist/pdf/command.js.map +1 -1
  38. package/dist/pdf/extract.js +23 -2
  39. package/dist/pdf/extract.js.map +1 -1
  40. package/dist/pdf/generic-register-table.d.ts +5 -0
  41. package/dist/pdf/generic-register-table.js +125 -0
  42. package/dist/pdf/generic-register-table.js.map +1 -0
  43. package/dist/pdf/index.d.ts +2 -0
  44. package/dist/pdf/index.js +2 -0
  45. package/dist/pdf/index.js.map +1 -1
  46. package/dist/pdf/interface-kind.d.ts +11 -0
  47. package/dist/pdf/interface-kind.js +18 -0
  48. package/dist/pdf/interface-kind.js.map +1 -1
  49. package/dist/pdf/manufacturer.js +39 -0
  50. package/dist/pdf/manufacturer.js.map +1 -1
  51. package/dist/pdf/maxim-register-map.d.ts +11 -0
  52. package/dist/pdf/maxim-register-map.js +544 -0
  53. package/dist/pdf/maxim-register-map.js.map +1 -0
  54. package/dist/pdf/part.js +8 -0
  55. package/dist/pdf/part.js.map +1 -1
  56. package/dist/pdf/prose-commands.d.ts +4 -0
  57. package/dist/pdf/prose-commands.js +90 -0
  58. package/dist/pdf/prose-commands.js.map +1 -0
  59. package/dist/pdf/st-bit-layout.d.ts +3 -0
  60. package/dist/pdf/st-bit-layout.js +238 -0
  61. package/dist/pdf/st-bit-layout.js.map +1 -0
  62. package/dist/pdf/ti-field-descriptions.d.ts +10 -0
  63. package/dist/pdf/ti-field-descriptions.js +87 -0
  64. package/dist/pdf/ti-field-descriptions.js.map +1 -0
  65. package/dist/pdf/ti-register-map.d.ts +5 -0
  66. package/dist/pdf/ti-register-map.js +84 -0
  67. package/dist/pdf/ti-register-map.js.map +1 -0
  68. package/dist/pdf/types.d.ts +15 -3
  69. package/dist/pdf/types.js +4 -1
  70. package/dist/pdf/types.js.map +1 -1
  71. package/dist/schema/assemble.d.ts +35 -3
  72. package/dist/schema/assemble.js +86 -13
  73. package/dist/schema/assemble.js.map +1 -1
  74. package/dist/schema/types.d.ts +21 -1
  75. package/dist/schema/validate.js +37 -10
  76. package/dist/schema/validate.js.map +1 -1
  77. package/dist/server.d.ts +18 -0
  78. package/dist/server.js +49 -3
  79. package/dist/server.js.map +1 -1
  80. package/package.json +1 -1
  81. package/schemas/datasheet.schema.json +17 -3
@@ -1,4 +1,36 @@
1
- import type { PdfAnalysis } from "../pdf/types.js";
2
- import type { DatasheetJson } from "./types.js";
1
+ import type { InterfaceKind, PdfAnalysis } from "../pdf/types.js";
2
+ import type { DatasheetJson, DeviceInterface, Extraction } from "./types.js";
3
+ /**
4
+ * Classify how complete the deterministic extraction is (see wiki:
5
+ * graceful-degradation). An empty map is a *deferral* (host-AI-completable) rather
6
+ * than a failure whenever there's positive evidence of that interface — a detected
7
+ * section, or the kind classifier landing on it — and only `none` (a hard error)
8
+ * when there is no signal at all.
9
+ */
10
+ export declare function deriveExtraction(iface: DeviceInterface, sections: {
11
+ registerPages: number[];
12
+ commandPages: number[];
13
+ }, kind: InterfaceKind, busKnown: boolean): Extraction;
14
+ /**
15
+ * Optional overrides for the host AI to steer assembly when its own reading of
16
+ * the datasheet disagrees with (or supplements) the deterministic detectors —
17
+ * see Session 10 / Contract A. Both are opt-in; omitting `opts` entirely is
18
+ * byte-identical to today's behavior.
19
+ */
20
+ export interface AssembleOpts {
21
+ /**
22
+ * Manufacturer name to use as a "hint"-style fallback. Applied ONLY when
23
+ * detectManufacturer lands on the generic default (no confident vendor) — a
24
+ * confident detection always wins and the hint is silently ignored. When
25
+ * applied, manufacturerConfidence is pinned to 0.5 (a hint is more than
26
+ * nothing but less than a confident deterministic match).
27
+ */
28
+ manufacturerHint?: string;
29
+ /**
30
+ * Forces the interface kind used for BOTH buildInterface and
31
+ * deriveExtraction, overriding detectInterfaceKind's classification.
32
+ */
33
+ interfaceKindHint?: "register_map" | "command_set";
34
+ }
3
35
  /** Assemble + validate the datasheet contract from a completed PDF analysis. */
4
- export declare function assembleDatasheet(analysis: PdfAnalysis): DatasheetJson;
36
+ export declare function assembleDatasheet(analysis: PdfAnalysis, opts?: AssembleOpts): DatasheetJson;
@@ -4,40 +4,113 @@
4
4
  // command/protocol/CRC extraction) come together into the object handed to the
5
5
  // host AI by ref. See wiki: json-schema-as-contract, mcp-tool-usage-flow.
6
6
  import { extractCommands, extractProtocol } from "../pdf/command.js";
7
- import { detectInterfaceKind } from "../pdf/interface-kind.js";
7
+ import { findGenericRegisterTable } from "../pdf/generic-register-table.js";
8
+ import { detectInterfaceKind, detectSections } from "../pdf/interface-kind.js";
8
9
  import { detectManufacturer } from "../pdf/manufacturer.js";
10
+ import { findMaximRegisterMap } from "../pdf/maxim-register-map.js";
9
11
  import { detectPart } from "../pdf/part.js";
12
+ import { extractProseCommands } from "../pdf/prose-commands.js";
10
13
  import { findRegisterTable } from "../pdf/register-table.js";
14
+ import { findStBitFields } from "../pdf/st-bit-layout.js";
15
+ import { findTiRegisterMap } from "../pdf/ti-register-map.js";
11
16
  import { validateDatasheet } from "./validate.js";
12
17
  function buildInterface(pages, kind) {
13
18
  if (kind === "command_set") {
14
- return { kind: "command_set", commands: extractCommands(pages) };
19
+ let commands = extractCommands(pages);
20
+ if (commands.length === 0)
21
+ commands = extractProseCommands(pages);
22
+ return { kind: "command_set", commands };
15
23
  }
16
- // register_map (and "unknown", which we treat as register-first): fall back to
17
- // a command set only if no register table is found but commands are present.
18
- const table = findRegisterTable(pages);
19
- if (!table && kind === "unknown") {
24
+ // register_map (and "unknown", treated register-first). Try the BME280/
25
+ // Microchip bit-table extractor, then the TI register-summary adapter, then the
26
+ // role-based generic extractor (raises the deterministic floor for unseen vendor
27
+ // table shapes see generic-register-table). Each runs only when the prior found
28
+ // nothing, so the specialized adapters (and their goldens) are never affected.
29
+ let registers = findRegisterTable(pages)?.registers ?? [];
30
+ if (registers.length === 0) {
31
+ registers = findTiRegisterMap(pages)?.registers ?? [];
32
+ }
33
+ // Maxim's register-matrix shape (see maxim-register-map): tried after TI's
34
+ // summary-table adapter and before the role-based generic fallback, same
35
+ // slot pattern as every prior specialized adapter in this chain.
36
+ if (registers.length === 0) {
37
+ registers = findMaximRegisterMap(pages)?.registers ?? [];
38
+ }
39
+ if (registers.length === 0) {
40
+ registers = findGenericRegisterTable(pages)?.registers ?? [];
41
+ // Enrich with ST's two-stacked-table bit-layout format (see
42
+ // st-bit-layout): a name-only match against the generic table's rows, so
43
+ // non-ST datasheets (an empty map) leave the address-only registers
44
+ // untouched.
45
+ if (registers.length > 0) {
46
+ const stFields = findStBitFields(pages);
47
+ if (stFields.size > 0) {
48
+ for (const r of registers) {
49
+ const bf = stFields.get(r.name);
50
+ if (bf)
51
+ r.bitFields = bf;
52
+ }
53
+ }
54
+ }
55
+ }
56
+ // Only reclassify as a command set when nothing register-like was found.
57
+ if (registers.length === 0 && kind === "unknown") {
20
58
  const commands = extractCommands(pages);
21
59
  if (commands.length > 0)
22
60
  return { kind: "command_set", commands };
23
61
  }
24
- return { kind: "register_map", registers: table?.registers ?? [] };
62
+ return { kind: "register_map", registers };
63
+ }
64
+ /**
65
+ * Classify how complete the deterministic extraction is (see wiki:
66
+ * graceful-degradation). An empty map is a *deferral* (host-AI-completable) rather
67
+ * than a failure whenever there's positive evidence of that interface — a detected
68
+ * section, or the kind classifier landing on it — and only `none` (a hard error)
69
+ * when there is no signal at all.
70
+ */
71
+ export function deriveExtraction(iface, sections, kind, busKnown) {
72
+ // An empty map defers (host-AI-completable) whenever there's ANY interface
73
+ // signal — a detected section, a concrete kind, or even a detected bus (a part
74
+ // with a known I2C/SPI bus almost certainly has registers/commands we just
75
+ // couldn't parse). Only a truly signal-less PDF is `none` (a hard error).
76
+ if (iface.kind === "register_map") {
77
+ if (iface.registers.length === 0) {
78
+ const detectedPages = sections.registerPages;
79
+ const deferred = detectedPages.length > 0 || kind === "register_map" || busKnown;
80
+ return { status: deferred ? "deferred" : "none", detectedPages };
81
+ }
82
+ const hasBits = iface.registers.some((r) => r.bitFields.length > 0);
83
+ return {
84
+ status: hasBits ? "complete" : "partial",
85
+ detectedPages: sections.registerPages,
86
+ };
87
+ }
88
+ if (iface.commands.length === 0) {
89
+ const detectedPages = sections.commandPages;
90
+ const deferred = detectedPages.length > 0 || kind === "command_set" || busKnown;
91
+ return { status: deferred ? "deferred" : "none", detectedPages };
92
+ }
93
+ return { status: "complete", detectedPages: sections.commandPages };
25
94
  }
26
95
  /** Assemble + validate the datasheet contract from a completed PDF analysis. */
27
- export function assembleDatasheet(analysis) {
96
+ export function assembleDatasheet(analysis, opts) {
28
97
  const { pages } = analysis;
29
98
  const manufacturer = detectManufacturer(pages);
30
- const kind = detectInterfaceKind(pages).kind;
99
+ const kind = opts?.interfaceKindHint ?? detectInterfaceKind(pages).kind;
100
+ const iface = buildInterface(pages, kind);
101
+ const protocol = extractProtocol(pages);
102
+ const manufacturerHint = manufacturer.manufacturer === "generic" ? opts?.manufacturerHint : undefined;
31
103
  const partial = {
32
104
  metadata: {
33
105
  part: detectPart(pages),
34
- manufacturer: manufacturer.manufacturer,
35
- manufacturerConfidence: manufacturer.confidence,
106
+ manufacturer: manufacturerHint ?? manufacturer.manufacturer,
107
+ manufacturerConfidence: manufacturerHint !== undefined ? 0.5 : manufacturer.confidence,
36
108
  pdfType: analysis.type,
37
109
  pageCount: analysis.pageCount,
38
110
  },
39
- protocol: extractProtocol(pages),
40
- interface: buildInterface(pages, kind),
111
+ protocol,
112
+ interface: iface,
113
+ extraction: deriveExtraction(iface, detectSections(pages), kind, protocol.bus !== "unknown"),
41
114
  };
42
115
  const validation = validateDatasheet({
43
116
  ...partial,
@@ -1 +1 @@
1
- {"version":3,"file":"assemble.js","sourceRoot":"","sources":["../../src/schema/assemble.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,8EAA8E;AAC9E,2EAA2E;AAC3E,+EAA+E;AAC/E,0EAA0E;AAE1E,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACrE,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAG7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAElD,SAAS,cAAc,CAAC,KAAoB,EAAE,IAAY;IACxD,IAAI,IAAI,KAAK,aAAa,EAAE,CAAC;QAC3B,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC;IACnE,CAAC;IACD,+EAA+E;IAC/E,6EAA6E;IAC7E,MAAM,KAAK,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;IACvC,IAAI,CAAC,KAAK,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACjC,MAAM,QAAQ,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;QACxC,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC;IACpE,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,IAAI,EAAE,EAAE,CAAC;AACrE,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,iBAAiB,CAAC,QAAqB;IACrD,MAAM,EAAE,KAAK,EAAE,GAAG,QAAQ,CAAC;IAC3B,MAAM,YAAY,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;IAC/C,MAAM,IAAI,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC;IAE7C,MAAM,OAAO,GAAG;QACd,QAAQ,EAAE;YACR,IAAI,EAAE,UAAU,CAAC,KAAK,CAAC;YACvB,YAAY,EAAE,YAAY,CAAC,YAAY;YACvC,sBAAsB,EAAE,YAAY,CAAC,UAAU;YAC/C,OAAO,EAAE,QAAQ,CAAC,IAAI;YACtB,SAAS,EAAE,QAAQ,CAAC,SAAS;SAC9B;QACD,QAAQ,EAAE,eAAe,CAAC,KAAK,CAAC;QAChC,SAAS,EAAE,cAAc,CAAC,KAAK,EAAE,IAAI,CAAC;KACvC,CAAC;IAEF,MAAM,UAAU,GAAG,iBAAiB,CAAC;QACnC,GAAG,OAAO;QACV,UAAU,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;KACtD,CAAC,CAAC;IAEH,OAAO,EAAE,GAAG,OAAO,EAAE,UAAU,EAAE,CAAC;AACpC,CAAC"}
1
+ {"version":3,"file":"assemble.js","sourceRoot":"","sources":["../../src/schema/assemble.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import type { PdfType, Register } from "../pdf/types.js";
2
- export type Bus = "I2C" | "SPI" | "UART" | "unknown";
2
+ export type Bus = "I2C" | "SPI" | "UART" | "CAN" | "unknown";
3
3
  export interface DatasheetMetadata {
4
4
  part: string;
5
5
  manufacturer: string;
@@ -42,10 +42,30 @@ export interface ValidationResult {
42
42
  errors: string[];
43
43
  warnings: string[];
44
44
  }
45
+ /**
46
+ * How complete the deterministic extraction of the interface is (see wiki:
47
+ * graceful-degradation). Drives whether an empty/incomplete map is a hard error
48
+ * or a host-AI-completable deferral.
49
+ *
50
+ * - `complete` — registers with bit-field detail, or a clean command list.
51
+ * - `partial` — ≥1 register but known-incomplete (e.g. an address-only list
52
+ * with no bit fields).
53
+ * - `deferred` — a register/command section was DETECTED but not auto-extracted;
54
+ * the host AI completes it from the datasheet resource.
55
+ * - `none` — no interface signal at all; a genuine parse failure.
56
+ */
57
+ export type ExtractionStatus = "complete" | "partial" | "deferred" | "none";
58
+ export interface Extraction {
59
+ status: ExtractionStatus;
60
+ /** 1-based pages where the register-map / command section was detected. */
61
+ detectedPages: number[];
62
+ }
45
63
  /** The full parsed datasheet handed (by ref) to the host AI. */
46
64
  export interface DatasheetJson {
47
65
  metadata: DatasheetMetadata;
48
66
  protocol: Protocol;
49
67
  interface: DeviceInterface;
68
+ /** Extraction completeness; absent on legacy JSON (treated as `none`). */
69
+ extraction?: Extraction;
50
70
  validation: ValidationResult;
51
71
  }
@@ -1,7 +1,10 @@
1
1
  // L5 — datasheet validator. Deterministic logic checks, per interface kind, that
2
2
  // gate malformed/incomplete JSON before it reaches the host AI (see wiki:
3
3
  // validate-before-sending-to-claude). Errors fail validation; warnings do not.
4
+ import { registerWidth } from "../pdf/types.js";
4
5
  const HEX_ONLY = /^0x[0-9a-f]+$/i;
6
+ const VALID_WIDTHS = new Set([8, 16, 32]);
7
+ const detectedOn = (pages) => pages.length > 0 ? ` (page(s) ${pages.join(", ")})` : "";
5
8
  export function validateDatasheet(d) {
6
9
  const errors = [];
7
10
  const warnings = [];
@@ -9,28 +12,47 @@ export function validateDatasheet(d) {
9
12
  warnings.push("metadata.part is empty");
10
13
  if (d.protocol.bus === "unknown")
11
14
  warnings.push("protocol.bus is unknown");
15
+ const status = d.extraction?.status;
16
+ const pages = d.extraction?.detectedPages ?? [];
12
17
  if (d.interface.kind === "register_map") {
13
- validateRegisters(d.interface.registers, errors);
18
+ validateRegisters(d.interface.registers, errors, warnings, status, pages);
14
19
  }
15
20
  else {
16
- validateCommands(d.interface.commands, errors, warnings);
21
+ validateCommands(d.interface.commands, errors, warnings, status, pages);
17
22
  }
18
23
  return { valid: errors.length === 0, errors, warnings };
19
24
  }
20
- function validateRegisters(registers, errors) {
25
+ function validateRegisters(registers, errors, warnings, status, pages) {
21
26
  if (registers.length === 0) {
22
- errors.push("register_map has no registers");
27
+ // A detected-but-unparsed map is a host-AI-completable deferral, not a failure
28
+ // (see wiki: graceful-degradation); only a true no-signal map is an error.
29
+ if (status === "deferred") {
30
+ warnings.push(`register map detected${detectedOn(pages)} but not auto-extracted — the host AI must complete it from the datasheet resource`);
31
+ }
32
+ else {
33
+ errors.push("register_map has no registers");
34
+ }
23
35
  return;
24
36
  }
37
+ if (status === "partial") {
38
+ warnings.push("register map is partial — addresses extracted without bit-field detail; the host AI should add bit fields from the datasheet");
39
+ }
25
40
  const addressCount = new Map();
26
41
  for (const r of registers) {
27
42
  // Duplicate single addresses (ranges like "0x88…0xA1" are skipped here).
28
43
  if (HEX_ONLY.test(r.address)) {
29
44
  addressCount.set(r.address, (addressCount.get(r.address) ?? 0) + 1);
30
45
  }
31
- const occupied = new Array(8).fill(false);
46
+ if (r.width !== undefined && !VALID_WIDTHS.has(r.width)) {
47
+ errors.push(`${r.name}: invalid register width ${r.width} (expected 8, 16, or 32)`);
48
+ }
49
+ const width = registerWidth(r);
50
+ const occupied = new Array(width).fill(false);
32
51
  for (const field of r.bitFields) {
33
- if (field.msb < 0 || field.msb > 7 || field.lsb < 0 || field.lsb > 7) {
52
+ if (field.msb < 0 ||
53
+ field.msb > width - 1 ||
54
+ field.lsb < 0 ||
55
+ field.lsb > width - 1) {
34
56
  errors.push(`${r.name}.${field.name}: bit index out of range (${field.msb}:${field.lsb})`);
35
57
  continue;
36
58
  }
@@ -45,8 +67,8 @@ function validateRegisters(registers, errors) {
45
67
  occupied[b] = true;
46
68
  }
47
69
  }
48
- if (HEX_ONLY.test(r.reset) && Number.parseInt(r.reset, 16) > 0xff) {
49
- errors.push(`${r.name}: reset ${r.reset} exceeds the 8-bit register width`);
70
+ if (HEX_ONLY.test(r.reset) && Number.parseInt(r.reset, 16) > 2 ** width - 1) {
71
+ errors.push(`${r.name}: reset ${r.reset} exceeds the ${width}-bit register width`);
50
72
  }
51
73
  }
52
74
  for (const [address, count] of addressCount) {
@@ -55,9 +77,14 @@ function validateRegisters(registers, errors) {
55
77
  }
56
78
  }
57
79
  }
58
- function validateCommands(commands, errors, warnings) {
80
+ function validateCommands(commands, errors, warnings, status, pages) {
59
81
  if (commands.length === 0) {
60
- errors.push("command_set has no commands");
82
+ if (status === "deferred") {
83
+ warnings.push(`command set detected${detectedOn(pages)} but not auto-extracted — the host AI must complete it from the datasheet resource`);
84
+ }
85
+ else {
86
+ errors.push("command_set has no commands");
87
+ }
61
88
  return;
62
89
  }
63
90
  const codeCount = new Map();
@@ -1 +1 @@
1
- {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/schema/validate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/schema/validate.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,0EAA0E;AAC1E,+EAA+E;AAE/E,OAAO,EAAE,aAAa,EAAiB,MAAM,iBAAiB,CAAC;AAQ/D,MAAM,QAAQ,GAAG,gBAAgB,CAAC;AAClC,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;AAE1C,MAAM,UAAU,GAAG,CAAC,KAAe,EAAU,EAAE,CAC7C,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,aAAa,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;AAE3D,MAAM,UAAU,iBAAiB,CAAC,CAAgB;IAChD,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI;QAAE,QAAQ,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;IAC9D,IAAI,CAAC,CAAC,QAAQ,CAAC,GAAG,KAAK,SAAS;QAAE,QAAQ,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;IAE3E,MAAM,MAAM,GAAG,CAAC,CAAC,UAAU,EAAE,MAAM,CAAC;IACpC,MAAM,KAAK,GAAG,CAAC,CAAC,UAAU,EAAE,aAAa,IAAI,EAAE,CAAC;IAEhD,IAAI,CAAC,CAAC,SAAS,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;QACxC,iBAAiB,CAAC,CAAC,CAAC,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;IAC5E,CAAC;SAAM,CAAC;QACN,gBAAgB,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;IAC1E,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;AAC1D,CAAC;AAED,SAAS,iBAAiB,CACxB,SAAqB,EACrB,MAAgB,EAChB,QAAkB,EAClB,MAAoC,EACpC,KAAe;IAEf,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,+EAA+E;QAC/E,2EAA2E;QAC3E,IAAI,MAAM,KAAK,UAAU,EAAE,CAAC;YAC1B,QAAQ,CAAC,IAAI,CACX,wBAAwB,UAAU,CAAC,KAAK,CAAC,oFAAoF,CAC9H,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;QAC/C,CAAC;QACD,OAAO;IACT,CAAC;IAED,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,QAAQ,CAAC,IAAI,CACX,8HAA8H,CAC/H,CAAC;IACJ,CAAC;IAED,MAAM,YAAY,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC/C,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;QAC1B,yEAAyE;QACzE,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;YAC7B,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACtE,CAAC;QAED,IAAI,CAAC,CAAC,KAAK,KAAK,SAAS,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;YACxD,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,4BAA4B,CAAC,CAAC,KAAK,0BAA0B,CAAC,CAAC;QACtF,CAAC;QACD,MAAM,KAAK,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;QAE/B,MAAM,QAAQ,GAAG,IAAI,KAAK,CAAU,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACvD,KAAK,MAAM,KAAK,IAAI,CAAC,CAAC,SAAS,EAAE,CAAC;YAChC,IACE,KAAK,CAAC,GAAG,GAAG,CAAC;gBACb,KAAK,CAAC,GAAG,GAAG,KAAK,GAAG,CAAC;gBACrB,KAAK,CAAC,GAAG,GAAG,CAAC;gBACb,KAAK,CAAC,GAAG,GAAG,KAAK,GAAG,CAAC,EACrB,CAAC;gBACD,MAAM,CAAC,IAAI,CACT,GAAG,CAAC,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,6BAA6B,KAAK,CAAC,GAAG,IAAI,KAAK,CAAC,GAAG,GAAG,CAC9E,CAAC;gBACF,SAAS;YACX,CAAC;YACD,IAAI,KAAK,CAAC,GAAG,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC;gBAC1B,MAAM,CAAC,IAAI,CACT,GAAG,CAAC,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,gBAAgB,KAAK,CAAC,GAAG,IAAI,KAAK,CAAC,GAAG,GAAG,CACjE,CAAC;gBACF,SAAS;YACX,CAAC;YACD,KAAK,IAAI,CAAC,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC5C,IAAI,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;oBAChB,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,SAAS,CAAC,iCAAiC,CAAC,CAAC;gBACpE,CAAC;gBACD,QAAQ,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;YACrB,CAAC;QACH,CAAC;QAED,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;YAC5E,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,WAAW,CAAC,CAAC,KAAK,gBAAgB,KAAK,qBAAqB,CAAC,CAAC;QACrF,CAAC;IACH,CAAC;IAED,KAAK,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,YAAY,EAAE,CAAC;QAC5C,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;YACd,MAAM,CAAC,IAAI,CAAC,8BAA8B,OAAO,KAAK,KAAK,IAAI,CAAC,CAAC;QACnE,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CACvB,QAAmB,EACnB,MAAgB,EAChB,QAAkB,EAClB,MAAoC,EACpC,KAAe;IAEf,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,IAAI,MAAM,KAAK,UAAU,EAAE,CAAC;YAC1B,QAAQ,CAAC,IAAI,CACX,uBAAuB,UAAU,CAAC,KAAK,CAAC,oFAAoF,CAC7H,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;QAC7C,CAAC;QACD,OAAO;IACT,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC5C,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3B,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,2BAA2B,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC;QAC7D,CAAC;aAAM,CAAC;YACN,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAC1D,CAAC;QACD,IAAI,CAAC,CAAC,aAAa,KAAK,SAAS,EAAE,CAAC;YAClC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,gCAAgC,CAAC,CAAC;QAC3D,CAAC;QACD,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;YACX,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,0BAA0B,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;IAED,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,SAAS,EAAE,CAAC;QACtC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;YACd,MAAM,CAAC,IAAI,CAAC,0BAA0B,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;AACH,CAAC"}
package/dist/server.d.ts CHANGED
@@ -5,3 +5,21 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
5
  * transport wiring so tests can drive it over an in-memory transport.
6
6
  */
7
7
  export declare function createServer(): McpServer;
8
+ /**
9
+ * Whether `moduleUrl` (an `import.meta.url`) is the file Node was invoked to
10
+ * run directly (`argv1`), rather than a module some other entry point
11
+ * imported — e.g. the test suite importing server.ts as a library.
12
+ *
13
+ * A raw `fileURLToPath(moduleUrl) === argv1` string comparison (B1) breaks
14
+ * under a POSIX npm-bin symlink: `npx driverge`/a global install invokes the
15
+ * package's bin SYMLINK, so `argv1` is the symlink path, while
16
+ * `fileURLToPath(import.meta.url)` resolves to the module's REAL (symlink
17
+ * target) path — the two strings never match, so the installed CLI silently
18
+ * does nothing. Falling back to a `realpathSync(argv1)` comparison resolves
19
+ * the symlink to the same real path the module URL already has, so the direct
20
+ * string match still short-circuits the common case and only the symlink
21
+ * case pays for an extra syscall. `realpathSync` is wrapped in try/catch
22
+ * because `argv1` could point at a file that no longer exists (or never did)
23
+ * — in which case this is simply not that file, not a crash.
24
+ */
25
+ export declare function isMainModule(moduleUrl: string, argv1: string | undefined): boolean;
package/dist/server.js CHANGED
@@ -6,13 +6,30 @@
6
6
  // analyze_datasheet / generate_driver / validate_driver / validate_datasheet
7
7
  // tools, the datasheet + schema resources, and the generate-driver prompt.
8
8
  // See wiki: mcp-tool-usage-flow.
9
+ import { readFileSync, realpathSync } from "node:fs";
9
10
  import { fileURLToPath } from "node:url";
10
11
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
11
12
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
12
13
  import { z } from "zod";
13
14
  import { registerDriverge } from "./mcp/register.js";
14
15
  const SERVER_NAME = "driverge-mcp";
15
- const SERVER_VERSION = "0.0.0";
16
+ // Read the version from package.json rather than hardcoding it (Session 10 /
17
+ // Contract B7), so it can't drift from what `npm` actually published. The
18
+ // relative path resolves correctly from BOTH src/ (ts-node/vitest) and dist/
19
+ // (the built, published layout) since both sit exactly one level under the
20
+ // package root. Falls back to "0.0.0" if the file is somehow unreadable —
21
+ // never crash the server over a version string.
22
+ function readServerVersion() {
23
+ try {
24
+ const url = new URL("../package.json", import.meta.url);
25
+ const pkg = JSON.parse(readFileSync(fileURLToPath(url), "utf8"));
26
+ return pkg.version ?? "0.0.0";
27
+ }
28
+ catch {
29
+ return "0.0.0";
30
+ }
31
+ }
32
+ const SERVER_VERSION = readServerVersion();
16
33
  /**
17
34
  * Build a Driverge MCP server with its tools registered. Kept separate from the
18
35
  * transport wiring so tests can drive it over an in-memory transport.
@@ -36,10 +53,39 @@ async function main() {
36
53
  const transport = new StdioServerTransport();
37
54
  await server.connect(transport);
38
55
  }
56
+ /**
57
+ * Whether `moduleUrl` (an `import.meta.url`) is the file Node was invoked to
58
+ * run directly (`argv1`), rather than a module some other entry point
59
+ * imported — e.g. the test suite importing server.ts as a library.
60
+ *
61
+ * A raw `fileURLToPath(moduleUrl) === argv1` string comparison (B1) breaks
62
+ * under a POSIX npm-bin symlink: `npx driverge`/a global install invokes the
63
+ * package's bin SYMLINK, so `argv1` is the symlink path, while
64
+ * `fileURLToPath(import.meta.url)` resolves to the module's REAL (symlink
65
+ * target) path — the two strings never match, so the installed CLI silently
66
+ * does nothing. Falling back to a `realpathSync(argv1)` comparison resolves
67
+ * the symlink to the same real path the module URL already has, so the direct
68
+ * string match still short-circuits the common case and only the symlink
69
+ * case pays for an extra syscall. `realpathSync` is wrapped in try/catch
70
+ * because `argv1` could point at a file that no longer exists (or never did)
71
+ * — in which case this is simply not that file, not a crash.
72
+ */
73
+ export function isMainModule(moduleUrl, argv1) {
74
+ if (argv1 === undefined)
75
+ return false;
76
+ const modulePath = fileURLToPath(moduleUrl);
77
+ if (modulePath === argv1)
78
+ return true;
79
+ try {
80
+ return realpathSync(argv1) === modulePath;
81
+ }
82
+ catch {
83
+ return false;
84
+ }
85
+ }
39
86
  // Start the stdio server only when this file is executed directly (via the
40
87
  // `driverge` bin), not when imported — e.g. by the test suite.
41
- const isDirectRun = process.argv[1] !== undefined &&
42
- fileURLToPath(import.meta.url) === process.argv[1];
88
+ const isDirectRun = isMainModule(import.meta.url, process.argv[1]);
43
89
  if (isDirectRun) {
44
90
  main().catch((error) => {
45
91
  console.error("driverge-mcp failed to start:", error);
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";AACA,qCAAqC;AACrC,EAAE;AACF,+EAA+E;AAC/E,0EAA0E;AAC1E,6EAA6E;AAC7E,2EAA2E;AAC3E,iCAAiC;AAEjC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAErD,MAAM,WAAW,GAAG,cAAc,CAAC;AACnC,MAAM,cAAc,GAAG,OAAO,CAAC;AAE/B;;;GAGG;AACH,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,CAAC;IAE7E,MAAM,CAAC,YAAY,CACjB,MAAM,EACN;QACE,KAAK,EAAE,MAAM;QACb,WAAW,EACT,8EAA8E;QAChF,WAAW,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE;KAChD,EACD,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;QACtB,OAAO,EAAE;YACP,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,OAAO,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE;SACvE;KACF,CAAC,CACH,CAAC;IAEF,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAEzB,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;IAC9B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC;AAED,2EAA2E;AAC3E,+DAA+D;AAC/D,MAAM,WAAW,GACf,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,SAAS;IAC7B,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAErD,IAAI,WAAW,EAAE,CAAC;IAChB,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;QAC9B,OAAO,CAAC,KAAK,CAAC,+BAA+B,EAAE,KAAK,CAAC,CAAC;QACtD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "driverge-mcp",
3
- "version": "0.0.0",
3
+ "version": "0.0.1",
4
4
  "description": "MCP server that turns IC datasheet PDFs into embedded C/C++ drivers, driven by any MCP client.",
5
5
  "keywords": [
6
6
  "mcp",
@@ -24,7 +24,7 @@
24
24
  "required": ["bus"],
25
25
  "additionalProperties": false,
26
26
  "properties": {
27
- "bus": { "enum": ["I2C", "SPI", "UART", "unknown"] },
27
+ "bus": { "enum": ["I2C", "SPI", "UART", "CAN", "unknown"] },
28
28
  "addresses": { "type": "array", "items": { "type": "string" } },
29
29
  "maxClockHz": { "type": "number", "minimum": 0 }
30
30
  }
@@ -60,6 +60,16 @@
60
60
  "errors": { "type": "array", "items": { "type": "string" } },
61
61
  "warnings": { "type": "array", "items": { "type": "string" } }
62
62
  }
63
+ },
64
+ "extraction": {
65
+ "type": "object",
66
+ "description": "How complete the deterministic extraction is. Optional (absent on legacy JSON, treated as `none`).",
67
+ "required": ["status", "detectedPages"],
68
+ "additionalProperties": false,
69
+ "properties": {
70
+ "status": { "enum": ["complete", "partial", "deferred", "none"] },
71
+ "detectedPages": { "type": "array", "items": { "type": "integer", "minimum": 1 } }
72
+ }
63
73
  }
64
74
  },
65
75
  "definitions": {
@@ -71,6 +81,10 @@
71
81
  "name": { "type": "string" },
72
82
  "address": { "type": "string" },
73
83
  "reset": { "type": "string" },
84
+ "width": {
85
+ "description": "Register width in bits; absent means 8. Bounds bit-field indices and the reset value (enforced by the L5 validator).",
86
+ "enum": [8, 16, 32]
87
+ },
74
88
  "bitFields": { "type": "array", "items": { "$ref": "#/definitions/bitField" } }
75
89
  }
76
90
  },
@@ -80,8 +94,8 @@
80
94
  "additionalProperties": false,
81
95
  "properties": {
82
96
  "name": { "type": "string" },
83
- "msb": { "type": "integer", "minimum": 0, "maximum": 7 },
84
- "lsb": { "type": "integer", "minimum": 0, "maximum": 7 }
97
+ "msb": { "type": "integer", "minimum": 0, "maximum": 31 },
98
+ "lsb": { "type": "integer", "minimum": 0, "maximum": 31 }
85
99
  }
86
100
  },
87
101
  "command": {