@pure-ds/core 0.7.3 → 0.7.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.
Files changed (39) hide show
  1. package/.cursorrules +21 -0
  2. package/.github/copilot-instructions.md +21 -0
  3. package/dist/types/pds.d.ts +1 -0
  4. package/dist/types/public/assets/js/pds-ask.d.ts +2 -1
  5. package/dist/types/public/assets/js/pds-ask.d.ts.map +1 -1
  6. package/dist/types/public/assets/js/pds-autocomplete.d.ts +25 -36
  7. package/dist/types/public/assets/js/pds-autocomplete.d.ts.map +1 -1
  8. package/dist/types/public/assets/js/pds-enhancers.d.ts +4 -4
  9. package/dist/types/public/assets/js/pds-enhancers.d.ts.map +1 -1
  10. package/dist/types/public/assets/js/pds-manager.d.ts +444 -159
  11. package/dist/types/public/assets/js/pds-manager.d.ts.map +1 -1
  12. package/dist/types/public/assets/js/pds-toast.d.ts +7 -6
  13. package/dist/types/public/assets/js/pds-toast.d.ts.map +1 -1
  14. package/dist/types/public/assets/js/pds.d.ts +4 -3
  15. package/dist/types/public/assets/js/pds.d.ts.map +1 -1
  16. package/dist/types/src/js/pds-core/pds-start-helpers.d.ts.map +1 -1
  17. package/package.json +8 -2
  18. package/packages/pds-cli/bin/pds-bootstrap.js +1 -1
  19. package/packages/pds-cli/bin/pds-import.js +1 -1
  20. package/packages/pds-cli/bin/pds-mcp-eval.js +79 -0
  21. package/packages/pds-cli/bin/pds-mcp-health.js +128 -0
  22. package/packages/pds-cli/bin/pds-mcp-server.js +140 -0
  23. package/packages/pds-cli/bin/pds-setup-mcp.js +72 -0
  24. package/packages/pds-cli/bin/pds-static.js +5 -1
  25. package/packages/pds-cli/bin/sync-assets.js +7 -1
  26. package/packages/pds-cli/lib/pds-mcp-core.js +497 -0
  27. package/packages/pds-cli/lib/pds-mcp-eval-cases.json +72 -0
  28. package/public/assets/js/app.js +43 -4
  29. package/public/assets/js/app.js.map +2 -2
  30. package/public/assets/js/pds-manager.js +35 -2
  31. package/public/assets/js/pds-manager.js.map +2 -2
  32. package/public/assets/js/pds.js +35 -2
  33. package/public/assets/js/pds.js.map +2 -2
  34. package/public/assets/pds/core/pds-manager.js +35 -2
  35. package/public/assets/pds/core.js +35 -2
  36. package/readme.md +44 -0
  37. package/src/js/pds-core/pds-start-helpers.js +40 -2
  38. package/src/js/pds.d.ts +1 -0
  39. package/public/assets/pds/core/pds-auto-definer.js +0 -306
