@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
@@ -11202,7 +11202,40 @@ async function setupAutoDefinerAndEnhancers(options, { baseEnhancers = [] } = {}
11202
11202
  return `${tag}.js`;
11203
11203
  }
11204
11204
  };
11205
- const { mapper: _overrideMapperIgnored, ...restAutoDefineOverrides } = autoDefineOverrides && typeof autoDefineOverrides === "object" ? autoDefineOverrides : {};
11205
+ const {
11206
+ mapper: _overrideMapperIgnored,
11207
+ enhancers: overrideEnhancers,
11208
+ ...restAutoDefineOverrides
11209
+ } = autoDefineOverrides && typeof autoDefineOverrides === "object" ? autoDefineOverrides : {};
11210
+ const normalizedOverrideEnhancers = (() => {
11211
+ if (!overrideEnhancers)
11212
+ return [];
11213
+ if (Array.isArray(overrideEnhancers))
11214
+ return overrideEnhancers;
11215
+ if (typeof overrideEnhancers === "object") {
11216
+ return Object.values(overrideEnhancers);
11217
+ }
11218
+ return [];
11219
+ })();
11220
+ const resolvedEnhancers = (() => {
11221
+ const map = /* @__PURE__ */ new Map();
11222
+ (mergedEnhancers || []).forEach((enhancer) => {
11223
+ if (!enhancer?.selector)
11224
+ return;
11225
+ map.set(enhancer.selector, enhancer);
11226
+ });
11227
+ (normalizedOverrideEnhancers || []).forEach((enhancer) => {
11228
+ if (!enhancer?.selector)
11229
+ return;
11230
+ const existing = map.get(enhancer.selector) || null;
11231
+ map.set(enhancer.selector, {
11232
+ ...existing || {},
11233
+ ...enhancer,
11234
+ run: typeof enhancer?.run === "function" ? enhancer.run : existing?.run
11235
+ });
11236
+ });
11237
+ return Array.from(map.values());
11238
+ })();
11206
11239
  const normalizedBaseURL = autoDefineBaseURL ? ensureTrailingSlash2(
11207
11240
  ensureAbsoluteAssetURL(autoDefineBaseURL, {
11208
11241
  preferModule: autoDefinePreferModule
@@ -11215,7 +11248,7 @@ async function setupAutoDefinerAndEnhancers(options, { baseEnhancers = [] } = {}
11215
11248
  observeShadows: true,
11216
11249
  patchAttachShadow: true,
11217
11250
  debounceMs: 16,
11218
- enhancers: mergedEnhancers,
11251
+ enhancers: resolvedEnhancers,
11219
11252
  onError: (tag, err) => {
11220
11253
  if (typeof tag === "string" && tag.startsWith("pds-")) {
11221
11254
  const litDependentComponents = ["pds-form", "pds-drawer"];
@@ -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"];
package/readme.md CHANGED
@@ -186,6 +186,50 @@ Install `@pure-ds/storybook` and get a cloned PDS Storybook instance right where
186
186
 
187
187
  Install `@pure-ds/core` and get instant PDS AI Coding Instrucions at your fingertips (GitHub Copilot & Cursor support built in)
188
188
 
189
+ #### MCP-first SSoT delegation for coding agents
190
+
191
+ PDS also ships a local MCP server so agents can delegate lookups to actual SSoT files instead of relying on duplicated prompt text.
192
+
193
+ **Included binaries**
194
+ - `pds-mcp-server` — stdio MCP server
195
+ - `pds-setup-mcp` — writes local MCP config for VS Code and Cursor
196
+ - `pds-mcp-eval` — runs baseline parity checks against bundled cases
197
+
198
+ **Tool coverage**
199
+ - `get_tokens` → `public/assets/pds/pds.css-data.json`
200
+ - `find_utility_class` → `src/js/pds-core/pds-ontology.js`
201
+ - `get_component_api` → `custom-elements.json`
202
+ - `get_enhancer_metadata` → `src/js/pds-core/pds-enhancers-meta.js`
203
+ - `get_config_relations` → `src/js/pds-core/pds-config.js` (`PDS_CONFIG_RELATIONS`)
204
+ - `validate_pds_snippet` → validates classes/tokens/components against SSoT indexes
205
+
206
+ **Consumer project setup**
207
+
208
+ Run this in any project that depends on `@pure-ds/core`:
209
+
210
+ ```bash
211
+ npx pds-setup-mcp
212
+ ```
213
+
214
+ This creates/updates:
215
+ - `.vscode/mcp.json`
216
+ - `.cursor/mcp.json`
217
+
218
+ Both configs point to:
219
+
220
+ ```text
221
+ node ./node_modules/@pure-ds/core/packages/pds-cli/bin/pds-mcp-server.js
222
+ ```
223
+
224
+ Restart your IDE/agent after setup.
225
+
226
+ **Quality/parity check**
227
+
228
+ ```bash
229
+ npm run pds:mcp:health
230
+ npm run pds:mcp:eval
231
+ ```
232
+
189
233
  ### How It Works
190
234
 
191
235
  It all starts with your `pds.confog.js` file in the root of the project (auto-generated when installing)
@@ -362,11 +362,49 @@ export async function setupAutoDefinerAndEnhancers(options, { baseEnhancers = []
362
362
  };
363
363
 
364
364
  // Respect user overrides but never allow them to overwrite our mapper wrapper.
365
- const { mapper: _overrideMapperIgnored, ...restAutoDefineOverrides } =
365
+ // Also merge `autoDefine.enhancers` safely instead of allowing it to clobber
366
+ // default enhancers (this previously caused silent loss of required/dropdown behavior).
367
+ const {
368
+ mapper: _overrideMapperIgnored,
369
+ enhancers: overrideEnhancers,
370
+ ...restAutoDefineOverrides
371
+ } =
366
372
  autoDefineOverrides && typeof autoDefineOverrides === "object"
367
373
  ? autoDefineOverrides
368
374
  : {};
369
375
 
376
+ const normalizedOverrideEnhancers = (() => {
377
+ if (!overrideEnhancers) return [];
378
+ if (Array.isArray(overrideEnhancers)) return overrideEnhancers;
379
+ if (typeof overrideEnhancers === "object") {
380
+ return Object.values(overrideEnhancers);
381
+ }
382
+ return [];
383
+ })();
384
+
385
+ const resolvedEnhancers = (() => {
386
+ const map = new Map();
387
+ (mergedEnhancers || []).forEach((enhancer) => {
388
+ if (!enhancer?.selector) return;
389
+ map.set(enhancer.selector, enhancer);
390
+ });
391
+
392
+ (normalizedOverrideEnhancers || []).forEach((enhancer) => {
393
+ if (!enhancer?.selector) return;
394
+ const existing = map.get(enhancer.selector) || null;
395
+ map.set(enhancer.selector, {
396
+ ...(existing || {}),
397
+ ...enhancer,
398
+ run:
399
+ typeof enhancer?.run === "function"
400
+ ? enhancer.run
401
+ : existing?.run,
402
+ });
403
+ });
404
+
405
+ return Array.from(map.values());
406
+ })();
407
+
370
408
  const normalizedBaseURL = autoDefineBaseURL
371
409
  ? ensureTrailingSlash(
372
410
  ensureAbsoluteAssetURL(autoDefineBaseURL, {
@@ -382,7 +420,7 @@ export async function setupAutoDefinerAndEnhancers(options, { baseEnhancers = []
382
420
  observeShadows: true,
383
421
  patchAttachShadow: true,
384
422
  debounceMs: 16,
385
- enhancers: mergedEnhancers,
423
+ enhancers: resolvedEnhancers,
386
424
  onError: (tag, err) => {
387
425
  if (typeof tag === "string" && tag.startsWith("pds-")) {
388
426
  const litDependentComponents = ["pds-form", "pds-drawer"];
package/src/js/pds.d.ts CHANGED
@@ -300,6 +300,7 @@ export class PDS extends EventTarget {
300
300
  preset?: string;
301
301
  design?: any;
302
302
  autoDefine?: {
303
+ /** AutoDefiner is bundled with PDS core; external moduleURL overrides are not supported. */
303
304
  baseURL?: string;
304
305
  predefine?: string[];
305
306
  mapper?: (tag: string) => string | undefined | null | false;
@@ -1,306 +0,0 @@
1
- // node_modules/pure-web/src/js/auto-definer.js
2
- async function defineWebComponents(...args) {
3
- let opts = {};
4
- if (args.length && typeof args[args.length - 1] === "object") {
5
- opts = args.pop() || {};
6
- }
7
- const tags = args;
8
- const {
9
- baseURL,
10
- mapper = (tag) => `${tag}.js`,
11
- onError = (tag, err) => console.error(`[defineWebComponents] ${tag}:`, err)
12
- } = opts;
13
- const base = baseURL ? new URL(
14
- baseURL,
15
- typeof location !== "undefined" ? location.href : import.meta.url
16
- ) : new URL("./", import.meta.url);
17
- const toPascal = (tag) => tag.toLowerCase().replace(/(^|-)([a-z])/g, (_, __, c) => c.toUpperCase());
18
- const loadOne = async (tag) => {
19
- try {
20
- if (customElements.get(tag))
21
- return { tag, status: "already-defined" };
22
- const spec = mapper(tag);
23
- const href = spec instanceof URL ? spec.href : new URL(spec, base).href;
24
- const mod = await import(href);
25
- const Named = mod?.default ?? mod?.[toPascal(tag)];
26
- if (!Named) {
27
- if (customElements.get(tag))
28
- return { tag, status: "self-defined" };
29
- throw new Error(
30
- `No export found for ${tag}. Expected default export or named export "${toPascal(
31
- tag
32
- )}".`
33
- );
34
- }
35
- if (!customElements.get(tag)) {
36
- customElements.define(tag, Named);
37
- return { tag, status: "defined" };
38
- }
39
- return { tag, status: "race-already-defined" };
40
- } catch (err) {
41
- onError(tag, err);
42
- throw err;
43
- }
44
- };
45
- return Promise.all(tags.map(loadOne));
46
- }
47
- var AutoDefiner = class {
48
- constructor(options = {}) {
49
- const {
50
- baseURL,
51
- mapper,
52
- onError,
53
- predicate = () => true,
54
- attributeModule = "data-module",
55
- root = document,
56
- scanExisting = true,
57
- debounceMs = 16,
58
- observeShadows = true,
59
- enhancers = [],
60
- // [{String selector, Function run(elem)}]
61
- patchAttachShadow = true
62
- } = options;
63
- const pending = /* @__PURE__ */ new Set();
64
- const inFlight = /* @__PURE__ */ new Set();
65
- const knownMissing = /* @__PURE__ */ new Set();
66
- const perTagModulePath = /* @__PURE__ */ new Map();
67
- const shadowObservers = /* @__PURE__ */ new WeakMap();
68
- const enhancerApplied = /* @__PURE__ */ new WeakMap();
69
- let timer = 0;
70
- let stopped = false;
71
- let restoreAttachShadow = null;
72
- const applyEnhancers = (element) => {
73
- if (!element || !enhancers.length)
74
- return;
75
- let appliedEnhancers = enhancerApplied.get(element);
76
- if (!appliedEnhancers) {
77
- appliedEnhancers = /* @__PURE__ */ new Set();
78
- enhancerApplied.set(element, appliedEnhancers);
79
- }
80
- for (const enhancer of enhancers) {
81
- if (!enhancer.selector || !enhancer.run)
82
- continue;
83
- if (appliedEnhancers.has(enhancer.selector))
84
- continue;
85
- try {
86
- if (element.matches && element.matches(enhancer.selector)) {
87
- enhancer.run(element);
88
- appliedEnhancers.add(enhancer.selector);
89
- }
90
- } catch (err) {
91
- console.warn(
92
- `[AutoDefiner] Error applying enhancer for selector "${enhancer.selector}":`,
93
- err
94
- );
95
- }
96
- }
97
- };
98
- const queueTag = (tag, el) => {
99
- if (stopped)
100
- return;
101
- if (!tag || !tag.includes("-"))
102
- return;
103
- if (customElements.get(tag))
104
- return;
105
- if (inFlight.has(tag))
106
- return;
107
- if (knownMissing.has(tag))
108
- return;
109
- if (el && el.getAttribute) {
110
- const override = el.getAttribute(attributeModule);
111
- if (override && !perTagModulePath.has(tag)) {
112
- perTagModulePath.set(tag, override);
113
- }
114
- }
115
- pending.add(tag);
116
- schedule();
117
- };
118
- const schedule = () => {
119
- if (timer)
120
- return;
121
- timer = setTimeout(flush, debounceMs);
122
- };
123
- const crawlTree = (rootNode) => {
124
- if (!rootNode)
125
- return;
126
- if (rootNode.nodeType === 1) {
127
- const el = (
128
- /** @type {Element} */
129
- rootNode
130
- );
131
- const tag = el.tagName?.toLowerCase();
132
- if (tag && tag.includes("-") && !customElements.get(tag) && predicate(tag, el)) {
133
- queueTag(tag, el);
134
- }
135
- applyEnhancers(el);
136
- if (observeShadows && el.shadowRoot) {
137
- observeShadowRoot(el.shadowRoot);
138
- }
139
- }
140
- if (rootNode.querySelectorAll) {
141
- rootNode.querySelectorAll("*").forEach((e) => {
142
- const t = e.tagName?.toLowerCase();
143
- if (t && t.includes("-") && !customElements.get(t) && predicate(t, e)) {
144
- queueTag(t, e);
145
- }
146
- applyEnhancers(e);
147
- if (observeShadows && e.shadowRoot) {
148
- observeShadowRoot(e.shadowRoot);
149
- }
150
- });
151
- }
152
- };
153
- const observeShadowRoot = (sr) => {
154
- if (!sr || shadowObservers.has(sr))
155
- return;
156
- crawlTree(sr);
157
- const mo = new MutationObserver((mutations) => {
158
- for (const m of mutations) {
159
- m.addedNodes?.forEach((n) => {
160
- crawlTree(n);
161
- });
162
- if (m.type === "attributes" && m.target) {
163
- crawlTree(m.target);
164
- }
165
- }
166
- });
167
- mo.observe(sr, {
168
- childList: true,
169
- subtree: true,
170
- attributes: true,
171
- attributeFilter: [
172
- attributeModule,
173
- ...enhancers.map((e) => e.selector).filter((s) => s.startsWith("data-"))
174
- ]
175
- });
176
- shadowObservers.set(sr, mo);
177
- };
178
- async function flush() {
179
- clearTimeout(timer);
180
- timer = 0;
181
- if (!pending.size)
182
- return;
183
- const tags = Array.from(pending);
184
- pending.clear();
185
- tags.forEach((t) => inFlight.add(t));
186
- try {
187
- const effectiveMapper = (tag) => perTagModulePath.get(tag) ?? (mapper ? mapper(tag) : `${tag}.js`);
188
- await defineWebComponents(...tags, {
189
- baseURL,
190
- mapper: effectiveMapper,
191
- onError: (tag, err) => {
192
- knownMissing.add(tag);
193
- onError?.(tag, err);
194
- }
195
- });
196
- } catch {
197
- } finally {
198
- tags.forEach((t) => inFlight.delete(t));
199
- }
200
- }
201
- const mountNode = root === document ? document.documentElement : root;
202
- const obs = new MutationObserver((mutations) => {
203
- for (const m of mutations) {
204
- m.addedNodes?.forEach((n) => {
205
- crawlTree(n);
206
- });
207
- if (m.type === "attributes" && m.target) {
208
- crawlTree(m.target);
209
- }
210
- }
211
- });
212
- obs.observe(mountNode, {
213
- childList: true,
214
- subtree: true,
215
- attributes: true,
216
- attributeFilter: [
217
- attributeModule,
218
- ...enhancers.map((e) => e.selector).filter((s) => s.startsWith("data-"))
219
- ]
220
- });
221
- if (observeShadows && patchAttachShadow && Element.prototype.attachShadow) {
222
- const orig = Element.prototype.attachShadow;
223
- Element.prototype.attachShadow = function patchedAttachShadow(init) {
224
- const sr = orig.call(this, init);
225
- if (init && init.mode === "open") {
226
- observeShadowRoot(sr);
227
- const tag = this.tagName?.toLowerCase();
228
- if (tag && tag.includes("-") && !customElements.get(tag)) {
229
- queueTag(tag, this);
230
- }
231
- }
232
- return sr;
233
- };
234
- restoreAttachShadow = () => Element.prototype.attachShadow = orig;
235
- }
236
- if (scanExisting) {
237
- crawlTree(mountNode);
238
- }
239
- return {
240
- stop() {
241
- stopped = true;
242
- obs.disconnect();
243
- if (restoreAttachShadow)
244
- restoreAttachShadow();
245
- if (timer) {
246
- clearTimeout(timer);
247
- timer = 0;
248
- }
249
- shadowObservers.forEach((mo) => mo.disconnect());
250
- },
251
- flush
252
- };
253
- }
254
- /**
255
- * Dynamically load and (idempotently) define a set of web components by tag name.
256
- */
257
- static async define(...args) {
258
- let opts = {};
259
- if (args.length && typeof args[args.length - 1] === "object") {
260
- opts = args.pop() || {};
261
- }
262
- const tags = args;
263
- const {
264
- baseURL,
265
- mapper = (tag) => `${tag}.js`,
266
- onError = (tag, err) => console.error(`[defineWebComponents] ${tag}:`, err)
267
- } = opts;
268
- const base = baseURL ? new URL(
269
- baseURL,
270
- typeof location !== "undefined" ? location.href : import.meta.url
271
- ) : new URL("./", import.meta.url);
272
- const toPascal = (tag) => tag.toLowerCase().replace(/(^|-)([a-z])/g, (_, __, c) => c.toUpperCase());
273
- const loadOne = async (tag) => {
274
- try {
275
- if (customElements.get(tag))
276
- return { tag, status: "already-defined" };
277
- const spec = mapper(tag);
278
- const href = spec instanceof URL ? spec.href : new URL(spec, base).href;
279
- const mod = await import(href);
280
- const Named = mod?.default ?? mod?.[toPascal(tag)];
281
- if (!Named) {
282
- if (customElements.get(tag))
283
- return { tag, status: "self-defined" };
284
- throw new Error(
285
- `No export found for ${tag}. Expected default export or named export "${toPascal(
286
- tag
287
- )}".`
288
- );
289
- }
290
- if (!customElements.get(tag)) {
291
- customElements.define(tag, Named);
292
- return { tag, status: "defined" };
293
- }
294
- return { tag, status: "race-already-defined" };
295
- } catch (err) {
296
- onError(tag, err);
297
- throw err;
298
- }
299
- };
300
- return Promise.all(tags.map(loadOne));
301
- }
302
- };
303
- export {
304
- AutoDefiner
305
- };
306
- //# sourceMappingURL=pds-auto-definer.js.map