@nysds/mcp-server 1.0.0 → 1.15.0
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/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/lib/cem-parser.d.ts +96 -0
- package/dist/lib/cem-parser.d.ts.map +1 -0
- package/dist/lib/cem-parser.js +82 -0
- package/dist/lib/search.d.ts +20 -0
- package/dist/lib/search.d.ts.map +1 -0
- package/dist/lib/search.js +87 -0
- package/dist/lib/token-parser.d.ts +140 -0
- package/dist/lib/token-parser.d.ts.map +1 -0
- package/dist/lib/token-parser.js +458 -0
- package/dist/prompts/nysds-mode.d.ts +8 -0
- package/dist/prompts/nysds-mode.d.ts.map +1 -0
- package/dist/prompts/nysds-mode.js +51 -0
- package/dist/resources/components.d.ts +12 -0
- package/dist/resources/components.d.ts.map +1 -0
- package/dist/resources/components.js +62 -0
- package/dist/resources/guides.d.ts +11 -0
- package/dist/resources/guides.d.ts.map +1 -0
- package/dist/resources/guides.js +80 -0
- package/dist/resources/index.d.ts +8 -0
- package/dist/resources/index.d.ts.map +1 -0
- package/dist/resources/index.js +13 -0
- package/dist/resources/tokens.d.ts +17 -0
- package/dist/resources/tokens.d.ts.map +1 -0
- package/dist/resources/tokens.js +312 -0
- package/dist/server.d.ts +11 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +30 -0
- package/dist/tools/component-tools.d.ts +14 -0
- package/dist/tools/component-tools.d.ts.map +1 -0
- package/dist/tools/component-tools.js +127 -0
- package/dist/tools/index.d.ts +8 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +13 -0
- package/dist/tools/token-tools.d.ts +17 -0
- package/dist/tools/token-tools.d.ts.map +1 -0
- package/dist/tools/token-tools.js +504 -0
- package/dist/tools/validation-tools.d.ts +12 -0
- package/dist/tools/validation-tools.d.ts.map +1 -0
- package/dist/tools/validation-tools.js +222 -0
- package/package.json +1 -1
|
@@ -0,0 +1,458 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Design Token Parser
|
|
3
|
+
*
|
|
4
|
+
* Reads and parses NYSDS design tokens with a CSS-centric approach.
|
|
5
|
+
* Returns data aligned with tokens.css output (not JSON internals).
|
|
6
|
+
*
|
|
7
|
+
* Key transformations:
|
|
8
|
+
* - Token paths are converted to CSS variable names
|
|
9
|
+
* - Alias references become var() expressions
|
|
10
|
+
* - Layer prefixes (primitive, applied) are stripped
|
|
11
|
+
*/
|
|
12
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
13
|
+
import { resolve, dirname } from "node:path";
|
|
14
|
+
import { fileURLToPath } from "node:url";
|
|
15
|
+
// ESM path resolution
|
|
16
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
17
|
+
const __dirname = dirname(__filename);
|
|
18
|
+
// ============================================================================
|
|
19
|
+
// Token Data Cache
|
|
20
|
+
// ============================================================================
|
|
21
|
+
let cachedLegacyTokens = null;
|
|
22
|
+
let cachedCSSTokens = null;
|
|
23
|
+
let cachedTokenGraph = null;
|
|
24
|
+
let cachedRawTokens = null;
|
|
25
|
+
// ============================================================================
|
|
26
|
+
// Path Resolution
|
|
27
|
+
// ============================================================================
|
|
28
|
+
/**
|
|
29
|
+
* Get the path to tokens.json file
|
|
30
|
+
* Uses ESM-compatible path resolution with fallbacks for different contexts
|
|
31
|
+
*/
|
|
32
|
+
export function getTokensPath() {
|
|
33
|
+
// Fallback paths for different execution contexts
|
|
34
|
+
const possiblePaths = [
|
|
35
|
+
// From lib/ directory (normal execution)
|
|
36
|
+
resolve(__dirname, "../../../../tokens/src/tokens.json"),
|
|
37
|
+
// From mcp-server package root
|
|
38
|
+
resolve(__dirname, "../../../tokens/src/tokens.json"),
|
|
39
|
+
// From monorepo root
|
|
40
|
+
resolve(__dirname, "../../../../../packages/tokens/src/tokens.json"),
|
|
41
|
+
// Direct path from monorepo root
|
|
42
|
+
resolve(process.cwd(), "packages/tokens/src/tokens.json"),
|
|
43
|
+
// From mcp-server package
|
|
44
|
+
resolve(process.cwd(), "../tokens/src/tokens.json"),
|
|
45
|
+
];
|
|
46
|
+
for (const path of possiblePaths) {
|
|
47
|
+
if (existsSync(path)) {
|
|
48
|
+
return path;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Get the path to tokens.css file
|
|
55
|
+
*/
|
|
56
|
+
export function getTokensCSSPath() {
|
|
57
|
+
const possiblePaths = [
|
|
58
|
+
resolve(__dirname, "../../../../tokens/dist/tokens.css"),
|
|
59
|
+
resolve(__dirname, "../../../tokens/dist/tokens.css"),
|
|
60
|
+
resolve(__dirname, "../../../../../packages/tokens/dist/tokens.css"),
|
|
61
|
+
resolve(process.cwd(), "packages/tokens/dist/tokens.css"),
|
|
62
|
+
resolve(process.cwd(), "../tokens/dist/tokens.css"),
|
|
63
|
+
];
|
|
64
|
+
for (const path of possiblePaths) {
|
|
65
|
+
if (existsSync(path)) {
|
|
66
|
+
return path;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
// ============================================================================
|
|
72
|
+
// CSS Variable Transformation
|
|
73
|
+
// ============================================================================
|
|
74
|
+
/**
|
|
75
|
+
* Transform a JSON token path to CSS variable name
|
|
76
|
+
*
|
|
77
|
+
* Examples:
|
|
78
|
+
* - "primitive.color.neutral.900" → "--nys-color-neutral-900"
|
|
79
|
+
* - "applied.color.text.default" → "--nys-color-text"
|
|
80
|
+
* - "color.theme.default" → "--nys-color-theme"
|
|
81
|
+
* - "font.size.md" → "--nys-font-size-md"
|
|
82
|
+
*/
|
|
83
|
+
export function toCSSVariable(jsonPath) {
|
|
84
|
+
let name = "--nys-" +
|
|
85
|
+
jsonPath
|
|
86
|
+
// Strip layer prefixes
|
|
87
|
+
.replace(/^(primitive|applied|appearance|theme)\./, "")
|
|
88
|
+
// Dots to hyphens
|
|
89
|
+
.replace(/\./g, "-");
|
|
90
|
+
// Strip trailing -default suffix
|
|
91
|
+
name = name.replace(/-default$/, "");
|
|
92
|
+
return name;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Convert an alias reference to CSS var() syntax
|
|
96
|
+
*
|
|
97
|
+
* Examples:
|
|
98
|
+
* - "{primitive.color.neutral.900}" → "var(--nys-color-neutral-900)"
|
|
99
|
+
* - "{font.size.md}" → "var(--nys-font-size-md)"
|
|
100
|
+
*/
|
|
101
|
+
export function aliasToVarRef(aliasValue) {
|
|
102
|
+
// Extract the path from {path.to.token}
|
|
103
|
+
const match = aliasValue.match(/^\{(.+)\}$/);
|
|
104
|
+
if (!match) {
|
|
105
|
+
return { cssValue: aliasValue, referencesVariable: "" };
|
|
106
|
+
}
|
|
107
|
+
const referencesVariable = toCSSVariable(match[1]);
|
|
108
|
+
const cssValue = `var(${referencesVariable})`;
|
|
109
|
+
return { cssValue, referencesVariable };
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Determine the category from a JSON path
|
|
113
|
+
*/
|
|
114
|
+
function getCategoryFromPath(jsonPath) {
|
|
115
|
+
const parts = jsonPath.split(".");
|
|
116
|
+
// Skip layer prefix if present
|
|
117
|
+
const startIndex = ["primitive", "applied", "appearance", "theme"].includes(parts[0])
|
|
118
|
+
? 1
|
|
119
|
+
: 0;
|
|
120
|
+
return parts[startIndex] || "unknown";
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Determine the layer from a JSON path
|
|
124
|
+
*
|
|
125
|
+
* Layers:
|
|
126
|
+
* - primitive: Raw values (colors, sizes, fonts, spacing, etc.)
|
|
127
|
+
* - applied: Semantic tokens that reference primitives (includes color.theme.* defaults)
|
|
128
|
+
* - theme: Agency theme overrides
|
|
129
|
+
* - appearance: Light/dark mode variations
|
|
130
|
+
*/
|
|
131
|
+
function getLayerFromPath(jsonPath) {
|
|
132
|
+
const parts = jsonPath.split(".");
|
|
133
|
+
// Check for explicit layer prefixes
|
|
134
|
+
if (["primitive", "applied", "appearance", "theme"].includes(parts[0])) {
|
|
135
|
+
return parts[0];
|
|
136
|
+
}
|
|
137
|
+
// color.theme.* tokens are applied semantic tokens (agency themes override these)
|
|
138
|
+
if (parts[0] === "color" && parts[1] === "theme") {
|
|
139
|
+
return "applied";
|
|
140
|
+
}
|
|
141
|
+
// Non-prefixed categories (space, size, font, radius, etc.) contain raw values
|
|
142
|
+
// so they are classified as "primitive"
|
|
143
|
+
return "primitive";
|
|
144
|
+
}
|
|
145
|
+
// ============================================================================
|
|
146
|
+
// Token Parsing
|
|
147
|
+
// ============================================================================
|
|
148
|
+
/**
|
|
149
|
+
* Load raw token data from tokens.json
|
|
150
|
+
*/
|
|
151
|
+
function loadRawTokens() {
|
|
152
|
+
if (cachedRawTokens) {
|
|
153
|
+
return cachedRawTokens;
|
|
154
|
+
}
|
|
155
|
+
const tokensPath = getTokensPath();
|
|
156
|
+
if (!tokensPath) {
|
|
157
|
+
console.error("Warning: No tokens file found");
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
try {
|
|
161
|
+
const content = readFileSync(tokensPath, "utf-8");
|
|
162
|
+
cachedRawTokens = JSON.parse(content);
|
|
163
|
+
return cachedRawTokens;
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
console.error("Warning: Could not parse tokens file:", error);
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Parse tokens recursively into CSS-centric format
|
|
172
|
+
*/
|
|
173
|
+
function parseCSSTokens(obj, prefix = "", resolvedValues = new Map()) {
|
|
174
|
+
const tokens = [];
|
|
175
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
176
|
+
if (key.startsWith("$"))
|
|
177
|
+
continue; // Skip meta properties
|
|
178
|
+
const jsonPath = prefix ? `${prefix}.${key}` : key;
|
|
179
|
+
if (typeof value === "object" &&
|
|
180
|
+
value !== null &&
|
|
181
|
+
"$value" in value) {
|
|
182
|
+
// This is a token
|
|
183
|
+
const tokenObj = value;
|
|
184
|
+
const rawValue = tokenObj.$value;
|
|
185
|
+
const description = tokenObj.$description;
|
|
186
|
+
const cssVariable = toCSSVariable(jsonPath);
|
|
187
|
+
const category = getCategoryFromPath(jsonPath);
|
|
188
|
+
const layer = getLayerFromPath(jsonPath);
|
|
189
|
+
let cssValue;
|
|
190
|
+
let referencesVariable;
|
|
191
|
+
let resolvedValue;
|
|
192
|
+
// Handle different value types
|
|
193
|
+
if (typeof rawValue === "string" && rawValue.startsWith("{")) {
|
|
194
|
+
// Alias reference
|
|
195
|
+
const aliasResult = aliasToVarRef(rawValue);
|
|
196
|
+
cssValue = aliasResult.cssValue;
|
|
197
|
+
referencesVariable = aliasResult.referencesVariable;
|
|
198
|
+
// Try to resolve the value
|
|
199
|
+
resolvedValue = resolvedValues.get(referencesVariable);
|
|
200
|
+
}
|
|
201
|
+
else if (Array.isArray(rawValue)) {
|
|
202
|
+
// Complex value (like shadows) - format as string
|
|
203
|
+
cssValue = JSON.stringify(rawValue);
|
|
204
|
+
resolvedValue = cssValue;
|
|
205
|
+
}
|
|
206
|
+
else if (typeof rawValue === "object" && rawValue !== null) {
|
|
207
|
+
// Object value (like single shadow)
|
|
208
|
+
cssValue = JSON.stringify(rawValue);
|
|
209
|
+
resolvedValue = cssValue;
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
// Direct value
|
|
213
|
+
cssValue = String(rawValue);
|
|
214
|
+
resolvedValue = cssValue;
|
|
215
|
+
}
|
|
216
|
+
// Store resolved value for other tokens to reference
|
|
217
|
+
if (resolvedValue) {
|
|
218
|
+
resolvedValues.set(cssVariable, resolvedValue);
|
|
219
|
+
}
|
|
220
|
+
tokens.push({
|
|
221
|
+
cssVariable,
|
|
222
|
+
cssValue,
|
|
223
|
+
referencesVariable,
|
|
224
|
+
resolvedValue,
|
|
225
|
+
description,
|
|
226
|
+
category,
|
|
227
|
+
layer,
|
|
228
|
+
jsonPath,
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
else if (typeof value === "object" && value !== null) {
|
|
232
|
+
// Recurse into nested group
|
|
233
|
+
tokens.push(...parseCSSTokens(value, jsonPath, resolvedValues));
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return tokens;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Resolve all alias values to their final resolved values
|
|
240
|
+
*/
|
|
241
|
+
function resolveAllValues(tokens) {
|
|
242
|
+
const byVariable = new Map();
|
|
243
|
+
for (const token of tokens) {
|
|
244
|
+
byVariable.set(token.cssVariable, token);
|
|
245
|
+
}
|
|
246
|
+
// Iterate to resolve nested aliases (max 10 levels to prevent infinite loops)
|
|
247
|
+
for (let i = 0; i < 10; i++) {
|
|
248
|
+
let changed = false;
|
|
249
|
+
for (const token of tokens) {
|
|
250
|
+
if (token.referencesVariable && !token.resolvedValue) {
|
|
251
|
+
const referenced = byVariable.get(token.referencesVariable);
|
|
252
|
+
if (referenced?.resolvedValue) {
|
|
253
|
+
token.resolvedValue = referenced.resolvedValue;
|
|
254
|
+
changed = true;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
if (!changed)
|
|
259
|
+
break;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
// ============================================================================
|
|
263
|
+
// Token Graph
|
|
264
|
+
// ============================================================================
|
|
265
|
+
/**
|
|
266
|
+
* Build a dependency graph of tokens
|
|
267
|
+
* Shows which tokens reference which, and which tokens are used by which
|
|
268
|
+
*/
|
|
269
|
+
export function buildTokenGraph() {
|
|
270
|
+
if (cachedTokenGraph) {
|
|
271
|
+
return cachedTokenGraph;
|
|
272
|
+
}
|
|
273
|
+
const tokens = getCSSTokens();
|
|
274
|
+
const graph = new Map();
|
|
275
|
+
// Initialize all nodes
|
|
276
|
+
for (const token of tokens) {
|
|
277
|
+
graph.set(token.cssVariable, {
|
|
278
|
+
cssVariable: token.cssVariable,
|
|
279
|
+
referencesVariable: token.referencesVariable,
|
|
280
|
+
usedBy: [],
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
// Build usedBy relationships
|
|
284
|
+
for (const token of tokens) {
|
|
285
|
+
if (token.referencesVariable) {
|
|
286
|
+
const referenced = graph.get(token.referencesVariable);
|
|
287
|
+
if (referenced) {
|
|
288
|
+
referenced.usedBy.push(token.cssVariable);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
cachedTokenGraph = graph;
|
|
293
|
+
return graph;
|
|
294
|
+
}
|
|
295
|
+
// ============================================================================
|
|
296
|
+
// Public API - CSS-Centric
|
|
297
|
+
// ============================================================================
|
|
298
|
+
/**
|
|
299
|
+
* Get all tokens in CSS-centric format
|
|
300
|
+
*/
|
|
301
|
+
export function getCSSTokens() {
|
|
302
|
+
if (cachedCSSTokens) {
|
|
303
|
+
return cachedCSSTokens;
|
|
304
|
+
}
|
|
305
|
+
const rawTokens = loadRawTokens();
|
|
306
|
+
if (!rawTokens) {
|
|
307
|
+
cachedCSSTokens = [];
|
|
308
|
+
return cachedCSSTokens;
|
|
309
|
+
}
|
|
310
|
+
cachedCSSTokens = parseCSSTokens(rawTokens);
|
|
311
|
+
resolveAllValues(cachedCSSTokens);
|
|
312
|
+
return cachedCSSTokens;
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Get CSS tokens filtered by category
|
|
316
|
+
*/
|
|
317
|
+
export function getCSSTokensByCategory(category) {
|
|
318
|
+
const tokens = getCSSTokens();
|
|
319
|
+
return tokens.filter((t) => t.category.toLowerCase() === category.toLowerCase());
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Get CSS tokens filtered by layer
|
|
323
|
+
*/
|
|
324
|
+
export function getCSSTokensByLayer(layer) {
|
|
325
|
+
const tokens = getCSSTokens();
|
|
326
|
+
return tokens.filter((t) => t.layer.toLowerCase() === layer.toLowerCase());
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Search CSS tokens by variable name, value, or description
|
|
330
|
+
*/
|
|
331
|
+
export function searchCSSTokens(query) {
|
|
332
|
+
const tokens = getCSSTokens();
|
|
333
|
+
const lowerQuery = query.toLowerCase();
|
|
334
|
+
return tokens.filter((t) => t.cssVariable.toLowerCase().includes(lowerQuery) ||
|
|
335
|
+
t.cssValue.toLowerCase().includes(lowerQuery) ||
|
|
336
|
+
t.resolvedValue?.toLowerCase().includes(lowerQuery) ||
|
|
337
|
+
t.description?.toLowerCase().includes(lowerQuery));
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Get a single token by CSS variable name
|
|
341
|
+
*/
|
|
342
|
+
export function getCSSTokenByVariable(variableName) {
|
|
343
|
+
const tokens = getCSSTokens();
|
|
344
|
+
// Normalize: accept with or without -- prefix
|
|
345
|
+
const normalized = variableName.startsWith("--")
|
|
346
|
+
? variableName
|
|
347
|
+
: `--nys-${variableName}`;
|
|
348
|
+
return tokens.find((t) => t.cssVariable === normalized);
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Get all unique categories
|
|
352
|
+
*/
|
|
353
|
+
export function getCSSTokenCategories() {
|
|
354
|
+
const tokens = getCSSTokens();
|
|
355
|
+
const counts = new Map();
|
|
356
|
+
for (const token of tokens) {
|
|
357
|
+
counts.set(token.category, (counts.get(token.category) || 0) + 1);
|
|
358
|
+
}
|
|
359
|
+
return Array.from(counts.entries())
|
|
360
|
+
.map(([category, count]) => ({ category, count }))
|
|
361
|
+
.sort((a, b) => a.category.localeCompare(b.category));
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Get raw tokens.css content
|
|
365
|
+
*/
|
|
366
|
+
export function getTokensCSS() {
|
|
367
|
+
const cssPath = getTokensCSSPath();
|
|
368
|
+
if (!cssPath) {
|
|
369
|
+
return null;
|
|
370
|
+
}
|
|
371
|
+
try {
|
|
372
|
+
return readFileSync(cssPath, "utf-8");
|
|
373
|
+
}
|
|
374
|
+
catch {
|
|
375
|
+
return null;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
// ============================================================================
|
|
379
|
+
// Public API - Legacy (Backward Compatible)
|
|
380
|
+
// ============================================================================
|
|
381
|
+
/**
|
|
382
|
+
* Parse DTCG format tokens recursively (legacy format)
|
|
383
|
+
*/
|
|
384
|
+
function parseDTCGTokens(obj, prefix = "", category = "") {
|
|
385
|
+
const tokens = [];
|
|
386
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
387
|
+
if (key.startsWith("$"))
|
|
388
|
+
continue; // Skip meta properties
|
|
389
|
+
const name = prefix ? `${prefix}.${key}` : key;
|
|
390
|
+
const currentCategory = category || key;
|
|
391
|
+
if (typeof value === "object" &&
|
|
392
|
+
value !== null &&
|
|
393
|
+
"$value" in value) {
|
|
394
|
+
// This is a token
|
|
395
|
+
const tokenObj = value;
|
|
396
|
+
tokens.push({
|
|
397
|
+
name,
|
|
398
|
+
value: String(tokenObj.$value),
|
|
399
|
+
category: currentCategory,
|
|
400
|
+
description: tokenObj.$description,
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
else if (typeof value === "object" && value !== null) {
|
|
404
|
+
// Recurse into nested group
|
|
405
|
+
tokens.push(...parseDTCGTokens(value, name, currentCategory));
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
return tokens;
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Load all design tokens (legacy format)
|
|
412
|
+
*/
|
|
413
|
+
export function getAllTokens() {
|
|
414
|
+
if (cachedLegacyTokens) {
|
|
415
|
+
return cachedLegacyTokens;
|
|
416
|
+
}
|
|
417
|
+
const rawTokens = loadRawTokens();
|
|
418
|
+
if (!rawTokens) {
|
|
419
|
+
cachedLegacyTokens = [];
|
|
420
|
+
return cachedLegacyTokens;
|
|
421
|
+
}
|
|
422
|
+
cachedLegacyTokens = parseDTCGTokens(rawTokens);
|
|
423
|
+
return cachedLegacyTokens;
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Get tokens filtered by category (legacy format)
|
|
427
|
+
*/
|
|
428
|
+
export function getTokensByCategory(category) {
|
|
429
|
+
const tokens = getAllTokens();
|
|
430
|
+
return tokens.filter((t) => t.category.toLowerCase() === category.toLowerCase());
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* Search tokens by name or value (legacy format)
|
|
434
|
+
*/
|
|
435
|
+
export function searchTokens(query) {
|
|
436
|
+
const tokens = getAllTokens();
|
|
437
|
+
const lowerQuery = query.toLowerCase();
|
|
438
|
+
return tokens.filter((t) => t.name.toLowerCase().includes(lowerQuery) ||
|
|
439
|
+
t.value.toLowerCase().includes(lowerQuery) ||
|
|
440
|
+
t.description?.toLowerCase().includes(lowerQuery));
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* Get available token categories (legacy format)
|
|
444
|
+
*/
|
|
445
|
+
export function getTokenCategories() {
|
|
446
|
+
const tokens = getAllTokens();
|
|
447
|
+
const categories = new Set(tokens.map((t) => t.category));
|
|
448
|
+
return Array.from(categories).sort();
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Clear all cached tokens (useful for testing)
|
|
452
|
+
*/
|
|
453
|
+
export function clearTokenCache() {
|
|
454
|
+
cachedLegacyTokens = null;
|
|
455
|
+
cachedCSSTokens = null;
|
|
456
|
+
cachedTokenGraph = null;
|
|
457
|
+
cachedRawTokens = null;
|
|
458
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NYSDS Mode Prompt
|
|
3
|
+
*
|
|
4
|
+
* Activates NYSDS-aware coding assistance.
|
|
5
|
+
*/
|
|
6
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
7
|
+
export declare function registerPrompts(server: McpServer): void;
|
|
8
|
+
//# sourceMappingURL=nysds-mode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nysds-mode.d.ts","sourceRoot":"","sources":["../../src/prompts/nysds-mode.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAkDvD"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NYSDS Mode Prompt
|
|
3
|
+
*
|
|
4
|
+
* Activates NYSDS-aware coding assistance.
|
|
5
|
+
*/
|
|
6
|
+
export function registerPrompts(server) {
|
|
7
|
+
server.prompt("nysds_mode", "Activates NYSDS-aware coding assistance with knowledge of components, tokens, and best practices", {}, async () => {
|
|
8
|
+
return {
|
|
9
|
+
messages: [
|
|
10
|
+
{
|
|
11
|
+
role: "user",
|
|
12
|
+
content: {
|
|
13
|
+
type: "text",
|
|
14
|
+
text: `You are now in NYSDS (New York State Design System) mode. You have access to comprehensive knowledge about NYSDS web components and design tokens.
|
|
15
|
+
|
|
16
|
+
## Your Capabilities
|
|
17
|
+
|
|
18
|
+
1. **Component Knowledge**: You can list, search, and provide detailed documentation for all NYSDS web components using the available tools.
|
|
19
|
+
|
|
20
|
+
2. **Design Tokens**: You can access and explain NYSDS design tokens for colors, spacing, typography, and more.
|
|
21
|
+
|
|
22
|
+
3. **Code Generation**: When generating code that uses UI components, prefer NYSDS components over generic HTML or other libraries.
|
|
23
|
+
|
|
24
|
+
4. **Validation**: You can validate component usage to ensure correct attribute and property usage.
|
|
25
|
+
|
|
26
|
+
5. **Framework Integration**: You can provide setup guides for various frameworks (React, Angular, Vue, .NET, Drupal).
|
|
27
|
+
|
|
28
|
+
## Best Practices
|
|
29
|
+
|
|
30
|
+
- Always use semantic NYSDS components (e.g., \`<nys-button>\` instead of \`<button>\`)
|
|
31
|
+
- Use NYSDS design tokens via CSS custom properties for consistent styling
|
|
32
|
+
- Follow accessibility guidelines built into NYSDS components
|
|
33
|
+
- Reference the official documentation at https://designsystem.ny.gov/
|
|
34
|
+
|
|
35
|
+
## Available Tools
|
|
36
|
+
|
|
37
|
+
- \`list_components\`: See all available components
|
|
38
|
+
- \`get_component_docs\`: Get detailed docs for a specific component
|
|
39
|
+
- \`find_components\`: Search for components by functionality
|
|
40
|
+
- \`get_design_tokens\`: Access design token values
|
|
41
|
+
- \`validate_component_api\`: Validate component usage
|
|
42
|
+
- \`setup_framework\`: Get framework-specific setup guides
|
|
43
|
+
- \`get_usage_guide\`: General installation and usage guide
|
|
44
|
+
|
|
45
|
+
When helping with UI development for New York State projects, prioritize NYSDS components and patterns.`,
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component Resources
|
|
3
|
+
*
|
|
4
|
+
* MCP resources for NYSDS component documentation.
|
|
5
|
+
*
|
|
6
|
+
* P0 Resources:
|
|
7
|
+
* - nysds://components - Component overview list
|
|
8
|
+
* - nysds://component/{tag} - Individual component docs
|
|
9
|
+
*/
|
|
10
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
11
|
+
export declare function registerComponentResources(server: McpServer): void;
|
|
12
|
+
//# sourceMappingURL=components.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"components.d.ts","sourceRoot":"","sources":["../../src/resources/components.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGzE,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAiElE"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component Resources
|
|
3
|
+
*
|
|
4
|
+
* MCP resources for NYSDS component documentation.
|
|
5
|
+
*
|
|
6
|
+
* P0 Resources:
|
|
7
|
+
* - nysds://components - Component overview list
|
|
8
|
+
* - nysds://component/{tag} - Individual component docs
|
|
9
|
+
*/
|
|
10
|
+
import { getAllComponents, getComponent } from "../lib/cem-parser.js";
|
|
11
|
+
export function registerComponentResources(server) {
|
|
12
|
+
// nysds://components - Component overview list
|
|
13
|
+
server.resource("components", "nysds://components", {
|
|
14
|
+
description: "List of all NYSDS web components with summaries",
|
|
15
|
+
mimeType: "application/json",
|
|
16
|
+
}, async () => {
|
|
17
|
+
const components = getAllComponents();
|
|
18
|
+
const list = components.map((c) => ({
|
|
19
|
+
tagName: c.tagName,
|
|
20
|
+
name: c.name,
|
|
21
|
+
summary: c.summary || c.description?.split("\n")[0] || "No description",
|
|
22
|
+
}));
|
|
23
|
+
return {
|
|
24
|
+
contents: [
|
|
25
|
+
{
|
|
26
|
+
uri: "nysds://components",
|
|
27
|
+
mimeType: "application/json",
|
|
28
|
+
text: JSON.stringify(list, null, 2),
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
};
|
|
32
|
+
});
|
|
33
|
+
// nysds://component/{tag} - Individual component docs
|
|
34
|
+
server.resource("component", "nysds://component/{tag}", {
|
|
35
|
+
description: "Full documentation for a specific NYSDS component",
|
|
36
|
+
mimeType: "application/json",
|
|
37
|
+
}, async (uri) => {
|
|
38
|
+
// Extract tag from URI: nysds://component/nys-button -> nys-button
|
|
39
|
+
const tag = uri.pathname.split("/").pop() || "";
|
|
40
|
+
const component = getComponent(tag);
|
|
41
|
+
if (!component) {
|
|
42
|
+
return {
|
|
43
|
+
contents: [
|
|
44
|
+
{
|
|
45
|
+
uri: uri.href,
|
|
46
|
+
mimeType: "text/plain",
|
|
47
|
+
text: `Component "${tag}" not found`,
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
contents: [
|
|
54
|
+
{
|
|
55
|
+
uri: uri.href,
|
|
56
|
+
mimeType: "application/json",
|
|
57
|
+
text: JSON.stringify(component, null, 2),
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
};
|
|
61
|
+
});
|
|
62
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Guide Resources
|
|
3
|
+
*
|
|
4
|
+
* MCP resources for NYSDS installation and usage guides.
|
|
5
|
+
*
|
|
6
|
+
* P0 Resources:
|
|
7
|
+
* - nysds://installation - Installation guide
|
|
8
|
+
*/
|
|
9
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
10
|
+
export declare function registerGuideResources(server: McpServer): void;
|
|
11
|
+
//# sourceMappingURL=guides.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guides.d.ts","sourceRoot":"","sources":["../../src/resources/guides.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA6E9D"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Guide Resources
|
|
3
|
+
*
|
|
4
|
+
* MCP resources for NYSDS installation and usage guides.
|
|
5
|
+
*
|
|
6
|
+
* P0 Resources:
|
|
7
|
+
* - nysds://installation - Installation guide
|
|
8
|
+
*/
|
|
9
|
+
export function registerGuideResources(server) {
|
|
10
|
+
// nysds://installation - Installation guide
|
|
11
|
+
server.resource("installation", "nysds://installation", {
|
|
12
|
+
description: "NYSDS installation and setup guide",
|
|
13
|
+
mimeType: "text/markdown",
|
|
14
|
+
}, async () => {
|
|
15
|
+
const guide = `# NYSDS Installation Guide
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
Install the NYSDS components package:
|
|
20
|
+
|
|
21
|
+
\`\`\`bash
|
|
22
|
+
npm install @nysds/components
|
|
23
|
+
\`\`\`
|
|
24
|
+
|
|
25
|
+
## Import Components
|
|
26
|
+
|
|
27
|
+
### Option 1: Import All Components
|
|
28
|
+
|
|
29
|
+
\`\`\`javascript
|
|
30
|
+
import '@nysds/components';
|
|
31
|
+
\`\`\`
|
|
32
|
+
|
|
33
|
+
### Option 2: Import Individual Components
|
|
34
|
+
|
|
35
|
+
\`\`\`javascript
|
|
36
|
+
import '@nysds/components/nys-button';
|
|
37
|
+
import '@nysds/components/nys-alert';
|
|
38
|
+
\`\`\`
|
|
39
|
+
|
|
40
|
+
## Include Styles
|
|
41
|
+
|
|
42
|
+
Import the base CSS for design tokens:
|
|
43
|
+
|
|
44
|
+
\`\`\`css
|
|
45
|
+
@import '@nysds/components/dist/styles.css';
|
|
46
|
+
\`\`\`
|
|
47
|
+
|
|
48
|
+
## Usage
|
|
49
|
+
|
|
50
|
+
Once imported, use components as HTML elements:
|
|
51
|
+
|
|
52
|
+
\`\`\`html
|
|
53
|
+
<nys-button label="Submit" variant="primary"></nys-button>
|
|
54
|
+
<nys-alert type="success">Operation completed successfully!</nys-alert>
|
|
55
|
+
\`\`\`
|
|
56
|
+
|
|
57
|
+
## Framework Integration
|
|
58
|
+
|
|
59
|
+
For framework-specific setup (React, Angular, Vue, etc.), use the \`setup_framework\` tool.
|
|
60
|
+
|
|
61
|
+
## Browser Support
|
|
62
|
+
|
|
63
|
+
NYSDS components support all modern browsers (Chrome, Firefox, Safari, Edge).
|
|
64
|
+
|
|
65
|
+
## Resources
|
|
66
|
+
|
|
67
|
+
- Documentation: https://designsystem.ny.gov/
|
|
68
|
+
- GitHub: https://github.com/ITS-HCD/nysds
|
|
69
|
+
`;
|
|
70
|
+
return {
|
|
71
|
+
contents: [
|
|
72
|
+
{
|
|
73
|
+
uri: "nysds://installation",
|
|
74
|
+
mimeType: "text/markdown",
|
|
75
|
+
text: guide,
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
};
|
|
79
|
+
});
|
|
80
|
+
}
|