@seed-ship/mcp-ui-cli 1.0.2

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/CHANGELOG.md ADDED
@@ -0,0 +1,76 @@
1
+ # @mcp-ui/cli Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## [1.0.0] - 2025-01-14
6
+
7
+ ### Added
8
+ - Initial release of `@mcp-ui/cli` package
9
+ - Command-line interface for component registry operations
10
+ - `validate` command: Validates registries against JSON Schema and Zod
11
+ - `generate-types` command: Generates TypeScript types from component schemas
12
+ - `test-examples` command: Tests all component examples for validity
13
+ - `diff` command: Compares registry versions for breaking changes
14
+
15
+ ### Features
16
+ - **Dual Validation**: Both JSON Schema (Ajv) and Zod validation
17
+ - **Type Generation**: Automatic TypeScript type generation with json-schema-to-typescript
18
+ - **Example Testing**: Validates all component examples against schemas
19
+ - **Breaking Change Detection**: Semantic diff with breaking/non-breaking classification
20
+ - **Beautiful Output**: Colorful terminal output with chalk and ora spinners
21
+ - **Exit Codes**: Proper exit codes for CI/CD integration
22
+ - **Verbose Mode**: Detailed output for debugging
23
+
24
+ ### Commands
25
+
26
+ #### validate
27
+ ```bash
28
+ mcp-ui validate <file> [--strict] [--verbose]
29
+ ```
30
+ Validates a component registry against both JSON Schema and Zod schemas.
31
+
32
+ #### generate-types
33
+ ```bash
34
+ mcp-ui generate-types <input> [output] [--namespace <name>] [--export-all]
35
+ ```
36
+ Generates TypeScript types from component schemas.
37
+
38
+ #### test-examples
39
+ ```bash
40
+ mcp-ui test-examples <file> [--component <id>] [--verbose]
41
+ ```
42
+ Tests all examples in a component registry.
43
+
44
+ #### diff
45
+ ```bash
46
+ mcp-ui diff <old> <new> [--json] [--fail-on-breaking]
47
+ ```
48
+ Compares two registry versions for breaking changes.
49
+
50
+ ### Dependencies
51
+ - commander: CLI framework
52
+ - ajv: JSON Schema validation
53
+ - zod: Runtime TypeScript validation
54
+ - json-schema-to-typescript: Type generation
55
+ - chalk: Terminal colors
56
+ - ora: Spinners
57
+
58
+ ### Installation
59
+ ```bash
60
+ pnpm add -D @mcp-ui/cli
61
+ ```
62
+
63
+ ### Usage
64
+ ```bash
65
+ # Validate a registry
66
+ mcp-ui validate ./my-registry.json
67
+
68
+ # Generate types
69
+ mcp-ui generate-types ./my-registry.json ./types.ts
70
+
71
+ # Test examples
72
+ mcp-ui test-examples ./my-registry.json
73
+
74
+ # Check for breaking changes
75
+ mcp-ui diff ./old-registry.json ./new-registry.json --fail-on-breaking
76
+ ```
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Gabriel Brument
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,67 @@
1
+ # @mcp-ui/cli
2
+
3
+ CLI tools for validating and generating MCP UI component registries.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pnpm add -D @mcp-ui/cli
9
+ ```
10
+
11
+ ## Commands
12
+
13
+ ### Validate Registry
14
+
15
+ ```bash
16
+ mcp-ui validate registry.json
17
+ ```
18
+
19
+ Validates a component registry against the JSON Schema specification.
20
+
21
+ ### Generate TypeScript Types
22
+
23
+ ```bash
24
+ mcp-ui generate-types registry.json --output types/
25
+ ```
26
+
27
+ Generates TypeScript type definitions from a component registry.
28
+
29
+ ### Test Examples
30
+
31
+ ```bash
32
+ mcp-ui test-examples registry.json
33
+ ```
34
+
35
+ Validates all component examples in the registry.
36
+
37
+ ### Create Component
38
+
39
+ ```bash
40
+ mcp-ui create-component quickchart-line
41
+ ```
42
+
43
+ Creates a new component template.
44
+
45
+ ### Check Breaking Changes
46
+
47
+ ```bash
48
+ mcp-ui diff registry-old.json registry-new.json
49
+ ```
50
+
51
+ Compares two registry files and reports breaking changes.
52
+
53
+ ## Usage in CI
54
+
55
+ ```yaml
56
+ # .github/workflows/validate.yml
57
+ - name: Validate Component Registry
58
+ run: pnpm mcp-ui validate registry.json
59
+ ```
60
+
61
+ ## Documentation
62
+
63
+ See the [full documentation](../../docs/features/generative-ui/) for more details.
64
+
65
+ ## License
66
+
67
+ MIT
package/dist/cli.cjs ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ const commander = require("commander");
4
+ const diff = require("./diff-B1c8BBVB.cjs");
5
+ const program = new commander.Command();
6
+ program.name("mcp-ui").description("CLI tools for MCP UI component registries").version("1.0.0");
7
+ program.command("validate").description("Validate a component registry against the schema").argument("<file>", "Path to registry JSON file").option("--strict", "Enable strict validation mode", false).option("--verbose", "Show detailed validation output", false).action(diff.validateCommand);
8
+ program.command("generate-types").description("Generate TypeScript types from a registry").argument("<input>", "Path to registry JSON file").argument("[output]", "Output file path (default: stdout)").option("--namespace <name>", "Wrap types in a namespace").option("--export-all", "Export all generated types", false).action(diff.generateTypesCommand);
9
+ program.command("test-examples").description("Test all examples in a component registry").argument("<file>", "Path to registry JSON file").option("--component <id>", "Test only specific component").option("--verbose", "Show detailed test output", false).action(diff.testExamplesCommand);
10
+ program.command("diff").description("Compare two registry versions for breaking changes").argument("<old>", "Path to old registry JSON file").argument("<new>", "Path to new registry JSON file").option("--json", "Output diff as JSON", false).option("--fail-on-breaking", "Exit with error if breaking changes found", false).action(diff.diffCommand);
11
+ program.parse();
12
+ //# sourceMappingURL=cli.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.cjs","sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * @seed-ship/mcp-ui-cli\n *\n * Command-line interface for MCP UI component registry operations\n */\n\nimport { Command } from 'commander'\nimport { validateCommand } from './commands/validate.js'\nimport { generateTypesCommand } from './commands/generate-types.js'\nimport { testExamplesCommand } from './commands/test-examples.js'\nimport { diffCommand } from './commands/diff.js'\n\nconst program = new Command()\n\nprogram.name('mcp-ui').description('CLI tools for MCP UI component registries').version('1.0.0')\n\n// Validate command\nprogram\n .command('validate')\n .description('Validate a component registry against the schema')\n .argument('<file>', 'Path to registry JSON file')\n .option('--strict', 'Enable strict validation mode', false)\n .option('--verbose', 'Show detailed validation output', false)\n .action(validateCommand)\n\n// Generate types command\nprogram\n .command('generate-types')\n .description('Generate TypeScript types from a registry')\n .argument('<input>', 'Path to registry JSON file')\n .argument('[output]', 'Output file path (default: stdout)')\n .option('--namespace <name>', 'Wrap types in a namespace')\n .option('--export-all', 'Export all generated types', false)\n .action(generateTypesCommand)\n\n// Test examples command\nprogram\n .command('test-examples')\n .description('Test all examples in a component registry')\n .argument('<file>', 'Path to registry JSON file')\n .option('--component <id>', 'Test only specific component')\n .option('--verbose', 'Show detailed test output', false)\n .action(testExamplesCommand)\n\n// Diff command\nprogram\n .command('diff')\n .description('Compare two registry versions for breaking changes')\n .argument('<old>', 'Path to old registry JSON file')\n .argument('<new>', 'Path to new registry JSON file')\n .option('--json', 'Output diff as JSON', false)\n .option('--fail-on-breaking', 'Exit with error if breaking changes found', false)\n .action(diffCommand)\n\nprogram.parse()\n"],"names":["Command","validateCommand","generateTypesCommand","testExamplesCommand","diffCommand"],"mappings":";;;;AAcA,MAAM,UAAU,IAAIA,UAAAA,QAAA;AAEpB,QAAQ,KAAK,QAAQ,EAAE,YAAY,2CAA2C,EAAE,QAAQ,OAAO;AAG/F,QACG,QAAQ,UAAU,EAClB,YAAY,kDAAkD,EAC9D,SAAS,UAAU,4BAA4B,EAC/C,OAAO,YAAY,iCAAiC,KAAK,EACzD,OAAO,aAAa,mCAAmC,KAAK,EAC5D,OAAOC,oBAAe;AAGzB,QACG,QAAQ,gBAAgB,EACxB,YAAY,2CAA2C,EACvD,SAAS,WAAW,4BAA4B,EAChD,SAAS,YAAY,oCAAoC,EACzD,OAAO,sBAAsB,2BAA2B,EACxD,OAAO,gBAAgB,8BAA8B,KAAK,EAC1D,OAAOC,yBAAoB;AAG9B,QACG,QAAQ,eAAe,EACvB,YAAY,2CAA2C,EACvD,SAAS,UAAU,4BAA4B,EAC/C,OAAO,oBAAoB,8BAA8B,EACzD,OAAO,aAAa,6BAA6B,KAAK,EACtD,OAAOC,wBAAmB;AAG7B,QACG,QAAQ,MAAM,EACd,YAAY,oDAAoD,EAChE,SAAS,SAAS,gCAAgC,EAClD,SAAS,SAAS,gCAAgC,EAClD,OAAO,UAAU,uBAAuB,KAAK,EAC7C,OAAO,sBAAsB,6CAA6C,KAAK,EAC/E,OAAOC,KAAAA,WAAW;AAErB,QAAQ,MAAA;"}
package/dist/cli.js ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from "commander";
3
+ import { v as validateCommand, g as generateTypesCommand, t as testExamplesCommand, d as diffCommand } from "./diff-B8QJSPfQ.js";
4
+ const program = new Command();
5
+ program.name("mcp-ui").description("CLI tools for MCP UI component registries").version("1.0.0");
6
+ program.command("validate").description("Validate a component registry against the schema").argument("<file>", "Path to registry JSON file").option("--strict", "Enable strict validation mode", false).option("--verbose", "Show detailed validation output", false).action(validateCommand);
7
+ program.command("generate-types").description("Generate TypeScript types from a registry").argument("<input>", "Path to registry JSON file").argument("[output]", "Output file path (default: stdout)").option("--namespace <name>", "Wrap types in a namespace").option("--export-all", "Export all generated types", false).action(generateTypesCommand);
8
+ program.command("test-examples").description("Test all examples in a component registry").argument("<file>", "Path to registry JSON file").option("--component <id>", "Test only specific component").option("--verbose", "Show detailed test output", false).action(testExamplesCommand);
9
+ program.command("diff").description("Compare two registry versions for breaking changes").argument("<old>", "Path to old registry JSON file").argument("<new>", "Path to new registry JSON file").option("--json", "Output diff as JSON", false).option("--fail-on-breaking", "Exit with error if breaking changes found", false).action(diffCommand);
10
+ program.parse();
11
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * @seed-ship/mcp-ui-cli\n *\n * Command-line interface for MCP UI component registry operations\n */\n\nimport { Command } from 'commander'\nimport { validateCommand } from './commands/validate.js'\nimport { generateTypesCommand } from './commands/generate-types.js'\nimport { testExamplesCommand } from './commands/test-examples.js'\nimport { diffCommand } from './commands/diff.js'\n\nconst program = new Command()\n\nprogram.name('mcp-ui').description('CLI tools for MCP UI component registries').version('1.0.0')\n\n// Validate command\nprogram\n .command('validate')\n .description('Validate a component registry against the schema')\n .argument('<file>', 'Path to registry JSON file')\n .option('--strict', 'Enable strict validation mode', false)\n .option('--verbose', 'Show detailed validation output', false)\n .action(validateCommand)\n\n// Generate types command\nprogram\n .command('generate-types')\n .description('Generate TypeScript types from a registry')\n .argument('<input>', 'Path to registry JSON file')\n .argument('[output]', 'Output file path (default: stdout)')\n .option('--namespace <name>', 'Wrap types in a namespace')\n .option('--export-all', 'Export all generated types', false)\n .action(generateTypesCommand)\n\n// Test examples command\nprogram\n .command('test-examples')\n .description('Test all examples in a component registry')\n .argument('<file>', 'Path to registry JSON file')\n .option('--component <id>', 'Test only specific component')\n .option('--verbose', 'Show detailed test output', false)\n .action(testExamplesCommand)\n\n// Diff command\nprogram\n .command('diff')\n .description('Compare two registry versions for breaking changes')\n .argument('<old>', 'Path to old registry JSON file')\n .argument('<new>', 'Path to new registry JSON file')\n .option('--json', 'Output diff as JSON', false)\n .option('--fail-on-breaking', 'Exit with error if breaking changes found', false)\n .action(diffCommand)\n\nprogram.parse()\n"],"names":[],"mappings":";;;AAcA,MAAM,UAAU,IAAI,QAAA;AAEpB,QAAQ,KAAK,QAAQ,EAAE,YAAY,2CAA2C,EAAE,QAAQ,OAAO;AAG/F,QACG,QAAQ,UAAU,EAClB,YAAY,kDAAkD,EAC9D,SAAS,UAAU,4BAA4B,EAC/C,OAAO,YAAY,iCAAiC,KAAK,EACzD,OAAO,aAAa,mCAAmC,KAAK,EAC5D,OAAO,eAAe;AAGzB,QACG,QAAQ,gBAAgB,EACxB,YAAY,2CAA2C,EACvD,SAAS,WAAW,4BAA4B,EAChD,SAAS,YAAY,oCAAoC,EACzD,OAAO,sBAAsB,2BAA2B,EACxD,OAAO,gBAAgB,8BAA8B,KAAK,EAC1D,OAAO,oBAAoB;AAG9B,QACG,QAAQ,eAAe,EACvB,YAAY,2CAA2C,EACvD,SAAS,UAAU,4BAA4B,EAC/C,OAAO,oBAAoB,8BAA8B,EACzD,OAAO,aAAa,6BAA6B,KAAK,EACtD,OAAO,mBAAmB;AAG7B,QACG,QAAQ,MAAM,EACd,YAAY,oDAAoD,EAChE,SAAS,SAAS,gCAAgC,EAClD,SAAS,SAAS,gCAAgC,EAClD,OAAO,UAAU,uBAAuB,KAAK,EAC7C,OAAO,sBAAsB,6CAA6C,KAAK,EAC/E,OAAO,WAAW;AAErB,QAAQ,MAAA;"}
@@ -0,0 +1,420 @@
1
+ "use strict";
2
+ const fs = require("fs");
3
+ const path = require("path");
4
+ const Ajv = require("ajv");
5
+ const chalk = require("chalk");
6
+ const ora = require("ora");
7
+ const mcpUiSpec = require("@seed-ship/mcp-ui-spec");
8
+ const url = require("url");
9
+ const jsonSchemaToTypescript = require("json-schema-to-typescript");
10
+ var _documentCurrentScript = typeof document !== "undefined" ? document.currentScript : null;
11
+ const __filename$1 = url.fileURLToPath(typeof document === "undefined" ? require("url").pathToFileURL(__filename).href : _documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === "SCRIPT" && _documentCurrentScript.src || new URL("diff-B1c8BBVB.cjs", document.baseURI).href);
12
+ const __dirname$1 = path.dirname(__filename$1);
13
+ async function validateCommand(file, options) {
14
+ var _a;
15
+ const spinner = ora("Loading registry...").start();
16
+ try {
17
+ const registryPath = path.resolve(process.cwd(), file);
18
+ const registryContent = fs.readFileSync(registryPath, "utf-8");
19
+ const registry = JSON.parse(registryContent);
20
+ spinner.text = "Validating with Zod schema...";
21
+ const zodResult = mcpUiSpec.ComponentRegistrySchema.safeParse(registry);
22
+ if (!zodResult.success) {
23
+ spinner.fail("Zod validation failed");
24
+ console.error(chalk.red("\nValidation Errors:"));
25
+ zodResult.error.errors.forEach((err) => {
26
+ console.error(chalk.red(` • ${err.path.join(".")}: ${err.message}`));
27
+ });
28
+ process.exit(1);
29
+ }
30
+ spinner.text = "Validating with JSON Schema...";
31
+ const schemaPath = path.join(
32
+ __dirname$1,
33
+ "../../node_modules/@seed-ship/mcp-ui-spec/schemas/component-registry-v1.json"
34
+ );
35
+ let jsonSchemaContent;
36
+ try {
37
+ jsonSchemaContent = fs.readFileSync(schemaPath, "utf-8");
38
+ } catch {
39
+ const localSchemaPath = path.join(
40
+ __dirname$1,
41
+ "../../../mcp-ui-spec/schemas/component-registry-v1.json"
42
+ );
43
+ jsonSchemaContent = fs.readFileSync(localSchemaPath, "utf-8");
44
+ }
45
+ const jsonSchema = JSON.parse(jsonSchemaContent);
46
+ const ajv = new Ajv({
47
+ allErrors: options.strict,
48
+ verbose: options.verbose,
49
+ strict: options.strict
50
+ });
51
+ const validate = ajv.compile(jsonSchema);
52
+ const jsonValid = validate(registry);
53
+ if (!jsonValid && validate.errors) {
54
+ spinner.fail("JSON Schema validation failed");
55
+ console.error(chalk.red("\nValidation Errors:"));
56
+ validate.errors.forEach((err) => {
57
+ const path2 = err.instancePath || "root";
58
+ console.error(chalk.red(` • ${path2}: ${err.message}`));
59
+ if (options.verbose && err.params) {
60
+ console.error(chalk.gray(` Params: ${JSON.stringify(err.params)}`));
61
+ }
62
+ });
63
+ process.exit(1);
64
+ }
65
+ spinner.succeed(chalk.green("Registry is valid!"));
66
+ if (options.verbose) {
67
+ console.log(chalk.gray("\nRegistry Summary:"));
68
+ console.log(chalk.gray(` Version: ${registry.version}`));
69
+ console.log(chalk.gray(` Components: ${registry.components.length}`));
70
+ if ((_a = registry.metadata) == null ? void 0 : _a.name) {
71
+ console.log(chalk.gray(` Name: ${registry.metadata.name}`));
72
+ }
73
+ console.log(chalk.gray("\nComponents:"));
74
+ const validRegistry = registry;
75
+ validRegistry.components.forEach((comp) => {
76
+ console.log(chalk.gray(` • ${comp.id} (${comp.type}): ${comp.examples.length} example(s)`));
77
+ });
78
+ }
79
+ process.exit(0);
80
+ } catch (error) {
81
+ spinner.fail("Validation failed");
82
+ if (error instanceof Error) {
83
+ if (error.message.includes("ENOENT")) {
84
+ console.error(chalk.red(`
85
+ File not found: ${file}`));
86
+ } else if (error instanceof SyntaxError) {
87
+ console.error(chalk.red("\nInvalid JSON syntax"));
88
+ console.error(chalk.gray(error.message));
89
+ } else {
90
+ console.error(chalk.red("\nUnexpected error:"));
91
+ console.error(chalk.gray(error.message));
92
+ }
93
+ }
94
+ process.exit(1);
95
+ }
96
+ }
97
+ async function generateTypesCommand(input, output, options) {
98
+ const spinner = ora("Loading registry...").start();
99
+ try {
100
+ const registryPath = path.resolve(process.cwd(), input);
101
+ const registryContent = fs.readFileSync(registryPath, "utf-8");
102
+ const registry = JSON.parse(registryContent);
103
+ spinner.text = "Generating TypeScript types...";
104
+ const typeDefinitions = [];
105
+ typeDefinitions.push("/**");
106
+ typeDefinitions.push(" * Auto-generated TypeScript types from component registry");
107
+ typeDefinitions.push(" * Generated by @seed-ship/mcp-ui-cli");
108
+ typeDefinitions.push(" */");
109
+ typeDefinitions.push("");
110
+ if (options.namespace) {
111
+ typeDefinitions.push(`export namespace ${options.namespace} {`);
112
+ }
113
+ for (const component of registry.components) {
114
+ spinner.text = `Generating types for ${component.id}...`;
115
+ const typeName = componentIdToTypeName(component.id);
116
+ try {
117
+ const ts = await jsonSchemaToTypescript.compile(component.schema, typeName, {
118
+ bannerComment: `/* ${component.name} - ${component.description || "No description"} */`,
119
+ style: {
120
+ semi: false,
121
+ singleQuote: true
122
+ }
123
+ });
124
+ if (options.namespace) {
125
+ const indented = ts.split("\n").map((line) => line ? ` ${line}` : line).join("\n");
126
+ typeDefinitions.push(indented);
127
+ } else {
128
+ typeDefinitions.push(ts);
129
+ }
130
+ typeDefinitions.push("");
131
+ } catch (error) {
132
+ spinner.warn(`Skipping ${component.id}: type generation failed`);
133
+ if (error instanceof Error) {
134
+ console.error(chalk.yellow(` ${error.message}`));
135
+ }
136
+ }
137
+ }
138
+ if (options.namespace) {
139
+ typeDefinitions.push("}");
140
+ }
141
+ const generatedCode = typeDefinitions.join("\n");
142
+ spinner.succeed("Type generation complete");
143
+ if (output) {
144
+ const outputPath = path.resolve(process.cwd(), output);
145
+ fs.writeFileSync(outputPath, generatedCode, "utf-8");
146
+ console.log(chalk.green(`✓ Types written to ${output}`));
147
+ } else {
148
+ console.log("\n" + generatedCode);
149
+ }
150
+ process.exit(0);
151
+ } catch (error) {
152
+ spinner.fail("Type generation failed");
153
+ if (error instanceof Error) {
154
+ if (error.message.includes("ENOENT")) {
155
+ console.error(chalk.red(`
156
+ File not found: ${input}`));
157
+ } else {
158
+ console.error(chalk.red("\nUnexpected error:"));
159
+ console.error(chalk.gray(error.message));
160
+ }
161
+ }
162
+ process.exit(1);
163
+ }
164
+ }
165
+ function componentIdToTypeName(id) {
166
+ return id.split("-").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
167
+ }
168
+ async function testExamplesCommand(file, options) {
169
+ const spinner = ora("Loading registry...").start();
170
+ try {
171
+ const registryPath = path.resolve(process.cwd(), file);
172
+ const registryContent = fs.readFileSync(registryPath, "utf-8");
173
+ const registry = JSON.parse(registryContent);
174
+ const componentsToTest = options.component ? registry.components.filter((c) => c.id === options.component) : registry.components;
175
+ if (componentsToTest.length === 0) {
176
+ spinner.fail(`Component not found: ${options.component}`);
177
+ process.exit(1);
178
+ }
179
+ spinner.text = "Running example tests...";
180
+ const results = [];
181
+ let totalExamples = 0;
182
+ let passedExamples = 0;
183
+ for (const component of componentsToTest) {
184
+ spinner.text = `Testing examples for ${component.id}...`;
185
+ const ajv = new Ajv({ allErrors: true, verbose: options.verbose });
186
+ const validate = ajv.compile(component.schema);
187
+ for (const example of component.examples) {
188
+ totalExamples++;
189
+ const valid = validate(example.params);
190
+ const result = {
191
+ componentId: component.id,
192
+ exampleName: example.name,
193
+ passed: valid
194
+ };
195
+ if (!valid && validate.errors) {
196
+ result.errors = validate.errors.map((err) => {
197
+ const path2 = err.instancePath || "root";
198
+ return `${path2}: ${err.message}`;
199
+ });
200
+ }
201
+ if (valid) {
202
+ passedExamples++;
203
+ }
204
+ results.push(result);
205
+ }
206
+ }
207
+ spinner.stop();
208
+ console.log(chalk.bold("\nTest Results:\n"));
209
+ let hasFailures = false;
210
+ for (const result of results) {
211
+ const status = result.passed ? chalk.green("✓") : chalk.red("✗");
212
+ const componentLabel = chalk.cyan(result.componentId);
213
+ const exampleLabel = chalk.gray(result.exampleName);
214
+ console.log(`${status} ${componentLabel} › ${exampleLabel}`);
215
+ if (!result.passed && result.errors) {
216
+ hasFailures = true;
217
+ result.errors.forEach((error) => {
218
+ console.log(chalk.red(` ${error}`));
219
+ });
220
+ }
221
+ }
222
+ console.log("");
223
+ console.log(chalk.bold("Summary:"));
224
+ console.log(` ${chalk.green(`${passedExamples} passed`)} / ${totalExamples} total`);
225
+ if (hasFailures) {
226
+ console.log(chalk.red(` ${totalExamples - passedExamples} failed`));
227
+ process.exit(1);
228
+ }
229
+ console.log(chalk.green("\n✓ All examples are valid!"));
230
+ process.exit(0);
231
+ } catch (error) {
232
+ spinner.fail("Example testing failed");
233
+ if (error instanceof Error) {
234
+ if (error.message.includes("ENOENT")) {
235
+ console.error(chalk.red(`
236
+ File not found: ${file}`));
237
+ } else if (error instanceof SyntaxError) {
238
+ console.error(chalk.red("\nInvalid JSON syntax"));
239
+ console.error(chalk.gray(error.message));
240
+ } else {
241
+ console.error(chalk.red("\nUnexpected error:"));
242
+ console.error(chalk.gray(error.message));
243
+ }
244
+ }
245
+ process.exit(1);
246
+ }
247
+ }
248
+ async function diffCommand(oldFile, newFile, options) {
249
+ const spinner = ora("Loading registries...").start();
250
+ try {
251
+ const oldPath = path.resolve(process.cwd(), oldFile);
252
+ const newPath = path.resolve(process.cwd(), newFile);
253
+ const oldRegistry = JSON.parse(fs.readFileSync(oldPath, "utf-8"));
254
+ const newRegistry = JSON.parse(fs.readFileSync(newPath, "utf-8"));
255
+ spinner.text = "Comparing registries...";
256
+ const changes = [];
257
+ const oldComponents = new Map(oldRegistry.components.map((c) => [c.id, c]));
258
+ const newComponents = new Map(newRegistry.components.map((c) => [c.id, c]));
259
+ for (const [id] of oldComponents) {
260
+ if (!newComponents.has(id)) {
261
+ changes.push({
262
+ type: "removed",
263
+ breaking: true,
264
+ componentId: id,
265
+ message: `Component '${id}' was removed`
266
+ });
267
+ }
268
+ }
269
+ for (const [id] of newComponents) {
270
+ if (!oldComponents.has(id)) {
271
+ changes.push({
272
+ type: "added",
273
+ breaking: false,
274
+ componentId: id,
275
+ message: `Component '${id}' was added`
276
+ });
277
+ }
278
+ }
279
+ for (const [id, newComponent] of newComponents) {
280
+ const oldComponent = oldComponents.get(id);
281
+ if (!oldComponent) continue;
282
+ if (!oldComponent.deprecated && newComponent.deprecated) {
283
+ changes.push({
284
+ type: "deprecated",
285
+ breaking: false,
286
+ componentId: id,
287
+ message: `Component '${id}' was deprecated${newComponent.deprecationMessage ? `: ${newComponent.deprecationMessage}` : ""}`
288
+ });
289
+ }
290
+ if (oldComponent.type !== newComponent.type) {
291
+ changes.push({
292
+ type: "modified",
293
+ breaking: true,
294
+ componentId: id,
295
+ field: "type",
296
+ oldValue: oldComponent.type,
297
+ newValue: newComponent.type,
298
+ message: `Component '${id}' type changed from '${oldComponent.type}' to '${newComponent.type}'`
299
+ });
300
+ }
301
+ const oldRequired = new Set(oldComponent.schema.required || []);
302
+ const newRequired = new Set(newComponent.schema.required || []);
303
+ for (const field of newRequired) {
304
+ if (!oldRequired.has(field)) {
305
+ changes.push({
306
+ type: "modified",
307
+ breaking: true,
308
+ componentId: id,
309
+ field: `schema.required`,
310
+ message: `Component '${id}' now requires field '${field}'`
311
+ });
312
+ }
313
+ }
314
+ for (const field of oldRequired) {
315
+ if (!newRequired.has(field)) {
316
+ changes.push({
317
+ type: "modified",
318
+ breaking: false,
319
+ componentId: id,
320
+ field: `schema.required`,
321
+ message: `Component '${id}' no longer requires field '${field}'`
322
+ });
323
+ }
324
+ }
325
+ if (oldComponent.version !== newComponent.version) {
326
+ const oldVersion = oldComponent.version || "0.0.0";
327
+ const newVersion = newComponent.version || "0.0.0";
328
+ const breaking = isMajorVersionChange(oldVersion, newVersion);
329
+ changes.push({
330
+ type: "modified",
331
+ breaking,
332
+ componentId: id,
333
+ field: "version",
334
+ oldValue: oldVersion,
335
+ newValue: newVersion,
336
+ message: `Component '${id}' version changed from ${oldVersion} to ${newVersion}`
337
+ });
338
+ }
339
+ }
340
+ spinner.stop();
341
+ if (options.json) {
342
+ console.log(JSON.stringify({ changes }, null, 2));
343
+ } else {
344
+ displayHumanReadableDiff(changes);
345
+ }
346
+ const hasBreakingChanges = changes.some((c) => c.breaking);
347
+ if (options.failOnBreaking && hasBreakingChanges) {
348
+ console.error(chalk.red("\n✗ Breaking changes detected!"));
349
+ process.exit(1);
350
+ }
351
+ process.exit(0);
352
+ } catch (error) {
353
+ spinner.fail("Diff failed");
354
+ if (error instanceof Error) {
355
+ if (error.message.includes("ENOENT")) {
356
+ console.error(chalk.red(`
357
+ File not found`));
358
+ } else {
359
+ console.error(chalk.red("\nUnexpected error:"));
360
+ console.error(chalk.gray(error.message));
361
+ }
362
+ }
363
+ process.exit(1);
364
+ }
365
+ }
366
+ function displayHumanReadableDiff(changes) {
367
+ console.log(chalk.bold("\nRegistry Changes:\n"));
368
+ if (changes.length === 0) {
369
+ console.log(chalk.gray("No changes detected"));
370
+ return;
371
+ }
372
+ const breakingChanges = changes.filter((c) => c.breaking);
373
+ const nonBreakingChanges = changes.filter((c) => !c.breaking);
374
+ if (breakingChanges.length > 0) {
375
+ console.log(chalk.red.bold("Breaking Changes:"));
376
+ for (const change of breakingChanges) {
377
+ const icon = getChangeIcon(change.type);
378
+ console.log(chalk.red(` ${icon} ${change.message}`));
379
+ }
380
+ console.log("");
381
+ }
382
+ if (nonBreakingChanges.length > 0) {
383
+ console.log(chalk.yellow.bold("Non-Breaking Changes:"));
384
+ for (const change of nonBreakingChanges) {
385
+ const icon = getChangeIcon(change.type);
386
+ console.log(chalk.yellow(` ${icon} ${change.message}`));
387
+ }
388
+ console.log("");
389
+ }
390
+ console.log(chalk.bold("Summary:"));
391
+ console.log(` Total changes: ${changes.length}`);
392
+ console.log(
393
+ ` Breaking: ${breakingChanges.length > 0 ? chalk.red(breakingChanges.length) : chalk.green("0")}`
394
+ );
395
+ console.log(` Non-breaking: ${nonBreakingChanges.length}`);
396
+ }
397
+ function getChangeIcon(type) {
398
+ switch (type) {
399
+ case "added":
400
+ return "+";
401
+ case "removed":
402
+ return "-";
403
+ case "modified":
404
+ return "~";
405
+ case "deprecated":
406
+ return "⚠";
407
+ default:
408
+ return "•";
409
+ }
410
+ }
411
+ function isMajorVersionChange(oldVersion, newVersion) {
412
+ const oldMajor = parseInt(oldVersion.split(".")[0], 10);
413
+ const newMajor = parseInt(newVersion.split(".")[0], 10);
414
+ return newMajor > oldMajor;
415
+ }
416
+ exports.diffCommand = diffCommand;
417
+ exports.generateTypesCommand = generateTypesCommand;
418
+ exports.testExamplesCommand = testExamplesCommand;
419
+ exports.validateCommand = validateCommand;
420
+ //# sourceMappingURL=diff-B1c8BBVB.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-B1c8BBVB.cjs","sources":["../src/commands/validate.ts","../src/commands/generate-types.ts","../src/commands/test-examples.ts","../src/commands/diff.ts"],"sourcesContent":["/**\n * Validate command - validates component registry against JSON Schema\n */\n\nimport { readFileSync } from 'fs'\nimport { resolve } from 'path'\nimport Ajv from 'ajv'\nimport chalk from 'chalk'\nimport ora from 'ora'\nimport { ComponentRegistrySchema, type ComponentRegistry } from '@seed-ship/mcp-ui-spec'\n\n// Load JSON Schema from @seed-ship/mcp-ui-spec package\nimport { fileURLToPath } from 'url'\nimport { dirname, join } from 'path'\n\nconst __filename = fileURLToPath(import.meta.url)\nconst __dirname = dirname(__filename)\n\ninterface ValidateOptions {\n strict?: boolean\n verbose?: boolean\n}\n\nexport async function validateCommand(file: string, options: ValidateOptions) {\n const spinner = ora('Loading registry...').start()\n\n try {\n // Read registry file\n const registryPath = resolve(process.cwd(), file)\n const registryContent = readFileSync(registryPath, 'utf-8')\n const registry = JSON.parse(registryContent)\n\n spinner.text = 'Validating with Zod schema...'\n\n // First validate with Zod (runtime validation)\n const zodResult = ComponentRegistrySchema.safeParse(registry)\n\n if (!zodResult.success) {\n spinner.fail('Zod validation failed')\n console.error(chalk.red('\\nValidation Errors:'))\n zodResult.error.errors.forEach((err) => {\n console.error(chalk.red(` • ${err.path.join('.')}: ${err.message}`))\n })\n process.exit(1)\n }\n\n spinner.text = 'Validating with JSON Schema...'\n\n // Load JSON Schema for secondary validation\n const schemaPath = join(\n __dirname,\n '../../node_modules/@seed-ship/mcp-ui-spec/schemas/component-registry-v1.json'\n )\n let jsonSchemaContent: string\n\n try {\n jsonSchemaContent = readFileSync(schemaPath, 'utf-8')\n } catch {\n // Fallback to local schema if node_modules path fails\n const localSchemaPath = join(\n __dirname,\n '../../../mcp-ui-spec/schemas/component-registry-v1.json'\n )\n jsonSchemaContent = readFileSync(localSchemaPath, 'utf-8')\n }\n\n const jsonSchema = JSON.parse(jsonSchemaContent)\n\n // Validate with JSON Schema using Ajv\n const ajv = new Ajv({\n allErrors: options.strict,\n verbose: options.verbose,\n strict: options.strict,\n })\n\n const validate = ajv.compile(jsonSchema)\n const jsonValid = validate(registry)\n\n if (!jsonValid && validate.errors) {\n spinner.fail('JSON Schema validation failed')\n console.error(chalk.red('\\nValidation Errors:'))\n validate.errors.forEach((err) => {\n const path = err.instancePath || 'root'\n console.error(chalk.red(` • ${path}: ${err.message}`))\n if (options.verbose && err.params) {\n console.error(chalk.gray(` Params: ${JSON.stringify(err.params)}`))\n }\n })\n process.exit(1)\n }\n\n spinner.succeed(chalk.green('Registry is valid!'))\n\n // Summary\n if (options.verbose) {\n console.log(chalk.gray('\\nRegistry Summary:'))\n console.log(chalk.gray(` Version: ${registry.version}`))\n console.log(chalk.gray(` Components: ${registry.components.length}`))\n\n if (registry.metadata?.name) {\n console.log(chalk.gray(` Name: ${registry.metadata.name}`))\n }\n\n console.log(chalk.gray('\\nComponents:'))\n const validRegistry = registry as ComponentRegistry\n validRegistry.components.forEach((comp) => {\n console.log(chalk.gray(` • ${comp.id} (${comp.type}): ${comp.examples.length} example(s)`))\n })\n }\n\n process.exit(0)\n } catch (error) {\n spinner.fail('Validation failed')\n\n if (error instanceof Error) {\n if (error.message.includes('ENOENT')) {\n console.error(chalk.red(`\\nFile not found: ${file}`))\n } else if (error instanceof SyntaxError) {\n console.error(chalk.red('\\nInvalid JSON syntax'))\n console.error(chalk.gray(error.message))\n } else {\n console.error(chalk.red('\\nUnexpected error:'))\n console.error(chalk.gray(error.message))\n }\n }\n\n process.exit(1)\n }\n}\n","/**\n * Generate Types command - generates TypeScript types from registry\n */\n\nimport { readFileSync, writeFileSync } from 'fs'\nimport { resolve } from 'path'\nimport { compile } from 'json-schema-to-typescript'\nimport chalk from 'chalk'\nimport ora from 'ora'\nimport type { Component, ComponentRegistry } from '@seed-ship/mcp-ui-spec'\n\ninterface GenerateTypesOptions {\n namespace?: string\n exportAll?: boolean\n}\n\nexport async function generateTypesCommand(\n input: string,\n output: string | undefined,\n options: GenerateTypesOptions\n) {\n const spinner = ora('Loading registry...').start()\n\n try {\n // Read registry file\n const registryPath = resolve(process.cwd(), input)\n const registryContent = readFileSync(registryPath, 'utf-8')\n const registry: ComponentRegistry = JSON.parse(registryContent)\n\n spinner.text = 'Generating TypeScript types...'\n\n // Generate types for each component\n const typeDefinitions: string[] = []\n\n // Add header comment\n typeDefinitions.push('/**')\n typeDefinitions.push(' * Auto-generated TypeScript types from component registry')\n typeDefinitions.push(' * Generated by @seed-ship/mcp-ui-cli')\n typeDefinitions.push(' */')\n typeDefinitions.push('')\n\n if (options.namespace) {\n typeDefinitions.push(`export namespace ${options.namespace} {`)\n }\n\n // Generate types for each component\n for (const component of registry.components as Component[]) {\n spinner.text = `Generating types for ${component.id}...`\n\n // Generate interface name from component ID\n const typeName = componentIdToTypeName(component.id)\n\n try {\n const ts = await compile(component.schema as any, typeName, {\n bannerComment: `/* ${component.name} - ${component.description || 'No description'} */`,\n style: {\n semi: false,\n singleQuote: true,\n },\n })\n\n // Add the generated type\n if (options.namespace) {\n // Indent for namespace\n const indented = ts\n .split('\\n')\n .map((line) => (line ? ` ${line}` : line))\n .join('\\n')\n typeDefinitions.push(indented)\n } else {\n typeDefinitions.push(ts)\n }\n\n typeDefinitions.push('')\n } catch (error) {\n spinner.warn(`Skipping ${component.id}: type generation failed`)\n if (error instanceof Error) {\n console.error(chalk.yellow(` ${error.message}`))\n }\n }\n }\n\n if (options.namespace) {\n typeDefinitions.push('}')\n }\n\n const generatedCode = typeDefinitions.join('\\n')\n\n spinner.succeed('Type generation complete')\n\n // Write to file or stdout\n if (output) {\n const outputPath = resolve(process.cwd(), output)\n writeFileSync(outputPath, generatedCode, 'utf-8')\n console.log(chalk.green(`✓ Types written to ${output}`))\n } else {\n console.log('\\n' + generatedCode)\n }\n\n process.exit(0)\n } catch (error) {\n spinner.fail('Type generation failed')\n\n if (error instanceof Error) {\n if (error.message.includes('ENOENT')) {\n console.error(chalk.red(`\\nFile not found: ${input}`))\n } else {\n console.error(chalk.red('\\nUnexpected error:'))\n console.error(chalk.gray(error.message))\n }\n }\n\n process.exit(1)\n }\n}\n\n/**\n * Convert component ID to TypeScript type name\n * Examples:\n * quickchart-bar -> QuickchartBar\n * metric-card -> MetricCard\n * data-table -> DataTable\n */\nfunction componentIdToTypeName(id: string): string {\n return id\n .split('-')\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join('')\n}\n","/**\n * Test Examples command - validates all component examples\n */\n\nimport { readFileSync } from 'fs'\nimport { resolve } from 'path'\nimport Ajv from 'ajv'\nimport chalk from 'chalk'\nimport ora from 'ora'\nimport type { ComponentRegistry } from '@seed-ship/mcp-ui-spec'\n\ninterface TestExamplesOptions {\n component?: string\n verbose?: boolean\n}\n\ninterface TestResult {\n componentId: string\n exampleName: string\n passed: boolean\n errors?: string[]\n}\n\nexport async function testExamplesCommand(file: string, options: TestExamplesOptions) {\n const spinner = ora('Loading registry...').start()\n\n try {\n // Read registry file\n const registryPath = resolve(process.cwd(), file)\n const registryContent = readFileSync(registryPath, 'utf-8')\n const registry: ComponentRegistry = JSON.parse(registryContent)\n\n // Filter components if specific component requested\n const componentsToTest = options.component\n ? registry.components.filter((c) => c.id === options.component)\n : registry.components\n\n if (componentsToTest.length === 0) {\n spinner.fail(`Component not found: ${options.component}`)\n process.exit(1)\n }\n\n spinner.text = 'Running example tests...'\n\n const results: TestResult[] = []\n let totalExamples = 0\n let passedExamples = 0\n\n // Test each component's examples\n for (const component of componentsToTest) {\n spinner.text = `Testing examples for ${component.id}...`\n\n // Create Ajv validator for this component's schema\n const ajv = new Ajv({ allErrors: true, verbose: options.verbose })\n const validate = ajv.compile(component.schema as any)\n\n // Test each example\n for (const example of component.examples) {\n totalExamples++\n\n const valid = validate(example.params)\n const result: TestResult = {\n componentId: component.id,\n exampleName: example.name,\n passed: valid,\n }\n\n if (!valid && validate.errors) {\n result.errors = validate.errors.map((err) => {\n const path = err.instancePath || 'root'\n return `${path}: ${err.message}`\n })\n }\n\n if (valid) {\n passedExamples++\n }\n\n results.push(result)\n }\n }\n\n spinner.stop()\n\n // Display results\n console.log(chalk.bold('\\nTest Results:\\n'))\n\n let hasFailures = false\n\n for (const result of results) {\n const status = result.passed ? chalk.green('✓') : chalk.red('✗')\n const componentLabel = chalk.cyan(result.componentId)\n const exampleLabel = chalk.gray(result.exampleName)\n\n console.log(`${status} ${componentLabel} › ${exampleLabel}`)\n\n if (!result.passed && result.errors) {\n hasFailures = true\n result.errors.forEach((error) => {\n console.log(chalk.red(` ${error}`))\n })\n }\n }\n\n // Summary\n console.log('')\n console.log(chalk.bold('Summary:'))\n console.log(` ${chalk.green(`${passedExamples} passed`)} / ${totalExamples} total`)\n\n if (hasFailures) {\n console.log(chalk.red(` ${totalExamples - passedExamples} failed`))\n process.exit(1)\n }\n\n console.log(chalk.green('\\n✓ All examples are valid!'))\n process.exit(0)\n } catch (error) {\n spinner.fail('Example testing failed')\n\n if (error instanceof Error) {\n if (error.message.includes('ENOENT')) {\n console.error(chalk.red(`\\nFile not found: ${file}`))\n } else if (error instanceof SyntaxError) {\n console.error(chalk.red('\\nInvalid JSON syntax'))\n console.error(chalk.gray(error.message))\n } else {\n console.error(chalk.red('\\nUnexpected error:'))\n console.error(chalk.gray(error.message))\n }\n }\n\n process.exit(1)\n }\n}\n","/**\n * Diff command - compares two registry versions for breaking changes\n */\n\nimport { readFileSync } from 'fs'\nimport { resolve } from 'path'\nimport chalk from 'chalk'\nimport ora from 'ora'\nimport type { ComponentRegistry } from '@seed-ship/mcp-ui-spec'\n\ninterface DiffOptions {\n json?: boolean\n failOnBreaking?: boolean\n}\n\ninterface ChangeType {\n type: 'added' | 'removed' | 'modified' | 'deprecated'\n breaking: boolean\n componentId: string\n field?: string\n oldValue?: unknown\n newValue?: unknown\n message: string\n}\n\nexport async function diffCommand(oldFile: string, newFile: string, options: DiffOptions) {\n const spinner = ora('Loading registries...').start()\n\n try {\n // Read both registry files\n const oldPath = resolve(process.cwd(), oldFile)\n const newPath = resolve(process.cwd(), newFile)\n\n const oldRegistry: ComponentRegistry = JSON.parse(readFileSync(oldPath, 'utf-8'))\n const newRegistry: ComponentRegistry = JSON.parse(readFileSync(newPath, 'utf-8'))\n\n spinner.text = 'Comparing registries...'\n\n const changes: ChangeType[] = []\n\n // Create maps for easier lookup\n const oldComponents = new Map(oldRegistry.components.map((c) => [c.id, c]))\n const newComponents = new Map(newRegistry.components.map((c) => [c.id, c]))\n\n // Check for removed components (breaking)\n for (const [id] of oldComponents) {\n if (!newComponents.has(id)) {\n changes.push({\n type: 'removed',\n breaking: true,\n componentId: id,\n message: `Component '${id}' was removed`,\n })\n }\n }\n\n // Check for added components (non-breaking)\n for (const [id] of newComponents) {\n if (!oldComponents.has(id)) {\n changes.push({\n type: 'added',\n breaking: false,\n componentId: id,\n message: `Component '${id}' was added`,\n })\n }\n }\n\n // Check for modified components\n for (const [id, newComponent] of newComponents) {\n const oldComponent = oldComponents.get(id)\n if (!oldComponent) continue\n\n // Check deprecation\n if (!oldComponent.deprecated && newComponent.deprecated) {\n changes.push({\n type: 'deprecated',\n breaking: false,\n componentId: id,\n message: `Component '${id}' was deprecated${\n newComponent.deprecationMessage ? `: ${newComponent.deprecationMessage}` : ''\n }`,\n })\n }\n\n // Check type change (breaking)\n if (oldComponent.type !== newComponent.type) {\n changes.push({\n type: 'modified',\n breaking: true,\n componentId: id,\n field: 'type',\n oldValue: oldComponent.type,\n newValue: newComponent.type,\n message: `Component '${id}' type changed from '${oldComponent.type}' to '${newComponent.type}'`,\n })\n }\n\n // Check required fields change (breaking)\n const oldRequired = new Set(oldComponent.schema.required || [])\n const newRequired = new Set(newComponent.schema.required || [])\n\n for (const field of newRequired) {\n if (!oldRequired.has(field)) {\n changes.push({\n type: 'modified',\n breaking: true,\n componentId: id,\n field: `schema.required`,\n message: `Component '${id}' now requires field '${field}'`,\n })\n }\n }\n\n for (const field of oldRequired) {\n if (!newRequired.has(field)) {\n changes.push({\n type: 'modified',\n breaking: false,\n componentId: id,\n field: `schema.required`,\n message: `Component '${id}' no longer requires field '${field}'`,\n })\n }\n }\n\n // Check version change\n if (oldComponent.version !== newComponent.version) {\n const oldVersion = oldComponent.version || '0.0.0'\n const newVersion = newComponent.version || '0.0.0'\n\n const breaking = isMajorVersionChange(oldVersion, newVersion)\n\n changes.push({\n type: 'modified',\n breaking,\n componentId: id,\n field: 'version',\n oldValue: oldVersion,\n newValue: newVersion,\n message: `Component '${id}' version changed from ${oldVersion} to ${newVersion}`,\n })\n }\n }\n\n spinner.stop()\n\n // Output results\n if (options.json) {\n console.log(JSON.stringify({ changes }, null, 2))\n } else {\n displayHumanReadableDiff(changes)\n }\n\n // Check if we should fail on breaking changes\n const hasBreakingChanges = changes.some((c) => c.breaking)\n if (options.failOnBreaking && hasBreakingChanges) {\n console.error(chalk.red('\\n✗ Breaking changes detected!'))\n process.exit(1)\n }\n\n process.exit(0)\n } catch (error) {\n spinner.fail('Diff failed')\n\n if (error instanceof Error) {\n if (error.message.includes('ENOENT')) {\n console.error(chalk.red(`\\nFile not found`))\n } else {\n console.error(chalk.red('\\nUnexpected error:'))\n console.error(chalk.gray(error.message))\n }\n }\n\n process.exit(1)\n }\n}\n\nfunction displayHumanReadableDiff(changes: ChangeType[]) {\n console.log(chalk.bold('\\nRegistry Changes:\\n'))\n\n if (changes.length === 0) {\n console.log(chalk.gray('No changes detected'))\n return\n }\n\n const breakingChanges = changes.filter((c) => c.breaking)\n const nonBreakingChanges = changes.filter((c) => !c.breaking)\n\n if (breakingChanges.length > 0) {\n console.log(chalk.red.bold('Breaking Changes:'))\n for (const change of breakingChanges) {\n const icon = getChangeIcon(change.type)\n console.log(chalk.red(` ${icon} ${change.message}`))\n }\n console.log('')\n }\n\n if (nonBreakingChanges.length > 0) {\n console.log(chalk.yellow.bold('Non-Breaking Changes:'))\n for (const change of nonBreakingChanges) {\n const icon = getChangeIcon(change.type)\n console.log(chalk.yellow(` ${icon} ${change.message}`))\n }\n console.log('')\n }\n\n // Summary\n console.log(chalk.bold('Summary:'))\n console.log(` Total changes: ${changes.length}`)\n console.log(\n ` Breaking: ${breakingChanges.length > 0 ? chalk.red(breakingChanges.length) : chalk.green('0')}`\n )\n console.log(` Non-breaking: ${nonBreakingChanges.length}`)\n}\n\nfunction getChangeIcon(type: ChangeType['type']): string {\n switch (type) {\n case 'added':\n return '+'\n case 'removed':\n return '-'\n case 'modified':\n return '~'\n case 'deprecated':\n return '⚠'\n default:\n return '•'\n }\n}\n\nfunction isMajorVersionChange(oldVersion: string, newVersion: string): boolean {\n const oldMajor = parseInt(oldVersion.split('.')[0], 10)\n const newMajor = parseInt(newVersion.split('.')[0], 10)\n return newMajor > oldMajor\n}\n"],"names":["__filename","fileURLToPath","__dirname","dirname","resolve","readFileSync","ComponentRegistrySchema","join","path","compile","writeFileSync"],"mappings":"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"}
@@ -0,0 +1,420 @@
1
+ import { readFileSync, writeFileSync } from "fs";
2
+ import { dirname, resolve, join } from "path";
3
+ import Ajv from "ajv";
4
+ import chalk from "chalk";
5
+ import ora from "ora";
6
+ import { ComponentRegistrySchema } from "@seed-ship/mcp-ui-spec";
7
+ import { fileURLToPath } from "url";
8
+ import { compile } from "json-schema-to-typescript";
9
+ const __filename$1 = fileURLToPath(import.meta.url);
10
+ const __dirname$1 = dirname(__filename$1);
11
+ async function validateCommand(file, options) {
12
+ var _a;
13
+ const spinner = ora("Loading registry...").start();
14
+ try {
15
+ const registryPath = resolve(process.cwd(), file);
16
+ const registryContent = readFileSync(registryPath, "utf-8");
17
+ const registry = JSON.parse(registryContent);
18
+ spinner.text = "Validating with Zod schema...";
19
+ const zodResult = ComponentRegistrySchema.safeParse(registry);
20
+ if (!zodResult.success) {
21
+ spinner.fail("Zod validation failed");
22
+ console.error(chalk.red("\nValidation Errors:"));
23
+ zodResult.error.errors.forEach((err) => {
24
+ console.error(chalk.red(` • ${err.path.join(".")}: ${err.message}`));
25
+ });
26
+ process.exit(1);
27
+ }
28
+ spinner.text = "Validating with JSON Schema...";
29
+ const schemaPath = join(
30
+ __dirname$1,
31
+ "../../node_modules/@seed-ship/mcp-ui-spec/schemas/component-registry-v1.json"
32
+ );
33
+ let jsonSchemaContent;
34
+ try {
35
+ jsonSchemaContent = readFileSync(schemaPath, "utf-8");
36
+ } catch {
37
+ const localSchemaPath = join(
38
+ __dirname$1,
39
+ "../../../mcp-ui-spec/schemas/component-registry-v1.json"
40
+ );
41
+ jsonSchemaContent = readFileSync(localSchemaPath, "utf-8");
42
+ }
43
+ const jsonSchema = JSON.parse(jsonSchemaContent);
44
+ const ajv = new Ajv({
45
+ allErrors: options.strict,
46
+ verbose: options.verbose,
47
+ strict: options.strict
48
+ });
49
+ const validate = ajv.compile(jsonSchema);
50
+ const jsonValid = validate(registry);
51
+ if (!jsonValid && validate.errors) {
52
+ spinner.fail("JSON Schema validation failed");
53
+ console.error(chalk.red("\nValidation Errors:"));
54
+ validate.errors.forEach((err) => {
55
+ const path = err.instancePath || "root";
56
+ console.error(chalk.red(` • ${path}: ${err.message}`));
57
+ if (options.verbose && err.params) {
58
+ console.error(chalk.gray(` Params: ${JSON.stringify(err.params)}`));
59
+ }
60
+ });
61
+ process.exit(1);
62
+ }
63
+ spinner.succeed(chalk.green("Registry is valid!"));
64
+ if (options.verbose) {
65
+ console.log(chalk.gray("\nRegistry Summary:"));
66
+ console.log(chalk.gray(` Version: ${registry.version}`));
67
+ console.log(chalk.gray(` Components: ${registry.components.length}`));
68
+ if ((_a = registry.metadata) == null ? void 0 : _a.name) {
69
+ console.log(chalk.gray(` Name: ${registry.metadata.name}`));
70
+ }
71
+ console.log(chalk.gray("\nComponents:"));
72
+ const validRegistry = registry;
73
+ validRegistry.components.forEach((comp) => {
74
+ console.log(chalk.gray(` • ${comp.id} (${comp.type}): ${comp.examples.length} example(s)`));
75
+ });
76
+ }
77
+ process.exit(0);
78
+ } catch (error) {
79
+ spinner.fail("Validation failed");
80
+ if (error instanceof Error) {
81
+ if (error.message.includes("ENOENT")) {
82
+ console.error(chalk.red(`
83
+ File not found: ${file}`));
84
+ } else if (error instanceof SyntaxError) {
85
+ console.error(chalk.red("\nInvalid JSON syntax"));
86
+ console.error(chalk.gray(error.message));
87
+ } else {
88
+ console.error(chalk.red("\nUnexpected error:"));
89
+ console.error(chalk.gray(error.message));
90
+ }
91
+ }
92
+ process.exit(1);
93
+ }
94
+ }
95
+ async function generateTypesCommand(input, output, options) {
96
+ const spinner = ora("Loading registry...").start();
97
+ try {
98
+ const registryPath = resolve(process.cwd(), input);
99
+ const registryContent = readFileSync(registryPath, "utf-8");
100
+ const registry = JSON.parse(registryContent);
101
+ spinner.text = "Generating TypeScript types...";
102
+ const typeDefinitions = [];
103
+ typeDefinitions.push("/**");
104
+ typeDefinitions.push(" * Auto-generated TypeScript types from component registry");
105
+ typeDefinitions.push(" * Generated by @seed-ship/mcp-ui-cli");
106
+ typeDefinitions.push(" */");
107
+ typeDefinitions.push("");
108
+ if (options.namespace) {
109
+ typeDefinitions.push(`export namespace ${options.namespace} {`);
110
+ }
111
+ for (const component of registry.components) {
112
+ spinner.text = `Generating types for ${component.id}...`;
113
+ const typeName = componentIdToTypeName(component.id);
114
+ try {
115
+ const ts = await compile(component.schema, typeName, {
116
+ bannerComment: `/* ${component.name} - ${component.description || "No description"} */`,
117
+ style: {
118
+ semi: false,
119
+ singleQuote: true
120
+ }
121
+ });
122
+ if (options.namespace) {
123
+ const indented = ts.split("\n").map((line) => line ? ` ${line}` : line).join("\n");
124
+ typeDefinitions.push(indented);
125
+ } else {
126
+ typeDefinitions.push(ts);
127
+ }
128
+ typeDefinitions.push("");
129
+ } catch (error) {
130
+ spinner.warn(`Skipping ${component.id}: type generation failed`);
131
+ if (error instanceof Error) {
132
+ console.error(chalk.yellow(` ${error.message}`));
133
+ }
134
+ }
135
+ }
136
+ if (options.namespace) {
137
+ typeDefinitions.push("}");
138
+ }
139
+ const generatedCode = typeDefinitions.join("\n");
140
+ spinner.succeed("Type generation complete");
141
+ if (output) {
142
+ const outputPath = resolve(process.cwd(), output);
143
+ writeFileSync(outputPath, generatedCode, "utf-8");
144
+ console.log(chalk.green(`✓ Types written to ${output}`));
145
+ } else {
146
+ console.log("\n" + generatedCode);
147
+ }
148
+ process.exit(0);
149
+ } catch (error) {
150
+ spinner.fail("Type generation failed");
151
+ if (error instanceof Error) {
152
+ if (error.message.includes("ENOENT")) {
153
+ console.error(chalk.red(`
154
+ File not found: ${input}`));
155
+ } else {
156
+ console.error(chalk.red("\nUnexpected error:"));
157
+ console.error(chalk.gray(error.message));
158
+ }
159
+ }
160
+ process.exit(1);
161
+ }
162
+ }
163
+ function componentIdToTypeName(id) {
164
+ return id.split("-").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
165
+ }
166
+ async function testExamplesCommand(file, options) {
167
+ const spinner = ora("Loading registry...").start();
168
+ try {
169
+ const registryPath = resolve(process.cwd(), file);
170
+ const registryContent = readFileSync(registryPath, "utf-8");
171
+ const registry = JSON.parse(registryContent);
172
+ const componentsToTest = options.component ? registry.components.filter((c) => c.id === options.component) : registry.components;
173
+ if (componentsToTest.length === 0) {
174
+ spinner.fail(`Component not found: ${options.component}`);
175
+ process.exit(1);
176
+ }
177
+ spinner.text = "Running example tests...";
178
+ const results = [];
179
+ let totalExamples = 0;
180
+ let passedExamples = 0;
181
+ for (const component of componentsToTest) {
182
+ spinner.text = `Testing examples for ${component.id}...`;
183
+ const ajv = new Ajv({ allErrors: true, verbose: options.verbose });
184
+ const validate = ajv.compile(component.schema);
185
+ for (const example of component.examples) {
186
+ totalExamples++;
187
+ const valid = validate(example.params);
188
+ const result = {
189
+ componentId: component.id,
190
+ exampleName: example.name,
191
+ passed: valid
192
+ };
193
+ if (!valid && validate.errors) {
194
+ result.errors = validate.errors.map((err) => {
195
+ const path = err.instancePath || "root";
196
+ return `${path}: ${err.message}`;
197
+ });
198
+ }
199
+ if (valid) {
200
+ passedExamples++;
201
+ }
202
+ results.push(result);
203
+ }
204
+ }
205
+ spinner.stop();
206
+ console.log(chalk.bold("\nTest Results:\n"));
207
+ let hasFailures = false;
208
+ for (const result of results) {
209
+ const status = result.passed ? chalk.green("✓") : chalk.red("✗");
210
+ const componentLabel = chalk.cyan(result.componentId);
211
+ const exampleLabel = chalk.gray(result.exampleName);
212
+ console.log(`${status} ${componentLabel} › ${exampleLabel}`);
213
+ if (!result.passed && result.errors) {
214
+ hasFailures = true;
215
+ result.errors.forEach((error) => {
216
+ console.log(chalk.red(` ${error}`));
217
+ });
218
+ }
219
+ }
220
+ console.log("");
221
+ console.log(chalk.bold("Summary:"));
222
+ console.log(` ${chalk.green(`${passedExamples} passed`)} / ${totalExamples} total`);
223
+ if (hasFailures) {
224
+ console.log(chalk.red(` ${totalExamples - passedExamples} failed`));
225
+ process.exit(1);
226
+ }
227
+ console.log(chalk.green("\n✓ All examples are valid!"));
228
+ process.exit(0);
229
+ } catch (error) {
230
+ spinner.fail("Example testing failed");
231
+ if (error instanceof Error) {
232
+ if (error.message.includes("ENOENT")) {
233
+ console.error(chalk.red(`
234
+ File not found: ${file}`));
235
+ } else if (error instanceof SyntaxError) {
236
+ console.error(chalk.red("\nInvalid JSON syntax"));
237
+ console.error(chalk.gray(error.message));
238
+ } else {
239
+ console.error(chalk.red("\nUnexpected error:"));
240
+ console.error(chalk.gray(error.message));
241
+ }
242
+ }
243
+ process.exit(1);
244
+ }
245
+ }
246
+ async function diffCommand(oldFile, newFile, options) {
247
+ const spinner = ora("Loading registries...").start();
248
+ try {
249
+ const oldPath = resolve(process.cwd(), oldFile);
250
+ const newPath = resolve(process.cwd(), newFile);
251
+ const oldRegistry = JSON.parse(readFileSync(oldPath, "utf-8"));
252
+ const newRegistry = JSON.parse(readFileSync(newPath, "utf-8"));
253
+ spinner.text = "Comparing registries...";
254
+ const changes = [];
255
+ const oldComponents = new Map(oldRegistry.components.map((c) => [c.id, c]));
256
+ const newComponents = new Map(newRegistry.components.map((c) => [c.id, c]));
257
+ for (const [id] of oldComponents) {
258
+ if (!newComponents.has(id)) {
259
+ changes.push({
260
+ type: "removed",
261
+ breaking: true,
262
+ componentId: id,
263
+ message: `Component '${id}' was removed`
264
+ });
265
+ }
266
+ }
267
+ for (const [id] of newComponents) {
268
+ if (!oldComponents.has(id)) {
269
+ changes.push({
270
+ type: "added",
271
+ breaking: false,
272
+ componentId: id,
273
+ message: `Component '${id}' was added`
274
+ });
275
+ }
276
+ }
277
+ for (const [id, newComponent] of newComponents) {
278
+ const oldComponent = oldComponents.get(id);
279
+ if (!oldComponent) continue;
280
+ if (!oldComponent.deprecated && newComponent.deprecated) {
281
+ changes.push({
282
+ type: "deprecated",
283
+ breaking: false,
284
+ componentId: id,
285
+ message: `Component '${id}' was deprecated${newComponent.deprecationMessage ? `: ${newComponent.deprecationMessage}` : ""}`
286
+ });
287
+ }
288
+ if (oldComponent.type !== newComponent.type) {
289
+ changes.push({
290
+ type: "modified",
291
+ breaking: true,
292
+ componentId: id,
293
+ field: "type",
294
+ oldValue: oldComponent.type,
295
+ newValue: newComponent.type,
296
+ message: `Component '${id}' type changed from '${oldComponent.type}' to '${newComponent.type}'`
297
+ });
298
+ }
299
+ const oldRequired = new Set(oldComponent.schema.required || []);
300
+ const newRequired = new Set(newComponent.schema.required || []);
301
+ for (const field of newRequired) {
302
+ if (!oldRequired.has(field)) {
303
+ changes.push({
304
+ type: "modified",
305
+ breaking: true,
306
+ componentId: id,
307
+ field: `schema.required`,
308
+ message: `Component '${id}' now requires field '${field}'`
309
+ });
310
+ }
311
+ }
312
+ for (const field of oldRequired) {
313
+ if (!newRequired.has(field)) {
314
+ changes.push({
315
+ type: "modified",
316
+ breaking: false,
317
+ componentId: id,
318
+ field: `schema.required`,
319
+ message: `Component '${id}' no longer requires field '${field}'`
320
+ });
321
+ }
322
+ }
323
+ if (oldComponent.version !== newComponent.version) {
324
+ const oldVersion = oldComponent.version || "0.0.0";
325
+ const newVersion = newComponent.version || "0.0.0";
326
+ const breaking = isMajorVersionChange(oldVersion, newVersion);
327
+ changes.push({
328
+ type: "modified",
329
+ breaking,
330
+ componentId: id,
331
+ field: "version",
332
+ oldValue: oldVersion,
333
+ newValue: newVersion,
334
+ message: `Component '${id}' version changed from ${oldVersion} to ${newVersion}`
335
+ });
336
+ }
337
+ }
338
+ spinner.stop();
339
+ if (options.json) {
340
+ console.log(JSON.stringify({ changes }, null, 2));
341
+ } else {
342
+ displayHumanReadableDiff(changes);
343
+ }
344
+ const hasBreakingChanges = changes.some((c) => c.breaking);
345
+ if (options.failOnBreaking && hasBreakingChanges) {
346
+ console.error(chalk.red("\n✗ Breaking changes detected!"));
347
+ process.exit(1);
348
+ }
349
+ process.exit(0);
350
+ } catch (error) {
351
+ spinner.fail("Diff failed");
352
+ if (error instanceof Error) {
353
+ if (error.message.includes("ENOENT")) {
354
+ console.error(chalk.red(`
355
+ File not found`));
356
+ } else {
357
+ console.error(chalk.red("\nUnexpected error:"));
358
+ console.error(chalk.gray(error.message));
359
+ }
360
+ }
361
+ process.exit(1);
362
+ }
363
+ }
364
+ function displayHumanReadableDiff(changes) {
365
+ console.log(chalk.bold("\nRegistry Changes:\n"));
366
+ if (changes.length === 0) {
367
+ console.log(chalk.gray("No changes detected"));
368
+ return;
369
+ }
370
+ const breakingChanges = changes.filter((c) => c.breaking);
371
+ const nonBreakingChanges = changes.filter((c) => !c.breaking);
372
+ if (breakingChanges.length > 0) {
373
+ console.log(chalk.red.bold("Breaking Changes:"));
374
+ for (const change of breakingChanges) {
375
+ const icon = getChangeIcon(change.type);
376
+ console.log(chalk.red(` ${icon} ${change.message}`));
377
+ }
378
+ console.log("");
379
+ }
380
+ if (nonBreakingChanges.length > 0) {
381
+ console.log(chalk.yellow.bold("Non-Breaking Changes:"));
382
+ for (const change of nonBreakingChanges) {
383
+ const icon = getChangeIcon(change.type);
384
+ console.log(chalk.yellow(` ${icon} ${change.message}`));
385
+ }
386
+ console.log("");
387
+ }
388
+ console.log(chalk.bold("Summary:"));
389
+ console.log(` Total changes: ${changes.length}`);
390
+ console.log(
391
+ ` Breaking: ${breakingChanges.length > 0 ? chalk.red(breakingChanges.length) : chalk.green("0")}`
392
+ );
393
+ console.log(` Non-breaking: ${nonBreakingChanges.length}`);
394
+ }
395
+ function getChangeIcon(type) {
396
+ switch (type) {
397
+ case "added":
398
+ return "+";
399
+ case "removed":
400
+ return "-";
401
+ case "modified":
402
+ return "~";
403
+ case "deprecated":
404
+ return "⚠";
405
+ default:
406
+ return "•";
407
+ }
408
+ }
409
+ function isMajorVersionChange(oldVersion, newVersion) {
410
+ const oldMajor = parseInt(oldVersion.split(".")[0], 10);
411
+ const newMajor = parseInt(newVersion.split(".")[0], 10);
412
+ return newMajor > oldMajor;
413
+ }
414
+ export {
415
+ diffCommand as d,
416
+ generateTypesCommand as g,
417
+ testExamplesCommand as t,
418
+ validateCommand as v
419
+ };
420
+ //# sourceMappingURL=diff-B8QJSPfQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-B8QJSPfQ.js","sources":["../src/commands/validate.ts","../src/commands/generate-types.ts","../src/commands/test-examples.ts","../src/commands/diff.ts"],"sourcesContent":["/**\n * Validate command - validates component registry against JSON Schema\n */\n\nimport { readFileSync } from 'fs'\nimport { resolve } from 'path'\nimport Ajv from 'ajv'\nimport chalk from 'chalk'\nimport ora from 'ora'\nimport { ComponentRegistrySchema, type ComponentRegistry } from '@seed-ship/mcp-ui-spec'\n\n// Load JSON Schema from @seed-ship/mcp-ui-spec package\nimport { fileURLToPath } from 'url'\nimport { dirname, join } from 'path'\n\nconst __filename = fileURLToPath(import.meta.url)\nconst __dirname = dirname(__filename)\n\ninterface ValidateOptions {\n strict?: boolean\n verbose?: boolean\n}\n\nexport async function validateCommand(file: string, options: ValidateOptions) {\n const spinner = ora('Loading registry...').start()\n\n try {\n // Read registry file\n const registryPath = resolve(process.cwd(), file)\n const registryContent = readFileSync(registryPath, 'utf-8')\n const registry = JSON.parse(registryContent)\n\n spinner.text = 'Validating with Zod schema...'\n\n // First validate with Zod (runtime validation)\n const zodResult = ComponentRegistrySchema.safeParse(registry)\n\n if (!zodResult.success) {\n spinner.fail('Zod validation failed')\n console.error(chalk.red('\\nValidation Errors:'))\n zodResult.error.errors.forEach((err) => {\n console.error(chalk.red(` • ${err.path.join('.')}: ${err.message}`))\n })\n process.exit(1)\n }\n\n spinner.text = 'Validating with JSON Schema...'\n\n // Load JSON Schema for secondary validation\n const schemaPath = join(\n __dirname,\n '../../node_modules/@seed-ship/mcp-ui-spec/schemas/component-registry-v1.json'\n )\n let jsonSchemaContent: string\n\n try {\n jsonSchemaContent = readFileSync(schemaPath, 'utf-8')\n } catch {\n // Fallback to local schema if node_modules path fails\n const localSchemaPath = join(\n __dirname,\n '../../../mcp-ui-spec/schemas/component-registry-v1.json'\n )\n jsonSchemaContent = readFileSync(localSchemaPath, 'utf-8')\n }\n\n const jsonSchema = JSON.parse(jsonSchemaContent)\n\n // Validate with JSON Schema using Ajv\n const ajv = new Ajv({\n allErrors: options.strict,\n verbose: options.verbose,\n strict: options.strict,\n })\n\n const validate = ajv.compile(jsonSchema)\n const jsonValid = validate(registry)\n\n if (!jsonValid && validate.errors) {\n spinner.fail('JSON Schema validation failed')\n console.error(chalk.red('\\nValidation Errors:'))\n validate.errors.forEach((err) => {\n const path = err.instancePath || 'root'\n console.error(chalk.red(` • ${path}: ${err.message}`))\n if (options.verbose && err.params) {\n console.error(chalk.gray(` Params: ${JSON.stringify(err.params)}`))\n }\n })\n process.exit(1)\n }\n\n spinner.succeed(chalk.green('Registry is valid!'))\n\n // Summary\n if (options.verbose) {\n console.log(chalk.gray('\\nRegistry Summary:'))\n console.log(chalk.gray(` Version: ${registry.version}`))\n console.log(chalk.gray(` Components: ${registry.components.length}`))\n\n if (registry.metadata?.name) {\n console.log(chalk.gray(` Name: ${registry.metadata.name}`))\n }\n\n console.log(chalk.gray('\\nComponents:'))\n const validRegistry = registry as ComponentRegistry\n validRegistry.components.forEach((comp) => {\n console.log(chalk.gray(` • ${comp.id} (${comp.type}): ${comp.examples.length} example(s)`))\n })\n }\n\n process.exit(0)\n } catch (error) {\n spinner.fail('Validation failed')\n\n if (error instanceof Error) {\n if (error.message.includes('ENOENT')) {\n console.error(chalk.red(`\\nFile not found: ${file}`))\n } else if (error instanceof SyntaxError) {\n console.error(chalk.red('\\nInvalid JSON syntax'))\n console.error(chalk.gray(error.message))\n } else {\n console.error(chalk.red('\\nUnexpected error:'))\n console.error(chalk.gray(error.message))\n }\n }\n\n process.exit(1)\n }\n}\n","/**\n * Generate Types command - generates TypeScript types from registry\n */\n\nimport { readFileSync, writeFileSync } from 'fs'\nimport { resolve } from 'path'\nimport { compile } from 'json-schema-to-typescript'\nimport chalk from 'chalk'\nimport ora from 'ora'\nimport type { Component, ComponentRegistry } from '@seed-ship/mcp-ui-spec'\n\ninterface GenerateTypesOptions {\n namespace?: string\n exportAll?: boolean\n}\n\nexport async function generateTypesCommand(\n input: string,\n output: string | undefined,\n options: GenerateTypesOptions\n) {\n const spinner = ora('Loading registry...').start()\n\n try {\n // Read registry file\n const registryPath = resolve(process.cwd(), input)\n const registryContent = readFileSync(registryPath, 'utf-8')\n const registry: ComponentRegistry = JSON.parse(registryContent)\n\n spinner.text = 'Generating TypeScript types...'\n\n // Generate types for each component\n const typeDefinitions: string[] = []\n\n // Add header comment\n typeDefinitions.push('/**')\n typeDefinitions.push(' * Auto-generated TypeScript types from component registry')\n typeDefinitions.push(' * Generated by @seed-ship/mcp-ui-cli')\n typeDefinitions.push(' */')\n typeDefinitions.push('')\n\n if (options.namespace) {\n typeDefinitions.push(`export namespace ${options.namespace} {`)\n }\n\n // Generate types for each component\n for (const component of registry.components as Component[]) {\n spinner.text = `Generating types for ${component.id}...`\n\n // Generate interface name from component ID\n const typeName = componentIdToTypeName(component.id)\n\n try {\n const ts = await compile(component.schema as any, typeName, {\n bannerComment: `/* ${component.name} - ${component.description || 'No description'} */`,\n style: {\n semi: false,\n singleQuote: true,\n },\n })\n\n // Add the generated type\n if (options.namespace) {\n // Indent for namespace\n const indented = ts\n .split('\\n')\n .map((line) => (line ? ` ${line}` : line))\n .join('\\n')\n typeDefinitions.push(indented)\n } else {\n typeDefinitions.push(ts)\n }\n\n typeDefinitions.push('')\n } catch (error) {\n spinner.warn(`Skipping ${component.id}: type generation failed`)\n if (error instanceof Error) {\n console.error(chalk.yellow(` ${error.message}`))\n }\n }\n }\n\n if (options.namespace) {\n typeDefinitions.push('}')\n }\n\n const generatedCode = typeDefinitions.join('\\n')\n\n spinner.succeed('Type generation complete')\n\n // Write to file or stdout\n if (output) {\n const outputPath = resolve(process.cwd(), output)\n writeFileSync(outputPath, generatedCode, 'utf-8')\n console.log(chalk.green(`✓ Types written to ${output}`))\n } else {\n console.log('\\n' + generatedCode)\n }\n\n process.exit(0)\n } catch (error) {\n spinner.fail('Type generation failed')\n\n if (error instanceof Error) {\n if (error.message.includes('ENOENT')) {\n console.error(chalk.red(`\\nFile not found: ${input}`))\n } else {\n console.error(chalk.red('\\nUnexpected error:'))\n console.error(chalk.gray(error.message))\n }\n }\n\n process.exit(1)\n }\n}\n\n/**\n * Convert component ID to TypeScript type name\n * Examples:\n * quickchart-bar -> QuickchartBar\n * metric-card -> MetricCard\n * data-table -> DataTable\n */\nfunction componentIdToTypeName(id: string): string {\n return id\n .split('-')\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join('')\n}\n","/**\n * Test Examples command - validates all component examples\n */\n\nimport { readFileSync } from 'fs'\nimport { resolve } from 'path'\nimport Ajv from 'ajv'\nimport chalk from 'chalk'\nimport ora from 'ora'\nimport type { ComponentRegistry } from '@seed-ship/mcp-ui-spec'\n\ninterface TestExamplesOptions {\n component?: string\n verbose?: boolean\n}\n\ninterface TestResult {\n componentId: string\n exampleName: string\n passed: boolean\n errors?: string[]\n}\n\nexport async function testExamplesCommand(file: string, options: TestExamplesOptions) {\n const spinner = ora('Loading registry...').start()\n\n try {\n // Read registry file\n const registryPath = resolve(process.cwd(), file)\n const registryContent = readFileSync(registryPath, 'utf-8')\n const registry: ComponentRegistry = JSON.parse(registryContent)\n\n // Filter components if specific component requested\n const componentsToTest = options.component\n ? registry.components.filter((c) => c.id === options.component)\n : registry.components\n\n if (componentsToTest.length === 0) {\n spinner.fail(`Component not found: ${options.component}`)\n process.exit(1)\n }\n\n spinner.text = 'Running example tests...'\n\n const results: TestResult[] = []\n let totalExamples = 0\n let passedExamples = 0\n\n // Test each component's examples\n for (const component of componentsToTest) {\n spinner.text = `Testing examples for ${component.id}...`\n\n // Create Ajv validator for this component's schema\n const ajv = new Ajv({ allErrors: true, verbose: options.verbose })\n const validate = ajv.compile(component.schema as any)\n\n // Test each example\n for (const example of component.examples) {\n totalExamples++\n\n const valid = validate(example.params)\n const result: TestResult = {\n componentId: component.id,\n exampleName: example.name,\n passed: valid,\n }\n\n if (!valid && validate.errors) {\n result.errors = validate.errors.map((err) => {\n const path = err.instancePath || 'root'\n return `${path}: ${err.message}`\n })\n }\n\n if (valid) {\n passedExamples++\n }\n\n results.push(result)\n }\n }\n\n spinner.stop()\n\n // Display results\n console.log(chalk.bold('\\nTest Results:\\n'))\n\n let hasFailures = false\n\n for (const result of results) {\n const status = result.passed ? chalk.green('✓') : chalk.red('✗')\n const componentLabel = chalk.cyan(result.componentId)\n const exampleLabel = chalk.gray(result.exampleName)\n\n console.log(`${status} ${componentLabel} › ${exampleLabel}`)\n\n if (!result.passed && result.errors) {\n hasFailures = true\n result.errors.forEach((error) => {\n console.log(chalk.red(` ${error}`))\n })\n }\n }\n\n // Summary\n console.log('')\n console.log(chalk.bold('Summary:'))\n console.log(` ${chalk.green(`${passedExamples} passed`)} / ${totalExamples} total`)\n\n if (hasFailures) {\n console.log(chalk.red(` ${totalExamples - passedExamples} failed`))\n process.exit(1)\n }\n\n console.log(chalk.green('\\n✓ All examples are valid!'))\n process.exit(0)\n } catch (error) {\n spinner.fail('Example testing failed')\n\n if (error instanceof Error) {\n if (error.message.includes('ENOENT')) {\n console.error(chalk.red(`\\nFile not found: ${file}`))\n } else if (error instanceof SyntaxError) {\n console.error(chalk.red('\\nInvalid JSON syntax'))\n console.error(chalk.gray(error.message))\n } else {\n console.error(chalk.red('\\nUnexpected error:'))\n console.error(chalk.gray(error.message))\n }\n }\n\n process.exit(1)\n }\n}\n","/**\n * Diff command - compares two registry versions for breaking changes\n */\n\nimport { readFileSync } from 'fs'\nimport { resolve } from 'path'\nimport chalk from 'chalk'\nimport ora from 'ora'\nimport type { ComponentRegistry } from '@seed-ship/mcp-ui-spec'\n\ninterface DiffOptions {\n json?: boolean\n failOnBreaking?: boolean\n}\n\ninterface ChangeType {\n type: 'added' | 'removed' | 'modified' | 'deprecated'\n breaking: boolean\n componentId: string\n field?: string\n oldValue?: unknown\n newValue?: unknown\n message: string\n}\n\nexport async function diffCommand(oldFile: string, newFile: string, options: DiffOptions) {\n const spinner = ora('Loading registries...').start()\n\n try {\n // Read both registry files\n const oldPath = resolve(process.cwd(), oldFile)\n const newPath = resolve(process.cwd(), newFile)\n\n const oldRegistry: ComponentRegistry = JSON.parse(readFileSync(oldPath, 'utf-8'))\n const newRegistry: ComponentRegistry = JSON.parse(readFileSync(newPath, 'utf-8'))\n\n spinner.text = 'Comparing registries...'\n\n const changes: ChangeType[] = []\n\n // Create maps for easier lookup\n const oldComponents = new Map(oldRegistry.components.map((c) => [c.id, c]))\n const newComponents = new Map(newRegistry.components.map((c) => [c.id, c]))\n\n // Check for removed components (breaking)\n for (const [id] of oldComponents) {\n if (!newComponents.has(id)) {\n changes.push({\n type: 'removed',\n breaking: true,\n componentId: id,\n message: `Component '${id}' was removed`,\n })\n }\n }\n\n // Check for added components (non-breaking)\n for (const [id] of newComponents) {\n if (!oldComponents.has(id)) {\n changes.push({\n type: 'added',\n breaking: false,\n componentId: id,\n message: `Component '${id}' was added`,\n })\n }\n }\n\n // Check for modified components\n for (const [id, newComponent] of newComponents) {\n const oldComponent = oldComponents.get(id)\n if (!oldComponent) continue\n\n // Check deprecation\n if (!oldComponent.deprecated && newComponent.deprecated) {\n changes.push({\n type: 'deprecated',\n breaking: false,\n componentId: id,\n message: `Component '${id}' was deprecated${\n newComponent.deprecationMessage ? `: ${newComponent.deprecationMessage}` : ''\n }`,\n })\n }\n\n // Check type change (breaking)\n if (oldComponent.type !== newComponent.type) {\n changes.push({\n type: 'modified',\n breaking: true,\n componentId: id,\n field: 'type',\n oldValue: oldComponent.type,\n newValue: newComponent.type,\n message: `Component '${id}' type changed from '${oldComponent.type}' to '${newComponent.type}'`,\n })\n }\n\n // Check required fields change (breaking)\n const oldRequired = new Set(oldComponent.schema.required || [])\n const newRequired = new Set(newComponent.schema.required || [])\n\n for (const field of newRequired) {\n if (!oldRequired.has(field)) {\n changes.push({\n type: 'modified',\n breaking: true,\n componentId: id,\n field: `schema.required`,\n message: `Component '${id}' now requires field '${field}'`,\n })\n }\n }\n\n for (const field of oldRequired) {\n if (!newRequired.has(field)) {\n changes.push({\n type: 'modified',\n breaking: false,\n componentId: id,\n field: `schema.required`,\n message: `Component '${id}' no longer requires field '${field}'`,\n })\n }\n }\n\n // Check version change\n if (oldComponent.version !== newComponent.version) {\n const oldVersion = oldComponent.version || '0.0.0'\n const newVersion = newComponent.version || '0.0.0'\n\n const breaking = isMajorVersionChange(oldVersion, newVersion)\n\n changes.push({\n type: 'modified',\n breaking,\n componentId: id,\n field: 'version',\n oldValue: oldVersion,\n newValue: newVersion,\n message: `Component '${id}' version changed from ${oldVersion} to ${newVersion}`,\n })\n }\n }\n\n spinner.stop()\n\n // Output results\n if (options.json) {\n console.log(JSON.stringify({ changes }, null, 2))\n } else {\n displayHumanReadableDiff(changes)\n }\n\n // Check if we should fail on breaking changes\n const hasBreakingChanges = changes.some((c) => c.breaking)\n if (options.failOnBreaking && hasBreakingChanges) {\n console.error(chalk.red('\\n✗ Breaking changes detected!'))\n process.exit(1)\n }\n\n process.exit(0)\n } catch (error) {\n spinner.fail('Diff failed')\n\n if (error instanceof Error) {\n if (error.message.includes('ENOENT')) {\n console.error(chalk.red(`\\nFile not found`))\n } else {\n console.error(chalk.red('\\nUnexpected error:'))\n console.error(chalk.gray(error.message))\n }\n }\n\n process.exit(1)\n }\n}\n\nfunction displayHumanReadableDiff(changes: ChangeType[]) {\n console.log(chalk.bold('\\nRegistry Changes:\\n'))\n\n if (changes.length === 0) {\n console.log(chalk.gray('No changes detected'))\n return\n }\n\n const breakingChanges = changes.filter((c) => c.breaking)\n const nonBreakingChanges = changes.filter((c) => !c.breaking)\n\n if (breakingChanges.length > 0) {\n console.log(chalk.red.bold('Breaking Changes:'))\n for (const change of breakingChanges) {\n const icon = getChangeIcon(change.type)\n console.log(chalk.red(` ${icon} ${change.message}`))\n }\n console.log('')\n }\n\n if (nonBreakingChanges.length > 0) {\n console.log(chalk.yellow.bold('Non-Breaking Changes:'))\n for (const change of nonBreakingChanges) {\n const icon = getChangeIcon(change.type)\n console.log(chalk.yellow(` ${icon} ${change.message}`))\n }\n console.log('')\n }\n\n // Summary\n console.log(chalk.bold('Summary:'))\n console.log(` Total changes: ${changes.length}`)\n console.log(\n ` Breaking: ${breakingChanges.length > 0 ? chalk.red(breakingChanges.length) : chalk.green('0')}`\n )\n console.log(` Non-breaking: ${nonBreakingChanges.length}`)\n}\n\nfunction getChangeIcon(type: ChangeType['type']): string {\n switch (type) {\n case 'added':\n return '+'\n case 'removed':\n return '-'\n case 'modified':\n return '~'\n case 'deprecated':\n return '⚠'\n default:\n return '•'\n }\n}\n\nfunction isMajorVersionChange(oldVersion: string, newVersion: string): boolean {\n const oldMajor = parseInt(oldVersion.split('.')[0], 10)\n const newMajor = parseInt(newVersion.split('.')[0], 10)\n return newMajor > oldMajor\n}\n"],"names":["__filename","__dirname"],"mappings":"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"}
package/dist/index.cjs ADDED
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const diff = require("./diff-B1c8BBVB.cjs");
4
+ exports.diffCommand = diff.diffCommand;
5
+ exports.generateTypesCommand = diff.generateTypesCommand;
6
+ exports.testExamplesCommand = diff.testExamplesCommand;
7
+ exports.validateCommand = diff.validateCommand;
8
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;"}
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ import { d, g, t, v } from "./diff-B8QJSPfQ.js";
2
+ export {
3
+ d as diffCommand,
4
+ g as generateTypesCommand,
5
+ t as testExamplesCommand,
6
+ v as validateCommand
7
+ };
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "@seed-ship/mcp-ui-cli",
3
+ "version": "1.0.2",
4
+ "description": "CLI tools for validating and generating MCP UI component registries",
5
+ "type": "module",
6
+ "bin": {
7
+ "mcp-ui": "./dist/cli.js"
8
+ },
9
+ "main": "./dist/index.cjs",
10
+ "module": "./dist/index.js",
11
+ "types": "./dist/index.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "import": "./dist/index.js",
15
+ "require": "./dist/index.cjs",
16
+ "types": "./dist/index.d.ts"
17
+ }
18
+ },
19
+ "files": [
20
+ "dist",
21
+ "README.md",
22
+ "CHANGELOG.md"
23
+ ],
24
+ "dependencies": {
25
+ "ajv": "^8.12.0",
26
+ "commander": "^11.1.0",
27
+ "json-schema-to-typescript": "^13.1.1",
28
+ "zod": "^3.22.4",
29
+ "chalk": "^5.3.0",
30
+ "ora": "^7.0.1",
31
+ "@seed-ship/mcp-ui-spec": "1.0.2"
32
+ },
33
+ "devDependencies": {
34
+ "@types/node": "^20.10.0",
35
+ "@typescript-eslint/eslint-plugin": "^6.15.0",
36
+ "@typescript-eslint/parser": "^6.15.0",
37
+ "eslint": "^8.56.0",
38
+ "typescript": "^5.3.3",
39
+ "vite": "^5.0.10",
40
+ "vitest": "^1.1.0"
41
+ },
42
+ "keywords": [
43
+ "mcp",
44
+ "ui",
45
+ "cli",
46
+ "validation",
47
+ "codegen",
48
+ "component-registry"
49
+ ],
50
+ "author": "Gabriel Brument",
51
+ "license": "MIT",
52
+ "repository": {
53
+ "type": "git",
54
+ "url": "https://github.com/theseedship/mcp-ui.git",
55
+ "directory": "mcp-ui-cli"
56
+ },
57
+ "homepage": "https://github.com/theseedship/mcp-ui#readme",
58
+ "bugs": {
59
+ "url": "https://github.com/theseedship/mcp-ui/issues"
60
+ },
61
+ "scripts": {
62
+ "build": "vite build",
63
+ "build:types": "tsc --emitDeclarationOnly --outDir dist",
64
+ "dev": "vite build --watch",
65
+ "test": "vitest run",
66
+ "test:watch": "vitest",
67
+ "lint": "eslint src",
68
+ "typecheck": "tsc --noEmit",
69
+ "clean": "rm -rf dist"
70
+ }
71
+ }