@@ -0,0 +1,497 @@
1
+ import { readFile } from 'fs/promises';
2
+ import { existsSync } from 'fs';
3
+ import path from 'path';
4
+ import { fileURLToPath, pathToFileURL } from 'url';
5
+
6
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
7
+ const PACKAGE_ROOT = path.resolve(__dirname, '../../..');
8
+
9
+ function isObject(value) {
10
+ return value && typeof value === 'object' && !Array.isArray(value);
11
+ }
12
+
13
+ function normalize(value) {
14
+ return String(value || '').toLowerCase();
15
+ }
16
+
17
+ function decodeDataTextUrl(url) {
18
+ if (typeof url !== 'string' || !url.startsWith('data:text/plain,')) return null;
19
+ try {
20
+ return decodeURIComponent(url.replace('data:text/plain,', ''));
21
+ } catch {
22
+ return null;
23
+ }
24
+ }
25
+
26
+ function normalizePath(p) {
27
+ return p.split(path.sep).join('/');
28
+ }
29
+
30
+ function resolveSsoTRoot(projectRoot = process.cwd()) {
31
+ const candidates = [
32
+ PACKAGE_ROOT,
33
+ path.join(projectRoot, 'node_modules', '@pure-ds', 'core'),
34
+ projectRoot,
35
+ ];
36
+
37
+ for (const candidate of candidates) {
38
+ const hasCustomElements = existsSync(path.join(candidate, 'custom-elements.json'));
39
+ const hasCssData = existsSync(path.join(candidate, 'public', 'assets', 'pds', 'pds.css-data.json'));
40
+ const hasCore = existsSync(path.join(candidate, 'src', 'js', 'pds-core'));
41
+ if (hasCustomElements && hasCssData && hasCore) {
42
+ return candidate;
43
+ }
44
+ }
45
+
46
+ return PACKAGE_ROOT;
47
+ }
48
+
49
+ function getSelectorClasses(selector) {
50
+ const classes = [];
51
+ const regex = /\.([a-zA-Z][\w-]*)/g;
52
+ let match = regex.exec(selector);
53
+ while (match) {
54
+ classes.push(match[1]);
55
+ match = regex.exec(selector);
56
+ }
57
+ return classes;
58
+ }
59
+
60
+ function buildSuggestions(items, term, limit = 5) {
61
+ const needle = normalize(term);
62
+ if (!needle) return [];
63
+ const starts = [];
64
+ const contains = [];
65
+ for (const item of items) {
66
+ const n = normalize(item);
67
+ if (n.startsWith(needle)) starts.push(item);
68
+ else if (n.includes(needle)) contains.push(item);
69
+ }
70
+ return [...new Set([...starts, ...contains])].slice(0, limit);
71
+ }
72
+
73
+ function getToolSchema() {
74
+ return [
75
+ {
76
+ name: 'get_tokens',
77
+ description: 'Search PDS CSS custom property tokens from pds.css-data.json.',
78
+ inputSchema: {
79
+ type: 'object',
80
+ properties: {
81
+ contains: { type: 'string', description: 'Substring to search in token name/description.' },
82
+ prefix: { type: 'string', description: 'Token prefix filter, e.g. --color-, --spacing-.' },
83
+ limit: { type: 'number', minimum: 1, maximum: 200, default: 40 },
84
+ includeValues: { type: 'boolean', default: true },
85
+ },
86
+ },
87
+ },
88
+ {
89
+ name: 'find_utility_class',
90
+ description: 'Find PDS selectors/classes from ontology primitives/layout/utilities metadata.',
91
+ inputSchema: {
92
+ type: 'object',
93
+ properties: {
94
+ query: { type: 'string', description: 'Class or concept, e.g. gap, surface, btn, flex.' },
95
+ limit: { type: 'number', minimum: 1, maximum: 100, default: 30 },
96
+ section: {
97
+ type: 'string',
98
+ enum: ['primitives', 'components', 'layoutPatterns', 'all'],
99
+ default: 'all',
100
+ },
101
+ },
102
+ },
103
+ },
104
+ {
105
+ name: 'get_component_api',
106
+ description: 'Lookup PDS custom element API from custom-elements.json.',
107
+ inputSchema: {
108
+ type: 'object',
109
+ properties: {
110
+ tagName: { type: 'string', description: 'Custom element tag, e.g. pds-form.' },
111
+ contains: { type: 'string', description: 'Search by tag/member/attribute/event text.' },
112
+ limit: { type: 'number', minimum: 1, maximum: 50, default: 10 },
113
+ },
114
+ },
115
+ },
116
+ {
117
+ name: 'get_enhancer_metadata',
118
+ description: 'Read enhancer selector descriptions and demoHtml from pds-enhancers-meta.js.',
119
+ inputSchema: {
120
+ type: 'object',
121
+ properties: {
122
+ selector: { type: 'string', description: 'Exact or partial enhancer selector.' },
123
+ contains: { type: 'string', description: 'Search text in selector/description/demoHtml.' },
124
+ includeDemoHtml: { type: 'boolean', default: true },
125
+ limit: { type: 'number', minimum: 1, maximum: 100, default: 20 },
126
+ },
127
+ },
128
+ },
129
+ {
130
+ name: 'get_config_relations',
131
+ description: 'Read PDS_CONFIG_RELATIONS from pds-config.js for deterministic token mapping.',
132
+ inputSchema: {
133
+ type: 'object',
134
+ properties: {
135
+ pathPrefix: { type: 'string', description: 'Config path prefix, e.g. colors, layout.' },
136
+ contains: { type: 'string', description: 'Search inside relation payload JSON.' },
137
+ limit: { type: 'number', minimum: 1, maximum: 200, default: 60 },
138
+ },
139
+ },
140
+ },
141
+ {
142
+ name: 'validate_pds_snippet',
143
+ description: 'Validate HTML snippet for unknown classes, tokens, and pds-* tags against SSoT.',
144
+ inputSchema: {
145
+ type: 'object',
146
+ required: ['html'],
147
+ properties: {
148
+ html: { type: 'string', description: 'HTML snippet to validate.' },
149
+ },
150
+ },
151
+ },
152
+ ];
153
+ }
154
+
155
+ async function loadJson(filePath) {
156
+ const raw = await readFile(filePath, 'utf-8');
157
+ return JSON.parse(raw);
158
+ }
159
+
160
+ async function importModule(filePath) {
161
+ return import(pathToFileURL(filePath).href);
162
+ }
163
+
164
+ export function createPdsMcpContext({ projectRoot = process.cwd() } = {}) {
165
+ const ssoTRoot = resolveSsoTRoot(projectRoot);
166
+ return {
167
+ projectRoot,
168
+ ssoTRoot,
169
+ files: {
170
+ cssData: path.join(ssoTRoot, 'public', 'assets', 'pds', 'pds.css-data.json'),
171
+ customElements: path.join(ssoTRoot, 'custom-elements.json'),
172
+ ontology: path.join(ssoTRoot, 'src', 'js', 'pds-core', 'pds-ontology.js'),
173
+ enhancersMeta: path.join(ssoTRoot, 'src', 'js', 'pds-core', 'pds-enhancers-meta.js'),
174
+ config: path.join(ssoTRoot, 'src', 'js', 'pds-core', 'pds-config.js'),
175
+ },
176
+ cache: new Map(),
177
+ };
178
+ }
179
+
180
+ async function getCssData(ctx) {
181
+ if (!ctx.cache.has('cssData')) {
182
+ ctx.cache.set('cssData', await loadJson(ctx.files.cssData));
183
+ }
184
+ return ctx.cache.get('cssData');
185
+ }
186
+
187
+ async function getCustomElements(ctx) {
188
+ if (!ctx.cache.has('customElements')) {
189
+ ctx.cache.set('customElements', await loadJson(ctx.files.customElements));
190
+ }
191
+ return ctx.cache.get('customElements');
192
+ }
193
+
194
+ async function getOntology(ctx) {
195
+ if (!ctx.cache.has('ontology')) {
196
+ const mod = await importModule(ctx.files.ontology);
197
+ ctx.cache.set('ontology', mod.ontology || {});
198
+ }
199
+ return ctx.cache.get('ontology');
200
+ }
201
+
202
+ async function getEnhancerMeta(ctx) {
203
+ if (!ctx.cache.has('enhancersMeta')) {
204
+ const mod = await importModule(ctx.files.enhancersMeta);
205
+ ctx.cache.set('enhancersMeta', mod.defaultPDSEnhancerMetadata || []);
206
+ }
207
+ return ctx.cache.get('enhancersMeta');
208
+ }
209
+
210
+ async function getConfigRelations(ctx) {
211
+ if (!ctx.cache.has('configRelations')) {
212
+ const mod = await importModule(ctx.files.config);
213
+ ctx.cache.set('configRelations', mod.PDS_CONFIG_RELATIONS || {});
214
+ }
215
+ return ctx.cache.get('configRelations');
216
+ }
217
+
218
+ function shapeComponentDeclaration(declaration) {
219
+ const pick = (items = [], mapper) => items.map(mapper).slice(0, 80);
220
+ return {
221
+ tagName: declaration.tagName,
222
+ className: declaration.name,
223
+ description: declaration.description || '',
224
+ attributes: pick(declaration.attributes, (a) => ({
225
+ name: a.name,
226
+ type: a?.type?.text || null,
227
+ description: a.description || '',
228
+ })),
229
+ events: pick(declaration.events, (e) => ({
230
+ name: e.name,
231
+ type: e?.type?.text || null,
232
+ description: e.description || '',
233
+ })),
234
+ cssParts: pick(declaration.cssParts, (p) => ({ name: p.name, description: p.description || '' })),
235
+ cssProperties: pick(declaration.cssProperties, (p) => ({ name: p.name, description: p.description || '' })),
236
+ members: pick(declaration.members, (m) => ({
237
+ name: m.name,
238
+ kind: m.kind,
239
+ type: m?.type?.text || null,
240
+ description: m.description || '',
241
+ })),
242
+ slots: pick(declaration.slots, (s) => ({ name: s.name || '', description: s.description || '' })),
243
+ };
244
+ }
245
+
246
+ async function handleGetTokens(ctx, args = {}) {
247
+ const { contains = '', prefix = '', includeValues = true } = args;
248
+ const limit = Math.min(Math.max(Number(args.limit || 40), 1), 200);
249
+ const cssData = await getCssData(ctx);
250
+ const needle = normalize(contains);
251
+ const prefixNeedle = normalize(prefix);
252
+
253
+ const matches = (cssData.properties || [])
254
+ .filter((property) => {
255
+ const name = normalize(property.name);
256
+ const description = normalize(property.description);
257
+ const prefixOk = !prefixNeedle || name.startsWith(prefixNeedle);
258
+ const containsOk = !needle || name.includes(needle) || description.includes(needle);
259
+ return prefixOk && containsOk;
260
+ })
261
+ .slice(0, limit)
262
+ .map((property) => {
263
+ const value = includeValues
264
+ ? decodeDataTextUrl(property?.references?.find((r) => r.name === 'Value')?.url)
265
+ : null;
266
+ return {
267
+ name: property.name,
268
+ description: property.description || '',
269
+ syntax: property.syntax || '',
270
+ value,
271
+ };
272
+ });
273
+
274
+ return {
275
+ ssoTRoot: normalizePath(ctx.ssoTRoot),
276
+ source: normalizePath(path.relative(ctx.ssoTRoot, ctx.files.cssData)),
277
+ totalMatches: matches.length,
278
+ tokens: matches,
279
+ };
280
+ }
281
+
282
+ async function handleFindUtilityClass(ctx, args = {}) {
283
+ const { query = '', section = 'all' } = args;
284
+ const limit = Math.min(Math.max(Number(args.limit || 30), 1), 100);
285
+ const ontology = await getOntology(ctx);
286
+ const needle = normalize(query);
287
+
288
+ const buckets = [];
289
+ if (section === 'all' || section === 'primitives') buckets.push(...(ontology.primitives || []));
290
+ if (section === 'all' || section === 'components') buckets.push(...(ontology.components || []));
291
+ if (section === 'all' || section === 'layoutPatterns') buckets.push(...(ontology.layoutPatterns || []));
292
+
293
+ const matches = [];
294
+ const classSet = new Set();
295
+
296
+ for (const item of buckets) {
297
+ const selectors = item.selectors || [];
298
+ for (const selector of selectors) {
299
+ const selectorText = String(selector);
300
+ const matchTarget = `${item.name || ''} ${item.description || ''} ${selectorText}`.toLowerCase();
301
+ if (needle && !matchTarget.includes(needle)) continue;
302
+ matches.push({
303
+ selector: selectorText,
304
+ name: item.name || '',
305
+ description: item.description || '',
306
+ category: item.category || '',
307
+ id: item.id || '',
308
+ });
309
+
310
+ const classes = getSelectorClasses(selectorText);
311
+ for (const className of classes) classSet.add(className);
312
+ }
313
+ }
314
+
315
+ return {
316
+ ssoTRoot: normalizePath(ctx.ssoTRoot),
317
+ source: normalizePath(path.relative(ctx.ssoTRoot, ctx.files.ontology)),
318
+ totalMatches: matches.length,
319
+ matches: matches.slice(0, limit),
320
+ extractedClassesSample: [...classSet].slice(0, 80),
321
+ };
322
+ }
323
+
324
+ async function handleGetComponentApi(ctx, args = {}) {
325
+ const { tagName = '', contains = '' } = args;
326
+ const limit = Math.min(Math.max(Number(args.limit || 10), 1), 50);
327
+ const customElements = await getCustomElements(ctx);
328
+ const tagNeedle = normalize(tagName);
329
+ const textNeedle = normalize(contains);
330
+
331
+ const declarations = [];
332
+ for (const moduleEntry of customElements.modules || []) {
333
+ for (const declaration of moduleEntry.declarations || []) {
334
+ if (!declaration.customElement || !declaration.tagName) continue;
335
+ const shaped = shapeComponentDeclaration(declaration);
336
+ const hay = normalize(JSON.stringify(shaped));
337
+ const tagOk = !tagNeedle || normalize(shaped.tagName) === tagNeedle || normalize(shaped.tagName).includes(tagNeedle);
338
+ const textOk = !textNeedle || hay.includes(textNeedle);
339
+ if (tagOk && textOk) declarations.push(shaped);
340
+ }
341
+ }
342
+
343
+ return {
344
+ ssoTRoot: normalizePath(ctx.ssoTRoot),
345
+ source: normalizePath(path.relative(ctx.ssoTRoot, ctx.files.customElements)),
346
+ totalMatches: declarations.length,
347
+ components: declarations.slice(0, limit),
348
+ };
349
+ }
350
+
351
+ async function handleGetEnhancerMetadata(ctx, args = {}) {
352
+ const { selector = '', contains = '', includeDemoHtml = true } = args;
353
+ const limit = Math.min(Math.max(Number(args.limit || 20), 1), 100);
354
+ const list = await getEnhancerMeta(ctx);
355
+ const selectorNeedle = normalize(selector);
356
+ const textNeedle = normalize(contains);
357
+
358
+ const matches = list
359
+ .filter((item) => {
360
+ const sel = normalize(item.selector);
361
+ const hay = normalize(`${item.selector} ${item.description || ''} ${item.demoHtml || ''}`);
362
+ const selectorOk = !selectorNeedle || sel.includes(selectorNeedle);
363
+ const textOk = !textNeedle || hay.includes(textNeedle);
364
+ return selectorOk && textOk;
365
+ })
366
+ .slice(0, limit)
367
+ .map((item) => ({
368
+ selector: item.selector,
369
+ description: item.description || '',
370
+ demoHtml: includeDemoHtml ? item.demoHtml || '' : undefined,
371
+ }));
372
+
373
+ return {
374
+ ssoTRoot: normalizePath(ctx.ssoTRoot),
375
+ source: normalizePath(path.relative(ctx.ssoTRoot, ctx.files.enhancersMeta)),
376
+ totalMatches: matches.length,
377
+ enhancers: matches,
378
+ };
379
+ }
380
+
381
+ async function handleGetConfigRelations(ctx, args = {}) {
382
+ const { pathPrefix = '', contains = '' } = args;
383
+ const limit = Math.min(Math.max(Number(args.limit || 60), 1), 200);
384
+ const relations = await getConfigRelations(ctx);
385
+ const pathNeedle = normalize(pathPrefix);
386
+ const textNeedle = normalize(contains);
387
+
388
+ const entries = Object.entries(relations)
389
+ .filter(([relationPath, payload]) => {
390
+ const pathOk = !pathNeedle || normalize(relationPath).startsWith(pathNeedle);
391
+ const textOk = !textNeedle || normalize(JSON.stringify(payload)).includes(textNeedle);
392
+ return pathOk && textOk;
393
+ })
394
+ .slice(0, limit)
395
+ .map(([relationPath, payload]) => ({ path: relationPath, relations: payload }));
396
+
397
+ return {
398
+ ssoTRoot: normalizePath(ctx.ssoTRoot),
399
+ source: normalizePath(path.relative(ctx.ssoTRoot, ctx.files.config)),
400
+ totalMatches: entries.length,
401
+ relations: entries,
402
+ };
403
+ }
404
+
405
+ async function handleValidateSnippet(ctx, args = {}) {
406
+ const html = String(args.html || '');
407
+ if (!html.trim()) {
408
+ throw new Error('The "html" argument is required.');
409
+ }
410
+
411
+ const [ontology, cssData, customElements] = await Promise.all([
412
+ getOntology(ctx),
413
+ getCssData(ctx),
414
+ getCustomElements(ctx),
415
+ ]);
416
+
417
+ const knownTokens = new Set((cssData.properties || []).map((p) => p.name));
418
+ const knownComponents = new Set();
419
+ for (const moduleEntry of customElements.modules || []) {
420
+ for (const declaration of moduleEntry.declarations || []) {
421
+ if (declaration.customElement && declaration.tagName) knownComponents.add(declaration.tagName);
422
+ }
423
+ }
424
+
425
+ const knownClasses = new Set();
426
+ for (const group of [ontology.primitives || [], ontology.layoutPatterns || [], ontology.components || []]) {
427
+ for (const item of group) {
428
+ for (const selector of item.selectors || []) {
429
+ for (const className of getSelectorClasses(String(selector))) knownClasses.add(className);
430
+ }
431
+ }
432
+ }
433
+
434
+ const usedClasses = new Set();
435
+ const classRegex = /class\s*=\s*['\"]([^'\"]+)['\"]/g;
436
+ let classMatch = classRegex.exec(html);
437
+ while (classMatch) {
438
+ for (const className of classMatch[1].split(/\s+/).filter(Boolean)) {
439
+ usedClasses.add(className.trim());
440
+ }
441
+ classMatch = classRegex.exec(html);
442
+ }
443
+
444
+ const usedTokens = new Set(html.match(/--[a-zA-Z0-9-]+/g) || []);
445
+
446
+ const componentRegex = /<\s*(pds-[a-z0-9-]+)/gi;
447
+ const usedComponents = new Set();
448
+ let componentMatch = componentRegex.exec(html);
449
+ while (componentMatch) {
450
+ usedComponents.add(componentMatch[1].toLowerCase());
451
+ componentMatch = componentRegex.exec(html);
452
+ }
453
+
454
+ const unknownClasses = [...usedClasses].filter((className) => !knownClasses.has(className));
455
+ const unknownTokens = [...usedTokens].filter((token) => !knownTokens.has(token));
456
+ const unknownComponents = [...usedComponents].filter((tag) => !knownComponents.has(tag));
457
+
458
+ return {
459
+ ssoTRoot: normalizePath(ctx.ssoTRoot),
460
+ valid: unknownClasses.length === 0 && unknownTokens.length === 0 && unknownComponents.length === 0,
461
+ unknown: {
462
+ classes: unknownClasses.map((className) => ({
463
+ name: className,
464
+ suggestions: buildSuggestions([...knownClasses], className),
465
+ })),
466
+ tokens: unknownTokens.map((token) => ({
467
+ name: token,
468
+ suggestions: buildSuggestions([...knownTokens], token),
469
+ })),
470
+ components: unknownComponents.map((tag) => ({
471
+ name: tag,
472
+ suggestions: buildSuggestions([...knownComponents], tag),
473
+ })),
474
+ },
475
+ };
476
+ }
477
+
478
+ const TOOL_HANDLERS = {
479
+ get_tokens: handleGetTokens,
480
+ find_utility_class: handleFindUtilityClass,
481
+ get_component_api: handleGetComponentApi,
482
+ get_enhancer_metadata: handleGetEnhancerMetadata,
483
+ get_config_relations: handleGetConfigRelations,
484
+ validate_pds_snippet: handleValidateSnippet,
485
+ };
486
+
487
+ export function getPdsMcpTools() {
488
+ return getToolSchema();
489
+ }
490
+
491
+ export async function runPdsMcpTool(ctx, name, args = {}) {
492
+ const handler = TOOL_HANDLERS[name];
493
+ if (!handler) {
494
+ throw new Error(`Unknown tool: ${name}`);
495
+ }
496
+ return handler(ctx, isObject(args) ? args : {});
497
+ }
@@ -0,0 +1,72 @@
1
+ [
2
+ {
3
+ "id": "tokens-color",
4
+ "tool": "get_tokens",
5
+ "args": {
6
+ "prefix": "--color-primary-",
7
+ "limit": 5
8
+ },
9
+ "expect": {
10
+ "paths": [
11
+ "tokens",
12
+ "tokens.0.name"
13
+ ]
14
+ }
15
+ },
16
+ {
17
+ "id": "utility-flex",
18
+ "tool": "find_utility_class",
19
+ "args": {
20
+ "query": "flex",
21
+ "limit": 5
22
+ },
23
+ "expect": {
24
+ "paths": [
25
+ "matches",
26
+ "matches.0.selector"
27
+ ]
28
+ }
29
+ },
30
+ {
31
+ "id": "component-form",
32
+ "tool": "get_component_api",
33
+ "args": {
34
+ "tagName": "pds-form",
35
+ "limit": 1
36
+ },
37
+ "expect": {
38
+ "paths": [
39
+ "components",
40
+ "components.0.tagName"
41
+ ]
42
+ }
43
+ },
44
+ {
45
+ "id": "enhancer-dropdown",
46
+ "tool": "get_enhancer_metadata",
47
+ "args": {
48
+ "selector": "data-dropdown",
49
+ "limit": 1
50
+ },
51
+ "expect": {
52
+ "paths": [
53
+ "enhancers",
54
+ "enhancers.0.selector"
55
+ ]
56
+ }
57
+ },
58
+ {
59
+ "id": "relations-colors",
60
+ "tool": "get_config_relations",
61
+ "args": {
62
+ "pathPrefix": "colors",
63
+ "limit": 3
64
+ },
65
+ "expect": {
66
+ "paths": [
67
+ "relations",
68
+ "relations.0.path"
69
+ ]
70
+ }
71
+ }
72
+ ]
@@ -817,7 +817,40 @@ async function setupAutoDefinerAndEnhancers(options, { baseEnhancers = [] } = {}
817
817
  return `${tag}.js`;
818
818
  }
819
819
  };
