@sebgroup/green-core 2.33.0 → 2.34.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 +24 -0
- package/bin/context-cli/framework.d.ts +3 -0
- package/bin/context-cli/framework.js +23 -0
- package/bin/context-cli/index.d.ts +2 -0
- package/bin/context-cli/index.js +363 -0
- package/bin/context-cli/parse-args.d.ts +22 -0
- package/bin/context-cli/parse-args.js +46 -0
- package/bin/mcp-server/errors.d.ts +2 -7
- package/bin/mcp-server/handlers.d.ts +86 -0
- package/bin/mcp-server/handlers.js +356 -0
- package/bin/mcp-server/search.js +8 -1
- package/bin/mcp-server/tools.d.ts +13 -1
- package/bin/mcp-server/tools.js +8 -303
- package/components/table/table.component.js +2 -2
- package/custom-elements.json +3182 -2916
- package/gds-element.js +1 -1
- package/generated/mcp/components.json +1 -1
- package/generated/mcp/icons.json +1 -1
- package/generated/mcp/index.json +1 -1
- package/generated/react/index.d.ts +7 -7
- package/generated/react/index.js +7 -7
- package/package.json +3 -2
- package/utils/helpers/custom-element-scoping.js +1 -1
- package/utils/testing/index.js +6 -2
package/README.md
CHANGED
|
@@ -125,3 +125,27 @@ Then you can just use `<Button />` like a regular React component.
|
|
|
125
125
|
## Documentation
|
|
126
126
|
|
|
127
127
|
Check out the [Storybook (@sebgroup/core)](https://storybook.seb.io/latest/core/) for components and documentation.
|
|
128
|
+
|
|
129
|
+
## Testing
|
|
130
|
+
|
|
131
|
+
The test suite is split by runtime so Node tooling tests do not run in browser mode.
|
|
132
|
+
|
|
133
|
+
- **Node tests** (`src/bin/**`) for developer tooling such as CLI and MCP server:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
nx run core:test:node
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
- **Browser tests** for web components and UI behavior (Chromium + WebKit):
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
nx run core:test:browser
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
- **Full suite** (same split as CI/local default target):
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
nx run core:test
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Use `core:test:node` when working on CLI/MCP code for faster feedback, and `core:test:browser` when working on components, interactions, or rendering behavior.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import "../../chunks/chunk.QU3DSPNU.js";
|
|
2
|
+
const DOCS_FRAMEWORK_CANONICAL = [
|
|
3
|
+
"angular",
|
|
4
|
+
"react",
|
|
5
|
+
"web-component"
|
|
6
|
+
];
|
|
7
|
+
const DOCS_FRAMEWORK_ALIASES = {
|
|
8
|
+
angular: "angular",
|
|
9
|
+
react: "react",
|
|
10
|
+
"web-component": "web-component",
|
|
11
|
+
"web-components": "web-component",
|
|
12
|
+
webcomponent: "web-component",
|
|
13
|
+
webcomponents: "web-component",
|
|
14
|
+
web: "web-component"
|
|
15
|
+
};
|
|
16
|
+
function normalizeDocsFramework(input) {
|
|
17
|
+
const normalized = DOCS_FRAMEWORK_ALIASES[input.trim().toLowerCase()];
|
|
18
|
+
return normalized ?? null;
|
|
19
|
+
}
|
|
20
|
+
export {
|
|
21
|
+
DOCS_FRAMEWORK_CANONICAL,
|
|
22
|
+
normalizeDocsFramework
|
|
23
|
+
};
|
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import "../../chunks/chunk.QU3DSPNU.js";
|
|
3
|
+
import { McpError } from "../mcp-server/errors.js";
|
|
4
|
+
import {
|
|
5
|
+
handleGetComponentDocs,
|
|
6
|
+
handleGetGuide,
|
|
7
|
+
handleGetInstructions,
|
|
8
|
+
handleListGuides,
|
|
9
|
+
handleResolveUri,
|
|
10
|
+
handleSearchComponents
|
|
11
|
+
} from "../mcp-server/handlers.js";
|
|
12
|
+
import { getPackageVersion } from "../mcp-server/utils.js";
|
|
13
|
+
import {
|
|
14
|
+
DOCS_FRAMEWORK_CANONICAL,
|
|
15
|
+
normalizeDocsFramework
|
|
16
|
+
} from "./framework.js";
|
|
17
|
+
import { parseArgs } from "./parse-args.js";
|
|
18
|
+
function getPrimaryTextContent(result) {
|
|
19
|
+
const textBlock = result.content.find(
|
|
20
|
+
(block) => block.type === "text"
|
|
21
|
+
);
|
|
22
|
+
if (!textBlock) {
|
|
23
|
+
throw new Error("Tool response did not include a text content block");
|
|
24
|
+
}
|
|
25
|
+
return textBlock.text;
|
|
26
|
+
}
|
|
27
|
+
import { parseArgs as parseArgs2 } from "./parse-args.js";
|
|
28
|
+
const PROGRAM_NAME = "green-core-context";
|
|
29
|
+
const HELP_TEXT = `
|
|
30
|
+
Green Design System \u2014 Context CLI
|
|
31
|
+
|
|
32
|
+
Provides design system documentation, component APIs, guides, and usage
|
|
33
|
+
instructions directly from the command line. Outputs to stdout for easy
|
|
34
|
+
piping to grep, jq, less, etc.
|
|
35
|
+
|
|
36
|
+
USAGE
|
|
37
|
+
${PROGRAM_NAME} <command> [options]
|
|
38
|
+
|
|
39
|
+
COMMANDS
|
|
40
|
+
search <query> Search for components and icons
|
|
41
|
+
docs <component> <framework> Get component documentation
|
|
42
|
+
get <uri> Fetch raw content by green:// URI
|
|
43
|
+
guides List available guides
|
|
44
|
+
guide <name> Get a specific guide's content
|
|
45
|
+
instructions Get base usage instructions
|
|
46
|
+
|
|
47
|
+
GLOBAL OPTIONS
|
|
48
|
+
-h, --help Show this help message
|
|
49
|
+
-v, --version Show version number
|
|
50
|
+
|
|
51
|
+
Run '${PROGRAM_NAME} <command> --help' for command-specific options.
|
|
52
|
+
`.trim();
|
|
53
|
+
const SEARCH_HELP = `
|
|
54
|
+
Search for Green Design System components and icons by name, description,
|
|
55
|
+
or functionality.
|
|
56
|
+
|
|
57
|
+
USAGE
|
|
58
|
+
${PROGRAM_NAME} search <query> [options]
|
|
59
|
+
|
|
60
|
+
ARGUMENTS
|
|
61
|
+
query Search term (required)
|
|
62
|
+
|
|
63
|
+
OPTIONS
|
|
64
|
+
--category <type> Filter by type: component, icon, all
|
|
65
|
+
(default: all)
|
|
66
|
+
--no-split-terms Don't split query on spaces/commas
|
|
67
|
+
--match-all Require ALL terms to match (AND logic)
|
|
68
|
+
--use-regex Treat query as a regular expression
|
|
69
|
+
--max-results <n> Maximum results to return, 1-100
|
|
70
|
+
(default: 20)
|
|
71
|
+
-h, --help Show this help message
|
|
72
|
+
|
|
73
|
+
EXAMPLES
|
|
74
|
+
${PROGRAM_NAME} search button
|
|
75
|
+
${PROGRAM_NAME} search "dropdown menu" --match-all
|
|
76
|
+
${PROGRAM_NAME} search "^gds-card" --use-regex
|
|
77
|
+
${PROGRAM_NAME} search arrow --category icon
|
|
78
|
+
${PROGRAM_NAME} search button | jq '.results[0]'
|
|
79
|
+
`.trim();
|
|
80
|
+
const DOCS_HELP = `
|
|
81
|
+
Get complete documentation for a specific Green component, including
|
|
82
|
+
framework-specific import paths, API reference, and design guidelines.
|
|
83
|
+
|
|
84
|
+
USAGE
|
|
85
|
+
${PROGRAM_NAME} docs <component> <framework> [options]
|
|
86
|
+
|
|
87
|
+
ARGUMENTS
|
|
88
|
+
component Component name, e.g. "button" or
|
|
89
|
+
"gds-button" (required)
|
|
90
|
+
framework Target framework (required)
|
|
91
|
+
Allowed: ${DOCS_FRAMEWORK_CANONICAL.join(", ")}
|
|
92
|
+
Aliases: web, webcomponent, web-components
|
|
93
|
+
|
|
94
|
+
OPTIONS
|
|
95
|
+
--no-guidelines Exclude UX/design guidelines
|
|
96
|
+
--no-instructions Exclude agent-specific instructions
|
|
97
|
+
-h, --help Show this help message
|
|
98
|
+
|
|
99
|
+
EXAMPLES
|
|
100
|
+
${PROGRAM_NAME} docs button angular
|
|
101
|
+
${PROGRAM_NAME} docs gds-dropdown react
|
|
102
|
+
${PROGRAM_NAME} docs card web
|
|
103
|
+
${PROGRAM_NAME} docs card web-component --no-guidelines
|
|
104
|
+
`.trim();
|
|
105
|
+
const GET_HELP = `
|
|
106
|
+
Fetch raw content for a green:// resource URI. Use 'search' to discover
|
|
107
|
+
URIs, then use 'get' to retrieve the raw document content.
|
|
108
|
+
|
|
109
|
+
USAGE
|
|
110
|
+
${PROGRAM_NAME} get <uri>
|
|
111
|
+
|
|
112
|
+
ARGUMENTS
|
|
113
|
+
uri A green:// resource URI (required)
|
|
114
|
+
|
|
115
|
+
SUPPORTED URI FORMATS
|
|
116
|
+
green://components/{name}/{doc} Component docs (api, angular, react,
|
|
117
|
+
guidelines, instructions)
|
|
118
|
+
green://icons/{name}/{doc} Icon docs (api, angular, react)
|
|
119
|
+
green://guides/{name} Setup and framework guides
|
|
120
|
+
green://concepts/{name} Conceptual documentation
|
|
121
|
+
green://instructions Base instructions document
|
|
122
|
+
|
|
123
|
+
OPTIONS
|
|
124
|
+
-h, --help Show this help message
|
|
125
|
+
|
|
126
|
+
EXAMPLES
|
|
127
|
+
${PROGRAM_NAME} get green://components/button/api
|
|
128
|
+
${PROGRAM_NAME} get green://components/dropdown/angular
|
|
129
|
+
${PROGRAM_NAME} get green://guides/react
|
|
130
|
+
${PROGRAM_NAME} get green://concepts/tokens
|
|
131
|
+
${PROGRAM_NAME} get green://instructions
|
|
132
|
+
`.trim();
|
|
133
|
+
const GUIDES_HELP = `
|
|
134
|
+
List available setup guides and conceptual documentation.
|
|
135
|
+
|
|
136
|
+
USAGE
|
|
137
|
+
${PROGRAM_NAME} guides [options]
|
|
138
|
+
|
|
139
|
+
OPTIONS
|
|
140
|
+
--category <type> Filter by category: framework-setup,
|
|
141
|
+
getting-started, concepts,
|
|
142
|
+
troubleshooting, migration, all
|
|
143
|
+
(default: all)
|
|
144
|
+
--framework <name> Filter by framework: angular, react, all
|
|
145
|
+
-h, --help Show this help message
|
|
146
|
+
|
|
147
|
+
EXAMPLES
|
|
148
|
+
${PROGRAM_NAME} guides
|
|
149
|
+
${PROGRAM_NAME} guides --category concepts
|
|
150
|
+
${PROGRAM_NAME} guides --framework angular
|
|
151
|
+
`.trim();
|
|
152
|
+
const GUIDE_HELP = `
|
|
153
|
+
Get the full content of a specific guide.
|
|
154
|
+
|
|
155
|
+
USAGE
|
|
156
|
+
${PROGRAM_NAME} guide <name>
|
|
157
|
+
|
|
158
|
+
ARGUMENTS
|
|
159
|
+
name Guide name, e.g. "angular", "installing",
|
|
160
|
+
"troubleshooting" (required).
|
|
161
|
+
Run '${PROGRAM_NAME} guides' to see
|
|
162
|
+
available guide names.
|
|
163
|
+
|
|
164
|
+
OPTIONS
|
|
165
|
+
-h, --help Show this help message
|
|
166
|
+
|
|
167
|
+
EXAMPLES
|
|
168
|
+
${PROGRAM_NAME} guide angular
|
|
169
|
+
${PROGRAM_NAME} guide troubleshooting | less
|
|
170
|
+
`.trim();
|
|
171
|
+
const INSTRUCTIONS_HELP = `
|
|
172
|
+
Get the base instructions for using Green Design System. Contains critical
|
|
173
|
+
rules, typography guidelines, layout system requirements, and best practices.
|
|
174
|
+
|
|
175
|
+
USAGE
|
|
176
|
+
${PROGRAM_NAME} instructions
|
|
177
|
+
|
|
178
|
+
OPTIONS
|
|
179
|
+
-h, --help Show this help message
|
|
180
|
+
`.trim();
|
|
181
|
+
async function runSearch(args) {
|
|
182
|
+
if (args.flags["h"] || args.flags["help"]) {
|
|
183
|
+
process.stdout.write(SEARCH_HELP + "\n");
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
const query = args.positional[0];
|
|
187
|
+
if (!query) {
|
|
188
|
+
process.stderr.write("Error: search requires a <query> argument.\n\n");
|
|
189
|
+
process.stderr.write(SEARCH_HELP + "\n");
|
|
190
|
+
process.exitCode = 1;
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
const input = { query };
|
|
194
|
+
if (args.flags["category"] !== void 0) {
|
|
195
|
+
input.category = args.flags["category"];
|
|
196
|
+
}
|
|
197
|
+
if (args.flags["split-terms"] === false) {
|
|
198
|
+
input.splitTerms = false;
|
|
199
|
+
}
|
|
200
|
+
if (args.flags["match-all"]) {
|
|
201
|
+
input.matchAll = true;
|
|
202
|
+
}
|
|
203
|
+
if (args.flags["use-regex"]) {
|
|
204
|
+
input.useRegex = true;
|
|
205
|
+
}
|
|
206
|
+
if (args.flags["max-results"] !== void 0) {
|
|
207
|
+
const n = Number(args.flags["max-results"]);
|
|
208
|
+
if (Number.isNaN(n)) {
|
|
209
|
+
process.stderr.write("Error: --max-results must be a number.\n");
|
|
210
|
+
process.exitCode = 1;
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
input.maxResults = n;
|
|
214
|
+
}
|
|
215
|
+
const result = await handleSearchComponents(input);
|
|
216
|
+
process.stdout.write(getPrimaryTextContent(result) + "\n");
|
|
217
|
+
}
|
|
218
|
+
async function runDocs(args) {
|
|
219
|
+
if (args.flags["h"] || args.flags["help"]) {
|
|
220
|
+
process.stdout.write(DOCS_HELP + "\n");
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
const componentName = args.positional[0];
|
|
224
|
+
const frameworkInput = args.positional[1];
|
|
225
|
+
if (!componentName || !frameworkInput) {
|
|
226
|
+
process.stderr.write(
|
|
227
|
+
"Error: docs requires <component> and <framework> arguments.\n\n"
|
|
228
|
+
);
|
|
229
|
+
process.stderr.write(DOCS_HELP + "\n");
|
|
230
|
+
process.exitCode = 1;
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
const framework = normalizeDocsFramework(frameworkInput);
|
|
234
|
+
if (!framework) {
|
|
235
|
+
process.stderr.write(
|
|
236
|
+
`Error: Invalid framework '${frameworkInput}'. Allowed values: ${DOCS_FRAMEWORK_CANONICAL.join(", ")}.
|
|
237
|
+
`
|
|
238
|
+
);
|
|
239
|
+
process.stderr.write(
|
|
240
|
+
"Aliases accepted for web-component: web, webcomponent, web-components.\n\n"
|
|
241
|
+
);
|
|
242
|
+
process.stderr.write(DOCS_HELP + "\n");
|
|
243
|
+
process.exitCode = 1;
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
const input = { componentName, framework };
|
|
247
|
+
if (args.flags["guidelines"] === false) {
|
|
248
|
+
input.includeGuidelines = false;
|
|
249
|
+
}
|
|
250
|
+
if (args.flags["instructions"] === false) {
|
|
251
|
+
input.includeInstructions = false;
|
|
252
|
+
}
|
|
253
|
+
const result = await handleGetComponentDocs(input);
|
|
254
|
+
process.stdout.write(getPrimaryTextContent(result) + "\n");
|
|
255
|
+
}
|
|
256
|
+
async function runGet(args) {
|
|
257
|
+
if (args.flags["h"] || args.flags["help"]) {
|
|
258
|
+
process.stdout.write(GET_HELP + "\n");
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
const uri = args.positional[0];
|
|
262
|
+
if (!uri) {
|
|
263
|
+
process.stderr.write("Error: get requires a <uri> argument.\n\n");
|
|
264
|
+
process.stderr.write(GET_HELP + "\n");
|
|
265
|
+
process.exitCode = 1;
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
const result = await handleResolveUri(uri);
|
|
269
|
+
process.stdout.write(getPrimaryTextContent(result) + "\n");
|
|
270
|
+
}
|
|
271
|
+
async function runGuides(args) {
|
|
272
|
+
if (args.flags["h"] || args.flags["help"]) {
|
|
273
|
+
process.stdout.write(GUIDES_HELP + "\n");
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
const input = {};
|
|
277
|
+
if (args.flags["category"] !== void 0) {
|
|
278
|
+
input.category = args.flags["category"];
|
|
279
|
+
}
|
|
280
|
+
if (args.flags["framework"] !== void 0) {
|
|
281
|
+
input.framework = args.flags["framework"];
|
|
282
|
+
}
|
|
283
|
+
const result = await handleListGuides(input);
|
|
284
|
+
process.stdout.write(getPrimaryTextContent(result) + "\n");
|
|
285
|
+
}
|
|
286
|
+
async function runGuide(args) {
|
|
287
|
+
if (args.flags["h"] || args.flags["help"]) {
|
|
288
|
+
process.stdout.write(GUIDE_HELP + "\n");
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
const name = args.positional[0];
|
|
292
|
+
if (!name) {
|
|
293
|
+
process.stderr.write("Error: guide requires a <name> argument.\n\n");
|
|
294
|
+
process.stderr.write(GUIDE_HELP + "\n");
|
|
295
|
+
process.exitCode = 1;
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
const result = await handleGetGuide({ name });
|
|
299
|
+
process.stdout.write(getPrimaryTextContent(result) + "\n");
|
|
300
|
+
}
|
|
301
|
+
async function runInstructions(args) {
|
|
302
|
+
if (args.flags["h"] || args.flags["help"]) {
|
|
303
|
+
process.stdout.write(INSTRUCTIONS_HELP + "\n");
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
const result = await handleGetInstructions();
|
|
307
|
+
const cliText = getPrimaryTextContent(result).replace(/\bMCP server\b/gi, "Context CLI").replace(/\bMCP Server\b/g, "Context CLI").replace(/\bMCP\b/g, "CLI");
|
|
308
|
+
process.stdout.write(cliText + "\n");
|
|
309
|
+
}
|
|
310
|
+
async function main() {
|
|
311
|
+
const args = parseArgs(process.argv.slice(2));
|
|
312
|
+
if (args.flags["v"] || args.flags["version"]) {
|
|
313
|
+
const version = await getPackageVersion();
|
|
314
|
+
process.stdout.write(version + "\n");
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
if (!args.command) {
|
|
318
|
+
process.stdout.write(HELP_TEXT + "\n");
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
switch (args.command) {
|
|
322
|
+
case "search":
|
|
323
|
+
await runSearch(args);
|
|
324
|
+
break;
|
|
325
|
+
case "docs":
|
|
326
|
+
await runDocs(args);
|
|
327
|
+
break;
|
|
328
|
+
case "get":
|
|
329
|
+
await runGet(args);
|
|
330
|
+
break;
|
|
331
|
+
case "guides":
|
|
332
|
+
await runGuides(args);
|
|
333
|
+
break;
|
|
334
|
+
case "guide":
|
|
335
|
+
await runGuide(args);
|
|
336
|
+
break;
|
|
337
|
+
case "instructions":
|
|
338
|
+
await runInstructions(args);
|
|
339
|
+
break;
|
|
340
|
+
default:
|
|
341
|
+
process.stderr.write(`Error: Unknown command '${args.command}'.
|
|
342
|
+
|
|
343
|
+
`);
|
|
344
|
+
process.stdout.write(HELP_TEXT + "\n");
|
|
345
|
+
process.exitCode = 1;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
main().catch((error) => {
|
|
349
|
+
if (error instanceof McpError) {
|
|
350
|
+
process.stderr.write(`Error [${error.code}]: ${error.message}
|
|
351
|
+
`);
|
|
352
|
+
} else if (error instanceof Error) {
|
|
353
|
+
process.stderr.write(`Error: ${error.message}
|
|
354
|
+
`);
|
|
355
|
+
} else {
|
|
356
|
+
process.stderr.write(`Error: ${String(error)}
|
|
357
|
+
`);
|
|
358
|
+
}
|
|
359
|
+
process.exitCode = 1;
|
|
360
|
+
});
|
|
361
|
+
export {
|
|
362
|
+
parseArgs2 as parseArgs
|
|
363
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** Parsed result from the argument parser */
|
|
2
|
+
export interface ParsedArgs {
|
|
3
|
+
/** The subcommand (or null for top-level flags like --help / --version) */
|
|
4
|
+
command: string | null;
|
|
5
|
+
/** Positional arguments following the subcommand */
|
|
6
|
+
positional: string[];
|
|
7
|
+
/** Named flags (e.g. --category → category) mapped to their values */
|
|
8
|
+
flags: Record<string, string | boolean>;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Parse process.argv into a structured object.
|
|
12
|
+
*
|
|
13
|
+
* Supports:
|
|
14
|
+
* - Positional arguments
|
|
15
|
+
* - Long flags: --flag, --flag value, --flag=value
|
|
16
|
+
* - Short flags: -h, -v
|
|
17
|
+
* - Boolean negation: --no-<flag> → flag = false
|
|
18
|
+
*
|
|
19
|
+
* @param argv - Raw argument array (typically process.argv.slice(2))
|
|
20
|
+
* @returns Parsed command, positional args, and flags
|
|
21
|
+
*/
|
|
22
|
+
export declare function parseArgs(argv: string[]): ParsedArgs;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import "../../chunks/chunk.QU3DSPNU.js";
|
|
2
|
+
function parseArgs(argv) {
|
|
3
|
+
const positional = [];
|
|
4
|
+
const flags = {};
|
|
5
|
+
let i = 0;
|
|
6
|
+
while (i < argv.length) {
|
|
7
|
+
const arg = argv[i];
|
|
8
|
+
if (arg === "--") {
|
|
9
|
+
positional.push(...argv.slice(i + 1));
|
|
10
|
+
break;
|
|
11
|
+
}
|
|
12
|
+
if (arg.startsWith("--")) {
|
|
13
|
+
const eqIndex = arg.indexOf("=");
|
|
14
|
+
if (eqIndex !== -1) {
|
|
15
|
+
const key = arg.slice(2, eqIndex);
|
|
16
|
+
flags[key] = arg.slice(eqIndex + 1);
|
|
17
|
+
} else {
|
|
18
|
+
const key = arg.slice(2);
|
|
19
|
+
if (key.startsWith("no-")) {
|
|
20
|
+
flags[key.slice(3)] = false;
|
|
21
|
+
} else {
|
|
22
|
+
const next = argv[i + 1];
|
|
23
|
+
if (next !== void 0 && !next.startsWith("-")) {
|
|
24
|
+
flags[key] = next;
|
|
25
|
+
i++;
|
|
26
|
+
} else {
|
|
27
|
+
flags[key] = true;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
} else if (arg.startsWith("-") && arg.length === 2) {
|
|
32
|
+
flags[arg.slice(1)] = true;
|
|
33
|
+
} else {
|
|
34
|
+
positional.push(arg);
|
|
35
|
+
}
|
|
36
|
+
i++;
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
command: positional.length > 0 ? positional[0] : null,
|
|
40
|
+
positional: positional.slice(1),
|
|
41
|
+
flags
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
export {
|
|
45
|
+
parseArgs
|
|
46
|
+
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Error handling for the Green Design System MCP Server
|
|
3
3
|
*/
|
|
4
|
+
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
4
5
|
/**
|
|
5
6
|
* Error codes for MCP operations
|
|
6
7
|
*/
|
|
@@ -75,13 +76,7 @@ export declare class RegexError extends McpError {
|
|
|
75
76
|
* @param error - The error to convert
|
|
76
77
|
* @returns Formatted error response
|
|
77
78
|
*/
|
|
78
|
-
export declare function formatErrorResponse(error: unknown):
|
|
79
|
-
content: Array<{
|
|
80
|
-
type: string;
|
|
81
|
-
text: string;
|
|
82
|
-
}>;
|
|
83
|
-
isError: boolean;
|
|
84
|
-
};
|
|
79
|
+
export declare function formatErrorResponse(error: unknown): CallToolResult;
|
|
85
80
|
/**
|
|
86
81
|
* Log error with structured information
|
|
87
82
|
* @param error - The error to log
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool handler implementations for the Green Design System.
|
|
3
|
+
*
|
|
4
|
+
* This module contains the core business logic for each tool operation:
|
|
5
|
+
* searching components, fetching documentation, listing guides, and
|
|
6
|
+
* retrieving instructions. These handlers are shared between the MCP
|
|
7
|
+
* server (tools.ts) and the context CLI (context-cli/index.ts).
|
|
8
|
+
*
|
|
9
|
+
* Each handler:
|
|
10
|
+
* 1. Validates its input via the validation module
|
|
11
|
+
* 2. Loads pre-generated MCP data from disk
|
|
12
|
+
* 3. Applies business logic (search, filtering, assembly)
|
|
13
|
+
* 4. Returns a uniform `{ content: [{ type: 'text', text: string }] }` response
|
|
14
|
+
*
|
|
15
|
+
* @module handlers
|
|
16
|
+
*/
|
|
17
|
+
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
18
|
+
/**
|
|
19
|
+
* Standard response shape returned by all handlers.
|
|
20
|
+
* Mirrors the MCP content response format so both the MCP server
|
|
21
|
+
* and the CLI can consume results uniformly.
|
|
22
|
+
*/
|
|
23
|
+
export type HandlerResponse = CallToolResult;
|
|
24
|
+
/**
|
|
25
|
+
* Handle search_components — search for components and icons by name,
|
|
26
|
+
* description, or functionality.
|
|
27
|
+
*
|
|
28
|
+
* @param input - Raw input object (validated internally)
|
|
29
|
+
* @returns Search results as JSON text
|
|
30
|
+
* @throws {ValidationError} If input fails validation
|
|
31
|
+
*/
|
|
32
|
+
export declare function handleSearchComponents(input: unknown): Promise<HandlerResponse>;
|
|
33
|
+
/**
|
|
34
|
+
* Handle get_component_docs — retrieve full documentation for a specific
|
|
35
|
+
* component, including framework-specific imports, API reference, design
|
|
36
|
+
* guidelines, and agent usage instructions.
|
|
37
|
+
*
|
|
38
|
+
* @param input - Raw input object (validated internally)
|
|
39
|
+
* @returns Assembled markdown documentation
|
|
40
|
+
* @throws {ValidationError} If input fails validation
|
|
41
|
+
* @throws {NotFoundError} If the component cannot be found
|
|
42
|
+
*/
|
|
43
|
+
export declare function handleGetComponentDocs(input: unknown): Promise<HandlerResponse>;
|
|
44
|
+
/**
|
|
45
|
+
* Handle list_guides — list available setup guides and conceptual
|
|
46
|
+
* documentation, optionally filtered by category and framework.
|
|
47
|
+
*
|
|
48
|
+
* @param input - Raw input object (validated internally)
|
|
49
|
+
* @returns JSON list of guides with metadata and resource URIs
|
|
50
|
+
* @throws {ValidationError} If input fails validation
|
|
51
|
+
* @throws {NotFoundError} If the global index cannot be loaded
|
|
52
|
+
*/
|
|
53
|
+
export declare function handleListGuides(input: unknown): Promise<HandlerResponse>;
|
|
54
|
+
/**
|
|
55
|
+
* Handle get_guide — retrieve the full content of a specific guide.
|
|
56
|
+
*
|
|
57
|
+
* @param input - Raw input object (validated internally)
|
|
58
|
+
* @returns Guide content as markdown
|
|
59
|
+
* @throws {ValidationError} If input fails validation
|
|
60
|
+
* @throws {NotFoundError} If the guide cannot be found
|
|
61
|
+
*/
|
|
62
|
+
export declare function handleGetGuide(input: unknown): Promise<HandlerResponse>;
|
|
63
|
+
/**
|
|
64
|
+
* Handle get_instructions — retrieve the base instructions document
|
|
65
|
+
* containing critical rules, typography guidelines, layout system
|
|
66
|
+
* requirements, and general best practices.
|
|
67
|
+
*
|
|
68
|
+
* @returns Instructions content as markdown
|
|
69
|
+
* @throws {NotFoundError} If instructions are not available
|
|
70
|
+
*/
|
|
71
|
+
export declare function handleGetInstructions(): Promise<HandlerResponse>;
|
|
72
|
+
/**
|
|
73
|
+
* Handle URI resolution — read the raw content of a green:// resource URI.
|
|
74
|
+
*
|
|
75
|
+
* Supports all URI types:
|
|
76
|
+
* - green://components/{name}/{docType} (e.g. green://components/button/api)
|
|
77
|
+
* - green://icons/{name}/{docType} (e.g. green://icons/arrow/api)
|
|
78
|
+
* - green://guides/{name} (e.g. green://guides/angular)
|
|
79
|
+
* - green://concepts/{name} (e.g. green://concepts/tokens)
|
|
80
|
+
* - green://instructions (the root instructions document)
|
|
81
|
+
*
|
|
82
|
+
* @param uri - A green:// resource URI string
|
|
83
|
+
* @returns Raw markdown content of the resource
|
|
84
|
+
* @throws {NotFoundError} If the URI is invalid or the resource doesn't exist
|
|
85
|
+
*/
|
|
86
|
+
export declare function handleResolveUri(uri: string): Promise<HandlerResponse>;
|