@santi020k/lumen-mcp 0.3.0 → 1.0.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/bin/lumen-mcp-http.mjs +1 -1
- package/bin/lumen-mcp-local.mjs +5 -7
- package/bin/lumen-mcp.mjs +1 -1
- package/data/lumen-data.json +17741 -10805
- package/dist/data.d.ts +1 -0
- package/dist/data.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +23 -22
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +124 -73
- package/package.json +3 -3
package/dist/data.d.ts
CHANGED
package/dist/data.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data.d.ts","sourceRoot":"","sources":["../src/data.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"data.d.ts","sourceRoot":"","sources":["../src/data.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Server as HttpServer } from 'node:http';
|
|
2
|
-
export { loadLumenData } from './data.js';
|
|
3
2
|
export type { LumenData } from './data.js';
|
|
3
|
+
export { loadLumenData } from './data.js';
|
|
4
4
|
export { createLumenServer } from './server.js';
|
|
5
5
|
export * from './tools.js';
|
|
6
6
|
/** Start the Lumen MCP server over stdio. Called by the `lumen-mcp` bin. */
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,WAAW,CAAA;AAYrD,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,WAAW,CAAA;AAYrD,YAAY,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAC/C,cAAc,YAAY,CAAA;AAE1B,4EAA4E;AAC5E,eAAO,MAAM,aAAa,QAAa,OAAO,CAAC,IAAI,CAKlD,CAAA;AAED,MAAM,WAAW,mBAAmB;IAClC,YAAY,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAA;IACnC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC7B,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACzB,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAC1B;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1B,UAAU,EAAE,UAAU,CAAA;IACtB,GAAG,EAAE,GAAG,CAAA;CACT;AAmDD,wFAAwF;AACxF,eAAO,MAAM,iBAAiB,GAC5B,UAAS,mBAAwB,KAChC,OAAO,CAAC,kBAAkB,CA+F5B,CAAA"}
|
package/dist/index.js
CHANGED
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAoB,MAAM,yCAAyC,CAAA;AA2JrF,eAAO,MAAM,iBAAiB,QAAO,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAoB,MAAM,yCAAyC,CAAA;AA2JrF,eAAO,MAAM,iBAAiB,QAAO,SAmQpC,CAAA"}
|
package/dist/server.js
CHANGED
|
@@ -46,6 +46,7 @@ const searchOutputSchema = z.strictObject({
|
|
|
46
46
|
});
|
|
47
47
|
const tokensOutputSchema = z.strictObject({
|
|
48
48
|
tokens: z.strictObject({
|
|
49
|
+
chart: z.record(z.string(), z.string().trim()),
|
|
49
50
|
colors: z.record(z.string(), z.string().trim()),
|
|
50
51
|
glass: z.record(z.string(), z.string().trim()),
|
|
51
52
|
semantic: z.array(z.string().trim()),
|
|
@@ -101,9 +102,9 @@ const diagnosticsOutputSchema = z.strictObject({
|
|
|
101
102
|
}),
|
|
102
103
|
status: z.enum(['healthy', 'issues'])
|
|
103
104
|
});
|
|
104
|
-
const structuredData = (data) => typeof data === 'object' && data !== null
|
|
105
|
-
|
|
106
|
-
|
|
105
|
+
const structuredData = (data) => typeof data === 'object' && data !== null ?
|
|
106
|
+
data :
|
|
107
|
+
{ value: data };
|
|
107
108
|
const toMcpResult = (result) => ({
|
|
108
109
|
content: [{ text: result.text, type: 'text' }],
|
|
109
110
|
isError: result.isError ?? false,
|
|
@@ -138,7 +139,7 @@ export const createLumenServer = () => {
|
|
|
138
139
|
.meta({ description: 'Only list components that belong to this recipe.' })
|
|
139
140
|
}),
|
|
140
141
|
outputSchema: listComponentsOutputSchema
|
|
141
|
-
},
|
|
142
|
+
}, args => toMcpResult(listComponents(args)));
|
|
142
143
|
server.registerTool('lumen_get_component', {
|
|
143
144
|
annotations: readOnlyAnnotations,
|
|
144
145
|
description: 'Get framework-specific Lumen component usage: description, imports, styles, typed props or ' +
|
|
@@ -156,7 +157,7 @@ export const createLumenServer = () => {
|
|
|
156
157
|
.meta({ description: 'Component name, for example "Button" or "data-table".' })
|
|
157
158
|
}),
|
|
158
159
|
outputSchema: componentOutputSchema
|
|
159
|
-
},
|
|
160
|
+
}, args => toMcpResult(getComponent(args)));
|
|
160
161
|
server.registerTool('lumen_get_recipe', {
|
|
161
162
|
annotations: readOnlyAnnotations,
|
|
162
163
|
description: 'Get a Lumen recipe or component set with its purpose, categories, components, files, and ' +
|
|
@@ -169,7 +170,7 @@ export const createLumenServer = () => {
|
|
|
169
170
|
.meta({ description: 'Recipe name, for example "scheduler" or "advanced-fields".' })
|
|
170
171
|
}),
|
|
171
172
|
outputSchema: recipeOutputSchema
|
|
172
|
-
},
|
|
173
|
+
}, args => toMcpResult(getRecipe(args)));
|
|
173
174
|
server.registerTool('lumen_search', {
|
|
174
175
|
annotations: readOnlyAnnotations,
|
|
175
176
|
description: 'Rank natural-language matches across descriptions, categories, curated collections, ' +
|
|
@@ -185,7 +186,7 @@ export const createLumenServer = () => {
|
|
|
185
186
|
.meta({ description: 'Keyword or natural-language use-case to search for.' })
|
|
186
187
|
}),
|
|
187
188
|
outputSchema: searchOutputSchema
|
|
188
|
-
},
|
|
189
|
+
}, args => toMcpResult(search(args)));
|
|
189
190
|
server.registerTool('lumen_get_meta', {
|
|
190
191
|
annotations: readOnlyAnnotations,
|
|
191
192
|
description: 'Return snapshot provenance: server and package versions, schema version, component count, ' +
|
|
@@ -210,7 +211,7 @@ export const createLumenServer = () => {
|
|
|
210
211
|
.meta({ description: 'Optional previous catalog hash for a fast unchanged check.' })
|
|
211
212
|
}),
|
|
212
213
|
outputSchema: catalogDiffOutputSchema
|
|
213
|
-
},
|
|
214
|
+
}, args => toMcpResult(diffCatalog(args)));
|
|
214
215
|
server.registerTool('lumen_diagnose', {
|
|
215
216
|
annotations: readOnlyAnnotations,
|
|
216
217
|
description: 'Run deterministic snapshot integrity checks and report framework coverage. Useful when testing a new MCP connection.',
|
|
@@ -232,19 +233,19 @@ export const createLumenServer = () => {
|
|
|
232
233
|
server.registerResource('lumen-meta', 'lumen://meta', {
|
|
233
234
|
description: 'Lumen MCP snapshot provenance and package versions.',
|
|
234
235
|
mimeType: 'application/json'
|
|
235
|
-
},
|
|
236
|
+
}, uri => jsonResource(uri, getMeta().data));
|
|
236
237
|
server.registerResource('lumen-catalog-manifest', 'lumen://catalog-manifest', {
|
|
237
238
|
description: 'Stable component and recipe fingerprints for catalog change detection.',
|
|
238
239
|
mimeType: 'application/json'
|
|
239
|
-
},
|
|
240
|
+
}, uri => jsonResource(uri, getCatalogManifest().data));
|
|
240
241
|
server.registerResource('lumen-diagnostics', 'lumen://diagnostics', {
|
|
241
242
|
description: 'Lumen MCP snapshot integrity checks and framework coverage.',
|
|
242
243
|
mimeType: 'application/json'
|
|
243
|
-
},
|
|
244
|
+
}, uri => jsonResource(uri, diagnose().data));
|
|
244
245
|
server.registerResource('lumen-rules', 'lumen://rules', {
|
|
245
246
|
description: 'Lumen agent rules (llms.txt).',
|
|
246
247
|
mimeType: 'text/markdown'
|
|
247
|
-
},
|
|
248
|
+
}, uri => ({
|
|
248
249
|
contents: [{
|
|
249
250
|
mimeType: 'text/markdown',
|
|
250
251
|
text: getRules().text,
|
|
@@ -254,20 +255,20 @@ export const createLumenServer = () => {
|
|
|
254
255
|
server.registerResource('lumen-tokens', 'lumen://tokens', {
|
|
255
256
|
description: 'Structured Lumen design tokens.',
|
|
256
257
|
mimeType: 'application/json'
|
|
257
|
-
},
|
|
258
|
+
}, uri => jsonResource(uri, getTokens().data));
|
|
258
259
|
server.registerResource('lumen-components', 'lumen://components', {
|
|
259
260
|
description: 'Compact structured component catalog.',
|
|
260
261
|
mimeType: 'application/json'
|
|
261
|
-
},
|
|
262
|
+
}, uri => jsonResource(uri, listComponents().data));
|
|
262
263
|
server.registerResource('lumen-component', new ResourceTemplate('lumen://components/{name}', {
|
|
263
264
|
complete: {
|
|
264
|
-
name:
|
|
265
|
-
.map(
|
|
266
|
-
.filter(
|
|
265
|
+
name: value => data.components
|
|
266
|
+
.map(component => component.name)
|
|
267
|
+
.filter(name => name.toLowerCase().includes(value.toLowerCase()))
|
|
267
268
|
.slice(0, 30)
|
|
268
269
|
},
|
|
269
270
|
list: () => ({
|
|
270
|
-
resources: data.components.map(
|
|
271
|
+
resources: data.components.map(component => ({
|
|
271
272
|
description: component.description,
|
|
272
273
|
mimeType: 'application/json',
|
|
273
274
|
name: component.name,
|
|
@@ -284,12 +285,12 @@ export const createLumenServer = () => {
|
|
|
284
285
|
});
|
|
285
286
|
server.registerResource('lumen-recipe', new ResourceTemplate('lumen://recipes/{name}', {
|
|
286
287
|
complete: {
|
|
287
|
-
name:
|
|
288
|
-
.map(
|
|
289
|
-
.filter(
|
|
288
|
+
name: value => data.recipes
|
|
289
|
+
.map(recipe => recipe.name)
|
|
290
|
+
.filter(name => name.includes(value.toLowerCase()))
|
|
290
291
|
},
|
|
291
292
|
list: () => ({
|
|
292
|
-
resources: data.recipes.map(
|
|
293
|
+
resources: data.recipes.map(recipe => ({
|
|
293
294
|
description: recipe.description,
|
|
294
295
|
mimeType: 'application/json',
|
|
295
296
|
name: recipe.name,
|
package/dist/tools.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,oBAAoB,EACpB,sBAAsB,EACtB,SAAS,EACT,cAAc,EAEd,mBAAmB,EACpB,MAAM,WAAW,CAAA;AAGlB,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,SAAS,EAAE,MAAM,EAAE,CAAA;CACpB;AACD,MAAM,MAAM,oBAAoB,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,CAAA;AAEjE,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,cAAc,EAAE,CAAA;IAC5B,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,EAAE,CAAA;CAClB;AAED,MAAM,MAAM,eAAe,GAAG,cAAc,CAAA;AAE5C,MAAM,WAAW,eAAe,CAAC,IAAI,GAAG,OAAO;IAC7C,IAAI,EAAE,IAAI,CAAA;IACV,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,CAAC,EAAE,cAAc,EAAE,CAAA;IAC7B,IAAI,EAAE,WAAW,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAA;IAC/C,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;CACd;
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
|
package/dist/tools.js
CHANGED
|
@@ -1,21 +1,44 @@
|
|
|
1
1
|
import { loadLumenData } from './data.js';
|
|
2
|
-
const normalize = (value) => value
|
|
3
|
-
|
|
2
|
+
const normalize = (value) => value
|
|
3
|
+
.replaceAll(/([a-z0-9])([A-Z])/g, '$1-$2')
|
|
4
|
+
.replaceAll(/[\s_]+/g, '-')
|
|
5
|
+
.toLowerCase();
|
|
6
|
+
const tokenize = (value) => normalize(value)
|
|
7
|
+
.split(/[^a-z0-9]+/)
|
|
8
|
+
.filter(Boolean);
|
|
4
9
|
const searchStopWords = new Set([
|
|
5
|
-
'a',
|
|
6
|
-
'
|
|
10
|
+
'a',
|
|
11
|
+
'accessibility',
|
|
12
|
+
'accessible',
|
|
13
|
+
'admin',
|
|
14
|
+
'an',
|
|
15
|
+
'and',
|
|
16
|
+
'app',
|
|
17
|
+
'application',
|
|
18
|
+
'component',
|
|
19
|
+
'for',
|
|
20
|
+
'in',
|
|
21
|
+
'lumen',
|
|
22
|
+
'not',
|
|
23
|
+
'of',
|
|
24
|
+
'or',
|
|
25
|
+
'the',
|
|
26
|
+
'to',
|
|
27
|
+
'ui',
|
|
28
|
+
'with'
|
|
7
29
|
]);
|
|
8
30
|
const searchTermAliases = {
|
|
9
31
|
booking: ['booking', 'schedule', 'calendar', 'appointment', 'date'],
|
|
10
32
|
dark: ['dark', 'theme'],
|
|
11
33
|
dashboard: ['dashboard', 'data-table', 'sidebar', 'chart', 'stat', 'metric'],
|
|
12
34
|
mode: ['mode', 'theme'],
|
|
35
|
+
paginated: ['paginated', 'pagination'],
|
|
13
36
|
pagination: ['pagination', 'paginated'],
|
|
14
37
|
sortable: ['sortable', 'sort']
|
|
15
38
|
};
|
|
16
39
|
const meaningfulSearchTerms = (value) => {
|
|
17
40
|
const terms = tokenize(value);
|
|
18
|
-
const meaningful = terms.filter(
|
|
41
|
+
const meaningful = terms.filter(term => !searchStopWords.has(term));
|
|
19
42
|
return meaningful.length > 0 ? meaningful : terms;
|
|
20
43
|
};
|
|
21
44
|
const availableFrameworks = (component) => Object.entries(component.frameworks)
|
|
@@ -28,17 +51,17 @@ const componentSummary = (component) => ({
|
|
|
28
51
|
frameworks: availableFrameworks(component),
|
|
29
52
|
kebab: component.kebab,
|
|
30
53
|
name: component.name,
|
|
31
|
-
recipes: component.recipes.map(
|
|
54
|
+
recipes: component.recipes.map(recipe => recipe.name)
|
|
32
55
|
});
|
|
33
56
|
export const resolveComponent = (name, data = loadLumenData()) => {
|
|
34
57
|
const target = normalize(name);
|
|
35
|
-
return data.components.find(
|
|
36
|
-
data.components.find(
|
|
37
|
-
data.components.find(
|
|
58
|
+
return (data.components.find(component => component.name === name) ??
|
|
59
|
+
data.components.find(component => component.kebab === target) ??
|
|
60
|
+
data.components.find(component => normalize(component.name) === target));
|
|
38
61
|
};
|
|
39
62
|
export const resolveRecipe = (name, data = loadLumenData()) => {
|
|
40
63
|
const target = normalize(name);
|
|
41
|
-
return data.recipes.find(
|
|
64
|
+
return data.recipes.find(recipe => normalize(recipe.name) === target);
|
|
42
65
|
};
|
|
43
66
|
const frameworkBehaviorSearchText = (behavior) => [
|
|
44
67
|
behavior?.description ?? '',
|
|
@@ -51,13 +74,13 @@ const frameworkDetailsSearchText = (framework) => [
|
|
|
51
74
|
...frameworkBehaviorSearchText(framework.behavior),
|
|
52
75
|
framework.example,
|
|
53
76
|
framework.propsExtends ?? '',
|
|
54
|
-
framework.props.map(
|
|
77
|
+
framework.props.map(prop => `${prop.name} ${prop.type}`).join(' '),
|
|
55
78
|
framework.attributes?.join(' ') ?? '',
|
|
56
79
|
framework.tagName ?? ''
|
|
57
80
|
];
|
|
58
|
-
const frameworkSearchText = (component, framework) => (framework
|
|
59
|
-
|
|
60
|
-
|
|
81
|
+
const frameworkSearchText = (component, framework) => (framework ?
|
|
82
|
+
[Reflect.get(component.frameworkDetails, framework)] :
|
|
83
|
+
Object.values(component.frameworkDetails))
|
|
61
84
|
.flatMap(frameworkDetailsSearchText)
|
|
62
85
|
.join(' ');
|
|
63
86
|
const componentSearchText = (component, framework) => [
|
|
@@ -66,31 +89,32 @@ const componentSearchText = (component, framework) => [
|
|
|
66
89
|
component.description,
|
|
67
90
|
component.category,
|
|
68
91
|
component.collections.join(' '),
|
|
69
|
-
component.recipes.map(
|
|
92
|
+
component.recipes.map(recipe => recipe.name).join(' '),
|
|
70
93
|
component.keywords.join(' '),
|
|
71
94
|
component.dependencies.join(' '),
|
|
72
95
|
component.guidance?.when ?? '',
|
|
73
96
|
component.guidance?.distinction ?? '',
|
|
74
97
|
component.apiReference
|
|
75
|
-
.map(
|
|
98
|
+
.map(row => `${row.attribute} ${row.values} ${row.description}`)
|
|
76
99
|
.join(' '),
|
|
77
100
|
frameworkSearchText(component, framework)
|
|
78
101
|
].join(' ');
|
|
79
102
|
const scoreCandidate = (query, terms, searchableText, primaryName = '') => {
|
|
80
103
|
const normalizedText = normalize(searchableText);
|
|
81
|
-
const matchedTerms = terms.filter(
|
|
104
|
+
const matchedTerms = terms.filter(term => (Reflect.get(searchTermAliases, term) ?? [term]).some(candidate => normalizedText.includes(candidate)));
|
|
82
105
|
if (matchedTerms.length === 0)
|
|
83
106
|
return { matchedTerms, score: 0 };
|
|
84
107
|
const normalizedQuery = terms.join('-');
|
|
85
108
|
const normalizedName = normalize(primaryName);
|
|
86
109
|
const coverage = matchedTerms.length / terms.length;
|
|
87
|
-
let score = matchedTerms.reduce((total, term) => total +
|
|
88
|
-
?
|
|
89
|
-
|
|
110
|
+
let score = matchedTerms.reduce((total, term) => total +
|
|
111
|
+
((Reflect.get(searchTermAliases, term) ?? [term]).some(candidate => normalizedName.includes(candidate)) ?
|
|
112
|
+
20 :
|
|
113
|
+
5), 0);
|
|
90
114
|
score += Math.round(coverage * 80);
|
|
91
115
|
score -= (terms.length - matchedTerms.length) * 3;
|
|
92
|
-
if (terms.includes(normalizedName))
|
|
93
|
-
score +=
|
|
116
|
+
if (terms.some(term => (Reflect.get(searchTermAliases, term) ?? [term]).includes(normalizedName)))
|
|
117
|
+
score += 150;
|
|
94
118
|
if (normalizedText.includes(normalizedQuery))
|
|
95
119
|
score += 100;
|
|
96
120
|
if (normalizedName === normalizedQuery)
|
|
@@ -130,7 +154,7 @@ const collectSearchResults = (query, terms, data, framework) => {
|
|
|
130
154
|
name: token
|
|
131
155
|
}, query, terms, token);
|
|
132
156
|
}
|
|
133
|
-
for (const line of data.rules.split('\n').filter(
|
|
157
|
+
for (const line of data.rules.split('\n').filter(rule => rule.trim())) {
|
|
134
158
|
appendSearchResult(results, {
|
|
135
159
|
description: line.trim(),
|
|
136
160
|
kind: 'rule',
|
|
@@ -144,11 +168,11 @@ export const listComponents = (args = {}, data = loadLumenData()) => {
|
|
|
144
168
|
const queryTerms = query ? meaningfulSearchTerms(query) : [];
|
|
145
169
|
const recipe = args.recipe ? resolveRecipe(args.recipe, data) : undefined;
|
|
146
170
|
const recipeName = recipe?.name ?? (args.recipe ? normalize(args.recipe) : undefined);
|
|
147
|
-
const matches = data.components.filter(
|
|
171
|
+
const matches = data.components.filter(component => {
|
|
148
172
|
if (args.framework && !component.frameworks[args.framework])
|
|
149
173
|
return false;
|
|
150
174
|
if (recipeName &&
|
|
151
|
-
!component.recipes.some(
|
|
175
|
+
!component.recipes.some(componentRecipe => normalize(componentRecipe.name) === recipeName))
|
|
152
176
|
return false;
|
|
153
177
|
if (query &&
|
|
154
178
|
scoreCandidate(query, queryTerms, componentSearchText(component, args.framework), component.name).score === 0)
|
|
@@ -162,10 +186,10 @@ export const listComponents = (args = {}, data = loadLumenData()) => {
|
|
|
162
186
|
text: 'No components matched the given filters.'
|
|
163
187
|
};
|
|
164
188
|
}
|
|
165
|
-
const lines = summaries.map(
|
|
166
|
-
const recipeNote = component.recipes.length > 0
|
|
167
|
-
|
|
168
|
-
|
|
189
|
+
const lines = summaries.map(component => {
|
|
190
|
+
const recipeNote = component.recipes.length > 0 ?
|
|
191
|
+
` [recipes: ${component.recipes.join(', ')}]` :
|
|
192
|
+
'';
|
|
169
193
|
return `${component.name} (${component.kebab}) — ${component.description} — ${component.frameworks.join(', ')}${recipeNote}`;
|
|
170
194
|
});
|
|
171
195
|
return {
|
|
@@ -216,23 +240,23 @@ const componentDetail = (component, framework, detail) => {
|
|
|
216
240
|
keyboardInteractions: component.keyboardInteractions,
|
|
217
241
|
runtimeEvents: component.runtimeEvents
|
|
218
242
|
};
|
|
219
|
-
return detail === 'source'
|
|
220
|
-
|
|
221
|
-
|
|
243
|
+
return detail === 'source' ?
|
|
244
|
+
{ ...usage, framework: selectedFramework } :
|
|
245
|
+
usage;
|
|
222
246
|
};
|
|
223
247
|
const formatProps = (framework) => {
|
|
224
248
|
if (framework.attributes && framework.attributes.length > 0) {
|
|
225
|
-
return `Attributes:\n${framework.attributes.map(
|
|
249
|
+
return `Attributes:\n${framework.attributes.map(attribute => `- ${attribute}`).join('\n')}`;
|
|
226
250
|
}
|
|
227
251
|
if (framework.props.length === 0) {
|
|
228
|
-
return framework.propsExtends
|
|
229
|
-
|
|
230
|
-
|
|
252
|
+
return framework.propsExtends ?
|
|
253
|
+
`Props extend ${framework.propsExtends}; no additional local props were detected.` :
|
|
254
|
+
'No typed props detected.';
|
|
231
255
|
}
|
|
232
|
-
const lines = framework.props.map(
|
|
233
|
-
const header = framework.propsExtends
|
|
234
|
-
|
|
235
|
-
|
|
256
|
+
const lines = framework.props.map(prop => `- ${prop.name}${prop.optional ? '?' : ''}: ${prop.type}`);
|
|
257
|
+
const header = framework.propsExtends ?
|
|
258
|
+
`Props (extends ${framework.propsExtends}):` :
|
|
259
|
+
'Props:';
|
|
236
260
|
return `${header}\n${lines.join('\n')}`;
|
|
237
261
|
};
|
|
238
262
|
const buildSummarySections = (component, frameworkName, framework) => [
|
|
@@ -244,9 +268,9 @@ const buildSummarySections = (component, frameworkName, framework) => [
|
|
|
244
268
|
`Import: ${framework.importStatement}`,
|
|
245
269
|
`Styles: ${framework.styleImport}`,
|
|
246
270
|
framework.tagName ? `Custom element: <${framework.tagName}>` : '',
|
|
247
|
-
component.recipes.length > 0
|
|
248
|
-
|
|
249
|
-
|
|
271
|
+
component.recipes.length > 0 ?
|
|
272
|
+
`Recipes: ${component.recipes.map(recipe => recipe.name).join(', ')}` :
|
|
273
|
+
'Recipes: none'
|
|
250
274
|
].filter(Boolean);
|
|
251
275
|
const appendBehaviorSections = (sections, behavior) => {
|
|
252
276
|
if (!behavior)
|
|
@@ -257,10 +281,10 @@ const appendBehaviorSections = (sections, behavior) => {
|
|
|
257
281
|
if (behavior.description)
|
|
258
282
|
sections.push(behavior.description);
|
|
259
283
|
if (behavior.options && behavior.options.length > 0) {
|
|
260
|
-
sections.push('', 'Hook options:', ...behavior.options.map(
|
|
284
|
+
sections.push('', 'Hook options:', ...behavior.options.map(option => `- ${option.name}: ${option.type} — ${option.description}`));
|
|
261
285
|
}
|
|
262
286
|
if (behavior.controller && behavior.controller.length > 0) {
|
|
263
|
-
sections.push('', 'Controller values:', ...behavior.controller.map(
|
|
287
|
+
sections.push('', 'Controller values:', ...behavior.controller.map(value => `- ${value.name}: ${value.type} — ${value.description}`));
|
|
264
288
|
}
|
|
265
289
|
};
|
|
266
290
|
const appendGuidanceSections = (sections, component) => {
|
|
@@ -271,15 +295,15 @@ const appendGuidanceSections = (sections, component) => {
|
|
|
271
295
|
}
|
|
272
296
|
if (component.keyboardInteractions.length > 0) {
|
|
273
297
|
sections.push('', '## Keyboard interactions');
|
|
274
|
-
sections.push(...component.keyboardInteractions.map(
|
|
298
|
+
sections.push(...component.keyboardInteractions.map(interaction => `- ${interaction.key}: ${interaction.action}`));
|
|
275
299
|
}
|
|
276
300
|
if (component.apiReference.length > 0) {
|
|
277
301
|
sections.push('', '## API reference');
|
|
278
|
-
sections.push(...component.apiReference.map(
|
|
302
|
+
sections.push(...component.apiReference.map(row => `- \`${row.attribute}\` ${row.values} — ${row.description}`));
|
|
279
303
|
}
|
|
280
304
|
if (component.runtimeEvents.length > 0) {
|
|
281
305
|
sections.push('', '## Runtime events');
|
|
282
|
-
sections.push(...component.runtimeEvents.map(
|
|
306
|
+
sections.push(...component.runtimeEvents.map(event => `- ${event.name}: ${event.when}`));
|
|
283
307
|
}
|
|
284
308
|
};
|
|
285
309
|
const formatComponentUsage = (component, frameworkName, detail) => {
|
|
@@ -335,9 +359,11 @@ export const getRecipe = (args, data = loadLumenData()) => {
|
|
|
335
359
|
};
|
|
336
360
|
}
|
|
337
361
|
const framework = args.framework ?? 'astro';
|
|
338
|
-
const componentLines = (recipe.components ?? []).map(
|
|
362
|
+
const componentLines = (recipe.components ?? []).map(name => {
|
|
339
363
|
const component = resolveComponent(name, data);
|
|
340
|
-
return component ?
|
|
364
|
+
return component ?
|
|
365
|
+
`- ${component.name}: ${component.description}` :
|
|
366
|
+
`- ${name}`;
|
|
341
367
|
});
|
|
342
368
|
return {
|
|
343
369
|
data: { found: true, recipe },
|
|
@@ -382,7 +408,7 @@ export const search = (args, data = loadLumenData()) => {
|
|
|
382
408
|
}
|
|
383
409
|
return {
|
|
384
410
|
data: { query, results: shown, total: results.length },
|
|
385
|
-
text: `${results.length} match(es) for "${args.query}"${results.length > shown.length ? ` (showing ${shown.length})` : ''}:\n\n${shown.map(
|
|
411
|
+
text: `${results.length} match(es) for "${args.query}"${results.length > shown.length ? ` (showing ${shown.length})` : ''}:\n\n${shown.map(result => `${result.kind}: ${result.name} — ${result.description} [matched: ${result.matchedTerms.join(', ')}]`).join('\n')}`
|
|
386
412
|
};
|
|
387
413
|
};
|
|
388
414
|
export const getMeta = (data = loadLumenData()) => ({
|
|
@@ -402,12 +428,19 @@ const diffManifestSection = (current, baseline) => {
|
|
|
402
428
|
const currentNames = Object.keys(current);
|
|
403
429
|
const baselineNames = Object.keys(baseline);
|
|
404
430
|
return {
|
|
405
|
-
added: currentNames
|
|
431
|
+
added: currentNames
|
|
432
|
+
.filter(name => Reflect.get(baseline, name) === undefined)
|
|
433
|
+
.sort(),
|
|
406
434
|
changed: currentNames
|
|
407
|
-
.filter(
|
|
435
|
+
.filter(name => Reflect.get(baseline, name) !== undefined &&
|
|
436
|
+
Reflect.get(baseline, name) !== Reflect.get(current, name))
|
|
437
|
+
.sort(),
|
|
438
|
+
removed: baselineNames
|
|
439
|
+
.filter(name => Reflect.get(current, name) === undefined)
|
|
408
440
|
.sort(),
|
|
409
|
-
|
|
410
|
-
|
|
441
|
+
unchanged: currentNames
|
|
442
|
+
.filter(name => Reflect.get(baseline, name) === Reflect.get(current, name))
|
|
443
|
+
.sort()
|
|
411
444
|
};
|
|
412
445
|
};
|
|
413
446
|
export const getCatalogManifest = (data = loadLumenData()) => ({
|
|
@@ -446,23 +479,27 @@ export const diffCatalog = (args, data = loadLumenData()) => {
|
|
|
446
479
|
recipes,
|
|
447
480
|
unchanged
|
|
448
481
|
},
|
|
449
|
-
text: unchanged
|
|
450
|
-
|
|
451
|
-
|
|
482
|
+
text: unchanged ?
|
|
483
|
+
`The Lumen catalog is unchanged (${data.meta.catalogHash}).` :
|
|
484
|
+
[
|
|
452
485
|
'# Lumen catalog changes',
|
|
453
486
|
`Current catalog hash: ${data.meta.catalogHash}`,
|
|
454
487
|
`Changed entries: ${changedCount}`,
|
|
455
|
-
`Components — added: ${components.added.length}, changed: ${components.changed.length},
|
|
456
|
-
|
|
488
|
+
`Components — added: ${components.added.length}, changed: ${components.changed.length}, ` +
|
|
489
|
+
`removed: ${components.removed.length}`,
|
|
490
|
+
`Recipes — added: ${recipes.added.length}, changed: ${recipes.changed.length}, ` +
|
|
491
|
+
`removed: ${recipes.removed.length}`
|
|
457
492
|
].join('\n')
|
|
458
493
|
};
|
|
459
494
|
};
|
|
460
495
|
export const diagnose = (data = loadLumenData()) => {
|
|
461
|
-
const componentNames = data.components.map(
|
|
496
|
+
const componentNames = data.components.map(component => component.name);
|
|
462
497
|
const frameworkCoverage = {
|
|
463
|
-
astro: data.components.filter(
|
|
464
|
-
|
|
465
|
-
|
|
498
|
+
astro: data.components.filter(component => component.frameworks.astro)
|
|
499
|
+
.length,
|
|
500
|
+
elements: data.components.filter(component => component.frameworks.elements).length,
|
|
501
|
+
react: data.components.filter(component => component.frameworks.react)
|
|
502
|
+
.length
|
|
466
503
|
};
|
|
467
504
|
const checks = [
|
|
468
505
|
{
|
|
@@ -473,39 +510,50 @@ export const diagnose = (data = loadLumenData()) => {
|
|
|
473
510
|
{
|
|
474
511
|
message: 'Component names are unique.',
|
|
475
512
|
name: 'unique-components',
|
|
476
|
-
status: new Set(componentNames).size === componentNames.length ?
|
|
513
|
+
status: new Set(componentNames).size === componentNames.length ?
|
|
514
|
+
'pass' :
|
|
515
|
+
'fail'
|
|
477
516
|
},
|
|
478
517
|
{
|
|
479
518
|
message: 'Every component has a manifest fingerprint.',
|
|
480
519
|
name: 'component-manifest',
|
|
481
|
-
status: componentNames.every(
|
|
520
|
+
status: componentNames.every(name => Reflect.get(data.catalogManifest.components, name)) ?
|
|
521
|
+
'pass' :
|
|
522
|
+
'fail'
|
|
482
523
|
},
|
|
483
524
|
{
|
|
484
525
|
message: 'Every available framework contract has an example and import statement.',
|
|
485
526
|
name: 'framework-contracts',
|
|
486
|
-
status: data.components.every(
|
|
527
|
+
status: data.components.every(component => Object.entries(component.frameworks).every(([framework, available]) => {
|
|
487
528
|
if (!available)
|
|
488
529
|
return true;
|
|
489
530
|
const details = Reflect.get(component.frameworkDetails, framework);
|
|
490
|
-
return Boolean(details?.example.trim()) &&
|
|
491
|
-
|
|
531
|
+
return (Boolean(details?.example.trim()) &&
|
|
532
|
+
Boolean(details?.importStatement.trim()));
|
|
533
|
+
})) ?
|
|
534
|
+
'pass' :
|
|
535
|
+
'fail'
|
|
492
536
|
}
|
|
493
537
|
];
|
|
494
|
-
const status = checks.every(
|
|
538
|
+
const status = checks.every(check => check.status === 'pass') ?
|
|
539
|
+
'healthy' :
|
|
540
|
+
'issues';
|
|
495
541
|
return {
|
|
496
542
|
data: { checks, frameworkCoverage, status },
|
|
497
543
|
isError: status === 'issues',
|
|
498
544
|
text: [
|
|
499
545
|
`# Lumen MCP diagnostics: ${status}`,
|
|
500
546
|
`Catalog hash: ${data.meta.catalogHash}`,
|
|
501
|
-
`Framework coverage — Astro: ${frameworkCoverage.astro},
|
|
547
|
+
`Framework coverage — Astro: ${frameworkCoverage.astro}, ` +
|
|
548
|
+
`React: ${frameworkCoverage.react}, Elements: ${frameworkCoverage.elements}`,
|
|
502
549
|
'',
|
|
503
|
-
...checks.map(
|
|
550
|
+
...checks.map(check => `- ${check.status.toUpperCase()} ${check.name}: ${check.message}`)
|
|
504
551
|
].join('\n')
|
|
505
552
|
};
|
|
506
553
|
};
|
|
507
554
|
export const getTokens = (data = loadLumenData()) => {
|
|
508
555
|
const { tokens } = data;
|
|
556
|
+
const chartLines = Object.entries(tokens.chart).map(([name, value]) => `- ${name}: ${value}`);
|
|
509
557
|
const colorLines = Object.entries(tokens.colors).map(([name, value]) => `- ${name}: hsl(${value})`);
|
|
510
558
|
const glassLines = Object.entries(tokens.glass).map(([name, value]) => `- ${name}: ${value}`);
|
|
511
559
|
const text = [
|
|
@@ -513,11 +561,14 @@ export const getTokens = (data = loadLumenData()) => {
|
|
|
513
561
|
`Theme attribute: ${tokens.themeAttribute} (values: light, dark)`,
|
|
514
562
|
'',
|
|
515
563
|
'## Semantic token names (use as `text-ink`, `bg-surface`, `border-line`, etc.)',
|
|
516
|
-
tokens.semantic.map(
|
|
564
|
+
tokens.semantic.map(token => `- ${token}`).join('\n'),
|
|
517
565
|
'',
|
|
518
566
|
'## Base color values',
|
|
519
567
|
colorLines.join('\n'),
|
|
520
568
|
'',
|
|
569
|
+
'## Data visualization tokens',
|
|
570
|
+
chartLines.join('\n'),
|
|
571
|
+
'',
|
|
521
572
|
'## Glass surface tokens',
|
|
522
573
|
glassLines.join('\n')
|
|
523
574
|
].join('\n');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@santi020k/lumen-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -83,8 +83,8 @@
|
|
|
83
83
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
84
84
|
"test": "vitest run --config ../../vitest.config.ts --project mcp",
|
|
85
85
|
"test:coverage": "vitest run --config ../../vitest.config.ts --project mcp --coverage",
|
|
86
|
-
"lint": "eslint . --no-warn-ignored",
|
|
87
|
-
"lint:fix": "eslint . --fix --no-warn-ignored",
|
|
86
|
+
"lint": "eslint . --no-warn-ignored --max-warnings=0",
|
|
87
|
+
"lint:fix": "eslint . --fix --no-warn-ignored --max-warnings=0",
|
|
88
88
|
"clean": "rm -rf dist coverage"
|
|
89
89
|
}
|
|
90
90
|
}
|