@czi-sds/mcp 0.14.0 → 0.16.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/data/component-props/ButtonDropdownV2.json +1 -1
- package/data/component-props/ButtonIcon.json +1 -1
- package/data/component-props/ButtonNew.json +1 -1
- package/data/component-props/ButtonToggle.json +1 -1
- package/data/component-props/ButtonToggleV2.json +1 -1
- package/data/component-props/ButtonV2.json +1 -1
- package/data/component-props/Dropdown.json +2 -3
- package/data/component-props/InputSearch.json +1 -1
- package/data/component-props/InputSlider.json +1 -1
- package/data/component-props/MenuItem.json +1 -1
- package/data/component-props/Popover.json +0 -116
- package/data/component-props/PreComposedTable.json +24 -28
- package/data/component-props/Tooltip.json +1 -1
- package/data/zeroheight-cache.json +1 -1
- package/dist/stdio.js +572 -773
- package/package.json +5 -5
package/dist/stdio.js
CHANGED
|
@@ -1,242 +1,186 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { StdioServerTransport } from
|
|
3
|
-
import { McpServer } from
|
|
4
|
-
import { z } from
|
|
5
|
-
import fs, {
|
|
6
|
-
import path, { dirname
|
|
7
|
-
import { fileURLToPath } from
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import fs, { existsSync, readFileSync } from "fs";
|
|
6
|
+
import path, { dirname, join } from "path";
|
|
7
|
+
import { fileURLToPath } from "url";
|
|
8
|
+
//#region src/server.ts
|
|
9
|
+
const server = new McpServer({
|
|
10
|
+
name: "sds-mcp",
|
|
11
|
+
version: "0.1.0",
|
|
12
|
+
capabilities: {
|
|
13
|
+
prompts: {},
|
|
14
|
+
resources: {
|
|
15
|
+
subscribe: true,
|
|
16
|
+
listChanged: true
|
|
17
|
+
},
|
|
18
|
+
tools: {}
|
|
19
|
+
}
|
|
20
20
|
});
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
//#endregion
|
|
22
|
+
//#region src/lib/fetch.ts
|
|
23
|
+
const filename$1 = fileURLToPath(import.meta.url);
|
|
24
|
+
const dirname$2 = path.dirname(filename$1);
|
|
25
|
+
/**
|
|
26
|
+
* Gets all component names from both packages
|
|
27
|
+
*/
|
|
23
28
|
async function getAllComponentNames() {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
throw new Error(
|
|
42
|
-
"Component list not found in any expected location. Please run 'yarn generate:components-list' first."
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
const fileContent = fs.readFileSync(dataPath, "utf-8");
|
|
46
|
-
const componentList = JSON.parse(fileContent);
|
|
47
|
-
return componentList;
|
|
48
|
-
} catch (error) {
|
|
49
|
-
throw new Error(
|
|
50
|
-
`Failed to load component list: ${error instanceof Error ? error.message : `Unknown error ${error}`}`
|
|
51
|
-
);
|
|
52
|
-
}
|
|
29
|
+
try {
|
|
30
|
+
const possiblePaths = [
|
|
31
|
+
path.join(dirname$2, "../../data/component-list.json"),
|
|
32
|
+
path.join(dirname$2, "../data/component-list.json"),
|
|
33
|
+
path.join(process.cwd(), "data/component-list.json")
|
|
34
|
+
];
|
|
35
|
+
let dataPath = "";
|
|
36
|
+
for (const p of possiblePaths) if (fs.existsSync(p)) {
|
|
37
|
+
dataPath = p;
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
if (!dataPath) throw new Error("Component list not found in any expected location. Please run 'yarn generate:components-list' first.");
|
|
41
|
+
const fileContent = fs.readFileSync(dataPath, "utf-8");
|
|
42
|
+
return JSON.parse(fileContent);
|
|
43
|
+
} catch (error) {
|
|
44
|
+
throw new Error(`Failed to load component list: ${error instanceof Error ? error.message : `Unknown error ${error}`}`);
|
|
45
|
+
}
|
|
53
46
|
}
|
|
54
47
|
async function fetchComponentProps(component) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
props: {}
|
|
76
|
-
}
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
const fileContent = fs.readFileSync(propsPath, "utf-8");
|
|
80
|
-
return JSON.parse(fileContent);
|
|
81
|
-
} catch (error) {
|
|
82
|
-
throw new Error(
|
|
83
|
-
`Failed to load props for ${component}: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
84
|
-
);
|
|
85
|
-
}
|
|
48
|
+
try {
|
|
49
|
+
const propsPaths = [
|
|
50
|
+
path.join(dirname$2, `../../data/component-props/${component}.json`),
|
|
51
|
+
path.join(dirname$2, `../data/component-props/${component}.json`),
|
|
52
|
+
path.join(process.cwd(), `data/component-props/${component}.json`)
|
|
53
|
+
];
|
|
54
|
+
let propsPath = "";
|
|
55
|
+
for (const p of propsPaths) if (fs.existsSync(p)) {
|
|
56
|
+
propsPath = p;
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
if (!propsPath) return { [component]: {
|
|
60
|
+
message: "Props information not available for this component. Run 'yarn generate:component-props' to generate props data.",
|
|
61
|
+
props: {}
|
|
62
|
+
} };
|
|
63
|
+
const fileContent = fs.readFileSync(propsPath, "utf-8");
|
|
64
|
+
return JSON.parse(fileContent);
|
|
65
|
+
} catch (error) {
|
|
66
|
+
throw new Error(`Failed to load props for ${component}: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
67
|
+
}
|
|
86
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* Gets all component names from both packages
|
|
71
|
+
*/
|
|
87
72
|
async function fetchTailwindTokens() {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
throw new Error(
|
|
106
|
-
"Component list not found in any expected location. Please run 'yarn generate:tailwind-tokens' first."
|
|
107
|
-
);
|
|
108
|
-
}
|
|
109
|
-
const fileContent = fs.readFileSync(dataPath, "utf-8");
|
|
110
|
-
const tailwindTokens = JSON.parse(fileContent);
|
|
111
|
-
return tailwindTokens;
|
|
112
|
-
} catch (error) {
|
|
113
|
-
throw new Error(
|
|
114
|
-
`Failed to load tailwind tokens: ${error instanceof Error ? error.message : `Unknown error ${error}`}`
|
|
115
|
-
);
|
|
116
|
-
}
|
|
73
|
+
try {
|
|
74
|
+
const possiblePaths = [
|
|
75
|
+
path.join(dirname$2, "../../data/tailwind.json"),
|
|
76
|
+
path.join(dirname$2, "../data/tailwind.json"),
|
|
77
|
+
path.join(process.cwd(), "data/tailwind.json")
|
|
78
|
+
];
|
|
79
|
+
let dataPath = "";
|
|
80
|
+
for (const p of possiblePaths) if (fs.existsSync(p)) {
|
|
81
|
+
dataPath = p;
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
if (!dataPath) throw new Error("Component list not found in any expected location. Please run 'yarn generate:tailwind-tokens' first.");
|
|
85
|
+
const fileContent = fs.readFileSync(dataPath, "utf-8");
|
|
86
|
+
return JSON.parse(fileContent);
|
|
87
|
+
} catch (error) {
|
|
88
|
+
throw new Error(`Failed to load tailwind tokens: ${error instanceof Error ? error.message : `Unknown error ${error}`}`);
|
|
89
|
+
}
|
|
117
90
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
const json = await fetchComponentProps(component);
|
|
148
|
-
return {
|
|
149
|
-
content: [
|
|
150
|
-
{
|
|
151
|
-
type: "text",
|
|
152
|
-
text: JSON.stringify(json)
|
|
153
|
-
}
|
|
154
|
-
]
|
|
155
|
-
};
|
|
156
|
-
} catch (error) {
|
|
157
|
-
return {
|
|
158
|
-
content: [
|
|
159
|
-
{
|
|
160
|
-
type: "text",
|
|
161
|
-
text: `Failed to get component props for ${component}: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
162
|
-
}
|
|
163
|
-
]
|
|
164
|
-
};
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
);
|
|
168
|
-
}
|
|
91
|
+
//#endregion
|
|
92
|
+
//#region src/tools/get-component-props.ts
|
|
93
|
+
const getComponentPropsTool = {
|
|
94
|
+
name: "get_component_props",
|
|
95
|
+
description: "Get detailed properties of a specific SDS component. This tool retrieves the properties, attributes, design related props for a component, like sdsStyle, sdsType, sdsSize, etc. and configuration options available for a given SDS component.",
|
|
96
|
+
async ctx() {
|
|
97
|
+
try {
|
|
98
|
+
const componentList = await getAllComponentNames();
|
|
99
|
+
return { componentList: [...componentList.components, ...componentList["data-viz"]] };
|
|
100
|
+
} catch (error) {
|
|
101
|
+
throw new Error(`Failed to initialize component props tool: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
exec(server, { ctx, name, description }) {
|
|
105
|
+
server.tool(name, description, { component: z.enum(ctx.componentList).describe("The name of the SDS component to get properties for") }, async ({ component }) => {
|
|
106
|
+
try {
|
|
107
|
+
const json = await fetchComponentProps(component);
|
|
108
|
+
return { content: [{
|
|
109
|
+
type: "text",
|
|
110
|
+
text: JSON.stringify(json)
|
|
111
|
+
}] };
|
|
112
|
+
} catch (error) {
|
|
113
|
+
return { content: [{
|
|
114
|
+
type: "text",
|
|
115
|
+
text: `Failed to get component props for ${component}: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
116
|
+
}] };
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
}
|
|
169
120
|
};
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
type: "text",
|
|
191
|
-
text: JSON.stringify(ctx.componentList, null, 2)
|
|
192
|
-
}
|
|
193
|
-
]
|
|
194
|
-
};
|
|
195
|
-
});
|
|
196
|
-
}
|
|
121
|
+
//#endregion
|
|
122
|
+
//#region src/tools/list-components.ts
|
|
123
|
+
const listComponentsTool = {
|
|
124
|
+
name: "list_components",
|
|
125
|
+
description: "List all available components in SDS. This tool retrieves the names of all SDS components from both the @czi-sds/components package and the @czi-sds/data-viz package.",
|
|
126
|
+
async ctx() {
|
|
127
|
+
try {
|
|
128
|
+
return { componentList: await getAllComponentNames() };
|
|
129
|
+
} catch (error) {
|
|
130
|
+
throw new Error(`Failed to initialize list components tool: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
exec(server, { ctx, name, description }) {
|
|
134
|
+
server.tool(name, description, {}, async () => {
|
|
135
|
+
return { content: [{
|
|
136
|
+
type: "text",
|
|
137
|
+
text: JSON.stringify(ctx.componentList, null, 2)
|
|
138
|
+
}] };
|
|
139
|
+
});
|
|
140
|
+
}
|
|
197
141
|
};
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
142
|
+
//#endregion
|
|
143
|
+
//#region src/lib/tailwind-guidance.ts
|
|
144
|
+
const TAILWIND_TOKEN_GUIDANCE = {
|
|
145
|
+
colors: {
|
|
146
|
+
category: "Colors",
|
|
147
|
+
description: "Theme-aware color tokens support both light and dark modes. Both modes follow the same token name structure: use light-token-name for light mode colors and dark:dark-token-name for dark mode colors.",
|
|
148
|
+
prefixes: [
|
|
149
|
+
"bg-",
|
|
150
|
+
"border-",
|
|
151
|
+
"divide-",
|
|
152
|
+
"outline-",
|
|
153
|
+
"ring-",
|
|
154
|
+
"ring-offset-",
|
|
155
|
+
"text-",
|
|
156
|
+
"placeholder-",
|
|
157
|
+
"caret-",
|
|
158
|
+
"decoration-",
|
|
159
|
+
"accent-",
|
|
160
|
+
"shadow-",
|
|
161
|
+
"fill-",
|
|
162
|
+
"stroke-",
|
|
163
|
+
"from-",
|
|
164
|
+
"via-",
|
|
165
|
+
"to-"
|
|
166
|
+
],
|
|
167
|
+
examples: [
|
|
168
|
+
{
|
|
169
|
+
description: "Basic text and background colors",
|
|
170
|
+
code: `<div className="bg-light-sds-color-semantic-base-background-primary dark:bg-dark-sds-color-semantic-base-background-primary text-light-sds-color-semantic-base-text-primary dark:text-dark-sds-color-semantic-base-text-primary">
|
|
227
171
|
Content with semantic colors
|
|
228
172
|
</div>`
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
description: "Dark mode with hover states",
|
|
176
|
+
code: `<button className="bg-light-sds-color-semantic-accent-fill-primary dark:bg-dark-sds-color-semantic-accent-fill-primary
|
|
233
177
|
hover:bg-light-sds-color-semantic-accent-fill-hover dark:hover:bg-dark-sds-color-semantic-accent-fill-hover">
|
|
234
178
|
Click me
|
|
235
179
|
</button>`
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
description: "Border and focus states",
|
|
183
|
+
code: `<input className="
|
|
240
184
|
border-light-sds-color-semantic-base-border-primary
|
|
241
185
|
hover:border-light-sds-color-semantic-base-border-primary-hover
|
|
242
186
|
focus:border-light-sds-color-semantic-base-border-primary-pressed
|
|
@@ -244,21 +188,22 @@ var TAILWIND_TOKEN_GUIDANCE = {
|
|
|
244
188
|
dark:hover:border-dark-sds-color-semantic-base-border-primary-hover
|
|
245
189
|
dark:focus:border-dark-sds-color-semantic-base-border-primary-pressed
|
|
246
190
|
"/>`
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
191
|
+
}
|
|
192
|
+
],
|
|
193
|
+
tips: ["Always use semantic colors (e.g., 'bg-light-sds-color-semantic-base-background-primary dark:bg-dark-sds-color-semantic-base-background-primary') over primitive colors when possible", "Include both light and dark variants for proper theme support"]
|
|
194
|
+
},
|
|
195
|
+
typography: {
|
|
196
|
+
category: "Typography",
|
|
197
|
+
description: "Complete text styling presets including font, size, weight, and spacing",
|
|
198
|
+
prefixes: [
|
|
199
|
+
"font-",
|
|
200
|
+
"text-",
|
|
201
|
+
"leading-",
|
|
202
|
+
"tracking-"
|
|
203
|
+
],
|
|
204
|
+
examples: [{
|
|
205
|
+
description: "Typography presets (recommended). SDS typography tokens come in narrow and wide variants: use token-narrow on screens smaller than md, and token-wide on md and up.",
|
|
206
|
+
code: `<!-- Use typography tokens for complete text styling -->
|
|
262
207
|
<h1 className="prose-sds-title-l-700-wide">Title</h1>
|
|
263
208
|
<h1 className="prose-sds-header-xl-600-wide">Heading</h1>
|
|
264
209
|
<p className="prose-sds-body-m-500-wide">Body text</p>
|
|
@@ -266,10 +211,9 @@ var TAILWIND_TOKEN_GUIDANCE = {
|
|
|
266
211
|
<span className="prose-sds-tabular-xxs-600-wide">Tabular Numbers</span>
|
|
267
212
|
<span className="prose-sds-code-s-500-wide">Code</span>
|
|
268
213
|
<span className="prose-sds-link-l-500-wide">Link style</span>`
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
code: `<!-- Or use individual properties when needed -->
|
|
214
|
+
}, {
|
|
215
|
+
description: "Individual typography properties",
|
|
216
|
+
code: `<!-- Or use individual properties when needed -->
|
|
273
217
|
<p className="
|
|
274
218
|
font-sds-body
|
|
275
219
|
text-sds-body-m-400-wide
|
|
@@ -278,48 +222,47 @@ var TAILWIND_TOKEN_GUIDANCE = {
|
|
|
278
222
|
">
|
|
279
223
|
Custom styled text
|
|
280
224
|
</p>`
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
code: `<div className="p-sds-m mx-sds-l my-sds-s">
|
|
225
|
+
}],
|
|
226
|
+
tips: [
|
|
227
|
+
"Use 'narrow' variants for mobile/compact layouts",
|
|
228
|
+
"Use 'wide' variants for desktop/spacious layouts",
|
|
229
|
+
"Font weights: 400 (regular), 500 (medium), 600 (semibold), 700 (bold)"
|
|
230
|
+
]
|
|
231
|
+
},
|
|
232
|
+
spacing: {
|
|
233
|
+
category: "Spacing",
|
|
234
|
+
description: "Consistent spacing scale for padding, margin, and gaps",
|
|
235
|
+
prefixes: [
|
|
236
|
+
"p-",
|
|
237
|
+
"px-",
|
|
238
|
+
"py-",
|
|
239
|
+
"pt-",
|
|
240
|
+
"pr-",
|
|
241
|
+
"pb-",
|
|
242
|
+
"pl-",
|
|
243
|
+
"m-",
|
|
244
|
+
"mx-",
|
|
245
|
+
"my-",
|
|
246
|
+
"mt-",
|
|
247
|
+
"mr-",
|
|
248
|
+
"mb-",
|
|
249
|
+
"ml-",
|
|
250
|
+
"gap-",
|
|
251
|
+
"gap-x-",
|
|
252
|
+
"gap-y-",
|
|
253
|
+
"space-x-",
|
|
254
|
+
"space-y-"
|
|
255
|
+
],
|
|
256
|
+
examples: [
|
|
257
|
+
{
|
|
258
|
+
description: "Padding and margin",
|
|
259
|
+
code: `<div className="p-sds-m mx-sds-l my-sds-s">
|
|
317
260
|
Content with medium padding and different margins
|
|
318
261
|
</div>`
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
description: "Flexbox and grid gaps",
|
|
265
|
+
code: `<div className="flex gap-sds-m">
|
|
323
266
|
<div>Item 1</div>
|
|
324
267
|
<div>Item 2</div>
|
|
325
268
|
</div>
|
|
@@ -327,72 +270,71 @@ var TAILWIND_TOKEN_GUIDANCE = {
|
|
|
327
270
|
<div className="grid grid-cols-3 gap-sds-l">
|
|
328
271
|
<div>Grid item</div>
|
|
329
272
|
</div>`
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
description: "Negative margins for overlapping",
|
|
276
|
+
code: `<div className="-mt-sds-s">
|
|
334
277
|
Overlapping element
|
|
335
278
|
</div>`
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
code: `<div className="rounded-sds-default">
|
|
279
|
+
}
|
|
280
|
+
],
|
|
281
|
+
tips: [
|
|
282
|
+
"Scale: sds-s (small), sds-default (default), sds-m (medium), sds-l (large), sds-xl (extra large)",
|
|
283
|
+
"Use consistent spacing throughout your component",
|
|
284
|
+
"Combine with responsive prefixes: sm:p-sds-m lg:p-sds-l"
|
|
285
|
+
]
|
|
286
|
+
},
|
|
287
|
+
borderRadius: {
|
|
288
|
+
category: "Border Radius",
|
|
289
|
+
description: "Corner radius values for rounded elements",
|
|
290
|
+
prefixes: [
|
|
291
|
+
"rounded-",
|
|
292
|
+
"rounded-t-",
|
|
293
|
+
"rounded-r-",
|
|
294
|
+
"rounded-b-",
|
|
295
|
+
"rounded-l-"
|
|
296
|
+
],
|
|
297
|
+
examples: [{
|
|
298
|
+
description: "Basic rounded corners",
|
|
299
|
+
code: `<div className="rounded-sds-default">
|
|
358
300
|
Standard rounded corners
|
|
359
301
|
</div>
|
|
360
302
|
|
|
361
303
|
<button className="rounded-sds-m">
|
|
362
304
|
More rounded button
|
|
363
305
|
</button>`
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
code: `<div className="rounded-t-sds-l rounded-b-none">
|
|
306
|
+
}, {
|
|
307
|
+
description: "Directional radius",
|
|
308
|
+
code: `<div className="rounded-t-sds-l rounded-b-none">
|
|
368
309
|
Only top corners rounded
|
|
369
310
|
</div>`
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
311
|
+
}],
|
|
312
|
+
tips: [
|
|
313
|
+
"Use sds-default for most UI elements",
|
|
314
|
+
"Larger values (sds-l, sds-xl) for prominent elements",
|
|
315
|
+
"Combine with borders: border rounded-sds-m"
|
|
316
|
+
]
|
|
317
|
+
},
|
|
318
|
+
boxShadow: {
|
|
319
|
+
category: "Box Shadow",
|
|
320
|
+
description: "Elevation shadows for depth and hierarchy",
|
|
321
|
+
prefixes: [
|
|
322
|
+
"shadow-",
|
|
323
|
+
"hover:shadow-",
|
|
324
|
+
"focus:shadow-"
|
|
325
|
+
],
|
|
326
|
+
examples: [{
|
|
327
|
+
description: "Basic shadows",
|
|
328
|
+
code: `<div className="shadow-sds-s">
|
|
386
329
|
Subtle shadow
|
|
387
330
|
</div>
|
|
388
331
|
|
|
389
332
|
<div className="shadow-sds-m">
|
|
390
333
|
Medium elevation
|
|
391
334
|
</div>`
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
code: `<button className="
|
|
335
|
+
}, {
|
|
336
|
+
description: "Interactive shadows",
|
|
337
|
+
code: `<button className="
|
|
396
338
|
shadow-sds-s
|
|
397
339
|
hover:shadow-sds-m
|
|
398
340
|
active:shadow-sds-xs
|
|
@@ -400,18 +342,16 @@ var TAILWIND_TOKEN_GUIDANCE = {
|
|
|
400
342
|
">
|
|
401
343
|
Interactive element
|
|
402
344
|
</button>`
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
}
|
|
345
|
+
}],
|
|
346
|
+
tips: [
|
|
347
|
+
"Use smaller shadows (sds-xs, sds-s) for subtle depth",
|
|
348
|
+
"Use larger shadows (sds-l, sds-xl) for modals and popovers",
|
|
349
|
+
"Combine with hover states for interactive feedback"
|
|
350
|
+
]
|
|
351
|
+
}
|
|
411
352
|
};
|
|
412
353
|
function getTokenGuidance(category) {
|
|
413
|
-
|
|
414
|
-
return `SDS Design System Tokens for Tailwind CSS
|
|
354
|
+
if (!category || category === "all") return `SDS Design System Tokens for Tailwind CSS
|
|
415
355
|
|
|
416
356
|
The Science Design System provides a comprehensive set of design tokens that map directly to Tailwind utilities.
|
|
417
357
|
|
|
@@ -438,450 +378,309 @@ typography: This category can be used for formatting typography in the tailwind.
|
|
|
438
378
|
height, width, borderRadius, boxShadow, breakpoints: These categories can be used for formatting height, width, border radius, box shadow, and breakpoints in the tailwind.config.js file
|
|
439
379
|
spacing: This category can be used for formatting spacing in the tailwind.config.js file
|
|
440
380
|
colors: This category can be used for formatting colors in the tailwind.config.js file`;
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
`;
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
output += `### Examples:
|
|
458
|
-
|
|
459
|
-
`;
|
|
460
|
-
guidance.examples.forEach((example, index) => {
|
|
461
|
-
output += `${index + 1}. **${example.description}**
|
|
462
|
-
\`\`\`jsx
|
|
463
|
-
${example.code}
|
|
464
|
-
\`\`\`
|
|
465
|
-
|
|
466
|
-
`;
|
|
467
|
-
});
|
|
468
|
-
if (guidance.tips && guidance.tips.length > 0) {
|
|
469
|
-
output += `### Tips:
|
|
470
|
-
`;
|
|
471
|
-
guidance.tips.forEach((tip) => {
|
|
472
|
-
output += `- ${tip}
|
|
473
|
-
`;
|
|
474
|
-
});
|
|
475
|
-
}
|
|
476
|
-
return output;
|
|
381
|
+
const guidance = TAILWIND_TOKEN_GUIDANCE[category];
|
|
382
|
+
if (!guidance) return `Category "${category}" not found. Available categories: ${Object.keys(TAILWIND_TOKEN_GUIDANCE).join(", ")}`;
|
|
383
|
+
let output = `## ${guidance.category} Tokens\n\n`;
|
|
384
|
+
output += `${guidance.description}\n\n`;
|
|
385
|
+
output += `**Tailwind Prefixes:** ${guidance.prefixes.join(", ")}\n\n`;
|
|
386
|
+
output += `### Examples:\n\n`;
|
|
387
|
+
guidance.examples.forEach((example, index) => {
|
|
388
|
+
output += `${index + 1}. **${example.description}**\n\`\`\`jsx\n${example.code}\n\`\`\`\n\n`;
|
|
389
|
+
});
|
|
390
|
+
if (guidance.tips && guidance.tips.length > 0) {
|
|
391
|
+
output += `### Tips:\n`;
|
|
392
|
+
guidance.tips.forEach((tip) => {
|
|
393
|
+
output += `- ${tip}\n`;
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
return output;
|
|
477
397
|
}
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
});
|
|
534
|
-
responseContent.push({
|
|
535
|
-
type: "text",
|
|
536
|
-
text: JSON.stringify(result, null, 2)
|
|
537
|
-
});
|
|
538
|
-
return {
|
|
539
|
-
content: responseContent
|
|
540
|
-
};
|
|
541
|
-
} catch (error) {
|
|
542
|
-
return {
|
|
543
|
-
content: [
|
|
544
|
-
{
|
|
545
|
-
type: "text",
|
|
546
|
-
text: `Failed to get Tailwind tokens: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
547
|
-
}
|
|
548
|
-
]
|
|
549
|
-
};
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
);
|
|
553
|
-
}
|
|
398
|
+
//#endregion
|
|
399
|
+
//#region src/tools/get-tailwind-tokens.ts
|
|
400
|
+
const getTailwindTokensTool = {
|
|
401
|
+
name: "get_tailwind_tokens",
|
|
402
|
+
description: "Get all available Tailwind tokens from the SDS design system. Available design tokens include fontFamily, fontSize, fontVariantNumeric, letterSpacing, lineHeight, textDecoration, textTransform, typography, height, width, borderRadius, boxShadow, breakpoints, colors, spacing, and more.",
|
|
403
|
+
async ctx() {
|
|
404
|
+
try {
|
|
405
|
+
return { tailwindTokens: await fetchTailwindTokens() };
|
|
406
|
+
} catch (error) {
|
|
407
|
+
throw new Error(`Failed to initialize tailwind tokens tool: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
408
|
+
}
|
|
409
|
+
},
|
|
410
|
+
exec(server, { ctx, name, description }) {
|
|
411
|
+
server.tool(name, description, { category: z.enum([
|
|
412
|
+
"all",
|
|
413
|
+
"fontFamily",
|
|
414
|
+
"fontSize",
|
|
415
|
+
"fontVariantNumeric",
|
|
416
|
+
"letterSpacing",
|
|
417
|
+
"lineHeight",
|
|
418
|
+
"textDecoration",
|
|
419
|
+
"textTransform",
|
|
420
|
+
"typography",
|
|
421
|
+
"height",
|
|
422
|
+
"width",
|
|
423
|
+
"borderRadius",
|
|
424
|
+
"boxShadow",
|
|
425
|
+
"breakpoints",
|
|
426
|
+
"colors",
|
|
427
|
+
"spacing"
|
|
428
|
+
]).optional().describe("Optional category of tokens to retrieve. If not specified, returns all tokens.") }, async ({ category }) => {
|
|
429
|
+
try {
|
|
430
|
+
const tokens = ctx.tailwindTokens;
|
|
431
|
+
let result;
|
|
432
|
+
if (!category || category === "all") result = tokens;
|
|
433
|
+
else result = tokens[category] || {};
|
|
434
|
+
const responseContent = [];
|
|
435
|
+
const guidance = getTokenGuidance(category);
|
|
436
|
+
responseContent.push({
|
|
437
|
+
type: "text",
|
|
438
|
+
text: guidance
|
|
439
|
+
});
|
|
440
|
+
responseContent.push({
|
|
441
|
+
type: "text",
|
|
442
|
+
text: JSON.stringify(result, null, 2)
|
|
443
|
+
});
|
|
444
|
+
return { content: responseContent };
|
|
445
|
+
} catch (error) {
|
|
446
|
+
return { content: [{
|
|
447
|
+
type: "text",
|
|
448
|
+
text: `Failed to get Tailwind tokens: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
449
|
+
}] };
|
|
450
|
+
}
|
|
451
|
+
});
|
|
452
|
+
}
|
|
554
453
|
};
|
|
555
|
-
|
|
556
|
-
|
|
454
|
+
//#endregion
|
|
455
|
+
//#region src/tools/get-component-docs.ts
|
|
456
|
+
const filename = fileURLToPath(import.meta.url);
|
|
457
|
+
const dirname$1 = path.dirname(filename);
|
|
458
|
+
/**
|
|
459
|
+
* Maps a component name to the corresponding Zeroheight file using manual mapping
|
|
460
|
+
*/
|
|
557
461
|
function mapComponentToFile(componentName, exportedFiles) {
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
CellBasic: "Table",
|
|
601
|
-
CellComponent: "Table",
|
|
602
|
-
CellHeader: "Table",
|
|
603
|
-
// Filter components
|
|
604
|
-
ComplexFilter: "Filters",
|
|
605
|
-
// Other components
|
|
606
|
-
Icon: "Icons",
|
|
607
|
-
Chip: "Tags",
|
|
608
|
-
// Chips are often similar to tags
|
|
609
|
-
Pagination: "Navigation"
|
|
610
|
-
// Pagination is often part of navigation
|
|
611
|
-
};
|
|
612
|
-
const mappedFile = componentToFileMap[componentName];
|
|
613
|
-
if (mappedFile && exportedFiles.includes(mappedFile)) {
|
|
614
|
-
return `${mappedFile}.md`;
|
|
615
|
-
}
|
|
616
|
-
if (exportedFiles.includes(componentName)) {
|
|
617
|
-
return `${componentName}.md`;
|
|
618
|
-
}
|
|
619
|
-
return null;
|
|
462
|
+
const mappedFile = {
|
|
463
|
+
Button: "Buttons",
|
|
464
|
+
ButtonDropdown: "Buttons",
|
|
465
|
+
ButtonIcon: "Buttons",
|
|
466
|
+
ButtonToggle: "Buttons",
|
|
467
|
+
TableHeader: "Table",
|
|
468
|
+
TableRow: "Table",
|
|
469
|
+
InputCheckbox: "Control-Inputs",
|
|
470
|
+
InputRadio: "Control-Inputs",
|
|
471
|
+
InputToggle: "Control-Inputs",
|
|
472
|
+
InputText: "Field-Inputs",
|
|
473
|
+
InputDropdown: "Dropdown-Input",
|
|
474
|
+
InputSearch: "Search-Input",
|
|
475
|
+
InputSlider: "Control-Inputs",
|
|
476
|
+
Dropdown: "Dropdown-Menu",
|
|
477
|
+
DropdownMenu: "Dropdown-Menu",
|
|
478
|
+
ContentCard: "Content-Card",
|
|
479
|
+
LoadingIndicator: "Loading-Indicator",
|
|
480
|
+
NavigationFooter: "Navigation",
|
|
481
|
+
NavigationHeader: "Navigation",
|
|
482
|
+
NavigationJumpTo: "Navigation",
|
|
483
|
+
SegmentedControl: "Segmented-Control",
|
|
484
|
+
List: "Lists",
|
|
485
|
+
Menu: "Dropdown-Menu",
|
|
486
|
+
MenuItem: "Dropdown-Menu",
|
|
487
|
+
MenuSelect: "Dropdown-Menu",
|
|
488
|
+
Tag: "Tags",
|
|
489
|
+
TagFilter: "Tags",
|
|
490
|
+
Tooltip: "Tooltips",
|
|
491
|
+
TooltipCondensed: "Tooltips",
|
|
492
|
+
TooltipTable: "Tooltips",
|
|
493
|
+
CellBasic: "Table",
|
|
494
|
+
CellComponent: "Table",
|
|
495
|
+
CellHeader: "Table",
|
|
496
|
+
ComplexFilter: "Filters",
|
|
497
|
+
Icon: "Icons",
|
|
498
|
+
Chip: "Tags",
|
|
499
|
+
Pagination: "Navigation"
|
|
500
|
+
}[componentName];
|
|
501
|
+
if (mappedFile && exportedFiles.includes(mappedFile)) return `${mappedFile}.md`;
|
|
502
|
+
if (exportedFiles.includes(componentName)) return `${componentName}.md`;
|
|
503
|
+
return null;
|
|
620
504
|
}
|
|
505
|
+
/**
|
|
506
|
+
* Get list of exported documentation files
|
|
507
|
+
*/
|
|
621
508
|
function getExportedFiles() {
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
return [];
|
|
643
|
-
}
|
|
644
|
-
const files = fs.readdirSync(exportDir).filter((file) => file.endsWith(".md") && file !== "README.md").map((file) => file.replace(".md", ""));
|
|
645
|
-
return files;
|
|
646
|
-
} catch (error) {
|
|
647
|
-
console.warn("Could not read exported files:", error);
|
|
648
|
-
return [];
|
|
649
|
-
}
|
|
509
|
+
try {
|
|
510
|
+
const possiblePaths = [
|
|
511
|
+
path.join(dirname$1, "../../data/zeroheight-exports"),
|
|
512
|
+
path.join(dirname$1, "../data/zeroheight-exports"),
|
|
513
|
+
path.join(process.cwd(), "data/zeroheight-exports")
|
|
514
|
+
];
|
|
515
|
+
let exportDir = "";
|
|
516
|
+
for (const p of possiblePaths) if (fs.existsSync(p)) {
|
|
517
|
+
exportDir = p;
|
|
518
|
+
break;
|
|
519
|
+
}
|
|
520
|
+
if (!exportDir) {
|
|
521
|
+
console.warn("Export directory not found in any expected location. Please run Zeroheight export first.");
|
|
522
|
+
return [];
|
|
523
|
+
}
|
|
524
|
+
return fs.readdirSync(exportDir).filter((file) => file.endsWith(".md") && file !== "README.md").map((file) => file.replace(".md", ""));
|
|
525
|
+
} catch (error) {
|
|
526
|
+
console.warn("Could not read exported files:", error);
|
|
527
|
+
return [];
|
|
528
|
+
}
|
|
650
529
|
}
|
|
530
|
+
/**
|
|
531
|
+
* Get list of components that have documentation available
|
|
532
|
+
*/
|
|
651
533
|
function getComponentsWithDocs(allComponents, exportedFiles) {
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
});
|
|
534
|
+
return allComponents.filter((component) => {
|
|
535
|
+
return mapComponentToFile(component, exportedFiles) !== null;
|
|
536
|
+
});
|
|
656
537
|
}
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
for (const p of possiblePaths) {
|
|
712
|
-
if (fs.existsSync(p)) {
|
|
713
|
-
filePath = p;
|
|
714
|
-
break;
|
|
715
|
-
}
|
|
716
|
-
}
|
|
717
|
-
if (!filePath) {
|
|
718
|
-
throw new Error(`Documentation file ${mappedFile} not found`);
|
|
719
|
-
}
|
|
720
|
-
const documentation = fs.readFileSync(filePath, "utf8");
|
|
721
|
-
return {
|
|
722
|
-
content: [
|
|
723
|
-
{
|
|
724
|
-
type: "text",
|
|
725
|
-
text: `# Documentation for ${component}
|
|
726
|
-
|
|
727
|
-
Source: ${mappedFile}
|
|
728
|
-
|
|
729
|
-
${documentation}`
|
|
730
|
-
}
|
|
731
|
-
]
|
|
732
|
-
};
|
|
733
|
-
} catch (error) {
|
|
734
|
-
return {
|
|
735
|
-
content: [
|
|
736
|
-
{
|
|
737
|
-
type: "text",
|
|
738
|
-
text: `Error reading documentation file for '${component}': ${error instanceof Error ? error.message : "Unknown error"}`
|
|
739
|
-
}
|
|
740
|
-
]
|
|
741
|
-
};
|
|
742
|
-
}
|
|
743
|
-
}
|
|
744
|
-
);
|
|
745
|
-
}
|
|
746
|
-
};
|
|
747
|
-
|
|
748
|
-
// src/tools/index.ts
|
|
749
|
-
var tools = [
|
|
750
|
-
getComponentPropsTool,
|
|
751
|
-
getComponentDocsTool,
|
|
752
|
-
listComponentsTool,
|
|
753
|
-
getTailwindTokensTool
|
|
538
|
+
//#endregion
|
|
539
|
+
//#region src/tools/index.ts
|
|
540
|
+
const tools = [
|
|
541
|
+
getComponentPropsTool,
|
|
542
|
+
{
|
|
543
|
+
name: "get_component_docs",
|
|
544
|
+
description: "Get design system documentation for a specific component. Retrieves the corresponding Zeroheight documentation file for the given component name. Supports all SDS components and maps them to their appropriate documentation files.",
|
|
545
|
+
async ctx() {
|
|
546
|
+
try {
|
|
547
|
+
const componentList = await getAllComponentNames();
|
|
548
|
+
const allComponents = [...componentList.components, ...componentList["data-viz"]];
|
|
549
|
+
const exportedFiles = getExportedFiles();
|
|
550
|
+
return {
|
|
551
|
+
componentsWithDocs: getComponentsWithDocs(allComponents, exportedFiles),
|
|
552
|
+
exportedFiles
|
|
553
|
+
};
|
|
554
|
+
} catch (error) {
|
|
555
|
+
throw new Error(`Failed to initialize get component docs tool: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
556
|
+
}
|
|
557
|
+
},
|
|
558
|
+
exec(server, { ctx, name, description }) {
|
|
559
|
+
server.tool(name, description, { component: z.enum(ctx.componentsWithDocs).describe("The name of the SDS component to get documentation for") }, async ({ component }) => {
|
|
560
|
+
try {
|
|
561
|
+
const mappedFile = mapComponentToFile(component, ctx.exportedFiles);
|
|
562
|
+
if (!mappedFile) return { content: [{
|
|
563
|
+
type: "text",
|
|
564
|
+
text: `No documentation found for component '${component}'. This component may not have design system documentation available.`
|
|
565
|
+
}] };
|
|
566
|
+
const possiblePaths = [
|
|
567
|
+
path.join(dirname$1, "../../data/zeroheight-exports", mappedFile),
|
|
568
|
+
path.join(dirname$1, "../data/zeroheight-exports", mappedFile),
|
|
569
|
+
path.join(process.cwd(), "data/zeroheight-exports", mappedFile)
|
|
570
|
+
];
|
|
571
|
+
let filePath = "";
|
|
572
|
+
for (const p of possiblePaths) if (fs.existsSync(p)) {
|
|
573
|
+
filePath = p;
|
|
574
|
+
break;
|
|
575
|
+
}
|
|
576
|
+
if (!filePath) throw new Error(`Documentation file ${mappedFile} not found`);
|
|
577
|
+
return { content: [{
|
|
578
|
+
type: "text",
|
|
579
|
+
text: `# Documentation for ${component}\n\nSource: ${mappedFile}\n\n${fs.readFileSync(filePath, "utf8")}`
|
|
580
|
+
}] };
|
|
581
|
+
} catch (error) {
|
|
582
|
+
return { content: [{
|
|
583
|
+
type: "text",
|
|
584
|
+
text: `Error reading documentation file for '${component}': ${error instanceof Error ? error.message : "Unknown error"}`
|
|
585
|
+
}] };
|
|
586
|
+
}
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
},
|
|
590
|
+
listComponentsTool,
|
|
591
|
+
getTailwindTokensTool
|
|
754
592
|
];
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
name: tool.name
|
|
770
|
-
});
|
|
771
|
-
})
|
|
772
|
-
);
|
|
593
|
+
const registeredToolCache = /* @__PURE__ */ new Map();
|
|
594
|
+
const initializeTools = async (server, config) => {
|
|
595
|
+
const enabledTools = tools.filter((tool) => !tool.disabled?.(config));
|
|
596
|
+
await Promise.all(enabledTools.map(async (tool) => {
|
|
597
|
+
const toolCtx = await tool.ctx?.();
|
|
598
|
+
if (registeredToolCache.has(tool.name)) return;
|
|
599
|
+
registeredToolCache.set(tool.name, tool);
|
|
600
|
+
tool.exec(server, {
|
|
601
|
+
config,
|
|
602
|
+
ctx: toolCtx,
|
|
603
|
+
description: tool.description,
|
|
604
|
+
name: tool.name
|
|
605
|
+
});
|
|
606
|
+
}));
|
|
773
607
|
};
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
608
|
+
//#endregion
|
|
609
|
+
//#region src/resources/index.ts
|
|
610
|
+
const DIRNAME = dirname(fileURLToPath(import.meta.url));
|
|
611
|
+
const MIME_TYPE_MARKDOWN = "text/markdown";
|
|
612
|
+
const UNKNOWN_ERROR = "Unknown error";
|
|
613
|
+
/**
|
|
614
|
+
* Finds the resource file by trying multiple paths
|
|
615
|
+
* to support both dev and production environments
|
|
616
|
+
*/
|
|
778
617
|
function findResourceFile(fileName) {
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
];
|
|
787
|
-
for (const p of possiblePaths) {
|
|
788
|
-
if (existsSync(p)) {
|
|
789
|
-
return p;
|
|
790
|
-
}
|
|
791
|
-
}
|
|
792
|
-
throw new Error(
|
|
793
|
-
`Resource file '${fileName}' not found in any expected location`
|
|
794
|
-
);
|
|
618
|
+
const possiblePaths = [
|
|
619
|
+
join(DIRNAME, "../../data/resources", fileName),
|
|
620
|
+
join(DIRNAME, "../data/resources", fileName),
|
|
621
|
+
join(process.cwd(), "data/resources", fileName)
|
|
622
|
+
];
|
|
623
|
+
for (const p of possiblePaths) if (existsSync(p)) return p;
|
|
624
|
+
throw new Error(`Resource file '${fileName}' not found in any expected location`);
|
|
795
625
|
}
|
|
796
|
-
function initializeResources(
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
};
|
|
843
|
-
} catch (err) {
|
|
844
|
-
const message = err instanceof Error ? err.message : UNKNOWN_ERROR;
|
|
845
|
-
throw new Error("Failed to read component rules: " + message);
|
|
846
|
-
}
|
|
847
|
-
}
|
|
848
|
-
);
|
|
849
|
-
server2.resource(
|
|
850
|
-
"Zeroheight Documentation Rules",
|
|
851
|
-
"sds://rules/zeroheight",
|
|
852
|
-
{
|
|
853
|
-
mimeType: MIME_TYPE_MARKDOWN,
|
|
854
|
-
description: "Rules for following Zeroheight documentation"
|
|
855
|
-
},
|
|
856
|
-
async () => {
|
|
857
|
-
try {
|
|
858
|
-
const filePath = findResourceFile("zeroheight-rules.md");
|
|
859
|
-
const content = readFileSync(filePath, "utf-8");
|
|
860
|
-
return {
|
|
861
|
-
contents: [
|
|
862
|
-
{
|
|
863
|
-
uri: "sds://rules/zeroheight",
|
|
864
|
-
mimeType: MIME_TYPE_MARKDOWN,
|
|
865
|
-
text: content
|
|
866
|
-
}
|
|
867
|
-
]
|
|
868
|
-
};
|
|
869
|
-
} catch (err) {
|
|
870
|
-
const message = err instanceof Error ? err.message : UNKNOWN_ERROR;
|
|
871
|
-
throw new Error("Failed to read Zeroheight rules: " + message);
|
|
872
|
-
}
|
|
873
|
-
}
|
|
874
|
-
);
|
|
626
|
+
function initializeResources(server) {
|
|
627
|
+
server.resource("Figma to Code Translation Rules", "sds://rules/figma", {
|
|
628
|
+
mimeType: MIME_TYPE_MARKDOWN,
|
|
629
|
+
description: "Rules for translating Figma designs to SDS code"
|
|
630
|
+
}, async () => {
|
|
631
|
+
try {
|
|
632
|
+
return { contents: [{
|
|
633
|
+
uri: "sds://rules/figma",
|
|
634
|
+
mimeType: MIME_TYPE_MARKDOWN,
|
|
635
|
+
text: readFileSync(findResourceFile("figma-rules.md"), "utf-8")
|
|
636
|
+
}] };
|
|
637
|
+
} catch (err) {
|
|
638
|
+
const message = err instanceof Error ? err.message : UNKNOWN_ERROR;
|
|
639
|
+
throw new Error("Failed to read Figma rules: " + message);
|
|
640
|
+
}
|
|
641
|
+
});
|
|
642
|
+
server.resource("SDS Component Usage Rules", "sds://rules/components", {
|
|
643
|
+
mimeType: MIME_TYPE_MARKDOWN,
|
|
644
|
+
description: "Guidelines for using SDS components correctly"
|
|
645
|
+
}, async () => {
|
|
646
|
+
try {
|
|
647
|
+
return { contents: [{
|
|
648
|
+
uri: "sds://rules/components",
|
|
649
|
+
mimeType: MIME_TYPE_MARKDOWN,
|
|
650
|
+
text: readFileSync(findResourceFile("sds-component-rules.md"), "utf-8")
|
|
651
|
+
}] };
|
|
652
|
+
} catch (err) {
|
|
653
|
+
const message = err instanceof Error ? err.message : UNKNOWN_ERROR;
|
|
654
|
+
throw new Error("Failed to read component rules: " + message);
|
|
655
|
+
}
|
|
656
|
+
});
|
|
657
|
+
server.resource("Zeroheight Documentation Rules", "sds://rules/zeroheight", {
|
|
658
|
+
mimeType: MIME_TYPE_MARKDOWN,
|
|
659
|
+
description: "Rules for following Zeroheight documentation"
|
|
660
|
+
}, async () => {
|
|
661
|
+
try {
|
|
662
|
+
return { contents: [{
|
|
663
|
+
uri: "sds://rules/zeroheight",
|
|
664
|
+
mimeType: MIME_TYPE_MARKDOWN,
|
|
665
|
+
text: readFileSync(findResourceFile("zeroheight-rules.md"), "utf-8")
|
|
666
|
+
}] };
|
|
667
|
+
} catch (err) {
|
|
668
|
+
const message = err instanceof Error ? err.message : UNKNOWN_ERROR;
|
|
669
|
+
throw new Error("Failed to read Zeroheight rules: " + message);
|
|
670
|
+
}
|
|
671
|
+
});
|
|
875
672
|
}
|
|
876
|
-
|
|
877
|
-
|
|
673
|
+
//#endregion
|
|
674
|
+
//#region src/stdio.ts
|
|
878
675
|
async function main() {
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
676
|
+
await initializeTools(server, {});
|
|
677
|
+
initializeResources(server);
|
|
678
|
+
const transport = new StdioServerTransport();
|
|
679
|
+
await server.connect(transport);
|
|
883
680
|
}
|
|
884
681
|
main().catch((error) => {
|
|
885
|
-
|
|
886
|
-
|
|
682
|
+
console.error("Fatal error in main():", error);
|
|
683
|
+
process.exit(1);
|
|
887
684
|
});
|
|
685
|
+
//#endregion
|
|
686
|
+
export {};
|