@castandcrew/spotlight-mcp 0.1.3 → 0.1.4
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 +137 -16
- package/data/index.json +56002 -1197
- package/dist/data/health.d.ts +33 -0
- package/dist/data/health.js +111 -0
- package/dist/data/health.js.map +1 -0
- package/dist/data/loader.d.ts +19 -0
- package/dist/data/loader.js +61 -4
- package/dist/data/loader.js.map +1 -1
- package/dist/lib/regex-safety.d.ts +14 -0
- package/dist/lib/regex-safety.js +34 -0
- package/dist/lib/regex-safety.js.map +1 -0
- package/dist/server.js +25 -1
- package/dist/server.js.map +1 -1
- package/dist/tools/_fuzzy.d.ts +49 -0
- package/dist/tools/_fuzzy.js +103 -0
- package/dist/tools/_fuzzy.js.map +1 -0
- package/dist/tools/_guard.d.ts +31 -0
- package/dist/tools/_guard.js +62 -0
- package/dist/tools/_guard.js.map +1 -0
- package/dist/tools/_synonyms.d.ts +1 -0
- package/dist/tools/_synonyms.js +28 -0
- package/dist/tools/_synonyms.js.map +1 -0
- package/dist/tools/ask_spotlight.js +67 -5
- package/dist/tools/ask_spotlight.js.map +1 -1
- package/dist/tools/get_component.js +14 -5
- package/dist/tools/get_component.js.map +1 -1
- package/dist/tools/get_migration_guide.js +4 -2
- package/dist/tools/get_migration_guide.js.map +1 -1
- package/dist/tools/get_pattern.js +22 -7
- package/dist/tools/get_pattern.js.map +1 -1
- package/dist/tools/get_recipe.js +4 -2
- package/dist/tools/get_recipe.js.map +1 -1
- package/dist/tools/get_token.js +5 -3
- package/dist/tools/get_token.js.map +1 -1
- package/dist/tools/identify_pattern.js +7 -5
- package/dist/tools/identify_pattern.js.map +1 -1
- package/dist/tools/list_deprecated.js +4 -2
- package/dist/tools/list_deprecated.js.map +1 -1
- package/dist/tools/search_components.js +9 -3
- package/dist/tools/search_components.js.map +1 -1
- package/dist/tools/search_tokens.js +8 -3
- package/dist/tools/search_tokens.js.map +1 -1
- package/dist/tools/search_utility_classes.js +4 -2
- package/dist/tools/search_utility_classes.js.map +1 -1
- package/dist/tools/validate_usage.js +25 -5
- package/dist/tools/validate_usage.js.map +1 -1
- package/dist/transports/http.js +21 -1
- package/dist/transports/http.js.map +1 -1
- package/dist/types.d.ts +8 -2
- package/dist/version.d.ts +1 -0
- package/dist/version.js +8 -0
- package/dist/version.js.map +1 -0
- package/package.json +10 -7
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Common design vocabulary that doesn't match Spotlight's own naming.
|
|
3
|
+
*
|
|
4
|
+
* Spotlight tokens/components use its own vocabulary ("attention", "Tag",
|
|
5
|
+
* "GridTable") that doesn't always match the generic UI words people
|
|
6
|
+
* naturally reach for ("warning", "badge", "table") — so
|
|
7
|
+
* `search_tokens("warning")` found nothing even though the `attention`
|
|
8
|
+
* tokens are exactly what "warning" means here (SPT-1828).
|
|
9
|
+
*
|
|
10
|
+
* `expandWithSynonyms` appends (never replaces) the Spotlight-vocabulary
|
|
11
|
+
* equivalent for each recognized word, so both the generic term and
|
|
12
|
+
* Spotlight's term are searched.
|
|
13
|
+
*/
|
|
14
|
+
const SYNONYMS = {
|
|
15
|
+
warning: 'attention',
|
|
16
|
+
error: 'critical',
|
|
17
|
+
success: 'positive',
|
|
18
|
+
badge: 'Tag Badge',
|
|
19
|
+
table: 'GridTable',
|
|
20
|
+
};
|
|
21
|
+
export function expandWithSynonyms(query) {
|
|
22
|
+
const words = query.toLowerCase().split(/\s+/).filter(Boolean);
|
|
23
|
+
const additions = words
|
|
24
|
+
.map(w => SYNONYMS[w])
|
|
25
|
+
.filter((v) => Boolean(v));
|
|
26
|
+
return additions.length ? `${query} ${additions.join(' ')}` : query;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=_synonyms.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_synonyms.js","sourceRoot":"","sources":["../../src/tools/_synonyms.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,QAAQ,GAA2B;IACvC,OAAO,EAAE,WAAW;IACpB,KAAK,EAAE,UAAU;IACjB,OAAO,EAAE,UAAU;IACnB,KAAK,EAAE,WAAW;IAClB,KAAK,EAAE,WAAW;CACnB,CAAC;AAEF,MAAM,UAAU,kBAAkB,CAAC,KAAa;IAC9C,MAAM,KAAK,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC/D,MAAM,SAAS,GAAG,KAAK;SACpB,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;SACrB,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1C,OAAO,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK,IAAI,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;AACtE,CAAC"}
|
|
@@ -1,16 +1,31 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import Fuse from 'fuse.js';
|
|
3
|
+
import { requireCollections } from './_guard.js';
|
|
3
4
|
import { loadIndex } from '../data/loader.js';
|
|
5
|
+
import { getIndexHealth, remedyFor } from '../data/health.js';
|
|
6
|
+
import { searchOrPerTerm } from './_fuzzy.js';
|
|
7
|
+
import { expandWithSynonyms } from './_synonyms.js';
|
|
4
8
|
const EXCERPT = 8000;
|
|
5
9
|
const STOPWORDS = new Set([
|
|
10
|
+
// English
|
|
6
11
|
'how', 'should', 'shall', 'would', 'could', 'can', 'the', 'and', 'for', 'with', 'what',
|
|
7
12
|
'when', 'which', 'use', 'used', 'using', 'do', 'does', 'are', 'is', 'be', 'to', 'of', 'in',
|
|
8
13
|
'on', 'or', 'my', 'me', 'it', 'this', 'that', 'an', 'a', 'i', 'about', 'best', 'way', 'ways',
|
|
14
|
+
// Spanish — questions from Spanish-speaking users otherwise reduce to nothing but
|
|
15
|
+
// function words after filtering, e.g. "¿Qué pauta ... aplica para decidir entre
|
|
16
|
+
// un botón primario y uno secundario?" (SPT-1828).
|
|
17
|
+
'qué', 'que', 'cómo', 'como', 'para', 'decidir', 'entre', 'cuál', 'cual', 'cuáles', 'cuales',
|
|
18
|
+
'uno', 'una', 'unos', 'unas', 'el', 'la', 'los', 'las', 'de', 'del', 'en', 'es', 'son',
|
|
19
|
+
'cuando', 'usar', 'aplica', 'con', 'sin', 'sobre', 'por', 'se', 'su', 'sus', 'al', 'lo',
|
|
20
|
+
'mejor', 'debo', 'debe', 'puedo', 'puede', 'y', 'o', 'un',
|
|
9
21
|
]);
|
|
10
22
|
function keywords(question) {
|
|
11
23
|
const kw = question
|
|
12
24
|
.toLowerCase()
|
|
13
|
-
|
|
25
|
+
// Keep accented Latin letters (á é í ó ú ñ ü) — stripping them mangles
|
|
26
|
+
// Spanish questions ("qué" -> "qu", "botón" -> "bot n") before stopword
|
|
27
|
+
// filtering even gets a chance to run (SPT-1828).
|
|
28
|
+
.replace(/[^a-z0-9À-ÿ\s-]/g, ' ')
|
|
14
29
|
.split(/\s+/)
|
|
15
30
|
.filter(w => w.length >= 3 && !STOPWORDS.has(w));
|
|
16
31
|
return kw.length ? kw.join(' ') : question;
|
|
@@ -25,8 +40,34 @@ export function registerAskSpotlight(server) {
|
|
|
25
40
|
.string()
|
|
26
41
|
.describe('A natural-language question, e.g. "how should I label and place buttons?"'),
|
|
27
42
|
}, async ({ question }) => {
|
|
43
|
+
// ask_spotlight is the documented default entry point, so it must degrade
|
|
44
|
+
// rather than refuse. Erroring here because one collection is empty throws
|
|
45
|
+
// away everything the index *does* have — with 0 components but 111 patterns
|
|
46
|
+
// there is still real guidance to give, and the model reaches for this tool
|
|
47
|
+
// first. Hard-fail only when there is nothing at all to answer with.
|
|
48
|
+
const health = getIndexHealth();
|
|
49
|
+
if (health.fatal || (health.counts.components === 0 && health.counts.patterns === 0)) {
|
|
50
|
+
const error = requireCollections('ask_spotlight', 'components', 'patterns');
|
|
51
|
+
if (error)
|
|
52
|
+
return error;
|
|
53
|
+
}
|
|
28
54
|
const index = loadIndex();
|
|
29
|
-
|
|
55
|
+
// Name the gaps up front so the model reports them instead of quietly
|
|
56
|
+
// presenting a partial answer as complete.
|
|
57
|
+
const missing = ['components', 'patterns', 'tokens', 'utilityClasses', 'migration']
|
|
58
|
+
.filter(c => health.counts[c] === 0);
|
|
59
|
+
// Desktop testing (R1, 2026-09-10) showed the header warning alone is easy to
|
|
60
|
+
// skip once there IS content to lead with: the model answered correctly from
|
|
61
|
+
// one pattern and never mentioned the index was broken — so the user would
|
|
62
|
+
// never learn to fix it. Repeat it per entry and in the hint.
|
|
63
|
+
const incompleteNote = missing.length
|
|
64
|
+
? `INCOMPLETE — the Spotlight index has no ${missing.join(', no ')}. ` +
|
|
65
|
+
'Tell the user this answer is partial and the index needs rebuilding.'
|
|
66
|
+
: null;
|
|
67
|
+
// Expand with Spotlight-vocabulary synonyms (e.g. "warning" -> "attention")
|
|
68
|
+
// before searching, so generic UI words find Spotlight's own naming —
|
|
69
|
+
// this is what search_tokens("warning") relies on too (SPT-1828).
|
|
70
|
+
const query = expandWithSynonyms(keywords(question));
|
|
30
71
|
// Patterns: title/id/components are weighted far above content so a guide that's
|
|
31
72
|
// *about* the topic beats a big rules doc that merely mentions the word.
|
|
32
73
|
const patternFuse = new Fuse(index.patterns, {
|
|
@@ -40,13 +81,14 @@ export function registerAskSpotlight(server) {
|
|
|
40
81
|
threshold: 0.45,
|
|
41
82
|
ignoreLocation: true,
|
|
42
83
|
});
|
|
43
|
-
const guidance = patternFuse
|
|
84
|
+
const guidance = searchOrPerTerm(patternFuse, query, 3).map(r => {
|
|
44
85
|
const p = r.item;
|
|
45
86
|
const truncated = p.content.length > EXCERPT;
|
|
46
87
|
return {
|
|
47
88
|
id: p.id,
|
|
48
89
|
title: p.title,
|
|
49
90
|
category: p.category,
|
|
91
|
+
...(incompleteNote ? { incomplete: incompleteNote } : {}),
|
|
50
92
|
excerpt: truncated
|
|
51
93
|
? `${p.content.slice(0, EXCERPT)}\n… (call get_pattern "${p.id}" for the full guide)`
|
|
52
94
|
: p.content,
|
|
@@ -58,7 +100,7 @@ export function registerAskSpotlight(server) {
|
|
|
58
100
|
threshold: 0.4,
|
|
59
101
|
ignoreLocation: true,
|
|
60
102
|
});
|
|
61
|
-
const components = compFuse
|
|
103
|
+
const components = searchOrPerTerm(compFuse, query, 3).map(r => {
|
|
62
104
|
const c = r.item;
|
|
63
105
|
return {
|
|
64
106
|
name: c.name,
|
|
@@ -104,13 +146,33 @@ export function registerAskSpotlight(server) {
|
|
|
104
146
|
.map(m => ({ from: m.fromComponent, to: m.toComponent }))
|
|
105
147
|
: [];
|
|
106
148
|
const payload = {
|
|
149
|
+
...(missing.length
|
|
150
|
+
? {
|
|
151
|
+
degraded: {
|
|
152
|
+
missing: [...missing],
|
|
153
|
+
warning: `The Spotlight index has no ${missing.join(', no ')}. This answer is built ` +
|
|
154
|
+
'from the collections that do have data and is therefore incomplete. Say so ' +
|
|
155
|
+
'in your reply, and do not fill the gaps from memory or invent ' +
|
|
156
|
+
'component/token names.',
|
|
157
|
+
indexPath: health.indexPath,
|
|
158
|
+
counts: health.counts,
|
|
159
|
+
remedy: remedyFor(health.indexPath),
|
|
160
|
+
},
|
|
161
|
+
}
|
|
162
|
+
: {}),
|
|
107
163
|
question,
|
|
108
164
|
components,
|
|
109
165
|
guidance,
|
|
110
166
|
...(tokens.length ? { tokens } : {}),
|
|
111
167
|
...(utilityClasses.length ? { utilityClasses } : {}),
|
|
112
168
|
...(migration.length ? { migration } : {}),
|
|
113
|
-
hint:
|
|
169
|
+
hint: (incompleteNote
|
|
170
|
+
? `YOU MUST TELL THE USER THIS ANSWER IS INCOMPLETE: the index has no ${missing.join(', no ')}, ` +
|
|
171
|
+
'so whole categories of Spotlight guidance are missing from it. State that plainly ' +
|
|
172
|
+
'before or alongside your answer, give the remedy above, and do not present what ' +
|
|
173
|
+
'follows as a complete picture. '
|
|
174
|
+
: '') +
|
|
175
|
+
'This is the consolidated answer context. For a full component (all props) call ' +
|
|
114
176
|
'get_component; for a full guide call get_pattern with the id; for a migration guide ' +
|
|
115
177
|
'call get_migration_guide with the "from" value.',
|
|
116
178
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ask_spotlight.js","sourceRoot":"","sources":["../../src/tools/ask_spotlight.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;
|
|
1
|
+
{"version":3,"file":"ask_spotlight.js","sourceRoot":"","sources":["../../src/tools/ask_spotlight.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,18 +1,27 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import {
|
|
2
|
+
import { guardedIndex } from './_guard.js';
|
|
3
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 =
|
|
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 or id, e.g. "Button", "TextField". When two components share a name across categories, pass the id from search_components (e.g. "header-data-display").') }, async ({ name }) => {
|
|
5
|
+
const { index, error } = guardedIndex('get_component', 'components');
|
|
6
|
+
if (error)
|
|
7
|
+
return error;
|
|
6
8
|
const component = index.components.find(c => c.name.toLowerCase() === name.toLowerCase() ||
|
|
7
9
|
c.id.toLowerCase() === name.toLowerCase());
|
|
8
10
|
if (!component) {
|
|
9
11
|
return {
|
|
10
|
-
content: [{ type: 'text', text: `Component "${name}" not found. Use search_components to find available components.` }],
|
|
12
|
+
content: [{ type: 'text', text: `Component "${name}" not found among the ${index.components.length} indexed Spotlight components. Use search_components to find available components.` }],
|
|
11
13
|
isError: true,
|
|
12
14
|
};
|
|
13
15
|
}
|
|
16
|
+
const sameName = index.components.filter(c => c !== component && c.name.toLowerCase() === component.name.toLowerCase());
|
|
17
|
+
const payload = sameName.length
|
|
18
|
+
? {
|
|
19
|
+
...component,
|
|
20
|
+
otherComponentsWithSameName: sameName.map(c => ({ id: c.id, category: c.category })),
|
|
21
|
+
}
|
|
22
|
+
: component;
|
|
14
23
|
return {
|
|
15
|
-
content: [{ type: 'text', text: JSON.stringify(
|
|
24
|
+
content: [{ type: 'text', text: JSON.stringify(payload, null, 2) }],
|
|
16
25
|
};
|
|
17
26
|
});
|
|
18
27
|
}
|
|
@@ -1 +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,
|
|
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,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,MAAM,UAAU,oBAAoB,CAAC,MAAiB;IACpD,MAAM,CAAC,IAAI,CACT,eAAe,EACf,uHAAuH,EACvH,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,wKAAwK,CAAC,EAAE,EACvM,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;QACjB,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,YAAY,CAAC,eAAe,EAAE,YAAY,CAAC,CAAC;QACrE,IAAI,KAAK;YAAE,OAAO,KAAK,CAAC;QACxB,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,yBAAyB,KAAK,CAAC,UAAU,CAAC,MAAM,oFAAoF,EAAE,CAAC;gBAClM,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;QACD,MAAM,QAAQ,GAAG,KAAK,CAAC,UAAU,CAAC,MAAM,CACtC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,SAAS,IAAI,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,SAAS,CAAC,IAAI,CAAC,WAAW,EAAE,CAC9E,CAAC;QACF,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM;YAC7B,CAAC,CAAC;gBACE,GAAG,SAAS;gBACZ,2BAA2B,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;aACrF;YACH,CAAC,CAAC,SAAS,CAAC;QACd,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"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import {
|
|
2
|
+
import { guardedIndex } from './_guard.js';
|
|
3
3
|
export function registerGetMigrationGuide(server) {
|
|
4
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 =
|
|
5
|
+
const { index, error } = guardedIndex('get_migration_guide', 'migration');
|
|
6
|
+
if (error)
|
|
7
|
+
return error;
|
|
6
8
|
const guide = index.migration.find(m => m.fromComponent.toLowerCase() === fromComponent.toLowerCase());
|
|
7
9
|
if (!guide) {
|
|
8
10
|
const available = index.migration.map(m => m.fromComponent);
|
|
@@ -1 +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,
|
|
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,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,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,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,YAAY,CAAC,qBAAqB,EAAE,WAAW,CAAC,CAAC;QAC1E,IAAI,KAAK;YAAE,OAAO,KAAK,CAAC;QACxB,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"}
|
|
@@ -1,23 +1,38 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import Fuse from 'fuse.js';
|
|
3
|
-
import {
|
|
3
|
+
import { guardedIndex } from './_guard.js';
|
|
4
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.', {
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
server.tool('get_pattern', 'Get a Spotlight usage pattern: when to use which component, comparisons between alternatives, and code examples.', {
|
|
6
|
+
query: z
|
|
7
|
+
.string()
|
|
8
|
+
.optional()
|
|
9
|
+
.describe('Pattern name or topic, e.g. "overlay", "modal vs drawer", "filtering", "pagination"'),
|
|
10
|
+
id: z
|
|
11
|
+
.string()
|
|
12
|
+
.optional()
|
|
13
|
+
.describe('Exact (or near-exact) pattern id, e.g. "form-multi-step-selection-guide". Alias for `query` — use either.'),
|
|
14
|
+
}, async ({ query, id }) => {
|
|
15
|
+
const { index, error } = guardedIndex('get_pattern', 'patterns');
|
|
16
|
+
if (error)
|
|
17
|
+
return error;
|
|
18
|
+
// `id` is an alias for `query` — accept either so a call with only
|
|
19
|
+
// `{ id: "..." }` (as identify_pattern's matches return) doesn't fail
|
|
20
|
+
// schema validation (SPT-1828).
|
|
21
|
+
const effectiveQuery = query ?? id;
|
|
22
|
+
if (!effectiveQuery) {
|
|
8
23
|
return {
|
|
9
|
-
content: [{ type: 'text', text: '
|
|
24
|
+
content: [{ type: 'text', text: 'Provide either "query" or "id".' }],
|
|
10
25
|
};
|
|
11
26
|
}
|
|
12
27
|
const fuse = new Fuse(index.patterns, {
|
|
13
28
|
keys: ['title', 'description', 'id', 'components'],
|
|
14
29
|
threshold: 0.4,
|
|
15
30
|
});
|
|
16
|
-
const results = fuse.search(
|
|
31
|
+
const results = fuse.search(effectiveQuery, { limit: 3 });
|
|
17
32
|
if (!results.length) {
|
|
18
33
|
const available = index.patterns.map(p => p.title);
|
|
19
34
|
return {
|
|
20
|
-
content: [{ type: 'text', text: `No patterns found for "${
|
|
35
|
+
content: [{ type: 'text', text: `No patterns found for "${effectiveQuery}".\n\nAvailable patterns: ${available.join(', ')}` }],
|
|
21
36
|
};
|
|
22
37
|
}
|
|
23
38
|
return {
|
|
@@ -1 +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,
|
|
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,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,MAAM,UAAU,kBAAkB,CAAC,MAAiB;IAClD,MAAM,CAAC,IAAI,CACT,aAAa,EACb,kHAAkH,EAClH;QACE,KAAK,EAAE,CAAC;aACL,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,qFAAqF,CAAC;QAClG,EAAE,EAAE,CAAC;aACF,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,2GAA2G,CAAC;KACzH,EACD,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE;QACtB,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,YAAY,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC;QACjE,IAAI,KAAK;YAAE,OAAO,KAAK,CAAC;QACxB,mEAAmE;QACnE,sEAAsE;QACtE,gCAAgC;QAChC,MAAM,cAAc,GAAG,KAAK,IAAI,EAAE,CAAC;QACnC,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,iCAAiC,EAAE,CAAC;aAC9E,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,cAAc,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;QAC1D,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,cAAc,6BAA6B,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;aACxI,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"}
|
package/dist/tools/get_recipe.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import Fuse from 'fuse.js';
|
|
3
|
-
import {
|
|
3
|
+
import { guardedIndex } from './_guard.js';
|
|
4
4
|
export function registerGetRecipe(server) {
|
|
5
5
|
server.tool('get_recipe', 'Get the implementation recipe for a Spotlight pattern — concise, AI-consumable instructions ' +
|
|
6
6
|
'for building the pattern correctly. Call this after identify_pattern confirms which pattern ' +
|
|
@@ -10,7 +10,9 @@ export function registerGetRecipe(server) {
|
|
|
10
10
|
.string()
|
|
11
11
|
.describe('Pattern ID from identify_pattern, e.g. "data-display-table-pattern" or "filter-chips-pattern"'),
|
|
12
12
|
}, async ({ patternId }) => {
|
|
13
|
-
const index =
|
|
13
|
+
const { index, error } = guardedIndex('get_recipe', 'patterns');
|
|
14
|
+
if (error)
|
|
15
|
+
return error;
|
|
14
16
|
const recipes = index.patterns.filter(p => p.category === 'recipe');
|
|
15
17
|
// 1. Exact id match within recipes.
|
|
16
18
|
const exact = recipes.find(p => p.id === patternId);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get_recipe.js","sourceRoot":"","sources":["../../src/tools/get_recipe.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,IAAI,MAAM,SAAS,CAAC;AAC3B,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"get_recipe.js","sourceRoot":"","sources":["../../src/tools/get_recipe.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/get_token.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import {
|
|
2
|
+
import { guardedIndex } from './_guard.js';
|
|
3
3
|
export function registerGetToken(server) {
|
|
4
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 =
|
|
5
|
+
const { index, error } = guardedIndex('get_token', 'tokens');
|
|
6
|
+
if (error)
|
|
7
|
+
return error;
|
|
6
8
|
const token = index.tokens.find(t => t.name.toLowerCase() === name.toLowerCase());
|
|
7
9
|
if (!token) {
|
|
8
10
|
return {
|
|
9
|
-
content: [{ type: 'text', text: `Token "${name}" not found. Use search_tokens to find available tokens.` }],
|
|
11
|
+
content: [{ type: 'text', text: `Token "${name}" not found among the ${index.tokens.length} indexed Spotlight tokens. Use search_tokens to find available tokens.` }],
|
|
10
12
|
isError: true,
|
|
11
13
|
};
|
|
12
14
|
}
|
|
@@ -1 +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,
|
|
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,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,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,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,YAAY,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;QAC7D,IAAI,KAAK;YAAE,OAAO,KAAK,CAAC;QACxB,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,yBAAyB,KAAK,CAAC,MAAM,CAAC,MAAM,wEAAwE,EAAE,CAAC;gBAC9K,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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import Fuse from 'fuse.js';
|
|
3
|
-
import {
|
|
3
|
+
import { guardedIndex } from './_guard.js';
|
|
4
|
+
import { searchOrPerTerm, searchOrPerTermStrict } from './_fuzzy.js';
|
|
4
5
|
const HIGH_THRESHOLD = 0.25;
|
|
5
6
|
const MEDIUM_THRESHOLD = 0.42;
|
|
6
7
|
const SEARCH_THRESHOLD = 0.55;
|
|
@@ -29,7 +30,9 @@ export function registerIdentifyPattern(server) {
|
|
|
29
30
|
.optional()
|
|
30
31
|
.describe('Spotlight component names already in scope (optional), e.g. ["GridTable", "Chip"]'),
|
|
31
32
|
}, async ({ useCase, components }) => {
|
|
32
|
-
const index =
|
|
33
|
+
const { index, error } = guardedIndex('identify_pattern', 'patterns');
|
|
34
|
+
if (error)
|
|
35
|
+
return error;
|
|
33
36
|
// Pool: selection guides + recipe files only.
|
|
34
37
|
const pool = index.patterns.filter(p => p.category === 'selection' || p.category === 'recipe');
|
|
35
38
|
// Build recipe id set for recipeAvailable lookup.
|
|
@@ -61,7 +64,7 @@ export function registerIdentifyPattern(server) {
|
|
|
61
64
|
ignoreLocation: true,
|
|
62
65
|
includeScore: true,
|
|
63
66
|
});
|
|
64
|
-
const results = fuse
|
|
67
|
+
const results = searchOrPerTermStrict(fuse, query, 3);
|
|
65
68
|
if (!results.length) {
|
|
66
69
|
// Suggest component names tangentially related to the use case.
|
|
67
70
|
const compFuse = new Fuse(index.components, {
|
|
@@ -69,8 +72,7 @@ export function registerIdentifyPattern(server) {
|
|
|
69
72
|
threshold: 0.4,
|
|
70
73
|
ignoreLocation: true,
|
|
71
74
|
});
|
|
72
|
-
const suggestions = compFuse
|
|
73
|
-
.search(useCase, { limit: 5 })
|
|
75
|
+
const suggestions = searchOrPerTerm(compFuse, useCase, 5)
|
|
74
76
|
.map(r => r.item.name);
|
|
75
77
|
return {
|
|
76
78
|
content: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"identify_pattern.js","sourceRoot":"","sources":["../../src/tools/identify_pattern.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,IAAI,MAAM,SAAS,CAAC;AAC3B,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"identify_pattern.js","sourceRoot":"","sources":["../../src/tools/identify_pattern.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { guardedIndex } from './_guard.js';
|
|
2
2
|
export function registerListDeprecated(server) {
|
|
3
3
|
server.tool('list_deprecated', 'List all deprecated and legacy Spotlight components with their replacements and removal dates.', {}, async () => {
|
|
4
|
-
const index =
|
|
4
|
+
const { index, error } = guardedIndex('list_deprecated', 'components');
|
|
5
|
+
if (error)
|
|
6
|
+
return error;
|
|
5
7
|
return {
|
|
6
8
|
content: [{ type: 'text', text: JSON.stringify(index.deprecated, null, 2) }],
|
|
7
9
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list_deprecated.js","sourceRoot":"","sources":["../../src/tools/list_deprecated.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"list_deprecated.js","sourceRoot":"","sources":["../../src/tools/list_deprecated.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,MAAM,UAAU,sBAAsB,CAAC,MAAiB;IACtD,MAAM,CAAC,IAAI,CACT,iBAAiB,EACjB,gGAAgG,EAChG,EAAE,EACF,KAAK,IAAI,EAAE;QACT,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,YAAY,CAAC,iBAAiB,EAAE,YAAY,CAAC,CAAC;QACvE,IAAI,KAAK;YAAE,OAAO,KAAK,CAAC;QACxB,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"}
|
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import Fuse from 'fuse.js';
|
|
3
|
-
import {
|
|
3
|
+
import { guardedIndex } from './_guard.js';
|
|
4
|
+
import { searchOrPerTerm } from './_fuzzy.js';
|
|
4
5
|
export function registerSearchComponents(server) {
|
|
5
6
|
server.tool('search_components', 'Search Spotlight components by name, description, or category. Returns a ranked list of matches.', {
|
|
6
7
|
query: z.string().describe('Search query, e.g. "date picker", "dropdown", "inputs"'),
|
|
7
8
|
limit: z.number().optional().default(10).describe('Max results to return (default 10)'),
|
|
8
9
|
}, async ({ query, limit }) => {
|
|
9
|
-
const index =
|
|
10
|
+
const { index, error } = guardedIndex('search_components', 'components');
|
|
11
|
+
if (error)
|
|
12
|
+
return error;
|
|
10
13
|
const fuse = new Fuse(index.components, {
|
|
11
14
|
keys: ['name', 'description', 'category', 'id'],
|
|
12
15
|
threshold: 0.4,
|
|
13
16
|
includeScore: true,
|
|
14
17
|
});
|
|
15
|
-
|
|
18
|
+
// `id` is what disambiguates same-named components across categories
|
|
19
|
+
// (e.g. header-inputs vs header-data-display) in get_component.
|
|
20
|
+
const results = searchOrPerTerm(fuse, query, limit).map(r => ({
|
|
21
|
+
id: r.item.id,
|
|
16
22
|
name: r.item.name,
|
|
17
23
|
category: r.item.category,
|
|
18
24
|
status: r.item.status,
|
|
@@ -1 +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,
|
|
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,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,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,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,YAAY,CAAC,mBAAmB,EAAE,YAAY,CAAC,CAAC;QACzE,IAAI,KAAK;YAAE,OAAO,KAAK,CAAC;QACxB,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,qEAAqE;QACrE,gEAAgE;QAChE,MAAM,OAAO,GAAG,eAAe,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAC5D,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE;YACb,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"}
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import Fuse from 'fuse.js';
|
|
3
|
-
import {
|
|
3
|
+
import { guardedIndex } from './_guard.js';
|
|
4
|
+
import { searchOrPerTerm } from './_fuzzy.js';
|
|
5
|
+
import { expandWithSynonyms } from './_synonyms.js';
|
|
4
6
|
export function registerSearchTokens(server) {
|
|
5
7
|
server.tool('search_tokens', 'Search Spotlight design tokens by name, description, or category.', {
|
|
6
8
|
query: z.string().describe('Semantic description, e.g. "large spacing", "positive color", "border radius"'),
|
|
7
9
|
category: z.string().optional().describe('Filter by category: "spacing", "color-semantic", "typography", etc.'),
|
|
8
10
|
limit: z.number().optional().default(10).describe('Max results to return (default 10)'),
|
|
9
11
|
}, async ({ query, category, limit }) => {
|
|
10
|
-
const index =
|
|
12
|
+
const { index, error } = guardedIndex('search_tokens', 'tokens');
|
|
13
|
+
if (error)
|
|
14
|
+
return error;
|
|
11
15
|
const tokens = category
|
|
12
16
|
? index.tokens.filter(t => t.category.toLowerCase().includes(category.toLowerCase()))
|
|
13
17
|
: index.tokens;
|
|
@@ -17,7 +21,8 @@ export function registerSearchTokens(server) {
|
|
|
17
21
|
ignoreLocation: true,
|
|
18
22
|
includeScore: true,
|
|
19
23
|
});
|
|
20
|
-
const
|
|
24
|
+
const expandedQuery = expandWithSynonyms(query);
|
|
25
|
+
const results = searchOrPerTerm(fuse, expandedQuery, limit).map(r => ({
|
|
21
26
|
name: r.item.name,
|
|
22
27
|
value: r.item.value,
|
|
23
28
|
category: r.item.category,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search_tokens.js","sourceRoot":"","sources":["../../src/tools/search_tokens.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,IAAI,MAAM,SAAS,CAAC;AAC3B,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"search_tokens.js","sourceRoot":"","sources":["../../src/tools/search_tokens.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,IAAI,MAAM,SAAS,CAAC;AAC3B,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAGpD,MAAM,UAAU,oBAAoB,CAAC,MAAiB;IACpD,MAAM,CAAC,IAAI,CACT,eAAe,EACf,mEAAmE,EACnE;QACE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,+EAA+E,CAAC;QAC3G,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,qEAAqE,CAAC;QAC/G,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,QAAQ,EAAE,KAAK,EAAE,EAAE,EAAE;QACnC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,YAAY,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC;QACjE,IAAI,KAAK;YAAE,OAAO,KAAK,CAAC;QACxB,MAAM,MAAM,GAAG,QAAQ;YACrB,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;YACrF,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;QAEjB,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,MAAM,EAAE;YAC5B,IAAI,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,CAAC;YAC3E,SAAS,EAAE,GAAG;YACd,cAAc,EAAE,IAAI;YACpB,YAAY,EAAE,IAAI;SACnB,CAAC,CAAC;QACH,MAAM,aAAa,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;QAChD,MAAM,OAAO,GAAG,eAAe,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YACpE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI;YACjB,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK;YACnB,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ;YACzB,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK;YACnB,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO;YACvB,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"}
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import Fuse from 'fuse.js';
|
|
3
|
-
import {
|
|
3
|
+
import { guardedIndex } from './_guard.js';
|
|
4
4
|
export function registerSearchUtilityClasses(server) {
|
|
5
5
|
server.tool('search_utility_classes', 'Search Spotlight CSS utility classes (e.g. ".spotlight_body-xs") by name, category, or subcategory. Use to find the helper class for typography, layout, spacing, alignment, etc.', {
|
|
6
6
|
query: z.string().describe('Search query, e.g. "body text", "heading", "flex", "grid column"'),
|
|
7
7
|
category: z.string().optional().describe('Filter by category: "typography", "layout", "spacing", etc.'),
|
|
8
8
|
limit: z.number().optional().default(10).describe('Max results to return (default 10)'),
|
|
9
9
|
}, async ({ query, category, limit }) => {
|
|
10
|
-
const index =
|
|
10
|
+
const { index, error } = guardedIndex('search_utility_classes', 'utilityClasses');
|
|
11
|
+
if (error)
|
|
12
|
+
return error;
|
|
11
13
|
const classes = category
|
|
12
14
|
? index.utilityClasses.filter(c => c.category.toLowerCase().includes(category.toLowerCase()))
|
|
13
15
|
: index.utilityClasses;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search_utility_classes.js","sourceRoot":"","sources":["../../src/tools/search_utility_classes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,IAAI,MAAM,SAAS,CAAC;AAC3B,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"search_utility_classes.js","sourceRoot":"","sources":["../../src/tools/search_utility_classes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,IAAI,MAAM,SAAS,CAAC;AAC3B,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,MAAM,UAAU,4BAA4B,CAAC,MAAiB;IAC5D,MAAM,CAAC,IAAI,CACT,wBAAwB,EACxB,mLAAmL,EACnL;QACE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,kEAAkE,CAAC;QAC9F,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,6DAA6D,CAAC;QACvG,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,QAAQ,EAAE,KAAK,EAAE,EAAE,EAAE;QACnC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,YAAY,CAAC,wBAAwB,EAAE,gBAAgB,CAAC,CAAC;QAClF,IAAI,KAAK;YAAE,OAAO,KAAK,CAAC;QACxB,MAAM,OAAO,GAAG,QAAQ;YACtB,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;YAC7F,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC;QAEzB,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,OAAO,EAAE;YAC7B,IAAI,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,aAAa,EAAE,OAAO,CAAC;YAClD,SAAS,EAAE,GAAG;YACd,cAAc,EAAE,IAAI;YACpB,iBAAiB,EAAE,IAAI;YACvB,YAAY,EAAE,IAAI;SACnB,CAAC,CAAC;QACH,wEAAwE;QACxE,gFAAgF;QAChF,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxE,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YACxD,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI;YACjB,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ;YACzB,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW;YAC/B,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK;YACnB,UAAU,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU;YAC7B,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"}
|