820
- const { mapper: _overrideMapperIgnored, ...restAutoDefineOverrides } = autoDefineOverrides && typeof autoDefineOverrides === "object" ? autoDefineOverrides : {};
820
+ const {
821
+ mapper: _overrideMapperIgnored,
822
+ enhancers: overrideEnhancers,
823
+ ...restAutoDefineOverrides
824
+ } = autoDefineOverrides && typeof autoDefineOverrides === "object" ? autoDefineOverrides : {};
825
+ const normalizedOverrideEnhancers = (() => {
826
+ if (!overrideEnhancers)
827
+ return [];
828
+ if (Array.isArray(overrideEnhancers))
829
+ return overrideEnhancers;
830
+ if (typeof overrideEnhancers === "object") {
831
+ return Object.values(overrideEnhancers);
832
+ }
833
+ return [];
834
+ })();
835
+ const resolvedEnhancers = (() => {
836
+ const map = /* @__PURE__ */ new Map();
837
+ (mergedEnhancers || []).forEach((enhancer) => {
838
+ if (!enhancer?.selector)
839
+ return;
840
+ map.set(enhancer.selector, enhancer);
841
+ });
842
+ (normalizedOverrideEnhancers || []).forEach((enhancer) => {
843
+ if (!enhancer?.selector)
844
+ return;
845
+ const existing = map.get(enhancer.selector) || null;
846
+ map.set(enhancer.selector, {
847
+ ...existing || {},
848
+ ...enhancer,
849
+ run: typeof enhancer?.run === "function" ? enhancer.run : existing?.run
850
+ });
851
+ });
852
+ return Array.from(map.values());
853
+ })();
821
854
  const normalizedBaseURL = autoDefineBaseURL ? ensureTrailingSlash2(
822
855
  ensureAbsoluteAssetURL(autoDefineBaseURL, {
823
856
  preferModule: autoDefinePreferModule
@@ -830,7 +863,7 @@ async function setupAutoDefinerAndEnhancers(options, { baseEnhancers = [] } = {}
830
863
  observeShadows: true,
831
864
  patchAttachShadow: true,
832
865
  debounceMs: 16,
833
- enhancers: mergedEnhancers,
866
+ enhancers: resolvedEnhancers,
834
867
  onError: (tag, err) => {
835
868
  if (typeof tag === "string" && tag.startsWith("pds-")) {
836
869
  const litDependentComponents = ["pds-form", "pds-drawer"];
@@ -1417,7 +1450,7 @@ var config = {
1417
1450
  var package_default = {
1418
1451
  name: "@pure-ds/core",
1419
1452
  shortname: "pds",
1420
- version: "0.7.2",
1453
+ version: "0.7.4",
1421
1454
  description: "Why develop a Design System when you can generate one?",
1422
1455
  repository: {
1423
1456
  type: "git",
@@ -1447,8 +1480,12 @@ var package_default = {
1447
1480
  "pds-build-icons": "packages/pds-cli/bin/pds-build-icons.js",
1448
1481
  "pds-import": "packages/pds-cli/bin/pds-import.js",
1449
1482
  "pds-setup-copilot": "packages/pds-cli/bin/pds-setup-copilot.js",
1483
+ "pds-setup-mcp": "packages/pds-cli/bin/pds-setup-mcp.js",
1450
1484
  "pds-init-config": "packages/pds-cli/bin/pds-init-config.js",
1451
- "pds-bootstrap": "packages/pds-cli/bin/pds-bootstrap.js"
1485
+ "pds-bootstrap": "packages/pds-cli/bin/pds-bootstrap.js",
1486
+ "pds-mcp-server": "packages/pds-cli/bin/pds-mcp-server.js",
1487
+ "pds-mcp-health": "packages/pds-cli/bin/pds-mcp-health.js",
1488
+ "pds-mcp-eval": "packages/pds-cli/bin/pds-mcp-eval.js"
1452
1489
  },
1453
1490
  exports: {
1454
1491
  ".": {
@@ -1504,6 +1541,8 @@ var package_default = {
1504
1541
  "pds:css-data": "node packages/pds-cli/bin/generate-css-data.js",
1505
1542
  "pds:import": "node packages/pds-cli/bin/pds-import.js",
1506
1543
  "pds:dx": "node packages/pds-cli/bin/pds-dx.js",
1544
+ "pds:mcp:health": "node packages/pds-cli/bin/pds-mcp-health.js",
1545
+ "pds:mcp:eval": "node packages/pds-cli/bin/pds-mcp-eval.js",
1507
1546
  "storybook:generate": "cd packages/pds-storybook && npm run generate-stories",
1508
1547
  "storybook:dev": "cd packages/pds-storybook && npm run storybook:dev",
1509
1548
  "storybook:build": "cd packages/pds-storybook && npm run storybook:build"