@castandcrew/spotlight-mcp 0.1.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 +265 -0
- package/data/index.json +1541 -0
- package/dist/data/loader.d.ts +3 -0
- package/dist/data/loader.js +19 -0
- package/dist/data/loader.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.js +33 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/ask_spotlight.d.ts +2 -0
- package/dist/tools/ask_spotlight.js +122 -0
- package/dist/tools/ask_spotlight.js.map +1 -0
- package/dist/tools/get_component.d.ts +2 -0
- package/dist/tools/get_component.js +19 -0
- package/dist/tools/get_component.js.map +1 -0
- package/dist/tools/get_migration_guide.d.ts +2 -0
- package/dist/tools/get_migration_guide.js +19 -0
- package/dist/tools/get_migration_guide.js.map +1 -0
- package/dist/tools/get_pattern.d.ts +2 -0
- package/dist/tools/get_pattern.js +28 -0
- package/dist/tools/get_pattern.js.map +1 -0
- package/dist/tools/get_recipe.d.ts +2 -0
- package/dist/tools/get_recipe.js +72 -0
- package/dist/tools/get_recipe.js.map +1 -0
- package/dist/tools/get_token.d.ts +2 -0
- package/dist/tools/get_token.js +18 -0
- package/dist/tools/get_token.js.map +1 -0
- package/dist/tools/identify_pattern.d.ts +2 -0
- package/dist/tools/identify_pattern.js +96 -0
- package/dist/tools/identify_pattern.js.map +1 -0
- package/dist/tools/list_deprecated.d.ts +2 -0
- package/dist/tools/list_deprecated.js +10 -0
- package/dist/tools/list_deprecated.js.map +1 -0
- package/dist/tools/search_components.d.ts +2 -0
- package/dist/tools/search_components.js +27 -0
- package/dist/tools/search_components.js.map +1 -0
- package/dist/tools/search_tokens.d.ts +2 -0
- package/dist/tools/search_tokens.js +33 -0
- package/dist/tools/search_tokens.js.map +1 -0
- package/dist/tools/search_utility_classes.d.ts +2 -0
- package/dist/tools/search_utility_classes.js +37 -0
- package/dist/tools/search_utility_classes.js.map +1 -0
- package/dist/tools/validate_usage.d.ts +2 -0
- package/dist/tools/validate_usage.js +42 -0
- package/dist/tools/validate_usage.js.map +1 -0
- package/dist/transports/http.d.ts +1 -0
- package/dist/transports/http.js +71 -0
- package/dist/transports/http.js.map +1 -0
- package/dist/transports/stdio.d.ts +1 -0
- package/dist/transports/stdio.js +9 -0
- package/dist/transports/stdio.js.map +1 -0
- package/dist/types.d.ts +120 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { readFileSync } from 'fs';
|
|
2
|
+
import { resolve, dirname } from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
5
|
+
let cached = null;
|
|
6
|
+
export function loadIndex() {
|
|
7
|
+
if (cached)
|
|
8
|
+
return cached;
|
|
9
|
+
const indexPath = process.env.SPOTLIGHT_INDEX_PATH
|
|
10
|
+
? resolve(process.env.SPOTLIGHT_INDEX_PATH)
|
|
11
|
+
: resolve(__dirname, '../../data/index.json');
|
|
12
|
+
cached = JSON.parse(readFileSync(indexPath, 'utf-8'));
|
|
13
|
+
return cached;
|
|
14
|
+
}
|
|
15
|
+
export function reloadIndex() {
|
|
16
|
+
cached = null;
|
|
17
|
+
return loadIndex();
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/data/loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAGpC,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAE1D,IAAI,MAAM,GAA0B,IAAI,CAAC;AAEzC,MAAM,UAAU,SAAS;IACvB,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAC1B,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB;QAChD,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;QAC3C,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,uBAAuB,CAAC,CAAC;IAChD,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAmB,CAAC;IACxE,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,MAAM,GAAG,IAAI,CAAC;IACd,OAAO,SAAS,EAAE,CAAC;AACrB,CAAC"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { runStdio } from './transports/stdio.js';
|
|
3
|
+
import { runHttp } from './transports/http.js';
|
|
4
|
+
const args = process.argv.slice(2);
|
|
5
|
+
if (args.includes('--http')) {
|
|
6
|
+
const portArg = args.find(a => a.startsWith('--port='));
|
|
7
|
+
const port = portArg ? Number(portArg.split('=')[1]) : undefined;
|
|
8
|
+
runHttp(port).catch(console.error);
|
|
9
|
+
}
|
|
10
|
+
else {
|
|
11
|
+
runStdio().catch(console.error);
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAE/C,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAEnC,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;IAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC;IACxD,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACjE,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AACrC,CAAC;KAAM,CAAC;IACN,QAAQ,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAClC,CAAC"}
|
package/dist/server.d.ts
ADDED
package/dist/server.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { registerGetComponent } from './tools/get_component.js';
|
|
3
|
+
import { registerSearchComponents } from './tools/search_components.js';
|
|
4
|
+
import { registerGetToken } from './tools/get_token.js';
|
|
5
|
+
import { registerSearchTokens } from './tools/search_tokens.js';
|
|
6
|
+
import { registerGetMigrationGuide } from './tools/get_migration_guide.js';
|
|
7
|
+
import { registerGetPattern } from './tools/get_pattern.js';
|
|
8
|
+
import { registerValidateUsage } from './tools/validate_usage.js';
|
|
9
|
+
import { registerListDeprecated } from './tools/list_deprecated.js';
|
|
10
|
+
import { registerSearchUtilityClasses } from './tools/search_utility_classes.js';
|
|
11
|
+
import { registerAskSpotlight } from './tools/ask_spotlight.js';
|
|
12
|
+
import { registerIdentifyPattern } from './tools/identify_pattern.js';
|
|
13
|
+
import { registerGetRecipe } from './tools/get_recipe.js';
|
|
14
|
+
export function createServer() {
|
|
15
|
+
const server = new McpServer({
|
|
16
|
+
name: 'spotlight-mcp',
|
|
17
|
+
version: '0.1.0',
|
|
18
|
+
});
|
|
19
|
+
registerGetComponent(server);
|
|
20
|
+
registerSearchComponents(server);
|
|
21
|
+
registerGetToken(server);
|
|
22
|
+
registerSearchTokens(server);
|
|
23
|
+
registerGetMigrationGuide(server);
|
|
24
|
+
registerGetPattern(server);
|
|
25
|
+
registerValidateUsage(server);
|
|
26
|
+
registerListDeprecated(server);
|
|
27
|
+
registerSearchUtilityClasses(server);
|
|
28
|
+
registerAskSpotlight(server);
|
|
29
|
+
registerIdentifyPattern(server);
|
|
30
|
+
registerGetRecipe(server);
|
|
31
|
+
return server;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAC;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,4BAA4B,EAAE,MAAM,mCAAmC,CAAC;AACjF,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AACtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE1D,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,eAAe;QACrB,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC7B,wBAAwB,CAAC,MAAM,CAAC,CAAC;IACjC,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACzB,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC7B,yBAAyB,CAAC,MAAM,CAAC,CAAC;IAClC,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAC3B,qBAAqB,CAAC,MAAM,CAAC,CAAC;IAC9B,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC/B,4BAA4B,CAAC,MAAM,CAAC,CAAC;IACrC,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC7B,uBAAuB,CAAC,MAAM,CAAC,CAAC;IAChC,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAE1B,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import Fuse from 'fuse.js';
|
|
3
|
+
import { loadIndex } from '../data/loader.js';
|
|
4
|
+
const EXCERPT = 8000;
|
|
5
|
+
const STOPWORDS = new Set([
|
|
6
|
+
'how', 'should', 'shall', 'would', 'could', 'can', 'the', 'and', 'for', 'with', 'what',
|
|
7
|
+
'when', 'which', 'use', 'used', 'using', 'do', 'does', 'are', 'is', 'be', 'to', 'of', 'in',
|
|
8
|
+
'on', 'or', 'my', 'me', 'it', 'this', 'that', 'an', 'a', 'i', 'about', 'best', 'way', 'ways',
|
|
9
|
+
]);
|
|
10
|
+
function keywords(question) {
|
|
11
|
+
const kw = question
|
|
12
|
+
.toLowerCase()
|
|
13
|
+
.replace(/[^a-z0-9\s-]/g, ' ')
|
|
14
|
+
.split(/\s+/)
|
|
15
|
+
.filter(w => w.length >= 3 && !STOPWORDS.has(w));
|
|
16
|
+
return kw.length ? kw.join(' ') : question;
|
|
17
|
+
}
|
|
18
|
+
export function registerAskSpotlight(server) {
|
|
19
|
+
server.tool('ask_spotlight', 'Answer a Spotlight Design System question in ONE call. The default entry point for any ' +
|
|
20
|
+
'natural-language question about Spotlight — which component to use, when/how to use it, ' +
|
|
21
|
+
'props, design tokens, button labeling/placement, MUI migration, etc. Searches components, ' +
|
|
22
|
+
'usage patterns/guides, and tokens, and returns the most relevant material consolidated so ' +
|
|
23
|
+
'no follow-up calls are needed for a typical answer.', {
|
|
24
|
+
question: z
|
|
25
|
+
.string()
|
|
26
|
+
.describe('A natural-language question, e.g. "how should I label and place buttons?"'),
|
|
27
|
+
}, async ({ question }) => {
|
|
28
|
+
const index = loadIndex();
|
|
29
|
+
const query = keywords(question);
|
|
30
|
+
// Patterns: title/id/components are weighted far above content so a guide that's
|
|
31
|
+
// *about* the topic beats a big rules doc that merely mentions the word.
|
|
32
|
+
const patternFuse = new Fuse(index.patterns, {
|
|
33
|
+
keys: [
|
|
34
|
+
{ name: 'title', weight: 3 },
|
|
35
|
+
{ name: 'id', weight: 2 },
|
|
36
|
+
{ name: 'components', weight: 2 },
|
|
37
|
+
{ name: 'description', weight: 1 },
|
|
38
|
+
{ name: 'content', weight: 0.2 },
|
|
39
|
+
],
|
|
40
|
+
threshold: 0.45,
|
|
41
|
+
ignoreLocation: true,
|
|
42
|
+
});
|
|
43
|
+
const guidance = patternFuse.search(query, { limit: 3 }).map(r => {
|
|
44
|
+
const p = r.item;
|
|
45
|
+
const truncated = p.content.length > EXCERPT;
|
|
46
|
+
return {
|
|
47
|
+
id: p.id,
|
|
48
|
+
title: p.title,
|
|
49
|
+
category: p.category,
|
|
50
|
+
excerpt: truncated
|
|
51
|
+
? `${p.content.slice(0, EXCERPT)}\n… (call get_pattern "${p.id}" for the full guide)`
|
|
52
|
+
: p.content,
|
|
53
|
+
};
|
|
54
|
+
});
|
|
55
|
+
// Components: name/description/category.
|
|
56
|
+
const compFuse = new Fuse(index.components, {
|
|
57
|
+
keys: [{ name: 'name', weight: 3 }, { name: 'category', weight: 1 }, { name: 'description', weight: 1 }],
|
|
58
|
+
threshold: 0.4,
|
|
59
|
+
ignoreLocation: true,
|
|
60
|
+
});
|
|
61
|
+
const components = compFuse.search(query, { limit: 3 }).map(r => {
|
|
62
|
+
const c = r.item;
|
|
63
|
+
return {
|
|
64
|
+
name: c.name,
|
|
65
|
+
category: c.category,
|
|
66
|
+
status: c.status,
|
|
67
|
+
description: c.description,
|
|
68
|
+
propsCount: c.props.length,
|
|
69
|
+
examples: c.stories.filter(s => s.code).slice(0, 3).map(s => s.code),
|
|
70
|
+
relatedPatterns: c.relatedPatterns ?? [],
|
|
71
|
+
};
|
|
72
|
+
});
|
|
73
|
+
// Stem the keywords and match short-field data deterministically — fuzzy search
|
|
74
|
+
// is unreliable on token/class names ("spacing" → "--space-md", etc.).
|
|
75
|
+
const stems = query.split(/\s+/).filter(w => w.length >= 3).map(w => w.replace(/(ings?|es|s)$/, ''));
|
|
76
|
+
const matches = (text) => {
|
|
77
|
+
const t = text.toLowerCase();
|
|
78
|
+
return stems.some(s => s.length >= 3 && t.includes(s));
|
|
79
|
+
};
|
|
80
|
+
// Tokens — when the question is token/style-shaped.
|
|
81
|
+
const tokenIntent = /token|colou?r|spac|gap|margin|pad|radius|radii|typograph|font|weight|text|shadow|elevation|\bsize/i.test(question);
|
|
82
|
+
const tokens = tokenIntent
|
|
83
|
+
? index.tokens
|
|
84
|
+
.filter(t => matches(`${t.name} ${t.category} ${t.useCase ?? ''}`))
|
|
85
|
+
.slice(0, 8)
|
|
86
|
+
.map(t => ({ name: t.name, value: t.value, useCase: t.useCase, layer: t.layer }))
|
|
87
|
+
: [];
|
|
88
|
+
// Utility classes — when the question mentions classes/utilities/layout.
|
|
89
|
+
const classIntent = /class|utilit|grid|flex|column|align|justif|spotlight_|body|heading|display|label/i.test(question);
|
|
90
|
+
const utilityClasses = classIntent
|
|
91
|
+
? index.utilityClasses
|
|
92
|
+
.filter(c => matches(`${c.name} ${c.category} ${c.subCategory ?? ''}`))
|
|
93
|
+
.slice(0, 8)
|
|
94
|
+
.map(c => c.name)
|
|
95
|
+
: [];
|
|
96
|
+
// Migration — when the question is about MUI/migrating; match the component, not "mui".
|
|
97
|
+
const wantsMigration = /\b(mui|material[-\s]?ui|migrat|reskin|replace)\b/i.test(question);
|
|
98
|
+
const generic = new Set(['mui', 'material', 'materialui', 'migrate', 'migrat', 'migration', 'reskin', 'replace', 'component']);
|
|
99
|
+
const migStems = stems.filter(s => !generic.has(s));
|
|
100
|
+
const migration = wantsMigration
|
|
101
|
+
? index.migration
|
|
102
|
+
.filter(m => migStems.some(s => `${m.fromComponent} ${m.toComponent}`.toLowerCase().includes(s)))
|
|
103
|
+
.slice(0, 4)
|
|
104
|
+
.map(m => ({ from: m.fromComponent, to: m.toComponent }))
|
|
105
|
+
: [];
|
|
106
|
+
const payload = {
|
|
107
|
+
question,
|
|
108
|
+
components,
|
|
109
|
+
guidance,
|
|
110
|
+
...(tokens.length ? { tokens } : {}),
|
|
111
|
+
...(utilityClasses.length ? { utilityClasses } : {}),
|
|
112
|
+
...(migration.length ? { migration } : {}),
|
|
113
|
+
hint: 'This is the consolidated answer context. For a full component (all props) call ' +
|
|
114
|
+
'get_component; for a full guide call get_pattern with the id; for a migration guide ' +
|
|
115
|
+
'call get_migration_guide with the "from" value.',
|
|
116
|
+
};
|
|
117
|
+
return {
|
|
118
|
+
content: [{ type: 'text', text: JSON.stringify(payload, null, 2) }],
|
|
119
|
+
};
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=ask_spotlight.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ask_spotlight.js","sourceRoot":"","sources":["../../src/tools/ask_spotlight.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { loadIndex } from '../data/loader.js';
|
|
3
|
+
export function registerGetComponent(server) {
|
|
4
|
+
server.tool('get_component', 'Get full details for a Spotlight component: props, usage guidelines, examples, related components, and design tokens.', { name: z.string().describe('Component name, e.g. "Button", "TextField"') }, async ({ name }) => {
|
|
5
|
+
const index = loadIndex();
|
|
6
|
+
const component = index.components.find(c => c.name.toLowerCase() === name.toLowerCase() ||
|
|
7
|
+
c.id.toLowerCase() === name.toLowerCase());
|
|
8
|
+
if (!component) {
|
|
9
|
+
return {
|
|
10
|
+
content: [{ type: 'text', text: `Component "${name}" not found. Use search_components to find available components.` }],
|
|
11
|
+
isError: true,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
return {
|
|
15
|
+
content: [{ type: 'text', text: JSON.stringify(component, null, 2) }],
|
|
16
|
+
};
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=get_component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get_component.js","sourceRoot":"","sources":["../../src/tools/get_component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAG9C,MAAM,UAAU,oBAAoB,CAAC,MAAiB;IACpD,MAAM,CAAC,IAAI,CACT,eAAe,EACf,uHAAuH,EACvH,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,4CAA4C,CAAC,EAAE,EAC3E,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;QACjB,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;QAC1B,MAAM,SAAS,GAAG,KAAK,CAAC,UAAU,CAAC,IAAI,CACrC,CAAC,CAAC,EAAE,CACF,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,IAAI,CAAC,WAAW,EAAE;YAC3C,CAAC,CAAC,EAAE,CAAC,WAAW,EAAE,KAAK,IAAI,CAAC,WAAW,EAAE,CAC5C,CAAC;QACF,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,cAAc,IAAI,kEAAkE,EAAE,CAAC;gBAChI,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;QACD,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;SAC/E,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { loadIndex } from '../data/loader.js';
|
|
3
|
+
export function registerGetMigrationGuide(server) {
|
|
4
|
+
server.tool('get_migration_guide', 'Get the migration guide from a MUI or deprecated Spotlight component to its current equivalent, including prop mapping.', { fromComponent: z.string().describe('Source component, e.g. "MUI/Button", "ComboBox"') }, async ({ fromComponent }) => {
|
|
5
|
+
const index = loadIndex();
|
|
6
|
+
const guide = index.migration.find(m => m.fromComponent.toLowerCase() === fromComponent.toLowerCase());
|
|
7
|
+
if (!guide) {
|
|
8
|
+
const available = index.migration.map(m => m.fromComponent);
|
|
9
|
+
return {
|
|
10
|
+
content: [{ type: 'text', text: `No migration guide found for "${fromComponent}".\n\nAvailable: ${available.join(', ')}` }],
|
|
11
|
+
isError: true,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
return {
|
|
15
|
+
content: [{ type: 'text', text: JSON.stringify(guide, null, 2) }],
|
|
16
|
+
};
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=get_migration_guide.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get_migration_guide.js","sourceRoot":"","sources":["../../src/tools/get_migration_guide.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAG9C,MAAM,UAAU,yBAAyB,CAAC,MAAiB;IACzD,MAAM,CAAC,IAAI,CACT,qBAAqB,EACrB,yHAAyH,EACzH,EAAE,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iDAAiD,CAAC,EAAE,EACzF,KAAK,EAAE,EAAE,aAAa,EAAE,EAAE,EAAE;QAC1B,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;QAC1B,MAAM,KAAK,GAAG,KAAK,CAAC,SAAS,CAAC,IAAI,CAChC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,WAAW,EAAE,KAAK,aAAa,CAAC,WAAW,EAAE,CACnE,CAAC;QACF,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;YAC5D,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,iCAAiC,aAAa,oBAAoB,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;gBACpI,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;QACD,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;SAC3E,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import Fuse from 'fuse.js';
|
|
3
|
+
import { loadIndex } from '../data/loader.js';
|
|
4
|
+
export function registerGetPattern(server) {
|
|
5
|
+
server.tool('get_pattern', 'Get a Spotlight usage pattern: when to use which component, comparisons between alternatives, and code examples.', { query: z.string().describe('Pattern name or topic, e.g. "overlay", "modal vs drawer", "filtering", "pagination"') }, async ({ query }) => {
|
|
6
|
+
const index = loadIndex();
|
|
7
|
+
if (!index.patterns.length) {
|
|
8
|
+
return {
|
|
9
|
+
content: [{ type: 'text', text: 'No patterns available in the index yet.' }],
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
const fuse = new Fuse(index.patterns, {
|
|
13
|
+
keys: ['title', 'description', 'id', 'components'],
|
|
14
|
+
threshold: 0.4,
|
|
15
|
+
});
|
|
16
|
+
const results = fuse.search(query, { limit: 3 });
|
|
17
|
+
if (!results.length) {
|
|
18
|
+
const available = index.patterns.map(p => p.title);
|
|
19
|
+
return {
|
|
20
|
+
content: [{ type: 'text', text: `No patterns found for "${query}".\n\nAvailable patterns: ${available.join(', ')}` }],
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
return {
|
|
24
|
+
content: [{ type: 'text', text: JSON.stringify(results[0].item, null, 2) }],
|
|
25
|
+
};
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=get_pattern.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get_pattern.js","sourceRoot":"","sources":["../../src/tools/get_pattern.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,IAAI,MAAM,SAAS,CAAC;AAC3B,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAG9C,MAAM,UAAU,kBAAkB,CAAC,MAAiB;IAClD,MAAM,CAAC,IAAI,CACT,aAAa,EACb,kHAAkH,EAClH,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,qFAAqF,CAAC,EAAE,EACrH,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;QAClB,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;QAC1B,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;YAC3B,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,yCAAyC,EAAE,CAAC;aACtF,CAAC;QACJ,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE;YACpC,IAAI,EAAE,CAAC,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,YAAY,CAAC;YAClD,SAAS,EAAE,GAAG;SACf,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;QACjD,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YACpB,MAAM,SAAS,GAAG,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YACnD,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,0BAA0B,KAAK,6BAA6B,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;aAC/H,CAAC;QACJ,CAAC;QACD,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;SACrF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import Fuse from 'fuse.js';
|
|
3
|
+
import { loadIndex } from '../data/loader.js';
|
|
4
|
+
export function registerGetRecipe(server) {
|
|
5
|
+
server.tool('get_recipe', 'Get the implementation recipe for a Spotlight pattern — concise, AI-consumable instructions ' +
|
|
6
|
+
'for building the pattern correctly. Call this after identify_pattern confirms which pattern ' +
|
|
7
|
+
'applies. Returns component structure, critical props, token usage, a complete implementation ' +
|
|
8
|
+
'example, and a validation checklist.', {
|
|
9
|
+
patternId: z
|
|
10
|
+
.string()
|
|
11
|
+
.describe('Pattern ID from identify_pattern, e.g. "data-display-table-pattern" or "filter-chips-pattern"'),
|
|
12
|
+
}, async ({ patternId }) => {
|
|
13
|
+
const index = loadIndex();
|
|
14
|
+
const recipes = index.patterns.filter(p => p.category === 'recipe');
|
|
15
|
+
// 1. Exact id match within recipes.
|
|
16
|
+
const exact = recipes.find(p => p.id === patternId);
|
|
17
|
+
if (exact) {
|
|
18
|
+
return {
|
|
19
|
+
content: [
|
|
20
|
+
{
|
|
21
|
+
type: 'text',
|
|
22
|
+
text: JSON.stringify({ id: exact.id, title: exact.title, content: exact.content }, null, 2),
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
// 2. Fuzzy match against recipe titles and ids.
|
|
28
|
+
if (recipes.length > 0) {
|
|
29
|
+
const fuse = new Fuse(recipes, {
|
|
30
|
+
keys: [
|
|
31
|
+
{ name: 'id', weight: 3 },
|
|
32
|
+
{ name: 'title', weight: 2 },
|
|
33
|
+
{ name: 'description', weight: 1 },
|
|
34
|
+
],
|
|
35
|
+
threshold: 0.4,
|
|
36
|
+
ignoreLocation: true,
|
|
37
|
+
includeScore: true,
|
|
38
|
+
});
|
|
39
|
+
const results = fuse.search(patternId, { limit: 1 });
|
|
40
|
+
if (results.length) {
|
|
41
|
+
const best = results[0].item;
|
|
42
|
+
return {
|
|
43
|
+
content: [
|
|
44
|
+
{
|
|
45
|
+
type: 'text',
|
|
46
|
+
text: JSON.stringify({
|
|
47
|
+
id: best.id,
|
|
48
|
+
title: best.title,
|
|
49
|
+
content: best.content,
|
|
50
|
+
note: `No exact recipe for "${patternId}". Closest match: "${best.title}" (${best.id}).`,
|
|
51
|
+
}, null, 2),
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// 3. No recipe exists — direct caller to get_pattern.
|
|
58
|
+
return {
|
|
59
|
+
content: [
|
|
60
|
+
{
|
|
61
|
+
type: 'text',
|
|
62
|
+
text: JSON.stringify({
|
|
63
|
+
notFound: true,
|
|
64
|
+
patternId,
|
|
65
|
+
hint: `No implementation recipe exists for "${patternId}". Try calling get_pattern("${patternId}") for conceptual guidance, or call identify_pattern with a use-case description to find the right pattern.`,
|
|
66
|
+
}, null, 2),
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
};
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=get_recipe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get_recipe.js","sourceRoot":"","sources":["../../src/tools/get_recipe.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { loadIndex } from '../data/loader.js';
|
|
3
|
+
export function registerGetToken(server) {
|
|
4
|
+
server.tool('get_token', 'Get details for a Spotlight design token: its value, category, and which components use it.', { name: z.string().describe('Token name, e.g. "--space-md", "--color-background-positive"') }, async ({ name }) => {
|
|
5
|
+
const index = loadIndex();
|
|
6
|
+
const token = index.tokens.find(t => t.name.toLowerCase() === name.toLowerCase());
|
|
7
|
+
if (!token) {
|
|
8
|
+
return {
|
|
9
|
+
content: [{ type: 'text', text: `Token "${name}" not found. Use search_tokens to find available tokens.` }],
|
|
10
|
+
isError: true,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
return {
|
|
14
|
+
content: [{ type: 'text', text: JSON.stringify(token, null, 2) }],
|
|
15
|
+
};
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=get_token.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get_token.js","sourceRoot":"","sources":["../../src/tools/get_token.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAG9C,MAAM,UAAU,gBAAgB,CAAC,MAAiB;IAChD,MAAM,CAAC,IAAI,CACT,WAAW,EACX,6FAA6F,EAC7F,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,8DAA8D,CAAC,EAAE,EAC7F,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;QACjB,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;QAC1B,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAC7B,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,IAAI,CAAC,WAAW,EAAE,CACjD,CAAC;QACF,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,UAAU,IAAI,0DAA0D,EAAE,CAAC;gBACpH,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;QACD,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;SAC3E,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import Fuse from 'fuse.js';
|
|
3
|
+
import { loadIndex } from '../data/loader.js';
|
|
4
|
+
const HIGH_THRESHOLD = 0.25;
|
|
5
|
+
const MEDIUM_THRESHOLD = 0.42;
|
|
6
|
+
const SEARCH_THRESHOLD = 0.55;
|
|
7
|
+
function confidence(score) {
|
|
8
|
+
if (score < HIGH_THRESHOLD)
|
|
9
|
+
return 'high';
|
|
10
|
+
if (score < MEDIUM_THRESHOLD)
|
|
11
|
+
return 'medium';
|
|
12
|
+
return 'low';
|
|
13
|
+
}
|
|
14
|
+
function firstSentence(text) {
|
|
15
|
+
const trimmed = text.replace(/\s+/g, ' ').trim();
|
|
16
|
+
const end = trimmed.search(/[.!?]/);
|
|
17
|
+
return end > 0 ? trimmed.slice(0, end + 1) : trimmed.slice(0, 150);
|
|
18
|
+
}
|
|
19
|
+
export function registerIdentifyPattern(server) {
|
|
20
|
+
server.tool('identify_pattern', 'Identify the correct Spotlight pattern for a use case. Call this when you need to know ' +
|
|
21
|
+
'which pattern applies before implementing — provide a natural-language description of ' +
|
|
22
|
+
'what you are building. Returns ranked pattern matches with confidence scores and whether ' +
|
|
23
|
+
'a recipe is available.', {
|
|
24
|
+
useCase: z
|
|
25
|
+
.string()
|
|
26
|
+
.describe('Natural-language description of the UI you are building, e.g. "a table of timecards with sorting and row selection"'),
|
|
27
|
+
components: z
|
|
28
|
+
.array(z.string())
|
|
29
|
+
.optional()
|
|
30
|
+
.describe('Spotlight component names already in scope (optional), e.g. ["GridTable", "Chip"]'),
|
|
31
|
+
}, async ({ useCase, components }) => {
|
|
32
|
+
const index = loadIndex();
|
|
33
|
+
// Pool: selection guides + recipe files only.
|
|
34
|
+
const pool = index.patterns.filter(p => p.category === 'selection' || p.category === 'recipe');
|
|
35
|
+
// Build recipe id set for recipeAvailable lookup.
|
|
36
|
+
const recipeIds = new Set(index.patterns.filter(p => p.category === 'recipe').map(p => p.id));
|
|
37
|
+
const recipeAvailable = (matchId) => {
|
|
38
|
+
if (recipeIds.has(matchId))
|
|
39
|
+
return true;
|
|
40
|
+
// A selection guide may have a corresponding recipe whose id shares a common root.
|
|
41
|
+
const root = matchId.replace(/-pattern$/, '');
|
|
42
|
+
for (const rid of recipeIds) {
|
|
43
|
+
if (rid.startsWith(root) || rid === root)
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
return false;
|
|
47
|
+
};
|
|
48
|
+
// Boost query with provided component names so component-bearing queries
|
|
49
|
+
// surface patterns that mention those components.
|
|
50
|
+
const componentBoost = components?.length ? components.join(' ') + ' ' : '';
|
|
51
|
+
const query = componentBoost + useCase;
|
|
52
|
+
const fuse = new Fuse(pool, {
|
|
53
|
+
keys: [
|
|
54
|
+
{ name: 'title', weight: 4 },
|
|
55
|
+
{ name: 'id', weight: 3 },
|
|
56
|
+
{ name: 'components', weight: 2 },
|
|
57
|
+
{ name: 'description', weight: 1.5 },
|
|
58
|
+
{ name: 'content', weight: 0.1 },
|
|
59
|
+
],
|
|
60
|
+
threshold: SEARCH_THRESHOLD,
|
|
61
|
+
ignoreLocation: true,
|
|
62
|
+
includeScore: true,
|
|
63
|
+
});
|
|
64
|
+
const results = fuse.search(query, { limit: 3 });
|
|
65
|
+
if (!results.length) {
|
|
66
|
+
// Suggest component names tangentially related to the use case.
|
|
67
|
+
const compFuse = new Fuse(index.components, {
|
|
68
|
+
keys: [{ name: 'name', weight: 2 }, { name: 'description', weight: 1 }],
|
|
69
|
+
threshold: 0.4,
|
|
70
|
+
ignoreLocation: true,
|
|
71
|
+
});
|
|
72
|
+
const suggestions = compFuse
|
|
73
|
+
.search(useCase, { limit: 5 })
|
|
74
|
+
.map(r => r.item.name);
|
|
75
|
+
return {
|
|
76
|
+
content: [
|
|
77
|
+
{
|
|
78
|
+
type: 'text',
|
|
79
|
+
text: JSON.stringify({ noMatch: true, suggestions }, null, 2),
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
const matches = results.map(r => ({
|
|
85
|
+
id: r.item.id,
|
|
86
|
+
title: r.item.title,
|
|
87
|
+
confidence: confidence(r.score ?? 1),
|
|
88
|
+
recipeAvailable: recipeAvailable(r.item.id),
|
|
89
|
+
hint: firstSentence(r.item.description),
|
|
90
|
+
}));
|
|
91
|
+
return {
|
|
92
|
+
content: [{ type: 'text', text: JSON.stringify({ matches }, null, 2) }],
|
|
93
|
+
};
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=identify_pattern.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identify_pattern.js","sourceRoot":"","sources":["../../src/tools/identify_pattern.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { loadIndex } from '../data/loader.js';
|
|
2
|
+
export function registerListDeprecated(server) {
|
|
3
|
+
server.tool('list_deprecated', 'List all deprecated and legacy Spotlight components with their replacements and removal dates.', {}, async () => {
|
|
4
|
+
const index = loadIndex();
|
|
5
|
+
return {
|
|
6
|
+
content: [{ type: 'text', text: JSON.stringify(index.deprecated, null, 2) }],
|
|
7
|
+
};
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=list_deprecated.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list_deprecated.js","sourceRoot":"","sources":["../../src/tools/list_deprecated.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAG9C,MAAM,UAAU,sBAAsB,CAAC,MAAiB;IACtD,MAAM,CAAC,IAAI,CACT,iBAAiB,EACjB,gGAAgG,EAChG,EAAE,EACF,KAAK,IAAI,EAAE;QACT,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;QAC1B,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;SACtF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import Fuse from 'fuse.js';
|
|
3
|
+
import { loadIndex } from '../data/loader.js';
|
|
4
|
+
export function registerSearchComponents(server) {
|
|
5
|
+
server.tool('search_components', 'Search Spotlight components by name, description, or category. Returns a ranked list of matches.', {
|
|
6
|
+
query: z.string().describe('Search query, e.g. "date picker", "dropdown", "inputs"'),
|
|
7
|
+
limit: z.number().optional().default(10).describe('Max results to return (default 10)'),
|
|
8
|
+
}, async ({ query, limit }) => {
|
|
9
|
+
const index = loadIndex();
|
|
10
|
+
const fuse = new Fuse(index.components, {
|
|
11
|
+
keys: ['name', 'description', 'category', 'id'],
|
|
12
|
+
threshold: 0.4,
|
|
13
|
+
includeScore: true,
|
|
14
|
+
});
|
|
15
|
+
const results = fuse.search(query, { limit }).map(r => ({
|
|
16
|
+
name: r.item.name,
|
|
17
|
+
category: r.item.category,
|
|
18
|
+
status: r.item.status,
|
|
19
|
+
description: r.item.description,
|
|
20
|
+
score: r.score,
|
|
21
|
+
}));
|
|
22
|
+
return {
|
|
23
|
+
content: [{ type: 'text', text: JSON.stringify(results, null, 2) }],
|
|
24
|
+
};
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=search_components.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search_components.js","sourceRoot":"","sources":["../../src/tools/search_components.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,IAAI,MAAM,SAAS,CAAC;AAC3B,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAG9C,MAAM,UAAU,wBAAwB,CAAC,MAAiB;IACxD,MAAM,CAAC,IAAI,CACT,mBAAmB,EACnB,kGAAkG,EAClG;QACE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,wDAAwD,CAAC;QACpF,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,oCAAoC,CAAC;KACxF,EACD,KAAK,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE;QACzB,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;QAC1B,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE;YACtC,IAAI,EAAE,CAAC,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,IAAI,CAAC;YAC/C,SAAS,EAAE,GAAG;YACd,YAAY,EAAE,IAAI;SACnB,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YACtD,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI;YACjB,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ;YACzB,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM;YACrB,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW;YAC/B,KAAK,EAAE,CAAC,CAAC,KAAK;SACf,CAAC,CAAC,CAAC;QACJ,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;SAC7E,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
|