@mseep/dembrandt 0.19.5
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/LICENSE +21 -0
- package/README.md +408 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +532 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/browser.d.ts +16 -0
- package/dist/lib/browser.js +27 -0
- package/dist/lib/browser.js.map +1 -0
- package/dist/lib/colors.d.ts +101 -0
- package/dist/lib/colors.js +405 -0
- package/dist/lib/colors.js.map +1 -0
- package/dist/lib/compare.d.ts +31 -0
- package/dist/lib/compare.js +46 -0
- package/dist/lib/compare.js.map +1 -0
- package/dist/lib/discovery.d.ts +31 -0
- package/dist/lib/discovery.js +243 -0
- package/dist/lib/discovery.js.map +1 -0
- package/dist/lib/drift.d.ts +64 -0
- package/dist/lib/drift.js +383 -0
- package/dist/lib/drift.js.map +1 -0
- package/dist/lib/dtcg/validate.d.ts +51 -0
- package/dist/lib/dtcg/validate.js +1403 -0
- package/dist/lib/dtcg/validate.js.map +1 -0
- package/dist/lib/exit-codes.d.ts +29 -0
- package/dist/lib/exit-codes.js +26 -0
- package/dist/lib/exit-codes.js.map +1 -0
- package/dist/lib/extractors/breakpoints.d.ts +5 -0
- package/dist/lib/extractors/breakpoints.js +450 -0
- package/dist/lib/extractors/breakpoints.js.map +1 -0
- package/dist/lib/extractors/colors.d.ts +2 -0
- package/dist/lib/extractors/colors.js +657 -0
- package/dist/lib/extractors/colors.js.map +1 -0
- package/dist/lib/extractors/components.d.ts +4 -0
- package/dist/lib/extractors/components.js +370 -0
- package/dist/lib/extractors/components.js.map +1 -0
- package/dist/lib/extractors/index.d.ts +9 -0
- package/dist/lib/extractors/index.js +1257 -0
- package/dist/lib/extractors/index.js.map +1 -0
- package/dist/lib/extractors/logo.d.ts +2 -0
- package/dist/lib/extractors/logo.js +626 -0
- package/dist/lib/extractors/logo.js.map +1 -0
- package/dist/lib/extractors/spacing.d.ts +4 -0
- package/dist/lib/extractors/spacing.js +163 -0
- package/dist/lib/extractors/spacing.js.map +1 -0
- package/dist/lib/extractors/teach.d.ts +1 -0
- package/dist/lib/extractors/teach.js +66 -0
- package/dist/lib/extractors/teach.js.map +1 -0
- package/dist/lib/extractors/typography.d.ts +1 -0
- package/dist/lib/extractors/typography.js +163 -0
- package/dist/lib/extractors/typography.js.map +1 -0
- package/dist/lib/findings.d.ts +34 -0
- package/dist/lib/findings.js +166 -0
- package/dist/lib/findings.js.map +1 -0
- package/dist/lib/formatters/dtcg.d.ts +10 -0
- package/dist/lib/formatters/dtcg.js +416 -0
- package/dist/lib/formatters/dtcg.js.map +1 -0
- package/dist/lib/formatters/html.d.ts +25 -0
- package/dist/lib/formatters/html.js +479 -0
- package/dist/lib/formatters/html.js.map +1 -0
- package/dist/lib/formatters/markdown.d.ts +5 -0
- package/dist/lib/formatters/markdown.js +568 -0
- package/dist/lib/formatters/markdown.js.map +1 -0
- package/dist/lib/formatters/pdf.d.ts +12 -0
- package/dist/lib/formatters/pdf.js +1121 -0
- package/dist/lib/formatters/pdf.js.map +1 -0
- package/dist/lib/formatters/terminal.d.ts +6 -0
- package/dist/lib/formatters/terminal.js +954 -0
- package/dist/lib/formatters/terminal.js.map +1 -0
- package/dist/lib/formatters/theme.d.ts +35 -0
- package/dist/lib/formatters/theme.js +37 -0
- package/dist/lib/formatters/theme.js.map +1 -0
- package/dist/lib/merger.d.ts +14 -0
- package/dist/lib/merger.js +362 -0
- package/dist/lib/merger.js.map +1 -0
- package/dist/lib/normalize.d.ts +29 -0
- package/dist/lib/normalize.js +59 -0
- package/dist/lib/normalize.js.map +1 -0
- package/dist/lib/robots.d.ts +12 -0
- package/dist/lib/robots.js +110 -0
- package/dist/lib/robots.js.map +1 -0
- package/dist/lib/run-summary.d.ts +40 -0
- package/dist/lib/run-summary.js +64 -0
- package/dist/lib/run-summary.js.map +1 -0
- package/dist/lib/types.d.ts +329 -0
- package/dist/lib/types.js +7 -0
- package/dist/lib/types.js.map +1 -0
- package/dist/lib/version.d.ts +134 -0
- package/dist/lib/version.js +153 -0
- package/dist/lib/version.js.map +1 -0
- package/dist/mcp-server.d.ts +11 -0
- package/dist/mcp-server.js +311 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/package.json +106 -0
- package/dist/test/_vitest-shim.d.ts +13 -0
- package/dist/test/_vitest-shim.js +23 -0
- package/dist/test/_vitest-shim.js.map +1 -0
- package/dist/test/cli.test.d.ts +1 -0
- package/dist/test/cli.test.js +24 -0
- package/dist/test/cli.test.js.map +1 -0
- package/dist/test/colors.test.d.ts +1 -0
- package/dist/test/colors.test.js +64 -0
- package/dist/test/colors.test.js.map +1 -0
- package/dist/test/compare.test.d.ts +1 -0
- package/dist/test/compare.test.js +57 -0
- package/dist/test/compare.test.js.map +1 -0
- package/dist/test/drift.test.d.ts +1 -0
- package/dist/test/drift.test.js +53 -0
- package/dist/test/drift.test.js.map +1 -0
- package/dist/test/dtcg-formatter.test.d.ts +1 -0
- package/dist/test/dtcg-formatter.test.js +48 -0
- package/dist/test/dtcg-formatter.test.js.map +1 -0
- package/dist/test/dtcg-validate.test.d.ts +1 -0
- package/dist/test/dtcg-validate.test.js +2129 -0
- package/dist/test/dtcg-validate.test.js.map +1 -0
- package/dist/test/exit-codes.test.d.ts +1 -0
- package/dist/test/exit-codes.test.js +53 -0
- package/dist/test/exit-codes.test.js.map +1 -0
- package/dist/test/findings.test.d.ts +1 -0
- package/dist/test/findings.test.js +77 -0
- package/dist/test/findings.test.js.map +1 -0
- package/dist/test/html.test.d.ts +1 -0
- package/dist/test/html.test.js +95 -0
- package/dist/test/html.test.js.map +1 -0
- package/dist/test/markdown.test.d.ts +1 -0
- package/dist/test/markdown.test.js +145 -0
- package/dist/test/markdown.test.js.map +1 -0
- package/dist/test/merger.test.d.ts +1 -0
- package/dist/test/merger.test.js +98 -0
- package/dist/test/merger.test.js.map +1 -0
- package/dist/test/normalize.test.d.ts +1 -0
- package/dist/test/normalize.test.js +47 -0
- package/dist/test/normalize.test.js.map +1 -0
- package/dist/test/run-summary.test.d.ts +1 -0
- package/dist/test/run-summary.test.js +45 -0
- package/dist/test/run-summary.test.js.map +1 -0
- package/dist/test/version.test.d.ts +1 -0
- package/dist/test/version.test.js +73 -0
- package/dist/test/version.test.js.map +1 -0
- package/package.json +106 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single source of truth for dembrandt output versioning.
|
|
3
|
+
*
|
|
4
|
+
* Three independent version axes travel with every extraction. Keeping them
|
|
5
|
+
* separate is the whole point: a consumer (dembrandt-next, the MCP client, a
|
|
6
|
+
* skill, the drift engine) must be able to reason about the *output format*
|
|
7
|
+
* without coupling to which CLI release produced it.
|
|
8
|
+
*
|
|
9
|
+
* - toolVersion — the dembrandt CLI release (package.json version, e.g.
|
|
10
|
+
* "0.16.0"). Surfaced as meta.dembrandtVersion. Changes on
|
|
11
|
+
* every npm publish, including pure refactors.
|
|
12
|
+
* - schemaVersion — the dembrandt OUTPUT CONTRACT. Bumps only when the JSON
|
|
13
|
+
* shape changes in a way a consumer must adapt to. A tool
|
|
14
|
+
* release that does not change the shape leaves this alone.
|
|
15
|
+
* - specVersion — the W3C DTCG spec revision the `--dtcg` export targets.
|
|
16
|
+
*
|
|
17
|
+
* Version info is surfaced through the two extraction chokepoints, so every
|
|
18
|
+
* consumer inherits it without special-casing:
|
|
19
|
+
* - native JSON : meta.schemaVersion (alongside meta.dembrandtVersion),
|
|
20
|
+
* produced by extractBranding().
|
|
21
|
+
* - DTCG export : $extensions["com.dembrandt"], produced by toDtcgTokens().
|
|
22
|
+
* The DTCG spec mandates that tools preserve vendor extension
|
|
23
|
+
* data they do not understand, so this block survives a
|
|
24
|
+
* round-trip through any compliant tool.
|
|
25
|
+
*
|
|
26
|
+
* schemaVersion bump policy (semver over the output contract, not the tool):
|
|
27
|
+
* - PATCH : additive, non-semantic (a new optional field a consumer can ignore)
|
|
28
|
+
* - MINOR : additive but meaningful (a new field consumers will want to read)
|
|
29
|
+
* - MAJOR : removal, rename, or changed meaning of an existing field
|
|
30
|
+
* Pre-1.0 the tool used loose semver; the output contract starts clean at 1.0.0,
|
|
31
|
+
* baselined on the 0.16.0 shape (inline SVG logo fields, meta.degraded).
|
|
32
|
+
*/
|
|
33
|
+
/**
|
|
34
|
+
* dembrandt output contract version. Bump per the policy documented above.
|
|
35
|
+
*
|
|
36
|
+
* 1.1.0 — added SpacingValue.display, a guaranteed "Npx" string for rendering.
|
|
37
|
+
* Additive: 1.0.x consumers ignore it. Read `display` instead of
|
|
38
|
+
* formatting `px`, whose type narrows from "16px" to a number through
|
|
39
|
+
* normalizeExtraction().
|
|
40
|
+
* 1.0.0 — baselined on the 0.16.0 shape.
|
|
41
|
+
*/
|
|
42
|
+
export declare const SCHEMA_VERSION = "1.1.0";
|
|
43
|
+
/** W3C DTCG spec revision the `--dtcg` export targets. */
|
|
44
|
+
export declare const DTCG_SPEC_VERSION = "2025.10";
|
|
45
|
+
/**
|
|
46
|
+
* Reverse-domain key under which all dembrandt-specific data lives in DTCG
|
|
47
|
+
* output. The DTCG spec recommends reverse-domain notation for $extensions keys
|
|
48
|
+
* to avoid vendor clashes, and requires other tools to preserve unknown
|
|
49
|
+
* extension data. This is the only sanctioned channel for proprietary data;
|
|
50
|
+
* never invent custom `$`-prefixed keys or custom `$type` values.
|
|
51
|
+
*/
|
|
52
|
+
export declare const EXTENSION_KEY = "com.dembrandt";
|
|
53
|
+
/** Document-level provenance block embedded in DTCG `$extensions`. */
|
|
54
|
+
export interface DembrandtProvenance {
|
|
55
|
+
/** Output contract version (SCHEMA_VERSION). */
|
|
56
|
+
schemaVersion: string;
|
|
57
|
+
/** dembrandt CLI release that produced this, or null if unknown. */
|
|
58
|
+
toolVersion: string | null;
|
|
59
|
+
/** DTCG spec revision the export targets. */
|
|
60
|
+
specVersion: string;
|
|
61
|
+
/** Constant tool identifier. */
|
|
62
|
+
generator: 'dembrandt';
|
|
63
|
+
/** Extraction source. */
|
|
64
|
+
source: {
|
|
65
|
+
url: string | null;
|
|
66
|
+
domain: string;
|
|
67
|
+
};
|
|
68
|
+
/** ISO timestamp of the extraction, or null. */
|
|
69
|
+
extractedAt: string | null;
|
|
70
|
+
}
|
|
71
|
+
/** The slice of an extraction result this module needs to assemble provenance. */
|
|
72
|
+
export interface ExtractionLike {
|
|
73
|
+
url?: string;
|
|
74
|
+
extractedAt?: string;
|
|
75
|
+
meta?: {
|
|
76
|
+
dembrandtVersion?: string | null;
|
|
77
|
+
schemaVersion?: string | null;
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Build the canonical `com.dembrandt` provenance block for DTCG `$extensions`.
|
|
82
|
+
* Reads the tool version off the already-assembled native result so there is one
|
|
83
|
+
* place (extractBranding's meta) that owns toolVersion.
|
|
84
|
+
*/
|
|
85
|
+
export declare function buildDembrandtProvenance(result?: ExtractionLike): DembrandtProvenance;
|
|
86
|
+
/**
|
|
87
|
+
* Verdict of comparing an extraction's output-contract version against the
|
|
88
|
+
* contract this build understands.
|
|
89
|
+
*
|
|
90
|
+
* - 'current' : found === SCHEMA_VERSION exactly.
|
|
91
|
+
* - 'compatible' : same major, different minor/patch. Safe to consume: within a
|
|
92
|
+
* major the contract only changes additively, so a newer
|
|
93
|
+
* producer just carries extra fields a consumer can ignore,
|
|
94
|
+
* and an older producer is missing fields a consumer tolerates.
|
|
95
|
+
* - 'outdated' : found major < expected major. A breaking contract change
|
|
96
|
+
* landed since; re-extraction recommended.
|
|
97
|
+
* - 'ahead' : found major > expected major. The producer is newer than
|
|
98
|
+
* this build; upgrade the consumer to read it reliably.
|
|
99
|
+
* - 'legacy' : no schemaVersion present but a toolVersion is. A pre-1.0
|
|
100
|
+
* extraction made before the contract existed.
|
|
101
|
+
* - 'unknown' : no version metadata at all.
|
|
102
|
+
*
|
|
103
|
+
* `compatible` is true only for 'current' and 'compatible'; every other status
|
|
104
|
+
* carries a non-null `message`. This is the single sanctioned compatibility
|
|
105
|
+
* check: consumers (the viewer, dembrandt-next, the drift engine) must compare
|
|
106
|
+
* the OUTPUT CONTRACT here, never the CLI release (`toolVersion`), which churns
|
|
107
|
+
* on every publish and produces false "version mismatch" warnings.
|
|
108
|
+
*/
|
|
109
|
+
export type SchemaCompatibilityStatus = 'current' | 'compatible' | 'outdated' | 'ahead' | 'legacy' | 'unknown';
|
|
110
|
+
export interface SchemaCompatibility {
|
|
111
|
+
status: SchemaCompatibilityStatus;
|
|
112
|
+
/** True when the extraction can be consumed without caveats. */
|
|
113
|
+
compatible: boolean;
|
|
114
|
+
/** schemaVersion read off the extraction, or null when absent. */
|
|
115
|
+
found: string | null;
|
|
116
|
+
/** The contract version this build understands (SCHEMA_VERSION). */
|
|
117
|
+
expected: string;
|
|
118
|
+
/** CLI release that produced the extraction, for diagnostics only. */
|
|
119
|
+
toolVersion: string | null;
|
|
120
|
+
/** Human-readable caveat, or null when status is 'current' / 'compatible'. */
|
|
121
|
+
message: string | null;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Compare an extraction's output-contract version against this build's
|
|
125
|
+
* SCHEMA_VERSION. Never throws: malformed or missing version data degrades to
|
|
126
|
+
* 'unknown' / 'legacy'. See SchemaCompatibility for the status semantics.
|
|
127
|
+
*/
|
|
128
|
+
export declare function checkSchemaCompatibility(result?: ExtractionLike): SchemaCompatibility;
|
|
129
|
+
/**
|
|
130
|
+
* One-line notice for surfacing a compatibility verdict in a UI or log. Returns
|
|
131
|
+
* null when there is nothing to warn about, so callers can render unconditionally:
|
|
132
|
+
* `const notice = formatCompatibilityNotice(checkSchemaCompatibility(result));`
|
|
133
|
+
*/
|
|
134
|
+
export declare function formatCompatibilityNotice(compat: SchemaCompatibility): string | null;
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single source of truth for dembrandt output versioning.
|
|
3
|
+
*
|
|
4
|
+
* Three independent version axes travel with every extraction. Keeping them
|
|
5
|
+
* separate is the whole point: a consumer (dembrandt-next, the MCP client, a
|
|
6
|
+
* skill, the drift engine) must be able to reason about the *output format*
|
|
7
|
+
* without coupling to which CLI release produced it.
|
|
8
|
+
*
|
|
9
|
+
* - toolVersion — the dembrandt CLI release (package.json version, e.g.
|
|
10
|
+
* "0.16.0"). Surfaced as meta.dembrandtVersion. Changes on
|
|
11
|
+
* every npm publish, including pure refactors.
|
|
12
|
+
* - schemaVersion — the dembrandt OUTPUT CONTRACT. Bumps only when the JSON
|
|
13
|
+
* shape changes in a way a consumer must adapt to. A tool
|
|
14
|
+
* release that does not change the shape leaves this alone.
|
|
15
|
+
* - specVersion — the W3C DTCG spec revision the `--dtcg` export targets.
|
|
16
|
+
*
|
|
17
|
+
* Version info is surfaced through the two extraction chokepoints, so every
|
|
18
|
+
* consumer inherits it without special-casing:
|
|
19
|
+
* - native JSON : meta.schemaVersion (alongside meta.dembrandtVersion),
|
|
20
|
+
* produced by extractBranding().
|
|
21
|
+
* - DTCG export : $extensions["com.dembrandt"], produced by toDtcgTokens().
|
|
22
|
+
* The DTCG spec mandates that tools preserve vendor extension
|
|
23
|
+
* data they do not understand, so this block survives a
|
|
24
|
+
* round-trip through any compliant tool.
|
|
25
|
+
*
|
|
26
|
+
* schemaVersion bump policy (semver over the output contract, not the tool):
|
|
27
|
+
* - PATCH : additive, non-semantic (a new optional field a consumer can ignore)
|
|
28
|
+
* - MINOR : additive but meaningful (a new field consumers will want to read)
|
|
29
|
+
* - MAJOR : removal, rename, or changed meaning of an existing field
|
|
30
|
+
* Pre-1.0 the tool used loose semver; the output contract starts clean at 1.0.0,
|
|
31
|
+
* baselined on the 0.16.0 shape (inline SVG logo fields, meta.degraded).
|
|
32
|
+
*/
|
|
33
|
+
// URL is a global in both the Node and DOM libs; no import needed.
|
|
34
|
+
/**
|
|
35
|
+
* dembrandt output contract version. Bump per the policy documented above.
|
|
36
|
+
*
|
|
37
|
+
* 1.1.0 — added SpacingValue.display, a guaranteed "Npx" string for rendering.
|
|
38
|
+
* Additive: 1.0.x consumers ignore it. Read `display` instead of
|
|
39
|
+
* formatting `px`, whose type narrows from "16px" to a number through
|
|
40
|
+
* normalizeExtraction().
|
|
41
|
+
* 1.0.0 — baselined on the 0.16.0 shape.
|
|
42
|
+
*/
|
|
43
|
+
export const SCHEMA_VERSION = '1.1.0';
|
|
44
|
+
/** W3C DTCG spec revision the `--dtcg` export targets. */
|
|
45
|
+
export const DTCG_SPEC_VERSION = '2025.10';
|
|
46
|
+
/**
|
|
47
|
+
* Reverse-domain key under which all dembrandt-specific data lives in DTCG
|
|
48
|
+
* output. The DTCG spec recommends reverse-domain notation for $extensions keys
|
|
49
|
+
* to avoid vendor clashes, and requires other tools to preserve unknown
|
|
50
|
+
* extension data. This is the only sanctioned channel for proprietary data;
|
|
51
|
+
* never invent custom `$`-prefixed keys or custom `$type` values.
|
|
52
|
+
*/
|
|
53
|
+
export const EXTENSION_KEY = 'com.dembrandt';
|
|
54
|
+
/**
|
|
55
|
+
* Derive a clean domain from an extraction URL. Returns 'unknown' on failure so
|
|
56
|
+
* the contract never throws while assembling metadata.
|
|
57
|
+
*/
|
|
58
|
+
function domainOf(url) {
|
|
59
|
+
if (!url)
|
|
60
|
+
return 'unknown';
|
|
61
|
+
try {
|
|
62
|
+
return new URL(url).hostname.replace(/^www\./, '');
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return 'unknown';
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Build the canonical `com.dembrandt` provenance block for DTCG `$extensions`.
|
|
70
|
+
* Reads the tool version off the already-assembled native result so there is one
|
|
71
|
+
* place (extractBranding's meta) that owns toolVersion.
|
|
72
|
+
*/
|
|
73
|
+
export function buildDembrandtProvenance(result = {}) {
|
|
74
|
+
return {
|
|
75
|
+
schemaVersion: SCHEMA_VERSION,
|
|
76
|
+
toolVersion: result?.meta?.dembrandtVersion ?? null,
|
|
77
|
+
specVersion: DTCG_SPEC_VERSION,
|
|
78
|
+
generator: 'dembrandt',
|
|
79
|
+
source: {
|
|
80
|
+
url: result?.url ?? null,
|
|
81
|
+
domain: domainOf(result?.url),
|
|
82
|
+
},
|
|
83
|
+
extractedAt: result?.extractedAt ?? null,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
/** Parse a semver-ish string into its numeric parts, or null if unparseable. */
|
|
87
|
+
function parseSemver(v) {
|
|
88
|
+
if (!v)
|
|
89
|
+
return null;
|
|
90
|
+
const m = /^(\d+)\.(\d+)\.(\d+)/.exec(v.trim());
|
|
91
|
+
if (!m)
|
|
92
|
+
return null;
|
|
93
|
+
return { major: Number(m[1]), minor: Number(m[2]), patch: Number(m[3]) };
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Compare an extraction's output-contract version against this build's
|
|
97
|
+
* SCHEMA_VERSION. Never throws: malformed or missing version data degrades to
|
|
98
|
+
* 'unknown' / 'legacy'. See SchemaCompatibility for the status semantics.
|
|
99
|
+
*/
|
|
100
|
+
export function checkSchemaCompatibility(result = {}) {
|
|
101
|
+
const found = result?.meta?.schemaVersion ?? null;
|
|
102
|
+
const toolVersion = result?.meta?.dembrandtVersion ?? null;
|
|
103
|
+
const base = { found, expected: SCHEMA_VERSION, toolVersion };
|
|
104
|
+
const foundParts = parseSemver(found);
|
|
105
|
+
if (!foundParts) {
|
|
106
|
+
if (toolVersion) {
|
|
107
|
+
return {
|
|
108
|
+
...base,
|
|
109
|
+
status: 'legacy',
|
|
110
|
+
compatible: false,
|
|
111
|
+
message: `Extraction predates the schema contract (produced by dembrandt v${toolVersion}, ` +
|
|
112
|
+
`no schemaVersion). Re-extract with the current release to validate against ` +
|
|
113
|
+
`schema ${SCHEMA_VERSION}. Reading best-effort.`,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
return {
|
|
117
|
+
...base,
|
|
118
|
+
status: 'unknown',
|
|
119
|
+
compatible: false,
|
|
120
|
+
message: 'No version metadata on this extraction. Cannot verify schema compatibility; reading best-effort.',
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
const expectedParts = parseSemver(SCHEMA_VERSION);
|
|
124
|
+
if (foundParts.major === expectedParts.major) {
|
|
125
|
+
const status = found === SCHEMA_VERSION ? 'current' : 'compatible';
|
|
126
|
+
return { ...base, status, compatible: true, message: null };
|
|
127
|
+
}
|
|
128
|
+
if (foundParts.major < expectedParts.major) {
|
|
129
|
+
return {
|
|
130
|
+
...base,
|
|
131
|
+
status: 'outdated',
|
|
132
|
+
compatible: false,
|
|
133
|
+
message: `Extraction uses schema ${found}, this build expects ${SCHEMA_VERSION} ` +
|
|
134
|
+
`(breaking change between majors). Re-extract recommended.`,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
...base,
|
|
139
|
+
status: 'ahead',
|
|
140
|
+
compatible: false,
|
|
141
|
+
message: `Extraction uses schema ${found}, newer than this build's ${SCHEMA_VERSION} ` +
|
|
142
|
+
`(breaking change between majors). Upgrade dembrandt to read it reliably.`,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* One-line notice for surfacing a compatibility verdict in a UI or log. Returns
|
|
147
|
+
* null when there is nothing to warn about, so callers can render unconditionally:
|
|
148
|
+
* `const notice = formatCompatibilityNotice(checkSchemaCompatibility(result));`
|
|
149
|
+
*/
|
|
150
|
+
export function formatCompatibilityNotice(compat) {
|
|
151
|
+
return compat.compatible ? null : compat.message;
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../lib/version.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Dembrandt MCP Server
|
|
4
|
+
*
|
|
5
|
+
* Extract design tokens from any live website. Works with Claude Code, Cursor,
|
|
6
|
+
* Windsurf, and any MCP-compatible client.
|
|
7
|
+
*
|
|
8
|
+
* Install:
|
|
9
|
+
* claude mcp add --transport stdio dembrandt -- npx -y --package dembrandt dembrandt-mcp
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Dembrandt MCP Server
|
|
4
|
+
*
|
|
5
|
+
* Extract design tokens from any live website. Works with Claude Code, Cursor,
|
|
6
|
+
* Windsurf, and any MCP-compatible client.
|
|
7
|
+
*
|
|
8
|
+
* Install:
|
|
9
|
+
* claude mcp add --transport stdio dembrandt -- npx -y --package dembrandt dembrandt-mcp
|
|
10
|
+
*/
|
|
11
|
+
import { readFileSync } from "node:fs";
|
|
12
|
+
import { createRequire } from "node:module";
|
|
13
|
+
import { loadBrowserEngines, PlaywrightMissingError } from "./lib/browser.js";
|
|
14
|
+
import { extractBranding } from "./lib/extractors/index.js";
|
|
15
|
+
import { computeDrift } from "./lib/drift.js";
|
|
16
|
+
import { generateHtmlReport } from "./lib/formatters/html.js";
|
|
17
|
+
const { version } = JSON.parse(readFileSync(new URL("./package.json", import.meta.url), "utf8"));
|
|
18
|
+
/**
|
|
19
|
+
* @modelcontextprotocol/sdk and zod are optional peer dependencies: consumers
|
|
20
|
+
* of the pure exports (drift, types, normalize, dtcg) are not forced to install
|
|
21
|
+
* the MCP stack. The server entry defers their import to startup so a missing
|
|
22
|
+
* install surfaces a clear instruction instead of a raw ERR_MODULE_NOT_FOUND at
|
|
23
|
+
* module load, before any guard could run.
|
|
24
|
+
*/
|
|
25
|
+
class McpDepsMissingError extends Error {
|
|
26
|
+
constructor() {
|
|
27
|
+
super("MCP server dependencies not installed, run: npm i @modelcontextprotocol/sdk zod");
|
|
28
|
+
this.name = "McpDepsMissingError";
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
async function loadMcpDeps() {
|
|
32
|
+
try {
|
|
33
|
+
const [mcp, stdio, zod] = await Promise.all([
|
|
34
|
+
import("@modelcontextprotocol/sdk/server/mcp.js"),
|
|
35
|
+
import("@modelcontextprotocol/sdk/server/stdio.js"),
|
|
36
|
+
import("zod"),
|
|
37
|
+
]);
|
|
38
|
+
return { McpServer: mcp.McpServer, StdioServerTransport: stdio.StdioServerTransport, z: zod.z };
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
throw new McpDepsMissingError();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// extractBranding expects a spinner — stub it for MCP context
|
|
45
|
+
const nullSpinner = {
|
|
46
|
+
text: "",
|
|
47
|
+
start(msg) { this.text = msg; return this; },
|
|
48
|
+
stop() { return this; },
|
|
49
|
+
succeed(_msg) { return this; },
|
|
50
|
+
fail(_msg) { return this; },
|
|
51
|
+
warn(_msg) { return this; },
|
|
52
|
+
info(_msg) { return this; },
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Run extraction with error handling suitable for MCP responses.
|
|
56
|
+
* Returns { ok, data?, error? } so tool handlers never throw.
|
|
57
|
+
*/
|
|
58
|
+
async function runExtraction(url, options = {}) {
|
|
59
|
+
if (!/^https?:\/\//i.test(url))
|
|
60
|
+
url = "https://" + url;
|
|
61
|
+
let browser;
|
|
62
|
+
let chromium;
|
|
63
|
+
try {
|
|
64
|
+
({ chromium } = await loadBrowserEngines());
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
if (err instanceof PlaywrightMissingError)
|
|
68
|
+
return { ok: false, error: err.message };
|
|
69
|
+
throw err;
|
|
70
|
+
}
|
|
71
|
+
const pwVersion = createRequire(import.meta.url)("playwright-core/package.json").version;
|
|
72
|
+
try {
|
|
73
|
+
browser = await chromium.launch({
|
|
74
|
+
headless: true,
|
|
75
|
+
args: ["--disable-blink-features=AutomationControlled"],
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
return {
|
|
80
|
+
ok: false,
|
|
81
|
+
error: `Browser launch failed. Install the matching browser: npx playwright@${pwVersion} install chromium\n\n${err.message}`,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
// Suppress console output — extractors.js writes directly to stdout
|
|
85
|
+
// which would corrupt the JSON-RPC stream
|
|
86
|
+
const _log = console.log;
|
|
87
|
+
const _warn = console.warn;
|
|
88
|
+
const _error = console.error;
|
|
89
|
+
console.log = () => { };
|
|
90
|
+
console.warn = () => { };
|
|
91
|
+
console.error = () => { };
|
|
92
|
+
try {
|
|
93
|
+
const data = await extractBranding(url, nullSpinner, browser, {
|
|
94
|
+
navigationTimeout: 90000,
|
|
95
|
+
slow: options.slow || false,
|
|
96
|
+
darkMode: options.darkMode || false,
|
|
97
|
+
mobile: options.mobile || false,
|
|
98
|
+
});
|
|
99
|
+
return { ok: true, data };
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
const msg = err.message || String(err);
|
|
103
|
+
if (msg.includes("timeout") || msg.includes("Timeout")) {
|
|
104
|
+
return { ok: false, error: `Extraction timed out for ${url}. Try with slow: true for heavy SPAs.` };
|
|
105
|
+
}
|
|
106
|
+
if (msg.includes("net::ERR_NAME_NOT_RESOLVED")) {
|
|
107
|
+
return { ok: false, error: `Could not resolve ${url}. Check the URL.` };
|
|
108
|
+
}
|
|
109
|
+
if (msg.includes("net::ERR_CONNECTION_REFUSED")) {
|
|
110
|
+
return { ok: false, error: `Connection refused by ${url}.` };
|
|
111
|
+
}
|
|
112
|
+
return { ok: false, error: `Extraction failed for ${url}: ${msg}` };
|
|
113
|
+
}
|
|
114
|
+
finally {
|
|
115
|
+
console.log = _log;
|
|
116
|
+
console.warn = _warn;
|
|
117
|
+
console.error = _error;
|
|
118
|
+
await browser.close().catch(() => { });
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
function jsonResult(data) {
|
|
122
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
123
|
+
}
|
|
124
|
+
function errorResult(message) {
|
|
125
|
+
return { content: [{ type: "text", text: message }], isError: true };
|
|
126
|
+
}
|
|
127
|
+
// ── Job Queue ──────────────────────────────────────────────────────────
|
|
128
|
+
class JobQueue {
|
|
129
|
+
#jobs = new Map();
|
|
130
|
+
#queue = [];
|
|
131
|
+
#running = new Set();
|
|
132
|
+
#maxConcurrent = 2;
|
|
133
|
+
enqueue(url, opts, pick) {
|
|
134
|
+
const id = `job_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
135
|
+
this.#jobs.set(id, {
|
|
136
|
+
status: "queued",
|
|
137
|
+
url,
|
|
138
|
+
opts,
|
|
139
|
+
pick,
|
|
140
|
+
createdAt: Date.now(),
|
|
141
|
+
startedAt: undefined,
|
|
142
|
+
completedAt: undefined,
|
|
143
|
+
result: undefined,
|
|
144
|
+
error: undefined,
|
|
145
|
+
});
|
|
146
|
+
this.#queue.push(id);
|
|
147
|
+
void this.#drain();
|
|
148
|
+
return id;
|
|
149
|
+
}
|
|
150
|
+
get(id) {
|
|
151
|
+
return this.#jobs.get(id) ?? null;
|
|
152
|
+
}
|
|
153
|
+
cancel(id) {
|
|
154
|
+
const job = this.#jobs.get(id);
|
|
155
|
+
if (!job || job.status !== "queued")
|
|
156
|
+
return false;
|
|
157
|
+
job.status = "cancelled";
|
|
158
|
+
job.completedAt = Date.now();
|
|
159
|
+
const idx = this.#queue.indexOf(id);
|
|
160
|
+
if (idx !== -1)
|
|
161
|
+
this.#queue.splice(idx, 1);
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
async #drain() {
|
|
165
|
+
while (this.#queue.length > 0 && this.#running.size < this.#maxConcurrent) {
|
|
166
|
+
const id = this.#queue.shift();
|
|
167
|
+
const job = this.#jobs.get(id);
|
|
168
|
+
if (!job || job.status === "cancelled")
|
|
169
|
+
continue;
|
|
170
|
+
job.status = "running";
|
|
171
|
+
job.startedAt = Date.now();
|
|
172
|
+
this.#running.add(id);
|
|
173
|
+
runExtraction(job.url, job.opts)
|
|
174
|
+
.then((result) => {
|
|
175
|
+
if (job.status === "cancelled")
|
|
176
|
+
return;
|
|
177
|
+
if (result.ok) {
|
|
178
|
+
job.status = "completed";
|
|
179
|
+
job.result = job.pick(result.data);
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
job.status = "failed";
|
|
183
|
+
job.error = result.error;
|
|
184
|
+
}
|
|
185
|
+
})
|
|
186
|
+
.catch((err) => {
|
|
187
|
+
if (job.status !== "cancelled") {
|
|
188
|
+
job.status = "failed";
|
|
189
|
+
job.error = err.message || String(err);
|
|
190
|
+
}
|
|
191
|
+
})
|
|
192
|
+
.finally(() => {
|
|
193
|
+
job.completedAt = Date.now();
|
|
194
|
+
this.#running.delete(id);
|
|
195
|
+
void this.#drain();
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
// Remove completed/failed/cancelled jobs older than 1 hour
|
|
200
|
+
cleanup() {
|
|
201
|
+
const cutoff = Date.now() - 3_600_000;
|
|
202
|
+
for (const [id, job] of this.#jobs) {
|
|
203
|
+
if (["completed", "failed", "cancelled"].includes(job.status) &&
|
|
204
|
+
job.completedAt !== undefined &&
|
|
205
|
+
job.completedAt < cutoff) {
|
|
206
|
+
this.#jobs.delete(id);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
const jobQueue = new JobQueue();
|
|
212
|
+
setInterval(() => jobQueue.cleanup(), 600_000);
|
|
213
|
+
// ── Helpers ────────────────────────────────────────────────────────────
|
|
214
|
+
/**
|
|
215
|
+
* Wrapper for extraction tools.
|
|
216
|
+
* Async by default: enqueues and returns a job_id immediately.
|
|
217
|
+
* Pass sync: true to block and return the result directly.
|
|
218
|
+
*/
|
|
219
|
+
function toolHandler(pick, extraOptions = {}) {
|
|
220
|
+
return async (params) => {
|
|
221
|
+
const { url, slow, darkMode, sync } = params;
|
|
222
|
+
const opts = { slow, darkMode, ...extraOptions };
|
|
223
|
+
if (sync) {
|
|
224
|
+
const result = await runExtraction(url, opts);
|
|
225
|
+
if (!result.ok)
|
|
226
|
+
return errorResult(result.error);
|
|
227
|
+
return jsonResult(pick(result.data));
|
|
228
|
+
}
|
|
229
|
+
const jobId = jobQueue.enqueue(url, opts, pick);
|
|
230
|
+
return jsonResult({ job_id: jobId, status: "queued" });
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
// ── Server entry ───────────────────────────────────────────────────────
|
|
234
|
+
async function main() {
|
|
235
|
+
let McpServer, StdioServerTransport, z;
|
|
236
|
+
try {
|
|
237
|
+
({ McpServer, StdioServerTransport, z } = await loadMcpDeps());
|
|
238
|
+
}
|
|
239
|
+
catch (err) {
|
|
240
|
+
console.error(err.message);
|
|
241
|
+
process.exit(1);
|
|
242
|
+
}
|
|
243
|
+
const server = new McpServer({ name: "dembrandt", version });
|
|
244
|
+
// ── Shared params ──────────────────────────────────────────────────────
|
|
245
|
+
const url = z.string().describe("Website URL (e.g. example.com)");
|
|
246
|
+
const slow = z.boolean().optional().default(false).describe("3x timeouts for heavy SPAs");
|
|
247
|
+
const sync = z.boolean().optional().default(false).describe("Wait for result directly instead of returning a job_id (blocks 15-40s)");
|
|
248
|
+
// ── Extraction tools ───────────────────────────────────────────────────
|
|
249
|
+
server.tool("get_design_tokens", "Extract the full design system from a live website. Launches a real browser, navigates to the site, and returns production-ready design tokens: color palette (hex, RGB, LCH, OKLCH) with semantic roles and CSS custom properties, typography scale (families, fallbacks, sizes, weights, line heights, letter spacing by context), spacing system with grid detection, border radii, border patterns, box shadows for elevation, component styles (buttons with hover/focus states, inputs, links, badges), responsive breakpoints, logo and favicons, site name, detected CSS frameworks, and icon systems. Returns a job_id by default — use get_job_status to poll for the result.", { url, slow, sync }, toolHandler((d) => d));
|
|
250
|
+
server.tool("get_color_palette", "Extract brand colors from a live website. Returns semantic colors (primary, secondary, accent), full palette ranked by usage frequency and confidence (high/medium/low), CSS custom properties with their design-system names, and hover/focus state colors discovered by simulating real user interactions. Each color in hex, RGB, LCH, and OKLCH. Returns a job_id by default — use get_job_status to poll for the result.", {
|
|
251
|
+
url, slow, sync,
|
|
252
|
+
darkMode: z.boolean().optional().default(false).describe("Also extract dark mode palette"),
|
|
253
|
+
}, toolHandler((d) => ({ url: d.url, colors: d.colors })));
|
|
254
|
+
server.tool("get_typography", "Extract typography from a live website. Returns every font family with its fallback stack, the complete type scale grouped by context (heading, body, button, link, caption) with pixel and rem sizes, weights, line heights, letter spacing, and text transforms. Also reports font sources: Google Fonts URLs, Adobe Fonts usage, and variable font detection. Returns a job_id by default — use get_job_status to poll for the result.", { url, slow, sync }, toolHandler((d) => ({ url: d.url, typography: d.typography })));
|
|
255
|
+
server.tool("get_component_styles", "Extract UI component styles from a live website. Returns button variants with default, hover, active, and focus states (background, text color, padding, border radius, border, shadow, outline, opacity), input field styles (border, focus ring, padding, placeholder), link styles (color, text decoration, hover changes), and badge/tag styles. Returns a job_id by default — use get_job_status to poll for the result.", { url, slow, sync }, toolHandler((d) => ({ url: d.url, components: d.components })));
|
|
256
|
+
server.tool("get_surfaces", "Extract surface treatment tokens from a live website: border radii with element context (which radii are used on buttons vs cards vs inputs vs modals), border patterns (width + style + color combinations), and box shadow elevation levels. Returns a job_id by default — use get_job_status to poll for the result.", { url, slow, sync }, toolHandler((d) => ({
|
|
257
|
+
url: d.url,
|
|
258
|
+
borderRadius: d.borderRadius,
|
|
259
|
+
borders: d.borders,
|
|
260
|
+
shadows: d.shadows,
|
|
261
|
+
})));
|
|
262
|
+
server.tool("get_spacing", "Extract the spacing system from a live website: common margin and padding values sorted by frequency, pixel and rem values, and grid system detection (4px, 8px, or custom scale). Returns a job_id by default — use get_job_status to poll for the result.", { url, slow, sync }, toolHandler((d) => ({ url: d.url, spacing: d.spacing })));
|
|
263
|
+
server.tool("get_brand_identity", "Extract brand identity from a live website: site name, logo (source, dimensions, safe zone), all favicon variants (icon, apple-touch-icon, og:image, twitter:image with sizes and URLs), detected CSS frameworks (Tailwind, Bootstrap, MUI, etc.), icon systems (Font Awesome, Material Icons, SVG), and responsive breakpoints. Returns a job_id by default — use get_job_status to poll for the result.", { url, slow, sync }, toolHandler((d) => ({
|
|
264
|
+
url: d.url,
|
|
265
|
+
siteName: d.siteName,
|
|
266
|
+
logo: d.logo,
|
|
267
|
+
favicons: d.favicons,
|
|
268
|
+
frameworks: d.frameworks,
|
|
269
|
+
iconSystem: d.iconSystem,
|
|
270
|
+
breakpoints: d.breakpoints,
|
|
271
|
+
})));
|
|
272
|
+
// ── Drift & report tools (synchronous, no browser) ─────────────────────
|
|
273
|
+
// zod 4: z.record needs explicit key + value types; z.record(z.any()) treats
|
|
274
|
+
// the lone arg as the KEY and leaves value undefined, which crashes tools/list.
|
|
275
|
+
const extract = z.record(z.string(), z.any()).describe("A dembrandt extraction object, as returned by get_design_tokens");
|
|
276
|
+
server.tool("compute_drift", "Compare two dembrandt extractions and return a design-drift report: a 0-100 score (0 = identical), a stable/drift verdict, per-category scores, and the list of changed/added/removed tokens (colors, typography, spacing, radius, shadows). Pure and synchronous — no browser. Use it to check whether generated or updated UI has drifted from a brand baseline.", {
|
|
277
|
+
baseline: extract,
|
|
278
|
+
candidate: extract,
|
|
279
|
+
failThreshold: z.number().optional().describe("Score above this yields a 'drift' verdict (default 10)"),
|
|
280
|
+
}, ({ baseline, candidate, failThreshold }) => {
|
|
281
|
+
const report = computeDrift(baseline, candidate, failThreshold != null ? { failThreshold } : {});
|
|
282
|
+
return jsonResult(report);
|
|
283
|
+
});
|
|
284
|
+
server.tool("render_report", "Render a self-contained HTML report (inline CSS, no external resources) from a dembrandt extraction, optionally including a drift diff. Returns the HTML as text — write it to a .html file to open offline or attach as a CI artifact.", {
|
|
285
|
+
result: extract,
|
|
286
|
+
drift: z.any().optional().describe("A drift report from compute_drift, to render the diff banner"),
|
|
287
|
+
}, ({ result, drift }) => {
|
|
288
|
+
const html = generateHtmlReport(result, { drift: drift ?? undefined });
|
|
289
|
+
return { content: [{ type: "text", text: html }] };
|
|
290
|
+
});
|
|
291
|
+
// ── Job management tools ───────────────────────────────────────────────
|
|
292
|
+
server.tool("get_job_status", "Poll for the result of an async extraction job. Returns status (queued/running/completed/failed/cancelled) and the full result once completed. Call this after any extraction tool that returned a job_id.", { job_id: z.string().describe("The job_id returned by an extraction tool") }, ({ job_id }) => {
|
|
293
|
+
const job = jobQueue.get(job_id);
|
|
294
|
+
if (!job)
|
|
295
|
+
return errorResult(`No job found with id: ${job_id}`);
|
|
296
|
+
if (job.status === "completed")
|
|
297
|
+
return jsonResult({ job_id, status: "completed", result: job.result });
|
|
298
|
+
if (job.status === "failed")
|
|
299
|
+
return errorResult(`Job failed: ${job.error}`);
|
|
300
|
+
return jsonResult({ job_id, status: job.status });
|
|
301
|
+
});
|
|
302
|
+
server.tool("cancel_job", "Cancel a queued extraction job. Has no effect on jobs that are already running.", { job_id: z.string().describe("The job_id to cancel") }, ({ job_id }) => {
|
|
303
|
+
const cancelled = jobQueue.cancel(job_id);
|
|
304
|
+
return jsonResult({ job_id, cancelled });
|
|
305
|
+
});
|
|
306
|
+
// ── Start ──────────────────────────────────────────────────────────────
|
|
307
|
+
const transport = new StdioServerTransport();
|
|
308
|
+
await server.connect(transport);
|
|
309
|
+
}
|
|
310
|
+
await main();
|
|
311
|
+
//# sourceMappingURL=mcp-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-server.js","sourceRoot":"","sources":["../mcp-server.ts"],"names":[],"mappings":"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"}
|