@agiflowai/style-system 0.0.1

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 ADDED
@@ -0,0 +1,318 @@
1
+ # @agiflowai/style-system
2
+
3
+ > MCP server for enforcing brand consistency and style guide compliance
4
+
5
+ Help AI coding agents follow your company's branding and style guide. style-system ensures AI-generated code uses only approved design tokens, existing components, and adheres to your visual standards.
6
+
7
+ ## Why Use This?
8
+
9
+ When AI agents write frontend code, they don't know your brand guidelines:
10
+ - What colors, spacing, and typography are approved?
11
+ - What UI components already exist in your design system?
12
+ - Does the output match your brand's visual identity?
13
+
14
+ style-system solves this by:
15
+
16
+ 1. **Enforcing brand tokens** - Agent uses only approved colors, spacing, and typography from your theme
17
+ 2. **Preventing design drift** - Agent discovers existing components instead of creating inconsistent duplicates
18
+ 3. **Visual verification** - Agent can preview components to ensure brand alignment
19
+
20
+ ---
21
+
22
+ ## Quick Start
23
+
24
+ ### 1. Requirements
25
+
26
+ - Node.js >= 18
27
+ - MCP-compatible agent (Claude Code, Cursor, Gemini CLI)
28
+ - Chrome browser (recommended) OR Playwright browsers for `get_component_visual` tool
29
+
30
+ ### 2. Configure Your AI Agent
31
+
32
+ Add to your MCP config (`.mcp.json`, `.cursor/mcp.json`, etc.):
33
+
34
+ ```json
35
+ {
36
+ "mcpServers": {
37
+ "style-system": {
38
+ "command": "npx",
39
+ "args": ["-y", "@agiflowai/style-system", "mcp-serve"]
40
+ }
41
+ }
42
+ }
43
+ ```
44
+
45
+ ### 3. Start Using
46
+
47
+ Your AI agent now enforces your brand guidelines:
48
+
49
+ ```
50
+ You: "Style this button component"
51
+
52
+ Agent:
53
+ 1. Calls get_css_classes to get your approved design tokens
54
+ 2. Writes styles using only brand-approved colors, spacing, typography
55
+ 3. Output is consistent with your style guide
56
+ ```
57
+
58
+ ---
59
+
60
+ ## Available Tools
61
+
62
+ | Tool | Purpose | When to Use |
63
+ |------|---------|-------------|
64
+ | `list_themes` | List available brand themes | Understanding brand variations |
65
+ | `get_css_classes` | Extract approved design tokens from theme | Before writing any styles |
66
+ | `list_shared_components` | List brand-approved UI components | Before creating new components |
67
+ | `list_app_components` | List app-specific components | Finding existing branded components |
68
+ | `get_component_visual` | Render component preview screenshot | Verifying brand alignment |
69
+
70
+ ---
71
+
72
+ ## How It Works
73
+
74
+ ```
75
+ ┌─────────────────────────────────────────────────────────────┐
76
+ │ Your AI Agent │
77
+ └─────────────────────────────────────────────────────────────┘
78
+
79
+ ┌────────────────────┼────────────────────┐
80
+ ▼ ▼ ▼
81
+ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
82
+ │ Before │ │ Before │ │ Verifying │
83
+ │ Styling │ │ Creating │ │ Brand │
84
+ │ │ │ Components │ │ Alignment │
85
+ │ get_css_ │ │ list_shared_ │ │ get_ │
86
+ │ classes │ │ components │ │ component_ │
87
+ │ │ │ │ │ visual │
88
+ └──────────────┘ └──────────────┘ └──────────────┘
89
+ │ │ │
90
+ ▼ ▼ ▼
91
+ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
92
+ │ Brand Tokens │ │ Component │ │ Visual │
93
+ │ │ │ Library │ │ Preview │
94
+ │ │ │ │ │ │
95
+ │ • Colors │ │ • Buttons │ │ • Screenshot │
96
+ │ • Spacing │ │ • Forms │ │ • Brand │
97
+ │ • Typography │ │ • Layout │ │ check │
98
+ └──────────────┘ └──────────────┘ └──────────────┘
99
+ ```
100
+
101
+ ### Workflow Examples
102
+
103
+ **Enforcing Brand Tokens:**
104
+ ```
105
+ User: "Add hover styles to the card"
106
+
107
+ Agent:
108
+ 1. get_css_classes → extracts approved design tokens
109
+ 2. Sees brand colors: hover:bg-primary, hover:bg-secondary
110
+ 3. Applies only brand-approved styles
111
+ ```
112
+
113
+ **Reusing Brand Components:**
114
+ ```
115
+ User: "I need a modal dialog"
116
+
117
+ Agent:
118
+ 1. list_shared_components tags:["ui"]
119
+ 2. Finds: Dialog component at packages/ui/src/Dialog.tsx
120
+ 3. Uses existing branded component instead of creating off-brand duplicate
121
+ ```
122
+
123
+ **Verifying Brand Alignment:**
124
+ ```
125
+ User: "Show me the Button variants"
126
+
127
+ Agent:
128
+ 1. get_component_visual componentName:"Button" appPath:"apps/web"
129
+ 2. Returns: Screenshot showing branded button variants
130
+ 3. Agent verifies output matches brand guidelines
131
+ ```
132
+
133
+ ---
134
+
135
+ ## Configuration
136
+
137
+ Add `style-system` config to your app's `project.json`:
138
+
139
+ ```json
140
+ {
141
+ "name": "my-app",
142
+ "sourceRoot": "apps/my-app/src",
143
+ "style-system": {
144
+ "type": "tailwind",
145
+ "themeProvider": "@your-org/web-ui",
146
+ "themePath": "packages/web-theme/src/theme.css",
147
+ "cssFiles": ["src/styles/globals.css"],
148
+ "rootComponent": "src/providers/ThemeProvider.tsx",
149
+ "sharedComponentTags": ["ui", "primitives"]
150
+ }
151
+ }
152
+ ```
153
+
154
+ | Setup | project.json Location |
155
+ |-------|----------------------|
156
+ | Monorepo | `apps/my-app/project.json` |
157
+ | Monolith | `./project.json` (project root) |
158
+
159
+ ### Workspace Defaults (toolkit.yaml)
160
+
161
+ Configure workspace-level defaults and custom service overrides in `toolkit.yaml`:
162
+
163
+ ```yaml
164
+ style-system:
165
+ # Default tags for list_shared_components tool
166
+ sharedComponentTags:
167
+ - "ui"
168
+ - "primitives"
169
+
170
+ # Custom service for get_css_classes tool (optional)
171
+ getCssClasses:
172
+ customService: ./my-custom-css-service.ts
173
+
174
+ # Custom bundler service for component rendering (optional)
175
+ bundler:
176
+ customService: ./my-custom-bundler.ts
177
+ ```
178
+
179
+ | Option | Description |
180
+ |--------|-------------|
181
+ | `sharedComponentTags` | Default tags for `list_shared_components` tool |
182
+ | `getCssClasses.customService` | Path to custom CSS extraction service (extends `BaseCSSClassesService`) |
183
+ | `bundler.customService` | Path to custom bundler service (extends `BaseBundlerService`) |
184
+
185
+ ### Configuration Options
186
+
187
+ | Option | Required | Description |
188
+ |--------|----------|-------------|
189
+ | `type` | Yes | Style system type: `tailwind` or `shadcn` |
190
+ | `themeProvider` | Yes | Package or path providing brand theme |
191
+ | `themePath` | No | Path to brand token CSS file |
192
+ | `cssFiles` | No | Additional brand CSS files for rendering |
193
+ | `rootComponent` | No | Wrapper component for branded previews |
194
+ | `tailwindConfig` | No | Path to tailwind.config.js (if non-standard) |
195
+ | `sharedComponentTags` | No | Storybook tags for brand components (default: `['style-system']`) |
196
+ | `componentLibrary` | No | Component library path (for shadcn type) |
197
+
198
+ ---
199
+
200
+ ## Browser Requirements
201
+
202
+ The `get_component_visual` tool requires a browser to render and capture component screenshots. The tool automatically detects available browsers in this order:
203
+
204
+ 1. **System Chrome** (recommended) - Uses your installed Chrome browser
205
+ 2. **Playwright Chromium** - Playwright's bundled Chromium
206
+ 3. **Playwright Firefox** - Playwright's bundled Firefox
207
+
208
+ If no browser is found, you'll see an error with installation instructions:
209
+
210
+ ```bash
211
+ # Install Playwright browsers (if Chrome is not available)
212
+ npx playwright install chromium
213
+ ```
214
+
215
+ ---
216
+
217
+ ## Custom CSS Classes Service
218
+
219
+ For custom CSS extraction logic, extend `BaseCSSClassesService`:
220
+
221
+ ```typescript
222
+ // my-custom-css-service.ts
223
+ import { BaseCSSClassesService } from '@agiflowai/style-system';
224
+
225
+ export default class MyCustomCSSService extends BaseCSSClassesService {
226
+ getFrameworkId(): string { return 'my-framework'; }
227
+
228
+ // Key method to override:
229
+ async extractClasses(category, themePath) {
230
+ // Parse your CSS/theme file and return classes by category
231
+ return {
232
+ colors: [{ name: 'primary', value: '#007bff' }],
233
+ typography: [],
234
+ spacing: [],
235
+ effects: [],
236
+ };
237
+ }
238
+ }
239
+ ```
240
+
241
+ Configure in `toolkit.yaml`:
242
+
243
+ ```yaml
244
+ style-system:
245
+ getCssClasses:
246
+ customService: packages/my-app/src/my-custom-css-service.ts
247
+ ```
248
+
249
+ ---
250
+
251
+ ## Custom Bundler Service
252
+
253
+ For advanced use cases, extend `BaseBundlerService` to customize component rendering:
254
+
255
+ ```typescript
256
+ // my-custom-bundler.ts
257
+ import { BaseBundlerService } from '@agiflowai/style-system';
258
+
259
+ export default class MyCustomBundlerService extends BaseBundlerService {
260
+ // Key methods to override:
261
+ async startDevServer(appPath: string) { /* Start dev server */ }
262
+ async serveComponent(options) { /* Serve component via dev server */ }
263
+ async prerenderComponent(options) { /* Build static HTML */ }
264
+ async cleanup() { /* Cleanup resources */ }
265
+ }
266
+ ```
267
+
268
+ Configure in `toolkit.yaml`:
269
+
270
+ ```yaml
271
+ style-system:
272
+ bundler:
273
+ customService: packages/my-app/src/my-custom-bundler.ts
274
+ ```
275
+
276
+ ---
277
+
278
+ ## Server Options
279
+
280
+ ```bash
281
+ # stdio transport (default)
282
+ npx @agiflowai/style-system mcp-serve
283
+
284
+ # HTTP transport
285
+ npx @agiflowai/style-system mcp-serve --type http --port 3000
286
+
287
+ # SSE transport
288
+ npx @agiflowai/style-system mcp-serve --type sse --port 3000
289
+ ```
290
+
291
+ | Option | Description | Default |
292
+ |--------|-------------|---------|
293
+ | `-t, --type` | Transport: `stdio`, `http`, `sse` | `stdio` |
294
+ | `-p, --port` | Port for HTTP/SSE | `3000` |
295
+
296
+ ---
297
+
298
+ ## Development
299
+
300
+ ```bash
301
+ # Install dependencies
302
+ pnpm install
303
+
304
+ # Build
305
+ pnpm build
306
+
307
+ # Test
308
+ pnpm test
309
+
310
+ # Type check
311
+ pnpm typecheck
312
+ ```
313
+
314
+ ---
315
+
316
+ ## License
317
+
318
+ [AGPL-3.0](../../LICENSE)
package/dist/cli.cjs ADDED
@@ -0,0 +1,184 @@
1
+ #!/usr/bin/env node
2
+ const require_stdio = require('./stdio-BlNvX94v.cjs');
3
+ let __agiflowai_aicode_utils = require("@agiflowai/aicode-utils");
4
+ __agiflowai_aicode_utils = require_stdio.__toESM(__agiflowai_aicode_utils);
5
+ let commander = require("commander");
6
+ commander = require_stdio.__toESM(commander);
7
+
8
+ //#region src/commands/get-css-classes.ts
9
+ const getCSSClassesCommand = new commander.Command("get-css-classes").description("Extract and return all valid CSS classes from a theme CSS file").option("-c, --category <category>", "Category filter: 'colors', 'typography', 'spacing', 'effects', 'all'", "all").option("-a, --app-path <path>", "App path to read theme path from project.json (e.g., \"apps/agiflow-app\")").option("-t, --theme-path <path>", "Default theme CSS file path relative to workspace root (used if appPath not provided or themePath not in project.json)", "packages/frontend/web-theme/src/agimon-theme.css").action(async (options) => {
10
+ try {
11
+ const result = await new require_stdio.GetCSSClassesTool(options.themePath).execute({
12
+ category: options.category,
13
+ appPath: options.appPath
14
+ });
15
+ if (result.isError) {
16
+ const firstContent$1 = result.content[0];
17
+ const errorText = firstContent$1?.type === "text" ? firstContent$1.text : "Unknown error";
18
+ throw new Error(errorText);
19
+ }
20
+ const firstContent = result.content[0];
21
+ __agiflowai_aicode_utils.print.info(firstContent?.type === "text" ? firstContent.text : "");
22
+ } catch (error) {
23
+ __agiflowai_aicode_utils.print.error("Error getting CSS classes:", error instanceof Error ? error.message : String(error));
24
+ process.exit(1);
25
+ }
26
+ });
27
+
28
+ //#endregion
29
+ //#region src/commands/get-ui-component.ts
30
+ const getUiComponentCommand = new commander.Command("get-ui-component").description("Get a screenshot of a UI component rendered with app-specific design system configuration. Returns screenshot path and story file content.").requiredOption("-c, --component-name <name>", "The name of the component to capture (e.g., \"Button\", \"Card\")").requiredOption("-a, --app-path <path>", "The app path (relative or absolute) to load design system config from (e.g., \"apps/agiflow-app\")").option("-s, --story-name <name>", "The story name to render (e.g., \"Playground\", \"Default\")", "Playground").option("-d, --dark-mode", "Render the component in dark mode", false).action(async (options) => {
31
+ try {
32
+ const result = await new require_stdio.GetComponentVisualTool().execute({
33
+ componentName: options.componentName,
34
+ appPath: options.appPath,
35
+ storyName: options.storyName,
36
+ darkMode: options.darkMode
37
+ });
38
+ if (result.isError) {
39
+ const firstContent$1 = result.content[0];
40
+ const errorText = firstContent$1?.type === "text" ? firstContent$1.text : "Unknown error";
41
+ throw new Error(errorText);
42
+ }
43
+ const firstContent = result.content[0];
44
+ console.log(firstContent?.type === "text" ? firstContent.text : "");
45
+ } catch (error) {
46
+ console.error("Error:", error instanceof Error ? error.message : String(error));
47
+ process.exit(1);
48
+ }
49
+ });
50
+
51
+ //#endregion
52
+ //#region src/commands/list-app-components.ts
53
+ const listAppComponentsCommand = new commander.Command("list-app-components").description("List app-specific components and package components. Reads the app's package.json to find workspace dependencies.").requiredOption("-a, --app-path <path>", "The app path (relative or absolute) to list components for (e.g., \"apps/agiflow-app\")").option("-c, --cursor <cursor>", "Pagination cursor to fetch the next page").action(async (options) => {
54
+ try {
55
+ const result = await new require_stdio.ListAppComponentsTool().execute({
56
+ appPath: options.appPath,
57
+ cursor: options.cursor
58
+ });
59
+ if (result.isError) {
60
+ const firstContent$1 = result.content[0];
61
+ const errorText = firstContent$1?.type === "text" ? firstContent$1.text : "Unknown error";
62
+ throw new Error(errorText);
63
+ }
64
+ const firstContent = result.content[0];
65
+ __agiflowai_aicode_utils.print.info(firstContent?.type === "text" ? firstContent.text : "");
66
+ } catch (error) {
67
+ __agiflowai_aicode_utils.print.error("Error:", error instanceof Error ? error.message : String(error));
68
+ process.exit(1);
69
+ }
70
+ });
71
+
72
+ //#endregion
73
+ //#region src/commands/list-themes.ts
74
+ /**
75
+ * List all available theme configurations from CSS files
76
+ */
77
+ const listThemesCommand = new commander.Command("list-themes").description("List all available theme configurations from CSS files configured in project.json style-system config").option("-a, --app-path <path>", "App path to read theme config from project.json (e.g., \"apps/my-app\")").action(async (options) => {
78
+ try {
79
+ const result = await new require_stdio.ListThemesTool().execute({ appPath: options.appPath });
80
+ if (result.isError) {
81
+ const firstContent$1 = result.content[0];
82
+ const errorText = firstContent$1?.type === "text" ? firstContent$1.text : "Unknown error";
83
+ throw new Error(errorText);
84
+ }
85
+ const firstContent = result.content[0];
86
+ __agiflowai_aicode_utils.print.info(firstContent?.type === "text" ? firstContent.text : "");
87
+ } catch (error) {
88
+ __agiflowai_aicode_utils.print.error("Error listing themes:", error instanceof Error ? error.message : String(error));
89
+ process.exit(1);
90
+ }
91
+ });
92
+
93
+ //#endregion
94
+ //#region src/commands/list-shared-components.ts
95
+ const listSharedComponentsCommand = new commander.Command("list-shared-components").description("List all shared UI components available in the design system").option("-c, --cursor <cursor>", "Pagination cursor to fetch the next page").action(async (options) => {
96
+ try {
97
+ const result = await new require_stdio.ListSharedComponentsTool().execute({ cursor: options.cursor });
98
+ if (result.isError) {
99
+ const firstContent$1 = result.content[0];
100
+ const errorText = firstContent$1?.type === "text" ? firstContent$1.text : "Unknown error";
101
+ throw new Error(errorText);
102
+ }
103
+ const firstContent = result.content[0];
104
+ __agiflowai_aicode_utils.print.info(firstContent?.type === "text" ? firstContent.text : "");
105
+ } catch (error) {
106
+ __agiflowai_aicode_utils.print.error("Error listing shared components:", error instanceof Error ? error.message : String(error));
107
+ process.exit(1);
108
+ }
109
+ });
110
+
111
+ //#endregion
112
+ //#region src/commands/mcp-serve.ts
113
+ /**
114
+ * Start MCP server with given transport handler
115
+ */
116
+ async function startServer(handler, bundlerService) {
117
+ await handler.start();
118
+ const shutdown = async (signal) => {
119
+ console.error(`\nReceived ${signal}, shutting down gracefully...`);
120
+ try {
121
+ if (bundlerService.isServerRunning()) {
122
+ console.error("Stopping bundler dev server...");
123
+ await bundlerService.cleanup();
124
+ }
125
+ await handler.stop();
126
+ process.exit(0);
127
+ } catch (error) {
128
+ console.error("Error during shutdown:", error);
129
+ process.exit(1);
130
+ }
131
+ };
132
+ process.on("SIGINT", () => shutdown("SIGINT"));
133
+ process.on("SIGTERM", () => shutdown("SIGTERM"));
134
+ }
135
+ /**
136
+ * MCP Serve command
137
+ *
138
+ * Note: Design system configuration is now app-specific and read from each app's project.json.
139
+ * No global theme configuration is needed at the server level.
140
+ */
141
+ const mcpServeCommand = new commander.Command("mcp-serve").description("Start MCP server with specified transport").option("-t, --type <type>", "Transport type: stdio", "stdio").option("--theme-path <path>", "Default theme CSS file path relative to workspace root", "packages/frontend/web-theme/src/agimon-theme.css").option("--dev", "Start Vite dev server for component hot reload and caching").option("--app-path <path>", "App path for dev server (e.g., apps/agiflow-app)").action(async (options) => {
142
+ try {
143
+ const transportType = options.type.toLowerCase();
144
+ const bundlerService = await require_stdio.getBundlerServiceFromConfig();
145
+ if (options.dev) {
146
+ if (!options.appPath) {
147
+ console.error("Error: --app-path is required when using --dev flag");
148
+ console.error("Example: style-system-mcp mcp-serve --dev --app-path apps/agiflow-app");
149
+ process.exit(1);
150
+ }
151
+ const { url, port } = await bundlerService.startDevServer(options.appPath);
152
+ console.log(`✅ Dev server started at ${url} (port: ${port})`);
153
+ console.log("⚡ Components will be served with hot reload support and caching");
154
+ }
155
+ if (transportType === "stdio") await startServer(new require_stdio.StdioTransportHandler(require_stdio.createServer(options.themePath)), bundlerService);
156
+ else {
157
+ console.error(`Unknown transport type: ${transportType}. Use: stdio`);
158
+ process.exit(1);
159
+ }
160
+ } catch (error) {
161
+ console.error("Failed to start MCP server:", error);
162
+ process.exit(1);
163
+ }
164
+ });
165
+
166
+ //#endregion
167
+ //#region src/cli.ts
168
+ /**
169
+ * Main entry point
170
+ */
171
+ async function main() {
172
+ const program = new commander.Command();
173
+ program.name("style-system-mcp").description("MCP server for design system tools").version("0.1.0");
174
+ program.addCommand(getCSSClassesCommand);
175
+ program.addCommand(getUiComponentCommand);
176
+ program.addCommand(listAppComponentsCommand);
177
+ program.addCommand(listThemesCommand);
178
+ program.addCommand(listSharedComponentsCommand);
179
+ program.addCommand(mcpServeCommand);
180
+ await program.parseAsync(process.argv);
181
+ }
182
+ main();
183
+
184
+ //#endregion
package/dist/cli.d.cts ADDED
@@ -0,0 +1 @@
1
+ export { };
package/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ export { };
package/dist/cli.js ADDED
@@ -0,0 +1,183 @@
1
+ #!/usr/bin/env node
2
+ import { a as ListAppComponentsTool, i as ListThemesTool, m as GetCSSClassesTool, n as createServer, o as GetComponentVisualTool, r as ListSharedComponentsTool, t as StdioTransportHandler, u as getBundlerServiceFromConfig } from "./stdio-CGaoEmM8.js";
3
+ import { print } from "@agiflowai/aicode-utils";
4
+ import { Command } from "commander";
5
+
6
+ //#region src/commands/get-css-classes.ts
7
+ const getCSSClassesCommand = new Command("get-css-classes").description("Extract and return all valid CSS classes from a theme CSS file").option("-c, --category <category>", "Category filter: 'colors', 'typography', 'spacing', 'effects', 'all'", "all").option("-a, --app-path <path>", "App path to read theme path from project.json (e.g., \"apps/agiflow-app\")").option("-t, --theme-path <path>", "Default theme CSS file path relative to workspace root (used if appPath not provided or themePath not in project.json)", "packages/frontend/web-theme/src/agimon-theme.css").action(async (options) => {
8
+ try {
9
+ const result = await new GetCSSClassesTool(options.themePath).execute({
10
+ category: options.category,
11
+ appPath: options.appPath
12
+ });
13
+ if (result.isError) {
14
+ const firstContent$1 = result.content[0];
15
+ const errorText = firstContent$1?.type === "text" ? firstContent$1.text : "Unknown error";
16
+ throw new Error(errorText);
17
+ }
18
+ const firstContent = result.content[0];
19
+ print.info(firstContent?.type === "text" ? firstContent.text : "");
20
+ } catch (error) {
21
+ print.error("Error getting CSS classes:", error instanceof Error ? error.message : String(error));
22
+ process.exit(1);
23
+ }
24
+ });
25
+
26
+ //#endregion
27
+ //#region src/commands/get-ui-component.ts
28
+ const getUiComponentCommand = new Command("get-ui-component").description("Get a screenshot of a UI component rendered with app-specific design system configuration. Returns screenshot path and story file content.").requiredOption("-c, --component-name <name>", "The name of the component to capture (e.g., \"Button\", \"Card\")").requiredOption("-a, --app-path <path>", "The app path (relative or absolute) to load design system config from (e.g., \"apps/agiflow-app\")").option("-s, --story-name <name>", "The story name to render (e.g., \"Playground\", \"Default\")", "Playground").option("-d, --dark-mode", "Render the component in dark mode", false).action(async (options) => {
29
+ try {
30
+ const result = await new GetComponentVisualTool().execute({
31
+ componentName: options.componentName,
32
+ appPath: options.appPath,
33
+ storyName: options.storyName,
34
+ darkMode: options.darkMode
35
+ });
36
+ if (result.isError) {
37
+ const firstContent$1 = result.content[0];
38
+ const errorText = firstContent$1?.type === "text" ? firstContent$1.text : "Unknown error";
39
+ throw new Error(errorText);
40
+ }
41
+ const firstContent = result.content[0];
42
+ console.log(firstContent?.type === "text" ? firstContent.text : "");
43
+ } catch (error) {
44
+ console.error("Error:", error instanceof Error ? error.message : String(error));
45
+ process.exit(1);
46
+ }
47
+ });
48
+
49
+ //#endregion
50
+ //#region src/commands/list-app-components.ts
51
+ const listAppComponentsCommand = new Command("list-app-components").description("List app-specific components and package components. Reads the app's package.json to find workspace dependencies.").requiredOption("-a, --app-path <path>", "The app path (relative or absolute) to list components for (e.g., \"apps/agiflow-app\")").option("-c, --cursor <cursor>", "Pagination cursor to fetch the next page").action(async (options) => {
52
+ try {
53
+ const result = await new ListAppComponentsTool().execute({
54
+ appPath: options.appPath,
55
+ cursor: options.cursor
56
+ });
57
+ if (result.isError) {
58
+ const firstContent$1 = result.content[0];
59
+ const errorText = firstContent$1?.type === "text" ? firstContent$1.text : "Unknown error";
60
+ throw new Error(errorText);
61
+ }
62
+ const firstContent = result.content[0];
63
+ print.info(firstContent?.type === "text" ? firstContent.text : "");
64
+ } catch (error) {
65
+ print.error("Error:", error instanceof Error ? error.message : String(error));
66
+ process.exit(1);
67
+ }
68
+ });
69
+
70
+ //#endregion
71
+ //#region src/commands/list-themes.ts
72
+ /**
73
+ * List all available theme configurations from CSS files
74
+ */
75
+ const listThemesCommand = new Command("list-themes").description("List all available theme configurations from CSS files configured in project.json style-system config").option("-a, --app-path <path>", "App path to read theme config from project.json (e.g., \"apps/my-app\")").action(async (options) => {
76
+ try {
77
+ const result = await new ListThemesTool().execute({ appPath: options.appPath });
78
+ if (result.isError) {
79
+ const firstContent$1 = result.content[0];
80
+ const errorText = firstContent$1?.type === "text" ? firstContent$1.text : "Unknown error";
81
+ throw new Error(errorText);
82
+ }
83
+ const firstContent = result.content[0];
84
+ print.info(firstContent?.type === "text" ? firstContent.text : "");
85
+ } catch (error) {
86
+ print.error("Error listing themes:", error instanceof Error ? error.message : String(error));
87
+ process.exit(1);
88
+ }
89
+ });
90
+
91
+ //#endregion
92
+ //#region src/commands/list-shared-components.ts
93
+ const listSharedComponentsCommand = new Command("list-shared-components").description("List all shared UI components available in the design system").option("-c, --cursor <cursor>", "Pagination cursor to fetch the next page").action(async (options) => {
94
+ try {
95
+ const result = await new ListSharedComponentsTool().execute({ cursor: options.cursor });
96
+ if (result.isError) {
97
+ const firstContent$1 = result.content[0];
98
+ const errorText = firstContent$1?.type === "text" ? firstContent$1.text : "Unknown error";
99
+ throw new Error(errorText);
100
+ }
101
+ const firstContent = result.content[0];
102
+ print.info(firstContent?.type === "text" ? firstContent.text : "");
103
+ } catch (error) {
104
+ print.error("Error listing shared components:", error instanceof Error ? error.message : String(error));
105
+ process.exit(1);
106
+ }
107
+ });
108
+
109
+ //#endregion
110
+ //#region src/commands/mcp-serve.ts
111
+ /**
112
+ * Start MCP server with given transport handler
113
+ */
114
+ async function startServer(handler, bundlerService) {
115
+ await handler.start();
116
+ const shutdown = async (signal) => {
117
+ console.error(`\nReceived ${signal}, shutting down gracefully...`);
118
+ try {
119
+ if (bundlerService.isServerRunning()) {
120
+ console.error("Stopping bundler dev server...");
121
+ await bundlerService.cleanup();
122
+ }
123
+ await handler.stop();
124
+ process.exit(0);
125
+ } catch (error) {
126
+ console.error("Error during shutdown:", error);
127
+ process.exit(1);
128
+ }
129
+ };
130
+ process.on("SIGINT", () => shutdown("SIGINT"));
131
+ process.on("SIGTERM", () => shutdown("SIGTERM"));
132
+ }
133
+ /**
134
+ * MCP Serve command
135
+ *
136
+ * Note: Design system configuration is now app-specific and read from each app's project.json.
137
+ * No global theme configuration is needed at the server level.
138
+ */
139
+ const mcpServeCommand = new Command("mcp-serve").description("Start MCP server with specified transport").option("-t, --type <type>", "Transport type: stdio", "stdio").option("--theme-path <path>", "Default theme CSS file path relative to workspace root", "packages/frontend/web-theme/src/agimon-theme.css").option("--dev", "Start Vite dev server for component hot reload and caching").option("--app-path <path>", "App path for dev server (e.g., apps/agiflow-app)").action(async (options) => {
140
+ try {
141
+ const transportType = options.type.toLowerCase();
142
+ const bundlerService = await getBundlerServiceFromConfig();
143
+ if (options.dev) {
144
+ if (!options.appPath) {
145
+ console.error("Error: --app-path is required when using --dev flag");
146
+ console.error("Example: style-system-mcp mcp-serve --dev --app-path apps/agiflow-app");
147
+ process.exit(1);
148
+ }
149
+ const { url, port } = await bundlerService.startDevServer(options.appPath);
150
+ console.log(`✅ Dev server started at ${url} (port: ${port})`);
151
+ console.log("⚡ Components will be served with hot reload support and caching");
152
+ }
153
+ if (transportType === "stdio") await startServer(new StdioTransportHandler(createServer(options.themePath)), bundlerService);
154
+ else {
155
+ console.error(`Unknown transport type: ${transportType}. Use: stdio`);
156
+ process.exit(1);
157
+ }
158
+ } catch (error) {
159
+ console.error("Failed to start MCP server:", error);
160
+ process.exit(1);
161
+ }
162
+ });
163
+
164
+ //#endregion
165
+ //#region src/cli.ts
166
+ /**
167
+ * Main entry point
168
+ */
169
+ async function main() {
170
+ const program = new Command();
171
+ program.name("style-system-mcp").description("MCP server for design system tools").version("0.1.0");
172
+ program.addCommand(getCSSClassesCommand);
173
+ program.addCommand(getUiComponentCommand);
174
+ program.addCommand(listAppComponentsCommand);
175
+ program.addCommand(listThemesCommand);
176
+ program.addCommand(listSharedComponentsCommand);
177
+ program.addCommand(mcpServeCommand);
178
+ await program.parseAsync(process.argv);
179
+ }
180
+ main();
181
+
182
+ //#endregion
183
+ export { };