@santi020k/lumen-mcp 3.0.0 → 4.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/README.md +125 -42
- package/data/lumen-data.json +35076 -18207
- package/dist/cloudflare-worker.js +1 -1
- package/dist/compatibility.d.ts +18 -0
- package/dist/compatibility.d.ts.map +1 -0
- package/dist/compatibility.js +30 -0
- package/dist/contracts.d.ts +189 -0
- package/dist/contracts.d.ts.map +1 -0
- package/dist/contracts.js +122 -0
- package/dist/data.d.ts +22 -0
- package/dist/data.d.ts.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -3
- package/dist/migration.d.ts +10 -0
- package/dist/migration.d.ts.map +1 -0
- package/dist/migration.js +16 -0
- package/dist/server.d.ts +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +50 -21
- package/dist/tools.d.ts +2 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +76 -6
- package/package.json +8 -5
package/dist/server.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import { McpServer, ResourceTemplate } from '@modelcontextprotocol/
|
|
1
|
+
import { McpServer, ResourceTemplate } from '@modelcontextprotocol/server';
|
|
2
2
|
import * as z from 'zod';
|
|
3
|
+
import { checkCompatibility } from './compatibility.js';
|
|
4
|
+
import { compatibilityOutputSchema, componentOutputSchema, nativeComponentOutputSchema, recipeOutputSchema } from './contracts.js';
|
|
3
5
|
import { loadLumenData } from './data.js';
|
|
6
|
+
import { getMigration } from './migration.js';
|
|
4
7
|
import { diagnose, diffCatalog, getCatalogManifest, getComponent, getMeta, getNativeComponent, getRecipe, getRules, getTokens, listComponents, listNativeComponents, search } from './tools.js';
|
|
5
8
|
const readOnlyAnnotations = {
|
|
6
9
|
destructiveHint: false,
|
|
@@ -21,11 +24,6 @@ const listComponentsOutputSchema = z.strictObject({
|
|
|
21
24
|
components: z.array(componentSummarySchema),
|
|
22
25
|
count: z.int().min(0)
|
|
23
26
|
});
|
|
24
|
-
const componentOutputSchema = z.strictObject({
|
|
25
|
-
component: z.record(z.string(), z.unknown()).optional(),
|
|
26
|
-
found: z.boolean(),
|
|
27
|
-
message: z.string().trim().optional()
|
|
28
|
-
});
|
|
29
27
|
const nativePlatformSchema = z.enum(['react-native', 'swiftui', 'compose']);
|
|
30
28
|
const nativeComponentSummarySchema = z.strictObject({
|
|
31
29
|
accessibility: z.string().trim(),
|
|
@@ -40,11 +38,6 @@ const listNativeComponentsOutputSchema = z.strictObject({
|
|
|
40
38
|
components: z.array(nativeComponentSummarySchema),
|
|
41
39
|
count: z.int().min(0)
|
|
42
40
|
});
|
|
43
|
-
const recipeOutputSchema = z.strictObject({
|
|
44
|
-
found: z.boolean(),
|
|
45
|
-
message: z.string().trim().optional(),
|
|
46
|
-
recipe: z.record(z.string(), z.unknown()).optional()
|
|
47
|
-
});
|
|
48
41
|
const searchResultSchema = z.strictObject({
|
|
49
42
|
category: z.string().trim().optional(),
|
|
50
43
|
description: z.string().trim(),
|
|
@@ -62,10 +55,18 @@ const searchOutputSchema = z.strictObject({
|
|
|
62
55
|
});
|
|
63
56
|
const tokensOutputSchema = z.strictObject({
|
|
64
57
|
tokens: z.strictObject({
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
58
|
+
presets: z.strictObject({
|
|
59
|
+
attribute: z.string().trim(),
|
|
60
|
+
names: z.array(z.enum(['default', 'studio', 'glass'])),
|
|
61
|
+
schemeAttribute: z.string().trim(),
|
|
62
|
+
materialPolicy: z.literal('explicit-surfaces')
|
|
63
|
+
}),
|
|
64
|
+
chart: z.record(z.string().trim(), z.string().trim()),
|
|
65
|
+
colors: z.record(z.string().trim(), z.string().trim()),
|
|
66
|
+
glass: z.record(z.string().trim(), z.string().trim()),
|
|
68
67
|
semantic: z.array(z.string().trim()),
|
|
68
|
+
spacing: z.record(z.string().trim(), z.number().nonnegative()),
|
|
69
|
+
spacingRoles: z.record(z.string().trim(), z.string().trim()),
|
|
69
70
|
themeAttribute: z.string().trim()
|
|
70
71
|
})
|
|
71
72
|
});
|
|
@@ -78,7 +79,7 @@ const metaOutputSchema = z.strictObject({
|
|
|
78
79
|
componentCount: z.int().min(0),
|
|
79
80
|
nativeComponentCount: z.int().min(0),
|
|
80
81
|
packages: z.array(z.string().trim()),
|
|
81
|
-
packageVersions: z.record(z.string(), z.string().trim()),
|
|
82
|
+
packageVersions: z.record(z.string().trim(), z.string().trim()),
|
|
82
83
|
registryName: z.string().trim(),
|
|
83
84
|
registryVersion: z.int().min(1),
|
|
84
85
|
schemaVersion: z.int().min(1),
|
|
@@ -86,10 +87,10 @@ const metaOutputSchema = z.strictObject({
|
|
|
86
87
|
})
|
|
87
88
|
});
|
|
88
89
|
const catalogManifestSchema = z.strictObject({
|
|
89
|
-
components: z.record(z.string(), z.string().trim().regex(/^[a-f0-9]{64}$/)),
|
|
90
|
-
nativeComponents: z.record(z.string(), z.string().trim().regex(/^[a-f0-9]{64}$/))
|
|
90
|
+
components: z.record(z.string().trim(), z.string().trim().regex(/^[a-f0-9]{64}$/)),
|
|
91
|
+
nativeComponents: z.record(z.string().trim(), z.string().trim().regex(/^[a-f0-9]{64}$/))
|
|
91
92
|
.optional(),
|
|
92
|
-
recipes: z.record(z.string(), z.string().trim().regex(/^[a-f0-9]{64}$/))
|
|
93
|
+
recipes: z.record(z.string().trim(), z.string().trim().regex(/^[a-f0-9]{64}$/))
|
|
93
94
|
});
|
|
94
95
|
const catalogChangesSchema = z.strictObject({
|
|
95
96
|
added: z.array(z.string().trim()),
|
|
@@ -145,7 +146,7 @@ const jsonResource = (uri, data, mimeType = 'application/json') => ({
|
|
|
145
146
|
export const createLumenServer = () => {
|
|
146
147
|
const data = loadLumenData();
|
|
147
148
|
const server = new McpServer({ name: '@santi020k/lumen-mcp', version: data.meta.serverVersion }, {
|
|
148
|
-
instructions: 'Read lumen://meta, lumen://diagnostics, and lumen://rules before generating Lumen code. Search or list the catalog, ' +
|
|
149
|
+
instructions: 'Compare resolved installed versions with lumen_check_compatibility. On mismatch use installed public types or a matching catalog. Read lumen://meta, lumen://diagnostics, and lumen://rules before generating Lumen code. Search or list the catalog, ' +
|
|
149
150
|
'then inspect the selected web or native component for the target framework or platform at usage detail before requesting source.'
|
|
150
151
|
});
|
|
151
152
|
server.registerTool('lumen_list_components', {
|
|
@@ -204,7 +205,7 @@ export const createLumenServer = () => {
|
|
|
204
205
|
platform: nativePlatformSchema
|
|
205
206
|
.meta({ description: 'Native implementation contract to return.' })
|
|
206
207
|
}),
|
|
207
|
-
outputSchema:
|
|
208
|
+
outputSchema: nativeComponentOutputSchema
|
|
208
209
|
}, args => toMcpResult(getNativeComponent(args)));
|
|
209
210
|
server.registerTool('lumen_get_recipe', {
|
|
210
211
|
annotations: readOnlyAnnotations,
|
|
@@ -227,6 +228,8 @@ export const createLumenServer = () => {
|
|
|
227
228
|
framework: z.enum(['astro', 'react', 'elements'])
|
|
228
229
|
.optional()
|
|
229
230
|
.meta({ description: 'Only search framework-specific component contracts for this target.' }),
|
|
231
|
+
kind: z.enum(['component', 'native-component', 'recipe', 'rule', 'token']).optional()
|
|
232
|
+
.meta({ description: 'Return only this kind of match; combine with limit for focused discovery.' }),
|
|
230
233
|
limit: z.int().min(1).max(100)
|
|
231
234
|
.optional()
|
|
232
235
|
.meta({ description: 'Maximum results to return (1-100, default 20).' }),
|
|
@@ -237,6 +240,32 @@ export const createLumenServer = () => {
|
|
|
237
240
|
}),
|
|
238
241
|
outputSchema: searchOutputSchema
|
|
239
242
|
}, args => toMcpResult(search(args)));
|
|
243
|
+
server.registerTool('lumen_check_compatibility', {
|
|
244
|
+
annotations: readOnlyAnnotations,
|
|
245
|
+
description: 'Compare resolved installed Lumen package versions with this snapshot before generating or migrating code. Does not read repositories or change dependencies.',
|
|
246
|
+
inputSchema: z.strictObject({
|
|
247
|
+
packageVersions: z.record(z.string().trim().min(1).max(160), z.string().trim().min(1).max(100))
|
|
248
|
+
.meta({ description: 'Resolved versions from installed package metadata or native lock files, not manifest ranges. Include only Lumen packages.' })
|
|
249
|
+
}),
|
|
250
|
+
outputSchema: compatibilityOutputSchema
|
|
251
|
+
}, args => toMcpResult(checkCompatibility(args)));
|
|
252
|
+
server.registerTool('lumen_get_migration', {
|
|
253
|
+
annotations: readOnlyAnnotations,
|
|
254
|
+
description: 'Read the v4 migration contract, affected packages and review guidance. Does not modify consumer code or versions.',
|
|
255
|
+
inputSchema: z.strictObject({ packageName: z.string().trim().min(1).max(160).optional() }),
|
|
256
|
+
outputSchema: z.strictObject({
|
|
257
|
+
changes: z.array(z.strictObject({
|
|
258
|
+
currentContract: z.string().trim(),
|
|
259
|
+
docs: z.array(z.string().trim()),
|
|
260
|
+
id: z.string().trim(),
|
|
261
|
+
migration: z.string().trim(),
|
|
262
|
+
packages: z.array(z.string().trim()),
|
|
263
|
+
replacement: z.string().trim()
|
|
264
|
+
})),
|
|
265
|
+
status: z.string().trim(),
|
|
266
|
+
targetVersion: z.string().trim()
|
|
267
|
+
})
|
|
268
|
+
}, args => toMcpResult(getMigration(args)));
|
|
240
269
|
server.registerTool('lumen_get_meta', {
|
|
241
270
|
annotations: readOnlyAnnotations,
|
|
242
271
|
description: 'Return snapshot provenance: server and package versions, schema version, component count, ' +
|
|
@@ -270,7 +299,7 @@ export const createLumenServer = () => {
|
|
|
270
299
|
}, () => toMcpResult(diagnose()));
|
|
271
300
|
server.registerTool('lumen_get_tokens', {
|
|
272
301
|
annotations: readOnlyAnnotations,
|
|
273
|
-
description: 'Return
|
|
302
|
+
description: 'Return Lumen spacing dimensions and content roles, semantic colors, glass tokens, and theme attribute.',
|
|
274
303
|
inputSchema: z.strictObject({}),
|
|
275
304
|
outputSchema: tokensOutputSchema
|
|
276
305
|
}, () => toMcpResult(getTokens()));
|
package/dist/tools.d.ts
CHANGED
|
@@ -80,6 +80,7 @@ declare const componentDetail: (component: LumenComponentSnapshot, framework: Lu
|
|
|
80
80
|
name: string;
|
|
81
81
|
type: string;
|
|
82
82
|
}[];
|
|
83
|
+
runtimeBypass?: string;
|
|
83
84
|
setup: string;
|
|
84
85
|
};
|
|
85
86
|
example: string;
|
|
@@ -214,6 +215,7 @@ export declare const getRecipe: (args: {
|
|
|
214
215
|
}>;
|
|
215
216
|
export declare const search: (args: {
|
|
216
217
|
framework?: FrameworkFilter | undefined;
|
|
218
|
+
kind?: SearchResult["kind"] | undefined;
|
|
217
219
|
limit?: number | undefined;
|
|
218
220
|
platform?: NativePlatformFilter | undefined;
|
|
219
221
|
query: string;
|
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,4BAA4B,EAC5B,iCAAiC,EACjC,mBAAmB,EACnB,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;AAC5C,MAAM,MAAM,oBAAoB,GAAG,mBAAmB,CAAA;AAEtD,MAAM,WAAW,sBAAsB;IACrC,aAAa,EAAE,MAAM,CAAA;IACrB,QAAQ,EAAE,MAAM,CAAA;IAChB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,mBAAmB,EAAE,CAAA;IAChC,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;CACb;AAED,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,kBAAkB,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAA;IACpE,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,CAAC,EAAE,mBAAmB,EAAE,CAAA;IACjC,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,5 +1,7 @@
|
|
|
1
1
|
import { loadLumenData } from './data.js';
|
|
2
2
|
const normalize = (value) => value
|
|
3
|
+
.normalize('NFD')
|
|
4
|
+
.replaceAll(/[\u0300-\u036f]/g, '')
|
|
3
5
|
.replaceAll(/([a-z0-9])([A-Z])/g, '$1-$2')
|
|
4
6
|
.replaceAll(/[\s_]+/g, '-')
|
|
5
7
|
.toLowerCase();
|
|
@@ -25,9 +27,40 @@ const searchStopWords = new Set([
|
|
|
25
27
|
'the',
|
|
26
28
|
'to',
|
|
27
29
|
'ui',
|
|
28
|
-
'with'
|
|
30
|
+
'with',
|
|
31
|
+
'de',
|
|
32
|
+
'del',
|
|
33
|
+
'el',
|
|
34
|
+
'la',
|
|
35
|
+
'las',
|
|
36
|
+
'los',
|
|
37
|
+
'para',
|
|
38
|
+
'un',
|
|
39
|
+
'una',
|
|
40
|
+
'y',
|
|
41
|
+
'con',
|
|
42
|
+
'accesible'
|
|
29
43
|
]);
|
|
30
44
|
const searchTermAliases = {
|
|
45
|
+
boton: ['button'],
|
|
46
|
+
buscar: ['search'],
|
|
47
|
+
calendario: ['calendar'],
|
|
48
|
+
confirmar: ['confirm', 'confirmation'],
|
|
49
|
+
contrasena: ['password'],
|
|
50
|
+
eliminacion: ['delete', 'destructive'],
|
|
51
|
+
eliminar: ['delete', 'destructive'],
|
|
52
|
+
fecha: ['date'],
|
|
53
|
+
fechas: ['date'],
|
|
54
|
+
formulario: ['form'],
|
|
55
|
+
modal: ['modal', 'dialog'],
|
|
56
|
+
notificacion: ['toast', 'notification'],
|
|
57
|
+
oscuro: ['dark', 'theme'],
|
|
58
|
+
paginada: ['pagination', 'paginated'],
|
|
59
|
+
rango: ['range'],
|
|
60
|
+
registros: ['records', 'data-table'],
|
|
61
|
+
seleccion: ['select'],
|
|
62
|
+
selector: ['select', 'picker'],
|
|
63
|
+
tabla: ['table'],
|
|
31
64
|
booking: ['booking', 'schedule', 'calendar', 'appointment', 'date'],
|
|
32
65
|
dark: ['dark', 'theme'],
|
|
33
66
|
dashboard: ['dashboard', 'data-table', 'sidebar', 'chart', 'stat', 'metric'],
|
|
@@ -141,19 +174,19 @@ const nativeComponentSearchText = (component, platform) => [
|
|
|
141
174
|
].join(' ');
|
|
142
175
|
const scoreCandidate = (query, terms, searchableText, primaryName = '') => {
|
|
143
176
|
const normalizedText = normalize(searchableText);
|
|
144
|
-
const matchedTerms = terms.filter(term => (
|
|
177
|
+
const matchedTerms = terms.filter(term => ((Object.hasOwn(searchTermAliases, term) ? searchTermAliases[term] : undefined) ?? [term]).some(candidate => normalizedText.includes(candidate)));
|
|
145
178
|
if (matchedTerms.length === 0)
|
|
146
179
|
return { matchedTerms, score: 0 };
|
|
147
180
|
const normalizedQuery = terms.join('-');
|
|
148
181
|
const normalizedName = normalize(primaryName);
|
|
149
182
|
const coverage = matchedTerms.length / terms.length;
|
|
150
183
|
let score = matchedTerms.reduce((total, term) => total +
|
|
151
|
-
((
|
|
184
|
+
(((Object.hasOwn(searchTermAliases, term) ? searchTermAliases[term] : undefined) ?? [term]).some(candidate => normalizedName.includes(candidate)) ?
|
|
152
185
|
20 :
|
|
153
186
|
5), 0);
|
|
154
187
|
score += Math.round(coverage * 80);
|
|
155
188
|
score -= (terms.length - matchedTerms.length) * 3;
|
|
156
|
-
if (terms.some(term => (
|
|
189
|
+
if (terms.some(term => ((Object.hasOwn(searchTermAliases, term) ? searchTermAliases[term] : undefined) ?? [term]).includes(normalizedName)))
|
|
157
190
|
score += 150;
|
|
158
191
|
if (normalizedText.includes(normalizedQuery))
|
|
159
192
|
score += 100;
|
|
@@ -199,6 +232,12 @@ const collectComponentSearchResults = (query, terms, data, framework, platform)
|
|
|
199
232
|
}
|
|
200
233
|
return results;
|
|
201
234
|
};
|
|
235
|
+
const spacingValue = (tokens, token) => {
|
|
236
|
+
const value = tokens.spacing[token];
|
|
237
|
+
if (value === undefined)
|
|
238
|
+
throw new Error(`Missing spacing dimension for ${token}.`);
|
|
239
|
+
return value;
|
|
240
|
+
};
|
|
202
241
|
const collectReferenceSearchResults = (query, terms, data) => {
|
|
203
242
|
const results = [];
|
|
204
243
|
for (const recipe of data.recipes) {
|
|
@@ -216,6 +255,10 @@ const collectReferenceSearchResults = (query, terms, data) => {
|
|
|
216
255
|
name: token
|
|
217
256
|
}, query, terms, token);
|
|
218
257
|
}
|
|
258
|
+
for (const [role, token] of Object.entries(data.tokens.spacingRoles)) {
|
|
259
|
+
const description = `Content flow spacing role ${role}: ${spacingValue(data.tokens, token)}px; CSS --ui-space-${role}.`;
|
|
260
|
+
appendSearchResult(results, { description, kind: 'token', name: role }, query, terms, `${description} layout gap padding rhythm`);
|
|
261
|
+
}
|
|
219
262
|
for (const line of data.rules.split('\n').filter(rule => rule.trim())) {
|
|
220
263
|
appendSearchResult(results, {
|
|
221
264
|
description: line.trim(),
|
|
@@ -509,6 +552,22 @@ export const getNativeComponent = (args, data = loadLumenData()) => {
|
|
|
509
552
|
text: formatNativeComponent(component, args.platform, detail, data)
|
|
510
553
|
};
|
|
511
554
|
};
|
|
555
|
+
const recipeExamples = (recipe, framework) => {
|
|
556
|
+
const frameworks = [framework];
|
|
557
|
+
return frameworks.flatMap(target => {
|
|
558
|
+
const source = recipe.examples[target];
|
|
559
|
+
if (!source)
|
|
560
|
+
return [];
|
|
561
|
+
return [
|
|
562
|
+
'',
|
|
563
|
+
`## Complete composition (${target})`,
|
|
564
|
+
'Wire application actions and persistence before shipping; replace sample IDs when rendering multiple instances.',
|
|
565
|
+
`\`\`\`${{ astro: 'astro', elements: 'html', react: 'tsx' }[target]}`,
|
|
566
|
+
source,
|
|
567
|
+
'```'
|
|
568
|
+
];
|
|
569
|
+
});
|
|
570
|
+
};
|
|
512
571
|
export const getRecipe = (args, data = loadLumenData()) => {
|
|
513
572
|
const recipe = resolveRecipe(args.name, data);
|
|
514
573
|
if (!recipe) {
|
|
@@ -536,7 +595,8 @@ export const getRecipe = (args, data = loadLumenData()) => {
|
|
|
536
595
|
`Install for ${framework}: ${getRecipeInstall(recipe.install, framework)}`,
|
|
537
596
|
'',
|
|
538
597
|
'## Components',
|
|
539
|
-
...componentLines
|
|
598
|
+
...componentLines,
|
|
599
|
+
...recipeExamples(recipe, framework)
|
|
540
600
|
].join('\n')
|
|
541
601
|
};
|
|
542
602
|
};
|
|
@@ -550,7 +610,7 @@ export const search = (args, data = loadLumenData()) => {
|
|
|
550
610
|
};
|
|
551
611
|
}
|
|
552
612
|
const limit = Math.max(1, Math.min(args.limit ?? 20, 100));
|
|
553
|
-
const results = collectSearchResults(query, meaningfulSearchTerms(query), data, args.framework, args.platform);
|
|
613
|
+
const results = collectSearchResults(query, meaningfulSearchTerms(query), data, args.framework, args.platform).filter(result => !args.kind || result.kind === args.kind);
|
|
554
614
|
const kindPriority = {
|
|
555
615
|
component: 0,
|
|
556
616
|
'native-component': 1,
|
|
@@ -775,6 +835,16 @@ export const getTokens = (data = loadLumenData()) => {
|
|
|
775
835
|
const text = [
|
|
776
836
|
'# Lumen design tokens',
|
|
777
837
|
`Theme attribute: ${tokens.themeAttribute} (values: light, dark)`,
|
|
838
|
+
`Appearance presets: ${tokens.presets.names.join(', ')} via ${tokens.presets.attribute}; scheme via ${tokens.presets.schemeAttribute}.`,
|
|
839
|
+
'Studio follows the neutral PostLens appearance. Glass is explicit on supporting surfaces; native adapters use platform materials or opaque fallbacks.',
|
|
840
|
+
'',
|
|
841
|
+
'## Spacing scale (px at the default 16px root; CSS uses rem)',
|
|
842
|
+
Object.entries(tokens.spacing).map(([name, value]) => `- ${name}: ${value}px; --ui-space-${name}`).join('\n'),
|
|
843
|
+
'',
|
|
844
|
+
'## Content flow roles',
|
|
845
|
+
Object.entries(tokens.spacingRoles).map(([role, token]) => `- ${role}: ${token} (${spacingValue(tokens, token)}px); --ui-space-${role}`).join('\n'),
|
|
846
|
+
'Stack and Grid own sibling gaps; surfaces own padding; Field owns control feedback spacing.',
|
|
847
|
+
'Use related, group or section for Stack/Grid gap. Use inset for surface padding, not a gap prop.',
|
|
778
848
|
'',
|
|
779
849
|
'## Semantic token names (use as `text-ink`, `bg-surface`, `border-line`, etc.)',
|
|
780
850
|
tokens.semantic.map(token => `- ${token}`).join('\n'),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@santi020k/lumen-mcp",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -33,16 +33,19 @@
|
|
|
33
33
|
"lumen-mcp-http": "./bin/lumen-mcp-http.mjs"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@modelcontextprotocol/
|
|
36
|
+
"@modelcontextprotocol/express": "^2.0.1",
|
|
37
|
+
"@modelcontextprotocol/server": "^2.2.0",
|
|
38
|
+
"express": "^5.2.1",
|
|
37
39
|
"zod": "^4.6.5"
|
|
38
40
|
},
|
|
39
41
|
"devDependencies": {
|
|
40
42
|
"@astrojs/compiler": "^4.0.0",
|
|
43
|
+
"@modelcontextprotocol/client": "^2.2.0",
|
|
41
44
|
"@types/express": "^5.0.6",
|
|
42
|
-
"@types/node": "^26.6.
|
|
43
|
-
"@vitest/coverage-v8": "^5.0.
|
|
45
|
+
"@types/node": "^26.6.4",
|
|
46
|
+
"@vitest/coverage-v8": "^5.0.3",
|
|
44
47
|
"typescript": "~6.0.3",
|
|
45
|
-
"vitest": "^5.0.
|
|
48
|
+
"vitest": "^5.0.3"
|
|
46
49
|
},
|
|
47
50
|
"engines": {
|
|
48
51
|
"node": ">=20.20.0"
|