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.
- package/README.md +275 -29
- package/dist/codegen/esp32.d.ts +11 -3
- package/dist/codegen/esp32.js +221 -10
- package/dist/codegen/esp32.js.map +1 -1
- package/dist/codegen/ident.d.ts +24 -2
- package/dist/codegen/ident.js +37 -4
- package/dist/codegen/ident.js.map +1 -1
- package/dist/codegen/index.d.ts +12 -7
- package/dist/codegen/index.js +17 -14
- package/dist/codegen/index.js.map +1 -1
- package/dist/codegen/lint.js +28 -8
- package/dist/codegen/lint.js.map +1 -1
- package/dist/codegen/portable-cpp.d.ts +8 -0
- package/dist/codegen/portable-cpp.js +281 -0
- package/dist/codegen/portable-cpp.js.map +1 -0
- package/dist/codegen/portable.d.ts +99 -3
- package/dist/codegen/portable.js +419 -99
- package/dist/codegen/portable.js.map +1 -1
- package/dist/codegen/stm32.d.ts +11 -3
- package/dist/codegen/stm32.js +156 -11
- package/dist/codegen/stm32.js.map +1 -1
- package/dist/codegen/types.d.ts +32 -0
- package/dist/codegen/types.js +27 -0
- package/dist/codegen/types.js.map +1 -1
- package/dist/mcp/cache.d.ts +15 -2
- package/dist/mcp/cache.js +32 -4
- package/dist/mcp/cache.js.map +1 -1
- package/dist/mcp/register.d.ts +17 -0
- package/dist/mcp/register.js +149 -21
- package/dist/mcp/register.js.map +1 -1
- package/dist/mcp/summary.js +8 -0
- package/dist/mcp/summary.js.map +1 -1
- package/dist/pdf/address.d.ts +4 -0
- package/dist/pdf/address.js +28 -0
- package/dist/pdf/address.js.map +1 -0
- package/dist/pdf/command.js +87 -14
- package/dist/pdf/command.js.map +1 -1
- package/dist/pdf/extract.js +23 -2
- package/dist/pdf/extract.js.map +1 -1
- package/dist/pdf/generic-register-table.d.ts +5 -0
- package/dist/pdf/generic-register-table.js +125 -0
- package/dist/pdf/generic-register-table.js.map +1 -0
- package/dist/pdf/index.d.ts +2 -0
- package/dist/pdf/index.js +2 -0
- package/dist/pdf/index.js.map +1 -1
- package/dist/pdf/interface-kind.d.ts +11 -0
- package/dist/pdf/interface-kind.js +18 -0
- package/dist/pdf/interface-kind.js.map +1 -1
- package/dist/pdf/manufacturer.js +39 -0
- package/dist/pdf/manufacturer.js.map +1 -1
- package/dist/pdf/maxim-register-map.d.ts +11 -0
- package/dist/pdf/maxim-register-map.js +544 -0
- package/dist/pdf/maxim-register-map.js.map +1 -0
- package/dist/pdf/part.js +8 -0
- package/dist/pdf/part.js.map +1 -1
- package/dist/pdf/prose-commands.d.ts +4 -0
- package/dist/pdf/prose-commands.js +90 -0
- package/dist/pdf/prose-commands.js.map +1 -0
- package/dist/pdf/st-bit-layout.d.ts +3 -0
- package/dist/pdf/st-bit-layout.js +238 -0
- package/dist/pdf/st-bit-layout.js.map +1 -0
- package/dist/pdf/ti-field-descriptions.d.ts +10 -0
- package/dist/pdf/ti-field-descriptions.js +87 -0
- package/dist/pdf/ti-field-descriptions.js.map +1 -0
- package/dist/pdf/ti-register-map.d.ts +5 -0
- package/dist/pdf/ti-register-map.js +84 -0
- package/dist/pdf/ti-register-map.js.map +1 -0
- package/dist/pdf/types.d.ts +15 -3
- package/dist/pdf/types.js +4 -1
- package/dist/pdf/types.js.map +1 -1
- package/dist/schema/assemble.d.ts +35 -3
- package/dist/schema/assemble.js +86 -13
- package/dist/schema/assemble.js.map +1 -1
- package/dist/schema/types.d.ts +21 -1
- package/dist/schema/validate.js +37 -10
- package/dist/schema/validate.js.map +1 -1
- package/dist/server.d.ts +18 -0
- package/dist/server.js +49 -3
- package/dist/server.js.map +1 -1
- package/package.json +1 -1
- 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;
|
package/dist/schema/assemble.js
CHANGED
|
@@ -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 {
|
|
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
|
-
|
|
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",
|
|
17
|
-
//
|
|
18
|
-
|
|
19
|
-
|
|
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
|
|
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
|
|
40
|
-
interface:
|
|
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/
|
|
1
|
+
{"version":3,"file":"assemble.js","sourceRoot":"","sources":["../../src/schema/assemble.ts"],"names":[],"mappings":"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"}
|
package/dist/schema/types.d.ts
CHANGED
|
@@ -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
|
}
|
package/dist/schema/validate.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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 ||
|
|
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) >
|
|
49
|
-
errors.push(`${r.name}: reset ${r.reset} exceeds the
|
|
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
|
-
|
|
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":"AAAA,iFAAiF;AACjF,0EAA0E;AAC1E,+EAA+E;
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/schema/validate.ts"],"names":[],"mappings":"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"}
|
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
|
-
|
|
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]
|
|
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);
|
package/dist/server.js.map
CHANGED
|
@@ -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;
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -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":
|
|
84
|
-
"lsb": { "type": "integer", "minimum": 0, "maximum":
|
|
97
|
+
"msb": { "type": "integer", "minimum": 0, "maximum": 31 },
|
|
98
|
+
"lsb": { "type": "integer", "minimum": 0, "maximum": 31 }
|
|
85
99
|
}
|
|
86
100
|
},
|
|
87
101
|
"command": {
|