@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/LICENSE +661 -0
- package/README.md +318 -0
- package/dist/cli.cjs +184 -0
- package/dist/cli.d.cts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +183 -0
- package/dist/index.cjs +20 -0
- package/dist/index.d.cts +1368 -0
- package/dist/index.d.ts +1368 -0
- package/dist/index.js +3 -0
- package/dist/stdio-BlNvX94v.cjs +3251 -0
- package/dist/stdio-CGaoEmM8.js +3099 -0
- package/package.json +75 -0
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 { };
|