@santi020k/lumen-mcp 0.1.0 → 0.3.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/README.md +53 -9
- package/bin/lumen-mcp-http.mjs +20 -0
- package/bin/lumen-mcp-local.mjs +7 -6
- package/data/lumen-data.json +4303 -687
- package/dist/data.d.ts +26 -0
- package/dist/data.d.ts.map +1 -1
- package/dist/data.js +2 -1
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +114 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +95 -3
- package/dist/tools.d.ts +52 -1
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +232 -40
- package/package.json +11 -3
package/dist/tools.js
CHANGED
|
@@ -1,6 +1,23 @@
|
|
|
1
1
|
import { loadLumenData } from './data.js';
|
|
2
2
|
const normalize = (value) => value.replaceAll(/([a-z0-9])([A-Z])/g, '$1-$2').replaceAll(/[\s_]+/g, '-').toLowerCase();
|
|
3
3
|
const tokenize = (value) => normalize(value).split(/[^a-z0-9]+/).filter(Boolean);
|
|
4
|
+
const searchStopWords = new Set([
|
|
5
|
+
'a', 'accessibility', 'accessible', 'admin', 'an', 'and', 'app', 'application', 'component', 'for',
|
|
6
|
+
'in', 'lumen', 'not', 'of', 'or', 'the', 'to', 'ui', 'with'
|
|
7
|
+
]);
|
|
8
|
+
const searchTermAliases = {
|
|
9
|
+
booking: ['booking', 'schedule', 'calendar', 'appointment', 'date'],
|
|
10
|
+
dark: ['dark', 'theme'],
|
|
11
|
+
dashboard: ['dashboard', 'data-table', 'sidebar', 'chart', 'stat', 'metric'],
|
|
12
|
+
mode: ['mode', 'theme'],
|
|
13
|
+
pagination: ['pagination', 'paginated'],
|
|
14
|
+
sortable: ['sortable', 'sort']
|
|
15
|
+
};
|
|
16
|
+
const meaningfulSearchTerms = (value) => {
|
|
17
|
+
const terms = tokenize(value);
|
|
18
|
+
const meaningful = terms.filter((term) => !searchStopWords.has(term));
|
|
19
|
+
return meaningful.length > 0 ? meaningful : terms;
|
|
20
|
+
};
|
|
4
21
|
const availableFrameworks = (component) => Object.entries(component.frameworks)
|
|
5
22
|
.filter(([, available]) => available)
|
|
6
23
|
.map(([framework]) => framework);
|
|
@@ -23,22 +40,33 @@ export const resolveRecipe = (name, data = loadLumenData()) => {
|
|
|
23
40
|
const target = normalize(name);
|
|
24
41
|
return data.recipes.find((recipe) => normalize(recipe.name) === target);
|
|
25
42
|
};
|
|
26
|
-
const
|
|
27
|
-
|
|
43
|
+
const frameworkBehaviorSearchText = (behavior) => [
|
|
44
|
+
behavior?.description ?? '',
|
|
45
|
+
behavior?.hook ?? '',
|
|
46
|
+
behavior?.mode ?? '',
|
|
47
|
+
behavior?.setup ?? ''
|
|
48
|
+
];
|
|
49
|
+
const frameworkDetailsSearchText = (framework) => [
|
|
28
50
|
framework.packageName,
|
|
51
|
+
...frameworkBehaviorSearchText(framework.behavior),
|
|
52
|
+
framework.example,
|
|
29
53
|
framework.propsExtends ?? '',
|
|
30
54
|
framework.props.map((prop) => `${prop.name} ${prop.type}`).join(' '),
|
|
31
55
|
framework.attributes?.join(' ') ?? '',
|
|
32
56
|
framework.tagName ?? ''
|
|
33
|
-
]
|
|
57
|
+
];
|
|
58
|
+
const frameworkSearchText = (component, framework) => (framework
|
|
59
|
+
? [Reflect.get(component.frameworkDetails, framework)]
|
|
60
|
+
: Object.values(component.frameworkDetails))
|
|
61
|
+
.flatMap(frameworkDetailsSearchText)
|
|
34
62
|
.join(' ');
|
|
35
|
-
const componentSearchText = (component) => [
|
|
63
|
+
const componentSearchText = (component, framework) => [
|
|
36
64
|
component.name,
|
|
37
65
|
component.kebab,
|
|
38
|
-
'accessible accessibility',
|
|
39
66
|
component.description,
|
|
40
67
|
component.category,
|
|
41
68
|
component.collections.join(' '),
|
|
69
|
+
component.recipes.map((recipe) => recipe.name).join(' '),
|
|
42
70
|
component.keywords.join(' '),
|
|
43
71
|
component.dependencies.join(' '),
|
|
44
72
|
component.guidance?.when ?? '',
|
|
@@ -46,16 +74,23 @@ const componentSearchText = (component) => [
|
|
|
46
74
|
component.apiReference
|
|
47
75
|
.map((row) => `${row.attribute} ${row.values} ${row.description}`)
|
|
48
76
|
.join(' '),
|
|
49
|
-
frameworkSearchText(component)
|
|
77
|
+
frameworkSearchText(component, framework)
|
|
50
78
|
].join(' ');
|
|
51
79
|
const scoreCandidate = (query, terms, searchableText, primaryName = '') => {
|
|
52
80
|
const normalizedText = normalize(searchableText);
|
|
53
|
-
const matchedTerms = terms.filter((term) => normalizedText.includes(
|
|
54
|
-
if (matchedTerms.length
|
|
81
|
+
const matchedTerms = terms.filter((term) => (Reflect.get(searchTermAliases, term) ?? [term]).some((candidate) => normalizedText.includes(candidate)));
|
|
82
|
+
if (matchedTerms.length === 0)
|
|
55
83
|
return { matchedTerms, score: 0 };
|
|
56
|
-
const normalizedQuery =
|
|
84
|
+
const normalizedQuery = terms.join('-');
|
|
57
85
|
const normalizedName = normalize(primaryName);
|
|
58
|
-
|
|
86
|
+
const coverage = matchedTerms.length / terms.length;
|
|
87
|
+
let score = matchedTerms.reduce((total, term) => total + ((Reflect.get(searchTermAliases, term) ?? [term]).some((candidate) => normalizedName.includes(candidate))
|
|
88
|
+
? 20
|
|
89
|
+
: 5), 0);
|
|
90
|
+
score += Math.round(coverage * 80);
|
|
91
|
+
score -= (terms.length - matchedTerms.length) * 3;
|
|
92
|
+
if (terms.includes(normalizedName))
|
|
93
|
+
score += 50;
|
|
59
94
|
if (normalizedText.includes(normalizedQuery))
|
|
60
95
|
score += 100;
|
|
61
96
|
if (normalizedName === normalizedQuery)
|
|
@@ -63,20 +98,22 @@ const scoreCandidate = (query, terms, searchableText, primaryName = '') => {
|
|
|
63
98
|
return { matchedTerms, score };
|
|
64
99
|
};
|
|
65
100
|
const appendSearchResult = (results, candidate, query, terms, searchableText) => {
|
|
66
|
-
const match = scoreCandidate(query, terms, searchableText, candidate.name);
|
|
101
|
+
const match = scoreCandidate(query, terms, searchableText, candidate.kind === 'rule' ? '' : candidate.name);
|
|
67
102
|
if (match.score > 0)
|
|
68
103
|
results.push({ ...candidate, ...match });
|
|
69
104
|
};
|
|
70
|
-
const collectSearchResults = (query, terms, data) => {
|
|
105
|
+
const collectSearchResults = (query, terms, data, framework) => {
|
|
71
106
|
const results = [];
|
|
72
107
|
for (const component of data.components) {
|
|
108
|
+
if (framework && !Reflect.get(component.frameworks, framework))
|
|
109
|
+
continue;
|
|
73
110
|
appendSearchResult(results, {
|
|
74
111
|
category: component.category,
|
|
75
112
|
description: component.description,
|
|
76
113
|
frameworks: availableFrameworks(component),
|
|
77
114
|
kind: 'component',
|
|
78
115
|
name: component.name
|
|
79
|
-
}, query, terms, componentSearchText(component));
|
|
116
|
+
}, query, terms, componentSearchText(component, framework));
|
|
80
117
|
}
|
|
81
118
|
for (const recipe of data.recipes) {
|
|
82
119
|
appendSearchResult(results, {
|
|
@@ -104,14 +141,17 @@ const collectSearchResults = (query, terms, data) => {
|
|
|
104
141
|
};
|
|
105
142
|
export const listComponents = (args = {}, data = loadLumenData()) => {
|
|
106
143
|
const query = args.query?.trim();
|
|
107
|
-
const queryTerms = query ?
|
|
144
|
+
const queryTerms = query ? meaningfulSearchTerms(query) : [];
|
|
145
|
+
const recipe = args.recipe ? resolveRecipe(args.recipe, data) : undefined;
|
|
146
|
+
const recipeName = recipe?.name ?? (args.recipe ? normalize(args.recipe) : undefined);
|
|
108
147
|
const matches = data.components.filter((component) => {
|
|
109
148
|
if (args.framework && !component.frameworks[args.framework])
|
|
110
149
|
return false;
|
|
111
|
-
if (
|
|
150
|
+
if (recipeName &&
|
|
151
|
+
!component.recipes.some((componentRecipe) => normalize(componentRecipe.name) === recipeName))
|
|
112
152
|
return false;
|
|
113
153
|
if (query &&
|
|
114
|
-
scoreCandidate(query, queryTerms, componentSearchText(component), component.name).score === 0)
|
|
154
|
+
scoreCandidate(query, queryTerms, componentSearchText(component, args.framework), component.name).score === 0)
|
|
115
155
|
return false;
|
|
116
156
|
return true;
|
|
117
157
|
});
|
|
@@ -181,6 +221,9 @@ const componentDetail = (component, framework, detail) => {
|
|
|
181
221
|
: usage;
|
|
182
222
|
};
|
|
183
223
|
const formatProps = (framework) => {
|
|
224
|
+
if (framework.attributes && framework.attributes.length > 0) {
|
|
225
|
+
return `Attributes:\n${framework.attributes.map((attribute) => `- ${attribute}`).join('\n')}`;
|
|
226
|
+
}
|
|
184
227
|
if (framework.props.length === 0) {
|
|
185
228
|
return framework.propsExtends
|
|
186
229
|
? `Props extend ${framework.propsExtends}; no additional local props were detected.`
|
|
@@ -192,25 +235,35 @@ const formatProps = (framework) => {
|
|
|
192
235
|
: 'Props:';
|
|
193
236
|
return `${header}\n${lines.join('\n')}`;
|
|
194
237
|
};
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
238
|
+
const buildSummarySections = (component, frameworkName, framework) => [
|
|
239
|
+
`# ${component.name}`,
|
|
240
|
+
component.description,
|
|
241
|
+
`Category: ${component.category}`,
|
|
242
|
+
`Framework: ${frameworkName}`,
|
|
243
|
+
`Package: ${framework.packageName}`,
|
|
244
|
+
`Import: ${framework.importStatement}`,
|
|
245
|
+
`Styles: ${framework.styleImport}`,
|
|
246
|
+
framework.tagName ? `Custom element: <${framework.tagName}>` : '',
|
|
247
|
+
component.recipes.length > 0
|
|
248
|
+
? `Recipes: ${component.recipes.map((recipe) => recipe.name).join(', ')}`
|
|
249
|
+
: 'Recipes: none'
|
|
250
|
+
].filter(Boolean);
|
|
251
|
+
const appendBehaviorSections = (sections, behavior) => {
|
|
252
|
+
if (!behavior)
|
|
253
|
+
return;
|
|
254
|
+
sections.push('', '## Framework behavior', behavior.setup);
|
|
255
|
+
if (behavior.hook)
|
|
256
|
+
sections.push(`Hook: ${behavior.hook}`);
|
|
257
|
+
if (behavior.description)
|
|
258
|
+
sections.push(behavior.description);
|
|
259
|
+
if (behavior.options && behavior.options.length > 0) {
|
|
260
|
+
sections.push('', 'Hook options:', ...behavior.options.map((option) => `- ${option.name}: ${option.type} — ${option.description}`));
|
|
261
|
+
}
|
|
262
|
+
if (behavior.controller && behavior.controller.length > 0) {
|
|
263
|
+
sections.push('', 'Controller values:', ...behavior.controller.map((value) => `- ${value.name}: ${value.type} — ${value.description}`));
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
const appendGuidanceSections = (sections, component) => {
|
|
214
267
|
if (component.guidance) {
|
|
215
268
|
sections.push('', '## Guidance', component.guidance.when);
|
|
216
269
|
if (component.guidance.distinction)
|
|
@@ -218,15 +271,27 @@ const formatComponentUsage = (component, frameworkName, detail) => {
|
|
|
218
271
|
}
|
|
219
272
|
if (component.keyboardInteractions.length > 0) {
|
|
220
273
|
sections.push('', '## Keyboard interactions');
|
|
221
|
-
sections.push(...component.keyboardInteractions.map((
|
|
274
|
+
sections.push(...component.keyboardInteractions.map((interaction) => `- ${interaction.key}: ${interaction.action}`));
|
|
275
|
+
}
|
|
276
|
+
if (component.apiReference.length > 0) {
|
|
277
|
+
sections.push('', '## API reference');
|
|
278
|
+
sections.push(...component.apiReference.map((row) => `- \`${row.attribute}\` ${row.values} — ${row.description}`));
|
|
222
279
|
}
|
|
223
280
|
if (component.runtimeEvents.length > 0) {
|
|
224
281
|
sections.push('', '## Runtime events');
|
|
225
282
|
sections.push(...component.runtimeEvents.map((event) => `- ${event.name}: ${event.when}`));
|
|
226
283
|
}
|
|
284
|
+
};
|
|
285
|
+
const formatComponentUsage = (component, frameworkName, detail) => {
|
|
286
|
+
const framework = getFrameworkDetail(component.frameworkDetails, frameworkName);
|
|
287
|
+
const sections = buildSummarySections(component, frameworkName, framework);
|
|
288
|
+
if (detail === 'summary')
|
|
289
|
+
return sections.join('\n');
|
|
290
|
+
sections.push('', formatProps(framework), '', '## Example', `\`\`\`${framework.language}`, framework.example, '```');
|
|
291
|
+
appendBehaviorSections(sections, framework.behavior);
|
|
292
|
+
appendGuidanceSections(sections, component);
|
|
227
293
|
if (detail === 'source') {
|
|
228
|
-
sections.push('', `## ${frameworkName} reference source
|
|
229
|
-
sections.push(`\`\`\`${framework.language}`, framework.source.trimEnd(), '```');
|
|
294
|
+
sections.push('', `## ${frameworkName} reference source`, `\`\`\`${framework.language}`, framework.source.trimEnd(), '```');
|
|
230
295
|
}
|
|
231
296
|
return sections.join('\n');
|
|
232
297
|
};
|
|
@@ -298,8 +363,16 @@ export const search = (args, data = loadLumenData()) => {
|
|
|
298
363
|
};
|
|
299
364
|
}
|
|
300
365
|
const limit = Math.max(1, Math.min(args.limit ?? 20, 100));
|
|
301
|
-
const results = collectSearchResults(query,
|
|
302
|
-
|
|
366
|
+
const results = collectSearchResults(query, meaningfulSearchTerms(query), data, args.framework);
|
|
367
|
+
const kindPriority = {
|
|
368
|
+
component: 0,
|
|
369
|
+
recipe: 1,
|
|
370
|
+
rule: 3,
|
|
371
|
+
token: 2
|
|
372
|
+
};
|
|
373
|
+
results.sort((left, right) => right.score - left.score ||
|
|
374
|
+
kindPriority[left.kind] - kindPriority[right.kind] ||
|
|
375
|
+
left.name.localeCompare(right.name));
|
|
303
376
|
const shown = results.slice(0, limit);
|
|
304
377
|
if (results.length === 0) {
|
|
305
378
|
return {
|
|
@@ -312,6 +385,125 @@ export const search = (args, data = loadLumenData()) => {
|
|
|
312
385
|
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')}`
|
|
313
386
|
};
|
|
314
387
|
};
|
|
388
|
+
export const getMeta = (data = loadLumenData()) => ({
|
|
389
|
+
data: { meta: data.meta },
|
|
390
|
+
text: [
|
|
391
|
+
'# Lumen MCP snapshot',
|
|
392
|
+
`Server version: ${data.meta.serverVersion}`,
|
|
393
|
+
`Schema version: ${data.meta.schemaVersion}`,
|
|
394
|
+
`Catalog hash: ${data.meta.catalogHash}`,
|
|
395
|
+
`Components: ${data.meta.componentCount}`,
|
|
396
|
+
'',
|
|
397
|
+
'## Package versions',
|
|
398
|
+
...Object.entries(data.meta.packageVersions).map(([name, version]) => `- ${name}: ${version}`)
|
|
399
|
+
].join('\n')
|
|
400
|
+
});
|
|
401
|
+
const diffManifestSection = (current, baseline) => {
|
|
402
|
+
const currentNames = Object.keys(current);
|
|
403
|
+
const baselineNames = Object.keys(baseline);
|
|
404
|
+
return {
|
|
405
|
+
added: currentNames.filter((name) => Reflect.get(baseline, name) === undefined).sort(),
|
|
406
|
+
changed: currentNames
|
|
407
|
+
.filter((name) => Reflect.get(baseline, name) !== undefined && Reflect.get(baseline, name) !== Reflect.get(current, name))
|
|
408
|
+
.sort(),
|
|
409
|
+
removed: baselineNames.filter((name) => Reflect.get(current, name) === undefined).sort(),
|
|
410
|
+
unchanged: currentNames.filter((name) => Reflect.get(baseline, name) === Reflect.get(current, name)).sort()
|
|
411
|
+
};
|
|
412
|
+
};
|
|
413
|
+
export const getCatalogManifest = (data = loadLumenData()) => ({
|
|
414
|
+
data: {
|
|
415
|
+
catalogHash: data.meta.catalogHash,
|
|
416
|
+
manifest: data.catalogManifest,
|
|
417
|
+
schemaVersion: data.meta.schemaVersion
|
|
418
|
+
},
|
|
419
|
+
text: [
|
|
420
|
+
'# Lumen catalog manifest',
|
|
421
|
+
`Catalog hash: ${data.meta.catalogHash}`,
|
|
422
|
+
`Components: ${Object.keys(data.catalogManifest.components).length}`,
|
|
423
|
+
`Recipes: ${Object.keys(data.catalogManifest.recipes).length}`,
|
|
424
|
+
'',
|
|
425
|
+
'Keep this structured result and pass its manifest to lumen_diff_catalog after an MCP update.'
|
|
426
|
+
].join('\n')
|
|
427
|
+
});
|
|
428
|
+
export const diffCatalog = (args, data = loadLumenData()) => {
|
|
429
|
+
const components = diffManifestSection(data.catalogManifest.components, args.baseline.components);
|
|
430
|
+
const recipes = diffManifestSection(data.catalogManifest.recipes, args.baseline.recipes);
|
|
431
|
+
const changedCount = [
|
|
432
|
+
...components.added,
|
|
433
|
+
...components.changed,
|
|
434
|
+
...components.removed,
|
|
435
|
+
...recipes.added,
|
|
436
|
+
...recipes.changed,
|
|
437
|
+
...recipes.removed
|
|
438
|
+
].length;
|
|
439
|
+
const unchanged = changedCount === 0 &&
|
|
440
|
+
(args.baselineCatalogHash === undefined ||
|
|
441
|
+
args.baselineCatalogHash === data.meta.catalogHash);
|
|
442
|
+
return {
|
|
443
|
+
data: {
|
|
444
|
+
components,
|
|
445
|
+
currentCatalogHash: data.meta.catalogHash,
|
|
446
|
+
recipes,
|
|
447
|
+
unchanged
|
|
448
|
+
},
|
|
449
|
+
text: unchanged
|
|
450
|
+
? `The Lumen catalog is unchanged (${data.meta.catalogHash}).`
|
|
451
|
+
: [
|
|
452
|
+
'# Lumen catalog changes',
|
|
453
|
+
`Current catalog hash: ${data.meta.catalogHash}`,
|
|
454
|
+
`Changed entries: ${changedCount}`,
|
|
455
|
+
`Components — added: ${components.added.length}, changed: ${components.changed.length}, removed: ${components.removed.length}`,
|
|
456
|
+
`Recipes — added: ${recipes.added.length}, changed: ${recipes.changed.length}, removed: ${recipes.removed.length}`
|
|
457
|
+
].join('\n')
|
|
458
|
+
};
|
|
459
|
+
};
|
|
460
|
+
export const diagnose = (data = loadLumenData()) => {
|
|
461
|
+
const componentNames = data.components.map((component) => component.name);
|
|
462
|
+
const frameworkCoverage = {
|
|
463
|
+
astro: data.components.filter((component) => component.frameworks.astro).length,
|
|
464
|
+
elements: data.components.filter((component) => component.frameworks.elements).length,
|
|
465
|
+
react: data.components.filter((component) => component.frameworks.react).length
|
|
466
|
+
};
|
|
467
|
+
const checks = [
|
|
468
|
+
{
|
|
469
|
+
message: `${data.components.length} component records match metadata.`,
|
|
470
|
+
name: 'component-count',
|
|
471
|
+
status: data.components.length === data.meta.componentCount ? 'pass' : 'fail'
|
|
472
|
+
},
|
|
473
|
+
{
|
|
474
|
+
message: 'Component names are unique.',
|
|
475
|
+
name: 'unique-components',
|
|
476
|
+
status: new Set(componentNames).size === componentNames.length ? 'pass' : 'fail'
|
|
477
|
+
},
|
|
478
|
+
{
|
|
479
|
+
message: 'Every component has a manifest fingerprint.',
|
|
480
|
+
name: 'component-manifest',
|
|
481
|
+
status: componentNames.every((name) => Reflect.get(data.catalogManifest.components, name)) ? 'pass' : 'fail'
|
|
482
|
+
},
|
|
483
|
+
{
|
|
484
|
+
message: 'Every available framework contract has an example and import statement.',
|
|
485
|
+
name: 'framework-contracts',
|
|
486
|
+
status: data.components.every((component) => Object.entries(component.frameworks).every(([framework, available]) => {
|
|
487
|
+
if (!available)
|
|
488
|
+
return true;
|
|
489
|
+
const details = Reflect.get(component.frameworkDetails, framework);
|
|
490
|
+
return Boolean(details?.example.trim()) && Boolean(details?.importStatement.trim());
|
|
491
|
+
})) ? 'pass' : 'fail'
|
|
492
|
+
}
|
|
493
|
+
];
|
|
494
|
+
const status = checks.every((check) => check.status === 'pass') ? 'healthy' : 'issues';
|
|
495
|
+
return {
|
|
496
|
+
data: { checks, frameworkCoverage, status },
|
|
497
|
+
isError: status === 'issues',
|
|
498
|
+
text: [
|
|
499
|
+
`# Lumen MCP diagnostics: ${status}`,
|
|
500
|
+
`Catalog hash: ${data.meta.catalogHash}`,
|
|
501
|
+
`Framework coverage — Astro: ${frameworkCoverage.astro}, React: ${frameworkCoverage.react}, Elements: ${frameworkCoverage.elements}`,
|
|
502
|
+
'',
|
|
503
|
+
...checks.map((check) => `- ${check.status.toUpperCase()} ${check.name}: ${check.message}`)
|
|
504
|
+
].join('\n')
|
|
505
|
+
};
|
|
506
|
+
};
|
|
315
507
|
export const getTokens = (data = loadLumenData()) => {
|
|
316
508
|
const { tokens } = data;
|
|
317
509
|
const colorLines = Object.entries(tokens.colors).map(([name, value]) => `- ${name}: hsl(${value})`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@santi020k/lumen-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -29,20 +29,23 @@
|
|
|
29
29
|
"LICENSE"
|
|
30
30
|
],
|
|
31
31
|
"bin": {
|
|
32
|
-
"lumen-mcp": "./bin/lumen-mcp.mjs"
|
|
32
|
+
"lumen-mcp": "./bin/lumen-mcp.mjs",
|
|
33
|
+
"lumen-mcp-http": "./bin/lumen-mcp-http.mjs"
|
|
33
34
|
},
|
|
34
35
|
"dependencies": {
|
|
35
36
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
36
37
|
"zod": "^4.4.3"
|
|
37
38
|
},
|
|
38
39
|
"devDependencies": {
|
|
40
|
+
"@astrojs/compiler": "^3.0.1",
|
|
41
|
+
"@types/express": "^5.0.6",
|
|
39
42
|
"@types/node": "^26.1.1",
|
|
40
43
|
"@vitest/coverage-v8": "^4.1.10",
|
|
41
44
|
"typescript": "^6.0.3",
|
|
42
45
|
"vitest": "^4.1.10"
|
|
43
46
|
},
|
|
44
47
|
"engines": {
|
|
45
|
-
"node": ">=
|
|
48
|
+
"node": ">=20.20.0"
|
|
46
49
|
},
|
|
47
50
|
"repository": {
|
|
48
51
|
"type": "git",
|
|
@@ -69,9 +72,14 @@
|
|
|
69
72
|
"license": "MIT",
|
|
70
73
|
"scripts": {
|
|
71
74
|
"generate": "node scripts/generate-data.mjs",
|
|
75
|
+
"check:snapshot": "node scripts/generate-data.mjs --check",
|
|
72
76
|
"build": "pnpm run generate && tsc -p tsconfig.build.json",
|
|
73
77
|
"dev": "pnpm run generate && tsc -p tsconfig.build.json --watch --preserveWatchOutput",
|
|
74
78
|
"local": "node bin/lumen-mcp-local.mjs",
|
|
79
|
+
"eval": "pnpm --filter @santi020k/lumen-react... run build && pnpm run build && node scripts/evaluate.mjs && node scripts/validate-examples.mjs",
|
|
80
|
+
"eval:examples": "pnpm --filter @santi020k/lumen-react... run build && pnpm run build && node scripts/validate-examples.mjs",
|
|
81
|
+
"eval:search": "pnpm run build && node scripts/evaluate.mjs --search-only",
|
|
82
|
+
"smoke:package": "pnpm run build && node scripts/smoke-package.mjs",
|
|
75
83
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
76
84
|
"test": "vitest run --config ../../vitest.config.ts --project mcp",
|
|
77
85
|
"test:coverage": "vitest run --config ../../vitest.config.ts --project mcp --coverage",
|